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