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.
Files changed (81) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/README.rdoc +52 -0
  4. data/Rakefile +59 -0
  5. data/benchmark.rb +86 -0
  6. data/doc/amf3-speification.pdf +0 -0
  7. data/ext/rocketamf_ext/class_mapping.c +483 -0
  8. data/ext/rocketamf_ext/constants.h +52 -0
  9. data/ext/rocketamf_ext/deserializer.c +776 -0
  10. data/ext/rocketamf_ext/deserializer.h +28 -0
  11. data/ext/rocketamf_ext/extconf.rb +18 -0
  12. data/ext/rocketamf_ext/remoting.c +184 -0
  13. data/ext/rocketamf_ext/rocketamf_ext.c +38 -0
  14. data/ext/rocketamf_ext/serializer.c +834 -0
  15. data/ext/rocketamf_ext/serializer.h +29 -0
  16. data/ext/rocketamf_ext/utility.h +4 -0
  17. data/lib/amf/common/hash_with_type.rb +20 -0
  18. data/lib/amf/ext.rb +22 -0
  19. data/lib/amf/pure/amf_constants.rb +42 -0
  20. data/lib/amf/pure/deserializer.rb +354 -0
  21. data/lib/amf/pure/errors/all_files.rb +2 -0
  22. data/lib/amf/pure/errors/amf_error.rb +5 -0
  23. data/lib/amf/pure/errors/amf_error_incomplete.rb +5 -0
  24. data/lib/amf/pure/helpers/all_files.rb +8 -0
  25. data/lib/amf/pure/helpers/cache_objects.rb +18 -0
  26. data/lib/amf/pure/helpers/cache_strings.rb +14 -0
  27. data/lib/amf/pure/helpers/io_helper_base.rb +19 -0
  28. data/lib/amf/pure/helpers/io_helper_read.rb +67 -0
  29. data/lib/amf/pure/helpers/io_helper_write.rb +49 -0
  30. data/lib/amf/pure/mapping/class_mapper.rb +159 -0
  31. data/lib/amf/pure/mapping/mapping_set.rb +49 -0
  32. data/lib/amf/pure/serializer.rb +318 -0
  33. data/lib/amf/pure.rb +16 -0
  34. data/lib/amf.rb +140 -0
  35. data/mrpin-amf.gemspec +24 -0
  36. data/spec/fixtures/objects/complex/amf3-associative-array.bin +1 -0
  37. data/spec/fixtures/objects/complex/amf3-byte-array.bin +0 -0
  38. data/spec/fixtures/objects/complex/amf3-date.bin +0 -0
  39. data/spec/fixtures/objects/complex/amf3-dictionary.bin +0 -0
  40. data/spec/fixtures/objects/complex/amf3-dynamic-object.bin +2 -0
  41. data/spec/fixtures/objects/complex/amf3-empty-array.bin +1 -0
  42. data/spec/fixtures/objects/complex/amf3-empty-dictionary.bin +0 -0
  43. data/spec/fixtures/objects/complex/amf3-hash.bin +2 -0
  44. data/spec/fixtures/objects/complex/amf3-mixed-array.bin +10 -0
  45. data/spec/fixtures/objects/complex/amf3-primitive-array.bin +1 -0
  46. data/spec/fixtures/objects/complex/amf3-typed-object.bin +2 -0
  47. data/spec/fixtures/objects/encoding/amf3-complex-encoded-string-array.bin +1 -0
  48. data/spec/fixtures/objects/encoding/amf3-encoded-string-ref.bin +0 -0
  49. data/spec/fixtures/objects/references/amf3-array-ref.bin +1 -0
  50. data/spec/fixtures/objects/references/amf3-byte-array-ref.bin +1 -0
  51. data/spec/fixtures/objects/references/amf3-date-ref.bin +0 -0
  52. data/spec/fixtures/objects/references/amf3-empty-array-ref.bin +1 -0
  53. data/spec/fixtures/objects/references/amf3-empty-string-ref.bin +1 -0
  54. data/spec/fixtures/objects/references/amf3-graph-member.bin +0 -0
  55. data/spec/fixtures/objects/references/amf3-object-ref.bin +0 -0
  56. data/spec/fixtures/objects/references/amf3-string-ref.bin +0 -0
  57. data/spec/fixtures/objects/references/amf3-trait-ref.bin +3 -0
  58. data/spec/fixtures/objects/simple/amf3-0.bin +0 -0
  59. data/spec/fixtures/objects/simple/amf3-bigNum.bin +0 -0
  60. data/spec/fixtures/objects/simple/amf3-false.bin +1 -0
  61. data/spec/fixtures/objects/simple/amf3-float.bin +0 -0
  62. data/spec/fixtures/objects/simple/amf3-large-max.bin +0 -0
  63. data/spec/fixtures/objects/simple/amf3-large-min.bin +0 -0
  64. data/spec/fixtures/objects/simple/amf3-max.bin +1 -0
  65. data/spec/fixtures/objects/simple/amf3-min.bin +0 -0
  66. data/spec/fixtures/objects/simple/amf3-null.bin +1 -0
  67. data/spec/fixtures/objects/simple/amf3-string.bin +1 -0
  68. data/spec/fixtures/objects/simple/amf3-symbol.bin +1 -0
  69. data/spec/fixtures/objects/simple/amf3-true.bin +1 -0
  70. data/spec/helpers/class_mapping_test.rb +4 -0
  71. data/spec/helpers/class_mapping_test2.rb +3 -0
  72. data/spec/helpers/fixtures.rb +34 -0
  73. data/spec/helpers/other_class.rb +4 -0
  74. data/spec/helpers/ruby_class.rb +4 -0
  75. data/spec/helpers/test_ruby_class.rb +4 -0
  76. data/spec/spec-class_mapping.rb +98 -0
  77. data/spec/spec_deserializer.rb +239 -0
  78. data/spec/spec_fast_class_mapping.rb +147 -0
  79. data/spec/spec_helper.rb +8 -0
  80. data/spec/spec_serializer.rb +267 -0
  81. metadata +146 -0
