RocketAMF-ouvrages 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) 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 +770 -0
  8. data/ext/rocketamf_ext/deserializer.h +27 -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 +449 -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-hash.bin +0 -0
  36. data/spec/fixtures/objects/amf0-null.bin +1 -0
  37. data/spec/fixtures/objects/amf0-number.bin +0 -0
  38. data/spec/fixtures/objects/amf0-object.bin +0 -0
  39. data/spec/fixtures/objects/amf0-ref-test.bin +0 -0
  40. data/spec/fixtures/objects/amf0-strict-array.bin +0 -0
  41. data/spec/fixtures/objects/amf0-string.bin +0 -0
  42. data/spec/fixtures/objects/amf0-time.bin +0 -0
  43. data/spec/fixtures/objects/amf0-typed-object.bin +0 -0
  44. data/spec/fixtures/objects/amf0-undefined.bin +1 -0
  45. data/spec/fixtures/objects/amf0-untyped-object.bin +0 -0
  46. data/spec/fixtures/objects/amf0-xml-doc.bin +0 -0
  47. data/spec/fixtures/objects/amf3-0.bin +0 -0
  48. data/spec/fixtures/objects/amf3-array-collection.bin +2 -0
  49. data/spec/fixtures/objects/amf3-array-ref.bin +1 -0
  50. data/spec/fixtures/objects/amf3-associative-array.bin +1 -0
  51. data/spec/fixtures/objects/amf3-bigNum.bin +0 -0
  52. data/spec/fixtures/objects/amf3-byte-array-ref.bin +1 -0
  53. data/spec/fixtures/objects/amf3-byte-array.bin +0 -0
  54. data/spec/fixtures/objects/amf3-complex-array-collection.bin +6 -0
  55. data/spec/fixtures/objects/amf3-complex-encoded-string-array.bin +1 -0
  56. data/spec/fixtures/objects/amf3-date-ref.bin +0 -0
  57. data/spec/fixtures/objects/amf3-date.bin +0 -0
  58. data/spec/fixtures/objects/amf3-dictionary.bin +0 -0
  59. data/spec/fixtures/objects/amf3-dynamic-object.bin +2 -0
  60. data/spec/fixtures/objects/amf3-empty-array-ref.bin +1 -0
  61. data/spec/fixtures/objects/amf3-empty-array.bin +1 -0
  62. data/spec/fixtures/objects/amf3-empty-dictionary.bin +0 -0
  63. data/spec/fixtures/objects/amf3-empty-string-ref.bin +1 -0
  64. data/spec/fixtures/objects/amf3-encoded-string-ref.bin +0 -0
  65. data/spec/fixtures/objects/amf3-externalizable.bin +0 -0
  66. data/spec/fixtures/objects/amf3-false.bin +1 -0
  67. data/spec/fixtures/objects/amf3-float.bin +0 -0
  68. data/spec/fixtures/objects/amf3-graph-member.bin +0 -0
  69. data/spec/fixtures/objects/amf3-hash.bin +2 -0
  70. data/spec/fixtures/objects/amf3-large-max.bin +0 -0
  71. data/spec/fixtures/objects/amf3-large-min.bin +0 -0
  72. data/spec/fixtures/objects/amf3-max.bin +1 -0
  73. data/spec/fixtures/objects/amf3-min.bin +0 -0
  74. data/spec/fixtures/objects/amf3-mixed-array.bin +10 -0
  75. data/spec/fixtures/objects/amf3-null.bin +1 -0
  76. data/spec/fixtures/objects/amf3-object-ref.bin +0 -0
  77. data/spec/fixtures/objects/amf3-primitive-array.bin +1 -0
  78. data/spec/fixtures/objects/amf3-string-ref.bin +0 -0
  79. data/spec/fixtures/objects/amf3-string.bin +1 -0
  80. data/spec/fixtures/objects/amf3-symbol.bin +1 -0
  81. data/spec/fixtures/objects/amf3-trait-ref.bin +3 -0
  82. data/spec/fixtures/objects/amf3-true.bin +1 -0
  83. data/spec/fixtures/objects/amf3-typed-object.bin +2 -0
  84. data/spec/fixtures/objects/amf3-vector-double.bin +0 -0
  85. data/spec/fixtures/objects/amf3-vector-int.bin +0 -0
  86. data/spec/fixtures/objects/amf3-vector-object.bin +0 -0
  87. data/spec/fixtures/objects/amf3-vector-uint.bin +0 -0
  88. data/spec/fixtures/objects/amf3-xml-doc.bin +1 -0
  89. data/spec/fixtures/objects/amf3-xml-ref.bin +1 -0
  90. data/spec/fixtures/objects/amf3-xml.bin +1 -0
  91. data/spec/fixtures/request/acknowledge-response.bin +0 -0
  92. data/spec/fixtures/request/amf0-error-response.bin +0 -0
  93. data/spec/fixtures/request/blaze-response.bin +0 -0
  94. data/spec/fixtures/request/commandMessage.bin +0 -0
  95. data/spec/fixtures/request/flex-request.bin +0 -0
  96. data/spec/fixtures/request/multiple-simple-request.bin +0 -0
  97. data/spec/fixtures/request/remotingMessage.bin +0 -0
  98. data/spec/fixtures/request/simple-request.bin +0 -0
  99. data/spec/fixtures/request/simple-response.bin +0 -0
  100. data/spec/fixtures/request/unsupportedCommandMessage.bin +0 -0
  101. data/spec/messages_spec.rb +39 -0
  102. data/spec/remoting_spec.rb +196 -0
  103. data/spec/serializer_spec.rb +503 -0
  104. data/spec/spec_helper.rb +55 -0
  105. metadata +167 -0
