Merge 12304:14009 from trunk.
[rails.git] / test / functional / relation_controller_test.rb
index 5f23702db4c3891de137252bf70409a1977c07d6..f52981233371097a9cd3ad94a1a25f592b5c5405 100644 (file)
@@ -117,10 +117,45 @@ class RelationControllerTest < ActionController::TestCase
     assert_response :success
 
 
+    ###
     # create an relation with a node as member
+    # This time try with a role attribute in the relation
     nid = current_nodes(:used_node_1).id
     content "<osm><relation changeset='#{changeset_id}'>" +
-      "<member type='node' ref='#{nid}' role='some'/>" +
+      "<member  ref='#{nid}' type='node' role='some'/>" +
+      "<tag k='test' v='yes' /></relation></osm>"
+    put :create
+    # hope for success
+    assert_response :success, 
+        "relation upload did not return success status"
+    # read id of created relation and search for it
+    relationid = @response.body
+    checkrelation = Relation.find(relationid)
+    assert_not_nil checkrelation, 
+        "uploaded relation not found in data base after upload"
+    # compare values
+    assert_equal checkrelation.members.length, 1, 
+        "saved relation does not contain exactly one member"
+    assert_equal checkrelation.tags.length, 1, 
+        "saved relation does not contain exactly one tag"
+    assert_equal changeset_id, checkrelation.changeset.id,
+        "saved relation does not belong in the changeset it was assigned to"
+    assert_equal users(:normal_user).id, checkrelation.changeset.user_id, 
+        "saved relation does not belong to user that created it"
+    assert_equal true, checkrelation.visible, 
+        "saved relation is not visible"
+    # ok the relation is there but can we also retrieve it?
+    
+    get :read, :id => relationid
+    assert_response :success
+    
+    
+    ###
+    # create an relation with a node as member, this time test that we don't 
+    # need a role attribute to be included
+    nid = current_nodes(:used_node_1).id
+    content "<osm><relation changeset='#{changeset_id}'>" +
+      "<member  ref='#{nid}' type='node'/>"+
       "<tag k='test' v='yes' /></relation></osm>"
     put :create
     # hope for success
@@ -147,6 +182,7 @@ class RelationControllerTest < ActionController::TestCase
     get :read, :id => relationid
     assert_response :success
 
+    ###
     # create an relation with a way and a node as members
     nid = current_nodes(:used_node_1).id
     wid = current_ways(:used_way).id
@@ -200,6 +236,27 @@ class RelationControllerTest < ActionController::TestCase
         "relation upload with invalid node did not return 'precondition failed'"
   end
 
+  # -------------------------------------
+  # Test creating a relation, with some invalid XML
+  # -------------------------------------
+  def test_create_invalid_xml
+    basic_authorization "test@openstreetmap.org", "test"
+    
+    # put the relation in a dummy fixture changeset that works
+    changeset_id = changesets(:normal_user_first_change).id
+    
+    # create some xml that should return an error
+    content "<osm><relation changeset='#{changeset_id}'>" +
+    "<member type='type' ref='#{current_nodes(:used_node_1).id}' role=''/>" +
+    "<tag k='tester' v='yep'/></relation></osm>"
+    put :create
+    # expect failure
+    assert_response :bad_request
+    assert_match(/Cannot parse valid relation from xml string/, @response.body)
+    assert_match(/The type is not allowed only, /, @response.body)
+  end
+  
+  
   # -------------------------------------
   # Test deleting relations.
   # -------------------------------------
@@ -219,7 +276,8 @@ class RelationControllerTest < ActionController::TestCase
     # try to delete without specifying a changeset
     content "<osm><relation id='#{current_relations(:visible_relation).id}'/></osm>"
     delete :delete, :id => current_relations(:visible_relation).id
-    assert_response :conflict
+    assert_response :bad_request
+    assert_match(/You are missing the required changeset in the relation/, @response.body)
 
     # try to delete with an invalid (closed) changeset
     content update_changeset(current_relations(:visible_relation).to_xml,
@@ -335,6 +393,106 @@ class RelationControllerTest < ActionController::TestCase
     end
   end
   
+  ##
+  # check that relations are ordered
+  def test_relation_member_ordering
+    basic_authorization("test@openstreetmap.org", "test");  
+
+    doc_str = <<OSM
+<osm>
+ <relation changeset='1'>
+  <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)
+  end
+
+  ## 
+  # check that relations can contain duplicate members
+  def test_relation_member_duplicates
+    basic_authorization("test@openstreetmap.org", "test");  
+
+    doc_str = <<OSM
+<osm>
+ <relation changeset='1'>
+  <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
+
+    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)
+  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
+
   ##
   # create a changeset and yield to the caller to set it up, then assert
   # that the changeset bounding box is +bbox+.
@@ -359,10 +517,10 @@ class RelationControllerTest < ActionController::TestCase
       assert_response :success, "can't re-read changeset for modify test"
       assert_select "osm>changeset", 1
       assert_select "osm>changeset[id=#{changeset_id}]", 1
-      assert_select "osm>changeset[min_lon=#{bbox[0]}]", 1
-      assert_select "osm>changeset[min_lat=#{bbox[1]}]", 1
-      assert_select "osm>changeset[max_lon=#{bbox[2]}]", 1
-      assert_select "osm>changeset[max_lat=#{bbox[3]}]", 1
+      assert_select "osm>changeset[min_lon=#{bbox[0].to_f}]", 1
+      assert_select "osm>changeset[min_lat=#{bbox[1].to_f}]", 1
+      assert_select "osm>changeset[max_lon=#{bbox[2].to_f}]", 1
+      assert_select "osm>changeset[max_lat=#{bbox[3].to_f}]", 1
     end
   end
 
@@ -382,8 +540,7 @@ class RelationControllerTest < ActionController::TestCase
   ##
   # parse some xml
   def xml_parse(xml)
-    parser = XML::Parser.new
-    parser.string = xml
+    parser = XML::Parser.string(xml)
     parser.parse
   end
 end