scalm-RocketAMF 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. data/README.rdoc +47 -0
  2. data/Rakefile +59 -0
  3. data/RocketAMF.gemspec +20 -0
  4. data/benchmark.rb +74 -0
  5. data/ext/rocketamf_ext/class_mapping.c +484 -0
  6. data/ext/rocketamf_ext/constants.h +52 -0
  7. data/ext/rocketamf_ext/deserializer.c +776 -0
  8. data/ext/rocketamf_ext/deserializer.h +28 -0
  9. data/ext/rocketamf_ext/extconf.rb +18 -0
  10. data/ext/rocketamf_ext/remoting.c +184 -0
  11. data/ext/rocketamf_ext/rocketamf_ext.c +38 -0
  12. data/ext/rocketamf_ext/serializer.c +834 -0
  13. data/ext/rocketamf_ext/serializer.h +29 -0
  14. data/ext/rocketamf_ext/utility.h +4 -0
  15. data/lib/rocketamf.rb +216 -0
  16. data/lib/rocketamf/class_mapping.rb +237 -0
  17. data/lib/rocketamf/constants.rb +50 -0
  18. data/lib/rocketamf/ext.rb +28 -0
  19. data/lib/rocketamf/extensions.rb +22 -0
  20. data/lib/rocketamf/pure.rb +24 -0
  21. data/lib/rocketamf/pure/deserializer.rb +455 -0
  22. data/lib/rocketamf/pure/io_helpers.rb +94 -0
  23. data/lib/rocketamf/pure/remoting.rb +117 -0
  24. data/lib/rocketamf/pure/serializer.rb +474 -0
  25. data/lib/rocketamf/remoting.rb +196 -0
  26. data/lib/rocketamf/values/messages.rb +214 -0
  27. data/lib/rocketamf/values/typed_hash.rb +13 -0
  28. data/spec/class_mapping_spec.rb +110 -0
  29. data/spec/deserializer_spec.rb +455 -0
  30. data/spec/fast_class_mapping_spec.rb +144 -0
  31. data/spec/fixtures/objects/amf0-boolean.bin +1 -0
  32. data/spec/fixtures/objects/amf0-complex-encoded-string.bin +0 -0
  33. data/spec/fixtures/objects/amf0-date.bin +0 -0
  34. data/spec/fixtures/objects/amf0-ecma-ordinal-array.bin +0 -0
  35. data/spec/fixtures/objects/amf0-empty-string-key-hash.bin +0 -0
  36. data/spec/fixtures/objects/amf0-hash.bin +0 -0
  37. data/spec/fixtures/objects/amf0-null.bin +1 -0
  38. data/spec/fixtures/objects/amf0-number.bin +0 -0
  39. data/spec/fixtures/objects/amf0-object.bin +0 -0
  40. data/spec/fixtures/objects/amf0-ref-test.bin +0 -0
  41. data/spec/fixtures/objects/amf0-strict-array.bin +0 -0
  42. data/spec/fixtures/objects/amf0-string.bin +0 -0
  43. data/spec/fixtures/objects/amf0-time.bin +0 -0
  44. data/spec/fixtures/objects/amf0-typed-object.bin +0 -0
  45. data/spec/fixtures/objects/amf0-undefined.bin +1 -0
  46. data/spec/fixtures/objects/amf0-untyped-object.bin +0 -0
  47. data/spec/fixtures/objects/amf0-xml-doc.bin +0 -0
  48. data/spec/fixtures/objects/amf3-0.bin +0 -0
  49. data/spec/fixtures/objects/amf3-array-collection.bin +2 -0
  50. data/spec/fixtures/objects/amf3-array-ref.bin +1 -0
  51. data/spec/fixtures/objects/amf3-associative-array.bin +1 -0
  52. data/spec/fixtures/objects/amf3-bigNum.bin +0 -0
  53. data/spec/fixtures/objects/amf3-byte-array-ref.bin +1 -0
  54. data/spec/fixtures/objects/amf3-byte-array.bin +0 -0
  55. data/spec/fixtures/objects/amf3-complex-array-collection.bin +6 -0
  56. data/spec/fixtures/objects/amf3-complex-encoded-string-array.bin +1 -0
  57. data/spec/fixtures/objects/amf3-date-ref.bin +0 -0
  58. data/spec/fixtures/objects/amf3-date.bin +0 -0
  59. data/spec/fixtures/objects/amf3-dictionary.bin +0 -0
  60. data/spec/fixtures/objects/amf3-dynamic-object.bin +2 -0
  61. data/spec/fixtures/objects/amf3-empty-array-ref.bin +1 -0
  62. data/spec/fixtures/objects/amf3-empty-array.bin +1 -0
  63. data/spec/fixtures/objects/amf3-empty-dictionary.bin +0 -0
  64. data/spec/fixtures/objects/amf3-empty-string-ref.bin +1 -0
  65. data/spec/fixtures/objects/amf3-encoded-string-ref.bin +0 -0
  66. data/spec/fixtures/objects/amf3-externalizable.bin +0 -0
  67. data/spec/fixtures/objects/amf3-false.bin +1 -0
  68. data/spec/fixtures/objects/amf3-float.bin +0 -0
  69. data/spec/fixtures/objects/amf3-graph-member.bin +0 -0
  70. data/spec/fixtures/objects/amf3-hash.bin +2 -0
  71. data/spec/fixtures/objects/amf3-large-max.bin +0 -0
  72. data/spec/fixtures/objects/amf3-large-min.bin +0 -0
  73. data/spec/fixtures/objects/amf3-max.bin +1 -0
  74. data/spec/fixtures/objects/amf3-min.bin +0 -0
  75. data/spec/fixtures/objects/amf3-mixed-array.bin +10 -0
  76. data/spec/fixtures/objects/amf3-null.bin +1 -0
  77. data/spec/fixtures/objects/amf3-object-ref.bin +0 -0
  78. data/spec/fixtures/objects/amf3-primitive-array.bin +1 -0
  79. data/spec/fixtures/objects/amf3-string-ref.bin +0 -0
  80. data/spec/fixtures/objects/amf3-string.bin +1 -0
  81. data/spec/fixtures/objects/amf3-symbol.bin +1 -0
  82. data/spec/fixtures/objects/amf3-trait-ref.bin +3 -0
  83. data/spec/fixtures/objects/amf3-true.bin +1 -0
  84. data/spec/fixtures/objects/amf3-typed-object.bin +2 -0
  85. data/spec/fixtures/objects/amf3-vector-double.bin +0 -0
  86. data/spec/fixtures/objects/amf3-vector-int.bin +0 -0
  87. data/spec/fixtures/objects/amf3-vector-object.bin +0 -0
  88. data/spec/fixtures/objects/amf3-vector-uint.bin +0 -0
  89. data/spec/fixtures/objects/amf3-xml-doc.bin +1 -0
  90. data/spec/fixtures/objects/amf3-xml-ref.bin +1 -0
  91. data/spec/fixtures/objects/amf3-xml.bin +1 -0
  92. data/spec/fixtures/request/acknowledge-response.bin +0 -0
  93. data/spec/fixtures/request/amf0-error-response.bin +0 -0
  94. data/spec/fixtures/request/blaze-response.bin +0 -0
  95. data/spec/fixtures/request/commandMessage.bin +0 -0
  96. data/spec/fixtures/request/flex-request.bin +0 -0
  97. data/spec/fixtures/request/multiple-simple-request.bin +0 -0
  98. data/spec/fixtures/request/remotingMessage.bin +0 -0
  99. data/spec/fixtures/request/simple-request.bin +0 -0
  100. data/spec/fixtures/request/simple-response.bin +0 -0
  101. data/spec/fixtures/request/unsupportedCommandMessage.bin +0 -0
  102. data/spec/messages_spec.rb +39 -0
  103. data/spec/remoting_spec.rb +196 -0
  104. data/spec/serializer_spec.rb +503 -0
  105. data/spec/spec_helper.rb +55 -0
  106. metadata +164 -0