@@ -0,0 +1,449 @@
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 arrays from flash player" do
61
+ # Even Array is serialized as a "hash"
62
+ input = object_fixture('amf0-ecma-ordinal-array.bin')
63
+ output = RocketAMF.deserialize(input, 0)
64
+ output.should == {'0' => 'a', '1' => 'b', '2' => 'c', '3' => 'd'}
65
+ end
66
+
67
+ it "should deserialize strict arrays" do
68
+ input = object_fixture('amf0-strict-array.bin')
69
+ output = RocketAMF.deserialize(input, 0)
70
+ output.should == ['a', 'b', 'c', 'd']
71
+ end
72
+
73
+ it "should deserialize dates" do
74
+ input = object_fixture('amf0-time.bin')
75
+ output = RocketAMF.deserialize(input, 0)
76
+ output.should == Time.utc(2003, 2, 13, 5)
77
+ end
78
+
79
+ it "should deserialize an XML document" do
80
+ input = object_fixture('amf0-xml-doc.bin')
81
+ output = RocketAMF.deserialize(input, 0)
82
+ output.should == '<parent><child prop="test" /></parent>'
83
+ end
84
+
85
+ it "should deserialize anonymous objects" do
86
+ input = object_fixture('amf0-object.bin')
87
+ output = RocketAMF.deserialize(input, 0)
88
+ output.should == {'foo' => 'baz', 'bar' => 3.14}
89
+ output.type.should == ""
90
+ end
91
+
92
+ it "should deserialize an unmapped object as a dynamic anonymous object" do
93
+ input = object_fixture("amf0-typed-object.bin")
94
+ output = RocketAMF.deserialize(input, 0)
95
+
96
+ output.type.should == 'org.amf.ASClass'
97
+ output.should == {'foo' => 'bar', 'baz' => nil}
98
+ end
99
+
100
+ it "should deserialize a mapped object as a mapped ruby class instance" do
101
+ RocketAMF::ClassMapper.define {|m| m.map :as => 'org.amf.ASClass', :ruby => 'RubyClass'}
102
+
103
+ input = object_fixture("amf0-typed-object.bin")
104
+ output = RocketAMF.deserialize(input, 0)
105
+
106
+ output.should be_a(RubyClass)
107
+ output.foo.should == 'bar'
108
+ output.baz.should == nil
109
+ end
110
+
111
+ it "should deserialize references properly" do
112
+ input = object_fixture('amf0-ref-test.bin')
113
+ output = RocketAMF.deserialize(input, 0)
114
+ output.length.should == 2
115
+ output["0"].should === output["1"]
116
+ end
117
+ end
118
+
119
+ describe "AMF3" do
120
+ it "should update source pos if source is a StringIO object" do
121
+ input = StringIO.new(object_fixture('amf3-null.bin'))
122
+ input.pos.should == 0
123
+ output = RocketAMF.deserialize(input, 3)
124
+ input.pos.should == 1
125
+ end
126
+
127
+ describe "simple messages" do
128
+ it "should deserialize a null" do
129
+ input = object_fixture("amf3-null.bin")
130
+ output = RocketAMF.deserialize(input, 3)
131
+ output.should == nil
132
+ end
133
+
134
+ it "should deserialize a false" do
135
+ input = object_fixture("amf3-false.bin")
136
+ output = RocketAMF.deserialize(input, 3)
137
+ output.should == false
138
+ end
139
+
140
+ it "should deserialize a true" do
141
+ input = object_fixture("amf3-true.bin")
142
+ output = RocketAMF.deserialize(input, 3)
143
+ output.should == true
144
+ end
145
+
146
+ it "should deserialize integers" do
147
+ input = object_fixture("amf3-max.bin")
148
+ output = RocketAMF.deserialize(input, 3)
149
+ output.should == RocketAMF::MAX_INTEGER
150
+
151
+ input = object_fixture("amf3-0.bin")
152
+ output = RocketAMF.deserialize(input, 3)
153
+ output.should == 0
154
+
155
+ input = object_fixture("amf3-min.bin")
156
+ output = RocketAMF.deserialize(input, 3)
157
+ output.should == RocketAMF::MIN_INTEGER
158
+ end
159
+
160
+ it "should deserialize large integers" do
161
+ input = object_fixture("amf3-large-max.bin")
162
+ output = RocketAMF.deserialize(input, 3)
163
+ output.should == RocketAMF::MAX_INTEGER + 1
164
+
165
+ input = object_fixture("amf3-large-min.bin")
166
+ output = RocketAMF.deserialize(input, 3)
167
+ output.should == RocketAMF::MIN_INTEGER - 1
168
+ end
169
+
170
+ it "should deserialize BigNums" do
171
+ input = object_fixture("amf3-bignum.bin")
172
+ output = RocketAMF.deserialize(input, 3)
173
+ output.should == 2**1000
174
+ end
175
+
176
+ it "should deserialize a simple string" do
177
+ input = object_fixture("amf3-string.bin")
178
+ output = RocketAMF.deserialize(input, 3)
179
+ output.should == "String . String"
180
+ end
181
+
182
+ it "should deserialize a symbol as a string" do
183
+ input = object_fixture("amf3-symbol.bin")
184
+ output = RocketAMF.deserialize(input, 3)
185
+ output.should == "foo"
186
+ end
187
+
188
+ it "should deserialize dates" do
189
+ input = object_fixture("amf3-date.bin")
190
+ output = RocketAMF.deserialize(input, 3)
191
+ output.should == Time.at(0)
192
+ end
193
+
194
+ it "should deserialize XML" do
195
+ # XMLDocument tag
196
+ input = object_fixture("amf3-xml-doc.bin")
197
+ output = RocketAMF.deserialize(input, 3)
198
+ output.should == '<parent><child prop="test" /></parent>'
199
+
200
+ # XML tag
201
+ input = object_fixture("amf3-xml.bin")
202
+ output = RocketAMF.deserialize(input, 3)
203
+ output.should == '<parent><child prop="test"/></parent>'
204
+ end
205
+ end
206
+
207
+ describe "objects" do
208
+ it "should deserialize an unmapped object as a dynamic anonymous object" do
209
+ input = object_fixture("amf3-dynamic-object.bin")
210
+ output = RocketAMF.deserialize(input, 3)
211
+
212
+ expected = {
213
+ 'property_one' => 'foo',
214
+ 'nil_property' => nil,
215
+ 'another_public_property' => 'a_public_value'
216
+ }
217
+ output.should == expected
218
+ output.type.should == ""
219
+ end
220
+
221
+ it "should deserialize a mapped object as a mapped ruby class instance" do
222
+ RocketAMF::ClassMapper.define {|m| m.map :as => 'org.amf.ASClass', :ruby => 'RubyClass'}
223
+
224
+ input = object_fixture("amf3-typed-object.bin")
225
+ output = RocketAMF.deserialize(input, 3)
226
+
227
+ output.should be_a(RubyClass)
228
+ output.foo.should == 'bar'
229
+ output.baz.should == nil
230
+ end
231
+
232
+ it "should deserialize externalizable objects" do
233
+ RocketAMF::ClassMapper.define {|m| m.map :as => 'ExternalizableTest', :ruby => 'ExternalizableTest'}
234
+
235
+ input = object_fixture("amf3-externalizable.bin")
236
+ output = RocketAMF.deserialize(input, 3)
237
+
238
+ output.length.should == 2
239
+ output[0].one.should == 5
240
+ output[1].two.should == 5
241
+ end
242
+
243
+ it "should deserialize a hash as a dynamic anonymous object" do
244
+ input = object_fixture("amf3-hash.bin")
245
+ output = RocketAMF.deserialize(input, 3)
246
+ output.should == {'foo' => "bar", 'answer' => 42}
247
+ end
248
+
249
+ it "should deserialize an empty array" do
250
+ input = object_fixture("amf3-empty-array.bin")
251
+ output = RocketAMF.deserialize(input, 3)
252
+ output.should == []
253
+ end
254
+
255
+ it "should deserialize an array of primitives" do
256
+ input = object_fixture("amf3-primitive-array.bin")
257
+ output = RocketAMF.deserialize(input, 3)
258
+ output.should == [1,2,3,4,5]
259
+ end
260
+
261
+ it "should deserialize an associative array" do
262
+ input = object_fixture("amf3-associative-array.bin")
263
+ output = RocketAMF.deserialize(input, 3)
264
+ output.should == {0=>"bar1", 1=>"bar2", 2=>"bar3", "asdf"=>"fdsa", "foo"=>"bar", "42"=>"bar"}
265
+ end
266
+
267
+ it "should deserialize an array of mixed objects" do
268
+ input = object_fixture("amf3-mixed-array.bin")
269
+ output = RocketAMF.deserialize(input, 3)
270
+
271
+ h1 = {'foo_one' => "bar_one"}
272
+ h2 = {'foo_two' => ""}
273
+ so1 = {'foo_three' => 42}
274
+ output.should == [h1, h2, so1, {}, [h1, h2, so1], [], 42, "", [], "", {}, "bar_one", so1]
275
+ end
276
+
277
+ it "should deserialize an array collection as an array" do
278
+ input = object_fixture("amf3-array-collection.bin")
279
+ output = RocketAMF.deserialize(input, 3)
280
+
281
+ output.class.should == Array
282
+ output.should == ["foo", "bar"]
283
+ end
284
+
285
+ it "should deserialize a complex set of array collections" do
286
+ RocketAMF::ClassMapper.define {|m| m.map :as => 'org.amf.ASClass', :ruby => 'RubyClass'}
287
+ input = object_fixture('amf3-complex-array-collection.bin')
288
+
289
+ output = RocketAMF.deserialize(input, 3)
290
+
291
+ output[0].should == ["foo", "bar"]
292
+ output[1][0].should be_a(RubyClass)
293
+ output[1][1].should be_a(RubyClass)
294
+ output[2].should === output[1]
295
+ end
296
+
297
+ it "should deserialize a byte array" do
298
+ input = object_fixture("amf3-byte-array.bin")
299
+ output = RocketAMF.deserialize(input, 3)
300
+
301
+ output.should be_a(StringIO)
302
+ expected = "\000\003これtest\100"
303
+ expected.force_encoding("ASCII-8BIT") if expected.respond_to?(:force_encoding)
304
+ output.string.should == expected
305
+ end
306
+
307
+ it "should deserialize an empty dictionary" do
308
+ input = object_fixture("amf3-empty-dictionary.bin")
309
+ output = RocketAMF.deserialize(input, 3)
310
+ output.should == {}
311
+ end
312
+
313
+ it "should deserialize a dictionary" do
314
+ input = object_fixture("amf3-dictionary.bin")
315
+ output = RocketAMF.deserialize(input, 3)
316
+
317
+ keys = output.keys
318
+ keys.length.should == 2
319
+ obj_key, str_key = keys[0].is_a?(RocketAMF::Values::TypedHash) ? [keys[0], keys[1]] : [keys[1], keys[0]]
320
+ obj_key.type.should == 'org.amf.ASClass'
321
+ output[obj_key].should == "asdf2"
322
+ str_key.should == "bar"
323
+ output[str_key].should == "asdf1"
324
+ end
325
+
326
+ it "should deserialize Vector.<int>" do
327
+ input = object_fixture('amf3-vector-int.bin')
328
+ output = RocketAMF.deserialize(input, 3)
329
+ output.should == [4, -20, 12]
330
+ end
331
+
332
+ it "should deserialize Vector.<uint>" do
333
+ input = object_fixture('amf3-vector-uint.bin')
334
+ output = RocketAMF.deserialize(input, 3)
335
+ output.should == [4, 20, 12]
336
+ end
337
+
338
+ it "should deserialize Vector.<Number>" do
339
+ input = object_fixture('amf3-vector-double.bin')
340
+ output = RocketAMF.deserialize(input, 3)
341
+ output.should == [4.3, -20.6]
342
+ end
343
+
344
+ it "should deserialize Vector.<Object>" do
345
+ input = object_fixture('amf3-vector-object.bin')
346
+ output = RocketAMF.deserialize(input, 3)
347
+ output[0]['foo'].should == 'foo'
348
+ output[1].type.should == 'org.amf.ASClass'
349
+ output[2]['foo'].should == 'baz'
350
+ end
351
+ end
352
+
353
+ describe "and implementing the AMF Spec" do
354
+ it "should keep references of duplicate strings" do
355
+ input = object_fixture("amf3-string-ref.bin")
356
+ output = RocketAMF.deserialize(input, 3)
357
+
358
+ foo = "foo"
359
+ bar = "str"
360
+ output.should == [foo, bar, foo, bar, foo, {'str' => "foo"}]
361
+ end
362
+
363
+ it "should not reference the empty string" do
364
+ input = object_fixture("amf3-empty-string-ref.bin")
365
+ output = RocketAMF.deserialize(input, 3)
366
+ output.should == ["",""]
367
+ end
368
+
369
+ it "should keep references of duplicate dates" do
370
+ input = object_fixture("amf3-date-ref.bin")
371
+ output = RocketAMF.deserialize(input, 3)
372
+
373
+ output[0].should == Time.at(0)
374
+ output[0].should equal(output[1])
375
+ # Expected object:
376
+ # [DateTime.parse "1/1/1970", DateTime.parse "1/1/1970"]
377
+ end
378
+
379
+ it "should keep reference of duplicate objects" do
380
+ input = object_fixture("amf3-object-ref.bin")
381
+ output = RocketAMF.deserialize(input, 3)
382
+
383
+ obj1 = {'foo' => "bar"}
384
+ obj2 = {'foo' => obj1['foo']}
385
+ output.should == [[obj1, obj2], "bar", [obj1, obj2]]
386
+ end
387
+
388
+ it "should keep reference of duplicate object traits" do
389
+ RocketAMF::ClassMapper.define {|m| m.map :as => 'org.amf.ASClass', :ruby => 'RubyClass'}
390
+
391
+ input = object_fixture("amf3-trait-ref.bin")
392
+ output = RocketAMF.deserialize(input, 3)
393
+
394
+ output[0].foo.should == "foo"
395
+ output[1].foo.should == "bar"
396
+ end
397
+
398
+ it "should keep references of duplicate arrays" do
399
+ input = object_fixture("amf3-array-ref.bin")
400
+ output = RocketAMF.deserialize(input, 3)
401
+
402
+ a = [1,2,3]
403
+ b = %w{ a b c }
404
+ output.should == [a, b, a, b]
405
+ end
406
+
407
+ it "should not keep references of duplicate empty arrays unless the object_id matches" do
408
+ input = object_fixture("amf3-empty-array-ref.bin")
409
+ output = RocketAMF.deserialize(input, 3)
410
+
411
+ a = []
412
+ b = []
413
+ output.should == [a,b,a,b]
414
+ end
415
+
416
+ it "should keep references of duplicate XML and XMLDocuments" do
417
+ input = object_fixture("amf3-xml-ref.bin")
418
+ output = RocketAMF.deserialize(input, 3)
419
+ output.should == ['<parent><child prop="test"/></parent>', '<parent><child prop="test"/></parent>']
420
+ end
421
+
422
+ it "should keep references of duplicate byte arrays" do
423
+ input = object_fixture("amf3-byte-array-ref.bin")
424
+ output = RocketAMF.deserialize(input, 3)
425
+ output[0].object_id.should == output[1].object_id
426
+ output[0].string.should == "ASDF"
427
+ end
428
+
429
+ it "should deserialize a deep object graph with circular references" do
430
+ input = object_fixture("amf3-graph-member.bin")
431
+ output = RocketAMF.deserialize(input, 3)
432
+
433
+ output['children'][0]['parent'].should === output
434
+ output['parent'].should === nil
435
+ output['children'].length.should == 2
436
+ # Expected object:
437
+ # parent = Hash.new
438
+ # child1 = Hash.new
439
+ # child1[:parent] = parent
440
+ # child1[:children] = []
441
+ # child2 = Hash.new
442
+ # child2[:parent] = parent
443
+ # child2[:children] = []
444
+ # parent[:parent] = nil
445
+ # parent[:children] = [child1, child2]
446
+ end
447
+ end
448
+ end
449
+ end
@@ -0,0 +1,144 @@
1
+ require "spec_helper.rb"
2
+
3
+ describe RocketAMF::Ext::FastClassMapping do
4
+ before :each do
5
+ RocketAMF::Ext::FastClassMapping.reset
6
+ RocketAMF::Ext::FastClassMapping.define do |m|
7
+ m.map :as => 'ASClass', :ruby => 'ClassMappingTest'
8
+ end
9
+ @mapper = RocketAMF::Ext::FastClassMapping.new
10
+ end
11
+
12
+ describe "class name mapping" do
13
+ it "should allow resetting of mappings back to defaults" do
14
+ @mapper.get_as_class_name('ClassMappingTest').should_not be_nil
15
+ RocketAMF::Ext::FastClassMapping.reset
16
+ @mapper = RocketAMF::Ext::FastClassMapping.new
17
+ @mapper.get_as_class_name('ClassMappingTest').should be_nil
18
+ @mapper.get_as_class_name('RocketAMF::Values::AcknowledgeMessage').should_not be_nil
19
+ end
20
+
21
+ it "should return AS class name for ruby objects" do
22
+ @mapper.get_as_class_name(ClassMappingTest.new).should == 'ASClass'
23
+ @mapper.get_as_class_name('ClassMappingTest').should == 'ASClass'
24
+ @mapper.get_as_class_name(RocketAMF::Values::TypedHash.new('ClassMappingTest')).should == 'ASClass'
25
+ @mapper.get_as_class_name('BadClass').should be_nil
26
+ end
27
+
28
+ it "should instantiate a ruby class" do
29
+ @mapper.get_ruby_obj('ASClass').should be_a(ClassMappingTest)
30
+ end
31
+
32
+ it "should properly instantiate namespaced classes" do
33
+ RocketAMF::Ext::FastClassMapping.mappings.map :as => 'ASClass', :ruby => 'ANamespace::TestRubyClass'
34
+ @mapper = RocketAMF::Ext::FastClassMapping.new
35
+ @mapper.get_ruby_obj('ASClass').should be_a(ANamespace::TestRubyClass)
36
+ end
37
+
38
+ it "should return a hash with original type if not mapped" do
39
+ obj = @mapper.get_ruby_obj('UnmappedClass')
40
+ obj.should be_a(RocketAMF::Values::TypedHash)
41
+ obj.type.should == 'UnmappedClass'
42
+ end
43
+
44
+ it "should map special classes from AS by default" do
45
+ as_classes = [
46
+ 'flex.messaging.messages.AcknowledgeMessage',
47
+ 'flex.messaging.messages.CommandMessage',
48
+ 'flex.messaging.messages.RemotingMessage'
49
+ ]
50
+
51
+ as_classes.each do |as_class|
52
+ @mapper.get_ruby_obj(as_class).should_not be_a(RocketAMF::Values::TypedHash)
53
+ end
54
+ end
55
+
56
+ it "should map special classes from ruby by default" do
57
+ ruby_classes = [
58
+ 'RocketAMF::Values::AcknowledgeMessage',
59
+ 'RocketAMF::Values::ErrorMessage'
60
+ ]
61
+
62
+ ruby_classes.each do |obj|
63
+ @mapper.get_as_class_name(obj).should_not be_nil
64
+ end
65
+ end
66
+
67
+ it "should allow config modification" do
68
+ RocketAMF::Ext::FastClassMapping.mappings.map :as => 'SecondClass', :ruby => 'ClassMappingTest'
69
+ @mapper = RocketAMF::Ext::FastClassMapping.new
70
+ @mapper.get_as_class_name(ClassMappingTest.new).should == 'SecondClass'
71
+ end
72
+ end
73
+
74
+ describe "ruby object populator" do
75
+ it "should populate a ruby class" do
76
+ obj = @mapper.populate_ruby_obj ClassMappingTest.new, {:prop_a => 'Data'}
77
+ obj.prop_a.should == 'Data'
78
+ end
79
+
80
+ it "should populate a typed hash" do
81
+ obj = @mapper.populate_ruby_obj RocketAMF::Values::TypedHash.new('UnmappedClass'), {'prop_a' => 'Data'}
82
+ obj['prop_a'].should == 'Data'
83
+ end
84
+ end
85
+
86
+ describe "property extractor" do
87
+ # Use symbol keys for properties in Ruby >1.9
88
+ def prop_hash hash
89
+ out = {}
90
+ if RUBY_VERSION =~ /^1\.8/
91
+ hash.each {|k,v| out[k.to_s] = v}
92
+ else
93
+ hash.each {|k,v| out[k.to_sym] = v}
94
+ end
95
+ out
96
+ end
97
+
98
+ it "should return hash without modification" do
99
+ hash = {:a => 'test1', 'b' => 'test2'}
100
+ props = @mapper.props_for_serialization(hash)
101
+ props.should === hash
102
+ end
103
+
104
+ it "should extract object properties" do
105
+ obj = ClassMappingTest.new
106
+ obj.prop_a = 'Test A'
107
+
108
+ hash = @mapper.props_for_serialization obj
109
+ hash.should == prop_hash({'prop_a' => 'Test A', 'prop_b' => nil})
110
+ end
111
+
112
+ it "should extract inherited object properties" do
113
+ obj = ClassMappingTest2.new
114
+ obj.prop_a = 'Test A'
115
+ obj.prop_c = 'Test C'
116
+
117
+ hash = @mapper.props_for_serialization obj
118
+ hash.should == prop_hash({'prop_a' => 'Test A', 'prop_b' => nil, 'prop_c' => 'Test C'})
119
+ end
120
+
121
+ it "should cache property lookups by instance" do
122
+ class ClassMappingTest3; attr_accessor :prop_a; end;
123
+
124
+ # Cache properties
125
+ obj = ClassMappingTest3.new
126
+ hash = @mapper.props_for_serialization obj
127
+
128
+ # Add a method to ClassMappingTest3
129
+ class ClassMappingTest3; attr_accessor :prop_b; end;
130
+
131
+ # Test property list does not have new property
132
+ obj = ClassMappingTest3.new
133
+ obj.prop_a = 'Test A'
134
+ obj.prop_b = 'Test B'
135
+ hash = @mapper.props_for_serialization obj
136
+ hash.should == prop_hash({'prop_a' => 'Test A'})
137
+
138
+ # Test that new class mapper *does* have new property (cache per instance)
139
+ @mapper = RocketAMF::Ext::FastClassMapping.new
140
+ hash = @mapper.props_for_serialization obj
141
+ hash.should == prop_hash({'prop_a' => 'Test A', 'prop_b' => 'Test B'})
142
+ end
143
+ end
144
+ end