rack-amf 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +55 -0
- data/Rakefile +54 -0
- data/lib/amf/class_mapping.rb +210 -0
- data/lib/amf/common.rb +28 -0
- data/lib/amf/constants.rb +46 -0
- data/lib/amf/pure/deserializer.rb +353 -0
- data/lib/amf/pure/io_helpers.rb +94 -0
- data/lib/amf/pure/remoting.rb +120 -0
- data/lib/amf/pure/serializer.rb +218 -0
- data/lib/amf/pure.rb +14 -0
- data/lib/amf/values/array_collection.rb +9 -0
- data/lib/amf/values/messages.rb +133 -0
- data/lib/amf/values/typed_hash.rb +13 -0
- data/lib/amf/version.rb +9 -0
- data/lib/amf.rb +17 -0
- data/lib/rack/amf/application.rb +32 -0
- data/lib/rack/amf/request.rb +15 -0
- data/lib/rack/amf/response.rb +54 -0
- data/lib/rack/amf/service_manager.rb +35 -0
- data/lib/rack/amf.rb +17 -0
- data/spec/amf/class_mapping_set_spec.rb +34 -0
- data/spec/amf/class_mapping_spec.rb +109 -0
- data/spec/amf/deserializer_spec.rb +301 -0
- data/spec/amf/remoting_spec.rb +37 -0
- data/spec/amf/serializer_spec.rb +254 -0
- data/spec/amf/values/array_collection_spec.rb +6 -0
- data/spec/amf/values/messages_spec.rb +27 -0
- data/spec/rack/request_spec.rb +5 -0
- data/spec/rack/response_spec.rb +46 -0
- data/spec/rack/service_manager_spec.rb +26 -0
- data/spec/spec_helper.rb +24 -0
- metadata +97 -0
@@ -0,0 +1,109 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
describe AMF::ClassMapping do
|
4
|
+
before(:all) do
|
5
|
+
class RubyClass
|
6
|
+
attr_accessor :prop_a
|
7
|
+
attr_accessor :prop_b
|
8
|
+
attr_accessor :prop_c
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
before :each do
|
13
|
+
@mapper = AMF::ClassMapping.new
|
14
|
+
@mapper.define do |m|
|
15
|
+
m.map :as => 'ASClass', :ruby => 'RubyClass'
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should return AS class name for ruby objects" do
|
20
|
+
@mapper.get_as_class_name(RubyClass.new).should == 'ASClass'
|
21
|
+
@mapper.get_as_class_name('RubyClass').should == 'ASClass'
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should allow config modification" do
|
25
|
+
@mapper.define do |m|
|
26
|
+
m.map :as => 'SecondClass', :ruby => 'RubyClass'
|
27
|
+
end
|
28
|
+
@mapper.get_as_class_name(RubyClass.new).should == 'SecondClass'
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "ruby object generator" do
|
32
|
+
it "should instantiate a ruby class" do
|
33
|
+
@mapper.get_ruby_obj('ASClass').should be_a(RubyClass)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should properly instantiate namespaced classes" do
|
37
|
+
module ANamespace; class TestRubyClass; end; end
|
38
|
+
@mapper.define {|m| m.map :as => 'ASClass', :ruby => 'ANamespace::TestRubyClass'}
|
39
|
+
@mapper.get_ruby_obj('ASClass').should be_a(ANamespace::TestRubyClass)
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should return a hash with original type if not mapped" do
|
43
|
+
obj = @mapper.get_ruby_obj('UnmappedClass')
|
44
|
+
obj.should be_a(AMF::Values::TypedHash)
|
45
|
+
obj.type.should == 'UnmappedClass'
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe "ruby object populator" do
|
50
|
+
it "should populate a ruby class" do
|
51
|
+
obj = @mapper.populate_ruby_obj RubyClass.new, {:prop_a => 'Data'}
|
52
|
+
obj.prop_a.should == 'Data'
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should populate a typed hash" do
|
56
|
+
obj = @mapper.populate_ruby_obj AMF::Values::TypedHash.new('UnmappedClass'), {:prop_a => 'Data'}
|
57
|
+
obj[:prop_a].should == 'Data'
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should allow custom populators" do
|
61
|
+
class CustomPopulator
|
62
|
+
def can_handle? obj
|
63
|
+
true
|
64
|
+
end
|
65
|
+
def populate obj, props, dynamic_props
|
66
|
+
obj[:populated] = true
|
67
|
+
obj.merge! props
|
68
|
+
obj.merge! dynamic_props if dynamic_props
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
@mapper.object_populators << CustomPopulator.new
|
73
|
+
obj = @mapper.populate_ruby_obj({}, {:prop_a => 'Data'})
|
74
|
+
obj[:populated].should == true
|
75
|
+
obj[:prop_a].should == 'Data'
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe "property extractor" do
|
80
|
+
it "should extract hash properties" do
|
81
|
+
hash = {:a => 'test1', :b => 'test2'}
|
82
|
+
props = @mapper.props_for_serialization(hash)
|
83
|
+
props.should == {'a' => 'test1', 'b' => 'test2'}
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should extract object properties" do
|
87
|
+
obj = RubyClass.new
|
88
|
+
obj.prop_a = 'Test A'
|
89
|
+
obj.prop_b = 'Test B'
|
90
|
+
|
91
|
+
hash = @mapper.props_for_serialization obj
|
92
|
+
hash.should == {'prop_a' => 'Test A', 'prop_b' => 'Test B', 'prop_c' => nil}
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should allow custom serializers" do
|
96
|
+
class CustomSerializer
|
97
|
+
def can_handle? obj
|
98
|
+
true
|
99
|
+
end
|
100
|
+
def serialize obj
|
101
|
+
{:success => true}
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
@mapper.object_serializers << CustomSerializer.new
|
106
|
+
@mapper.props_for_serialization(nil).should == {:success => true}
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,301 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
describe "when deserializing" do
|
4
|
+
describe "AMF0" do
|
5
|
+
it "should deserialize numbers" do
|
6
|
+
input = object_fixture('amf0-number.bin')
|
7
|
+
output = AMF.deserialize(input, 0)
|
8
|
+
output.should == 3.5
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should deserialize booleans" do
|
12
|
+
input = object_fixture('amf0-boolean.bin')
|
13
|
+
output = AMF.deserialize(input, 0)
|
14
|
+
output.should === true
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should deserialize strings" do
|
18
|
+
input = object_fixture('amf0-string.bin')
|
19
|
+
output = AMF.deserialize(input, 0)
|
20
|
+
output.should == "this is a テスト"
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should deserialize anonymous objects" do
|
24
|
+
input = object_fixture('amf0-object.bin')
|
25
|
+
output = AMF.deserialize(input, 0)
|
26
|
+
output.should == {:foo => 'baz', :bar => 3.14}
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should deserialize nulls" do
|
30
|
+
input = object_fixture('amf0-null.bin')
|
31
|
+
output = AMF.deserialize(input, 0)
|
32
|
+
output.should == nil
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should deserialize undefineds" do
|
36
|
+
input = object_fixture('amf0-undefined.bin')
|
37
|
+
output = AMF.deserialize(input, 0)
|
38
|
+
output.should == nil
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should deserialize references properly" do
|
42
|
+
input = object_fixture('amf0-ref-test.bin')
|
43
|
+
output = AMF.deserialize(input, 0)
|
44
|
+
output.length.should == 2
|
45
|
+
output[0].should === output[1]
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should deserialize hashes" do
|
49
|
+
input = object_fixture('amf0-hash.bin')
|
50
|
+
output = AMF.deserialize(input, 0)
|
51
|
+
output.should == {:a => 'b', :c => 'd'}
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should deserialize arrays from flash player" do
|
55
|
+
# Even Array is serialized as a "hash", so check that deserializer converts to array
|
56
|
+
input = object_fixture('amf0-ecma-ordinal-array.bin')
|
57
|
+
output = AMF.deserialize(input, 0)
|
58
|
+
output.should == ['a', 'b', 'c', 'd']
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should deserialize dates" do
|
62
|
+
input = object_fixture('amf0-date.bin')
|
63
|
+
output = AMF.deserialize(input, 0)
|
64
|
+
output.should == Time.utc(2003, 2, 13, 5)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should deserialize an unmapped object as a dynamic anonymous object" do
|
68
|
+
input = object_fixture("amf0-typed-object.bin")
|
69
|
+
output = AMF.deserialize(input, 0)
|
70
|
+
|
71
|
+
output.type.should == 'org.rackAMF.ASClass'
|
72
|
+
output.should == {:foo => 'bar', :baz => nil}
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should deserialize a mapped object as a mapped ruby class instance" do
|
76
|
+
class RubyClass
|
77
|
+
attr_accessor :foo, :baz
|
78
|
+
end
|
79
|
+
AMF::ClassMapper.define {|m| m.map :as => 'org.rackAMF.ASClass', :ruby => 'RubyClass'}
|
80
|
+
|
81
|
+
input = object_fixture("amf0-typed-object.bin")
|
82
|
+
output = AMF.deserialize(input, 0)
|
83
|
+
|
84
|
+
output.should be_a(RubyClass)
|
85
|
+
output.foo.should == 'bar'
|
86
|
+
output.baz.should == nil
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe "AMF3" do
|
91
|
+
describe "simple messages" do
|
92
|
+
it "should deserialize a null" do
|
93
|
+
input = object_fixture("amf3-null.bin")
|
94
|
+
output = AMF.deserialize(input, 3)
|
95
|
+
output.should == nil
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should deserialize a false" do
|
99
|
+
input = object_fixture("amf3-false.bin")
|
100
|
+
output = AMF.deserialize(input, 3)
|
101
|
+
output.should == false
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should deserialize a true" do
|
105
|
+
input = object_fixture("amf3-true.bin")
|
106
|
+
output = AMF.deserialize(input, 3)
|
107
|
+
output.should == true
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should deserialize integers" do
|
111
|
+
input = object_fixture("amf3-max.bin")
|
112
|
+
output = AMF.deserialize(input, 3)
|
113
|
+
output.should == AMF::MAX_INTEGER
|
114
|
+
|
115
|
+
input = object_fixture("amf3-0.bin")
|
116
|
+
output = AMF.deserialize(input, 3)
|
117
|
+
output.should == 0
|
118
|
+
|
119
|
+
input = object_fixture("amf3-min.bin")
|
120
|
+
output = AMF.deserialize(input, 3)
|
121
|
+
output.should == AMF::MIN_INTEGER
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should deserialize large integers" do
|
125
|
+
input = object_fixture("amf3-largeMax.bin")
|
126
|
+
output = AMF.deserialize(input, 3)
|
127
|
+
output.should == AMF::MAX_INTEGER + 1
|
128
|
+
|
129
|
+
input = object_fixture("amf3-largeMin.bin")
|
130
|
+
output = AMF.deserialize(input, 3)
|
131
|
+
output.should == AMF::MIN_INTEGER - 1
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should deserialize BigNums" do
|
135
|
+
input = object_fixture("amf3-bigNum.bin")
|
136
|
+
output = AMF.deserialize(input, 3)
|
137
|
+
output.should == 2**1000
|
138
|
+
end
|
139
|
+
|
140
|
+
it "should deserialize a simple string" do
|
141
|
+
input = object_fixture("amf3-string.bin")
|
142
|
+
output = AMF.deserialize(input, 3)
|
143
|
+
output.should == "String . String"
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should deserialize a symbol as a string" do
|
147
|
+
input = object_fixture("amf3-symbol.bin")
|
148
|
+
output = AMF.deserialize(input, 3)
|
149
|
+
output.should == "foo"
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should deserialize dates" do
|
153
|
+
input = object_fixture("amf3-date.bin")
|
154
|
+
output = AMF.deserialize(input, 3)
|
155
|
+
output.should == Time.at(0)
|
156
|
+
end
|
157
|
+
|
158
|
+
#BAH! Who sends XML over AMF?
|
159
|
+
it "should deserialize a REXML document"
|
160
|
+
end
|
161
|
+
|
162
|
+
describe "objects" do
|
163
|
+
it "should deserialize an unmapped object as a dynamic anonymous object" do
|
164
|
+
input = object_fixture("amf3-dynObject.bin")
|
165
|
+
output = AMF.deserialize(input, 3)
|
166
|
+
|
167
|
+
expected = {
|
168
|
+
:property_one => 'foo',
|
169
|
+
:property_two => 1,
|
170
|
+
:nil_property => nil,
|
171
|
+
:another_public_property => 'a_public_value'
|
172
|
+
}
|
173
|
+
output.should == expected
|
174
|
+
end
|
175
|
+
|
176
|
+
it "should deserialize a mapped object as a mapped ruby class instance" do
|
177
|
+
class RubyClass
|
178
|
+
attr_accessor :foo, :baz
|
179
|
+
end
|
180
|
+
AMF::ClassMapper.define {|m| m.map :as => 'org.rackAMF.ASClass', :ruby => 'RubyClass'}
|
181
|
+
|
182
|
+
input = object_fixture("amf3-typedObject.bin")
|
183
|
+
output = AMF.deserialize(input, 3)
|
184
|
+
|
185
|
+
output.should be_a(RubyClass)
|
186
|
+
output.foo.should == 'bar'
|
187
|
+
output.baz.should == nil
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should deserialize a hash as a dynamic anonymous object" do
|
191
|
+
input = object_fixture("amf3-hash.bin")
|
192
|
+
output = AMF.deserialize(input, 3)
|
193
|
+
output.should == {:foo => "bar", :answer => 42}
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should deserialize an open struct as a dynamic anonymous object"
|
197
|
+
|
198
|
+
it "should deserialize an empty array" do
|
199
|
+
input = object_fixture("amf3-emptyArray.bin")
|
200
|
+
output = AMF.deserialize(input, 3)
|
201
|
+
output.should == []
|
202
|
+
end
|
203
|
+
|
204
|
+
it "should deserialize an array of primatives" do
|
205
|
+
input = object_fixture("amf3-primArray.bin")
|
206
|
+
output = AMF.deserialize(input, 3)
|
207
|
+
output.should == [1,2,3,4,5]
|
208
|
+
end
|
209
|
+
|
210
|
+
it "should deserialize an array of mixed objects" do
|
211
|
+
input = object_fixture("amf3-mixedArray.bin")
|
212
|
+
output = AMF.deserialize(input, 3)
|
213
|
+
|
214
|
+
h1 = {:foo_one => "bar_one"}
|
215
|
+
h2 = {:foo_two => ""}
|
216
|
+
so1 = {:foo_three => 42}
|
217
|
+
output.should == [h1, h2, so1, {:foo_three => nil}, {}, [h1, h2, so1], [], 42, "", [], "", {}, "bar_one", so1]
|
218
|
+
end
|
219
|
+
|
220
|
+
it "should deserialize a byte array"
|
221
|
+
end
|
222
|
+
|
223
|
+
describe "and implementing the AMF Spec" do
|
224
|
+
it "should keep references of duplicate strings" do
|
225
|
+
input = object_fixture("amf3-stringRef.bin")
|
226
|
+
output = AMF.deserialize(input, 3)
|
227
|
+
|
228
|
+
class StringCarrier; attr_accessor :str; end
|
229
|
+
foo = "foo"
|
230
|
+
bar = "str"
|
231
|
+
sc = StringCarrier.new
|
232
|
+
sc = {:str => foo}
|
233
|
+
output.should == [foo, bar, foo, bar, foo, sc]
|
234
|
+
end
|
235
|
+
|
236
|
+
it "should not reference the empty string" do
|
237
|
+
input = object_fixture("amf3-emptyStringRef.bin")
|
238
|
+
output = AMF.deserialize(input, 3)
|
239
|
+
output.should == ["",""]
|
240
|
+
end
|
241
|
+
|
242
|
+
it "should keep references of duplicate dates" do
|
243
|
+
input = object_fixture("amf3-datesRef.bin")
|
244
|
+
output = AMF.deserialize(input, 3)
|
245
|
+
|
246
|
+
output[0].should equal(output[1])
|
247
|
+
# Expected object:
|
248
|
+
# [DateTime.parse "1/1/1970", DateTime.parse "1/1/1970"]
|
249
|
+
end
|
250
|
+
|
251
|
+
it "should keep reference of duplicate objects" do
|
252
|
+
input = object_fixture("amf3-objRef.bin")
|
253
|
+
output = AMF.deserialize(input, 3)
|
254
|
+
|
255
|
+
obj1 = {:foo => "bar"}
|
256
|
+
obj2 = {:foo => obj1[:foo]}
|
257
|
+
output.should == [[obj1, obj2], "bar", [obj1, obj2]]
|
258
|
+
end
|
259
|
+
|
260
|
+
it "should keep references of duplicate arrays" do
|
261
|
+
input = object_fixture("amf3-arrayRef.bin")
|
262
|
+
output = AMF.deserialize(input, 3)
|
263
|
+
|
264
|
+
a = [1,2,3]
|
265
|
+
b = %w{ a b c }
|
266
|
+
output.should == [a, b, a, b]
|
267
|
+
end
|
268
|
+
|
269
|
+
it "should not keep references of duplicate empty arrays unless the object_id matches" do
|
270
|
+
input = object_fixture("amf3-emptyArrayRef.bin")
|
271
|
+
output = AMF.deserialize(input, 3)
|
272
|
+
|
273
|
+
a = []
|
274
|
+
b = []
|
275
|
+
output.should == [a,b,a,b]
|
276
|
+
end
|
277
|
+
|
278
|
+
it "should keep references of duplicate XML and XMLDocuments"
|
279
|
+
it "should keep references of duplicate byte arrays"
|
280
|
+
|
281
|
+
it "should deserialize a deep object graph with circular references" do
|
282
|
+
input = object_fixture("amf3-graphMember.bin")
|
283
|
+
output = AMF.deserialize(input, 3)
|
284
|
+
|
285
|
+
output[:children][0][:parent].should === output
|
286
|
+
output[:parent].should === nil
|
287
|
+
output[:children].length.should == 2
|
288
|
+
# Expected object:
|
289
|
+
# parent = Hash.new
|
290
|
+
# child1 = Hash.new
|
291
|
+
# child1[:parent] = parent
|
292
|
+
# child1[:children] = []
|
293
|
+
# child2 = Hash.new
|
294
|
+
# child2[:parent] = parent
|
295
|
+
# child2[:children] = []
|
296
|
+
# parent[:parent] = nil
|
297
|
+
# parent[:children] = [child1, child2]
|
298
|
+
end
|
299
|
+
end
|
300
|
+
end
|
301
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
describe "when handling requests" do
|
4
|
+
it "should handle remoting message from remote object" do
|
5
|
+
input = request_fixture("remotingMessage.bin")
|
6
|
+
req = AMF::Request.new.populate_from_stream(input)
|
7
|
+
|
8
|
+
req.headers.length.should == 0
|
9
|
+
req.messages.length.should == 1
|
10
|
+
message = req.messages[0].data
|
11
|
+
message.should be_a(AMF::Values::RemotingMessage)
|
12
|
+
message.messageId.should == "FE4AF2BC-DD3C-5470-05D8-9971D51FF89D"
|
13
|
+
message.body.should == [true]
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should handle command message from remote object" do
|
17
|
+
input = request_fixture("commandMessage.bin")
|
18
|
+
req = AMF::Request.new.populate_from_stream(input)
|
19
|
+
|
20
|
+
req.headers.length.should == 0
|
21
|
+
req.messages.length.should == 1
|
22
|
+
message = req.messages[0].data
|
23
|
+
message.should be_a(AMF::Values::CommandMessage)
|
24
|
+
message.messageId.should == "7B0ACE15-8D57-6AE5-B9D4-99C2D32C8246"
|
25
|
+
message.body.should == {}
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "when handling responses" do
|
30
|
+
it "should serialize a simple call" do
|
31
|
+
resp = AMF::Response.new
|
32
|
+
resp.messages << AMF::Message.new('/1/onResult', '', 'hello')
|
33
|
+
|
34
|
+
expected = request_fixture('simple-response.bin')
|
35
|
+
resp.serialize.should == expected
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,254 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper.rb'
|
2
|
+
|
3
|
+
require 'rexml/document'
|
4
|
+
|
5
|
+
describe "when serializing" do
|
6
|
+
describe "AMF3" do
|
7
|
+
describe "simple messages" do
|
8
|
+
it "should serialize a null" do
|
9
|
+
expected = object_fixture("amf3-null.bin")
|
10
|
+
output = AMF.serialize(nil, 3)
|
11
|
+
output.should == expected
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should serialize a false" do
|
15
|
+
expected = object_fixture("amf3-false.bin")
|
16
|
+
output = AMF.serialize(false, 3)
|
17
|
+
output.should == expected
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should serialize a true" do
|
21
|
+
expected = object_fixture("amf3-true.bin")
|
22
|
+
output = AMF.serialize(true, 3)
|
23
|
+
output.should == expected
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should serialize integers" do
|
27
|
+
expected = object_fixture("amf3-max.bin")
|
28
|
+
input = AMF::MAX_INTEGER
|
29
|
+
output = AMF.serialize(input, 3)
|
30
|
+
output.should == expected
|
31
|
+
|
32
|
+
expected = object_fixture("amf3-0.bin")
|
33
|
+
output = AMF.serialize(0, 3)
|
34
|
+
output.should == expected
|
35
|
+
|
36
|
+
expected = object_fixture("amf3-min.bin")
|
37
|
+
input = AMF::MIN_INTEGER
|
38
|
+
output = AMF.serialize(input, 3)
|
39
|
+
output.should == expected
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should serialize large integers" do
|
43
|
+
expected = object_fixture("amf3-largeMax.bin")
|
44
|
+
input = AMF::MAX_INTEGER + 1
|
45
|
+
output = AMF.serialize(input, 3)
|
46
|
+
output.should == expected
|
47
|
+
|
48
|
+
expected = object_fixture("amf3-largeMin.bin")
|
49
|
+
input = AMF::MIN_INTEGER - 1
|
50
|
+
output = AMF.serialize(input, 3)
|
51
|
+
output.should == expected
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should serialize BigNums" do
|
55
|
+
expected = object_fixture("amf3-bigNum.bin")
|
56
|
+
input = 2**1000
|
57
|
+
output = AMF.serialize(input, 3)
|
58
|
+
output.should == expected
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should serialize a simple string" do
|
62
|
+
expected = object_fixture("amf3-string.bin")
|
63
|
+
input = "String . String"
|
64
|
+
output = AMF.serialize(input, 3)
|
65
|
+
output.should == expected
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should serialize a symbol as a string" do
|
69
|
+
expected = object_fixture("amf3-symbol.bin")
|
70
|
+
output = AMF.serialize(:foo, 3)
|
71
|
+
output.should == expected
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should serialize Times" do
|
75
|
+
expected = object_fixture("amf3-date.bin")
|
76
|
+
input = Time.utc 1970, 1, 1, 0
|
77
|
+
output = AMF.serialize(input, 3)
|
78
|
+
output.should == expected
|
79
|
+
end
|
80
|
+
|
81
|
+
#BAH! Who sends XML over AMF?
|
82
|
+
it "should serialize a REXML document"
|
83
|
+
end
|
84
|
+
|
85
|
+
describe "objects" do
|
86
|
+
it "should serialize an unmapped object as a dynamic anonymous object" do
|
87
|
+
class NonMappedObject
|
88
|
+
attr_accessor :property_one
|
89
|
+
attr_accessor :property_two
|
90
|
+
attr_accessor :nil_property
|
91
|
+
attr_writer :read_only_prop
|
92
|
+
|
93
|
+
def another_public_property
|
94
|
+
'a_public_value'
|
95
|
+
end
|
96
|
+
|
97
|
+
def method_with_arg arg='foo'
|
98
|
+
arg
|
99
|
+
end
|
100
|
+
end
|
101
|
+
obj = NonMappedObject.new
|
102
|
+
obj.property_one = 'foo'
|
103
|
+
obj.property_two = 1
|
104
|
+
obj.nil_property = nil
|
105
|
+
|
106
|
+
expected = object_fixture("amf3-dynObject.bin")
|
107
|
+
input = obj
|
108
|
+
output = AMF.serialize(input, 3)
|
109
|
+
output.should == expected
|
110
|
+
end
|
111
|
+
|
112
|
+
it "should serialize a hash as a dynamic anonymous object" do
|
113
|
+
hash = {}
|
114
|
+
hash[:answer] = 42
|
115
|
+
hash[:foo] = "bar"
|
116
|
+
|
117
|
+
expected = object_fixture("amf3-hash.bin")
|
118
|
+
input = hash
|
119
|
+
output = AMF.serialize(input, 3)
|
120
|
+
output.should == expected
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should serialize an open struct as a dynamic anonymous object"
|
124
|
+
|
125
|
+
it "should serialize an empty array" do
|
126
|
+
expected = object_fixture("amf3-emptyArray.bin")
|
127
|
+
input = []
|
128
|
+
output = AMF.serialize(input, 3)
|
129
|
+
output.should == expected
|
130
|
+
end
|
131
|
+
|
132
|
+
it "should serialize an array of primatives" do
|
133
|
+
expected = object_fixture("amf3-primArray.bin")
|
134
|
+
input = [1, 2, 3, 4, 5]
|
135
|
+
output = AMF.serialize(input, 3)
|
136
|
+
output.should == expected
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should serialize an array of mixed objects" do
|
140
|
+
h1 = {:foo_one => "bar_one"}
|
141
|
+
h2 = {:foo_two => ""}
|
142
|
+
class SimpleObj
|
143
|
+
attr_accessor :foo_three
|
144
|
+
end
|
145
|
+
so1 = SimpleObj.new
|
146
|
+
so1.foo_three = 42
|
147
|
+
|
148
|
+
expected = object_fixture("amf3-mixedArray.bin")
|
149
|
+
input = [h1, h2, so1, SimpleObj.new, {}, [h1, h2, so1], [], 42, "", [], "", {}, "bar_one", so1]
|
150
|
+
output = AMF.serialize(input, 3)
|
151
|
+
output.should == expected
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should serialize a byte array"
|
155
|
+
end
|
156
|
+
|
157
|
+
describe "and implementing the AMF Spec" do
|
158
|
+
it "should keep references of duplicate strings" do
|
159
|
+
class StringCarrier
|
160
|
+
attr_accessor :str
|
161
|
+
end
|
162
|
+
foo = "foo"
|
163
|
+
bar = "str"
|
164
|
+
sc = StringCarrier.new
|
165
|
+
sc.str = foo
|
166
|
+
|
167
|
+
expected = object_fixture("amf3-stringRef.bin")
|
168
|
+
input = [foo, bar, foo, bar, foo, sc]
|
169
|
+
output = AMF.serialize(input, 3)
|
170
|
+
output.should == expected
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should not reference the empty string" do
|
174
|
+
expected = object_fixture("amf3-emptyStringRef.bin")
|
175
|
+
input = ""
|
176
|
+
output = AMF.serialize([input,input], 3)
|
177
|
+
output.should == expected
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should keep references of duplicate dates" do
|
181
|
+
expected = object_fixture("amf3-datesRef.bin")
|
182
|
+
input = Time.utc 1970, 1, 1, 0
|
183
|
+
output = AMF.serialize([input,input], 3)
|
184
|
+
output.should == expected
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should keep reference of duplicate objects" do
|
188
|
+
class SimpleReferenceableObj
|
189
|
+
attr_accessor :foo
|
190
|
+
end
|
191
|
+
obj1 = SimpleReferenceableObj.new
|
192
|
+
obj1.foo = :bar
|
193
|
+
obj2 = SimpleReferenceableObj.new
|
194
|
+
obj2.foo = obj1.foo
|
195
|
+
|
196
|
+
expected = object_fixture("amf3-objRef.bin")
|
197
|
+
input = [[obj1, obj2], "bar", [obj1, obj2]]
|
198
|
+
output = AMF.serialize(input, 3)
|
199
|
+
output.should == expected
|
200
|
+
end
|
201
|
+
|
202
|
+
it "should keep references of duplicate arrays" do
|
203
|
+
a = [1,2,3]
|
204
|
+
b = %w{ a b c }
|
205
|
+
|
206
|
+
expected = object_fixture("amf3-arrayRef.bin")
|
207
|
+
input = [a, b, a, b]
|
208
|
+
output = AMF.serialize(input, 3)
|
209
|
+
output.should == expected
|
210
|
+
end
|
211
|
+
|
212
|
+
it "should not keep references of duplicate empty arrays unless the object_id matches" do
|
213
|
+
a = []
|
214
|
+
b = []
|
215
|
+
a.should == b
|
216
|
+
a.object_id.should_not == b.object_id
|
217
|
+
|
218
|
+
expected = object_fixture("amf3-emptyArrayRef.bin")
|
219
|
+
input = [a,b,a,b]
|
220
|
+
output = AMF.serialize(input, 3)
|
221
|
+
output.should == expected
|
222
|
+
end
|
223
|
+
|
224
|
+
it "should keep references of duplicate XML and XMLDocuments"
|
225
|
+
it "should keep references of duplicate byte arrays"
|
226
|
+
|
227
|
+
it "should serialize a deep object graph with circular references" do
|
228
|
+
class GraphMember
|
229
|
+
attr_accessor :parent
|
230
|
+
attr_accessor :children
|
231
|
+
|
232
|
+
def initialize
|
233
|
+
self.children = []
|
234
|
+
end
|
235
|
+
|
236
|
+
def add_child child
|
237
|
+
children << child
|
238
|
+
child.parent = self
|
239
|
+
child
|
240
|
+
end
|
241
|
+
end
|
242
|
+
|
243
|
+
parent = GraphMember.new
|
244
|
+
level_1_child_1 = parent.add_child GraphMember.new
|
245
|
+
level_1_child_2 = parent.add_child GraphMember.new
|
246
|
+
|
247
|
+
expected = object_fixture("amf3-graphMember.bin")
|
248
|
+
input = parent
|
249
|
+
output = AMF.serialize(input, 3)
|
250
|
+
output.should == expected
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|