4   class WaysControllerTest < ActionDispatch::IntegrationTest
 
   6     # test all routes which lead to this controller
 
   9         { :path => "/api/0.6/way/create", :method => :put },
 
  10         { :controller => "api/ways", :action => "create" }
 
  13         { :path => "/api/0.6/way/1/full", :method => :get },
 
  14         { :controller => "api/ways", :action => "full", :id => "1" }
 
  17         { :path => "/api/0.6/way/1/full.json", :method => :get },
 
  18         { :controller => "api/ways", :action => "full", :id => "1", :format => "json" }
 
  21         { :path => "/api/0.6/way/1", :method => :get },
 
  22         { :controller => "api/ways", :action => "show", :id => "1" }
 
  25         { :path => "/api/0.6/way/1.json", :method => :get },
 
  26         { :controller => "api/ways", :action => "show", :id => "1", :format => "json" }
 
  29         { :path => "/api/0.6/way/1", :method => :put },
 
  30         { :controller => "api/ways", :action => "update", :id => "1" }
 
  33         { :path => "/api/0.6/way/1", :method => :delete },
 
  34         { :controller => "api/ways", :action => "delete", :id => "1" }
 
  37         { :path => "/api/0.6/ways", :method => :get },
 
  38         { :controller => "api/ways", :action => "index" }
 
  41         { :path => "/api/0.6/ways.json", :method => :get },
 
  42         { :controller => "api/ways", :action => "index", :format => "json" }
 
  46     # -------------------------------------
 
  48     # -------------------------------------
 
  51       # check that a visible way is returned properly
 
  52       get api_way_path(create(:way))
 
  53       assert_response :success
 
  55       # check that an invisible way is not returned
 
  56       get api_way_path(create(:way, :deleted))
 
  59       # check chat a non-existent way is not returned
 
  60       get api_way_path(:id => 0)
 
  61       assert_response :not_found
 
  65     # check the "full" mode
 
  67       way = create(:way_with_nodes, :nodes_count => 3)
 
  69       get way_full_path(way)
 
  71       assert_response :success
 
  73       # Check the way is correctly returned
 
  74       assert_select "osm way[id='#{way.id}'][version='1'][visible='true']", 1
 
  76       # check that each node in the way appears once in the output as a
 
  77       # reference and as the node element.
 
  79         assert_select "osm way nd[ref='#{n.id}']", 1
 
  80         assert_select "osm node[id='#{n.id}'][version='1'][lat='#{format('%<lat>.7f', :lat => n.lat)}'][lon='#{format('%<lon>.7f', :lon => n.lon)}']", 1
 
  85       way = create(:way, :deleted)
 
  87       get way_full_path(way)
 
  93     # test fetching multiple ways
 
  96       way2 = create(:way, :deleted)
 
 100       # check error when no parameter provided
 
 102       assert_response :bad_request
 
 104       # check error when no parameter value provided
 
 105       get ways_path, :params => { :ways => "" }
 
 106       assert_response :bad_request
 
 108       # test a working call
 
 109       get ways_path, :params => { :ways => "#{way1.id},#{way2.id},#{way3.id},#{way4.id}" }
 
 110       assert_response :success
 
 111       assert_select "osm" do
 
 112         assert_select "way", :count => 4
 
 113         assert_select "way[id='#{way1.id}'][visible='true']", :count => 1
 
 114         assert_select "way[id='#{way2.id}'][visible='false']", :count => 1
 
 115         assert_select "way[id='#{way3.id}'][visible='true']", :count => 1
 
 116         assert_select "way[id='#{way4.id}'][visible='true']", :count => 1
 
 119       # test a working call with json format
 
 120       get ways_path, :params => { :ways => "#{way1.id},#{way2.id},#{way3.id},#{way4.id}", :format => "json" }
 
 122       js = ActiveSupport::JSON.decode(@response.body)
 
 124       assert_equal 4, js["elements"].count
 
 125       assert_equal 4, (js["elements"].count { |a| a["type"] == "way" })
 
 126       assert_equal 1, (js["elements"].count { |a| a["id"] == way1.id && a["visible"].nil? })
 
 127       assert_equal 1, (js["elements"].count { |a| a["id"] == way2.id && a["visible"] == false })
 
 128       assert_equal 1, (js["elements"].count { |a| a["id"] == way3.id && a["visible"].nil? })
 
 129       assert_equal 1, (js["elements"].count { |a| a["id"] == way4.id && a["visible"].nil? })
 
 131       # check error when a non-existent way is included
 
 132       get ways_path, :params => { :ways => "#{way1.id},#{way2.id},#{way3.id},#{way4.id},0" }
 
 133       assert_response :not_found
 
 136     # -------------------------------------
 
 137     # Test simple way creation.
 
 138     # -------------------------------------
 
 141       node1 = create(:node)
 
 142       node2 = create(:node)
 
 143       private_user = create(:user, :data_public => false)
 
 144       private_changeset = create(:changeset, :user => private_user)
 
 146       changeset = create(:changeset, :user => user)
 
 148       ## First check that it fails when creating a way using a non-public user
 
 149       auth_header = basic_authorization_header private_user.email, "test"
 
 151       # use the first user's open changeset
 
 152       changeset_id = private_changeset.id
 
 154       # create a way with pre-existing nodes
 
 155       xml = "<osm><way changeset='#{changeset_id}'>" \
 
 156             "<nd ref='#{node1.id}'/><nd ref='#{node2.id}'/>" \
 
 157             "<tag k='test' v='yes' /></way></osm>"
 
 158       put way_create_path, :params => xml, :headers => auth_header
 
 160       assert_response :forbidden,
 
 161                       "way upload did not return forbidden status"
 
 163       ## Now use a public user
 
 164       auth_header = basic_authorization_header user.email, "test"
 
 166       # use the first user's open changeset
 
 167       changeset_id = changeset.id
 
 169       # create a way with pre-existing nodes
 
 170       xml = "<osm><way changeset='#{changeset_id}'>" \
 
 171             "<nd ref='#{node1.id}'/><nd ref='#{node2.id}'/>" \
 
 172             "<tag k='test' v='yes' /></way></osm>"
 
 173       put way_create_path, :params => xml, :headers => auth_header
 
 175       assert_response :success,
 
 176                       "way upload did not return success status"
 
 177       # read id of created way and search for it
 
 178       wayid = @response.body
 
 179       checkway = Way.find(wayid)
 
 180       assert_not_nil checkway,
 
 181                      "uploaded way not found in data base after upload"
 
 183       assert_equal(2, checkway.nds.length, "saved way does not contain exactly one node")
 
 184       assert_equal checkway.nds[0], node1.id,
 
 185                    "saved way does not contain the right node on pos 0"
 
 186       assert_equal checkway.nds[1], node2.id,
 
 187                    "saved way does not contain the right node on pos 1"
 
 188       assert_equal checkway.changeset_id, changeset_id,
 
 189                    "saved way does not belong to the correct changeset"
 
 190       assert_equal user.id, checkway.changeset.user_id,
 
 191                    "saved way does not belong to user that created it"
 
 192       assert checkway.visible,
 
 193              "saved way is not visible"
 
 196     # -------------------------------------
 
 197     # Test creating some invalid ways.
 
 198     # -------------------------------------
 
 200     def test_create_invalid
 
 202       private_user = create(:user, :data_public => false)
 
 203       private_open_changeset = create(:changeset, :user => private_user)
 
 204       private_closed_changeset = create(:changeset, :closed, :user => private_user)
 
 206       open_changeset = create(:changeset, :user => user)
 
 207       closed_changeset = create(:changeset, :closed, :user => user)
 
 209       ## First test with a private user to make sure that they are not authorized
 
 210       auth_header = basic_authorization_header private_user.email, "test"
 
 212       # use the first user's open changeset
 
 213       # create a way with non-existing node
 
 214       xml = "<osm><way changeset='#{private_open_changeset.id}'>" \
 
 215             "<nd ref='0'/><tag k='test' v='yes' /></way></osm>"
 
 216       put way_create_path, :params => xml, :headers => auth_header
 
 218       assert_response :forbidden,
 
 219                       "way upload with invalid node using a private user did not return 'forbidden'"
 
 221       # create a way with no nodes
 
 222       xml = "<osm><way changeset='#{private_open_changeset.id}'>" \
 
 223             "<tag k='test' v='yes' /></way></osm>"
 
 224       put way_create_path, :params => xml, :headers => auth_header
 
 226       assert_response :forbidden,
 
 227                       "way upload with no node using a private userdid not return 'forbidden'"
 
 229       # create a way inside a closed changeset
 
 230       xml = "<osm><way changeset='#{private_closed_changeset.id}'>" \
 
 231             "<nd ref='#{node.id}'/></way></osm>"
 
 232       put way_create_path, :params => xml, :headers => auth_header
 
 234       assert_response :forbidden,
 
 235                       "way upload to closed changeset with a private user did not return 'forbidden'"
 
 237       ## Now test with a public user
 
 238       auth_header = basic_authorization_header user.email, "test"
 
 240       # use the first user's open changeset
 
 241       # create a way with non-existing node
 
 242       xml = "<osm><way changeset='#{open_changeset.id}'>" \
 
 243             "<nd ref='0'/><tag k='test' v='yes' /></way></osm>"
 
 244       put way_create_path, :params => xml, :headers => auth_header
 
 246       assert_response :precondition_failed,
 
 247                       "way upload with invalid node did not return 'precondition failed'"
 
 248       assert_equal "Precondition failed: Way  requires the nodes with id in (0), which either do not exist, or are not visible.", @response.body
 
 250       # create a way with no nodes
 
 251       xml = "<osm><way changeset='#{open_changeset.id}'>" \
 
 252             "<tag k='test' v='yes' /></way></osm>"
 
 253       put way_create_path, :params => xml, :headers => auth_header
 
 255       assert_response :precondition_failed,
 
 256                       "way upload with no node did not return 'precondition failed'"
 
 257       assert_equal "Precondition failed: Cannot create way: data is invalid.", @response.body
 
 259       # create a way inside a closed changeset
 
 260       xml = "<osm><way changeset='#{closed_changeset.id}'>" \
 
 261             "<nd ref='#{node.id}'/></way></osm>"
 
 262       put way_create_path, :params => xml, :headers => auth_header
 
 264       assert_response :conflict,
 
 265                       "way upload to closed changeset did not return 'conflict'"
 
 267       # create a way with a tag which is too long
 
 268       xml = "<osm><way changeset='#{open_changeset.id}'>" \
 
 269             "<nd ref='#{node.id}'/>" \
 
 270             "<tag k='foo' v='#{'x' * 256}'/>" \
 
 272       put way_create_path, :params => xml, :headers => auth_header
 
 274       assert_response :bad_request,
 
 275                       "way upload to with too long tag did not return 'bad_request'"
 
 278     # -------------------------------------
 
 279     # Test deleting ways.
 
 280     # -------------------------------------
 
 283       private_user = create(:user, :data_public => false)
 
 284       private_open_changeset = create(:changeset, :user => private_user)
 
 285       private_closed_changeset = create(:changeset, :closed, :user => private_user)
 
 286       private_way = create(:way, :changeset => private_open_changeset)
 
 287       private_deleted_way = create(:way, :deleted, :changeset => private_open_changeset)
 
 288       private_used_way = create(:way, :changeset => private_open_changeset)
 
 289       create(:relation_member, :member => private_used_way)
 
 291       open_changeset = create(:changeset, :user => user)
 
 292       closed_changeset = create(:changeset, :closed, :user => user)
 
 293       way = create(:way, :changeset => open_changeset)
 
 294       deleted_way = create(:way, :deleted, :changeset => open_changeset)
 
 295       used_way = create(:way, :changeset => open_changeset)
 
 296       relation_member = create(:relation_member, :member => used_way)
 
 297       relation = relation_member.relation
 
 299       # first try to delete way without auth
 
 300       delete api_way_path(way)
 
 301       assert_response :unauthorized
 
 303       # now set auth using the private user
 
 304       auth_header = basic_authorization_header private_user.email, "test"
 
 306       # this shouldn't work as with the 0.6 api we need pay load to delete
 
 307       delete api_way_path(private_way), :headers => auth_header
 
 308       assert_response :forbidden
 
 310       # Now try without having a changeset
 
 311       xml = "<osm><way id='#{private_way.id}'/></osm>"
 
 312       delete api_way_path(private_way), :params => xml.to_s, :headers => auth_header
 
 313       assert_response :forbidden
 
 315       # try to delete with an invalid (closed) changeset
 
 316       xml = update_changeset(xml_for_way(private_way), private_closed_changeset.id)
 
 317       delete api_way_path(private_way), :params => xml.to_s, :headers => auth_header
 
 318       assert_response :forbidden
 
 320       # try to delete with an invalid (non-existent) changeset
 
 321       xml = update_changeset(xml_for_way(private_way), 0)
 
 322       delete api_way_path(private_way), :params => xml.to_s, :headers => auth_header
 
 323       assert_response :forbidden
 
 325       # Now try with a valid changeset
 
 326       xml = xml_for_way(private_way)
 
 327       delete api_way_path(private_way), :params => xml.to_s, :headers => auth_header
 
 328       assert_response :forbidden
 
 330       # check the returned value - should be the new version number
 
 331       # valid delete should return the new version number, which should
 
 332       # be greater than the old version number
 
 333       # assert @response.body.to_i > current_ways(:visible_way).version,
 
 334       #   "delete request should return a new version number for way"
 
 336       # this won't work since the way is already deleted
 
 337       xml = xml_for_way(private_deleted_way)
 
 338       delete api_way_path(private_deleted_way), :params => xml.to_s, :headers => auth_header
 
 339       assert_response :forbidden
 
 341       # this shouldn't work as the way is used in a relation
 
 342       xml = xml_for_way(private_used_way)
 
 343       delete api_way_path(private_used_way), :params => xml.to_s, :headers => auth_header
 
 344       assert_response :forbidden,
 
 345                       "shouldn't be able to delete a way used in a relation (#{@response.body}), when done by a private user"
 
 347       # this won't work since the way never existed
 
 348       delete api_way_path(:id => 0), :headers => auth_header
 
 349       assert_response :forbidden
 
 351       ### Now check with a public user
 
 353       auth_header = basic_authorization_header user.email, "test"
 
 355       # this shouldn't work as with the 0.6 api we need pay load to delete
 
 356       delete api_way_path(way), :headers => auth_header
 
 357       assert_response :bad_request
 
 359       # Now try without having a changeset
 
 360       xml = "<osm><way id='#{way.id}'/></osm>"
 
 361       delete api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 362       assert_response :bad_request
 
 364       # try to delete with an invalid (closed) changeset
 
 365       xml = update_changeset(xml_for_way(way), closed_changeset.id)
 
 366       delete api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 367       assert_response :conflict
 
 369       # try to delete with an invalid (non-existent) changeset
 
 370       xml = update_changeset(xml_for_way(way), 0)
 
 371       delete api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 372       assert_response :conflict
 
 374       # Now try with a valid changeset
 
 375       xml = xml_for_way(way)
 
 376       delete api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 377       assert_response :success
 
 379       # check the returned value - should be the new version number
 
 380       # valid delete should return the new version number, which should
 
 381       # be greater than the old version number
 
 382       assert @response.body.to_i > way.version,
 
 383              "delete request should return a new version number for way"
 
 385       # this won't work since the way is already deleted
 
 386       xml = xml_for_way(deleted_way)
 
 387       delete api_way_path(deleted_way), :params => xml.to_s, :headers => auth_header
 
 388       assert_response :gone
 
 390       # this shouldn't work as the way is used in a relation
 
 391       xml = xml_for_way(used_way)
 
 392       delete api_way_path(used_way), :params => xml.to_s, :headers => auth_header
 
 393       assert_response :precondition_failed,
 
 394                       "shouldn't be able to delete a way used in a relation (#{@response.body})"
 
 395       assert_equal "Precondition failed: Way #{used_way.id} is still used by relations #{relation.id}.", @response.body
 
 397       # this won't work since the way never existed
 
 398       delete api_way_path(:id => 0), :params => xml.to_s, :headers => auth_header
 
 399       assert_response :not_found
 
 403     # tests whether the API works and prevents incorrect use while trying
 
 406       private_user = create(:user, :data_public => false)
 
 407       private_way = create(:way, :changeset => create(:changeset, :user => private_user))
 
 409       way = create(:way, :changeset => create(:changeset, :user => user))
 
 411       create(:way_node, :way => private_way, :node => node)
 
 412       create(:way_node, :way => way, :node => node)
 
 414       ## First test with no user credentials
 
 415       # try and update a way without authorisation
 
 416       xml = xml_for_way(way)
 
 417       put api_way_path(way), :params => xml.to_s
 
 418       assert_response :unauthorized
 
 420       ## Second test with the private user
 
 423       auth_header = basic_authorization_header private_user.email, "test"
 
 425       ## trying to break changesets
 
 427       # try and update in someone else's changeset
 
 428       xml = update_changeset(xml_for_way(private_way),
 
 429                              create(:changeset).id)
 
 430       put api_way_path(private_way), :params => xml.to_s, :headers => auth_header
 
 431       assert_require_public_data "update with other user's changeset should be forbidden when date isn't public"
 
 433       # try and update in a closed changeset
 
 434       xml = update_changeset(xml_for_way(private_way),
 
 435                              create(:changeset, :closed, :user => private_user).id)
 
 436       put api_way_path(private_way), :params => xml.to_s, :headers => auth_header
 
 437       assert_require_public_data "update with closed changeset should be forbidden, when data isn't public"
 
 439       # try and update in a non-existant changeset
 
 440       xml = update_changeset(xml_for_way(private_way), 0)
 
 441       put api_way_path(private_way), :params => xml.to_s, :headers => auth_header
 
 442       assert_require_public_data("update with changeset=0 should be forbidden, when data isn't public")
 
 444       ## try and submit invalid updates
 
 445       xml = xml_replace_node(xml_for_way(private_way), node.id, 9999)
 
 446       put api_way_path(private_way), :params => xml.to_s, :headers => auth_header
 
 447       assert_require_public_data "way with non-existent node should be forbidden, when data isn't public"
 
 449       xml = xml_replace_node(xml_for_way(private_way), node.id, create(:node, :deleted).id)
 
 450       put api_way_path(private_way), :params => xml.to_s, :headers => auth_header
 
 451       assert_require_public_data "way with deleted node should be forbidden, when data isn't public"
 
 453       ## finally, produce a good request which will still not work
 
 454       xml = xml_for_way(private_way)
 
 455       put api_way_path(private_way), :params => xml.to_s, :headers => auth_header
 
 456       assert_require_public_data "should have failed with a forbidden when data isn't public"
 
 458       ## Finally test with the public user
 
 461       auth_header = basic_authorization_header user.email, "test"
 
 463       ## trying to break changesets
 
 465       # try and update in someone else's changeset
 
 466       xml = update_changeset(xml_for_way(way),
 
 467                              create(:changeset).id)
 
 468       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 469       assert_response :conflict, "update with other user's changeset should be rejected"
 
 471       # try and update in a closed changeset
 
 472       xml = update_changeset(xml_for_way(way),
 
 473                              create(:changeset, :closed, :user => user).id)
 
 474       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 475       assert_response :conflict, "update with closed changeset should be rejected"
 
 477       # try and update in a non-existant changeset
 
 478       xml = update_changeset(xml_for_way(way), 0)
 
 479       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 480       assert_response :conflict, "update with changeset=0 should be rejected"
 
 482       ## try and submit invalid updates
 
 483       xml = xml_replace_node(xml_for_way(way), node.id, 9999)
 
 484       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 485       assert_response :precondition_failed, "way with non-existent node should be rejected"
 
 487       xml = xml_replace_node(xml_for_way(way), node.id, create(:node, :deleted).id)
 
 488       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 489       assert_response :precondition_failed, "way with deleted node should be rejected"
 
 491       ## next, attack the versioning
 
 492       current_way_version = way.version
 
 494       # try and submit a version behind
 
 495       xml = xml_attr_rewrite(xml_for_way(way),
 
 496                              "version", current_way_version - 1)
 
 497       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 498       assert_response :conflict, "should have failed on old version number"
 
 500       # try and submit a version ahead
 
 501       xml = xml_attr_rewrite(xml_for_way(way),
 
 502                              "version", current_way_version + 1)
 
 503       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 504       assert_response :conflict, "should have failed on skipped version number"
 
 506       # try and submit total crap in the version field
 
 507       xml = xml_attr_rewrite(xml_for_way(way),
 
 508                              "version", "p1r4t3s!")
 
 509       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 510       assert_response :conflict,
 
 511                       "should not be able to put 'p1r4at3s!' in the version field"
 
 513       ## try an update with the wrong ID
 
 514       xml = xml_for_way(create(:way))
 
 515       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 516       assert_response :bad_request,
 
 517                       "should not be able to update a way with a different ID from the XML"
 
 519       ## try an update with a minimal valid XML doc which isn't a well-formed OSM doc.
 
 521       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 522       assert_response :bad_request,
 
 523                       "should not be able to update a way with non-OSM XML doc."
 
 525       ## finally, produce a good request which should work
 
 526       xml = xml_for_way(way)
 
 527       put api_way_path(way), :params => xml.to_s, :headers => auth_header
 
 528       assert_response :success, "a valid update request failed"
 
 531     # ------------------------------------------------------------
 
 533     # ------------------------------------------------------------
 
 536     # Try adding a new tag to a way
 
 538       private_user = create(:user, :data_public => false)
 
 539       private_way = create(:way_with_nodes, :nodes_count => 2, :changeset => create(:changeset, :user => private_user))
 
 541       way = create(:way_with_nodes, :nodes_count => 2, :changeset => create(:changeset, :user => user))
 
 543       ## Try with the non-public user
 
 545       auth_header = basic_authorization_header private_user.email, "test"
 
 547       # add an identical tag to the way
 
 548       tag_xml = XML::Node.new("tag")
 
 552       # add the tag into the existing xml
 
 553       way_xml = xml_for_way(private_way)
 
 554       way_xml.find("//osm/way").first << tag_xml
 
 557       put api_way_path(private_way), :params => way_xml.to_s, :headers => auth_header
 
 558       assert_response :forbidden,
 
 559                       "adding a duplicate tag to a way for a non-public should fail with 'forbidden'"
 
 561       ## Now try with the public user
 
 563       auth_header = basic_authorization_header user.email, "test"
 
 565       # add an identical tag to the way
 
 566       tag_xml = XML::Node.new("tag")
 
 570       # add the tag into the existing xml
 
 571       way_xml = xml_for_way(way)
 
 572       way_xml.find("//osm/way").first << tag_xml
 
 575       put api_way_path(way), :params => way_xml.to_s, :headers => auth_header
 
 576       assert_response :success,
 
 577                       "adding a new tag to a way should succeed"
 
 578       assert_equal way.version + 1, @response.body.to_i
 
 582     # Try adding a duplicate of an existing tag to a way
 
 583     def test_add_duplicate_tags
 
 584       private_user = create(:user, :data_public => false)
 
 585       private_way = create(:way, :changeset => create(:changeset, :user => private_user))
 
 586       private_existing_tag = create(:way_tag, :way => private_way)
 
 588       way = create(:way, :changeset => create(:changeset, :user => user))
 
 589       existing_tag = create(:way_tag, :way => way)
 
 591       ## Try with the non-public user
 
 593       auth_header = basic_authorization_header private_user.email, "test"
 
 595       # add an identical tag to the way
 
 596       tag_xml = XML::Node.new("tag")
 
 597       tag_xml["k"] = private_existing_tag.k
 
 598       tag_xml["v"] = private_existing_tag.v
 
 600       # add the tag into the existing xml
 
 601       way_xml = xml_for_way(private_way)
 
 602       way_xml.find("//osm/way").first << tag_xml
 
 605       put api_way_path(private_way), :params => way_xml.to_s, :headers => auth_header
 
 606       assert_response :forbidden,
 
 607                       "adding a duplicate tag to a way for a non-public should fail with 'forbidden'"
 
 609       ## Now try with the public user
 
 611       auth_header = basic_authorization_header user.email, "test"
 
 613       # add an identical tag to the way
 
 614       tag_xml = XML::Node.new("tag")
 
 615       tag_xml["k"] = existing_tag.k
 
 616       tag_xml["v"] = existing_tag.v
 
 618       # add the tag into the existing xml
 
 619       way_xml = xml_for_way(way)
 
 620       way_xml.find("//osm/way").first << tag_xml
 
 623       put api_way_path(way), :params => way_xml.to_s, :headers => auth_header
 
 624       assert_response :bad_request,
 
 625                       "adding a duplicate tag to a way should fail with 'bad request'"
 
 626       assert_equal "Element way/#{way.id} has duplicate tags with key #{existing_tag.k}", @response.body
 
 630     # Try adding a new duplicate tags to a way
 
 631     def test_new_duplicate_tags
 
 632       private_user = create(:user, :data_public => false)
 
 633       private_way = create(:way, :changeset => create(:changeset, :user => private_user))
 
 635       way = create(:way, :changeset => create(:changeset, :user => user))
 
 637       ## First test with the non-public user so should be rejected
 
 639       auth_header = basic_authorization_header private_user.email, "test"
 
 641       # create duplicate tag
 
 642       tag_xml = XML::Node.new("tag")
 
 643       tag_xml["k"] = "i_am_a_duplicate"
 
 644       tag_xml["v"] = "foobar"
 
 646       # add the tag into the existing xml
 
 647       way_xml = xml_for_way(private_way)
 
 649       # add two copies of the tag
 
 650       way_xml.find("//osm/way").first << tag_xml.copy(true) << tag_xml
 
 653       put api_way_path(private_way), :params => way_xml.to_s, :headers => auth_header
 
 654       assert_response :forbidden,
 
 655                       "adding new duplicate tags to a way using a non-public user should fail with 'forbidden'"
 
 657       ## Now test with the public user
 
 659       auth_header = basic_authorization_header user.email, "test"
 
 661       # create duplicate tag
 
 662       tag_xml = XML::Node.new("tag")
 
 663       tag_xml["k"] = "i_am_a_duplicate"
 
 664       tag_xml["v"] = "foobar"
 
 666       # add the tag into the existing xml
 
 667       way_xml = xml_for_way(way)
 
 669       # add two copies of the tag
 
 670       way_xml.find("//osm/way").first << tag_xml.copy(true) << tag_xml
 
 673       put api_way_path(way), :params => way_xml.to_s, :headers => auth_header
 
 674       assert_response :bad_request,
 
 675                       "adding new duplicate tags to a way should fail with 'bad request'"
 
 676       assert_equal "Element way/#{way.id} has duplicate tags with key i_am_a_duplicate", @response.body
 
 680     # Try adding a new duplicate tags to a way.
 
 681     # But be a bit subtle - use unicode decoding ambiguities to use different
 
 682     # binary strings which have the same decoding.
 
 683     def test_invalid_duplicate_tags
 
 684       private_user = create(:user, :data_public => false)
 
 685       private_changeset = create(:changeset, :user => private_user)
 
 687       changeset = create(:changeset, :user => user)
 
 689       ## First make sure that you can't with a non-public user
 
 691       auth_header = basic_authorization_header private_user.email, "test"
 
 693       # add the tag into the existing xml
 
 694       way_str = "<osm><way changeset='#{private_changeset.id}'>"
 
 695       way_str << "<tag k='addr:housenumber' v='1'/>"
 
 696       way_str << "<tag k='addr:housenumber' v='2'/>"
 
 697       way_str << "</way></osm>"
 
 700       put way_create_path, :params => way_str, :headers => auth_header
 
 701       assert_response :forbidden,
 
 702                       "adding new duplicate tags to a way with a non-public user should fail with 'forbidden'"
 
 704       ## Now do it with a public user
 
 706       auth_header = basic_authorization_header user.email, "test"
 
 708       # add the tag into the existing xml
 
 709       way_str = "<osm><way changeset='#{changeset.id}'>"
 
 710       way_str << "<tag k='addr:housenumber' v='1'/>"
 
 711       way_str << "<tag k='addr:housenumber' v='2'/>"
 
 712       way_str << "</way></osm>"
 
 715       put way_create_path, :params => way_str, :headers => auth_header
 
 716       assert_response :bad_request,
 
 717                       "adding new duplicate tags to a way should fail with 'bad request'"
 
 718       assert_equal "Element way/ has duplicate tags with key addr:housenumber", @response.body
 
 722     # test that a call to ways_for_node returns all ways that contain the node
 
 723     # and none that don't.
 
 724     def test_ways_for_node
 
 728       create(:way_node, :way => way1, :node => node)
 
 729       create(:way_node, :way => way2, :node => node)
 
 730       # create an unrelated way
 
 731       create(:way_with_nodes, :nodes_count => 2)
 
 732       # create a way which used to use the node
 
 733       way3_v1 = create(:old_way, :version => 1)
 
 734       _way3_v2 = create(:old_way, :current_way => way3_v1.current_way, :version => 2)
 
 735       create(:old_way_node, :old_way => way3_v1, :node => node)
 
 737       get node_ways_path(node)
 
 738       assert_response :success
 
 739       ways_xml = XML::Parser.string(@response.body).parse
 
 740       assert_not_nil ways_xml, "failed to parse ways_for_node response"
 
 742       # check that the set of IDs match expectations
 
 743       expected_way_ids = [way1.id,
 
 745       found_way_ids = ways_xml.find("//osm/way").collect { |w| w["id"].to_i }
 
 746       assert_equal expected_way_ids.sort, found_way_ids.sort,
 
 747                    "expected ways for node #{node.id} did not match found"
 
 749       # check the full ways to ensure we're not missing anything
 
 750       expected_way_ids.each do |id|
 
 751         way_xml = ways_xml.find("//osm/way[@id='#{id}']").first
 
 752         assert_ways_are_equal(Way.find(id),
 
 753                               Way.from_xml_node(way_xml))
 
 760     # update the changeset_id of a way element
 
 761     def update_changeset(xml, changeset_id)
 
 762       xml_attr_rewrite(xml, "changeset", changeset_id)
 
 766     # update an attribute in the way element
 
 767     def xml_attr_rewrite(xml, name, value)
 
 768       xml.find("//osm/way").first[name] = value.to_s
 
 773     # replace a node in a way element
 
 774     def xml_replace_node(xml, old_node, new_node)
 
 775       xml.find("//osm/way/nd[@ref='#{old_node}']").first["ref"] = new_node.to_s