ruby_sol 0.1

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 (75) hide show
  1. checksums.yaml +7 -0
  2. data/README.rdoc +90 -0
  3. data/Rakefile +43 -0
  4. data/lib/ruby_sol.rb +113 -0
  5. data/lib/ruby_sol/class_mapping.rb +250 -0
  6. data/lib/ruby_sol/constants.rb +50 -0
  7. data/lib/ruby_sol/extensions.rb +22 -0
  8. data/lib/ruby_sol/pure/deserializer.rb +461 -0
  9. data/lib/ruby_sol/pure/io_helpers.rb +94 -0
  10. data/lib/ruby_sol/pure/serializer.rb +490 -0
  11. data/spec/class_mapping_spec.rb +110 -0
  12. data/spec/deserializer_spec.rb +449 -0
  13. data/spec/fixtures/objects/amf0-boolean.bin +1 -0
  14. data/spec/fixtures/objects/amf0-complex-encoded-string.bin +0 -0
  15. data/spec/fixtures/objects/amf0-date.bin +0 -0
  16. data/spec/fixtures/objects/amf0-ecma-ordinal-array.bin +0 -0
  17. data/spec/fixtures/objects/amf0-hash.bin +0 -0
  18. data/spec/fixtures/objects/amf0-null.bin +1 -0
  19. data/spec/fixtures/objects/amf0-number.bin +0 -0
  20. data/spec/fixtures/objects/amf0-object.bin +0 -0
  21. data/spec/fixtures/objects/amf0-ref-test.bin +0 -0
  22. data/spec/fixtures/objects/amf0-strict-array.bin +0 -0
  23. data/spec/fixtures/objects/amf0-string.bin +0 -0
  24. data/spec/fixtures/objects/amf0-time.bin +0 -0
  25. data/spec/fixtures/objects/amf0-typed-object.bin +0 -0
  26. data/spec/fixtures/objects/amf0-undefined.bin +1 -0
  27. data/spec/fixtures/objects/amf0-untyped-object.bin +0 -0
  28. data/spec/fixtures/objects/amf0-xml-doc.bin +0 -0
  29. data/spec/fixtures/objects/amf3-0.bin +0 -0
  30. data/spec/fixtures/objects/amf3-array-collection.bin +2 -0
  31. data/spec/fixtures/objects/amf3-array-ref.bin +1 -0
  32. data/spec/fixtures/objects/amf3-associative-array.bin +1 -0
  33. data/spec/fixtures/objects/amf3-bigNum.bin +0 -0
  34. data/spec/fixtures/objects/amf3-byte-array-ref.bin +1 -0
  35. data/spec/fixtures/objects/amf3-byte-array.bin +0 -0
  36. data/spec/fixtures/objects/amf3-complex-array-collection.bin +6 -0
  37. data/spec/fixtures/objects/amf3-complex-encoded-string-array.bin +1 -0
  38. data/spec/fixtures/objects/amf3-date-ref.bin +0 -0
  39. data/spec/fixtures/objects/amf3-date.bin +0 -0
  40. data/spec/fixtures/objects/amf3-dictionary.bin +0 -0
  41. data/spec/fixtures/objects/amf3-dynamic-object.bin +2 -0
  42. data/spec/fixtures/objects/amf3-empty-array-ref.bin +1 -0
  43. data/spec/fixtures/objects/amf3-empty-array.bin +1 -0
  44. data/spec/fixtures/objects/amf3-empty-dictionary.bin +0 -0
  45. data/spec/fixtures/objects/amf3-empty-string-ref.bin +1 -0
  46. data/spec/fixtures/objects/amf3-encoded-string-ref.bin +0 -0
  47. data/spec/fixtures/objects/amf3-externalizable.bin +0 -0
  48. data/spec/fixtures/objects/amf3-false.bin +1 -0
  49. data/spec/fixtures/objects/amf3-float.bin +0 -0
  50. data/spec/fixtures/objects/amf3-graph-member.bin +0 -0
  51. data/spec/fixtures/objects/amf3-hash.bin +2 -0
  52. data/spec/fixtures/objects/amf3-large-max.bin +0 -0
  53. data/spec/fixtures/objects/amf3-large-min.bin +0 -0
  54. data/spec/fixtures/objects/amf3-max.bin +1 -0
  55. data/spec/fixtures/objects/amf3-min.bin +0 -0
  56. data/spec/fixtures/objects/amf3-mixed-array.bin +10 -0
  57. data/spec/fixtures/objects/amf3-null.bin +1 -0
  58. data/spec/fixtures/objects/amf3-object-ref.bin +0 -0
  59. data/spec/fixtures/objects/amf3-primitive-array.bin +1 -0
  60. data/spec/fixtures/objects/amf3-string-ref.bin +0 -0
  61. data/spec/fixtures/objects/amf3-string.bin +1 -0
  62. data/spec/fixtures/objects/amf3-symbol.bin +1 -0
  63. data/spec/fixtures/objects/amf3-trait-ref.bin +3 -0
  64. data/spec/fixtures/objects/amf3-true.bin +1 -0
  65. data/spec/fixtures/objects/amf3-typed-object.bin +2 -0
  66. data/spec/fixtures/objects/amf3-vector-double.bin +0 -0
  67. data/spec/fixtures/objects/amf3-vector-int.bin +0 -0
  68. data/spec/fixtures/objects/amf3-vector-object.bin +0 -0
  69. data/spec/fixtures/objects/amf3-vector-uint.bin +0 -0
  70. data/spec/fixtures/objects/amf3-xml-doc.bin +1 -0
  71. data/spec/fixtures/objects/amf3-xml-ref.bin +1 -0
  72. data/spec/fixtures/objects/amf3-xml.bin +1 -0
  73. data/spec/serializer_spec.rb +503 -0
  74. data/spec/spec_helper.rb +59 -0
  75. metadata +128 -0
