1 require File.dirname(__FILE__) + '/../test_helper'
2 require 'way_controller'
4 class WayControllerTest < ActionController::TestCase
7 def basic_authorization(user, pass)
8 @request.env["HTTP_AUTHORIZATION"] = "Basic %s" % Base64.encode64("#{user}:#{pass}")
12 @request.env["RAW_POST_DATA"] = c.to_s
15 # -------------------------------------
17 # -------------------------------------
20 # check that a visible way is returned properly
21 get :read, :id => current_ways(:visible_way).id
22 assert_response :success
24 # check that an invisible way is not returned
25 get :read, :id => current_ways(:invisible_way).id
28 # check chat a non-existent way is not returned
30 assert_response :not_found
34 # check the "full" mode
36 Way.find(:all).each do |way|
37 get :full, :id => way.id
39 # full call should say "gone" for non-visible ways...
45 # otherwise it should say success
46 assert_response :success
48 # Check the way is correctly returned
49 assert_select "osm way[id=#{way.id}][version=#{way.version}][visible=#{way.visible}]", 1
51 # check that each node in the way appears once in the output as a
52 # reference and as the node element. note the slightly dodgy assumption
53 # that nodes appear only once. this is currently the case with the
54 # fixtures, but it doesn't have to be.
56 assert_select "osm way nd[ref=#{n.id}]", 1
57 assert_select "osm node[id=#{n.id}][version=#{n.version}][lat=#{n.lat}][lon=#{n.lon}]", 1
62 # -------------------------------------
63 # Test simple way creation.
64 # -------------------------------------
67 nid1 = current_nodes(:used_node_1).id
68 nid2 = current_nodes(:used_node_2).id
69 basic_authorization "test@openstreetmap.org", "test"
71 # use the first user's open changeset
72 changeset_id = changesets(:normal_user_first_change).id
74 # create a way with pre-existing nodes
75 content "<osm><way changeset='#{changeset_id}'>" +
76 "<nd ref='#{nid1}'/><nd ref='#{nid2}'/>" +
77 "<tag k='test' v='yes' /></way></osm>"
80 assert_response :success,
81 "way upload did not return success status"
82 # read id of created way and search for it
83 wayid = @response.body
84 checkway = Way.find(wayid)
85 assert_not_nil checkway,
86 "uploaded way not found in data base after upload"
88 assert_equal checkway.nds.length, 2,
89 "saved way does not contain exactly one node"
90 assert_equal checkway.nds[0], nid1,
91 "saved way does not contain the right node on pos 0"
92 assert_equal checkway.nds[1], nid2,
93 "saved way does not contain the right node on pos 1"
94 assert_equal checkway.changeset_id, changeset_id,
95 "saved way does not belong to the correct changeset"
96 assert_equal users(:normal_user).id, checkway.changeset.user_id,
97 "saved way does not belong to user that created it"
98 assert_equal true, checkway.visible,
99 "saved way is not visible"
102 # -------------------------------------
103 # Test creating some invalid ways.
104 # -------------------------------------
106 def test_create_invalid
107 basic_authorization "test@openstreetmap.org", "test"
109 # use the first user's open changeset
110 open_changeset_id = changesets(:normal_user_first_change).id
111 closed_changeset_id = changesets(:normal_user_closed_change).id
112 nid1 = current_nodes(:used_node_1).id
114 # create a way with non-existing node
115 content "<osm><way changeset='#{open_changeset_id}'>" +
116 "<nd ref='0'/><tag k='test' v='yes' /></way></osm>"
119 assert_response :precondition_failed,
120 "way upload with invalid node did not return 'precondition failed'"
122 # create a way with no nodes
123 content "<osm><way changeset='#{open_changeset_id}'>" +
124 "<tag k='test' v='yes' /></way></osm>"
127 assert_response :precondition_failed,
128 "way upload with no node did not return 'precondition failed'"
130 # create a way inside a closed changeset
131 content "<osm><way changeset='#{closed_changeset_id}'>" +
132 "<nd ref='#{nid1}'/></way></osm>"
135 assert_response :conflict,
136 "way upload to closed changeset did not return 'conflict'"
139 # -------------------------------------
140 # Test deleting ways.
141 # -------------------------------------
144 # first try to delete way without auth
145 delete :delete, :id => current_ways(:visible_way).id
146 assert_response :unauthorized
149 basic_authorization("test@openstreetmap.org", "test");
151 # this shouldn't work as with the 0.6 api we need pay load to delete
152 delete :delete, :id => current_ways(:visible_way).id
153 assert_response :bad_request
155 # Now try without having a changeset
156 content "<osm><way id='#{current_ways(:visible_way).id}'></osm>"
157 delete :delete, :id => current_ways(:visible_way).id
158 assert_response :bad_request
160 # try to delete with an invalid (closed) changeset
161 content update_changeset(current_ways(:visible_way).to_xml,
162 changesets(:normal_user_closed_change).id)
163 delete :delete, :id => current_ways(:visible_way).id
164 assert_response :conflict
166 # try to delete with an invalid (non-existent) changeset
167 content update_changeset(current_ways(:visible_way).to_xml,0)
168 delete :delete, :id => current_ways(:visible_way).id
169 assert_response :conflict
171 # Now try with a valid changeset
172 content current_ways(:visible_way).to_xml
173 delete :delete, :id => current_ways(:visible_way).id
174 assert_response :success
176 # check the returned value - should be the new version number
177 # valid delete should return the new version number, which should
178 # be greater than the old version number
179 assert @response.body.to_i > current_ways(:visible_way).version,
180 "delete request should return a new version number for way"
182 # this won't work since the way is already deleted
183 content current_ways(:invisible_way).to_xml
184 delete :delete, :id => current_ways(:invisible_way).id
185 assert_response :gone
187 # this shouldn't work as the way is used in a relation
188 content current_ways(:used_way).to_xml
189 delete :delete, :id => current_ways(:used_way).id
190 assert_response :precondition_failed,
191 "shouldn't be able to delete a way used in a relation (#{@response.body})"
193 # this won't work since the way never existed
194 delete :delete, :id => 0
195 assert_response :not_found
198 # ------------------------------------------------------------
200 # ------------------------------------------------------------
203 # Try adding a duplicate of an existing tag to a way
204 def test_add_duplicate_tags
206 basic_authorization(users(:normal_user).email, "test")
208 # add an identical tag to the way
209 tag_xml = XML::Node.new("tag")
210 tag_xml['k'] = current_way_tags(:t1).k
211 tag_xml['v'] = current_way_tags(:t1).v
213 # add the tag into the existing xml
214 way_xml = current_ways(:visible_way).to_xml
215 way_xml.find("//osm/way").first << tag_xml
219 put :update, :id => current_ways(:visible_way).id
220 assert_response :bad_request,
221 "adding a duplicate tag to a way should fail with 'bad request'"
225 # Try adding a new duplicate tags to a way
226 def test_new_duplicate_tags
228 basic_authorization(users(:normal_user).email, "test")
230 # create duplicate tag
231 tag_xml = XML::Node.new("tag")
232 tag_xml['k'] = "i_am_a_duplicate"
233 tag_xml['v'] = "foobar"
235 # add the tag into the existing xml
236 way_xml = current_ways(:visible_way).to_xml
238 # add two copies of the tag
239 way_xml.find("//osm/way").first << tag_xml.copy(true) << tag_xml
243 put :update, :id => current_ways(:visible_way).id
244 assert_response :bad_request,
245 "adding new duplicate tags to a way should fail with 'bad request'"
249 # Try adding a new duplicate tags to a way.
250 # But be a bit subtle - use unicode decoding ambiguities to use different
251 # binary strings which have the same decoding.
253 # NOTE: I'm not sure this test is working correctly, as a lot of the tag
254 # keys seem to come out as "addr��housenumber". It might be something to
255 # do with Ruby's unicode handling...?
256 def test_invalid_duplicate_tags
258 basic_authorization(users(:normal_user).email, "test")
260 # add the tag into the existing xml
261 way_str = "<osm><way changeset='1'>"
262 way_str << "<tag k='addr:housenumber' v='1'/>"
264 # all of these keys have the same unicode decoding, but are binary
265 # not equal. libxml should make these identical as it decodes the
267 [ "addr\xc0\xbahousenumber",
268 "addr\xe0\x80\xbahousenumber",
269 "addr\xf0\x80\x80\xbahousenumber" ].each do |key|
270 # copy the XML doc to add the tags
271 way_str_copy = way_str.clone
273 # add all new tags to the way
274 way_str_copy << "<tag k='" << key << "' v='1'/>"
275 way_str_copy << "</way></osm>";
280 assert_response :bad_request,
281 "adding new duplicate tags to a way should fail with 'bad request'"
286 # test that a call to ways_for_node returns all ways that contain the node
287 # and none that don't.
288 def test_ways_for_node
289 # in current fixtures ways 1 and 3 all use node 3. ways 2 and 4
290 # *used* to use it but doesn't.
291 get :ways_for_node, :id => current_nodes(:used_node_1).id
292 assert_response :success
293 ways_xml = XML::Parser.string(@response.body).parse
294 assert_not_nil ways_xml, "failed to parse ways_for_node response"
296 # check that the set of IDs match expectations
297 expected_way_ids = [ current_ways(:visible_way).id,
298 current_ways(:used_way).id
300 found_way_ids = ways_xml.find("//osm/way").collect { |w| w["id"].to_i }
301 assert_equal expected_way_ids, found_way_ids,
302 "expected ways for node #{current_nodes(:used_node_1).id} did not match found"
304 # check the full ways to ensure we're not missing anything
305 expected_way_ids.each do |id|
306 way_xml = ways_xml.find("//osm/way[@id=#{id}]").first
307 assert_ways_are_equal(Way.find(id),
308 Way.from_xml_node(way_xml))
313 # update the changeset_id of a node element
314 def update_changeset(xml, changeset_id)
315 xml_attr_rewrite(xml, 'changeset', changeset_id)
319 # update an attribute in the node element
320 def xml_attr_rewrite(xml, name, value)
321 xml.find("//osm/way").first[name] = value.to_s