rocketamf_pure 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 (91) hide show
  1. data/README.rdoc +47 -0
  2. data/Rakefile +9 -0
  3. data/benchmark.rb +73 -0
  4. data/lib/rocketamf.rb +212 -0
  5. data/lib/rocketamf/class_mapping.rb +237 -0
  6. data/lib/rocketamf/constants.rb +46 -0
  7. data/lib/rocketamf/ext.rb +28 -0
  8. data/lib/rocketamf/extensions.rb +22 -0
  9. data/lib/rocketamf/pure.rb +24 -0
  10. data/lib/rocketamf/pure/deserializer.rb +417 -0
  11. data/lib/rocketamf/pure/io_helpers.rb +94 -0
  12. data/lib/rocketamf/pure/remoting.rb +117 -0
  13. data/lib/rocketamf/pure/serializer.rb +474 -0
  14. data/lib/rocketamf/remoting.rb +196 -0
  15. data/lib/rocketamf/values/messages.rb +212 -0
  16. data/lib/rocketamf/values/typed_hash.rb +13 -0
  17. data/lib/rocketamf_pure.rb +1 -0
  18. data/spec/class_mapping_spec.rb +110 -0
  19. data/spec/deserializer_spec.rb +423 -0
  20. data/spec/fast_class_mapping_spec.rb +144 -0
  21. data/spec/fixtures/objects/amf0-boolean.bin +1 -0
  22. data/spec/fixtures/objects/amf0-complex-encoded-string.bin +0 -0
  23. data/spec/fixtures/objects/amf0-date.bin +0 -0
  24. data/spec/fixtures/objects/amf0-ecma-ordinal-array.bin +0 -0
  25. data/spec/fixtures/objects/amf0-hash.bin +0 -0
  26. data/spec/fixtures/objects/amf0-null.bin +1 -0
  27. data/spec/fixtures/objects/amf0-number.bin +0 -0
  28. data/spec/fixtures/objects/amf0-object.bin +0 -0
  29. data/spec/fixtures/objects/amf0-ref-test.bin +0 -0
  30. data/spec/fixtures/objects/amf0-strict-array.bin +0 -0
  31. data/spec/fixtures/objects/amf0-string.bin +0 -0
  32. data/spec/fixtures/objects/amf0-time.bin +0 -0
  33. data/spec/fixtures/objects/amf0-typed-object.bin +0 -0
  34. data/spec/fixtures/objects/amf0-undefined.bin +1 -0
  35. data/spec/fixtures/objects/amf0-untyped-object.bin +0 -0
  36. data/spec/fixtures/objects/amf0-xml-doc.bin +0 -0
  37. data/spec/fixtures/objects/amf3-0.bin +0 -0
  38. data/spec/fixtures/objects/amf3-array-collection.bin +2 -0
  39. data/spec/fixtures/objects/amf3-array-ref.bin +1 -0
  40. data/spec/fixtures/objects/amf3-associative-array.bin +1 -0
  41. data/spec/fixtures/objects/amf3-bigNum.bin +0 -0
  42. data/spec/fixtures/objects/amf3-byte-array-ref.bin +1 -0
  43. data/spec/fixtures/objects/amf3-byte-array.bin +0 -0
  44. data/spec/fixtures/objects/amf3-complex-array-collection.bin +6 -0
  45. data/spec/fixtures/objects/amf3-complex-encoded-string-array.bin +1 -0
  46. data/spec/fixtures/objects/amf3-date-ref.bin +0 -0
  47. data/spec/fixtures/objects/amf3-date.bin +0 -0
  48. data/spec/fixtures/objects/amf3-dictionary.bin +0 -0
  49. data/spec/fixtures/objects/amf3-dynamic-object.bin +2 -0
  50. data/spec/fixtures/objects/amf3-empty-array-ref.bin +1 -0
  51. data/spec/fixtures/objects/amf3-empty-array.bin +1 -0
  52. data/spec/fixtures/objects/amf3-empty-dictionary.bin +0 -0
  53. data/spec/fixtures/objects/amf3-empty-string-ref.bin +1 -0
  54. data/spec/fixtures/objects/amf3-encoded-string-ref.bin +0 -0
  55. data/spec/fixtures/objects/amf3-externalizable.bin +0 -0
  56. data/spec/fixtures/objects/amf3-false.bin +1 -0
  57. data/spec/fixtures/objects/amf3-float.bin +0 -0
  58. data/spec/fixtures/objects/amf3-graph-member.bin +0 -0
  59. data/spec/fixtures/objects/amf3-hash.bin +2 -0
  60. data/spec/fixtures/objects/amf3-large-max.bin +0 -0
  61. data/spec/fixtures/objects/amf3-large-min.bin +0 -0
  62. data/spec/fixtures/objects/amf3-max.bin +1 -0
  63. data/spec/fixtures/objects/amf3-min.bin +0 -0
  64. data/spec/fixtures/objects/amf3-mixed-array.bin +10 -0
  65. data/spec/fixtures/objects/amf3-null.bin +1 -0
  66. data/spec/fixtures/objects/amf3-object-ref.bin +0 -0
  67. data/spec/fixtures/objects/amf3-primitive-array.bin +1 -0
  68. data/spec/fixtures/objects/amf3-string-ref.bin +0 -0
  69. data/spec/fixtures/objects/amf3-string.bin +1 -0
  70. data/spec/fixtures/objects/amf3-symbol.bin +1 -0
  71. data/spec/fixtures/objects/amf3-trait-ref.bin +3 -0
  72. data/spec/fixtures/objects/amf3-true.bin +1 -0
  73. data/spec/fixtures/objects/amf3-typed-object.bin +2 -0
  74. data/spec/fixtures/objects/amf3-xml-doc.bin +1 -0
  75. data/spec/fixtures/objects/amf3-xml-ref.bin +1 -0
  76. data/spec/fixtures/objects/amf3-xml.bin +1 -0
  77. data/spec/fixtures/request/acknowledge-response.bin +0 -0
  78. data/spec/fixtures/request/amf0-error-response.bin +0 -0
  79. data/spec/fixtures/request/blaze-response.bin +0 -0
  80. data/spec/fixtures/request/commandMessage.bin +0 -0
  81. data/spec/fixtures/request/flex-request.bin +0 -0
  82. data/spec/fixtures/request/multiple-simple-request.bin +0 -0
  83. data/spec/fixtures/request/remotingMessage.bin +0 -0
  84. data/spec/fixtures/request/simple-request.bin +0 -0
  85. data/spec/fixtures/request/simple-response.bin +0 -0
  86. data/spec/fixtures/request/unsupportedCommandMessage.bin +0 -0
  87. data/spec/messages_spec.rb +39 -0
  88. data/spec/remoting_spec.rb +196 -0
  89. data/spec/serializer_spec.rb +503 -0
  90. data/spec/spec_helper.rb +55 -0
  91. metadata +148 -0
