mrpin-amf 2.1.8
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.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/README.rdoc +52 -0
- data/Rakefile +59 -0
- data/benchmark.rb +86 -0
- data/doc/amf3-speification.pdf +0 -0
- data/ext/rocketamf_ext/class_mapping.c +483 -0
- data/ext/rocketamf_ext/constants.h +52 -0
- data/ext/rocketamf_ext/deserializer.c +776 -0
- data/ext/rocketamf_ext/deserializer.h +28 -0
- data/ext/rocketamf_ext/extconf.rb +18 -0
- data/ext/rocketamf_ext/remoting.c +184 -0
- data/ext/rocketamf_ext/rocketamf_ext.c +38 -0
- data/ext/rocketamf_ext/serializer.c +834 -0
- data/ext/rocketamf_ext/serializer.h +29 -0
- data/ext/rocketamf_ext/utility.h +4 -0
- data/lib/amf/common/hash_with_type.rb +20 -0
- data/lib/amf/ext.rb +22 -0
- data/lib/amf/pure/amf_constants.rb +42 -0
- data/lib/amf/pure/deserializer.rb +354 -0
- data/lib/amf/pure/errors/all_files.rb +2 -0
- data/lib/amf/pure/errors/amf_error.rb +5 -0
- data/lib/amf/pure/errors/amf_error_incomplete.rb +5 -0
- data/lib/amf/pure/helpers/all_files.rb +8 -0
- data/lib/amf/pure/helpers/cache_objects.rb +18 -0
- data/lib/amf/pure/helpers/cache_strings.rb +14 -0
- data/lib/amf/pure/helpers/io_helper_base.rb +19 -0
- data/lib/amf/pure/helpers/io_helper_read.rb +67 -0
- data/lib/amf/pure/helpers/io_helper_write.rb +49 -0
- data/lib/amf/pure/mapping/class_mapper.rb +159 -0
- data/lib/amf/pure/mapping/mapping_set.rb +49 -0
- data/lib/amf/pure/serializer.rb +318 -0
- data/lib/amf/pure.rb +16 -0
- data/lib/amf.rb +140 -0
- data/mrpin-amf.gemspec +24 -0
- data/spec/fixtures/objects/complex/amf3-associative-array.bin +1 -0
- data/spec/fixtures/objects/complex/amf3-byte-array.bin +0 -0
- data/spec/fixtures/objects/complex/amf3-date.bin +0 -0
- data/spec/fixtures/objects/complex/amf3-dictionary.bin +0 -0
- data/spec/fixtures/objects/complex/amf3-dynamic-object.bin +2 -0
- data/spec/fixtures/objects/complex/amf3-empty-array.bin +1 -0
- data/spec/fixtures/objects/complex/amf3-empty-dictionary.bin +0 -0
- data/spec/fixtures/objects/complex/amf3-hash.bin +2 -0
- data/spec/fixtures/objects/complex/amf3-mixed-array.bin +10 -0
- data/spec/fixtures/objects/complex/amf3-primitive-array.bin +1 -0
- data/spec/fixtures/objects/complex/amf3-typed-object.bin +2 -0
- data/spec/fixtures/objects/encoding/amf3-complex-encoded-string-array.bin +1 -0
- data/spec/fixtures/objects/encoding/amf3-encoded-string-ref.bin +0 -0
- data/spec/fixtures/objects/references/amf3-array-ref.bin +1 -0
- data/spec/fixtures/objects/references/amf3-byte-array-ref.bin +1 -0
- data/spec/fixtures/objects/references/amf3-date-ref.bin +0 -0
- data/spec/fixtures/objects/references/amf3-empty-array-ref.bin +1 -0
- data/spec/fixtures/objects/references/amf3-empty-string-ref.bin +1 -0
- data/spec/fixtures/objects/references/amf3-graph-member.bin +0 -0
- data/spec/fixtures/objects/references/amf3-object-ref.bin +0 -0
- data/spec/fixtures/objects/references/amf3-string-ref.bin +0 -0
- data/spec/fixtures/objects/references/amf3-trait-ref.bin +3 -0
- data/spec/fixtures/objects/simple/amf3-0.bin +0 -0
- data/spec/fixtures/objects/simple/amf3-bigNum.bin +0 -0
- data/spec/fixtures/objects/simple/amf3-false.bin +1 -0
- data/spec/fixtures/objects/simple/amf3-float.bin +0 -0
- data/spec/fixtures/objects/simple/amf3-large-max.bin +0 -0
- data/spec/fixtures/objects/simple/amf3-large-min.bin +0 -0
- data/spec/fixtures/objects/simple/amf3-max.bin +1 -0
- data/spec/fixtures/objects/simple/amf3-min.bin +0 -0
- data/spec/fixtures/objects/simple/amf3-null.bin +1 -0
- data/spec/fixtures/objects/simple/amf3-string.bin +1 -0
- data/spec/fixtures/objects/simple/amf3-symbol.bin +1 -0
- data/spec/fixtures/objects/simple/amf3-true.bin +1 -0
- data/spec/helpers/class_mapping_test.rb +4 -0
- data/spec/helpers/class_mapping_test2.rb +3 -0
- data/spec/helpers/fixtures.rb +34 -0
- data/spec/helpers/other_class.rb +4 -0
- data/spec/helpers/ruby_class.rb +4 -0
- data/spec/helpers/test_ruby_class.rb +4 -0
- data/spec/spec-class_mapping.rb +98 -0
- data/spec/spec_deserializer.rb +239 -0
- data/spec/spec_fast_class_mapping.rb +147 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/spec_serializer.rb +267 -0
- metadata +146 -0
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
Shift テストUTF テスト
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
abc
|
@@ -0,0 +1 @@
|
|
1
|
+
ASDF
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
����
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
|
@@ -0,0 +1 @@
|
|
1
|
+
String . String
|
@@ -0,0 +1 @@
|
|
1
|
+
foo
|
@@ -0,0 +1 @@
|
|
1
|
+
|
@@ -0,0 +1,34 @@
|
|
1
|
+
def request_fixture(binary_path)
|
2
|
+
data = File.open(File.dirname(__FILE__) + '/../fixtures/request/' + binary_path, 'rb').read
|
3
|
+
data.force_encoding('ASCII-8BIT') if data.respond_to?(:force_encoding)
|
4
|
+
data
|
5
|
+
end
|
6
|
+
|
7
|
+
def object_fixture(binary_path)
|
8
|
+
data = File.open(File.dirname(__FILE__) + '/../fixtures/objects/' + binary_path, 'rb').read
|
9
|
+
data.force_encoding('ASCII-8BIT') if data.respond_to?(:force_encoding)
|
10
|
+
data
|
11
|
+
end
|
12
|
+
|
13
|
+
def first_object_eq(object_fixture, value)
|
14
|
+
input = object_fixture(object_fixture)
|
15
|
+
output = AMF::Root.deserialize(input)
|
16
|
+
|
17
|
+
first_object = output[:objects][0]
|
18
|
+
|
19
|
+
expect(first_object).to eq(value)
|
20
|
+
end
|
21
|
+
|
22
|
+
def get_first_object(object_fixture)
|
23
|
+
input = object_fixture(object_fixture)
|
24
|
+
output = AMF::Root.deserialize(input)
|
25
|
+
|
26
|
+
requests = output[:objects]
|
27
|
+
requests[0]
|
28
|
+
end
|
29
|
+
|
30
|
+
def compare_with_fixture(input, fixture_name)
|
31
|
+
expected = object_fixture(fixture_name)
|
32
|
+
output = AMF::Root.serialize(input)
|
33
|
+
expect(output).to eq(expected)
|
34
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe AMF::ClassMapper do
|
4
|
+
before :each do
|
5
|
+
AMF::ClassMapper.reset
|
6
|
+
AMF::ClassMapper.register_class_alias('ClassMappingTest', 'ASClass')
|
7
|
+
|
8
|
+
@mapper = AMF::ClassMapper.new
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'class name mapping' do
|
12
|
+
it 'should allow resetting of mappings back to defaults' do
|
13
|
+
expect(@mapper.get_class_name_remote(ClassMappingTest.new)).not_to be_nil
|
14
|
+
|
15
|
+
AMF::ClassMapper.reset
|
16
|
+
|
17
|
+
@mapper = AMF::ClassMapper.new
|
18
|
+
expect(@mapper.get_class_name_remote(ClassMappingTest.new)).to be_nil
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should return AS class name for ruby objects' do
|
22
|
+
expect(@mapper.get_class_name_remote(ClassMappingTest.new)).to eq('ASClass')
|
23
|
+
expect(@mapper.get_class_name_remote(AMF::HashWithType.new('ClassMappingTest'))).to eq('ASClass')
|
24
|
+
expect(@mapper.get_class_name_remote('BadClass')).to be_nil
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should instantiate a ruby class' do
|
28
|
+
expect(@mapper.create_object('ASClass')).to be_a(ClassMappingTest)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should properly instantiate namespaced classes' do
|
32
|
+
AMF::ClassMapper.register_class_alias('ANamespace::TestRubyClass', 'ASClass')
|
33
|
+
@mapper = AMF::ClassMapper.new
|
34
|
+
|
35
|
+
expect(@mapper.create_object('ASClass')).to be_a(ANamespace::TestRubyClass)
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should return a hash with original type if not mapped' do
|
39
|
+
obj = @mapper.create_object('UnmappedClass')
|
40
|
+
|
41
|
+
expect(obj).to be_a(AMF::HashWithType)
|
42
|
+
expect(obj.class_type).to eq('UnmappedClass')
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should map special classes from AS by default' do
|
46
|
+
as_classes =
|
47
|
+
%w( )
|
48
|
+
|
49
|
+
as_classes.each do |as_class|
|
50
|
+
expect(@mapper.create_object(as_class)).not_to be_a(AMF::Types::HashWithType)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'should allow config modification' do
|
55
|
+
AMF::ClassMapper.register_class_alias('ClassMappingTest', 'SecondClass')
|
56
|
+
@mapper = AMF::ClassMapper.new
|
57
|
+
|
58
|
+
expect(@mapper.get_class_name_remote(ClassMappingTest.new)).to eq('SecondClass')
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe 'ruby object populator' do
|
63
|
+
it 'should populate a ruby class' do
|
64
|
+
obj = @mapper.object_deserialize ClassMappingTest.new, {:prop_a => 'Data'}
|
65
|
+
expect(obj.prop_a).to eq('Data')
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should populate a typed hash' do
|
69
|
+
obj = @mapper.object_deserialize AMF::HashWithType.new('UnmappedClass'), {prop_a: 'Data'}
|
70
|
+
expect(obj[:prop_a]).to eq('Data')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe 'property extractor' do
|
75
|
+
it 'should extract hash properties' do
|
76
|
+
hash = {a: 'test1', 'b' => 'test2'}
|
77
|
+
props = @mapper.object_serialize(hash)
|
78
|
+
expect(props).to eq({'a' => 'test1', 'b' => 'test2'})
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'should extract object properties' do
|
82
|
+
obj = ClassMappingTest.new
|
83
|
+
obj.prop_a = 'Test A'
|
84
|
+
|
85
|
+
hash = @mapper.object_serialize obj
|
86
|
+
expect(hash).to eq({'prop_a' => 'Test A', 'prop_b' => nil})
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'should extract inherited object properties' do
|
90
|
+
obj = ClassMappingTest2.new
|
91
|
+
obj.prop_a = 'Test A'
|
92
|
+
obj.prop_c = 'Test C'
|
93
|
+
|
94
|
+
hash = @mapper.object_serialize obj
|
95
|
+
expect(hash).to eq({'prop_a' => 'Test A', 'prop_b' => nil, 'prop_c' => 'Test C'})
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,239 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'spec_helper.rb'
|
4
|
+
|
5
|
+
describe 'when deserializing' do
|
6
|
+
before :each do
|
7
|
+
AMF::Root.clear_class_aliases
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'AMF3' do
|
11
|
+
it 'should update source pos if source is a StringIO object' do
|
12
|
+
input = StringIO.new(object_fixture('simple/amf3-null.bin'))
|
13
|
+
expect(input.pos).to eq(0)
|
14
|
+
|
15
|
+
AMF::Root.deserialize(input)
|
16
|
+
|
17
|
+
expect(input.pos).to eq(1)
|
18
|
+
end
|
19
|
+
|
20
|
+
describe 'simple messages' do
|
21
|
+
it 'should deserialize a null' do
|
22
|
+
first_object_eq('simple/amf3-null.bin', nil)
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'should deserialize a false' do
|
26
|
+
first_object_eq('simple/amf3-false.bin', false)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should deserialize a true' do
|
30
|
+
first_object_eq('simple/amf3-true.bin', true)
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should deserialize integers' do
|
34
|
+
first_object_eq('simple/amf3-max.bin', AMF::AMFConstants::INTEGER_MAX)
|
35
|
+
first_object_eq('simple/amf3-0.bin', 0)
|
36
|
+
first_object_eq('simple/amf3-min.bin', AMF::AMFConstants::INTEGER_MIN)
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should deserialize large integers' do
|
40
|
+
first_object_eq('simple/amf3-large-max.bin', AMF::AMFConstants::INTEGER_MAX + 1.0)
|
41
|
+
first_object_eq('simple/amf3-large-min.bin', AMF::AMFConstants::INTEGER_MIN - 1.0)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should deserialize BigNums' do
|
45
|
+
first_object_eq('simple/amf3-bignum.bin', 2.0**1000)
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should deserialize a simple string' do
|
49
|
+
first_object_eq('simple/amf3-string.bin', 'String . String')
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should deserialize a symbol as a string' do
|
53
|
+
first_object_eq('simple/amf3-symbol.bin', 'foo')
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
describe 'objects' do
|
59
|
+
|
60
|
+
it 'should deserialize dates' do
|
61
|
+
first_object_eq('complex/amf3-date.bin', Time.at(0))
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'should deserialize an unmapped object as a dynamic anonymous object' do
|
65
|
+
|
66
|
+
value =
|
67
|
+
{
|
68
|
+
'property_one' => 'foo',
|
69
|
+
'nil_property' => nil,
|
70
|
+
'another_public_property' => 'a_public_value'
|
71
|
+
}
|
72
|
+
|
73
|
+
request = get_first_object('complex/amf3-dynamic-object.bin')
|
74
|
+
|
75
|
+
expect(request).to match(value)
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should deserialize a mapped object as a mapped ruby class instance' do
|
79
|
+
AMF::Root.register_class_alias('RubyClass', 'org.amf.ASClass')
|
80
|
+
|
81
|
+
request = get_first_object('complex/amf3-typed-object.bin')
|
82
|
+
|
83
|
+
expect(request).to be_a(RubyClass)
|
84
|
+
expect(request.foo).to eq('bar')
|
85
|
+
expect(request.baz).to eq(nil)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should deserialize a hash as a dynamic anonymous object' do
|
89
|
+
first_object_eq('complex/amf3-hash.bin', {'foo' => 'bar', 'answer' => 42})
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'should deserialize an empty array' do
|
93
|
+
request = get_first_object('complex/amf3-empty-array.bin')
|
94
|
+
expect(request).to match_array([])
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should deserialize an array of primitives' do
|
98
|
+
request = get_first_object('complex/amf3-primitive-array.bin')
|
99
|
+
expect(request).to match_array([1, 2, 3, 4, 5])
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'should deserialize an associative array' do
|
103
|
+
request = get_first_object('complex/amf3-associative-array.bin')
|
104
|
+
expect(request).to match({0 => 'bar1', 1 => 'bar2', 2 => 'bar3', 'asdf' => 'fdsa', 'foo' => 'bar', '42' => 'bar'})
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'should deserialize an array of mixed objects' do
|
108
|
+
request = get_first_object('complex/amf3-mixed-array.bin')
|
109
|
+
|
110
|
+
value0 = {'foo_one' => 'bar_one'}
|
111
|
+
value1 = {'foo_two' => ''}
|
112
|
+
value2 = {'foo_three' => 42}
|
113
|
+
expect(request).to match_array([value0, value1, value2, {}, [value0, value1, value2], [], 42, '', [], '', {}, 'bar_one', value2])
|
114
|
+
end
|
115
|
+
|
116
|
+
it 'should deserialize a byte array' do
|
117
|
+
request = get_first_object('complex/amf3-byte-array.bin')
|
118
|
+
|
119
|
+
expect(request).to be_a(StringIO)
|
120
|
+
expected = "\000\003これtest\100"
|
121
|
+
expected.force_encoding('ASCII-8BIT') if expected.respond_to?(:force_encoding)
|
122
|
+
expect(request.string).to eq(expected)
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'should deserialize an empty dictionary' do
|
126
|
+
request = get_first_object('complex/amf3-empty-dictionary.bin')
|
127
|
+
expect(request).to match({})
|
128
|
+
end
|
129
|
+
|
130
|
+
it 'should deserialize a dictionary' do
|
131
|
+
request = get_first_object('complex/amf3-dictionary.bin')
|
132
|
+
|
133
|
+
keys = request.keys
|
134
|
+
expect(keys.length).to eq(2)
|
135
|
+
obj_key, str_key = keys[0].is_a?(AMF::HashWithType) ? [keys[0], keys[1]] : [keys[1], keys[0]]
|
136
|
+
|
137
|
+
expect(obj_key.class_type).to eq('org.amf.ASClass')
|
138
|
+
expect(request[obj_key]).to eq('asdf2')
|
139
|
+
expect(str_key).to eq('bar')
|
140
|
+
expect(request[str_key]).to eq('asdf1')
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
describe 'and implementing the AMF references' do
|
145
|
+
it 'should keep references of duplicate strings' do
|
146
|
+
output = get_first_object('references/amf3-string-ref.bin')
|
147
|
+
|
148
|
+
foo = 'foo'
|
149
|
+
bar = 'str'
|
150
|
+
expect(output).to match_array([foo, bar, foo, bar, foo, {'str' => 'foo'}])
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'should not reference the empty string' do
|
154
|
+
output = get_first_object('references/amf3-empty-string-ref.bin')
|
155
|
+
expect(output).to match_array(['', ''])
|
156
|
+
end
|
157
|
+
|
158
|
+
it 'should keep references of duplicate dates' do
|
159
|
+
output = get_first_object('references/amf3-date-ref.bin')
|
160
|
+
|
161
|
+
expect(output[0]).to eq(Time.at(0))
|
162
|
+
expect(output[0]).to eq(output[1])
|
163
|
+
# Expected object:
|
164
|
+
# [DateTime.parse '1/1/1970', DateTime.parse '1/1/1970']
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'should keep reference of duplicate objects' do
|
168
|
+
output = get_first_object('references/amf3-object-ref.bin')
|
169
|
+
|
170
|
+
obj1 = {'foo' => 'bar'}
|
171
|
+
obj2 = {'foo' => obj1['foo']}
|
172
|
+
|
173
|
+
expect(output).to match_array([[obj1, obj2], 'bar', [obj1, obj2]])
|
174
|
+
end
|
175
|
+
|
176
|
+
it 'should keep reference of duplicate object traits' do
|
177
|
+
AMF::Root.register_class_alias('RubyClass', 'org.amf.ASClass')
|
178
|
+
|
179
|
+
output = get_first_object('references/amf3-trait-ref.bin')
|
180
|
+
|
181
|
+
expect(output[0].foo).to eq('foo')
|
182
|
+
expect(output[0].class).to eq(RubyClass)
|
183
|
+
|
184
|
+
expect(output[1].foo).to eq('bar')
|
185
|
+
expect(output[1].class).to eq(RubyClass)
|
186
|
+
end
|
187
|
+
|
188
|
+
it 'should keep references of duplicate arrays' do
|
189
|
+
output = get_first_object('references/amf3-array-ref.bin')
|
190
|
+
|
191
|
+
a = [1, 2, 3]
|
192
|
+
b = %w{ a b c }
|
193
|
+
expect(output).to match_array([a, b, a, b])
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'should not keep references of duplicate empty arrays unless the object_id matches' do
|
197
|
+
output = get_first_object('references/amf3-empty-array-ref.bin')
|
198
|
+
|
199
|
+
a = []
|
200
|
+
b = []
|
201
|
+
|
202
|
+
expect(output).to match_array([a, b, a, b])
|
203
|
+
|
204
|
+
expect(output[0].object_id).to eq(output[2].object_id)
|
205
|
+
expect(output[1].object_id).to eq(output[3].object_id)
|
206
|
+
|
207
|
+
expect(output[0].object_id).not_to eq(output[1].object_id)
|
208
|
+
|
209
|
+
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'should keep references of duplicate byte arrays' do
|
213
|
+
output = get_first_object('references/amf3-byte-array-ref.bin')
|
214
|
+
|
215
|
+
expect(output[0].object_id).to eq(output[1].object_id)
|
216
|
+
expect(output[0].string).to eq('ASDF')
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'should deserialize a deep object graph with circular references' do
|
220
|
+
|
221
|
+
output = get_first_object('references/amf3-graph-member.bin')
|
222
|
+
|
223
|
+
expect(output['children'][0]['parent']).to eq(output)
|
224
|
+
expect(output['parent']).to eq(nil)
|
225
|
+
expect(output['children'].length).to eq(2)
|
226
|
+
# Expected object:
|
227
|
+
# parent = Hash.new
|
228
|
+
# child1 = Hash.new
|
229
|
+
# child1[:parent] = parent
|
230
|
+
# child1[:children] = []
|
231
|
+
# child2 = Hash.new
|
232
|
+
# child2[:parent] = parent
|
233
|
+
# child2[:children] = []
|
234
|
+
# parent[:parent] = nil
|
235
|
+
# parent[:children] = [child1, child2]
|
236
|
+
end
|
237
|
+
end
|
238
|
+
end
|
239
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe AMF::Ext::FastClassMapping do
|
4
|
+
before :each do
|
5
|
+
AMF::Ext::FastClassMapping.reset
|
6
|
+
AMF::Ext::FastClassMapping.define do |m|
|
7
|
+
m.map :as => 'ASClass', ruby: 'ClassMappingTest'
|
8
|
+
end
|
9
|
+
@mapper = AMF::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_class_name_remote('ClassMappingTest').should_not be_nil
|
15
|
+
AMF::Ext::FastClassMapping.reset
|
16
|
+
@mapper = AMF::Ext::FastClassMapping.new
|
17
|
+
@mapper.get_class_name_remote('ClassMappingTest').should be_nil
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should return AS class name for ruby objects' do
|
21
|
+
@mapper.get_class_name_remote(ClassMappingTest.new).should == 'ASClass'
|
22
|
+
@mapper.get_class_name_remote('ClassMappingTest').should == 'ASClass'
|
23
|
+
@mapper.get_class_name_remote(AMF::Types::HashWithType.new('ClassMappingTest')).should == 'ASClass'
|
24
|
+
@mapper.get_class_name_remote('BadClass').should be_nil
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should instantiate a ruby class' do
|
28
|
+
@mapper.create_object('ASClass').should be_a(ClassMappingTest)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should properly instantiate namespaced classes' do
|
32
|
+
AMF::Ext::FastClassMapping.map.map :as => 'ASClass', ruby: 'ANamespace::TestRubyClass'
|
33
|
+
@mapper = AMF::Ext::FastClassMapping.new
|
34
|
+
@mapper.create_object('ASClass').should be_a(ANamespace::TestRubyClass)
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should return a hash with original type if not mapped' do
|
38
|
+
obj = @mapper.create_object('UnmappedClass')
|
39
|
+
obj.should be_a(AMF::Types::HashWithType)
|
40
|
+
obj.class_type.should == 'UnmappedClass'
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'should map special classes from AS by default' do
|
44
|
+
as_classes =
|
45
|
+
%w(
|
46
|
+
flex.messaging.messages.CommandMessage
|
47
|
+
flex.messaging.messages.RemotingMessage
|
48
|
+
)
|
49
|
+
|
50
|
+
as_classes.each do |as_class|
|
51
|
+
@mapper.create_object(as_class).should_not be_a(AMF::Types::HashWithType)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should map special classes from ruby by default' do
|
56
|
+
ruby_classes =
|
57
|
+
%w(
|
58
|
+
AMF::Types::ErrorMessage
|
59
|
+
)
|
60
|
+
|
61
|
+
ruby_classes.each do |obj|
|
62
|
+
@mapper.get_class_name_remote(obj).should_not be_nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'should allow config modification' do
|
67
|
+
AMF::Ext::FastClassMapping.map.map :as => 'SecondClass', ruby: 'ClassMappingTest'
|
68
|
+
@mapper = AMF::Ext::FastClassMapping.new
|
69
|
+
@mapper.get_class_name_remote(ClassMappingTest.new).should == 'SecondClass'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe 'ruby object populator' do
|
74
|
+
it 'should populate a ruby class' do
|
75
|
+
obj = @mapper.object_deserialize ClassMappingTest.new, {:prop_a => 'Data'}
|
76
|
+
obj.prop_a.should == 'Data'
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should populate a typed hash' do
|
80
|
+
obj = @mapper.object_deserialize AMF::Types::HashWithType.new('UnmappedClass'), {'prop_a' => 'Data'}
|
81
|
+
obj['prop_a'].should == 'Data'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe 'property extractor' do
|
86
|
+
# Use symbol keys for properties in Ruby >1.9
|
87
|
+
def prop_hash hash
|
88
|
+
out = {}
|
89
|
+
if RUBY_VERSION =~ /^1\.8/
|
90
|
+
hash.each { |k, v| out[k.to_s] = v }
|
91
|
+
else
|
92
|
+
hash.each { |k, v| out[k.to_sym] = v }
|
93
|
+
end
|
94
|
+
out
|
95
|
+
end
|
96
|
+
|
97
|
+
it 'should return hash without modification' do
|
98
|
+
hash = {:a => 'test1', 'b' => 'test2'}
|
99
|
+
props = @mapper.object_serialize(hash)
|
100
|
+
props.should === hash
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should extract object properties' do
|
104
|
+
obj = ClassMappingTest.new
|
105
|
+
obj.prop_a = 'Test A'
|
106
|
+
|
107
|
+
hash = @mapper.object_serialize obj
|
108
|
+
hash.should == prop_hash({'prop_a' => 'Test A', 'prop_b' => nil})
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should extract inherited object properties' do
|
112
|
+
obj = ClassMappingTest2.new
|
113
|
+
obj.prop_a = 'Test A'
|
114
|
+
obj.prop_c = 'Test C'
|
115
|
+
|
116
|
+
hash = @mapper.object_serialize obj
|
117
|
+
hash.should == prop_hash({'prop_a' => 'Test A', 'prop_b' => nil, 'prop_c' => 'Test C'})
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'should cache property lookups by instance' do
|
121
|
+
class ClassMappingTest3;
|
122
|
+
attr_accessor :prop_a;
|
123
|
+
end;
|
124
|
+
|
125
|
+
# Cache properties
|
126
|
+
obj = ClassMappingTest3.new
|
127
|
+
hash = @mapper.object_serialize obj
|
128
|
+
|
129
|
+
# Add a method to ClassMappingTest3
|
130
|
+
class ClassMappingTest3;
|
131
|
+
attr_accessor :prop_b;
|
132
|
+
end
|
133
|
+
|
134
|
+
# Test property list does not have new property
|
135
|
+
obj = ClassMappingTest3.new
|
136
|
+
obj.prop_a = 'Test A'
|
137
|
+
obj.prop_b = 'Test B'
|
138
|
+
hash = @mapper.object_serialize obj
|
139
|
+
hash.should == prop_hash({'prop_a' => 'Test A'})
|
140
|
+
|
141
|
+
# Test that new class mapper *does* have new property (cache per instance)
|
142
|
+
@mapper = AMF::Ext::FastClassMapping.new
|
143
|
+
hash = @mapper.object_serialize obj
|
144
|
+
hash.should == prop_hash({'prop_a' => 'Test A', 'prop_b' => 'Test B'})
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|