]> git.openstreetmap.org Git - rails.git/blob - test/functional/way_controller_test.rb
19b7fd54c1c2055939ea5e98991af7ca6c81f68a
[rails.git] / test / functional / way_controller_test.rb
1 require File.dirname(__FILE__) + '/../test_helper'
2 require 'way_controller'
3
4 class WayControllerTest < ActionController::TestCase
5   api_fixtures
6
7   def basic_authorization(user, pass)
8     @request.env["HTTP_AUTHORIZATION"] = "Basic %s" % Base64.encode64("#{user}:#{pass}")
9   end
10
11   def content(c)
12     @request.env["RAW_POST_DATA"] = c.to_s
13   end
14
15   # -------------------------------------
16   # Test reading ways.
17   # -------------------------------------
18
19   def test_read
20     # check that a visible way is returned properly
21     get :read, :id => current_ways(:visible_way).id
22     assert_response :success
23
24     # check that an invisible way is not returned
25     get :read, :id => current_ways(:invisible_way).id
26     assert_response :gone
27
28     # check chat a non-existent way is not returned
29     get :read, :id => 0
30     assert_response :not_found
31   end
32
33   ##
34   # check the "full" mode
35   def test_full
36     get :full, :id => current_ways(:visible_way).id
37     assert_response :success
38     # FIXME check whether this contains the stuff we want!
39     #print @response.body
40     # Check the way is correctly returned
41     way = current_ways(:visible_way)
42     assert_select "osm way[id=#{way.id}][version=#{way.version}][visible=#{way.visible}]", 1
43     assert_select "osm way nd[ref=#{way.way_nodes[0].node_id}]", 1
44     # Check that the node is correctly returned
45     nd = current_ways(:visible_way).nodes
46     assert_equal 1, nd.count
47     nda = nd[0]
48     assert_select "osm node[id=#{nda.id}][version=#{nda.version}][lat=#{nda.lat}][lon=#{nda.lon}]", 1 
49   end
50
51   # -------------------------------------
52   # Test simple way creation.
53   # -------------------------------------
54
55   def test_create
56     nid1 = current_nodes(:used_node_1).id
57     nid2 = current_nodes(:used_node_2).id
58     basic_authorization "test@openstreetmap.org", "test"
59
60     # use the first user's open changeset
61     changeset_id = changesets(:normal_user_first_change).id
62     
63     # create a way with pre-existing nodes
64     content "<osm><way changeset='#{changeset_id}'>" +
65       "<nd ref='#{nid1}'/><nd ref='#{nid2}'/>" + 
66       "<tag k='test' v='yes' /></way></osm>"
67     put :create
68     # hope for success
69     assert_response :success, 
70         "way upload did not return success status"
71     # read id of created way and search for it
72     wayid = @response.body
73     checkway = Way.find(wayid)
74     assert_not_nil checkway, 
75         "uploaded way not found in data base after upload"
76     # compare values
77     assert_equal checkway.nds.length, 2, 
78         "saved way does not contain exactly one node"
79     assert_equal checkway.nds[0], nid1, 
80         "saved way does not contain the right node on pos 0"
81     assert_equal checkway.nds[1], nid2, 
82         "saved way does not contain the right node on pos 1"
83     assert_equal checkway.changeset_id, changeset_id,
84         "saved way does not belong to the correct changeset"
85     assert_equal users(:normal_user).id, checkway.changeset.user_id, 
86         "saved way does not belong to user that created it"
87     assert_equal true, checkway.visible, 
88         "saved way is not visible"
89   end
90
91   # -------------------------------------
92   # Test creating some invalid ways.
93   # -------------------------------------
94
95   def test_create_invalid
96     basic_authorization "test@openstreetmap.org", "test"
97
98     # use the first user's open changeset
99     open_changeset_id = changesets(:normal_user_first_change).id
100     closed_changeset_id = changesets(:normal_user_closed_change).id
101     nid1 = current_nodes(:used_node_1).id
102
103     # create a way with non-existing node
104     content "<osm><way changeset='#{open_changeset_id}'>" + 
105       "<nd ref='0'/><tag k='test' v='yes' /></way></osm>"
106     put :create
107     # expect failure
108     assert_response :precondition_failed, 
109         "way upload with invalid node did not return 'precondition failed'"
110
111     # create a way with no nodes
112     content "<osm><way changeset='#{open_changeset_id}'>" +
113       "<tag k='test' v='yes' /></way></osm>"
114     put :create
115     # expect failure
116     assert_response :precondition_failed, 
117         "way upload with no node did not return 'precondition failed'"
118
119     # create a way inside a closed changeset
120     content "<osm><way changeset='#{closed_changeset_id}'>" +
121       "<nd ref='#{nid1}'/></way></osm>"
122     put :create
123     # expect failure
124     assert_response :conflict, 
125         "way upload to closed changeset did not return 'conflict'"    
126   end
127
128   # -------------------------------------
129   # Test deleting ways.
130   # -------------------------------------
131   
132   def test_delete
133     # first try to delete way without auth
134     delete :delete, :id => current_ways(:visible_way).id
135     assert_response :unauthorized
136
137     # now set auth
138     basic_authorization("test@openstreetmap.org", "test");  
139
140     # this shouldn't work as with the 0.6 api we need pay load to delete
141     delete :delete, :id => current_ways(:visible_way).id
142     assert_response :bad_request
143     
144     # Now try without having a changeset
145     content "<osm><way id='#{current_ways(:visible_way).id}'></osm>"
146     delete :delete, :id => current_ways(:visible_way).id
147     assert_response :bad_request
148     
149     # try to delete with an invalid (closed) changeset
150     content update_changeset(current_ways(:visible_way).to_xml,
151                              changesets(:normal_user_closed_change).id)
152     delete :delete, :id => current_ways(:visible_way).id
153     assert_response :conflict
154
155     # try to delete with an invalid (non-existent) changeset
156     content update_changeset(current_ways(:visible_way).to_xml,0)
157     delete :delete, :id => current_ways(:visible_way).id
158     assert_response :conflict
159
160     # Now try with a valid changeset
161     content current_ways(:visible_way).to_xml
162     delete :delete, :id => current_ways(:visible_way).id
163     assert_response :success
164
165     # check the returned value - should be the new version number
166     # valid delete should return the new version number, which should
167     # be greater than the old version number
168     assert @response.body.to_i > current_ways(:visible_way).version,
169        "delete request should return a new version number for way"
170
171     # this won't work since the way is already deleted
172     content current_ways(:invisible_way).to_xml
173     delete :delete, :id => current_ways(:invisible_way).id
174     assert_response :gone
175
176     # this shouldn't work as the way is used in a relation
177     content current_ways(:used_way).to_xml
178     delete :delete, :id => current_ways(:used_way).id
179     assert_response :precondition_failed, 
180        "shouldn't be able to delete a way used in a relation (#{@response.body})"
181
182     # this won't work since the way never existed
183     delete :delete, :id => 0
184     assert_response :not_found
185   end
186
187   # ------------------------------------------------------------
188   # test tags handling
189   # ------------------------------------------------------------
190
191   ##
192   # Try adding a duplicate of an existing tag to a way
193   def test_add_duplicate_tags
194     # setup auth
195     basic_authorization(users(:normal_user).email, "test")
196
197     # add an identical tag to the way
198     tag_xml = XML::Node.new("tag")
199     tag_xml['k'] = current_way_tags(:t1).k
200     tag_xml['v'] = current_way_tags(:t1).v
201
202     # add the tag into the existing xml
203     way_xml = current_ways(:visible_way).to_xml
204     way_xml.find("//osm/way").first << tag_xml
205
206     # try and upload it
207     content way_xml
208     put :update, :id => current_ways(:visible_way).id
209     assert_response :bad_request, 
210        "adding a duplicate tag to a way should fail with 'bad request'"
211   end
212
213   ##
214   # Try adding a new duplicate tags to a way
215   def test_new_duplicate_tags
216     # setup auth
217     basic_authorization(users(:normal_user).email, "test")
218
219     # create duplicate tag
220     tag_xml = XML::Node.new("tag")
221     tag_xml['k'] = "i_am_a_duplicate"
222     tag_xml['v'] = "foobar"
223
224     # add the tag into the existing xml
225     way_xml = current_ways(:visible_way).to_xml
226
227     # add two copies of the tag
228     way_xml.find("//osm/way").first << tag_xml.copy(true) << tag_xml
229
230     # try and upload it
231     content way_xml
232     put :update, :id => current_ways(:visible_way).id
233     assert_response :bad_request, 
234        "adding new duplicate tags to a way should fail with 'bad request'"
235   end
236
237   ##
238   # Try adding a new duplicate tags to a way.
239   # But be a bit subtle - use unicode decoding ambiguities to use different
240   # binary strings which have the same decoding.
241   #
242   # NOTE: I'm not sure this test is working correctly, as a lot of the tag
243   # keys seem to come out as "addr��housenumber". It might be something to
244   # do with Ruby's unicode handling...?
245   def test_invalid_duplicate_tags
246     # setup auth
247     basic_authorization(users(:normal_user).email, "test")
248
249     # add the tag into the existing xml
250     way_str = "<osm><way changeset='1'>"
251     way_str << "<tag k='addr:housenumber' v='1'/>"
252
253     # all of these keys have the same unicode decoding, but are binary
254     # not equal. libxml should make these identical as it decodes the
255     # XML document...
256     [ "addr\xc0\xbahousenumber",
257       "addr\xe0\x80\xbahousenumber",
258       "addr\xf0\x80\x80\xbahousenumber" ].each do |key|
259       # copy the XML doc to add the tags
260       way_str_copy = way_str.clone
261
262       # add all new tags to the way
263       way_str_copy << "<tag k='" << key << "' v='1'/>"
264       way_str_copy << "</way></osm>";
265
266       # try and upload it
267       content way_str_copy
268       put :create
269       assert_response :bad_request, 
270          "adding new duplicate tags to a way should fail with 'bad request'"
271     end
272   end
273
274   ##
275   # test that a call to ways_for_node returns all ways that contain the node
276   # and none that don't.
277   def test_ways_for_node
278     # in current fixtures ways 1 and 3 all use node 3. ways 2 and 4 
279     # *used* to use it but doesn't.
280     get :ways_for_node, :id => current_nodes(:used_node_1).id
281     assert_response :success
282     ways_xml = XML::Parser.string(@response.body).parse
283     assert_not_nil ways_xml, "failed to parse ways_for_node response"
284
285     # check that the set of IDs match expectations
286     expected_way_ids = [ current_ways(:visible_way).id,
287                          current_ways(:used_way).id
288                        ]
289     found_way_ids = ways_xml.find("//osm/way").collect { |w| w["id"].to_i }
290     assert_equal expected_way_ids, found_way_ids,
291       "expected ways for node #{current_nodes(:used_node_1).id} did not match found"
292     
293     # check the full ways to ensure we're not missing anything
294     expected_way_ids.each do |id|
295       way_xml = ways_xml.find("//osm/way[@id=#{id}]").first
296       assert_ways_are_equal(Way.find(id),
297                             Way.from_xml_node(way_xml))
298     end
299   end
300
301   ##
302   # update the changeset_id of a node element
303   def update_changeset(xml, changeset_id)
304     xml_attr_rewrite(xml, 'changeset', changeset_id)
305   end
306
307   ##
308   # update an attribute in the node element
309   def xml_attr_rewrite(xml, name, value)
310     xml.find("//osm/way").first[name] = value.to_s
311     return xml
312   end
313 end