1 require File.dirname(__FILE__) + '/../test_helper'
2 require 'way_controller'
4 # Re-raise errors caught by the controller.
5 class WayController; def rescue_action(e) raise e end; end
7 class WayControllerTest < Test::Unit::TestCase
11 @controller = WayController.new
12 @request = ActionController::TestRequest.new
13 @response = ActionController::TestResponse.new
16 def basic_authorization(user, pass)
17 @request.env["HTTP_AUTHORIZATION"] = "Basic %s" % Base64.encode64("#{user}:#{pass}")
21 @request.env["RAW_POST_DATA"] = c.to_s
24 # -------------------------------------
26 # -------------------------------------
29 # check that a visible way is returned properly
30 get :read, :id => current_ways(:visible_way).id
31 assert_response :success
33 # check that an invisible way is not returned
34 get :read, :id => current_ways(:invisible_way).id
37 # check chat a non-existent way is not returned
39 assert_response :not_found
43 # check the "full" mode
45 get :full, :id => current_ways(:visible_way).id
46 assert_response :success
47 # FIXME check whether this contains the stuff we want!
49 # Check the way is correctly returned
50 way = current_ways(:visible_way)
51 assert_select "osm way[id=#{way.id}][version=#{way.version}][visible=#{way.visible}]", 1
52 assert_select "osm way nd[ref=#{way.way_nodes[0].node_id}]", 1
53 # Check that the node is correctly returned
54 nd = current_ways(:visible_way).nodes
55 assert_equal 1, nd.count
57 assert_select "osm node[id=#{nda.id}][version=#{nda.version}][lat=#{nda.lat}][lon=#{nda.lon}]", 1
60 # -------------------------------------
61 # Test simple way creation.
62 # -------------------------------------
65 nid1 = current_nodes(:used_node_1).id
66 nid2 = current_nodes(:used_node_2).id
67 basic_authorization "test@openstreetmap.org", "test"
69 # use the first user's open changeset
70 changeset_id = changesets(:normal_user_first_change).id
72 # create a way with pre-existing nodes
73 content "<osm><way changeset='#{changeset_id}'>" +
74 "<nd ref='#{nid1}'/><nd ref='#{nid2}'/>" +
75 "<tag k='test' v='yes' /></way></osm>"
78 assert_response :success,
79 "way upload did not return success status"
80 # read id of created way and search for it
81 wayid = @response.body
82 checkway = Way.find(wayid)
83 assert_not_nil checkway,
84 "uploaded way not found in data base after upload"
86 assert_equal checkway.nds.length, 2,
87 "saved way does not contain exactly one node"
88 assert_equal checkway.nds[0], nid1,
89 "saved way does not contain the right node on pos 0"
90 assert_equal checkway.nds[1], nid2,
91 "saved way does not contain the right node on pos 1"
92 assert_equal checkway.changeset_id, changeset_id,
93 "saved way does not belong to the correct changeset"
94 assert_equal users(:normal_user).id, checkway.changeset.user_id,
95 "saved way does not belong to user that created it"
96 assert_equal true, checkway.visible,
97 "saved way is not visible"
100 # -------------------------------------
101 # Test creating some invalid ways.
102 # -------------------------------------
104 def test_create_invalid
105 basic_authorization "test@openstreetmap.org", "test"
107 # use the first user's open changeset
108 open_changeset_id = changesets(:normal_user_first_change).id
109 closed_changeset_id = changesets(:normal_user_closed_change).id
110 nid1 = current_nodes(:used_node_1).id
112 # create a way with non-existing node
113 content "<osm><way changeset='#{open_changeset_id}'>" +
114 "<nd ref='0'/><tag k='test' v='yes' /></way></osm>"
117 assert_response :precondition_failed,
118 "way upload with invalid node did not return 'precondition failed'"
120 # create a way with no nodes
121 content "<osm><way changeset='#{open_changeset_id}'>" +
122 "<tag k='test' v='yes' /></way></osm>"
125 assert_response :precondition_failed,
126 "way upload with no node did not return 'precondition failed'"
128 # create a way inside a closed changeset
129 content "<osm><way changeset='#{closed_changeset_id}'>" +
130 "<nd ref='#{nid1}'/></way></osm>"
133 assert_response :conflict,
134 "way upload to closed changeset did not return 'conflict'"
137 # -------------------------------------
138 # Test deleting ways.
139 # -------------------------------------
142 # first try to delete way without auth
143 delete :delete, :id => current_ways(:visible_way).id
144 assert_response :unauthorized
147 basic_authorization("test@openstreetmap.org", "test");
149 # this shouldn't work as with the 0.6 api we need pay load to delete
150 delete :delete, :id => current_ways(:visible_way).id
151 assert_response :bad_request
153 # Now try without having a changeset
154 content "<osm><way id='#{current_ways(:visible_way).id}'></osm>"
155 delete :delete, :id => current_ways(:visible_way).id
156 assert_response :bad_request
158 # try to delete with an invalid (closed) changeset
159 content update_changeset(current_ways(:visible_way).to_xml,
160 changesets(:normal_user_closed_change).id)
161 delete :delete, :id => current_ways(:visible_way).id
162 assert_response :conflict
164 # try to delete with an invalid (non-existent) changeset
165 content update_changeset(current_ways(:visible_way).to_xml,0)
166 delete :delete, :id => current_ways(:visible_way).id
167 assert_response :conflict
169 # Now try with a valid changeset
170 content current_ways(:visible_way).to_xml
171 delete :delete, :id => current_ways(:visible_way).id
172 assert_response :success
174 # check the returned value - should be the new version number
175 # valid delete should return the new version number, which should
176 # be greater than the old version number
177 assert @response.body.to_i > current_ways(:visible_way).version,
178 "delete request should return a new version number for way"
180 # this won't work since the way is already deleted
181 content current_ways(:invisible_way).to_xml
182 delete :delete, :id => current_ways(:invisible_way).id
183 assert_response :gone
185 # this shouldn't work as the way is used in a relation
186 content current_ways(:used_way).to_xml
187 delete :delete, :id => current_ways(:used_way).id
188 assert_response :precondition_failed,
189 "shouldn't be able to delete a way used in a relation (#{@response.body})"
191 # this won't work since the way never existed
192 delete :delete, :id => 0
193 assert_response :not_found
196 # ------------------------------------------------------------
198 # ------------------------------------------------------------
201 # Try adding a duplicate of an existing tag to a way
202 def test_add_duplicate_tags
204 basic_authorization(users(:normal_user).email, "test")
206 # add an identical tag to the way
207 tag_xml = XML::Node.new("tag")
208 tag_xml['k'] = current_way_tags(:t1).k
209 tag_xml['v'] = current_way_tags(:t1).v
211 # add the tag into the existing xml
212 way_xml = current_ways(:visible_way).to_xml
213 way_xml.find("//osm/way").first << tag_xml
217 put :update, :id => current_ways(:visible_way).id
218 assert_response :bad_request,
219 "adding a duplicate tag to a way should fail with 'bad request'"
223 # Try adding a new duplicate tags to a way
224 def test_new_duplicate_tags
226 basic_authorization(users(:normal_user).email, "test")
228 # create duplicate tag
229 tag_xml = XML::Node.new("tag")
230 tag_xml['k'] = "i_am_a_duplicate"
231 tag_xml['v'] = "foobar"
233 # add the tag into the existing xml
234 way_xml = current_ways(:visible_way).to_xml
236 # add two copies of the tag
237 way_xml.find("//osm/way").first << tag_xml.copy(true) << tag_xml
241 put :update, :id => current_ways(:visible_way).id
242 assert_response :bad_request,
243 "adding new duplicate tags to a way should fail with 'bad request'"
247 # Try adding a new duplicate tags to a way.
248 # But be a bit subtle - use unicode decoding ambiguities to use different
249 # binary strings which have the same decoding.
251 # NOTE: I'm not sure this test is working correctly, as a lot of the tag
252 # keys seem to come out as "addr��housenumber". It might be something to
253 # do with Ruby's unicode handling...?
254 def test_invalid_duplicate_tags
256 basic_authorization(users(:normal_user).email, "test")
258 # add the tag into the existing xml
259 way_str = "<osm><way changeset='1'>"
260 way_str << "<tag k='addr:housenumber' v='1'/>"
262 # all of these keys have the same unicode decoding, but are binary
263 # not equal. libxml should make these identical as it decodes the
265 [ "addr\xc0\xbahousenumber",
266 "addr\xe0\x80\xbahousenumber",
267 "addr\xf0\x80\x80\xbahousenumber" ].each do |key|
268 # copy the XML doc to add the tags
269 way_str_copy = way_str.clone
271 # add all new tags to the way
272 way_str_copy << "<tag k='" << key << "' v='1'/>"
273 way_str_copy << "</way></osm>";
278 assert_response :bad_request,
279 "adding new duplicate tags to a way should fail with 'bad request'"
284 # test that a call to ways_for_node returns all ways that contain the node
285 # and none that don't.
286 def test_ways_for_node
287 # in current fixtures ways 1 and 3 all use node 3. ways 2 and 4
288 # *used* to use it but doesn't.
289 get :ways_for_node, :id => current_nodes(:used_node_1).id
290 assert_response :success
291 ways_xml = XML::Parser.string(@response.body).parse
292 assert_not_nil ways_xml, "failed to parse ways_for_node response"
294 # check that the set of IDs match expectations
295 expected_way_ids = [ current_ways(:visible_way).id,
296 current_ways(:used_way).id
298 found_way_ids = ways_xml.find("//osm/way").collect { |w| w["id"].to_i }
299 assert_equal expected_way_ids, found_way_ids,
300 "expected ways for node #{current_nodes(:used_node_1).id} did not match found"
302 # check the full ways to ensure we're not missing anything
303 expected_way_ids.each do |id|
304 way_xml = ways_xml.find("//osm/way[@id=#{id}]").first
305 assert_ways_are_equal(Way.find(id),
306 Way.from_xml_node(way_xml))
311 # update the changeset_id of a node element
312 def update_changeset(xml, changeset_id)
313 xml_attr_rewrite(xml, 'changeset', changeset_id)
317 # update an attribute in the node element
318 def xml_attr_rewrite(xml, name, value)
319 xml.find("//osm/way").first[name] = value.to_s