mrpin-rocketamf 1.0.4 → 2.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.
- checksums.yaml +4 -4
- data/README.rdoc +1 -1
- data/Rakefile +7 -7
- data/benchmark.rb +44 -37
- data/ext/rocketamf_ext/class_mapping.c +11 -11
- data/ext/rocketamf_ext/remoting.c +1 -1
- data/lib/rocketamf.rb +41 -98
- data/lib/rocketamf/constants.rb +20 -20
- data/lib/rocketamf/errors.rb +2 -0
- data/lib/rocketamf/errors/amf_error.rb +5 -0
- data/lib/rocketamf/errors/amf_error_incomplete.rb +5 -0
- data/lib/rocketamf/ext.rb +0 -6
- data/lib/rocketamf/extensions.rb +4 -4
- data/lib/rocketamf/{class_mapping.rb → mapping/class_mapping.rb} +70 -103
- data/lib/rocketamf/mapping/mapping_set.rb +63 -0
- data/lib/rocketamf/pure.rb +1 -9
- data/lib/rocketamf/pure/deserializer.rb +234 -262
- data/lib/rocketamf/pure/helpers/io_helper_base.rb +19 -0
- data/lib/rocketamf/pure/helpers/io_helper_read.rb +67 -0
- data/lib/rocketamf/pure/helpers/io_helper_write.rb +48 -0
- data/lib/rocketamf/pure/helpers/object_cache.rb +20 -0
- data/lib/rocketamf/pure/helpers/string_cache.rb +14 -0
- data/lib/rocketamf/pure/serializer.rb +138 -271
- data/lib/rocketamf/types.rb +1 -0
- data/lib/rocketamf/{values → types}/typed_hash.rb +12 -2
- data/mrpin-rocketamf.gemspec +27 -16
- data/spec/class_mapping_spec.rb +59 -52
- data/spec/deserializer_spec.rb +164 -328
- data/spec/fast_class_mapping_spec.rb +52 -46
- data/spec/helpers/class_mapping_test.rb +4 -0
- data/spec/helpers/class_mapping_test2.rb +3 -0
- data/spec/helpers/externalizable_test.rb +24 -0
- data/spec/helpers/fixtures.rb +28 -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/serializer_spec.rb +248 -339
- data/spec/spec_helper.rb +4 -49
- metadata +47 -53
- data/lib/rocketamf/pure/io_helpers.rb +0 -94
- data/lib/rocketamf/pure/remoting.rb +0 -117
- data/lib/rocketamf/remoting.rb +0 -196
- data/lib/rocketamf/values/messages.rb +0 -214
- data/spec/fixtures/objects/amf0-boolean.bin +0 -1
- 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-empty-string-key-hash.bin +0 -0
- data/spec/fixtures/objects/amf0-hash.bin +0 -0
- data/spec/fixtures/objects/amf0-null.bin +0 -1
- 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 +0 -1
- data/spec/fixtures/objects/amf0-untyped-object.bin +0 -0
- data/spec/fixtures/objects/amf0-xml-doc.bin +0 -0
- data/spec/messages_spec.rb +0 -39
- data/spec/remoting_spec.rb +0 -196
@@ -0,0 +1 @@
|
|
1
|
+
require 'rocketamf/types/typed_hash'
|
@@ -1,11 +1,21 @@
|
|
1
1
|
module RocketAMF
|
2
|
-
module
|
2
|
+
module Types #:nodoc:
|
3
|
+
|
3
4
|
# Hash-like object that can store a type string. Used to preserve type information
|
4
5
|
# for unmapped objects after deserialization.
|
5
6
|
class TypedHash < Hash
|
7
|
+
|
8
|
+
#
|
9
|
+
# Properties
|
10
|
+
#
|
11
|
+
|
6
12
|
attr_reader :type
|
7
13
|
|
8
|
-
|
14
|
+
#
|
15
|
+
# Methods
|
16
|
+
#
|
17
|
+
|
18
|
+
def initialize(type)
|
9
19
|
@type = type
|
10
20
|
end
|
11
21
|
end
|
data/mrpin-rocketamf.gemspec
CHANGED
@@ -1,22 +1,33 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
|
-
Gem::Specification.new do |
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = 'mrpin-rocketamf'
|
5
|
+
spec.version = '2.0.0'
|
6
|
+
spec.platform = Gem::Platform::RUBY
|
7
|
+
spec.authors = ['Jacob Henry', 'Stephen Augenstein', "Joc O'Connor", 'Gregory Tkach']
|
8
|
+
spec.email = %w(gregory.tkach@gmail.com)
|
9
|
+
spec.homepage = 'https://github.com/mrpin/mrpin-rocketamf'
|
10
|
+
spec.license = 'MIT'
|
11
|
+
spec.summary = 'Fast AMF3 serializer/deserializer'
|
12
|
+
spec.description = 'Fast AMF3 serializer/deserializer with remoting request/response wrappers to simplify integration'
|
11
13
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
files = []
|
15
|
+
files << 'README.rdoc'
|
16
|
+
files << 'benchmark.rb'
|
17
|
+
files << 'mrpin-rocketamf.gemspec'
|
18
|
+
files << 'Rakefile'
|
19
|
+
files << 'lib/**/*.rb'
|
20
|
+
files << 'spec/**/*.{rb,bin,opts}'
|
21
|
+
files << 'ext/**/*.{c,h,rb}'
|
16
22
|
|
17
|
-
|
23
|
+
spec.files = Dir[*files]
|
24
|
+
spec.test_files = Dir[*['spec/**/*_spec.rb']]
|
25
|
+
spec.extensions = Dir[*['ext/**/extconf.rb']]
|
26
|
+
spec.require_paths = ['lib']
|
18
27
|
|
19
|
-
|
20
|
-
|
21
|
-
|
28
|
+
spec.add_development_dependency 'rake-compiler', '~> 0'
|
29
|
+
|
30
|
+
spec.has_rdoc = true
|
31
|
+
spec.extra_rdoc_files = %w( README.rdoc )
|
32
|
+
spec.rdoc_options = %w(--line-numbers --main README.rdoc)
|
22
33
|
end
|
data/spec/class_mapping_spec.rb
CHANGED
@@ -1,110 +1,117 @@
|
|
1
|
-
require
|
1
|
+
require 'spec_helper.rb'
|
2
2
|
|
3
3
|
describe RocketAMF::ClassMapping do
|
4
4
|
before :each do
|
5
5
|
RocketAMF::ClassMapping.reset
|
6
6
|
RocketAMF::ClassMapping.define do |m|
|
7
|
-
m.map :
|
7
|
+
m.map as: 'ASClass', ruby: 'ClassMappingTest'
|
8
8
|
end
|
9
9
|
@mapper = RocketAMF::ClassMapping.new
|
10
10
|
end
|
11
11
|
|
12
|
-
describe
|
13
|
-
it
|
14
|
-
@mapper.get_as_class_name('ClassMappingTest').
|
12
|
+
describe 'class name mapping' do
|
13
|
+
it 'should allow resetting of mappings back to defaults' do
|
14
|
+
expect(@mapper.get_as_class_name('ClassMappingTest')).not_to be_nil
|
15
|
+
|
15
16
|
RocketAMF::ClassMapping.reset
|
17
|
+
|
16
18
|
@mapper = RocketAMF::ClassMapping.new
|
17
|
-
@mapper.get_as_class_name('ClassMappingTest').
|
18
|
-
@mapper.get_as_class_name('RocketAMF::
|
19
|
+
expect(@mapper.get_as_class_name('ClassMappingTest')).to be_nil
|
20
|
+
expect(@mapper.get_as_class_name('RocketAMF::Types::AcknowledgeMessage')).not_to be_nil
|
19
21
|
end
|
20
22
|
|
21
|
-
it
|
22
|
-
@mapper.get_as_class_name(ClassMappingTest.new).
|
23
|
-
@mapper.get_as_class_name('ClassMappingTest').
|
24
|
-
@mapper.get_as_class_name(RocketAMF::
|
25
|
-
@mapper.get_as_class_name('BadClass').
|
23
|
+
it 'should return AS class name for ruby objects' do
|
24
|
+
expect(@mapper.get_as_class_name(ClassMappingTest.new)).to eq('ASClass')
|
25
|
+
expect(@mapper.get_as_class_name('ClassMappingTest')).to eq('ASClass')
|
26
|
+
expect(@mapper.get_as_class_name(RocketAMF::Types::TypedHash.new('ClassMappingTest'))).to eq('ASClass')
|
27
|
+
expect(@mapper.get_as_class_name('BadClass')).to be_nil
|
26
28
|
end
|
27
29
|
|
28
|
-
it
|
29
|
-
@mapper.get_ruby_obj('ASClass').
|
30
|
+
it 'should instantiate a ruby class' do
|
31
|
+
expect(@mapper.get_ruby_obj('ASClass')).to be_a(ClassMappingTest)
|
30
32
|
end
|
31
33
|
|
32
|
-
it
|
33
|
-
RocketAMF::ClassMapping.mappings.map :
|
34
|
+
it 'should properly instantiate namespaced classes' do
|
35
|
+
RocketAMF::ClassMapping.mappings.map as: 'ASClass', ruby: 'ANamespace::TestRubyClass'
|
34
36
|
@mapper = RocketAMF::ClassMapping.new
|
35
|
-
|
37
|
+
|
38
|
+
expect(@mapper.get_ruby_obj('ASClass')).to be_a(ANamespace::TestRubyClass)
|
36
39
|
end
|
37
40
|
|
38
|
-
it
|
41
|
+
it 'should return a hash with original type if not mapped' do
|
39
42
|
obj = @mapper.get_ruby_obj('UnmappedClass')
|
40
|
-
|
41
|
-
obj.
|
43
|
+
|
44
|
+
expect(obj).to be_a(RocketAMF::Types::TypedHash)
|
45
|
+
expect(obj.type).to eq('UnmappedClass')
|
42
46
|
end
|
43
47
|
|
44
|
-
it
|
45
|
-
as_classes =
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
48
|
+
it 'should map special classes from AS by default' do
|
49
|
+
as_classes =
|
50
|
+
%w(
|
51
|
+
flex.messaging.messages.AcknowledgeMessage
|
52
|
+
flex.messaging.messages.CommandMessage
|
53
|
+
flex.messaging.messages.RemotingMessage
|
54
|
+
)
|
50
55
|
|
51
56
|
as_classes.each do |as_class|
|
52
|
-
@mapper.get_ruby_obj(as_class).
|
57
|
+
expect(@mapper.get_ruby_obj(as_class)).not_to be_a(RocketAMF::Types::TypedHash)
|
53
58
|
end
|
54
59
|
end
|
55
60
|
|
56
|
-
it
|
57
|
-
ruby_classes =
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
+
it 'should map special classes from ruby by default' do
|
62
|
+
ruby_classes =
|
63
|
+
%w(
|
64
|
+
RocketAMF::Types::AcknowledgeMessage
|
65
|
+
RocketAMF::Types::ErrorMessage
|
66
|
+
)
|
61
67
|
|
62
68
|
ruby_classes.each do |obj|
|
63
|
-
@mapper.get_as_class_name(obj).
|
69
|
+
expect(@mapper.get_as_class_name(obj)).not_to be_nil
|
64
70
|
end
|
65
71
|
end
|
66
72
|
|
67
|
-
it
|
68
|
-
RocketAMF::ClassMapping.mappings.map :
|
73
|
+
it 'should allow config modification' do
|
74
|
+
RocketAMF::ClassMapping.mappings.map as: 'SecondClass', ruby: 'ClassMappingTest'
|
69
75
|
@mapper = RocketAMF::ClassMapping.new
|
70
|
-
|
76
|
+
|
77
|
+
expect(@mapper.get_as_class_name(ClassMappingTest.new)).to eq('SecondClass')
|
71
78
|
end
|
72
79
|
end
|
73
80
|
|
74
|
-
describe
|
75
|
-
it
|
81
|
+
describe 'ruby object populator' do
|
82
|
+
it 'should populate a ruby class' do
|
76
83
|
obj = @mapper.populate_ruby_obj ClassMappingTest.new, {:prop_a => 'Data'}
|
77
|
-
obj.prop_a.
|
84
|
+
expect(obj.prop_a).to eq('Data')
|
78
85
|
end
|
79
86
|
|
80
|
-
it
|
81
|
-
obj = @mapper.populate_ruby_obj RocketAMF::
|
82
|
-
obj[:prop_a].
|
87
|
+
it 'should populate a typed hash' do
|
88
|
+
obj = @mapper.populate_ruby_obj RocketAMF::Types::TypedHash.new('UnmappedClass'), {prop_a: 'Data'}
|
89
|
+
expect(obj[:prop_a]).to eq('Data')
|
83
90
|
end
|
84
91
|
end
|
85
92
|
|
86
|
-
describe
|
87
|
-
it
|
88
|
-
hash
|
93
|
+
describe 'property extractor' do
|
94
|
+
it 'should extract hash properties' do
|
95
|
+
hash = {a: 'test1', 'b' => 'test2'}
|
89
96
|
props = @mapper.props_for_serialization(hash)
|
90
|
-
props.
|
97
|
+
expect(props).to eq({'a' => 'test1', 'b' => 'test2'})
|
91
98
|
end
|
92
99
|
|
93
|
-
it
|
94
|
-
obj
|
100
|
+
it 'should extract object properties' do
|
101
|
+
obj = ClassMappingTest.new
|
95
102
|
obj.prop_a = 'Test A'
|
96
103
|
|
97
104
|
hash = @mapper.props_for_serialization obj
|
98
|
-
hash.
|
105
|
+
expect(hash).to eq({'prop_a' => 'Test A', 'prop_b' => nil})
|
99
106
|
end
|
100
107
|
|
101
|
-
it
|
102
|
-
obj
|
108
|
+
it 'should extract inherited object properties' do
|
109
|
+
obj = ClassMappingTest2.new
|
103
110
|
obj.prop_a = 'Test A'
|
104
111
|
obj.prop_c = 'Test C'
|
105
112
|
|
106
113
|
hash = @mapper.props_for_serialization obj
|
107
|
-
hash.
|
114
|
+
expect(hash).to eq({'prop_a' => 'Test A', 'prop_b' => nil, 'prop_c' => 'Test C'})
|
108
115
|
end
|
109
116
|
end
|
110
117
|
end
|
data/spec/deserializer_spec.rb
CHANGED
@@ -1,444 +1,280 @@
|
|
1
1
|
# encoding: UTF-8
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'spec_helper.rb'
|
4
4
|
|
5
|
-
describe
|
5
|
+
describe 'when deserializing' do
|
6
6
|
before :each do
|
7
|
-
RocketAMF::
|
7
|
+
RocketAMF::CLASS_MAPPER.reset
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
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 hashes with empty string keys" do
|
61
|
-
input = object_fixture('amf0-empty-string-key-hash.bin')
|
62
|
-
output = RocketAMF.deserialize(input, 0)
|
63
|
-
output.should == {'a' => 'b', 'c' => 'd', '' => 'last'}
|
64
|
-
end
|
65
|
-
|
66
|
-
it "should deserialize arrays from flash player" do
|
67
|
-
# Even Array is serialized as a "hash"
|
68
|
-
input = object_fixture('amf0-ecma-ordinal-array.bin')
|
69
|
-
output = RocketAMF.deserialize(input, 0)
|
70
|
-
output.should == {'0' => 'a', '1' => 'b', '2' => 'c', '3' => 'd'}
|
71
|
-
end
|
72
|
-
|
73
|
-
it "should deserialize strict arrays" do
|
74
|
-
input = object_fixture('amf0-strict-array.bin')
|
75
|
-
output = RocketAMF.deserialize(input, 0)
|
76
|
-
output.should == ['a', 'b', 'c', 'd']
|
77
|
-
end
|
78
|
-
|
79
|
-
it "should deserialize dates" do
|
80
|
-
input = object_fixture('amf0-time.bin')
|
81
|
-
output = RocketAMF.deserialize(input, 0)
|
82
|
-
output.should == Time.utc(2003, 2, 13, 5)
|
83
|
-
end
|
84
|
-
|
85
|
-
it "should deserialize an XML document" do
|
86
|
-
input = object_fixture('amf0-xml-doc.bin')
|
87
|
-
output = RocketAMF.deserialize(input, 0)
|
88
|
-
output.should == '<parent><child prop="test" /></parent>'
|
89
|
-
end
|
90
|
-
|
91
|
-
it "should deserialize anonymous objects" do
|
92
|
-
input = object_fixture('amf0-object.bin')
|
93
|
-
output = RocketAMF.deserialize(input, 0)
|
94
|
-
output.should == {'foo' => 'baz', 'bar' => 3.14}
|
95
|
-
output.type.should == ""
|
96
|
-
end
|
97
|
-
|
98
|
-
it "should deserialize an unmapped object as a dynamic anonymous object" do
|
99
|
-
input = object_fixture("amf0-typed-object.bin")
|
100
|
-
output = RocketAMF.deserialize(input, 0)
|
101
|
-
|
102
|
-
output.type.should == 'org.amf.ASClass'
|
103
|
-
output.should == {'foo' => 'bar', 'baz' => nil}
|
104
|
-
end
|
105
|
-
|
106
|
-
it "should deserialize a mapped object as a mapped ruby class instance" do
|
107
|
-
RocketAMF::ClassMapper.define {|m| m.map :as => 'org.amf.ASClass', :ruby => 'RubyClass'}
|
108
|
-
|
109
|
-
input = object_fixture("amf0-typed-object.bin")
|
110
|
-
output = RocketAMF.deserialize(input, 0)
|
111
|
-
|
112
|
-
output.should be_a(RubyClass)
|
113
|
-
output.foo.should == 'bar'
|
114
|
-
output.baz.should == nil
|
115
|
-
end
|
10
|
+
describe 'AMF3' do
|
11
|
+
it 'should update source pos if source is a StringIO object' do
|
12
|
+
input = StringIO.new(object_fixture('amf3-null.bin'))
|
13
|
+
expect(input.pos).to eq(0)
|
116
14
|
|
117
|
-
|
118
|
-
input = object_fixture('amf0-ref-test.bin')
|
119
|
-
output = RocketAMF.deserialize(input, 0)
|
120
|
-
output.length.should == 2
|
121
|
-
output["0"].should === output["1"]
|
122
|
-
end
|
123
|
-
end
|
15
|
+
RocketAMF.deserialize(input)
|
124
16
|
|
125
|
-
|
126
|
-
it "should update source pos if source is a StringIO object" do
|
127
|
-
input = StringIO.new(object_fixture('amf3-null.bin'))
|
128
|
-
input.pos.should == 0
|
129
|
-
output = RocketAMF.deserialize(input, 3)
|
130
|
-
input.pos.should == 1
|
17
|
+
expect(input.pos).to eq(1)
|
131
18
|
end
|
132
19
|
|
133
|
-
describe
|
134
|
-
it
|
135
|
-
|
136
|
-
output = RocketAMF.deserialize(input, 3)
|
137
|
-
output.should == nil
|
20
|
+
describe 'simple messages' do
|
21
|
+
it 'should deserialize a null' do
|
22
|
+
first_request_eq('amf3-null.bin', nil)
|
138
23
|
end
|
139
24
|
|
140
|
-
it
|
141
|
-
|
142
|
-
output = RocketAMF.deserialize(input, 3)
|
143
|
-
output.should == false
|
25
|
+
it 'should deserialize a false' do
|
26
|
+
first_request_eq('amf3-false.bin', false)
|
144
27
|
end
|
145
28
|
|
146
|
-
it
|
147
|
-
|
148
|
-
output = RocketAMF.deserialize(input, 3)
|
149
|
-
output.should == true
|
29
|
+
it 'should deserialize a true' do
|
30
|
+
first_request_eq('amf3-true.bin', true)
|
150
31
|
end
|
151
32
|
|
152
|
-
it
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
input = object_fixture("amf3-0.bin")
|
158
|
-
output = RocketAMF.deserialize(input, 3)
|
159
|
-
output.should == 0
|
160
|
-
|
161
|
-
input = object_fixture("amf3-min.bin")
|
162
|
-
output = RocketAMF.deserialize(input, 3)
|
163
|
-
output.should == RocketAMF::MIN_INTEGER
|
33
|
+
it 'should deserialize integers' do
|
34
|
+
first_request_eq('amf3-max.bin', RocketAMF::MAX_INTEGER)
|
35
|
+
first_request_eq('amf3-0.bin', 0)
|
36
|
+
first_request_eq('amf3-min.bin', RocketAMF::MIN_INTEGER)
|
164
37
|
end
|
165
38
|
|
166
|
-
it
|
167
|
-
|
168
|
-
|
169
|
-
output.should == RocketAMF::MAX_INTEGER + 1
|
170
|
-
|
171
|
-
input = object_fixture("amf3-large-min.bin")
|
172
|
-
output = RocketAMF.deserialize(input, 3)
|
173
|
-
output.should == RocketAMF::MIN_INTEGER - 1
|
39
|
+
it 'should deserialize large integers' do
|
40
|
+
first_request_eq('amf3-large-max.bin', RocketAMF::MAX_INTEGER + 1.0)
|
41
|
+
first_request_eq('amf3-large-min.bin', RocketAMF::MIN_INTEGER - 1.0)
|
174
42
|
end
|
175
43
|
|
176
|
-
it
|
177
|
-
|
178
|
-
output = RocketAMF.deserialize(input, 3)
|
179
|
-
output.should == 2**1000
|
44
|
+
it 'should deserialize BigNums' do
|
45
|
+
first_request_eq('amf3-bignum.bin', 2.0**1000)
|
180
46
|
end
|
181
47
|
|
182
|
-
it
|
183
|
-
|
184
|
-
output = RocketAMF.deserialize(input, 3)
|
185
|
-
output.should == "String . String"
|
48
|
+
it 'should deserialize a simple string' do
|
49
|
+
first_request_eq('amf3-string.bin', 'String . String')
|
186
50
|
end
|
187
51
|
|
188
|
-
it
|
189
|
-
|
190
|
-
output = RocketAMF.deserialize(input, 3)
|
191
|
-
output.should == "foo"
|
52
|
+
it 'should deserialize a symbol as a string' do
|
53
|
+
first_request_eq('amf3-symbol.bin', 'foo')
|
192
54
|
end
|
193
55
|
|
194
|
-
it
|
195
|
-
|
196
|
-
output = RocketAMF.deserialize(input, 3)
|
197
|
-
output.should == Time.at(0)
|
56
|
+
it 'should deserialize dates' do
|
57
|
+
first_request_eq('amf3-date.bin', Time.at(0))
|
198
58
|
end
|
199
59
|
|
200
|
-
it
|
60
|
+
it 'should deserialize XML' do
|
201
61
|
# XMLDocument tag
|
202
|
-
|
203
|
-
output = RocketAMF.deserialize(input, 3)
|
204
|
-
output.should == '<parent><child prop="test" /></parent>'
|
62
|
+
first_request_eq('amf3-xml-doc.bin', '<parent><child prop="test" /></parent>')
|
205
63
|
|
206
64
|
# XML tag
|
207
|
-
|
208
|
-
output = RocketAMF.deserialize(input, 3)
|
209
|
-
output.should == '<parent><child prop="test"/></parent>'
|
65
|
+
first_request_eq('amf3-xml.bin', '<parent><child prop="test"/></parent>')
|
210
66
|
end
|
211
67
|
end
|
212
68
|
|
213
|
-
describe
|
214
|
-
it
|
215
|
-
|
216
|
-
|
69
|
+
describe 'objects' do
|
70
|
+
it 'should deserialize an unmapped object as a dynamic anonymous object' do
|
71
|
+
|
72
|
+
value =
|
73
|
+
{
|
74
|
+
'property_one' => 'foo',
|
75
|
+
'nil_property' => nil,
|
76
|
+
'another_public_property' => 'a_public_value'
|
77
|
+
}
|
217
78
|
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
}
|
223
|
-
output.should == expected
|
224
|
-
output.type.should == ""
|
79
|
+
request = get_first_request('amf3-dynamic-object.bin')
|
80
|
+
|
81
|
+
expect(request).to match(value)
|
82
|
+
expect(request.type).to eq('')
|
225
83
|
end
|
226
84
|
|
227
|
-
it
|
228
|
-
RocketAMF::
|
85
|
+
it 'should deserialize a mapped object as a mapped ruby class instance' do
|
86
|
+
RocketAMF::CLASS_MAPPER.define { |m| m.map :as => 'org.amf.ASClass', ruby: 'RubyClass' }
|
229
87
|
|
230
|
-
|
231
|
-
output = RocketAMF.deserialize(input, 3)
|
88
|
+
request = get_first_request('amf3-typed-object.bin')
|
232
89
|
|
233
|
-
|
234
|
-
|
235
|
-
|
90
|
+
expect(request).to be_a(RubyClass)
|
91
|
+
expect(request.foo).to eq('bar')
|
92
|
+
expect(request.baz).to eq(nil)
|
236
93
|
end
|
237
94
|
|
238
|
-
it
|
239
|
-
RocketAMF::
|
95
|
+
it 'should deserialize externalizable objects' do
|
96
|
+
RocketAMF::CLASS_MAPPER.define { |m| m.map :as => 'ExternalizableTest', ruby: 'ExternalizableTest' }
|
240
97
|
|
241
|
-
|
242
|
-
output = RocketAMF.deserialize(input, 3)
|
98
|
+
request = get_first_request('amf3-externalizable.bin')
|
243
99
|
|
244
|
-
|
245
|
-
|
246
|
-
|
100
|
+
expect(request.length).to eq(2)
|
101
|
+
expect(request[0].one).to eq(5)
|
102
|
+
expect(request[1].two).to eq(5)
|
247
103
|
end
|
248
104
|
|
249
|
-
it
|
250
|
-
|
251
|
-
output = RocketAMF.deserialize(input, 3)
|
252
|
-
output.should == {'foo' => "bar", 'answer' => 42}
|
105
|
+
it 'should deserialize a hash as a dynamic anonymous object' do
|
106
|
+
first_request_eq('amf3-hash.bin', {'foo' => 'bar', 'answer' => 42})
|
253
107
|
end
|
254
108
|
|
255
|
-
it
|
256
|
-
|
257
|
-
|
258
|
-
output.should == []
|
109
|
+
it 'should deserialize an empty array' do
|
110
|
+
request = get_first_request('amf3-empty-array.bin')
|
111
|
+
expect(request).to match_array([])
|
259
112
|
end
|
260
113
|
|
261
|
-
it
|
262
|
-
|
263
|
-
|
264
|
-
output.should == [1,2,3,4,5]
|
114
|
+
it 'should deserialize an array of primitives' do
|
115
|
+
request = get_first_request('amf3-primitive-array.bin')
|
116
|
+
expect(request).to match_array([1, 2, 3, 4, 5])
|
265
117
|
end
|
266
118
|
|
267
|
-
it
|
268
|
-
|
269
|
-
|
270
|
-
output.should == {0=>"bar1", 1=>"bar2", 2=>"bar3", "asdf"=>"fdsa", "foo"=>"bar", "42"=>"bar"}
|
119
|
+
it 'should deserialize an associative array' do
|
120
|
+
request = get_first_request('amf3-associative-array.bin')
|
121
|
+
expect(request).to match({0 => 'bar1', 1 => 'bar2', 2 => 'bar3', 'asdf' => 'fdsa', 'foo' => 'bar', '42' => 'bar'})
|
271
122
|
end
|
272
123
|
|
273
|
-
it
|
274
|
-
|
275
|
-
output = RocketAMF.deserialize(input, 3)
|
124
|
+
it 'should deserialize an array of mixed objects' do
|
125
|
+
request = get_first_request('amf3-mixed-array.bin')
|
276
126
|
|
277
|
-
h1
|
278
|
-
h2
|
127
|
+
h1 = {'foo_one' => 'bar_one'}
|
128
|
+
h2 = {'foo_two' => ''}
|
279
129
|
so1 = {'foo_three' => 42}
|
280
|
-
|
130
|
+
expect(request).to match_array([h1, h2, so1, {}, [h1, h2, so1], [], 42, '', [], '', {}, 'bar_one', so1])
|
281
131
|
end
|
282
132
|
|
283
|
-
it
|
284
|
-
|
285
|
-
output = RocketAMF.deserialize(input, 3)
|
133
|
+
it 'should deserialize an array collection as an array' do
|
134
|
+
request = get_first_request('amf3-array-collection.bin')
|
286
135
|
|
287
|
-
|
288
|
-
|
136
|
+
expect(request.class).to eq(Array)
|
137
|
+
expect(request).to match_array(%w( foo bar ))
|
289
138
|
end
|
290
139
|
|
291
|
-
it
|
292
|
-
RocketAMF::
|
293
|
-
input = object_fixture('amf3-complex-array-collection.bin')
|
140
|
+
it 'should deserialize a complex set of array collections' do
|
141
|
+
RocketAMF::CLASS_MAPPER.define { |m| m.map :as => 'org.amf.ASClass', ruby: 'RubyClass' }
|
294
142
|
|
295
|
-
|
143
|
+
request = get_first_request('amf3-complex-array-collection.bin')
|
296
144
|
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
145
|
+
expect(request[0]).to match_array(%w( foo bar ))
|
146
|
+
expect(request[1][0]).to be_a(RubyClass)
|
147
|
+
expect(request[1][1]).to be_a(RubyClass)
|
148
|
+
expect(request[2]).to eq(request[1])
|
301
149
|
end
|
302
150
|
|
303
|
-
it
|
304
|
-
|
305
|
-
output = RocketAMF.deserialize(input, 3)
|
151
|
+
it 'should deserialize a byte array' do
|
152
|
+
request = get_first_request('amf3-byte-array.bin')
|
306
153
|
|
307
|
-
|
154
|
+
expect(request).to be_a(StringIO)
|
308
155
|
expected = "\000\003これtest\100"
|
309
|
-
expected.force_encoding(
|
310
|
-
|
156
|
+
expected.force_encoding('ASCII-8BIT') if expected.respond_to?(:force_encoding)
|
157
|
+
expect(request.string).to eq(expected)
|
311
158
|
end
|
312
159
|
|
313
|
-
it
|
314
|
-
|
315
|
-
|
316
|
-
output.should == {}
|
160
|
+
it 'should deserialize an empty dictionary' do
|
161
|
+
request = get_first_request('amf3-empty-dictionary.bin')
|
162
|
+
expect(request).to match({})
|
317
163
|
end
|
318
164
|
|
319
|
-
it
|
320
|
-
|
321
|
-
|
165
|
+
it 'should deserialize a dictionary' do
|
166
|
+
request = get_first_request('amf3-dictionary.bin')
|
167
|
+
|
168
|
+
keys = request.keys
|
169
|
+
expect(keys.length).to eq(2)
|
170
|
+
obj_key, str_key = keys[0].is_a?(RocketAMF::Types::TypedHash) ? [keys[0], keys[1]] : [keys[1], keys[0]]
|
322
171
|
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
output[obj_key].should == "asdf2"
|
328
|
-
str_key.should == "bar"
|
329
|
-
output[str_key].should == "asdf1"
|
172
|
+
expect(obj_key.type).to eq('org.amf.ASClass')
|
173
|
+
expect(request[obj_key]).to eq('asdf2')
|
174
|
+
expect(str_key).to eq('bar')
|
175
|
+
expect(request[str_key]).to eq('asdf1')
|
330
176
|
end
|
331
177
|
|
332
|
-
it
|
333
|
-
|
334
|
-
|
335
|
-
output.should == [4, -20, 12]
|
178
|
+
it 'should deserialize Vector.<int>' do
|
179
|
+
request = get_first_request('amf3-vector-int.bin')
|
180
|
+
expect(request).to match_array([4, -20, 12])
|
336
181
|
end
|
337
182
|
|
338
|
-
it
|
339
|
-
|
340
|
-
|
341
|
-
output.should == [4, 20, 12]
|
183
|
+
it 'should deserialize Vector.<uint>' do
|
184
|
+
request = get_first_request('amf3-vector-uint.bin')
|
185
|
+
expect(request).to match_array([4, 20, 12])
|
342
186
|
end
|
343
187
|
|
344
|
-
it
|
345
|
-
|
346
|
-
output
|
347
|
-
output.should == [4.3, -20.6]
|
188
|
+
it 'should deserialize Vector.<Number>' do
|
189
|
+
output = get_first_request('amf3-vector-double.bin')
|
190
|
+
expect(output).to match_array([4.3, -20.6])
|
348
191
|
end
|
349
192
|
|
350
|
-
it
|
351
|
-
|
352
|
-
|
353
|
-
output[0]['foo'].
|
354
|
-
output[1].type.
|
355
|
-
output[2]['foo'].
|
193
|
+
it 'should deserialize Vector.<Object>' do
|
194
|
+
output = get_first_request('amf3-vector-object.bin')
|
195
|
+
|
196
|
+
expect(output[0]['foo']).to eq('foo')
|
197
|
+
expect(output[1].type).to eq('org.amf.ASClass')
|
198
|
+
expect(output[2]['foo']).to eq('baz')
|
356
199
|
end
|
357
200
|
end
|
358
201
|
|
359
|
-
describe
|
360
|
-
it
|
361
|
-
|
362
|
-
output = RocketAMF.deserialize(input, 3)
|
202
|
+
describe 'and implementing the AMF Spec' do
|
203
|
+
it 'should keep references of duplicate strings' do
|
204
|
+
output = get_first_request('amf3-string-ref.bin')
|
363
205
|
|
364
|
-
foo =
|
365
|
-
bar =
|
366
|
-
output.
|
206
|
+
foo = 'foo'
|
207
|
+
bar = 'str'
|
208
|
+
expect(output).to match_array([foo, bar, foo, bar, foo, {'str' => 'foo'}])
|
367
209
|
end
|
368
210
|
|
369
|
-
it
|
370
|
-
|
371
|
-
output
|
372
|
-
output.should == ["",""]
|
211
|
+
it 'should not reference the empty string' do
|
212
|
+
output = get_first_request('amf3-empty-string-ref.bin')
|
213
|
+
expect(output).to match_array(['', ''])
|
373
214
|
end
|
374
215
|
|
375
|
-
it
|
376
|
-
|
377
|
-
output = RocketAMF.deserialize(input, 3)
|
216
|
+
it 'should keep references of duplicate dates' do
|
217
|
+
output = get_first_request('amf3-date-ref.bin')
|
378
218
|
|
379
|
-
output[0].
|
380
|
-
output[0].
|
219
|
+
expect(output[0]).to eq(Time.at(0))
|
220
|
+
expect(output[0]).to eq(output[1])
|
381
221
|
# Expected object:
|
382
|
-
# [DateTime.parse
|
222
|
+
# [DateTime.parse '1/1/1970', DateTime.parse '1/1/1970']
|
383
223
|
end
|
384
224
|
|
385
|
-
it
|
386
|
-
|
387
|
-
output = RocketAMF.deserialize(input, 3)
|
225
|
+
it 'should keep reference of duplicate objects' do
|
226
|
+
output = get_first_request('amf3-object-ref.bin')
|
388
227
|
|
389
|
-
obj1 = {'foo' =>
|
228
|
+
obj1 = {'foo' => 'bar'}
|
390
229
|
obj2 = {'foo' => obj1['foo']}
|
391
|
-
|
230
|
+
|
231
|
+
expect(output).to match_array([[obj1, obj2], 'bar', [obj1, obj2]])
|
392
232
|
end
|
393
233
|
|
394
|
-
it
|
395
|
-
RocketAMF::
|
234
|
+
it 'should keep reference of duplicate object traits' do
|
235
|
+
RocketAMF::CLASS_MAPPER.define { |m| m.map :as => 'org.amf.ASClass', ruby: 'RubyClass' }
|
396
236
|
|
397
|
-
|
398
|
-
output = RocketAMF.deserialize(input, 3)
|
237
|
+
output = get_first_request('amf3-trait-ref.bin')
|
399
238
|
|
400
|
-
output[0].foo.
|
401
|
-
output[1].foo.
|
239
|
+
expect(output[0].foo).to eq('foo')
|
240
|
+
expect(output[1].foo).to eq('bar')
|
402
241
|
end
|
403
242
|
|
404
|
-
it
|
405
|
-
|
406
|
-
output = RocketAMF.deserialize(input, 3)
|
243
|
+
it 'should keep references of duplicate arrays' do
|
244
|
+
output = get_first_request('amf3-array-ref.bin')
|
407
245
|
|
408
|
-
a = [1,2,3]
|
246
|
+
a = [1, 2, 3]
|
409
247
|
b = %w{ a b c }
|
410
|
-
output.
|
248
|
+
expect(output).to match_array([a, b, a, b])
|
411
249
|
end
|
412
250
|
|
413
|
-
it
|
414
|
-
|
415
|
-
output = RocketAMF.deserialize(input, 3)
|
251
|
+
it 'should not keep references of duplicate empty arrays unless the object_id matches' do
|
252
|
+
output = get_first_request('amf3-empty-array-ref.bin')
|
416
253
|
|
417
254
|
a = []
|
418
255
|
b = []
|
419
|
-
output.
|
256
|
+
expect(output).to match_array([a, b, a, b])
|
420
257
|
end
|
421
258
|
|
422
|
-
it
|
423
|
-
|
424
|
-
|
425
|
-
output.should == ['<parent><child prop="test"/></parent>', '<parent><child prop="test"/></parent>']
|
259
|
+
it 'should keep references of duplicate XML and XMLDocuments' do
|
260
|
+
request = get_first_request('amf3-xml-ref.bin')
|
261
|
+
expect(request).to match_array(['<parent><child prop="test"/></parent>', '<parent><child prop="test"/></parent>'])
|
426
262
|
end
|
427
263
|
|
428
|
-
it
|
429
|
-
|
430
|
-
|
431
|
-
output[0].object_id.
|
432
|
-
output[0].string.
|
264
|
+
it 'should keep references of duplicate byte arrays' do
|
265
|
+
output = get_first_request('amf3-byte-array-ref.bin')
|
266
|
+
|
267
|
+
expect(output[0].object_id).to eq(output[1].object_id)
|
268
|
+
expect(output[0].string).to eq('ASDF')
|
433
269
|
end
|
434
270
|
|
435
|
-
it
|
436
|
-
|
437
|
-
output =
|
271
|
+
it 'should deserialize a deep object graph with circular references' do
|
272
|
+
|
273
|
+
output = get_first_request('amf3-graph-member.bin')
|
438
274
|
|
439
|
-
output['children'][0]['parent'].
|
440
|
-
output['parent'].
|
441
|
-
output['children'].length.
|
275
|
+
expect(output['children'][0]['parent']).to eq(output)
|
276
|
+
expect(output['parent']).to eq(nil)
|
277
|
+
expect(output['children'].length).to eq(2)
|
442
278
|
# Expected object:
|
443
279
|
# parent = Hash.new
|
444
280
|
# child1 = Hash.new
|