rocketamf_pure 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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