mrpin-rocketamf 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +7 -0
  2. data/README.rdoc +47 -0
  3. data/Rakefile +59 -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/mrpin-rocketamf.gemspec +22 -0
  29. data/spec/class_mapping_spec.rb +110 -0
  30. data/spec/deserializer_spec.rb +455 -0
  31. data/spec/fast_class_mapping_spec.rb +144 -0
  32. data/spec/fixtures/objects/amf0-boolean.bin +1 -0
  33. data/spec/fixtures/objects/amf0-complex-encoded-string.bin +0 -0
  34. data/spec/fixtures/objects/amf0-date.bin +0 -0
  35. data/spec/fixtures/objects/amf0-ecma-ordinal-array.bin +0 -0
  36. data/spec/fixtures/objects/amf0-empty-string-key-hash.bin +0 -0
  37. data/spec/fixtures/objects/amf0-hash.bin +0 -0
  38. data/spec/fixtures/objects/amf0-null.bin +1 -0
  39. data/spec/fixtures/objects/amf0-number.bin +0 -0
  40. data/spec/fixtures/objects/amf0-object.bin +0 -0
  41. data/spec/fixtures/objects/amf0-ref-test.bin +0 -0
  42. data/spec/fixtures/objects/amf0-strict-array.bin +0 -0
  43. data/spec/fixtures/objects/amf0-string.bin +0 -0
  44. data/spec/fixtures/objects/amf0-time.bin +0 -0
  45. data/spec/fixtures/objects/amf0-typed-object.bin +0 -0
  46. data/spec/fixtures/objects/amf0-undefined.bin +1 -0
  47. data/spec/fixtures/objects/amf0-untyped-object.bin +0 -0
  48. data/spec/fixtures/objects/amf0-xml-doc.bin +0 -0
  49. data/spec/fixtures/objects/amf3-0.bin +0 -0
  50. data/spec/fixtures/objects/amf3-array-collection.bin +2 -0
  51. data/spec/fixtures/objects/amf3-array-ref.bin +1 -0
  52. data/spec/fixtures/objects/amf3-associative-array.bin +1 -0
  53. data/spec/fixtures/objects/amf3-bigNum.bin +0 -0
  54. data/spec/fixtures/objects/amf3-byte-array-ref.bin +1 -0
  55. data/spec/fixtures/objects/amf3-byte-array.bin +0 -0
  56. data/spec/fixtures/objects/amf3-complex-array-collection.bin +6 -0
  57. data/spec/fixtures/objects/amf3-complex-encoded-string-array.bin +1 -0
  58. data/spec/fixtures/objects/amf3-date-ref.bin +0 -0
  59. data/spec/fixtures/objects/amf3-date.bin +0 -0
  60. data/spec/fixtures/objects/amf3-dictionary.bin +0 -0
  61. data/spec/fixtures/objects/amf3-dynamic-object.bin +2 -0
  62. data/spec/fixtures/objects/amf3-empty-array-ref.bin +1 -0
  63. data/spec/fixtures/objects/amf3-empty-array.bin +1 -0
  64. data/spec/fixtures/objects/amf3-empty-dictionary.bin +0 -0
  65. data/spec/fixtures/objects/amf3-empty-string-ref.bin +1 -0
  66. data/spec/fixtures/objects/amf3-encoded-string-ref.bin +0 -0
  67. data/spec/fixtures/objects/amf3-externalizable.bin +0 -0
  68. data/spec/fixtures/objects/amf3-false.bin +1 -0
  69. data/spec/fixtures/objects/amf3-float.bin +0 -0
  70. data/spec/fixtures/objects/amf3-graph-member.bin +0 -0
  71. data/spec/fixtures/objects/amf3-hash.bin +2 -0
  72. data/spec/fixtures/objects/amf3-large-max.bin +0 -0
  73. data/spec/fixtures/objects/amf3-large-min.bin +0 -0
  74. data/spec/fixtures/objects/amf3-max.bin +1 -0
  75. data/spec/fixtures/objects/amf3-min.bin +0 -0
  76. data/spec/fixtures/objects/amf3-mixed-array.bin +10 -0
  77. data/spec/fixtures/objects/amf3-null.bin +1 -0
  78. data/spec/fixtures/objects/amf3-object-ref.bin +0 -0
  79. data/spec/fixtures/objects/amf3-primitive-array.bin +1 -0
  80. data/spec/fixtures/objects/amf3-string-ref.bin +0 -0
  81. data/spec/fixtures/objects/amf3-string.bin +1 -0
  82. data/spec/fixtures/objects/amf3-symbol.bin +1 -0
  83. data/spec/fixtures/objects/amf3-trait-ref.bin +3 -0
  84. data/spec/fixtures/objects/amf3-true.bin +1 -0
  85. data/spec/fixtures/objects/amf3-typed-object.bin +2 -0
  86. data/spec/fixtures/objects/amf3-vector-double.bin +0 -0
  87. data/spec/fixtures/objects/amf3-vector-int.bin +0 -0
  88. data/spec/fixtures/objects/amf3-vector-object.bin +0 -0
  89. data/spec/fixtures/objects/amf3-vector-uint.bin +0 -0
  90. data/spec/fixtures/objects/amf3-xml-doc.bin +1 -0
  91. data/spec/fixtures/objects/amf3-xml-ref.bin +1 -0
  92. data/spec/fixtures/objects/amf3-xml.bin +1 -0
  93. data/spec/fixtures/request/acknowledge-response.bin +0 -0
  94. data/spec/fixtures/request/amf0-error-response.bin +0 -0
  95. data/spec/fixtures/request/blaze-response.bin +0 -0
  96. data/spec/fixtures/request/commandMessage.bin +0 -0
  97. data/spec/fixtures/request/flex-request.bin +0 -0
  98. data/spec/fixtures/request/multiple-simple-request.bin +0 -0
  99. data/spec/fixtures/request/remotingMessage.bin +0 -0
  100. data/spec/fixtures/request/simple-request.bin +0 -0
  101. data/spec/fixtures/request/simple-response.bin +0 -0
  102. data/spec/fixtures/request/unsupportedCommandMessage.bin +0 -0
  103. data/spec/messages_spec.rb +39 -0
  104. data/spec/remoting_spec.rb +196 -0
  105. data/spec/serializer_spec.rb +503 -0
  106. data/spec/spec_helper.rb +55 -0
  107. metadata +176 -0