@@ -0,0 +1,423 @@
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
+ end
326
+
327
+ describe "and implementing the AMF Spec" do
328
+ it "should keep references of duplicate strings" do
329
+ input = object_fixture("amf3-string-ref.bin")
330
+ output = RocketAMF.deserialize(input, 3)
331
+
332
+ foo = "foo"
333
+ bar = "str"
334
+ output.should == [foo, bar, foo, bar, foo, {:str => "foo"}]
335
+ end
336
+
337
+ it "should not reference the empty string" do
338
+ input = object_fixture("amf3-empty-string-ref.bin")
339
+ output = RocketAMF.deserialize(input, 3)
340
+ output.should == ["",""]
341
+ end
342
+
343
+ it "should keep references of duplicate dates" do
344
+ input = object_fixture("amf3-date-ref.bin")
345
+ output = RocketAMF.deserialize(input, 3)
346
+
347
+ output[0].should == Time.at(0)
348
+ output[0].should equal(output[1])
349
+ # Expected object:
350
+ # [DateTime.parse "1/1/1970", DateTime.parse "1/1/1970"]
351
+ end
352
+
353
+ it "should keep reference of duplicate objects" do
354
+ input = object_fixture("amf3-object-ref.bin")
355
+ output = RocketAMF.deserialize(input, 3)
356
+
357
+ obj1 = {:foo => "bar"}
358
+ obj2 = {:foo => obj1[:foo]}
359
+ output.should == [[obj1, obj2], "bar", [obj1, obj2]]
360
+ end
361
+
362
+ it "should keep reference of duplicate object traits" do
363
+ RocketAMF::ClassMapper.define {|m| m.map :as => 'org.amf.ASClass', :ruby => 'RubyClass'}
364
+
365
+ input = object_fixture("amf3-trait-ref.bin")
366
+ output = RocketAMF.deserialize(input, 3)
367
+
368
+ output[0].foo.should == "foo"
369
+ output[1].foo.should == "bar"
370
+ end
371
+
372
+ it "should keep references of duplicate arrays" do
373
+ input = object_fixture("amf3-array-ref.bin")
374
+ output = RocketAMF.deserialize(input, 3)
375
+
376
+ a = [1,2,3]
377
+ b = %w{ a b c }
378
+ output.should == [a, b, a, b]
379
+ end
380
+
381
+ it "should not keep references of duplicate empty arrays unless the object_id matches" do
382
+ input = object_fixture("amf3-empty-array-ref.bin")
383
+ output = RocketAMF.deserialize(input, 3)
384
+
385
+ a = []
386
+ b = []
387
+ output.should == [a,b,a,b]
388
+ end
389
+
390
+ it "should keep references of duplicate XML and XMLDocuments" do
391
+ input = object_fixture("amf3-xml-ref.bin")
392
+ output = RocketAMF.deserialize(input, 3)
393
+ output.should == ['<parent><child prop="test"/></parent>', '<parent><child prop="test"/></parent>']
394
+ end
395
+
396
+ it "should keep references of duplicate byte arrays" do
397
+ input = object_fixture("amf3-byte-array-ref.bin")
398
+ output = RocketAMF.deserialize(input, 3)
399
+ output[0].object_id.should == output[1].object_id
400
+ output[0].string.should == "ASDF"
401
+ end
402
+
403
+ it "should deserialize a deep object graph with circular references" do
404
+ input = object_fixture("amf3-graph-member.bin")
405
+ output = RocketAMF.deserialize(input, 3)
406
+
407
+ output[:children][0][:parent].should === output
408
+ output[:parent].should === nil
409
+ output[:children].length.should == 2
410
+ # Expected object:
411
+ # parent = Hash.new
412
+ # child1 = Hash.new
413
+ # child1[:parent] = parent
414
+ # child1[:children] = []
415
+ # child2 = Hash.new
416
+ # child2[:parent] = parent
417
+ # child2[:children] = []
418
+ # parent[:parent] = nil
419
+ # parent[:children] = [child1, child2]
420
+ end
421
+ end
422
+ end
423
+ 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