Update more relation_controller tests to use factories.
[rails.git] / test / controllers / amf_controller_test.rb
1 require "test_helper"
2 require "stringio"
3 include Potlatch
4
5 class AmfControllerTest < ActionController::TestCase
6   api_fixtures
7
8   ##
9   # test all routes which lead to this controller
10   def test_routes
11     assert_routing(
12       { :path => "/api/0.6/amf/read", :method => :post },
13       { :controller => "amf", :action => "amf_read" }
14     )
15     assert_routing(
16       { :path => "/api/0.6/amf/write", :method => :post },
17       { :controller => "amf", :action => "amf_write" }
18     )
19   end
20
21   def test_getpresets
22     user_en_de = create(:user, :languages => %w(en de))
23     user_de = create(:user, :languages => %w(de))
24     [user_en_de, user_de].each do |user|
25       amf_content "getpresets", "/1", ["#{user.email}:test", ""]
26       post :amf_read
27       assert_response :success
28       amf_parse_response
29       presets = amf_result("/1")
30
31       assert_equal 15, presets.length
32       assert_equal POTLATCH_PRESETS[0], presets[0]
33       assert_equal POTLATCH_PRESETS[1], presets[1]
34       assert_equal POTLATCH_PRESETS[2], presets[2]
35       assert_equal POTLATCH_PRESETS[3], presets[3]
36       assert_equal POTLATCH_PRESETS[4], presets[4]
37       assert_equal POTLATCH_PRESETS[5], presets[5]
38       assert_equal POTLATCH_PRESETS[6], presets[6]
39       assert_equal POTLATCH_PRESETS[7], presets[7]
40       assert_equal POTLATCH_PRESETS[8], presets[8]
41       assert_equal POTLATCH_PRESETS[9], presets[9]
42       assert_equal POTLATCH_PRESETS[10], presets[10]
43       assert_equal POTLATCH_PRESETS[12], presets[12]
44       assert_equal user.languages.first, presets[13]["__potlatch_locale"]
45     end
46   end
47
48   def test_getway
49     # check a visible way
50     way = create(:way_with_nodes, :nodes_count => 1)
51     node = way.nodes.first
52     user = way.changeset.user
53
54     amf_content "getway", "/1", [way.id]
55     post :amf_read
56     assert_response :success
57     amf_parse_response
58     result = amf_result("/1")
59     assert_equal 0, result[0]
60     assert_equal "", result[1]
61     assert_equal way.id, result[2]
62     assert_equal 1, result[3].length
63     assert_equal node.id, result[3][0][2]
64     assert_equal way.version, result[5]
65     assert_equal user.id, result[6]
66   end
67
68   def test_getway_invisible
69     # check an invisible way
70     id = create(:way, :deleted).id
71
72     amf_content "getway", "/1", [id]
73     post :amf_read
74     assert_response :success
75     amf_parse_response
76     result = amf_result("/1")
77     assert_equal -4, result[0]
78     assert_equal "way", result[1]
79     assert_equal id, result[2]
80     assert(result[3].nil? && result[4].nil? && result[5].nil? && result[6].nil?)
81   end
82
83   def test_getway_with_versions
84     # check a way with multiple versions
85     way = create(:way, :with_history, :version => 4)
86     create(:way_node, :way => way)
87     node = way.nodes.first
88     user = way.changeset.user
89
90     amf_content "getway", "/1", [way.id]
91     post :amf_read
92     assert_response :success
93     amf_parse_response
94     result = amf_result("/1")
95     assert_equal 0, result[0]
96     assert_equal "", result[1]
97     assert_equal way.id, result[2]
98     assert_equal 1, result[3].length
99     assert_equal node.id, result[3][0][2]
100     assert_equal way.version, result[5]
101     assert_equal user.id, result[6]
102   end
103
104   def test_getway_with_duplicate_nodes
105     # check a way with duplicate nodes
106     way = create(:way)
107     node = create(:node)
108     create(:way_node, :way => way, :node => node, :sequence_id => 1)
109     create(:way_node, :way => way, :node => node, :sequence_id => 2)
110     user = way.changeset.user
111
112     amf_content "getway", "/1", [way.id]
113     post :amf_read
114     assert_response :success
115     amf_parse_response
116     result = amf_result("/1")
117     assert_equal 0, result[0]
118     assert_equal "", result[1]
119     assert_equal way.id, result[2]
120     assert_equal 2, result[3].length
121     assert_equal node.id, result[3][0][2]
122     assert_equal node.id, result[3][1][2]
123     assert_equal way.version, result[5]
124     assert_equal user.id, result[6]
125   end
126
127   def test_getway_with_multiple_nodes
128     # check a way with multiple nodes
129     way = create(:way_with_nodes, :nodes_count => 3)
130     a = way.nodes[0].id
131     b = way.nodes[1].id
132     c = way.nodes[2].id
133     user = way.changeset.user
134
135     amf_content "getway", "/1", [way.id]
136     post :amf_read
137     assert_response :success
138     amf_parse_response
139     result = amf_result("/1")
140     assert_equal 0, result[0]
141     assert_equal "", result[1]
142     assert_equal way.id, result[2]
143     assert_equal 3, result[3].length
144     assert_equal a, result[3][0][2]
145     assert_equal b, result[3][1][2]
146     assert_equal c, result[3][2][2]
147     assert_equal way.version, result[5]
148     assert_equal user.id, result[6]
149   end
150
151   def test_getway_nonexistent
152     # check chat a non-existent way is not returned
153     amf_content "getway", "/1", [0]
154     post :amf_read
155     assert_response :success
156     amf_parse_response
157     way = amf_result("/1")
158     assert_equal -4, way[0]
159     assert_equal "way", way[1]
160     assert_equal 0, way[2]
161     assert(way[3].nil?) && way[4].nil? && way[5].nil? && way[6].nil?
162   end
163
164   def test_whichways
165     node = create(:node, :lat => 3.0, :lon => 3.0)
166     way = create(:way)
167     deleted_way = create(:way, :deleted)
168     create(:way_node, :way => way, :node => node)
169     create(:way_node, :way => deleted_way, :node => node)
170     create(:way_tag, :way => way)
171
172     minlon = node.lon - 0.1
173     minlat = node.lat - 0.1
174     maxlon = node.lon + 0.1
175     maxlat = node.lat + 0.1
176     amf_content "whichways", "/1", [minlon, minlat, maxlon, maxlat]
177     post :amf_read
178     assert_response :success
179     amf_parse_response
180
181     # check contents of message
182     map = amf_result "/1"
183     assert_equal 0, map[0], "map error code should be 0"
184     assert_equal "", map[1], "map error text should be empty"
185
186     # check the formatting of the message
187     assert_equal 5, map.length, "map should have length 5"
188     assert_equal Array, map[2].class, 'map "ways" element should be an array'
189     assert_equal Array, map[3].class, 'map "nodes" element should be an array'
190     assert_equal Array, map[4].class, 'map "relations" element should be an array'
191     map[2].each do |w|
192       assert_equal 2, w.length, "way should be (id, version) pair"
193       assert w[0] == w[0].floor, "way ID should be an integer"
194       assert w[1] == w[1].floor, "way version should be an integer"
195     end
196
197     map[3].each do |n|
198       assert_equal 5, w.length, "node should be (id, lat, lon, [tags], version) tuple"
199       assert n[0] == n[0].floor, "node ID should be an integer"
200       assert n[1] >= minlat - 0.01, "node lat should be greater than min"
201       assert n[1] <= maxlat - 0.01, "node lat should be less than max"
202       assert n[2] >= minlon - 0.01, "node lon should be greater than min"
203       assert n[2] <= maxlon - 0.01, "node lon should be less than max"
204       assert_equal Array, a[3].class, "node tags should be array"
205       assert n[4] == n[4].floor, "node version should be an integer"
206     end
207
208     map[4].each do |r|
209       assert_equal 2, r.length, "relation should be (id, version) pair"
210       assert r[0] == r[0].floor, "relation ID should be an integer"
211       assert r[1] == r[1].floor, "relation version should be an integer"
212     end
213
214     # TODO: looks like amf_controller changed since this test was written
215     # so someone who knows what they're doing should check this!
216     ways = map[2].collect { |x| x[0] }
217     assert ways.include?(way.id),
218            "map should include used way"
219     assert !ways.include?(deleted_way.id),
220            "map should not include deleted way"
221   end
222
223   ##
224   # checks that too-large a bounding box will not be served.
225   def test_whichways_toobig
226     bbox = [-0.1, -0.1, 1.1, 1.1]
227     check_bboxes_are_bad [bbox] do |map, _bbox|
228       assert_boundary_error map, " The server said: The maximum bbox size is 0.25, and your request was too large. Either request a smaller area, or use planet.osm"
229     end
230   end
231
232   ##
233   # checks that an invalid bounding box will not be served. in this case
234   # one with max < min latitudes.
235   #
236   # NOTE: the controller expands the bbox by 0.01 in each direction!
237   def test_whichways_badlat
238     bboxes = [[0, 0.1, 0.1, 0], [-0.1, 80, 0.1, 70], [0.24, 54.35, 0.25, 54.33]]
239     check_bboxes_are_bad bboxes do |map, bbox|
240       assert_boundary_error map, " The server said: The minimum latitude must be less than the maximum latitude, but it wasn't", bbox.inspect
241     end
242   end
243
244   ##
245   # same as test_whichways_badlat, but for longitudes
246   #
247   # NOTE: the controller expands the bbox by 0.01 in each direction!
248   def test_whichways_badlon
249     bboxes = [[80, -0.1, 70, 0.1], [54.35, 0.24, 54.33, 0.25]]
250     check_bboxes_are_bad bboxes do |map, bbox|
251       assert_boundary_error map, " The server said: The minimum longitude must be less than the maximum longitude, but it wasn't", bbox.inspect
252     end
253   end
254
255   def test_whichways_deleted
256     node = create(:node, :lat => 3.0, :lon => 3.0)
257     way = create(:way)
258     deleted_way = create(:way, :deleted)
259     create(:way_node, :way => way, :node => node)
260     create(:way_node, :way => deleted_way, :node => node)
261     create(:way_tag, :way => way)
262
263     minlon = node.lon - 0.1
264     minlat = node.lat - 0.1
265     maxlon = node.lon + 0.1
266     maxlat = node.lat + 0.1
267     amf_content "whichways_deleted", "/1", [minlon, minlat, maxlon, maxlat]
268     post :amf_read
269     assert_response :success
270     amf_parse_response
271
272     # check contents of message
273     map = amf_result "/1"
274     assert_equal 0, map[0], "first map element should be 0"
275     assert_equal "", map[1], "second map element should be an empty string"
276     assert_equal Array, map[2].class, "third map element should be an array"
277     # TODO: looks like amf_controller changed since this test was written
278     # so someone who knows what they're doing should check this!
279     assert !map[2].include?(current_ways(:used_way).id),
280            "map should not include used way"
281     assert map[2].include?(current_ways(:invisible_way).id),
282            "map should include deleted way"
283   end
284
285   def test_whichways_deleted_toobig
286     bbox = [-0.1, -0.1, 1.1, 1.1]
287     amf_content "whichways_deleted", "/1", bbox
288     post :amf_read
289     assert_response :success
290     amf_parse_response
291
292     map = amf_result "/1"
293     assert_deleted_boundary_error map, " The server said: The maximum bbox size is 0.25, and your request was too large. Either request a smaller area, or use planet.osm"
294   end
295
296   def test_getrelation
297     id = create(:relation).id
298     amf_content "getrelation", "/1", [id]
299     post :amf_read
300     assert_response :success
301     amf_parse_response
302     rel = amf_result("/1")
303     assert_equal rel[0], 0
304     assert_equal rel[2], id
305   end
306
307   def test_getrelation_invisible
308     id = create(:relation, :deleted).id
309     amf_content "getrelation", "/1", [id]
310     post :amf_read
311     assert_response :success
312     amf_parse_response
313     rel = amf_result("/1")
314     assert_equal rel[0], -4
315     assert_equal rel[1], "relation"
316     assert_equal rel[2], id
317     assert(rel[3].nil?) && rel[4].nil?
318   end
319
320   def test_getrelation_nonexistent
321     id = 0
322     amf_content "getrelation", "/1", [id]
323     post :amf_read
324     assert_response :success
325     amf_parse_response
326     rel = amf_result("/1")
327     assert_equal rel[0], -4
328     assert_equal rel[1], "relation"
329     assert_equal rel[2], id
330     assert(rel[3].nil?) && rel[4].nil?
331   end
332
333   def test_getway_old
334     # try to get the last visible version (specified by <0) (should be current version)
335     latest = current_ways(:way_with_versions)
336     # NOTE: looks from the API changes that this now expects a timestamp
337     # instead of a version number...
338     # try to get version 1
339     v1 = ways(:way_with_versions_v2)
340     { latest.id => "",
341       v1.way_id => v1.timestamp.strftime("%d %b %Y, %H:%M:%S") }.each do |id, t|
342       amf_content "getway_old", "/1", [id, t]
343       post :amf_read
344       assert_response :success
345       amf_parse_response
346       returned_way = amf_result("/1")
347       assert_equal 0, returned_way[0]
348       assert_equal id, returned_way[2]
349       # API returns the *latest* version, even for old ways...
350       assert_equal latest.version, returned_way[5]
351     end
352   end
353
354   ##
355   # test that the server doesn't fall over when rubbish is passed
356   # into the method args.
357   def test_getway_old_invalid
358     way_id = current_ways(:way_with_versions).id
359     { "foo"  => "bar",
360       way_id => "not a date",
361       way_id => "2009-03-25 00:00:00",                   # <- wrong format
362       way_id => "0 Jan 2009 00:00:00",                   # <- invalid date
363       -1     => "1 Jan 2009 00:00:00" }.each do |id, t|  # <- invalid
364       amf_content "getway_old", "/1", [id, t]
365       post :amf_read
366       assert_response :success
367       amf_parse_response
368       returned_way = amf_result("/1")
369       assert_equal -1, returned_way[0]
370       assert returned_way[3].nil?
371       assert returned_way[4].nil?
372       assert returned_way[5].nil?
373     end
374   end
375
376   def test_getway_old_nonexistent
377     # try to get the last version-10 (shoudn't exist)
378     v1 = ways(:way_with_versions_v1)
379     # try to get last visible version of non-existent way
380     # try to get specific version of non-existent way
381     [[0, ""],
382      [0, "1 Jan 1970, 00:00:00"],
383      [v1.way_id, (v1.timestamp - 10).strftime("%d %b %Y, %H:%M:%S")]].each do |id, t|
384       amf_content "getway_old", "/1", [id, t]
385       post :amf_read
386       assert_response :success
387       amf_parse_response
388       returned_way = amf_result("/1")
389       assert_equal -1, returned_way[0]
390       assert returned_way[3].nil?
391       assert returned_way[4].nil?
392       assert returned_way[5].nil?
393     end
394   end
395
396   def test_getway_old_invisible
397     v1 = ways(:invisible_way)
398     # try to get deleted version
399     [[v1.way_id, (v1.timestamp + 10).strftime("%d %b %Y, %H:%M:%S")]].each do |id, t|
400       amf_content "getway_old", "/1", [id, t]
401       post :amf_read
402       assert_response :success
403       amf_parse_response
404       returned_way = amf_result("/1")
405       assert_equal -1, returned_way[0]
406       assert returned_way[3].nil?
407       assert returned_way[4].nil?
408       assert returned_way[5].nil?
409     end
410   end
411
412   def test_getway_history
413     latest = current_ways(:way_with_versions)
414     oldest = ways(:way_with_versions_v1)
415
416     amf_content "getway_history", "/1", [latest.id]
417     post :amf_read
418     assert_response :success
419     amf_parse_response
420     history = amf_result("/1")
421
422     # ['way',wayid,history]
423     assert_equal "way", history[0]
424     assert_equal latest.id, history[1]
425     # We use dates rather than version numbers here, because you might
426     # have moved a node within a way (i.e. way version not incremented).
427     # The timestamp is +1 because we say "give me the revision of 15:33:02",
428     # but that might actually include changes at 15:33:02.457.
429     assert_equal (latest.timestamp + 1).strftime("%d %b %Y, %H:%M:%S"), history[2].first[0]
430     assert_equal (oldest.timestamp + 1).strftime("%d %b %Y, %H:%M:%S"), history[2].last[0]
431   end
432
433   def test_getway_history_nonexistent
434     amf_content "getway_history", "/1", [0]
435     post :amf_read
436     assert_response :success
437     amf_parse_response
438     history = amf_result("/1")
439
440     # ['way',wayid,history]
441     assert_equal history[0], "way"
442     assert_equal history[1], 0
443     assert history[2].empty?
444   end
445
446   def test_getnode_history
447     node = create(:node, :version => 2)
448     node_v1 = create(:old_node, :current_node => node, :version => 1, :timestamp => 3.days.ago)
449     _node_v2 = create(:old_node, :current_node => node, :version => 2, :timestamp => 2.days.ago)
450     node_v3 = create(:old_node, :current_node => node, :version => 3, :timestamp => 1.day.ago)
451
452     amf_content "getnode_history", "/1", [node.id]
453     post :amf_read
454     assert_response :success
455     amf_parse_response
456     history = amf_result("/1")
457
458     # ['node',nodeid,history]
459     # note that (as per getway_history) we actually round up
460     # to the next second
461     assert_equal history[0], "node",
462                  'first element should be "node"'
463     assert_equal history[1], node.id,
464                  "second element should be the input node ID"
465     assert_equal history[2].first[0],
466                  (node_v3.timestamp + 1).strftime("%d %b %Y, %H:%M:%S"),
467                  "first element in third element (array) should be the latest version"
468     assert_equal history[2].last[0],
469                  (node_v1.timestamp + 1).strftime("%d %b %Y, %H:%M:%S"),
470                  "last element in third element (array) should be the initial version"
471   end
472
473   def test_getnode_history_nonexistent
474     amf_content "getnode_history", "/1", [0]
475     post :amf_read
476     assert_response :success
477     amf_parse_response
478     history = amf_result("/1")
479
480     # ['node',nodeid,history]
481     assert_equal history[0], "node"
482     assert_equal history[1], 0
483     assert history[2].empty?
484   end
485
486   def test_findgpx_bad_user
487     amf_content "findgpx", "/1", [1, "test@example.com:wrong"]
488     post :amf_read
489     assert_response :success
490     amf_parse_response
491     result = amf_result("/1")
492
493     assert_equal 2, result.length
494     assert_equal -1, result[0]
495     assert_match /must be logged in/, result[1]
496
497     blocked_user = create(:user)
498     create(:user_block, :user => blocked_user)
499     amf_content "findgpx", "/1", [1, "#{blocked_user.email}:test"]
500     post :amf_read
501     assert_response :success
502     amf_parse_response
503     result = amf_result("/1")
504
505     assert_equal 2, result.length
506     assert_equal -1, result[0]
507     assert_match /access to the API has been blocked/, result[1]
508   end
509
510   def test_findgpx_by_id
511     user = create(:user)
512     trace = create(:trace, :visibility => "private", :user => user)
513
514     amf_content "findgpx", "/1", [trace.id, "#{user.email}:test"]
515     post :amf_read
516     assert_response :success
517     amf_parse_response
518     result = amf_result("/1")
519
520     assert_equal 3, result.length
521     assert_equal 0, result[0]
522     assert_equal "", result[1]
523     traces = result[2]
524     assert_equal 1, traces.length
525     assert_equal 3, traces[0].length
526     assert_equal trace.id, traces[0][0]
527     assert_equal trace.name, traces[0][1]
528     assert_equal trace.description, traces[0][2]
529   end
530
531   def test_findgpx_by_name
532     amf_content "findgpx", "/1", ["Trace", "test@example.com:test"]
533     post :amf_read
534     assert_response :success
535     amf_parse_response
536     result = amf_result("/1")
537
538     # find by name fails as it uses mysql text search syntax...
539     assert_equal 2, result.length
540     assert_equal -2, result[0]
541   end
542
543   def test_findrelations_by_id
544     relation = create(:relation, :version => 4)
545
546     amf_content "findrelations", "/1", [relation.id]
547     post :amf_read
548     assert_response :success
549     amf_parse_response
550     result = amf_result("/1")
551
552     assert_equal 1, result.length
553     assert_equal 4, result[0].length
554     assert_equal relation.id, result[0][0]
555     assert_equal relation.tags, result[0][1]
556     assert_equal relation.members, result[0][2]
557     assert_equal relation.version, result[0][3]
558
559     amf_content "findrelations", "/1", [999999]
560     post :amf_read
561     assert_response :success
562     amf_parse_response
563     result = amf_result("/1")
564
565     assert_equal 0, result.length
566   end
567
568   def test_findrelations_by_tags
569     visible_relation = create(:relation)
570     create(:relation_tag, :relation => visible_relation, :k => "test", :v => "yes")
571     used_relation = create(:relation)
572     super_relation = create(:relation)
573     create(:relation_member, :relation => super_relation, :member => used_relation)
574     create(:relation_tag, :relation => used_relation, :k => "test", :v => "yes")
575     create(:relation_tag, :relation => used_relation, :k => "name", :v => "Test Relation")
576
577     amf_content "findrelations", "/1", ["yes"]
578     post :amf_read
579     assert_response :success
580     amf_parse_response
581     result = amf_result("/1").sort
582
583     assert_equal 2, result.length
584     assert_equal 4, result[0].length
585     assert_equal visible_relation.id, result[0][0]
586     assert_equal visible_relation.tags, result[0][1]
587     assert_equal visible_relation.members, result[0][2]
588     assert_equal visible_relation.version, result[0][3]
589     assert_equal 4, result[1].length
590     assert_equal used_relation.id, result[1][0]
591     assert_equal used_relation.tags, result[1][1]
592     assert_equal used_relation.members, result[1][2]
593     assert_equal used_relation.version, result[1][3]
594
595     amf_content "findrelations", "/1", ["no"]
596     post :amf_read
597     assert_response :success
598     amf_parse_response
599     result = amf_result("/1").sort
600
601     assert_equal 0, result.length
602   end
603
604   def test_getpoi_without_timestamp
605     node = create(:node, :with_history, :version => 4)
606     create(:node_tag, :node => node)
607
608     amf_content "getpoi", "/1", [node.id, ""]
609     post :amf_read
610     assert_response :success
611     amf_parse_response
612     result = amf_result("/1")
613
614     assert_equal 7, result.length
615     assert_equal 0, result[0]
616     assert_equal "", result[1]
617     assert_equal node.id, result[2]
618     assert_equal node.lon, result[3]
619     assert_equal node.lat, result[4]
620     assert_equal node.tags, result[5]
621     assert_equal node.version, result[6]
622
623     amf_content "getpoi", "/1", [999999, ""]
624     post :amf_read
625     assert_response :success
626     amf_parse_response
627     result = amf_result("/1")
628
629     assert_equal 3, result.length
630     assert_equal -4, result[0]
631     assert_equal "node", result[1]
632     assert_equal 999999, result[2]
633   end
634
635   def test_getpoi_with_timestamp
636     current_node = create(:node, :with_history, :version => 4)
637     node = current_node.old_nodes.find_by(:version => 2)
638
639     # Timestamps are stored with microseconds, but xmlschema truncates them to
640     # previous whole second, causing <= comparison to fail
641     timestamp = (node.timestamp + 1.second).xmlschema
642
643     amf_content "getpoi", "/1", [node.node_id, timestamp]
644     post :amf_read
645     assert_response :success
646     amf_parse_response
647     result = amf_result("/1")
648
649     assert_equal 7, result.length
650     assert_equal 0, result[0]
651     assert_equal "", result[1]
652     assert_equal node.node_id, result[2]
653     assert_equal node.lon, result[3]
654     assert_equal node.lat, result[4]
655     assert_equal node.tags, result[5]
656     assert_equal current_node.version, result[6]
657
658     amf_content "getpoi", "/1", [node.node_id, "2000-01-01T00:00:00Z"]
659     post :amf_read
660     assert_response :success
661     amf_parse_response
662     result = amf_result("/1")
663
664     assert_equal 3, result.length
665     assert_equal -4, result[0]
666     assert_equal "node", result[1]
667     assert_equal node.node_id, result[2]
668
669     amf_content "getpoi", "/1", [999999, Time.now.xmlschema]
670     post :amf_read
671     assert_response :success
672     amf_parse_response
673     result = amf_result("/1")
674
675     assert_equal 3, result.length
676     assert_equal -4, result[0]
677     assert_equal "node", result[1]
678     assert_equal 999999, result[2]
679   end
680
681   # ************************************************************
682   # AMF Write tests
683
684   # check that we can update a poi
685   def test_putpoi_update_valid
686     nd = create(:node)
687     cs_id = nd.changeset.id
688     user = nd.changeset.user
689     amf_content "putpoi", "/1", ["#{user.email}:test", cs_id, nd.version, nd.id, nd.lon, nd.lat, nd.tags, nd.visible]
690     post :amf_write
691     assert_response :success
692     amf_parse_response
693     result = amf_result("/1")
694
695     assert_equal 5, result.size
696     assert_equal 0, result[0]
697     assert_equal "", result[1]
698     assert_equal nd.id, result[2]
699     assert_equal nd.id, result[3]
700     assert_equal nd.version + 1, result[4]
701
702     # Now try to update again, with a different lat/lon, using the updated version number
703     lat = nd.lat + 0.1
704     lon = nd.lon - 0.1
705     amf_content "putpoi", "/2", ["#{user.email}:test", cs_id, nd.version + 1, nd.id, lon, lat, nd.tags, nd.visible]
706     post :amf_write
707     assert_response :success
708     amf_parse_response
709     result = amf_result("/2")
710
711     assert_equal 5, result.size
712     assert_equal 0, result[0]
713     assert_equal "", result[1]
714     assert_equal nd.id, result[2]
715     assert_equal nd.id, result[3]
716     assert_equal nd.version + 2, result[4]
717   end
718
719   # Check that we can create a no valid poi
720   # Using similar method for the node controller test
721   def test_putpoi_create_valid
722     # This node has no tags
723
724     # create a node with random lat/lon
725     lat = rand(100) - 50 + rand
726     lon = rand(100) - 50 + rand
727
728     changeset = create(:changeset)
729     user = changeset.user
730
731     amf_content "putpoi", "/1", ["#{user.email}:test", changeset.id, nil, nil, lon, lat, {}, nil]
732     post :amf_write
733     assert_response :success
734     amf_parse_response
735     result = amf_result("/1")
736
737     # check the array returned by the amf
738     assert_equal 5, result.size
739     assert_equal 0, result[0], "expected to get the status ok from the amf"
740     assert_equal 0, result[2], "The old id should be 0"
741     assert result[3] > 0, "The new id should be greater than 0"
742     assert_equal 1, result[4], "The new version should be 1"
743
744     # Finally check that the node that was saved has saved the data correctly
745     # in both the current and history tables
746     # First check the current table
747     current_node = Node.find(result[3].to_i)
748     assert_in_delta lat, current_node.lat, 0.00001, "The latitude was not retreieved correctly"
749     assert_in_delta lon, current_node.lon, 0.00001, "The longitude was not retreived correctly"
750     assert_equal 0, current_node.tags.size, "There seems to be a tag that has been added to the node"
751     assert_equal result[4], current_node.version, "The version returned, is different to the one returned by the amf"
752     # Now check the history table
753     historic_nodes = OldNode.where(:node_id => result[3])
754     assert_equal 1, historic_nodes.size, "There should only be one historic node created"
755     first_historic_node = historic_nodes.first
756     assert_in_delta lat, first_historic_node.lat, 0.00001, "The latitude was not retreived correctly"
757     assert_in_delta lon, first_historic_node.lon, 0.00001, "The longitude was not retreuved correctly"
758     assert_equal 0, first_historic_node.tags.size, "There seems to be a tag that have been attached to this node"
759     assert_equal result[4], first_historic_node.version, "The version returned, is different to the one returned by the amf"
760
761     ####
762     # This node has some tags
763
764     # create a node with random lat/lon
765     lat = rand(100) - 50 + rand
766     lon = rand(100) - 50 + rand
767
768     amf_content "putpoi", "/2", ["#{user.email}:test", changeset.id, nil, nil, lon, lat, { "key" => "value", "ping" => "pong" }, nil]
769     post :amf_write
770     assert_response :success
771     amf_parse_response
772     result = amf_result("/2")
773
774     # check the array returned by the amf
775     assert_equal 5, result.size
776     assert_equal 0, result[0], "Expected to get the status ok in the amf"
777     assert_equal 0, result[2], "The old id should be 0"
778     assert result[3] > 0, "The new id should be greater than 0"
779     assert_equal 1, result[4], "The new version should be 1"
780
781     # Finally check that the node that was saved has saved the data correctly
782     # in both the current and history tables
783     # First check the current table
784     current_node = Node.find(result[3].to_i)
785     assert_in_delta lat, current_node.lat, 0.00001, "The latitude was not retreieved correctly"
786     assert_in_delta lon, current_node.lon, 0.00001, "The longitude was not retreived correctly"
787     assert_equal 2, current_node.tags.size, "There seems to be a tag that has been added to the node"
788     assert_equal({ "key" => "value", "ping" => "pong" }, current_node.tags, "tags are different")
789     assert_equal result[4], current_node.version, "The version returned, is different to the one returned by the amf"
790     # Now check the history table
791     historic_nodes = OldNode.where(:node_id => result[3])
792     assert_equal 1, historic_nodes.size, "There should only be one historic node created"
793     first_historic_node = historic_nodes.first
794     assert_in_delta lat, first_historic_node.lat, 0.00001, "The latitude was not retreived correctly"
795     assert_in_delta lon, first_historic_node.lon, 0.00001, "The longitude was not retreuved correctly"
796     assert_equal 2, first_historic_node.tags.size, "There seems to be a tag that have been attached to this node"
797     assert_equal({ "key" => "value", "ping" => "pong" }, first_historic_node.tags, "tags are different")
798     assert_equal result[4], first_historic_node.version, "The version returned, is different to the one returned by the amf"
799   end
800
801   # try creating a POI with rubbish in the tags
802   def test_putpoi_create_with_control_chars
803     # This node has no tags
804
805     # create a node with random lat/lon
806     lat = rand(100) - 50 + rand
807     lon = rand(100) - 50 + rand
808
809     changeset = create(:changeset)
810     user = changeset.user
811
812     mostly_invalid = (0..31).to_a.map(&:chr).join
813     tags = { "something" => "foo#{mostly_invalid}bar" }
814
815     amf_content "putpoi", "/1", ["#{user.email}:test", changeset.id, nil, nil, lon, lat, tags, nil]
816     post :amf_write
817     assert_response :success
818     amf_parse_response
819     result = amf_result("/1")
820
821     # check the array returned by the amf
822     assert_equal 5, result.size
823     assert_equal 0, result[0], "Expected to get the status ok in the amf"
824     assert_equal 0, result[2], "The old id should be 0"
825     assert result[3] > 0, "The new id should be greater than 0"
826     assert_equal 1, result[4], "The new version should be 1"
827
828     # Finally check that the node that was saved has saved the data correctly
829     # in both the current and history tables
830     # First check the current table
831     current_node = Node.find(result[3].to_i)
832     assert_equal 1, current_node.tags.size, "There seems to be a tag that has been added to the node"
833     assert_equal({ "something" => "foo\t\n\rbar" }, current_node.tags, "tags were not fixed correctly")
834     assert_equal result[4], current_node.version, "The version returned, is different to the one returned by the amf"
835   end
836
837   # try creating a POI with rubbish in the tags
838   def test_putpoi_create_with_invalid_utf8
839     # This node has no tags
840
841     # create a node with random lat/lon
842     lat = rand(100) - 50 + rand
843     lon = rand(100) - 50 + rand
844
845     changeset = create(:changeset)
846     user = changeset.user
847
848     invalid = "\xc0\xc0"
849     tags = { "something" => "foo#{invalid}bar" }
850
851     amf_content "putpoi", "/1", ["#{user.email}:test", changeset.id, nil, nil, lon, lat, tags, nil]
852     post :amf_write
853     assert_response :success
854     amf_parse_response
855     result = amf_result("/1")
856
857     assert_equal 2, result.size
858     assert_equal -1, result[0], "Expected to get the status FAIL in the amf"
859     assert_equal "One of the tags is invalid. Linux users may need to upgrade to Flash Player 10.1.", result[1]
860   end
861
862   # try deleting a node
863   def test_putpoi_delete_valid
864     nd = create(:node)
865     cs_id = nd.changeset.id
866     user = nd.changeset.user
867
868     amf_content "putpoi", "/1", ["#{user.email}:test", cs_id, nd.version, nd.id, nd.lon, nd.lat, nd.tags, false]
869     post :amf_write
870     assert_response :success
871     amf_parse_response
872     result = amf_result("/1")
873
874     assert_equal 5, result.size
875     assert_equal 0, result[0]
876     assert_equal "", result[1]
877     assert_equal nd.id, result[2]
878     assert_equal nd.id, result[3]
879     assert_equal nd.version + 1, result[4]
880
881     current_node = Node.find(result[3].to_i)
882     assert_equal false, current_node.visible
883   end
884
885   # try deleting a node that is already deleted
886   def test_putpoi_delete_already_deleted
887     nd = create(:node, :deleted)
888     cs_id = nd.changeset.id
889     user = nd.changeset.user
890
891     amf_content "putpoi", "/1", ["#{user.email}:test", cs_id, nd.version, nd.id, nd.lon, nd.lat, nd.tags, false]
892     post :amf_write
893     assert_response :success
894     amf_parse_response
895     result = amf_result("/1")
896
897     assert_equal 3, result.size
898     assert_equal -4, result[0]
899     assert_equal "node", result[1]
900     assert_equal nd.id, result[2]
901   end
902
903   # try deleting a node that has never existed
904   def test_putpoi_delete_not_found
905     changeset = create(:changeset)
906     cs_id = changeset.id
907     user = changeset.user
908
909     amf_content "putpoi", "/1", ["#{user.email}:test", cs_id, 1, 999999, 0, 0, {}, false]
910     post :amf_write
911     assert_response :success
912     amf_parse_response
913     result = amf_result("/1")
914
915     assert_equal 3, result.size
916     assert_equal -4, result[0]
917     assert_equal "node", result[1]
918     assert_equal 999999, result[2]
919   end
920
921   # try setting an invalid location on a node
922   def test_putpoi_invalid_latlon
923     nd = create(:node)
924     cs_id = nd.changeset.id
925     user = nd.changeset.user
926
927     amf_content "putpoi", "/1", ["#{user.email}:test", cs_id, nd.version, nd.id, 200, 100, nd.tags, true]
928     post :amf_write
929     assert_response :success
930     amf_parse_response
931     result = amf_result("/1")
932
933     assert_equal 2, result.size
934     assert_equal -2, result[0]
935     assert_match /Node is not in the world/, result[1]
936   end
937
938   # check that we can create a way
939   def test_putway_create_valid
940     changeset = create(:changeset)
941     cs_id = changeset.id
942     user = changeset.user
943
944     a = create(:node).id
945     b = create(:node).id
946     c = create(:node).id
947     d = create(:node).id
948     e = create(:node).id
949
950     amf_content "putway", "/1", ["#{user.email}:test", cs_id, 0, -1, [a, b, c], { "test" => "new" }, [], {}]
951     post :amf_write
952     assert_response :success
953     amf_parse_response
954     result = amf_result("/1")
955     new_way_id = result[3].to_i
956
957     assert_equal 8, result.size
958     assert_equal 0, result[0]
959     assert_equal "", result[1]
960     assert_equal -1, result[2]
961     assert_not_equal -1, result[3]
962     assert_equal({}, result[4])
963     assert_equal 1, result[5]
964     assert_equal({}, result[6])
965     assert_equal({}, result[7])
966
967     new_way = Way.find(new_way_id)
968     assert_equal 1, new_way.version
969     assert_equal [a, b, c], new_way.nds
970     assert_equal({ "test" => "new" }, new_way.tags)
971
972     amf_content "putway", "/1", ["#{user.email}:test", cs_id, 0, -1, [b, d, e, a], { "test" => "newer" }, [], {}]
973     post :amf_write
974     assert_response :success
975     amf_parse_response
976     result = amf_result("/1")
977     new_way_id = result[3].to_i
978
979     assert_equal 8, result.size
980     assert_equal 0, result[0]
981     assert_equal "", result[1]
982     assert_equal -1, result[2]
983     assert_not_equal -1, result[3]
984     assert_equal({}, result[4])
985     assert_equal 1, result[5]
986     assert_equal({}, result[6])
987     assert_equal({}, result[7])
988
989     new_way = Way.find(new_way_id)
990     assert_equal 1, new_way.version
991     assert_equal [b, d, e, a], new_way.nds
992     assert_equal({ "test" => "newer" }, new_way.tags)
993
994     amf_content "putway", "/1", ["#{user.email}:test", cs_id, 0, -1, [b, -1, d, e], { "test" => "newest" }, [[4.56, 12.34, -1, 0, { "test" => "new" }], [12.34, 4.56, d, 1, { "test" => "ok" }]], { a => 1 }]
995     post :amf_write
996     assert_response :success
997     amf_parse_response
998     result = amf_result("/1")
999     new_way_id = result[3].to_i
1000     new_node_id = result[4]["-1"].to_i
1001
1002     assert_equal 8, result.size
1003     assert_equal 0, result[0]
1004     assert_equal "", result[1]
1005     assert_equal -1, result[2]
1006     assert_not_equal -1, result[3]
1007     assert_equal({ "-1" => new_node_id }, result[4])
1008     assert_equal 1, result[5]
1009     assert_equal({ new_node_id.to_s => 1, d.to_s => 2 }, result[6])
1010     assert_equal({ a.to_s => 1 }, result[7])
1011
1012     new_way = Way.find(new_way_id)
1013     assert_equal 1, new_way.version
1014     assert_equal [b, new_node_id, d, e], new_way.nds
1015     assert_equal({ "test" => "newest" }, new_way.tags)
1016
1017     new_node = Node.find(new_node_id)
1018     assert_equal 1, new_node.version
1019     assert_equal true, new_node.visible
1020     assert_equal 4.56, new_node.lon
1021     assert_equal 12.34, new_node.lat
1022     assert_equal({ "test" => "new" }, new_node.tags)
1023
1024     changed_node = Node.find(d)
1025     assert_equal 2, changed_node.version
1026     assert_equal true, changed_node.visible
1027     assert_equal 12.34, changed_node.lon
1028     assert_equal 4.56, changed_node.lat
1029     assert_equal({ "test" => "ok" }, changed_node.tags)
1030
1031     # node is not deleted because our other ways are using it
1032     deleted_node = Node.find(a)
1033     assert_equal 1, deleted_node.version
1034     assert_equal true, deleted_node.visible
1035   end
1036
1037   # check that we can update a way
1038   def test_putway_update_valid
1039     way = create(:way_with_nodes, :nodes_count => 3)
1040     cs_id = way.changeset.id
1041     user = way.changeset.user
1042
1043     assert_not_equal({ "test" => "ok" }, way.tags)
1044     amf_content "putway", "/1", ["#{user.email}:test", cs_id, way.version, way.id, way.nds, { "test" => "ok" }, [], {}]
1045     post :amf_write
1046     assert_response :success
1047     amf_parse_response
1048     result = amf_result("/1")
1049
1050     assert_equal 8, result.size
1051     assert_equal 0, result[0]
1052     assert_equal "", result[1]
1053     assert_equal way.id, result[2]
1054     assert_equal way.id, result[3]
1055     assert_equal({}, result[4])
1056     assert_equal way.version + 1, result[5]
1057     assert_equal({}, result[6])
1058     assert_equal({}, result[7])
1059
1060     new_way = Way.find(way.id)
1061     assert_equal way.version + 1, new_way.version
1062     assert_equal way.nds, new_way.nds
1063     assert_equal({ "test" => "ok" }, new_way.tags)
1064
1065     # Test changing the nodes in the way
1066     a = create(:node).id
1067     b = create(:node).id
1068     c = create(:node).id
1069     d = create(:node).id
1070
1071     assert_not_equal [a, b, c, d], way.nds
1072     amf_content "putway", "/1", ["#{user.email}:test", cs_id, way.version + 1, way.id, [a, b, c, d], way.tags, [], {}]
1073     post :amf_write
1074     assert_response :success
1075     amf_parse_response
1076     result = amf_result("/1")
1077
1078     assert_equal 8, result.size
1079     assert_equal 0, result[0]
1080     assert_equal "", result[1]
1081     assert_equal way.id, result[2]
1082     assert_equal way.id, result[3]
1083     assert_equal({}, result[4])
1084     assert_equal way.version + 2, result[5]
1085     assert_equal({}, result[6])
1086     assert_equal({}, result[7])
1087
1088     new_way = Way.find(way.id)
1089     assert_equal way.version + 2, new_way.version
1090     assert_equal [a, b, c, d], new_way.nds
1091     assert_equal way.tags, new_way.tags
1092
1093     amf_content "putway", "/1", ["#{user.email}:test", cs_id, way.version + 2, way.id, [a, -1, b, c], way.tags, [[4.56, 12.34, -1, 0, { "test" => "new" }], [12.34, 4.56, b, 1, { "test" => "ok" }]], { d => 1 }]
1094     post :amf_write
1095     assert_response :success
1096     amf_parse_response
1097     result = amf_result("/1")
1098     new_node_id = result[4]["-1"].to_i
1099
1100     assert_equal 8, result.size
1101     assert_equal 0, result[0]
1102     assert_equal "", result[1]
1103     assert_equal way.id, result[2]
1104     assert_equal way.id, result[3]
1105     assert_equal({ "-1" => new_node_id }, result[4])
1106     assert_equal way.version + 3, result[5]
1107     assert_equal({ new_node_id.to_s => 1, b.to_s => 2 }, result[6])
1108     assert_equal({ d.to_s => 1 }, result[7])
1109
1110     new_way = Way.find(way.id)
1111     assert_equal way.version + 3, new_way.version
1112     assert_equal [a, new_node_id, b, c], new_way.nds
1113     assert_equal way.tags, new_way.tags
1114
1115     new_node = Node.find(new_node_id)
1116     assert_equal 1, new_node.version
1117     assert_equal true, new_node.visible
1118     assert_equal 4.56, new_node.lon
1119     assert_equal 12.34, new_node.lat
1120     assert_equal({ "test" => "new" }, new_node.tags)
1121
1122     changed_node = Node.find(b)
1123     assert_equal 2, changed_node.version
1124     assert_equal true, changed_node.visible
1125     assert_equal 12.34, changed_node.lon
1126     assert_equal 4.56, changed_node.lat
1127     assert_equal({ "test" => "ok" }, changed_node.tags)
1128
1129     deleted_node = Node.find(d)
1130     assert_equal 2, deleted_node.version
1131     assert_equal false, deleted_node.visible
1132   end
1133
1134   # check that we can delete a way
1135   def test_deleteway_valid
1136     way = create(:way_with_nodes, :nodes_count => 3)
1137     nodes = way.nodes.each_with_object({}) { |n, ns| ns[n.id] = n.version }
1138     cs_id = way.changeset.id
1139     user = way.changeset.user
1140
1141     # Of the three nodes, two should be kept since they are used in
1142     # a different way, and the third deleted since it's unused
1143
1144     a = way.nodes[0]
1145     create(:way_node, :node => a)
1146     b = way.nodes[1]
1147     create(:way_node, :node => b)
1148     c = way.nodes[2]
1149
1150     amf_content "deleteway", "/1", ["#{user.email}:test", cs_id, way.id, way.version, nodes]
1151     post :amf_write
1152     assert_response :success
1153     amf_parse_response
1154     result = amf_result("/1")
1155
1156     assert_equal 5, result.size
1157     assert_equal 0, result[0]
1158     assert_equal "", result[1]
1159     assert_equal way.id, result[2]
1160     assert_equal way.version + 1, result[3]
1161     assert_equal({ c.id.to_s => 2 }, result[4])
1162
1163     new_way = Way.find(way.id)
1164     assert_equal way.version + 1, new_way.version
1165     assert_equal false, new_way.visible
1166
1167     way.nds.each do |node_id|
1168       assert_equal result[4][node_id.to_s].nil?, Node.find(node_id).visible
1169     end
1170   end
1171
1172   # check that we can't delete a way that is in use
1173   def test_deleteway_inuse
1174     way = create(:way_with_nodes, :nodes_count => 4)
1175     create(:relation_member, :member => way)
1176     nodes = way.nodes.each_with_object({}) { |n, ns| ns[n.id] = n.version }
1177     cs_id = way.changeset.id
1178     user = way.changeset.user
1179
1180     amf_content "deleteway", "/1", ["#{user.email}:test", cs_id, way.id, way.version, nodes]
1181     post :amf_write
1182     assert_response :success
1183     amf_parse_response
1184     result = amf_result("/1")
1185
1186     assert_equal 2, result.size
1187     assert_equal -1, result[0]
1188     assert_match /Way #{way.id} is still used/, result[1]
1189
1190     new_way = Way.find(way.id)
1191     assert_equal way.version, new_way.version
1192     assert_equal true, new_way.visible
1193
1194     way.nds.each do |node_id|
1195       assert_equal true, Node.find(node_id).visible
1196     end
1197   end
1198
1199   # check that we can create a relation
1200   def test_putrelation_create_valid
1201     changeset = create(:changeset)
1202     user = changeset.user
1203     cs_id = changeset.id
1204
1205     node = create(:node)
1206     way = create(:way_with_nodes, :nodes_count => 2)
1207     relation = create(:relation)
1208
1209     amf_content "putrelation", "/1", ["#{user.email}:test", cs_id, 0, -1, { "test" => "new" }, [["Node", node.id, "node"], ["Way", way.id, "way"], ["Relation", relation.id, "relation"]], true]
1210     post :amf_write
1211     assert_response :success
1212     amf_parse_response
1213     result = amf_result("/1")
1214     new_relation_id = result[3].to_i
1215
1216     assert_equal 5, result.size
1217     assert_equal 0, result[0]
1218     assert_equal "", result[1]
1219     assert_equal -1, result[2]
1220     assert_not_equal -1, result[3]
1221     assert_equal 1, result[4]
1222
1223     new_relation = Relation.find(new_relation_id)
1224     assert_equal 1, new_relation.version
1225     assert_equal [["Node", node.id, "node"], ["Way", way.id, "way"], ["Relation", relation.id, "relation"]], new_relation.members
1226     assert_equal({ "test" => "new" }, new_relation.tags)
1227     assert_equal true, new_relation.visible
1228   end
1229
1230   # check that we can update a relation
1231   def test_putrelation_update_valid
1232     relation = create(:relation)
1233     create(:relation_member, :relation => relation)
1234     user = relation.changeset.user
1235     cs_id = relation.changeset.id
1236
1237     assert_not_equal({ "test" => "ok" }, relation.tags)
1238     amf_content "putrelation", "/1", ["#{user.email}:test", cs_id, relation.version, relation.id, { "test" => "ok" }, relation.members, true]
1239     post :amf_write
1240     assert_response :success
1241     amf_parse_response
1242     result = amf_result("/1")
1243
1244     assert_equal 5, result.size
1245     assert_equal 0, result[0]
1246     assert_equal "", result[1]
1247     assert_equal relation.id, result[2]
1248     assert_equal relation.id, result[3]
1249     assert_equal relation.version + 1, result[4]
1250
1251     new_relation = Relation.find(relation.id)
1252     assert_equal relation.version + 1, new_relation.version
1253     assert_equal relation.members, new_relation.members
1254     assert_equal({ "test" => "ok" }, new_relation.tags)
1255     assert_equal true, new_relation.visible
1256   end
1257
1258   # check that we can delete a relation
1259   def test_putrelation_delete_valid
1260     relation = create(:relation)
1261     create(:relation_member, :relation => relation)
1262     create(:relation_tag, :relation => relation)
1263     cs_id = relation.changeset.id
1264     user = relation.changeset.user
1265
1266     amf_content "putrelation", "/1", ["#{user.email}:test", cs_id, relation.version, relation.id, relation.tags, relation.members, false]
1267     post :amf_write
1268     assert_response :success
1269     amf_parse_response
1270     result = amf_result("/1")
1271
1272     assert_equal 5, result.size
1273     assert_equal 0, result[0]
1274     assert_equal "", result[1]
1275     assert_equal relation.id, result[2]
1276     assert_equal relation.id, result[3]
1277     assert_equal relation.version + 1, result[4]
1278
1279     new_relation = Relation.find(relation.id)
1280     assert_equal relation.version + 1, new_relation.version
1281     assert_equal [], new_relation.members
1282     assert_equal({}, new_relation.tags)
1283     assert_equal false, new_relation.visible
1284   end
1285
1286   # check that we can't delete a relation that is in use
1287   def test_putrelation_delete_inuse
1288     relation = create(:relation)
1289     super_relation = create(:relation)
1290     create(:relation_member, :relation => super_relation, :member => relation)
1291     cs_id = relation.changeset.id
1292     user = relation.changeset.user
1293
1294     amf_content "putrelation", "/1", ["#{user.email}:test", cs_id, relation.version, relation.id, relation.tags, relation.members, false]
1295     post :amf_write
1296     assert_response :success
1297     amf_parse_response
1298     result = amf_result("/1")
1299
1300     assert_equal 2, result.size
1301     assert_equal -1, result[0]
1302     assert_match /relation #{relation.id} is used in/, result[1]
1303
1304     new_relation = Relation.find(relation.id)
1305     assert_equal relation.version, new_relation.version
1306     assert_equal relation.members, new_relation.members
1307     assert_equal relation.tags, new_relation.tags
1308     assert_equal true, new_relation.visible
1309   end
1310
1311   # check that we can open a changeset
1312   def test_startchangeset_valid
1313     amf_content "startchangeset", "/1", ["test@example.com:test", { "source" => "new" }, nil, "new", 1]
1314     post :amf_write
1315     assert_response :success
1316     amf_parse_response
1317     result = amf_result("/1")
1318     new_cs_id = result[2].to_i
1319
1320     assert_equal 3, result.size
1321     assert_equal 0, result[0]
1322     assert_equal "", result[1]
1323
1324     cs = Changeset.find(new_cs_id)
1325     assert_equal true, cs.is_open?
1326     assert_equal({ "comment" => "new", "source" => "new" }, cs.tags)
1327
1328     old_cs_id = new_cs_id
1329
1330     amf_content "startchangeset", "/1", ["test@example.com:test", { "source" => "newer" }, old_cs_id, "newer", 1]
1331     post :amf_write
1332     assert_response :success
1333     amf_parse_response
1334     result = amf_result("/1")
1335     new_cs_id = result[2].to_i
1336
1337     assert_not_equal old_cs_id, new_cs_id
1338
1339     assert_equal 3, result.size
1340     assert_equal 0, result[0]
1341     assert_equal "", result[1]
1342
1343     cs = Changeset.find(old_cs_id)
1344     assert_equal false, cs.is_open?
1345     assert_equal({ "comment" => "newer", "source" => "new" }, cs.tags)
1346
1347     cs = Changeset.find(new_cs_id)
1348     assert_equal true, cs.is_open?
1349     assert_equal({ "comment" => "newer", "source" => "newer" }, cs.tags)
1350
1351     old_cs_id = new_cs_id
1352
1353     amf_content "startchangeset", "/1", ["test@example.com:test", {}, old_cs_id, "", 0]
1354     post :amf_write
1355     assert_response :success
1356     amf_parse_response
1357     result = amf_result("/1")
1358
1359     assert_equal 3, result.size
1360     assert_equal 0, result[0]
1361     assert_equal "", result[1]
1362     assert_nil result[2]
1363
1364     cs = Changeset.find(old_cs_id)
1365     assert_equal false, cs.is_open?
1366     assert_equal({ "comment" => "newer", "source" => "newer" }, cs.tags)
1367   end
1368
1369   # check that we can't close somebody elses changeset
1370   def test_startchangeset_invalid_wrong_user
1371     amf_content "startchangeset", "/1", ["test@example.com:test", { "source" => "new" }, nil, "new", 1]
1372     post :amf_write
1373     assert_response :success
1374     amf_parse_response
1375     result = amf_result("/1")
1376     cs_id = result[2].to_i
1377
1378     assert_equal 3, result.size
1379     assert_equal 0, result[0]
1380     assert_equal "", result[1]
1381
1382     cs = Changeset.find(cs_id)
1383     assert_equal true, cs.is_open?
1384     assert_equal({ "comment" => "new", "source" => "new" }, cs.tags)
1385
1386     amf_content "startchangeset", "/1", ["test@openstreetmap.org:test", {}, cs_id, "delete", 0]
1387     post :amf_write
1388     assert_response :success
1389     amf_parse_response
1390     result = amf_result("/1")
1391
1392     assert_equal 2, result.size
1393     assert_equal -2, result[0]
1394     assert_equal "The user doesn't own that changeset", result[1]
1395
1396     cs = Changeset.find(cs_id)
1397     assert_equal true, cs.is_open?
1398     assert_equal({ "comment" => "new", "source" => "new" }, cs.tags)
1399   end
1400
1401   # check that invalid characters are stripped from changeset tags
1402   def test_startchangeset_invalid_xmlchar_comment
1403     invalid = "\035\022"
1404     comment = "foo#{invalid}bar"
1405
1406     amf_content "startchangeset", "/1", ["test@example.com:test", {}, nil, comment, 1]
1407     post :amf_write
1408     assert_response :success
1409     amf_parse_response
1410     result = amf_result("/1")
1411     new_cs_id = result[2].to_i
1412
1413     assert_equal 3, result.size
1414     assert_equal 0, result[0]
1415     assert_equal "", result[1]
1416
1417     cs = Changeset.find(new_cs_id)
1418     assert_equal true, cs.is_open?
1419     assert_equal({ "comment" => "foobar" }, cs.tags)
1420   end
1421
1422   private
1423
1424   # ************************************************************
1425   # AMF Helper functions
1426
1427   # Get the result record for the specified ID
1428   # It's an assertion FAIL if the record does not exist
1429   def amf_result(ref)
1430     assert @amf_result.key?("#{ref}/onResult")
1431     @amf_result["#{ref}/onResult"]
1432   end
1433
1434   # Encode the AMF message to invoke "target" with parameters as
1435   # the passed data. The ref is used to retrieve the results.
1436   def amf_content(target, ref, data)
1437     a, b = 1.divmod(256)
1438     c = StringIO.new
1439     c.write 0.chr + 0.chr   # version 0
1440     c.write 0.chr + 0.chr   # n headers
1441     c.write a.chr + b.chr   # n bodies
1442     c.write AMF.encodestring(target)
1443     c.write AMF.encodestring(ref)
1444     c.write [-1].pack("N")
1445     c.write AMF.encodevalue(data)
1446
1447     @request.env["RAW_POST_DATA"] = c.string
1448   end
1449
1450   # Parses the @response object as an AMF messsage.
1451   # The result is a hash of message_ref => data.
1452   # The attribute @amf_result is initialised to this hash.
1453   def amf_parse_response
1454     req = StringIO.new(@response.body)
1455
1456     req.read(2) # version
1457
1458     # parse through any headers
1459     headers = AMF.getint(req)        # Read number of headers
1460     headers.times do                 # Read each header
1461       AMF.getstring(req)             #  |
1462       req.getc                       #  | skip boolean
1463       AMF.getvalue(req)              #  |
1464     end
1465
1466     # parse through responses
1467     results = {}
1468     bodies = AMF.getint(req)         # Read number of bodies
1469     bodies.times do                  # Read each body
1470       message = AMF.getstring(req)   #  | get message name
1471       AMF.getstring(req)             #  | get index in response sequence
1472       AMF.getlong(req)               #  | get total size in bytes
1473       args = AMF.getvalue(req)       #  | get response (probably an array)
1474       results[message] = args
1475     end
1476     @amf_result = results
1477     results
1478   end
1479
1480   ##
1481   # given an array of bounding boxes (each an array of 4 floats), call the
1482   # AMF "whichways" controller for each and pass the result back to the
1483   # caller's block for assertion testing.
1484   def check_bboxes_are_bad(bboxes)
1485     bboxes.each do |bbox|
1486       amf_content "whichways", "/1", bbox
1487       post :amf_read
1488       assert_response :success
1489       amf_parse_response
1490
1491       # pass the response back to the caller's block to be tested
1492       # against what the caller expected.
1493       map = amf_result "/1"
1494       yield map, bbox
1495     end
1496   end
1497
1498   # this should be what AMF controller returns when the bbox of a
1499   # whichways request is invalid or too large.
1500   def assert_boundary_error(map, msg = nil, error_hint = nil)
1501     expected_map = [-2, "Sorry - I can't get the map for that area.#{msg}"]
1502     assert_equal expected_map, map, "AMF controller should have returned an error. (#{error_hint})"
1503   end
1504
1505   # this should be what AMF controller returns when the bbox of a
1506   # whichways_deleted request is invalid or too large.
1507   def assert_deleted_boundary_error(map, msg = nil, error_hint = nil)
1508     expected_map = [-2, "Sorry - I can't get the map for that area.#{msg}"]
1509     assert_equal expected_map, map, "AMF controller should have returned an error. (#{error_hint})"
1510   end
1511 end