@@ -0,0 +1,503 @@
1
+ # encoding: UTF-8
2
+
3
+ require "spec_helper.rb"
4
+ require 'rexml/document'
5
+ require 'bigdecimal'
6
+ require 'rational'
7
+
8
+ describe "when serializing" do
9
+ before :each do
10
+ RocketAMF::ClassMapper.reset
11
+ end
12
+
13
+ it "should raise exception with invalid version number" do
14
+ lambda {
15
+ RocketAMF.serialize("", 5)
16
+ }.should raise_error("unsupported version 5")
17
+ end
18
+
19
+ describe "AMF0" do
20
+ it "should serialize nils" do
21
+ output = RocketAMF.serialize(nil, 0)
22
+ output.should == object_fixture('amf0-null.bin')
23
+ end
24
+
25
+ it "should serialize booleans" do
26
+ output = RocketAMF.serialize(true, 0)
27
+ output.should === object_fixture('amf0-boolean.bin')
28
+ end
29
+
30
+ it "should serialize numbers" do
31
+ output = RocketAMF.serialize(3.5, 0)
32
+ output.should == object_fixture('amf0-number.bin')
33
+ end
34
+
35
+ it "should serialize Numeric conformers" do
36
+ output = RocketAMF.serialize(BigDecimal.new("3.5"), 0)
37
+ output.should == object_fixture('amf0-number.bin')
38
+ end
39
+
40
+ it "should serialize strings" do
41
+ output = RocketAMF.serialize("this is a テスト", 0)
42
+ output.should == object_fixture('amf0-string.bin')
43
+ end
44
+
45
+ it "should serialize frozen strings" do
46
+ output = RocketAMF.serialize("this is a テスト".freeze, 0)
47
+ output.should == object_fixture('amf0-string.bin')
48
+ end
49
+
50
+ it "should serialize arrays" do
51
+ output = RocketAMF.serialize(['a', 'b', 'c', 'd'], 0)
52
+ output.should == object_fixture('amf0-strict-array.bin')
53
+ end
54
+
55
+ it "should serialize references" do
56
+ obj = OtherClass.new
57
+ obj.foo = "baz"
58
+ obj.bar = 3.14
59
+
60
+ output = RocketAMF.serialize({'0' => obj, '1' => obj}, 0)
61
+ output.should == object_fixture('amf0-ref-test.bin')
62
+ end
63
+
64
+ it "should serialize Time objects" do
65
+ output = RocketAMF.serialize(Time.utc(2003, 2, 13, 5), 0)
66
+ output.bytesize.should == 11
67
+ output[0,9].should == object_fixture('amf0-time.bin')[0,9] # Ignore TZ
68
+ end
69
+
70
+ it "should serialize Date objects" do
71
+ output = RocketAMF.serialize(Date.civil(2020, 5, 30), 0)
72
+ output.bytesize.should == 11
73
+ output[0,9].should == object_fixture('amf0-date.bin')[0,9] # Ignore TZ
74
+ end
75
+
76
+ it "should serialize DateTime objects" do
77
+ output = RocketAMF.serialize(DateTime.civil(2003, 2, 13, 5), 0)
78
+ output.bytesize.should == 11
79
+ output[0,9].should == object_fixture('amf0-time.bin')[0,9] # Ignore TZ
80
+ end
81
+
82
+ it "should serialize hashes as objects" do
83
+ output = RocketAMF.serialize({:baz => nil, "foo" => "bar"}, 0)
84
+ output.should == object_fixture('amf0-untyped-object.bin')
85
+ end
86
+
87
+ it "should serialize unmapped objects" do
88
+ obj = RubyClass.new
89
+ obj.foo = "bar"
90
+
91
+ output = RocketAMF.serialize(obj, 0)
92
+ output.should == object_fixture('amf0-untyped-object.bin')
93
+ end
94
+
95
+ it "should serialize mapped objects" do
96
+ obj = RubyClass.new
97
+ obj.foo = "bar"
98
+ RocketAMF::ClassMapper.define {|m| m.map :as => 'org.amf.ASClass', :ruby => 'RubyClass'}
99
+
100
+ output = RocketAMF.serialize(obj, 0)
101
+ output.should == object_fixture('amf0-typed-object.bin')
102
+ end
103
+
104
+ describe "and handling encodings", :if => "".respond_to?(:force_encoding) do
105
+ it "should support multiple encodings" do
106
+ shift_str = "\x53\x68\x69\x66\x74\x20\x83\x65\x83\x58\x83\x67".force_encoding("Shift_JIS") # "Shift テスト"
107
+ utf_str = "\x55\x54\x46\x20\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88".force_encoding("UTF-8") # "UTF テスト"
108
+ output = RocketAMF.serialize({:shift => shift_str, :utf => utf_str, :zed => 5}, 0)
109
+ output.should == object_fixture("amf0-complex-encoded-string.bin")
110
+ end
111
+ end
112
+ end
113
+
114
+ describe "AMF3" do
115
+ describe "simple messages" do
116
+ it "should serialize a null" do
117
+ expected = object_fixture("amf3-null.bin")
118
+ output = RocketAMF.serialize(nil, 3)
119
+ output.should == expected
120
+ end
121
+
122
+ it "should serialize a false" do
123
+ expected = object_fixture("amf3-false.bin")
124
+ output = RocketAMF.serialize(false, 3)
125
+ output.should == expected
126
+ end
127
+
128
+ it "should serialize a true" do
129
+ expected = object_fixture("amf3-true.bin")
130
+ output = RocketAMF.serialize(true, 3)
131
+ output.should == expected
132
+ end
133
+
134
+ it "should serialize integers" do
135
+ expected = object_fixture("amf3-max.bin")
136
+ input = RocketAMF::MAX_INTEGER
137
+ output = RocketAMF.serialize(input, 3)
138
+ output.should == expected
139
+
140
+ expected = object_fixture("amf3-0.bin")
141
+ output = RocketAMF.serialize(0, 3)
142
+ output.should == expected
143
+
144
+ expected = object_fixture("amf3-min.bin")
145
+ input = RocketAMF::MIN_INTEGER
146
+ output = RocketAMF.serialize(input, 3)
147
+ output.should == expected
148
+ end
149
+
150
+ it "should serialize large integers" do
151
+ expected = object_fixture("amf3-large-max.bin")
152
+ input = RocketAMF::MAX_INTEGER + 1
153
+ output = RocketAMF.serialize(input, 3)
154
+ output.should == expected
155
+
156
+ expected = object_fixture("amf3-large-min.bin")
157
+ input = RocketAMF::MIN_INTEGER - 1
158
+ output = RocketAMF.serialize(input, 3)
159
+ output.should == expected
160
+ end
161
+
162
+ it "should serialize floats" do
163
+ expected = object_fixture("amf3-float.bin")
164
+ input = 3.5
165
+ output = RocketAMF.serialize(input, 3)
166
+ output.should == expected
167
+ end
168
+
169
+ it "should serialize BigNums" do
170
+ expected = object_fixture("amf3-bigNum.bin")
171
+ input = 2**1000
172
+ output = RocketAMF.serialize(input, 3)
173
+ output.should == expected
174
+ end
175
+
176
+ it "should serialize float Numeric conformers" do
177
+ expected = object_fixture("amf3-float.bin")
178
+ input = Rational(7, 2) # 3.5
179
+ output = RocketAMF.serialize(input, 3)
180
+ output.should == expected
181
+ end
182
+
183
+ it "should serialize a simple string" do
184
+ expected = object_fixture("amf3-string.bin")
185
+ input = "String . String"
186
+ output = RocketAMF.serialize(input, 3)
187
+ output.should == expected
188
+ end
189
+
190
+ it "should serialize a frozen string" do
191
+ expected = object_fixture("amf3-string.bin")
192
+ input = "String . String".freeze
193
+ output = RocketAMF.serialize(input, 3)
194
+ output.should == expected
195
+ end
196
+
197
+ it "should serialize a symbol as a string" do
198
+ expected = object_fixture("amf3-symbol.bin")
199
+ output = RocketAMF.serialize(:foo, 3)
200
+ output.should == expected
201
+ end
202
+
203
+ it "should serialize Time objects" do
204
+ expected = object_fixture("amf3-date.bin")
205
+ input = Time.utc 1970, 1, 1, 0
206
+ output = RocketAMF.serialize(input, 3)
207
+ output.should == expected
208
+ end
209
+
210
+ it "should serialize Date objects" do
211
+ expected = object_fixture("amf3-date.bin")
212
+ input = Date.civil 1970, 1, 1, 0
213
+ output = RocketAMF.serialize(input, 3)
214
+ output.should == expected
215
+ end
216
+
217
+ it "should serialize DateTime objects" do
218
+ expected = object_fixture("amf3-date.bin")
219
+ input = DateTime.civil 1970, 1, 1, 0
220
+ output = RocketAMF.serialize(input, 3)
221
+ output.should == expected
222
+ end
223
+ end
224
+
225
+ describe "objects" do
226
+ it "should serialize an unmapped object as a dynamic anonymous object" do
227
+ class NonMappedObject
228
+ def another_public_property
229
+ 'a_public_value'
230
+ end
231
+
232
+ attr_accessor :nil_property
233
+ attr_accessor :property_one
234
+ attr_writer :read_only_prop
235
+
236
+ def method_with_arg arg='foo'
237
+ arg
238
+ end
239
+ end
240
+ obj = NonMappedObject.new
241
+ obj.property_one = 'foo'
242
+ obj.nil_property = nil
243
+
244
+ expected = object_fixture("amf3-dynamic-object.bin")
245
+ input = obj
246
+ output = RocketAMF.serialize(input, 3)
247
+ output.should == expected
248
+ end
249
+
250
+ it "should serialize externalizable objects" do
251
+ a = ExternalizableTest.new
252
+ a.one = 5
253
+ a.two = 7
254
+ b = ExternalizableTest.new
255
+ b.one = 13
256
+ b.two = 5
257
+ obj = [a, b]
258
+
259
+ expected = object_fixture("amf3-externalizable.bin")
260
+ input = obj
261
+ output = RocketAMF.serialize(input, 3)
262
+ output.should == expected
263
+ end
264
+
265
+ it "should serialize a hash as a dynamic anonymous object" do
266
+ hash = {}
267
+ hash[:answer] = 42
268
+ hash['foo'] = "bar"
269
+
270
+ expected = object_fixture("amf3-hash.bin")
271
+ input = hash
272
+ output = RocketAMF.serialize(input, 3)
273
+ output.should == expected
274
+ end
275
+
276
+ it "should serialize an empty array" do
277
+ expected = object_fixture("amf3-empty-array.bin")
278
+ input = []
279
+ output = RocketAMF.serialize(input, 3)
280
+ output.should == expected
281
+ end
282
+
283
+ it "should serialize an array of primatives" do
284
+ expected = object_fixture("amf3-primitive-array.bin")
285
+ input = [1, 2, 3, 4, 5]
286
+ output = RocketAMF.serialize(input, 3)
287
+ output.should == expected
288
+ end
289
+
290
+ it "should serialize an array of mixed objects" do
291
+ h1 = {:foo_one => "bar_one"}
292
+ h2 = {:foo_two => ""}
293
+ class SimpleObj
294
+ attr_accessor :foo_three
295
+ end
296
+ so1 = SimpleObj.new
297
+ so1.foo_three = 42
298
+
299
+ expected = object_fixture("amf3-mixed-array.bin")
300
+ input = [h1, h2, so1, {}, [h1, h2, so1], [], 42, "", [], "", {}, "bar_one", so1]
301
+ output = RocketAMF.serialize(input, 3)
302
+ output.should == expected
303
+ end
304
+
305
+ it "should serialize an array as an array collection" do
306
+ expected = object_fixture('amf3-array-collection.bin')
307
+
308
+ # Test global
309
+ RocketAMF::ClassMapper.use_array_collection = true
310
+ input = ["foo", "bar"]
311
+ output = RocketAMF.serialize(input, 3)
312
+ output.should == expected
313
+ RocketAMF::ClassMapper.use_array_collection = false
314
+
315
+ # Test override
316
+ input = ["foo", "bar"]
317
+ input.is_array_collection = true
318
+ output = RocketAMF.serialize(input, 3)
319
+ output.should == expected
320
+ end
321
+
322
+ it "should serialize a complex set of array collections" do
323
+ RocketAMF::ClassMapper.define {|m| m.map :as => 'org.amf.ASClass', :ruby => 'RubyClass'}
324
+ expected = object_fixture('amf3-complex-array-collection.bin')
325
+
326
+ a = ["foo", "bar"]
327
+ a.is_array_collection = true
328
+ obj1 = RubyClass.new
329
+ obj1.foo = "bar"
330
+ def obj1.encode_amf serializer
331
+ serializer.write_object(self, nil, {:class_name => 'org.amf.ASClass', :dynamic => false, :externalizable => false, :members => ["baz", "foo"]})
332
+ end
333
+ obj2 = RubyClass.new
334
+ obj2.foo = "asdf"
335
+ def obj2.encode_amf serializer
336
+ serializer.write_object(self, nil, {:class_name => 'org.amf.ASClass', :dynamic => false, :externalizable => false, :members => ["baz", "foo"]})
337
+ end
338
+ b = [obj1, obj2]
339
+ b.is_array_collection = true
340
+ input = [a, b, b]
341
+
342
+ output = RocketAMF.serialize(input, 3)
343
+ output.should == expected
344
+ end
345
+
346
+ it "should serialize a byte array" do
347
+ expected = object_fixture("amf3-byte-array.bin")
348
+ str = "\000\003これtest\100"
349
+ str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
350
+ input = StringIO.new(str)
351
+ output = RocketAMF.serialize(input, 3)
352
+ output.should == expected
353
+ end
354
+ end
355
+
356
+ describe "and implementing the AMF Spec" do
357
+ it "should keep references of duplicate strings" do
358
+ class StringCarrier
359
+ attr_accessor :str
360
+ end
361
+ foo = "foo"
362
+ bar = "str"
363
+ sc = StringCarrier.new
364
+ sc.str = foo
365
+
366
+ expected = object_fixture("amf3-string-ref.bin")
367
+ input = [foo, bar, foo, bar, foo, sc]
368
+ output = RocketAMF.serialize(input, 3)
369
+ output.should == expected
370
+ end
371
+
372
+ it "should not reference the empty string" do
373
+ expected = object_fixture("amf3-empty-string-ref.bin")
374
+ input = ""
375
+ output = RocketAMF.serialize([input,input], 3)
376
+ output.should == expected
377
+ end
378
+
379
+ it "should keep references of duplicate dates" do
380
+ expected = object_fixture("amf3-date-ref.bin")
381
+ input = Time.utc 1970, 1, 1, 0
382
+ output = RocketAMF.serialize([input,input], 3)
383
+ output.should == expected
384
+ end
385
+
386
+ it "should keep reference of duplicate objects" do
387
+ class SimpleReferenceableObj
388
+ attr_accessor :foo
389
+ end
390
+ obj1 = SimpleReferenceableObj.new
391
+ obj1.foo = :bar
392
+ obj2 = SimpleReferenceableObj.new
393
+ obj2.foo = obj1.foo
394
+
395
+ expected = object_fixture("amf3-object-ref.bin")
396
+ input = [[obj1, obj2], "bar", [obj1, obj2]]
397
+ output = RocketAMF.serialize(input, 3)
398
+ output.should == expected
399
+ end
400
+
401
+ it "should keep reference of duplicate object traits" do
402
+ obj1 = RubyClass.new
403
+ obj1.foo = "foo"
404
+ def obj1.encode_amf serializer
405
+ serializer.write_object(self, nil, {:class_name => 'org.amf.ASClass', :dynamic => false, :externalizable => false, :members => ["baz", "foo"]})
406
+ end
407
+ obj2 = RubyClass.new
408
+ obj2.foo = "bar"
409
+ def obj2.encode_amf serializer
410
+ serializer.write_object(self, nil, {:class_name => 'org.amf.ASClass', :dynamic => false, :externalizable => false, :members => ["baz", "foo"]})
411
+ end
412
+ input = [obj1, obj2]
413
+
414
+ expected = object_fixture("amf3-trait-ref.bin")
415
+ output = RocketAMF.serialize(input, 3)
416
+ output.should == expected
417
+ end
418
+
419
+ it "should keep references of duplicate arrays" do
420
+ a = [1,2,3]
421
+ b = %w{ a b c }
422
+
423
+ expected = object_fixture("amf3-array-ref.bin")
424
+ input = [a, b, a, b]
425
+ output = RocketAMF.serialize(input, 3)
426
+ output.should == expected
427
+ end
428
+
429
+ it "should not keep references of duplicate empty arrays unless the object_id matches" do
430
+ a = []
431
+ b = []
432
+ a.should == b
433
+ a.object_id.should_not == b.object_id
434
+
435
+ expected = object_fixture("amf3-empty-array-ref.bin")
436
+ input = [a,b,a,b]
437
+ output = RocketAMF.serialize(input, 3)
438
+ output.should == expected
439
+ end
440
+
441
+ it "should keep references of duplicate byte arrays" do
442
+ b = StringIO.new "ASDF"
443
+
444
+ expected = object_fixture("amf3-byte-array-ref.bin")
445
+ input = [b, b]
446
+ output = RocketAMF.serialize(input, 3)
447
+ output.should == expected
448
+ end
449
+
450
+ it "should serialize a deep object graph with circular references" do
451
+ class GraphMember
452
+ attr_accessor :children
453
+ attr_accessor :parent
454
+
455
+ def initialize
456
+ self.children = []
457
+ end
458
+
459
+ def add_child child
460
+ children << child
461
+ child.parent = self
462
+ child
463
+ end
464
+ end
465
+
466
+ parent = GraphMember.new
467
+ level_1_child_1 = parent.add_child GraphMember.new
468
+ level_1_child_2 = parent.add_child GraphMember.new
469
+
470
+ expected = object_fixture("amf3-graph-member.bin")
471
+ input = parent
472
+ output = RocketAMF.serialize(input, 3)
473
+ output.should == expected
474
+ end
475
+ end
476
+
477
+ describe "and handling encodings", :if => "".respond_to?(:force_encoding) do
478
+ it "should support multiple encodings" do
479
+ shift_str = "\x53\x68\x69\x66\x74\x20\x83\x65\x83\x58\x83\x67".force_encoding("Shift_JIS") # "Shift テスト"
480
+ utf_str = "\x55\x54\x46\x20\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88".force_encoding("UTF-8") # "UTF テスト"
481
+ output = RocketAMF.serialize([5, shift_str, utf_str, 5], 3)
482
+ output.should == object_fixture("amf3-complex-encoded-string-array.bin")
483
+ end
484
+
485
+ it "should keep references of duplicate strings with different encodings" do
486
+ # String is "this is a テスト"
487
+ shift_str = "\x74\x68\x69\x73\x20\x69\x73\x20\x61\x20\x83\x65\x83\x58\x83\x67".force_encoding("Shift_JIS")
488
+ utf_str = "\x74\x68\x69\x73\x20\x69\x73\x20\x61\x20\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88".force_encoding("UTF-8")
489
+
490
+ expected = object_fixture("amf3-encoded-string-ref.bin")
491
+ output = RocketAMF.serialize([shift_str, utf_str], 3)
492
+ output.should == expected
493
+ end
494
+
495
+ it "should handle inappropriate UTF-8 characters in byte arrays" do
496
+ str = "\xff\xff\xff".force_encoding("ASCII-8BIT")
497
+ str.freeze # For added amusement
498
+ output = RocketAMF.serialize(StringIO.new(str), 3)
499
+ output.should == "\x0c\x07\xff\xff\xff".force_encoding("ASCII-8BIT")
500
+ end
501
+ end
502
+ end
503
+ end