@@ -0,0 +1,2 @@
1
+
2
+ /another_public_propertya_public_valuenil_propertyproperty_onefoo
@@ -0,0 +1,10 @@
1
+ 
2
+ foo_onebar_one
3
+ foo_two
4
+ foo_three*
5
+  
6
+ 
7
+ 
8
+  * 
9
+ 
10
+ 
@@ -0,0 +1 @@
1
+ 
@@ -0,0 +1,2 @@
1
+
2
+ #org.amf.ASClassbazfoobar
@@ -0,0 +1 @@
1
+ Shift テストUTF テスト
@@ -0,0 +1 @@
1
+   abc  
@@ -0,0 +1,3 @@
1
+ 
2
+ #org.amf.ASClassbazfoo
3
+ bar
@@ -0,0 +1 @@
1
+ ����
@@ -0,0 +1 @@
1
+ String . String
@@ -0,0 +1 @@
1
+ foo
@@ -0,0 +1,4 @@
1
+ class ClassMappingTest
2
+ attr_accessor :prop_a
3
+ attr_accessor :prop_b
4
+ end
@@ -0,0 +1,3 @@
1
+ class ClassMappingTest2 < ClassMappingTest
2
+ attr_accessor :prop_c
3
+ end
@@ -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,4 @@
1
+ class OtherClass;
2
+ attr_accessor :bar
3
+ attr_accessor :foo
4
+ end
@@ -0,0 +1,4 @@
1
+ class RubyClass;
2
+ attr_accessor :baz
3
+ attr_accessor :foo
4
+ end
@@ -0,0 +1,4 @@
1
+ module ANamespace
2
+ class TestRubyClass
3
+ end
4
+ 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
@@ -0,0 +1,8 @@
1
+ require 'rubygems'
2
+ require 'rspec'
3
+
4
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
5
+
6
+ require 'amf'
7
+
8
+ Dir[File.dirname(__FILE__) + '/helpers/*.rb'].each { |file| require file }