+ ##
+ # check that relations are ordered
+ def test_relation_member_ordering
+ basic_authorization(users(:public_user).email, "test")
+
+ doc_str = <<OSM
+<osm>
+ <relation changeset='4'>
+ <member ref='1' type='node' role='first'/>
+ <member ref='3' type='node' role='second'/>
+ <member ref='1' type='way' role='third'/>
+ <member ref='3' type='way' role='fourth'/>
+ </relation>
+</osm>
+OSM
+ doc = XML::Parser.string(doc_str).parse
+
+ content doc
+ put :create
+ assert_response :success, "can't create a relation: #{@response.body}"
+ relation_id = @response.body.to_i
+
+ # get it back and check the ordering
+ get :read, :id => relation_id
+ assert_response :success, "can't read back the relation: #{@response.body}"
+ check_ordering(doc, @response.body)
+
+ # insert a member at the front
+ new_member = XML::Node.new "member"
+ new_member['ref'] = 5.to_s
+ new_member['type'] = 'node'
+ new_member['role'] = 'new first'
+ doc.find("//osm/relation").first.child.prev = new_member
+ # update the version, should be 1?
+ doc.find("//osm/relation").first['id'] = relation_id.to_s
+ doc.find("//osm/relation").first['version'] = 1.to_s
+
+ # upload the next version of the relation
+ content doc
+ put :update, :id => relation_id
+ assert_response :success, "can't update relation: #{@response.body}"
+ new_version = @response.body.to_i
+
+ # get it back again and check the ordering again
+ get :read, :id => relation_id
+ assert_response :success, "can't read back the relation: #{@response.body}"
+ check_ordering(doc, @response.body)
+
+ # check the ordering in the history tables:
+ with_controller(OldRelationController.new) do
+ get :version, :id => relation_id, :version => 2
+ assert_response :success, "can't read back version 2 of the relation #{relation_id}"
+ check_ordering(doc, @response.body)
+ end
+ end
+
+ ##
+ # check that relations can contain duplicate members
+ def test_relation_member_duplicates
+ doc_str = <<OSM
+<osm>
+ <relation changeset='4'>
+ <member ref='1' type='node' role='forward'/>
+ <member ref='3' type='node' role='forward'/>
+ <member ref='1' type='node' role='forward'/>
+ <member ref='3' type='node' role='forward'/>
+ </relation>
+</osm>
+OSM
+ doc = XML::Parser.string(doc_str).parse
+
+ ## First try with the private user
+ basic_authorization(users(:normal_user).email, "test");
+
+ content doc
+ put :create
+ assert_response :forbidden
+
+ ## Now try with the public user
+ basic_authorization(users(:public_user).email, "test");
+
+ content doc
+ put :create
+ assert_response :success, "can't create a relation: #{@response.body}"
+ relation_id = @response.body.to_i
+
+ # get it back and check the ordering
+ get :read, :id => relation_id
+ assert_response :success, "can't read back the relation: #{relation_id}"
+ check_ordering(doc, @response.body)
+ end
+
+ ##
+ # test that the ordering of elements in the history is the same as in current.
+ def test_history_ordering
+ doc_str = <<OSM
+<osm>
+ <relation changeset='4'>
+ <member ref='1' type='node' role='forward'/>
+ <member ref='5' type='node' role='forward'/>
+ <member ref='4' type='node' role='forward'/>
+ <member ref='3' type='node' role='forward'/>
+ </relation>
+</osm>
+OSM
+ doc = XML::Parser.string(doc_str).parse
+ basic_authorization(users(:public_user).email, "test");
+
+ content doc
+ put :create
+ assert_response :success, "can't create a relation: #{@response.body}"
+ relation_id = @response.body.to_i
+
+ # check the ordering in the current tables:
+ get :read, :id => relation_id
+ assert_response :success, "can't read back the relation: #{@response.body}"
+ check_ordering(doc, @response.body)
+
+ # check the ordering in the history tables:
+ with_controller(OldRelationController.new) do
+ get :version, :id => relation_id, :version => 1
+ assert_response :success, "can't read back version 1 of the relation: #{@response.body}"
+ check_ordering(doc, @response.body)
+ end
+ end
+
+ ##
+ # remove all the members from a relation. the result is pretty useless, but
+ # still technically valid.
+ def test_remove_all_members
+ check_changeset_modify(BoundingBox.new(3,3,5,5)) do |changeset_id|
+ relation_xml = current_relations(:visible_relation).to_xml
+ relation_xml.
+ find("//osm/relation/member").
+ each {|m| m.remove!}
+
+ # update changeset ID to point to new changeset
+ update_changeset(relation_xml, changeset_id)
+
+ # upload the change
+ content relation_xml
+ put :update, :id => current_relations(:visible_relation).id
+ assert_response :success, "can't update relation for remove all members test"
+ checkrelation = Relation.find(current_relations(:visible_relation).id)
+ assert_not_nil(checkrelation,
+ "uploaded relation not found in database after upload")
+ assert_equal(0, checkrelation.members.length,
+ "relation contains members but they should have all been deleted")
+ end
+ end
+
+ # ============================================================
+ # utility functions
+ # ============================================================
+
+ ##
+ # checks that the XML document and the string arguments have
+ # members in the same order.
+ def check_ordering(doc, xml)
+ new_doc = XML::Parser.string(xml).parse
+
+ doc_members = doc.find("//osm/relation/member").collect do |m|
+ [m['ref'].to_i, m['type'].to_sym, m['role']]
+ end
+
+ new_members = new_doc.find("//osm/relation/member").collect do |m|
+ [m['ref'].to_i, m['type'].to_sym, m['role']]
+ end
+
+ doc_members.zip(new_members).each do |d, n|
+ assert_equal d, n, "members are not equal - ordering is wrong? (#{doc}, #{xml})"
+ end
+ end
+