Merge remote-tracking branch 'openstreetmap/pull/1004'
[rails.git] / test / controllers / way_controller_test.rb
1 require "test_helper"
2 require "way_controller"
3
4 class WayControllerTest < ActionController::TestCase
5   api_fixtures
6
7   ##
8   # test all routes which lead to this controller
9   def test_routes
10     assert_routing(
11       { :path => "/api/0.6/way/create", :method => :put },
12       { :controller => "way", :action => "create" }
13     )
14     assert_routing(
15       { :path => "/api/0.6/way/1/full", :method => :get },
16       { :controller => "way", :action => "full", :id => "1" }
17     )
18     assert_routing(
19       { :path => "/api/0.6/way/1", :method => :get },
20       { :controller => "way", :action => "read", :id => "1" }
21     )
22     assert_routing(
23       { :path => "/api/0.6/way/1", :method => :put },
24       { :controller => "way", :action => "update", :id => "1" }
25     )
26     assert_routing(
27       { :path => "/api/0.6/way/1", :method => :delete },
28       { :controller => "way", :action => "delete", :id => "1" }
29     )
30     assert_routing(
31       { :path => "/api/0.6/ways", :method => :get },
32       { :controller => "way", :action => "ways" }
33     )
34   end
35
36   # -------------------------------------
37   # Test reading ways.
38   # -------------------------------------
39
40   def test_read
41     # check that a visible way is returned properly
42     get :read, :id => current_ways(:visible_way).id
43     assert_response :success
44
45     # check that an invisible way is not returned
46     get :read, :id => current_ways(:invisible_way).id
47     assert_response :gone
48
49     # check chat a non-existent way is not returned
50     get :read, :id => 0
51     assert_response :not_found
52   end
53
54   ##
55   # check the "full" mode
56   def test_full
57     Way.all.each do |way|
58       get :full, :id => way.id
59
60       # full call should say "gone" for non-visible ways...
61       unless way.visible
62         assert_response :gone
63         next
64       end
65
66       # otherwise it should say success
67       assert_response :success
68
69       # Check the way is correctly returned
70       assert_select "osm way[id='#{way.id}'][version='#{way.version}'][visible='#{way.visible}']", 1
71
72       # check that each node in the way appears once in the output as a
73       # reference and as the node element.
74       way.nodes.each do |n|
75         count = (way.nodes - (way.nodes - [n])).length
76         assert_select "osm way nd[ref='#{n.id}']", count
77         assert_select "osm node[id='#{n.id}'][version='#{n.version}'][lat='#{n.lat}'][lon='#{n.lon}']", 1
78       end
79     end
80   end
81
82   ##
83   # test fetching multiple ways
84   def test_ways
85     # check error when no parameter provided
86     get :ways
87     assert_response :bad_request
88
89     # check error when no parameter value provided
90     get :ways, :ways => ""
91     assert_response :bad_request
92
93     # test a working call
94     get :ways, :ways => "1,2,4,6"
95     assert_response :success
96     assert_select "osm" do
97       assert_select "way", :count => 4
98       assert_select "way[id='1'][visible='true']", :count => 1
99       assert_select "way[id='2'][visible='false']", :count => 1
100       assert_select "way[id='4'][visible='true']", :count => 1
101       assert_select "way[id='6'][visible='true']", :count => 1
102     end
103
104     # check error when a non-existent way is included
105     get :ways, :ways => "1,2,4,6,400"
106     assert_response :not_found
107   end
108
109   # -------------------------------------
110   # Test simple way creation.
111   # -------------------------------------
112
113   def test_create
114     ## First check that it fails when creating a way using a non-public user
115     nid1 = current_nodes(:used_node_1).id
116     nid2 = current_nodes(:used_node_2).id
117     basic_authorization users(:normal_user).email, "test"
118
119     # use the first user's open changeset
120     changeset_id = changesets(:normal_user_first_change).id
121
122     # create a way with pre-existing nodes
123     content "<osm><way changeset='#{changeset_id}'>" +
124             "<nd ref='#{nid1}'/><nd ref='#{nid2}'/>" +
125             "<tag k='test' v='yes' /></way></osm>"
126     put :create
127     # hope for failure
128     assert_response :forbidden,
129                     "way upload did not return forbidden status"
130
131     ## Now use a public user
132     nid1 = current_nodes(:used_node_1).id
133     nid2 = current_nodes(:used_node_2).id
134     basic_authorization users(:public_user).email, "test"
135
136     # use the first user's open changeset
137     changeset_id = changesets(:public_user_first_change).id
138
139     # create a way with pre-existing nodes
140     content "<osm><way changeset='#{changeset_id}'>" +
141             "<nd ref='#{nid1}'/><nd ref='#{nid2}'/>" +
142             "<tag k='test' v='yes' /></way></osm>"
143     put :create
144     # hope for success
145     assert_response :success,
146                     "way upload did not return success status"
147     # read id of created way and search for it
148     wayid = @response.body
149     checkway = Way.find(wayid)
150     assert_not_nil checkway,
151                    "uploaded way not found in data base after upload"
152     # compare values
153     assert_equal checkway.nds.length, 2,
154                  "saved way does not contain exactly one node"
155     assert_equal checkway.nds[0], nid1,
156                  "saved way does not contain the right node on pos 0"
157     assert_equal checkway.nds[1], nid2,
158                  "saved way does not contain the right node on pos 1"
159     assert_equal checkway.changeset_id, changeset_id,
160                  "saved way does not belong to the correct changeset"
161     assert_equal users(:public_user).id, checkway.changeset.user_id,
162                  "saved way does not belong to user that created it"
163     assert_equal true, checkway.visible,
164                  "saved way is not visible"
165   end
166
167   # -------------------------------------
168   # Test creating some invalid ways.
169   # -------------------------------------
170
171   def test_create_invalid
172     ## First test with a private user to make sure that they are not authorized
173     basic_authorization users(:normal_user).email, "test"
174
175     # use the first user's open changeset
176     open_changeset_id = changesets(:normal_user_first_change).id
177     closed_changeset_id = changesets(:normal_user_closed_change).id
178     nid1 = current_nodes(:used_node_1).id
179
180     # create a way with non-existing node
181     content "<osm><way changeset='#{open_changeset_id}'>" +
182             "<nd ref='0'/><tag k='test' v='yes' /></way></osm>"
183     put :create
184     # expect failure
185     assert_response :forbidden,
186                     "way upload with invalid node using a private user did not return 'forbidden'"
187
188     # create a way with no nodes
189     content "<osm><way changeset='#{open_changeset_id}'>" +
190             "<tag k='test' v='yes' /></way></osm>"
191     put :create
192     # expect failure
193     assert_response :forbidden,
194                     "way upload with no node using a private userdid not return 'forbidden'"
195
196     # create a way inside a closed changeset
197     content "<osm><way changeset='#{closed_changeset_id}'>" +
198             "<nd ref='#{nid1}'/></way></osm>"
199     put :create
200     # expect failure
201     assert_response :forbidden,
202                     "way upload to closed changeset with a private user did not return 'forbidden'"
203
204     ## Now test with a public user
205     basic_authorization users(:public_user).email, "test"
206
207     # use the first user's open changeset
208     open_changeset_id = changesets(:public_user_first_change).id
209     closed_changeset_id = changesets(:public_user_closed_change).id
210     nid1 = current_nodes(:used_node_1).id
211
212     # create a way with non-existing node
213     content "<osm><way changeset='#{open_changeset_id}'>" +
214             "<nd ref='0'/><tag k='test' v='yes' /></way></osm>"
215     put :create
216     # expect failure
217     assert_response :precondition_failed,
218                     "way upload with invalid node did not return 'precondition failed'"
219     assert_equal "Precondition failed: Way  requires the nodes with id in (0), which either do not exist, or are not visible.", @response.body
220
221     # create a way with no nodes
222     content "<osm><way changeset='#{open_changeset_id}'>" +
223             "<tag k='test' v='yes' /></way></osm>"
224     put :create
225     # expect failure
226     assert_response :precondition_failed,
227                     "way upload with no node did not return 'precondition failed'"
228     assert_equal "Precondition failed: Cannot create way: data is invalid.", @response.body
229
230     # create a way inside a closed changeset
231     content "<osm><way changeset='#{closed_changeset_id}'>" +
232             "<nd ref='#{nid1}'/></way></osm>"
233     put :create
234     # expect failure
235     assert_response :conflict,
236                     "way upload to closed changeset did not return 'conflict'"
237
238     # create a way with a tag which is too long
239     content "<osm><way changeset='#{open_changeset_id}'>" +
240             "<nd ref='#{nid1}'/>" +
241             "<tag k='foo' v='#{'x' * 256}'/>" +
242             "</way></osm>"
243     put :create
244     # expect failure
245     assert_response :bad_request,
246                     "way upload to with too long tag did not return 'bad_request'"
247   end
248
249   # -------------------------------------
250   # Test deleting ways.
251   # -------------------------------------
252
253   def test_delete
254     # first try to delete way without auth
255     delete :delete, :id => current_ways(:visible_way).id
256     assert_response :unauthorized
257
258     # now set auth using the private user
259     basic_authorization(users(:normal_user).email, "test")
260
261     # this shouldn't work as with the 0.6 api we need pay load to delete
262     delete :delete, :id => current_ways(:visible_way).id
263     assert_response :forbidden
264
265     # Now try without having a changeset
266     content "<osm><way id='#{current_ways(:visible_way).id}'/></osm>"
267     delete :delete, :id => current_ways(:visible_way).id
268     assert_response :forbidden
269
270     # try to delete with an invalid (closed) changeset
271     content update_changeset(current_ways(:visible_way).to_xml,
272                              changesets(:normal_user_closed_change).id)
273     delete :delete, :id => current_ways(:visible_way).id
274     assert_response :forbidden
275
276     # try to delete with an invalid (non-existent) changeset
277     content update_changeset(current_ways(:visible_way).to_xml, 0)
278     delete :delete, :id => current_ways(:visible_way).id
279     assert_response :forbidden
280
281     # Now try with a valid changeset
282     content current_ways(:visible_way).to_xml
283     delete :delete, :id => current_ways(:visible_way).id
284     assert_response :forbidden
285
286     # check the returned value - should be the new version number
287     # valid delete should return the new version number, which should
288     # be greater than the old version number
289     # assert @response.body.to_i > current_ways(:visible_way).version,
290     #   "delete request should return a new version number for way"
291
292     # this won't work since the way is already deleted
293     content current_ways(:invisible_way).to_xml
294     delete :delete, :id => current_ways(:invisible_way).id
295     assert_response :forbidden
296
297     # this shouldn't work as the way is used in a relation
298     content current_ways(:used_way).to_xml
299     delete :delete, :id => current_ways(:used_way).id
300     assert_response :forbidden,
301                     "shouldn't be able to delete a way used in a relation (#{@response.body}), when done by a private user"
302
303     # this won't work since the way never existed
304     delete :delete, :id => 0
305     assert_response :forbidden
306
307     ### Now check with a public user
308     # now set auth
309     basic_authorization(users(:public_user).email, "test")
310
311     # this shouldn't work as with the 0.6 api we need pay load to delete
312     delete :delete, :id => current_ways(:visible_way).id
313     assert_response :bad_request
314
315     # Now try without having a changeset
316     content "<osm><way id='#{current_ways(:visible_way).id}'/></osm>"
317     delete :delete, :id => current_ways(:visible_way).id
318     assert_response :bad_request
319
320     # try to delete with an invalid (closed) changeset
321     content update_changeset(current_ways(:visible_way).to_xml,
322                              changesets(:public_user_closed_change).id)
323     delete :delete, :id => current_ways(:visible_way).id
324     assert_response :conflict
325
326     # try to delete with an invalid (non-existent) changeset
327     content update_changeset(current_ways(:visible_way).to_xml, 0)
328     delete :delete, :id => current_ways(:visible_way).id
329     assert_response :conflict
330
331     # Now try with a valid changeset
332     content current_ways(:visible_way).to_xml
333     delete :delete, :id => current_ways(:visible_way).id
334     assert_response :success
335
336     # check the returned value - should be the new version number
337     # valid delete should return the new version number, which should
338     # be greater than the old version number
339     assert @response.body.to_i > current_ways(:visible_way).version,
340            "delete request should return a new version number for way"
341
342     # this won't work since the way is already deleted
343     content current_ways(:invisible_way).to_xml
344     delete :delete, :id => current_ways(:invisible_way).id
345     assert_response :gone
346
347     # this shouldn't work as the way is used in a relation
348     content current_ways(:used_way).to_xml
349     delete :delete, :id => current_ways(:used_way).id
350     assert_response :precondition_failed,
351                     "shouldn't be able to delete a way used in a relation (#{@response.body})"
352     assert_equal "Precondition failed: Way 3 is still used by relations 1.", @response.body
353
354     # this won't work since the way never existed
355     delete :delete, :id => 0
356     assert_response :not_found
357   end
358
359   ##
360   # tests whether the API works and prevents incorrect use while trying
361   # to update ways.
362   def test_update
363     ## First test with no user credentials
364     # try and update a way without authorisation
365     # first try to delete way without auth
366     content current_ways(:visible_way).to_xml
367     put :update, :id => current_ways(:visible_way).id
368     assert_response :unauthorized
369
370     ## Second test with the private user
371
372     # setup auth
373     basic_authorization(users(:normal_user).email, "test")
374
375     ## trying to break changesets
376
377     # try and update in someone else's changeset
378     content update_changeset(current_ways(:visible_way).to_xml,
379                              changesets(:public_user_first_change).id)
380     put :update, :id => current_ways(:visible_way).id
381     assert_require_public_data "update with other user's changeset should be forbidden when date isn't public"
382
383     # try and update in a closed changeset
384     content update_changeset(current_ways(:visible_way).to_xml,
385                              changesets(:normal_user_closed_change).id)
386     put :update, :id => current_ways(:visible_way).id
387     assert_require_public_data "update with closed changeset should be forbidden, when data isn't public"
388
389     # try and update in a non-existant changeset
390     content update_changeset(current_ways(:visible_way).to_xml, 0)
391     put :update, :id => current_ways(:visible_way).id
392     assert_require_public_data("update with changeset=0 should be forbidden, when data isn't public")
393
394     ## try and submit invalid updates
395     content xml_replace_node(current_ways(:visible_way).to_xml, 3, 9999)
396     put :update, :id => current_ways(:visible_way).id
397     assert_require_public_data "way with non-existent node should be forbidden, when data isn't public"
398
399     content xml_replace_node(current_ways(:visible_way).to_xml, 3, current_nodes(:invisible_node).id)
400     put :update, :id => current_ways(:visible_way).id
401     assert_require_public_data "way with deleted node should be forbidden, when data isn't public"
402
403     ## finally, produce a good request which should work
404     content current_ways(:visible_way).to_xml
405     put :update, :id => current_ways(:visible_way).id
406     assert_require_public_data "should have failed with a forbidden when data isn't public"
407
408     ## Finally test with the public user
409
410     # try and update a way without authorisation
411     # first try to delete way without auth
412     content current_ways(:visible_way).to_xml
413     put :update, :id => current_ways(:visible_way).id
414     assert_response :forbidden
415
416     # setup auth
417     basic_authorization(users(:public_user).email, "test")
418
419     ## trying to break changesets
420
421     # try and update in someone else's changeset
422     content update_changeset(current_ways(:visible_way).to_xml,
423                              changesets(:normal_user_first_change).id)
424     put :update, :id => current_ways(:visible_way).id
425     assert_response :conflict, "update with other user's changeset should be rejected"
426
427     # try and update in a closed changeset
428     content update_changeset(current_ways(:visible_way).to_xml,
429                              changesets(:normal_user_closed_change).id)
430     put :update, :id => current_ways(:visible_way).id
431     assert_response :conflict, "update with closed changeset should be rejected"
432
433     # try and update in a non-existant changeset
434     content update_changeset(current_ways(:visible_way).to_xml, 0)
435     put :update, :id => current_ways(:visible_way).id
436     assert_response :conflict, "update with changeset=0 should be rejected"
437
438     ## try and submit invalid updates
439     content xml_replace_node(current_ways(:visible_way).to_xml, 3, 9999)
440     put :update, :id => current_ways(:visible_way).id
441     assert_response :precondition_failed, "way with non-existent node should be rejected"
442
443     content xml_replace_node(current_ways(:visible_way).to_xml, 3, current_nodes(:invisible_node).id)
444     put :update, :id => current_ways(:visible_way).id
445     assert_response :precondition_failed, "way with deleted node should be rejected"
446
447     ## next, attack the versioning
448     current_way_version = current_ways(:visible_way).version
449
450     # try and submit a version behind
451     content xml_attr_rewrite(current_ways(:visible_way).to_xml,
452                              "version", current_way_version - 1)
453     put :update, :id => current_ways(:visible_way).id
454     assert_response :conflict, "should have failed on old version number"
455
456     # try and submit a version ahead
457     content xml_attr_rewrite(current_ways(:visible_way).to_xml,
458                              "version", current_way_version + 1)
459     put :update, :id => current_ways(:visible_way).id
460     assert_response :conflict, "should have failed on skipped version number"
461
462     # try and submit total crap in the version field
463     content xml_attr_rewrite(current_ways(:visible_way).to_xml,
464                              "version", "p1r4t3s!")
465     put :update, :id => current_ways(:visible_way).id
466     assert_response :conflict,
467                     "should not be able to put 'p1r4at3s!' in the version field"
468
469     ## try an update with the wrong ID
470     content current_ways(:used_way).to_xml
471     put :update, :id => current_ways(:visible_way).id
472     assert_response :bad_request,
473                     "should not be able to update a way with a different ID from the XML"
474
475     ## try an update with a minimal valid XML doc which isn't a well-formed OSM doc.
476     content "<update/>"
477     put :update, :id => current_ways(:visible_way).id
478     assert_response :bad_request,
479                     "should not be able to update a way with non-OSM XML doc."
480
481     ## finally, produce a good request which should work
482     content current_ways(:visible_way).to_xml
483     put :update, :id => current_ways(:visible_way).id
484     assert_response :success, "a valid update request failed"
485   end
486
487   # ------------------------------------------------------------
488   # test tags handling
489   # ------------------------------------------------------------
490
491   ##
492   # Try adding a new tag to a way
493   def test_add_tags
494     ## Try with the non-public user
495     # setup auth
496     basic_authorization(users(:normal_user).email, "test")
497
498     # add an identical tag to the way
499     tag_xml = XML::Node.new("tag")
500     tag_xml["k"] = "new"
501     tag_xml["v"] = "yes"
502
503     # add the tag into the existing xml
504     way_xml = current_ways(:visible_way).to_xml
505     way_xml.find("//osm/way").first << tag_xml
506
507     # try and upload it
508     content way_xml
509     put :update, :id => current_ways(:visible_way).id
510     assert_response :forbidden,
511                     "adding a duplicate tag to a way for a non-public should fail with 'forbidden'"
512
513     ## Now try with the public user
514     # setup auth
515     basic_authorization(users(:public_user).email, "test")
516
517     # add an identical tag to the way
518     tag_xml = XML::Node.new("tag")
519     tag_xml["k"] = "new"
520     tag_xml["v"] = "yes"
521
522     # add the tag into the existing xml
523     way_xml = current_ways(:visible_way).to_xml
524     way_xml.find("//osm/way").first << tag_xml
525
526     # try and upload it
527     content way_xml
528     put :update, :id => current_ways(:visible_way).id
529     assert_response :success,
530                     "adding a new tag to a way should succeed"
531     assert_equal current_ways(:visible_way).version + 1, @response.body.to_i
532   end
533
534   ##
535   # Try adding a duplicate of an existing tag to a way
536   def test_add_duplicate_tags
537     ## Try with the non-public user
538     # setup auth
539     basic_authorization(users(:normal_user).email, "test")
540
541     # add an identical tag to the way
542     tag_xml = XML::Node.new("tag")
543     tag_xml["k"] = current_way_tags(:t1).k
544     tag_xml["v"] = current_way_tags(:t1).v
545
546     # add the tag into the existing xml
547     way_xml = current_ways(:visible_way).to_xml
548     way_xml.find("//osm/way").first << tag_xml
549
550     # try and upload it
551     content way_xml
552     put :update, :id => current_ways(:visible_way).id
553     assert_response :forbidden,
554                     "adding a duplicate tag to a way for a non-public should fail with 'forbidden'"
555
556     ## Now try with the public user
557     # setup auth
558     basic_authorization(users(:public_user).email, "test")
559
560     # add an identical tag to the way
561     tag_xml = XML::Node.new("tag")
562     tag_xml["k"] = current_way_tags(:t1).k
563     tag_xml["v"] = current_way_tags(:t1).v
564
565     # add the tag into the existing xml
566     way_xml = current_ways(:visible_way).to_xml
567     way_xml.find("//osm/way").first << tag_xml
568
569     # try and upload it
570     content way_xml
571     put :update, :id => current_ways(:visible_way).id
572     assert_response :bad_request,
573                     "adding a duplicate tag to a way should fail with 'bad request'"
574     assert_equal "Element way/#{current_ways(:visible_way).id} has duplicate tags with key #{current_way_tags(:t1).k}", @response.body
575   end
576
577   ##
578   # Try adding a new duplicate tags to a way
579   def test_new_duplicate_tags
580     ## First test with the non-public user so should be rejected
581     # setup auth
582     basic_authorization(users(:normal_user).email, "test")
583
584     # create duplicate tag
585     tag_xml = XML::Node.new("tag")
586     tag_xml["k"] = "i_am_a_duplicate"
587     tag_xml["v"] = "foobar"
588
589     # add the tag into the existing xml
590     way_xml = current_ways(:visible_way).to_xml
591
592     # add two copies of the tag
593     way_xml.find("//osm/way").first << tag_xml.copy(true) << tag_xml
594
595     # try and upload it
596     content way_xml
597     put :update, :id => current_ways(:visible_way).id
598     assert_response :forbidden,
599                     "adding new duplicate tags to a way using a non-public user should fail with 'forbidden'"
600
601     ## Now test with the public user
602     # setup auth
603     basic_authorization(users(:public_user).email, "test")
604
605     # create duplicate tag
606     tag_xml = XML::Node.new("tag")
607     tag_xml["k"] = "i_am_a_duplicate"
608     tag_xml["v"] = "foobar"
609
610     # add the tag into the existing xml
611     way_xml = current_ways(:visible_way).to_xml
612
613     # add two copies of the tag
614     way_xml.find("//osm/way").first << tag_xml.copy(true) << tag_xml
615
616     # try and upload it
617     content way_xml
618     put :update, :id => current_ways(:visible_way).id
619     assert_response :bad_request,
620                     "adding new duplicate tags to a way should fail with 'bad request'"
621     assert_equal "Element way/#{current_ways(:visible_way).id} has duplicate tags with key i_am_a_duplicate", @response.body
622   end
623
624   ##
625   # Try adding a new duplicate tags to a way.
626   # But be a bit subtle - use unicode decoding ambiguities to use different
627   # binary strings which have the same decoding.
628   def test_invalid_duplicate_tags
629     ## First make sure that you can't with a non-public user
630     # setup auth
631     basic_authorization(users(:normal_user).email, "test")
632
633     # add the tag into the existing xml
634     way_str = "<osm><way changeset='1'>"
635     way_str << "<tag k='addr:housenumber' v='1'/>"
636     way_str << "<tag k='addr:housenumber' v='2'/>"
637     way_str << "</way></osm>"
638
639     # try and upload it
640     content way_str
641     put :create
642     assert_response :forbidden,
643                     "adding new duplicate tags to a way with a non-public user should fail with 'forbidden'"
644
645     ## Now do it with a public user
646     # setup auth
647     basic_authorization(users(:public_user).email, "test")
648
649     # add the tag into the existing xml
650     way_str = "<osm><way changeset='1'>"
651     way_str << "<tag k='addr:housenumber' v='1'/>"
652     way_str << "<tag k='addr:housenumber' v='2'/>"
653     way_str << "</way></osm>"
654
655     # try and upload it
656     content way_str
657     put :create
658     assert_response :bad_request,
659                     "adding new duplicate tags to a way should fail with 'bad request'"
660     assert_equal "Element way/ has duplicate tags with key addr:housenumber", @response.body
661   end
662
663   ##
664   # test that a call to ways_for_node returns all ways that contain the node
665   # and none that don't.
666   def test_ways_for_node
667     # in current fixtures ways 1 and 3 all use node 3. ways 2 and 4
668     # *used* to use it but doesn't.
669     get :ways_for_node, :id => current_nodes(:used_node_1).id
670     assert_response :success
671     ways_xml = XML::Parser.string(@response.body).parse
672     assert_not_nil ways_xml, "failed to parse ways_for_node response"
673
674     # check that the set of IDs match expectations
675     expected_way_ids = [current_ways(:visible_way).id,
676                         current_ways(:used_way).id]
677     found_way_ids = ways_xml.find("//osm/way").collect { |w| w["id"].to_i }
678     assert_equal expected_way_ids.sort, found_way_ids.sort,
679                  "expected ways for node #{current_nodes(:used_node_1).id} did not match found"
680
681     # check the full ways to ensure we're not missing anything
682     expected_way_ids.each do |id|
683       way_xml = ways_xml.find("//osm/way[@id='#{id}']").first
684       assert_ways_are_equal(Way.find(id),
685                             Way.from_xml_node(way_xml))
686     end
687   end
688
689   ##
690   # update the changeset_id of a way element
691   def update_changeset(xml, changeset_id)
692     xml_attr_rewrite(xml, "changeset", changeset_id)
693   end
694
695   ##
696   # update an attribute in the way element
697   def xml_attr_rewrite(xml, name, value)
698     xml.find("//osm/way").first[name] = value.to_s
699     xml
700   end
701
702   ##
703   # replace a node in a way element
704   def xml_replace_node(xml, old_node, new_node)
705     xml.find("//osm/way/nd[@ref='#{old_node}']").first["ref"] = new_node.to_s
706     xml
707   end
708 end