@@ -0,0 +1,455 @@
1
+ # encoding: UTF-8
2
+
3
+ require "spec_helper.rb"
4
+
5
+ describe "when deserializing" do
6
+ before :each do
7
+ RocketAMF::ClassMapper.reset
8
+ end
9
+
10
+ it "should raise exception with invalid version number" do
11
+ lambda {
12
+ RocketAMF.deserialize("", 5)
13
+ }.should raise_error("unsupported version 5")
14
+ end
15
+
16
+ describe "AMF0" do
17
+ it "should update source pos if source is a StringIO object" do
18
+ input = StringIO.new(object_fixture('amf0-number.bin'))
19
+ input.pos.should == 0
20
+ output = RocketAMF.deserialize(input, 0)
21
+ input.pos.should == 9
22
+ end
23
+
24
+ it "should deserialize numbers" do
25
+ input = object_fixture('amf0-number.bin')
26
+ output = RocketAMF.deserialize(input, 0)
27
+ output.should == 3.5
28
+ end
29
+
30
+ it "should deserialize booleans" do
31
+ input = object_fixture('amf0-boolean.bin')
32
+ output = RocketAMF.deserialize(input, 0)
33
+ output.should === true
34
+ end
35
+
36
+ it "should deserialize UTF8 strings" do
37
+ input = object_fixture('amf0-string.bin')
38
+ output = RocketAMF.deserialize(input, 0)
39
+ output.should == "this is a テスト"
40
+ end
41
+
42
+ it "should deserialize nulls" do
43
+ input = object_fixture('amf0-null.bin')
44
+ output = RocketAMF.deserialize(input, 0)
45
+ output.should == nil
46
+ end
47
+
48
+ it "should deserialize undefineds" do
49
+ input = object_fixture('amf0-undefined.bin')
50
+ output = RocketAMF.deserialize(input, 0)
51
+ output.should == nil
52
+ end
53
+
54
+ it "should deserialize hashes" do
55
+ input = object_fixture('amf0-hash.bin')
56
+ output = RocketAMF.deserialize(input, 0)
57
+ output.should == {'a' => 'b', 'c' => 'd'}
58
+ end
59
+
60
+ it "should deserialize hashes with empty string keys" do
61
+ input = object_fixture('amf0-empty-string-key-hash.bin')
62
+ output = RocketAMF.deserialize(input, 0)
63
+ output.should == {'a' => 'b', 'c' => 'd', '' => 'last'}
64
+ end
65
+
66
+ it "should deserialize arrays from flash player" do
67
+ # Even Array is serialized as a "hash"
68
+ input = object_fixture('amf0-ecma-ordinal-array.bin')
69
+ output = RocketAMF.deserialize(input, 0)
70
+ output.should == {'0' => 'a', '1' => 'b', '2' => 'c', '3' => 'd'}
71
+ end
72
+
73
+ it "should deserialize strict arrays" do
74
+ input = object_fixture('amf0-strict-array.bin')
75
+ output = RocketAMF.deserialize(input, 0)
76
+ output.should == ['a', 'b', 'c', 'd']
77
+ end
78
+
79
+ it "should deserialize dates" do
80
+ input = object_fixture('amf0-time.bin')
81
+ output = RocketAMF.deserialize(input, 0)
82
+ output.should == Time.utc(2003, 2, 13, 5)
83
+ end
84
+
85
+ it "should deserialize an XML document" do
86
+ input = object_fixture('amf0-xml-doc.bin')
87
+ output = RocketAMF.deserialize(input, 0)
88
+ output.should == '<parent><child prop="test" /></parent>'
89
+ end
90
+
91
+ it "should deserialize anonymous objects" do
92
+ input = object_fixture('amf0-object.bin')
93
+ output = RocketAMF.deserialize(input, 0)
94
+ output.should == {'foo' => 'baz', 'bar' => 3.14}
95
+ output.type.should == ""
96
+ end
97
+
98
+ it "should deserialize an unmapped object as a dynamic anonymous object" do
99
+ input = object_fixture("amf0-typed-object.bin")
100
+ output = RocketAMF.deserialize(input, 0)
101
+
102
+ output.type.should == 'org.amf.ASClass'
103
+ output.should == {'foo' => 'bar', 'baz' => nil}
104
+ end
105
+
106
+ it "should deserialize a mapped object as a mapped ruby class instance" do
107
+ RocketAMF::ClassMapper.define {|m| m.map :as => 'org.amf.ASClass', :ruby => 'RubyClass'}
108
+
109
+ input = object_fixture("amf0-typed-object.bin")
110
+ output = RocketAMF.deserialize(input, 0)
111
+
112
+ output.should be_a(RubyClass)
113
+ output.foo.should == 'bar'
114
+ output.baz.should == nil
115
+ end
116
+
117
+ it "should deserialize references properly" do
118
+ input = object_fixture('amf0-ref-test.bin')
119
+ output = RocketAMF.deserialize(input, 0)
120
+ output.length.should == 2
121
+ output["0"].should === output["1"]
122
+ end
123
+ end
124
+
125
+ describe "AMF3" do
126
+ it "should update source pos if source is a StringIO object" do
127
+ input = StringIO.new(object_fixture('amf3-null.bin'))
128
+ input.pos.should == 0
129
+ output = RocketAMF.deserialize(input, 3)
130
+ input.pos.should == 1
131
+ end
132
+
133
+ describe "simple messages" do
134
+ it "should deserialize a null" do
135
+ input = object_fixture("amf3-null.bin")
136
+ output = RocketAMF.deserialize(input, 3)
137
+ output.should == nil
138
+ end
139
+
140
+ it "should deserialize a false" do
141
+ input = object_fixture("amf3-false.bin")
142
+ output = RocketAMF.deserialize(input, 3)
143
+ output.should == false
144
+ end
145
+
146
+ it "should deserialize a true" do
147
+ input = object_fixture("amf3-true.bin")
148
+ output = RocketAMF.deserialize(input, 3)
149
+ output.should == true
150
+ end
151
+
152
+ it "should deserialize integers" do
153
+ input = object_fixture("amf3-max.bin")
154
+ output = RocketAMF.deserialize(input, 3)
155
+ output.should == RocketAMF::MAX_INTEGER
156
+
157
+ input = object_fixture("amf3-0.bin")
158
+ output = RocketAMF.deserialize(input, 3)
159
+ output.should == 0
160
+
161
+ input = object_fixture("amf3-min.bin")
162
+ output = RocketAMF.deserialize(input, 3)
163
+ output.should == RocketAMF::MIN_INTEGER
164
+ end
165
+
166
+ it "should deserialize large integers" do
167
+ input = object_fixture("amf3-large-max.bin")
168
+ output = RocketAMF.deserialize(input, 3)
169
+ output.should == RocketAMF::MAX_INTEGER + 1
170
+
171
+ input = object_fixture("amf3-large-min.bin")
172
+ output = RocketAMF.deserialize(input, 3)
173
+ output.should == RocketAMF::MIN_INTEGER - 1
174
+ end
175
+
176
+ it "should deserialize BigNums" do
177
+ input = object_fixture("amf3-bignum.bin")
178
+ output = RocketAMF.deserialize(input, 3)
179
+ output.should == 2**1000
180
+ end
181
+
182
+ it "should deserialize a simple string" do
183
+ input = object_fixture("amf3-string.bin")
184
+ output = RocketAMF.deserialize(input, 3)
185
+ output.should == "String . String"
186
+ end
187
+
188
+ it "should deserialize a symbol as a string" do
189
+ input = object_fixture("amf3-symbol.bin")
190
+ output = RocketAMF.deserialize(input, 3)
191
+ output.should == "foo"
192
+ end
193
+
194
+ it "should deserialize dates" do
195
+ input = object_fixture("amf3-date.bin")
196
+ output = RocketAMF.deserialize(input, 3)
197
+ output.should == Time.at(0)
198
+ end
199
+
200
+ it "should deserialize XML" do
201
+ # XMLDocument tag
202
+ input = object_fixture("amf3-xml-doc.bin")
203
+ output = RocketAMF.deserialize(input, 3)
204
+ output.should == '<parent><child prop="test" /></parent>'
205
+
206
+ # XML tag
207
+ input = object_fixture("amf3-xml.bin")
208
+ output = RocketAMF.deserialize(input, 3)
209
+ output.should == '<parent><child prop="test"/></parent>'
210
+ end
211
+ end
212
+
213
+ describe "objects" do
214
+ it "should deserialize an unmapped object as a dynamic anonymous object" do
215
+ input = object_fixture("amf3-dynamic-object.bin")
216
+ output = RocketAMF.deserialize(input, 3)
217
+
218
+ expected = {
219
+ 'property_one' => 'foo',
220
+ 'nil_property' => nil,
221
+ 'another_public_property' => 'a_public_value'
222
+ }
223
+ output.should == expected
224
+ output.type.should == ""
225
+ end
226
+
227
+ it "should deserialize a mapped object as a mapped ruby class instance" do
228
+ RocketAMF::ClassMapper.define {|m| m.map :as => 'org.amf.ASClass', :ruby => 'RubyClass'}
229
+
230
+ input = object_fixture("amf3-typed-object.bin")
231
+ output = RocketAMF.deserialize(input, 3)
232
+
233
+ output.should be_a(RubyClass)
234
+ output.foo.should == 'bar'
235
+ output.baz.should == nil
236
+ end
237
+
238
+ it "should deserialize externalizable objects" do
239
+ RocketAMF::ClassMapper.define {|m| m.map :as => 'ExternalizableTest', :ruby => 'ExternalizableTest'}
240
+
241
+ input = object_fixture("amf3-externalizable.bin")
242
+ output = RocketAMF.deserialize(input, 3)
243
+
244
+ output.length.should == 2
245
+ output[0].one.should == 5
246
+ output[1].two.should == 5
247
+ end
248
+
249
+ it "should deserialize a hash as a dynamic anonymous object" do
250
+ input = object_fixture("amf3-hash.bin")
251
+ output = RocketAMF.deserialize(input, 3)
252
+ output.should == {'foo' => "bar", 'answer' => 42}
253
+ end
254
+
255
+ it "should deserialize an empty array" do
256
+ input = object_fixture("amf3-empty-array.bin")
257
+ output = RocketAMF.deserialize(input, 3)
258
+ output.should == []
259
+ end
260
+
261
+ it "should deserialize an array of primitives" do
262
+ input = object_fixture("amf3-primitive-array.bin")
263
+ output = RocketAMF.deserialize(input, 3)
264
+ output.should == [1,2,3,4,5]
265
+ end
266
+
267
+ it "should deserialize an associative array" do
268
+ input = object_fixture("amf3-associative-array.bin")
269
+ output = RocketAMF.deserialize(input, 3)
270
+ output.should == {0=>"bar1", 1=>"bar2", 2=>"bar3", "asdf"=>"fdsa", "foo"=>"bar", "42"=>"bar"}
271
+ end
272
+
273
+ it "should deserialize an array of mixed objects" do
274
+ input = object_fixture("amf3-mixed-array.bin")
275
+ output = RocketAMF.deserialize(input, 3)
276
+
277
+ h1 = {'foo_one' => "bar_one"}
278
+ h2 = {'foo_two' => ""}
279
+ so1 = {'foo_three' => 42}
280
+ output.should == [h1, h2, so1, {}, [h1, h2, so1], [], 42, "", [], "", {}, "bar_one", so1]
281
+ end
282
+
283
+ it "should deserialize an array collection as an array" do
284
+ input = object_fixture("amf3-array-collection.bin")
285
+ output = RocketAMF.deserialize(input, 3)
286
+
287
+ output.class.should == Array
288
+ output.should == ["foo", "bar"]
289
+ end
290
+
291
+ it "should deserialize a complex set of array collections" do
292
+ RocketAMF::ClassMapper.define {|m| m.map :as => 'org.amf.ASClass', :ruby => 'RubyClass'}
293
+ input = object_fixture('amf3-complex-array-collection.bin')
294
+
295
+ output = RocketAMF.deserialize(input, 3)
296
+
297
+ output[0].should == ["foo", "bar"]
298
+ output[1][0].should be_a(RubyClass)
299
+ output[1][1].should be_a(RubyClass)
300
+ output[2].should === output[1]
301
+ end
302
+
303
+ it "should deserialize a byte array" do
304
+ input = object_fixture("amf3-byte-array.bin")
305
+ output = RocketAMF.deserialize(input, 3)
306
+
307
+ output.should be_a(StringIO)
308
+ expected = "\000\003これtest\100"
309
+ expected.force_encoding("ASCII-8BIT") if expected.respond_to?(:force_encoding)
310
+ output.string.should == expected
311
+ end
312
+
313
+ it "should deserialize an empty dictionary" do
314
+ input = object_fixture("amf3-empty-dictionary.bin")
315
+ output = RocketAMF.deserialize(input, 3)
316
+ output.should == {}
317
+ end
318
+
319
+ it "should deserialize a dictionary" do
320
+ input = object_fixture("amf3-dictionary.bin")
321
+ output = RocketAMF.deserialize(input, 3)
322
+
323
+ keys = output.keys
324
+ keys.length.should == 2
325
+ obj_key, str_key = keys[0].is_a?(RocketAMF::Values::TypedHash) ? [keys[0], keys[1]] : [keys[1], keys[0]]
326
+ obj_key.type.should == 'org.amf.ASClass'
327
+ output[obj_key].should == "asdf2"
328
+ str_key.should == "bar"
329
+ output[str_key].should == "asdf1"
330
+ end
331
+
332
+ it "should deserialize Vector.<int>" do
333
+ input = object_fixture('amf3-vector-int.bin')
334
+ output = RocketAMF.deserialize(input, 3)
335
+ output.should == [4, -20, 12]
336
+ end
337
+
338
+ it "should deserialize Vector.<uint>" do
339
+ input = object_fixture('amf3-vector-uint.bin')
340
+ output = RocketAMF.deserialize(input, 3)
341
+ output.should == [4, 20, 12]
342
+ end
343
+
344
+ it "should deserialize Vector.<Number>" do
345
+ input = object_fixture('amf3-vector-double.bin')
346
+ output = RocketAMF.deserialize(input, 3)
347
+ output.should == [4.3, -20.6]
348
+ end
349
+
350
+ it "should deserialize Vector.<Object>" do
351
+ input = object_fixture('amf3-vector-object.bin')
352
+ output = RocketAMF.deserialize(input, 3)
353
+ output[0]['foo'].should == 'foo'
354
+ output[1].type.should == 'org.amf.ASClass'
355
+ output[2]['foo'].should == 'baz'
356
+ end
357
+ end
358
+
359
+ describe "and implementing the AMF Spec" do
360
+ it "should keep references of duplicate strings" do
361
+ input = object_fixture("amf3-string-ref.bin")
362
+ output = RocketAMF.deserialize(input, 3)
363
+
364
+ foo = "foo"
365
+ bar = "str"
366
+ output.should == [foo, bar, foo, bar, foo, {'str' => "foo"}]
367
+ end
368
+
369
+ it "should not reference the empty string" do
370
+ input = object_fixture("amf3-empty-string-ref.bin")
371
+ output = RocketAMF.deserialize(input, 3)
372
+ output.should == ["",""]
373
+ end
374
+
375
+ it "should keep references of duplicate dates" do
376
+ input = object_fixture("amf3-date-ref.bin")
377
+ output = RocketAMF.deserialize(input, 3)
378
+
379
+ output[0].should == Time.at(0)
380
+ output[0].should equal(output[1])
381
+ # Expected object:
382
+ # [DateTime.parse "1/1/1970", DateTime.parse "1/1/1970"]
383
+ end
384
+
385
+ it "should keep reference of duplicate objects" do
386
+ input = object_fixture("amf3-object-ref.bin")
387
+ output = RocketAMF.deserialize(input, 3)
388
+
389
+ obj1 = {'foo' => "bar"}
390
+ obj2 = {'foo' => obj1['foo']}
391
+ output.should == [[obj1, obj2], "bar", [obj1, obj2]]
392
+ end
393
+
394
+ it "should keep reference of duplicate object traits" do
395
+ RocketAMF::ClassMapper.define {|m| m.map :as => 'org.amf.ASClass', :ruby => 'RubyClass'}
396
+
397
+ input = object_fixture("amf3-trait-ref.bin")
398
+ output = RocketAMF.deserialize(input, 3)
399
+
400
+ output[0].foo.should == "foo"
401
+ output[1].foo.should == "bar"
402
+ end
403
+
404
+ it "should keep references of duplicate arrays" do
405
+ input = object_fixture("amf3-array-ref.bin")
406
+ output = RocketAMF.deserialize(input, 3)
407
+
408
+ a = [1,2,3]
409
+ b = %w{ a b c }
410
+ output.should == [a, b, a, b]
411
+ end
412
+
413
+ it "should not keep references of duplicate empty arrays unless the object_id matches" do
414
+ input = object_fixture("amf3-empty-array-ref.bin")
415
+ output = RocketAMF.deserialize(input, 3)
416
+
417
+ a = []
418
+ b = []
419
+ output.should == [a,b,a,b]
420
+ end
421
+
422
+ it "should keep references of duplicate XML and XMLDocuments" do
423
+ input = object_fixture("amf3-xml-ref.bin")
424
+ output = RocketAMF.deserialize(input, 3)
425
+ output.should == ['<parent><child prop="test"/></parent>', '<parent><child prop="test"/></parent>']
426
+ end
427
+
428
+ it "should keep references of duplicate byte arrays" do
429
+ input = object_fixture("amf3-byte-array-ref.bin")
430
+ output = RocketAMF.deserialize(input, 3)
431
+ output[0].object_id.should == output[1].object_id
432
+ output[0].string.should == "ASDF"
433
+ end
434
+
435
+ it "should deserialize a deep object graph with circular references" do
436
+ input = object_fixture("amf3-graph-member.bin")
437
+ output = RocketAMF.deserialize(input, 3)
438
+
439
+ output['children'][0]['parent'].should === output
440
+ output['parent'].should === nil
441
+ output['children'].length.should == 2
442
+ # Expected object:
443
+ # parent = Hash.new
444
+ # child1 = Hash.new
445
+ # child1[:parent] = parent
446
+ # child1[:children] = []
447
+ # child2 = Hash.new
448
+ # child2[:parent] = parent
449
+ # child2[:children] = []
450
+ # parent[:parent] = nil
451
+ # parent[:children] = [child1, child2]
452
+ end
453
+ end
454
+ end
455
+ end