]> git.openstreetmap.org Git - rails.git/blob - test/controllers/amf_controller_test.rb
Use CanCanCan for user_roles auth
[rails.git] / test / controllers / amf_controller_test.rb
1 require "test_helper"
2 require "stringio"
3
4 class AmfControllerTest < ActionController::TestCase
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 => "amf", :action => "amf_read" }
13     )
14     assert_routing(
15       { :path => "/api/0.6/amf/write", :method => :post },
16       { :controller => "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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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 w[0] == w[0].floor, "way ID should be an integer"
185       assert 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 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 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 r[0] == r[0].floor, "relation ID should be an integer"
202       assert 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 ways.include?(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, :body => 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 map[2].include?(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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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 history[2].empty?
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, :body => 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, :body => 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 history[2].empty?
470   end
471
472   def test_findgpx_bad_user
473     post :amf_read, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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_equal false, 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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, :body => 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_equal true, 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_equal true, 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_equal true, 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, :body => 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, :body => 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, :body => 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_equal true, 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_equal true, 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_equal false, 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, :body => 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_equal false, 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, :body => 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_equal true, new_way.visible
1150
1151     way.nds.each do |node_id|
1152       assert_equal true, 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, :body => 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_equal true, 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, :body => 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_equal true, 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, :body => 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_equal false, 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, :body => 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_equal true, 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, :body => 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_equal true, 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, :body => 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_equal false, cs.is_open?
1298     assert_equal({ "comment" => "newer", "source" => "new" }, cs.tags)
1299
1300     cs = Changeset.find(new_cs_id)
1301     assert_equal true, 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, :body => 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_equal false, 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, :body => 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_equal true, cs.is_open?
1338     assert_equal({ "comment" => "new", "source" => "new" }, cs.tags)
1339
1340     post :amf_write, :body => 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_equal true, 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, :body => 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_equal true, 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     c.string
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, :body => 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