@@ -0,0 +1 @@
1
+ 
Binary file
Binary file
@@ -0,0 +1 @@
1
+ 
Binary file
@@ -0,0 +1 @@
1
+ 
Binary file
@@ -0,0 +1,2 @@
1
+
2
+ Cflex.messaging.io.ArrayCollection foobar
@@ -0,0 +1 @@
1
+   abc  
@@ -0,0 +1 @@
1
+  asdf fdsafoobar42 bar1 bar2 bar3
@@ -0,0 +1 @@
1
+  ASDF 
@@ -0,0 +1,6 @@
1
+ 
2
+ Cflex.messaging.io.ArrayCollection foobar
3
+  
4
+ #org.amf.ASClassbaz
5
+  asdf
6
+ 
@@ -0,0 +1 @@
1
+ Shift テストUTF テスト
Binary file
@@ -0,0 +1,2 @@
1
+
2
+ /another_public_propertya_public_valuenil_propertyproperty_onefoo
@@ -0,0 +1 @@
1
+     
@@ -0,0 +1 @@
1
+ 
@@ -0,0 +1 @@
1
+ 
@@ -0,0 +1,2 @@
1
+
2
+ 
@@ -0,0 +1 @@
1
+ ����
Binary file
@@ -0,0 +1,10 @@
1
+ 
2
+ foo_onebar_one
3
+ foo_two
4
+ foo_three*
5
+  
6
+ 
7
+ 
8
+  * 
9
+ 
10
+ 
@@ -0,0 +1 @@
1
+ 
@@ -0,0 +1 @@
1
+ 
@@ -0,0 +1 @@
1
+ String . String
@@ -0,0 +1 @@
1
+ foo
@@ -0,0 +1,3 @@
1
+ 
2
+ #org.amf.ASClassbazfoo
3
+ bar
@@ -0,0 +1 @@
1
+ 
@@ -0,0 +1,2 @@
1
+
2
+ #org.amf.ASClassbazfoobar
@@ -0,0 +1 @@
1
+ M<parent><child prop="test" /></parent>
@@ -0,0 +1 @@
1
+  K<parent><child prop="test"/></parent> 
@@ -0,0 +1 @@
1
+ K<parent><child prop="test"/></parent>
@@ -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
+ RubySol::ClassMapper.reset
11
+ end
12
+
13
+ it "should raise exception with invalid version number" do
14
+ lambda {
15
+ RubySol.serialize("", 5)
16
+ }.should raise_error("unsupported version 5")
17
+ end
18
+
19
+ describe "AMF0" do
20
+ it "should serialize nils" do
21
+ output = RubySol.serialize(nil, 0)
22
+ output.should == object_fixture('amf0-null.bin')
23
+ end
24
+
25
+ it "should serialize booleans" do
26
+ output = RubySol.serialize(true, 0)
27
+ output.should === object_fixture('amf0-boolean.bin')
28
+ end
29
+
30
+ it "should serialize numbers" do
31
+ output = RubySol.serialize(3.5, 0)
32
+ output.should == object_fixture('amf0-number.bin')
33
+ end
34
+
35
+ it "should serialize Numeric conformers" do
36
+ output = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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
+ RubySol::ClassMapper.define {|m| m.map :as => 'org.amf.ASClass', :ruby => 'RubyClass'}
99
+
100
+ output = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol::MAX_INTEGER
137
+ output = RubySol.serialize(input, 3)
138
+ output.should == expected
139
+
140
+ expected = object_fixture("amf3-0.bin")
141
+ output = RubySol.serialize(0, 3)
142
+ output.should == expected
143
+
144
+ expected = object_fixture("amf3-min.bin")
145
+ input = RubySol::MIN_INTEGER
146
+ output = RubySol.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 = RubySol::MAX_INTEGER + 1
153
+ output = RubySol.serialize(input, 3)
154
+ output.should == expected
155
+
156
+ expected = object_fixture("amf3-large-min.bin")
157
+ input = RubySol::MIN_INTEGER - 1
158
+ output = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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
+ RubySol::ClassMapper.use_array_collection = true
310
+ input = ["foo", "bar"]
311
+ output = RubySol.serialize(input, 3)
312
+ output.should == expected
313
+ RubySol::ClassMapper.use_array_collection = false
314
+
315
+ # Test override
316
+ input = ["foo", "bar"]
317
+ input.is_array_collection = true
318
+ output = RubySol.serialize(input, 3)
319
+ output.should == expected
320
+ end
321
+
322
+ it "should serialize a complex set of array collections" do
323
+ RubySol::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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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 = RubySol.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