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.
- data/README.rdoc +47 -0
- data/Rakefile +9 -0
- data/benchmark.rb +73 -0
- data/lib/rocketamf.rb +212 -0
- data/lib/rocketamf/class_mapping.rb +237 -0
- data/lib/rocketamf/constants.rb +46 -0
- data/lib/rocketamf/ext.rb +28 -0
- data/lib/rocketamf/extensions.rb +22 -0
- data/lib/rocketamf/pure.rb +24 -0
- data/lib/rocketamf/pure/deserializer.rb +417 -0
- data/lib/rocketamf/pure/io_helpers.rb +94 -0
- data/lib/rocketamf/pure/remoting.rb +117 -0
- data/lib/rocketamf/pure/serializer.rb +474 -0
- data/lib/rocketamf/remoting.rb +196 -0
- data/lib/rocketamf/values/messages.rb +212 -0
- data/lib/rocketamf/values/typed_hash.rb +13 -0
- data/lib/rocketamf_pure.rb +1 -0
- data/spec/class_mapping_spec.rb +110 -0
- data/spec/deserializer_spec.rb +423 -0
- data/spec/fast_class_mapping_spec.rb +144 -0
- data/spec/fixtures/objects/amf0-boolean.bin +1 -0
- data/spec/fixtures/objects/amf0-complex-encoded-string.bin +0 -0
- data/spec/fixtures/objects/amf0-date.bin +0 -0
- data/spec/fixtures/objects/amf0-ecma-ordinal-array.bin +0 -0
- data/spec/fixtures/objects/amf0-hash.bin +0 -0
- data/spec/fixtures/objects/amf0-null.bin +1 -0
- data/spec/fixtures/objects/amf0-number.bin +0 -0
- data/spec/fixtures/objects/amf0-object.bin +0 -0
- data/spec/fixtures/objects/amf0-ref-test.bin +0 -0
- data/spec/fixtures/objects/amf0-strict-array.bin +0 -0
- data/spec/fixtures/objects/amf0-string.bin +0 -0
- data/spec/fixtures/objects/amf0-time.bin +0 -0
- data/spec/fixtures/objects/amf0-typed-object.bin +0 -0
- data/spec/fixtures/objects/amf0-undefined.bin +1 -0
- data/spec/fixtures/objects/amf0-untyped-object.bin +0 -0
- data/spec/fixtures/objects/amf0-xml-doc.bin +0 -0
- data/spec/fixtures/objects/amf3-0.bin +0 -0
- data/spec/fixtures/objects/amf3-array-collection.bin +2 -0
- data/spec/fixtures/objects/amf3-array-ref.bin +1 -0
- data/spec/fixtures/objects/amf3-associative-array.bin +1 -0
- data/spec/fixtures/objects/amf3-bigNum.bin +0 -0
- data/spec/fixtures/objects/amf3-byte-array-ref.bin +1 -0
- data/spec/fixtures/objects/amf3-byte-array.bin +0 -0
- data/spec/fixtures/objects/amf3-complex-array-collection.bin +6 -0
- data/spec/fixtures/objects/amf3-complex-encoded-string-array.bin +1 -0
- data/spec/fixtures/objects/amf3-date-ref.bin +0 -0
- data/spec/fixtures/objects/amf3-date.bin +0 -0
- data/spec/fixtures/objects/amf3-dictionary.bin +0 -0
- data/spec/fixtures/objects/amf3-dynamic-object.bin +2 -0
- data/spec/fixtures/objects/amf3-empty-array-ref.bin +1 -0
- data/spec/fixtures/objects/amf3-empty-array.bin +1 -0
- data/spec/fixtures/objects/amf3-empty-dictionary.bin +0 -0
- data/spec/fixtures/objects/amf3-empty-string-ref.bin +1 -0
- data/spec/fixtures/objects/amf3-encoded-string-ref.bin +0 -0
- data/spec/fixtures/objects/amf3-externalizable.bin +0 -0
- data/spec/fixtures/objects/amf3-false.bin +1 -0
- data/spec/fixtures/objects/amf3-float.bin +0 -0
- data/spec/fixtures/objects/amf3-graph-member.bin +0 -0
- data/spec/fixtures/objects/amf3-hash.bin +2 -0
- data/spec/fixtures/objects/amf3-large-max.bin +0 -0
- data/spec/fixtures/objects/amf3-large-min.bin +0 -0
- data/spec/fixtures/objects/amf3-max.bin +1 -0
- data/spec/fixtures/objects/amf3-min.bin +0 -0
- data/spec/fixtures/objects/amf3-mixed-array.bin +10 -0
- data/spec/fixtures/objects/amf3-null.bin +1 -0
- data/spec/fixtures/objects/amf3-object-ref.bin +0 -0
- data/spec/fixtures/objects/amf3-primitive-array.bin +1 -0
- data/spec/fixtures/objects/amf3-string-ref.bin +0 -0
- data/spec/fixtures/objects/amf3-string.bin +1 -0
- data/spec/fixtures/objects/amf3-symbol.bin +1 -0
- data/spec/fixtures/objects/amf3-trait-ref.bin +3 -0
- data/spec/fixtures/objects/amf3-true.bin +1 -0
- data/spec/fixtures/objects/amf3-typed-object.bin +2 -0
- data/spec/fixtures/objects/amf3-xml-doc.bin +1 -0
- data/spec/fixtures/objects/amf3-xml-ref.bin +1 -0
- data/spec/fixtures/objects/amf3-xml.bin +1 -0
- data/spec/fixtures/request/acknowledge-response.bin +0 -0
- data/spec/fixtures/request/amf0-error-response.bin +0 -0
- data/spec/fixtures/request/blaze-response.bin +0 -0
- data/spec/fixtures/request/commandMessage.bin +0 -0
- data/spec/fixtures/request/flex-request.bin +0 -0
- data/spec/fixtures/request/multiple-simple-request.bin +0 -0
- data/spec/fixtures/request/remotingMessage.bin +0 -0
- data/spec/fixtures/request/simple-request.bin +0 -0
- data/spec/fixtures/request/simple-response.bin +0 -0
- data/spec/fixtures/request/unsupportedCommandMessage.bin +0 -0
- data/spec/messages_spec.rb +39 -0
- data/spec/remoting_spec.rb +196 -0
- data/spec/serializer_spec.rb +503 -0
- data/spec/spec_helper.rb +55 -0
- 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
|