rocketamf_pure 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. data/README.rdoc +47 -0
  2. data/Rakefile +9 -0
  3. data/benchmark.rb +73 -0
  4. data/lib/rocketamf.rb +212 -0
  5. data/lib/rocketamf/class_mapping.rb +237 -0
  6. data/lib/rocketamf/constants.rb +46 -0
  7. data/lib/rocketamf/ext.rb +28 -0
  8. data/lib/rocketamf/extensions.rb +22 -0
  9. data/lib/rocketamf/pure.rb +24 -0
  10. data/lib/rocketamf/pure/deserializer.rb +417 -0
  11. data/lib/rocketamf/pure/io_helpers.rb +94 -0
  12. data/lib/rocketamf/pure/remoting.rb +117 -0
  13. data/lib/rocketamf/pure/serializer.rb +474 -0
  14. data/lib/rocketamf/remoting.rb +196 -0
  15. data/lib/rocketamf/values/messages.rb +212 -0
  16. data/lib/rocketamf/values/typed_hash.rb +13 -0
  17. data/lib/rocketamf_pure.rb +1 -0
  18. data/spec/class_mapping_spec.rb +110 -0
  19. data/spec/deserializer_spec.rb +423 -0
  20. data/spec/fast_class_mapping_spec.rb +144 -0
  21. data/spec/fixtures/objects/amf0-boolean.bin +1 -0
  22. data/spec/fixtures/objects/amf0-complex-encoded-string.bin +0 -0
  23. data/spec/fixtures/objects/amf0-date.bin +0 -0
  24. data/spec/fixtures/objects/amf0-ecma-ordinal-array.bin +0 -0
  25. data/spec/fixtures/objects/amf0-hash.bin +0 -0
  26. data/spec/fixtures/objects/amf0-null.bin +1 -0
  27. data/spec/fixtures/objects/amf0-number.bin +0 -0
  28. data/spec/fixtures/objects/amf0-object.bin +0 -0
  29. data/spec/fixtures/objects/amf0-ref-test.bin +0 -0
  30. data/spec/fixtures/objects/amf0-strict-array.bin +0 -0
  31. data/spec/fixtures/objects/amf0-string.bin +0 -0
  32. data/spec/fixtures/objects/amf0-time.bin +0 -0
  33. data/spec/fixtures/objects/amf0-typed-object.bin +0 -0
  34. data/spec/fixtures/objects/amf0-undefined.bin +1 -0
  35. data/spec/fixtures/objects/amf0-untyped-object.bin +0 -0
  36. data/spec/fixtures/objects/amf0-xml-doc.bin +0 -0
  37. data/spec/fixtures/objects/amf3-0.bin +0 -0
  38. data/spec/fixtures/objects/amf3-array-collection.bin +2 -0
  39. data/spec/fixtures/objects/amf3-array-ref.bin +1 -0
  40. data/spec/fixtures/objects/amf3-associative-array.bin +1 -0
  41. data/spec/fixtures/objects/amf3-bigNum.bin +0 -0
  42. data/spec/fixtures/objects/amf3-byte-array-ref.bin +1 -0
  43. data/spec/fixtures/objects/amf3-byte-array.bin +0 -0
  44. data/spec/fixtures/objects/amf3-complex-array-collection.bin +6 -0
  45. data/spec/fixtures/objects/amf3-complex-encoded-string-array.bin +1 -0
  46. data/spec/fixtures/objects/amf3-date-ref.bin +0 -0
  47. data/spec/fixtures/objects/amf3-date.bin +0 -0
  48. data/spec/fixtures/objects/amf3-dictionary.bin +0 -0
  49. data/spec/fixtures/objects/amf3-dynamic-object.bin +2 -0
  50. data/spec/fixtures/objects/amf3-empty-array-ref.bin +1 -0
  51. data/spec/fixtures/objects/amf3-empty-array.bin +1 -0
  52. data/spec/fixtures/objects/amf3-empty-dictionary.bin +0 -0
  53. data/spec/fixtures/objects/amf3-empty-string-ref.bin +1 -0
  54. data/spec/fixtures/objects/amf3-encoded-string-ref.bin +0 -0
  55. data/spec/fixtures/objects/amf3-externalizable.bin +0 -0
  56. data/spec/fixtures/objects/amf3-false.bin +1 -0
  57. data/spec/fixtures/objects/amf3-float.bin +0 -0
  58. data/spec/fixtures/objects/amf3-graph-member.bin +0 -0
  59. data/spec/fixtures/objects/amf3-hash.bin +2 -0
  60. data/spec/fixtures/objects/amf3-large-max.bin +0 -0
  61. data/spec/fixtures/objects/amf3-large-min.bin +0 -0
  62. data/spec/fixtures/objects/amf3-max.bin +1 -0
  63. data/spec/fixtures/objects/amf3-min.bin +0 -0
  64. data/spec/fixtures/objects/amf3-mixed-array.bin +10 -0
  65. data/spec/fixtures/objects/amf3-null.bin +1 -0
  66. data/spec/fixtures/objects/amf3-object-ref.bin +0 -0
  67. data/spec/fixtures/objects/amf3-primitive-array.bin +1 -0
  68. data/spec/fixtures/objects/amf3-string-ref.bin +0 -0
  69. data/spec/fixtures/objects/amf3-string.bin +1 -0
  70. data/spec/fixtures/objects/amf3-symbol.bin +1 -0
  71. data/spec/fixtures/objects/amf3-trait-ref.bin +3 -0
  72. data/spec/fixtures/objects/amf3-true.bin +1 -0
  73. data/spec/fixtures/objects/amf3-typed-object.bin +2 -0
  74. data/spec/fixtures/objects/amf3-xml-doc.bin +1 -0
  75. data/spec/fixtures/objects/amf3-xml-ref.bin +1 -0
  76. data/spec/fixtures/objects/amf3-xml.bin +1 -0
  77. data/spec/fixtures/request/acknowledge-response.bin +0 -0
  78. data/spec/fixtures/request/amf0-error-response.bin +0 -0
  79. data/spec/fixtures/request/blaze-response.bin +0 -0
  80. data/spec/fixtures/request/commandMessage.bin +0 -0
  81. data/spec/fixtures/request/flex-request.bin +0 -0
  82. data/spec/fixtures/request/multiple-simple-request.bin +0 -0
  83. data/spec/fixtures/request/remotingMessage.bin +0 -0
  84. data/spec/fixtures/request/simple-request.bin +0 -0
  85. data/spec/fixtures/request/simple-response.bin +0 -0
  86. data/spec/fixtures/request/unsupportedCommandMessage.bin +0 -0
  87. data/spec/messages_spec.rb +39 -0
  88. data/spec/remoting_spec.rb +196 -0
  89. data/spec/serializer_spec.rb +503 -0
  90. data/spec/spec_helper.rb +55 -0
  91. metadata +148 -0
@@ -0,0 +1 @@
1
+ 
Binary file
Binary file
@@ -0,0 +1 @@
1
+ 
Binary file
@@ -0,0 +1 @@
1
+ 
Binary file
@@ -0,0 +1,2 @@
1
+
2
+ Cflex.messaging.io.ArrayCollection foobar
@@ -0,0 +1 @@
1
+   abc  
@@ -0,0 +1 @@
1
+  asdf fdsafoobar42 bar1 bar2 bar3
@@ -0,0 +1 @@
1
+  ASDF 
@@ -0,0 +1,6 @@
1
+ 
2
+ Cflex.messaging.io.ArrayCollection foobar
3
+  
4
+ #org.amf.ASClassbaz
5
+  asdf
6
+ 
@@ -0,0 +1 @@
1
+ Shift テストUTF テスト
Binary file
@@ -0,0 +1,2 @@
1
+
2
+ /another_public_propertya_public_valuenil_propertyproperty_onefoo
@@ -0,0 +1 @@
1
+     
@@ -0,0 +1 @@
1
+ 
@@ -0,0 +1 @@
1
+ 
@@ -0,0 +1,2 @@
1
+
2
+ 
@@ -0,0 +1 @@
1
+ ����
Binary file
@@ -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 @@
1
+ 
@@ -0,0 +1 @@
1
+ String . String
@@ -0,0 +1 @@
1
+ foo
@@ -0,0 +1,3 @@
1
+ 
2
+ #org.amf.ASClassbazfoo
3
+ bar
@@ -0,0 +1 @@
1
+ 
@@ -0,0 +1,2 @@
1
+
2
+ #org.amf.ASClassbazfoobar
@@ -0,0 +1 @@
1
+ M<parent><child prop="test" /></parent>
@@ -0,0 +1 @@
1
+  K<parent><child prop="test"/></parent> 
@@ -0,0 +1 @@
1
+ K<parent><child prop="test"/></parent>
@@ -0,0 +1,39 @@
1
+ require "spec_helper.rb"
2
+
3
+ describe RocketAMF::Values::AbstractMessage do
4
+ before :each do
5
+ @message = RocketAMF::Values::AbstractMessage.new
6
+ end
7
+
8
+ it "should generate conforming uuids" do
9
+ @message.send(:rand_uuid).should =~ /[A-F0-9]{8}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{12}/i
10
+ end
11
+
12
+ it "should read externalized shortened BlazeDS messages" do
13
+ env = create_envelope('blaze-response.bin')
14
+ msg = env.messages[0].data
15
+ msg.class.name.should == "RocketAMF::Values::AcknowledgeMessageExt"
16
+ msg.clientId.should == "8814a067-fe0d-3a9c-a274-4aaed9bd7b0b"
17
+ msg.body.should =~ /xmlsoap\.org/
18
+ end
19
+ end
20
+
21
+ describe RocketAMF::Values::ErrorMessage do
22
+ before :each do
23
+ @e = Exception.new('Error message')
24
+ @e.set_backtrace(['Backtrace 1', 'Backtrace 2'])
25
+ @message = RocketAMF::Values::ErrorMessage.new(nil, @e)
26
+ end
27
+
28
+ it "should serialize as a hash in AMF0" do
29
+ response = RocketAMF::Envelope.new
30
+ response.messages << RocketAMF::Message.new('1/onStatus', '', @message)
31
+ response.serialize.should == request_fixture('amf0-error-response.bin')
32
+ end
33
+
34
+ it "should extract exception properties correctly" do
35
+ @message.faultCode.should == 'Exception'
36
+ @message.faultString.should == 'Error message'
37
+ @message.faultDetail.should == "Backtrace 1\nBacktrace 2"
38
+ end
39
+ end
@@ -0,0 +1,196 @@
1
+ require "spec_helper.rb"
2
+
3
+ describe RocketAMF::Envelope do
4
+ describe 'deserializer' do
5
+ it "should handle remoting message from remote object" do
6
+ req = create_envelope("remotingMessage.bin")
7
+
8
+ req.headers.length.should == 0
9
+ req.messages.length.should == 1
10
+ message = req.messages[0].data
11
+ message.should be_a(RocketAMF::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
+ req = create_envelope("commandMessage.bin")
18
+
19
+ req.headers.length.should == 0
20
+ req.messages.length.should == 1
21
+ message = req.messages[0].data
22
+ message.should be_a(RocketAMF::Values::CommandMessage)
23
+ message.messageId.should == "7B0ACE15-8D57-6AE5-B9D4-99C2D32C8246"
24
+ message.body.should == {}
25
+ end
26
+ end
27
+
28
+ describe 'request builder' do
29
+ it "should create simple call" do
30
+ req = RocketAMF::Envelope.new
31
+ req.call('TestController.test', 'first_arg', 'second_arg')
32
+
33
+ expected = request_fixture('simple-request.bin')
34
+ req.serialize.should == expected
35
+ end
36
+
37
+ it "should allow multiple simple calls" do
38
+ req = RocketAMF::Envelope.new
39
+ req.call('TestController.test', 'first_arg', 'second_arg')
40
+ req.call('TestController.test2', 'first_arg', 'second_arg')
41
+
42
+ expected = request_fixture('multiple-simple-request.bin')
43
+ req.serialize.should == expected
44
+ end
45
+
46
+ it "should create flex remoting call" do
47
+ req = RocketAMF::Envelope.new :amf_version => 3
48
+ req.call_flex('TestController.test', 'first_arg', 'second_arg')
49
+ req.messages[0].data.timestamp = 0
50
+ req.messages[0].data.messageId = "9D108E33-B591-BE79-210D-F1A72D06B578"
51
+
52
+ expected = request_fixture('flex-request.bin')
53
+ req.serialize.should == expected
54
+ end
55
+
56
+ it "should require AMF version 3 for remoting calls" do
57
+ req = RocketAMF::Envelope.new :amf_version => 0
58
+ lambda {
59
+ req.call_flex('TestController.test')
60
+ }.should raise_error("Cannot use flex remoting calls with AMF0")
61
+ end
62
+
63
+ it "should require all calls be the same type" do
64
+ req = RocketAMF::Envelope.new :amf_version => 0
65
+ lambda {
66
+ req.call('TestController.test')
67
+ req.call_flex('TestController.test')
68
+ }.should raise_error("Cannot use different call types")
69
+ end
70
+ end
71
+
72
+ describe 'serializer' do
73
+ it "should serialize response when converted to string" do
74
+ res = RocketAMF::Envelope.new
75
+ res.should_receive(:serialize).and_return('serialized')
76
+ res.to_s.should == 'serialized'
77
+ end
78
+
79
+ it "should serialize a simple call" do
80
+ res = RocketAMF::Envelope.new :amf_version => 3
81
+ res.messages << RocketAMF::Message.new('/1/onResult', '', 'hello')
82
+
83
+ expected = request_fixture('simple-response.bin')
84
+ res.serialize.should == expected
85
+ end
86
+
87
+ it "should serialize a AcknowledgeMessage response" do
88
+ ak = RocketAMF::Values::AcknowledgeMessage.new
89
+ ak.clientId = "7B0ACE15-8D57-6AE5-B9D4-99C2D32C8246"
90
+ ak.messageId = "7B0ACE15-8D57-6AE5-B9D4-99C2D32C8246"
91
+ ak.timestamp = 0
92
+ res = RocketAMF::Envelope.new :amf_version => 3
93
+ res.messages << RocketAMF::Message.new('/1/onResult', '', ak)
94
+
95
+ expected = request_fixture('acknowledge-response.bin')
96
+ res.serialize.should == expected
97
+ end
98
+ end
99
+
100
+ describe 'message handler' do
101
+ it "should respond to ping command" do
102
+ res = RocketAMF::Envelope.new
103
+ req = create_envelope('commandMessage.bin')
104
+ res.each_method_call req do |method, args|
105
+ nil
106
+ end
107
+
108
+ res.messages.length.should == 1
109
+ res.messages[0].data.should be_a(RocketAMF::Values::AcknowledgeMessage)
110
+ end
111
+
112
+ it "should fail on unsupported command" do
113
+ res = RocketAMF::Envelope.new
114
+ req = create_envelope('unsupportedCommandMessage.bin')
115
+ res.each_method_call req do |method, args|
116
+ nil
117
+ end
118
+
119
+ res.messages.length.should == 1
120
+ res.messages[0].data.should be_a(RocketAMF::Values::ErrorMessage)
121
+ res.messages[0].data.faultString.should == "CommandMessage 10000 not implemented"
122
+ end
123
+
124
+ it "should handle RemotingMessages properly" do
125
+ res = RocketAMF::Envelope.new
126
+ req = create_envelope('remotingMessage.bin')
127
+ res.each_method_call req do |method, args|
128
+ method.should == 'WritesController.save'
129
+ args.should == [true]
130
+ true
131
+ end
132
+
133
+ res.messages.length.should == 1
134
+ res.messages[0].data.should be_a(RocketAMF::Values::AcknowledgeMessage)
135
+ res.messages[0].data.body.should == true
136
+ end
137
+
138
+ it "should catch exceptions properly" do
139
+ res = RocketAMF::Envelope.new
140
+ req = create_envelope('remotingMessage.bin')
141
+ res.each_method_call req do |method, args|
142
+ raise 'Error in call'
143
+ end
144
+
145
+ res.messages.length.should == 1
146
+ res.messages[0].data.should be_a(RocketAMF::Values::ErrorMessage)
147
+ res.messages[0].target_uri.should =~ /onStatus$/
148
+ end
149
+
150
+ it "should not crash if source missing on RemotingMessage" do
151
+ res = RocketAMF::Envelope.new
152
+ req = create_envelope('remotingMessage.bin')
153
+ req.messages[0].data.instance_variable_set("@source", nil)
154
+ lambda {
155
+ res.each_method_call req do |method,args|
156
+ true
157
+ end
158
+ }.should_not raise_error
159
+ end
160
+ end
161
+
162
+ describe 'response parser' do
163
+ it "should return the result of a simple response" do
164
+ req = RocketAMF::Envelope.new
165
+ req.call('TestController.test', 'first_arg', 'second_arg')
166
+ res = RocketAMF::Envelope.new
167
+ res.each_method_call req do |method, args|
168
+ ['a', 'b']
169
+ end
170
+
171
+ res.result.should == ['a', 'b']
172
+ end
173
+
174
+ it "should return the results of multiple simple response in a single request" do
175
+ req = RocketAMF::Envelope.new
176
+ req.call('TestController.test', 'first_arg', 'second_arg')
177
+ req.call('TestController.test2', 'first_arg', 'second_arg')
178
+ res = RocketAMF::Envelope.new
179
+ res.each_method_call req do |method, args|
180
+ ['a', 'b']
181
+ end
182
+
183
+ res.result.should == [['a', 'b'], ['a', 'b']]
184
+ end
185
+
186
+ it "should return the results of a flex response" do
187
+ req = RocketAMF::Envelope.new :amf_version => 3
188
+ req.call_flex('TestController.test', 'first_arg', 'second_arg')
189
+ res = RocketAMF::Envelope.new
190
+ res.each_method_call req do |method, args|
191
+ ['a', 'b']
192
+ end
193
+ res.result.should == ['a', 'b']
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,503 @@
1
+ # encoding: UTF-8
2
+
3
+ require "spec_helper.rb"
4
+ require 'rexml/document'
5
+ require 'bigdecimal'
6
+ require 'rational'
7
+
8
+ describe "when serializing" do
9
+ before :each do
10
+ RocketAMF::ClassMapper.reset
11
+ end
12
+
13
+ it "should raise exception with invalid version number" do
14
+ lambda {
15
+ RocketAMF.serialize("", 5)
16
+ }.should raise_error("unsupported version 5")
17
+ end
18
+
19
+ describe "AMF0" do
20
+ it "should serialize nils" do
21
+ output = RocketAMF.serialize(nil, 0)
22
+ output.should == object_fixture('amf0-null.bin')
23
+ end
24
+
25
+ it "should serialize booleans" do
26
+ output = RocketAMF.serialize(true, 0)
27
+ output.should === object_fixture('amf0-boolean.bin')
28
+ end
29
+
30
+ it "should serialize numbers" do
31
+ output = RocketAMF.serialize(3.5, 0)
32
+ output.should == object_fixture('amf0-number.bin')
33
+ end
34
+
35
+ it "should serialize Numeric conformers" do
36
+ output = RocketAMF.serialize(BigDecimal.new("3.5"), 0)
37
+ output.should == object_fixture('amf0-number.bin')
38
+ end
39
+
40
+ it "should serialize strings" do
41
+ output = RocketAMF.serialize("this is a テスト", 0)
42
+ output.should == object_fixture('amf0-string.bin')
43
+ end
44
+
45
+ it "should serialize frozen strings" do
46
+ output = RocketAMF.serialize("this is a テスト".freeze, 0)
47
+ output.should == object_fixture('amf0-string.bin')
48
+ end
49
+
50
+ it "should serialize arrays" do
51
+ output = RocketAMF.serialize(['a', 'b', 'c', 'd'], 0)
52
+ output.should == object_fixture('amf0-strict-array.bin')
53
+ end
54
+
55
+ it "should serialize references" do
56
+ obj = OtherClass.new
57
+ obj.foo = "baz"
58
+ obj.bar = 3.14
59
+
60
+ output = RocketAMF.serialize({'0' => obj, '1' => obj}, 0)
61
+ output.should == object_fixture('amf0-ref-test.bin')
62
+ end
63
+
64
+ it "should serialize Time objects" do
65
+ output = RocketAMF.serialize(Time.utc(2003, 2, 13, 5), 0)
66
+ output.bytesize.should == 11
67
+ output[0,9].should == object_fixture('amf0-time.bin')[0,9] # Ignore TZ
68
+ end
69
+
70
+ it "should serialize Date objects" do
71
+ output = RocketAMF.serialize(Date.civil(2020, 5, 30), 0)
72
+ output.bytesize.should == 11
73
+ output[0,9].should == object_fixture('amf0-date.bin')[0,9] # Ignore TZ
74
+ end
75
+
76
+ it "should serialize DateTime objects" do
77
+ output = RocketAMF.serialize(DateTime.civil(2003, 2, 13, 5), 0)
78
+ output.bytesize.should == 11
79
+ output[0,9].should == object_fixture('amf0-time.bin')[0,9] # Ignore TZ
80
+ end
81
+
82
+ it "should serialize hashes as objects" do
83
+ output = RocketAMF.serialize({:baz => nil, "foo" => "bar"}, 0)
84
+ output.should == object_fixture('amf0-untyped-object.bin')
85
+ end
86
+
87
+ it "should serialize unmapped objects" do
88
+ obj = RubyClass.new
89
+ obj.foo = "bar"
90
+
91
+ output = RocketAMF.serialize(obj, 0)
92
+ output.should == object_fixture('amf0-untyped-object.bin')
93
+ end
94
+
95
+ it "should serialize mapped objects" do
96
+ obj = RubyClass.new
97
+ obj.foo = "bar"
98
+ RocketAMF::ClassMapper.define {|m| m.map :as => 'org.amf.ASClass', :ruby => 'RubyClass'}
99
+
100
+ output = RocketAMF.serialize(obj, 0)
101
+ output.should == object_fixture('amf0-typed-object.bin')
102
+ end
103
+
104
+ describe "and handling encodings", :if => "".respond_to?(:force_encoding) do
105
+ it "should support multiple encodings" do
106
+ shift_str = "\x53\x68\x69\x66\x74\x20\x83\x65\x83\x58\x83\x67".force_encoding("Shift_JIS") # "Shift テスト"
107
+ utf_str = "\x55\x54\x46\x20\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88".force_encoding("UTF-8") # "UTF テスト"
108
+ output = RocketAMF.serialize({:shift => shift_str, :utf => utf_str, :zed => 5}, 0)
109
+ output.should == object_fixture("amf0-complex-encoded-string.bin")
110
+ end
111
+ end
112
+ end
113
+
114
+ describe "AMF3" do
115
+ describe "simple messages" do
116
+ it "should serialize a null" do
117
+ expected = object_fixture("amf3-null.bin")
118
+ output = RocketAMF.serialize(nil, 3)
119
+ output.should == expected
120
+ end
121
+
122
+ it "should serialize a false" do
123
+ expected = object_fixture("amf3-false.bin")
124
+ output = RocketAMF.serialize(false, 3)
125
+ output.should == expected
126
+ end
127
+
128
+ it "should serialize a true" do
129
+ expected = object_fixture("amf3-true.bin")
130
+ output = RocketAMF.serialize(true, 3)
131
+ output.should == expected
132
+ end
133
+
134
+ it "should serialize integers" do
135
+ expected = object_fixture("amf3-max.bin")
136
+ input = RocketAMF::MAX_INTEGER
137
+ output = RocketAMF.serialize(input, 3)
138
+ output.should == expected
139
+
140
+ expected = object_fixture("amf3-0.bin")
141
+ output = RocketAMF.serialize(0, 3)
142
+ output.should == expected
143
+
144
+ expected = object_fixture("amf3-min.bin")
145
+ input = RocketAMF::MIN_INTEGER
146
+ output = RocketAMF.serialize(input, 3)
147
+ output.should == expected
148
+ end
149
+
150
+ it "should serialize large integers" do
151
+ expected = object_fixture("amf3-large-max.bin")
152
+ input = RocketAMF::MAX_INTEGER + 1
153
+ output = RocketAMF.serialize(input, 3)
154
+ output.should == expected
155
+
156
+ expected = object_fixture("amf3-large-min.bin")
157
+ input = RocketAMF::MIN_INTEGER - 1
158
+ output = RocketAMF.serialize(input, 3)
159
+ output.should == expected
160
+ end
161
+
162
+ it "should serialize floats" do
163
+ expected = object_fixture("amf3-float.bin")
164
+ input = 3.5
165
+ output = RocketAMF.serialize(input, 3)
166
+ output.should == expected
167
+ end
168
+
169
+ it "should serialize BigNums" do
170
+ expected = object_fixture("amf3-bigNum.bin")
171
+ input = 2**1000
172
+ output = RocketAMF.serialize(input, 3)
173
+ output.should == expected
174
+ end
175
+
176
+ it "should serialize float Numeric conformers" do
177
+ expected = object_fixture("amf3-float.bin")
178
+ input = Rational(7, 2) # 3.5
179
+ output = RocketAMF.serialize(input, 3)
180
+ output.should == expected
181
+ end
182
+
183
+ it "should serialize a simple string" do
184
+ expected = object_fixture("amf3-string.bin")
185
+ input = "String . String"
186
+ output = RocketAMF.serialize(input, 3)
187
+ output.should == expected
188
+ end
189
+
190
+ it "should serialize a frozen string" do
191
+ expected = object_fixture("amf3-string.bin")
192
+ input = "String . String".freeze
193
+ output = RocketAMF.serialize(input, 3)
194
+ output.should == expected
195
+ end
196
+
197
+ it "should serialize a symbol as a string" do
198
+ expected = object_fixture("amf3-symbol.bin")
199
+ output = RocketAMF.serialize(:foo, 3)
200
+ output.should == expected
201
+ end
202
+
203
+ it "should serialize Time objects" do
204
+ expected = object_fixture("amf3-date.bin")
205
+ input = Time.utc 1970, 1, 1, 0
206
+ output = RocketAMF.serialize(input, 3)
207
+ output.should == expected
208
+ end
209
+
210
+ it "should serialize Date objects" do
211
+ expected = object_fixture("amf3-date.bin")
212
+ input = Date.civil 1970, 1, 1, 0
213
+ output = RocketAMF.serialize(input, 3)
214
+ output.should == expected
215
+ end
216
+
217
+ it "should serialize DateTime objects" do
218
+ expected = object_fixture("amf3-date.bin")
219
+ input = DateTime.civil 1970, 1, 1, 0
220
+ output = RocketAMF.serialize(input, 3)
221
+ output.should == expected
222
+ end
223
+ end
224
+
225
+ describe "objects" do
226
+ it "should serialize an unmapped object as a dynamic anonymous object" do
227
+ class NonMappedObject
228
+ def another_public_property
229
+ 'a_public_value'
230
+ end
231
+
232
+ attr_accessor :nil_property
233
+ attr_accessor :property_one
234
+ attr_writer :read_only_prop
235
+
236
+ def method_with_arg arg='foo'
237
+ arg
238
+ end
239
+ end
240
+ obj = NonMappedObject.new
241
+ obj.property_one = 'foo'
242
+ obj.nil_property = nil
243
+
244
+ expected = object_fixture("amf3-dynamic-object.bin")
245
+ input = obj
246
+ output = RocketAMF.serialize(input, 3)
247
+ output.should == expected
248
+ end
249
+
250
+ it "should serialize externalizable objects" do
251
+ a = ExternalizableTest.new
252
+ a.one = 5
253
+ a.two = 7
254
+ b = ExternalizableTest.new
255
+ b.one = 13
256
+ b.two = 5
257
+ obj = [a, b]
258
+
259
+ expected = object_fixture("amf3-externalizable.bin")
260
+ input = obj
261
+ output = RocketAMF.serialize(input, 3)
262
+ output.should == expected
263
+ end
264
+
265
+ it "should serialize a hash as a dynamic anonymous object" do
266
+ hash = {}
267
+ hash[:answer] = 42
268
+ hash['foo'] = "bar"
269
+
270
+ expected = object_fixture("amf3-hash.bin")
271
+ input = hash
272
+ output = RocketAMF.serialize(input, 3)
273
+ output.should == expected
274
+ end
275
+
276
+ it "should serialize an empty array" do
277
+ expected = object_fixture("amf3-empty-array.bin")
278
+ input = []
279
+ output = RocketAMF.serialize(input, 3)
280
+ output.should == expected
281
+ end
282
+
283
+ it "should serialize an array of primatives" do
284
+ expected = object_fixture("amf3-primitive-array.bin")
285
+ input = [1, 2, 3, 4, 5]
286
+ output = RocketAMF.serialize(input, 3)
287
+ output.should == expected
288
+ end
289
+
290
+ it "should serialize an array of mixed objects" do
291
+ h1 = {:foo_one => "bar_one"}
292
+ h2 = {:foo_two => ""}
293
+ class SimpleObj
294
+ attr_accessor :foo_three
295
+ end
296
+ so1 = SimpleObj.new
297
+ so1.foo_three = 42
298
+
299
+ expected = object_fixture("amf3-mixed-array.bin")
300
+ input = [h1, h2, so1, {}, [h1, h2, so1], [], 42, "", [], "", {}, "bar_one", so1]
301
+ output = RocketAMF.serialize(input, 3)
302
+ output.should == expected
303
+ end
304
+
305
+ it "should serialize an array as an array collection" do
306
+ expected = object_fixture('amf3-array-collection.bin')
307
+
308
+ # Test global
309
+ RocketAMF::ClassMapper.use_array_collection = true
310
+ input = ["foo", "bar"]
311
+ output = RocketAMF.serialize(input, 3)
312
+ output.should == expected
313
+ RocketAMF::ClassMapper.use_array_collection = false
314
+
315
+ # Test override
316
+ input = ["foo", "bar"]
317
+ input.is_array_collection = true
318
+ output = RocketAMF.serialize(input, 3)
319
+ output.should == expected
320
+ end
321
+
322
+ it "should serialize a complex set of array collections" do
323
+ RocketAMF::ClassMapper.define {|m| m.map :as => 'org.amf.ASClass', :ruby => 'RubyClass'}
324
+ expected = object_fixture('amf3-complex-array-collection.bin')
325
+
326
+ a = ["foo", "bar"]
327
+ a.is_array_collection = true
328
+ obj1 = RubyClass.new
329
+ obj1.foo = "bar"
330
+ def obj1.encode_amf serializer
331
+ serializer.write_object(self, nil, {:class_name => 'org.amf.ASClass', :dynamic => false, :externalizable => false, :members => ["baz", "foo"]})
332
+ end
333
+ obj2 = RubyClass.new
334
+ obj2.foo = "asdf"
335
+ def obj2.encode_amf serializer
336
+ serializer.write_object(self, nil, {:class_name => 'org.amf.ASClass', :dynamic => false, :externalizable => false, :members => ["baz", "foo"]})
337
+ end
338
+ b = [obj1, obj2]
339
+ b.is_array_collection = true
340
+ input = [a, b, b]
341
+
342
+ output = RocketAMF.serialize(input, 3)
343
+ output.should == expected
344
+ end
345
+
346
+ it "should serialize a byte array" do
347
+ expected = object_fixture("amf3-byte-array.bin")
348
+ str = "\000\003これtest\100"
349
+ str.force_encoding("ASCII-8BIT") if str.respond_to?(:force_encoding)
350
+ input = StringIO.new(str)
351
+ output = RocketAMF.serialize(input, 3)
352
+ output.should == expected
353
+ end
354
+ end
355
+
356
+ describe "and implementing the AMF Spec" do
357
+ it "should keep references of duplicate strings" do
358
+ class StringCarrier
359
+ attr_accessor :str
360
+ end
361
+ foo = "foo"
362
+ bar = "str"
363
+ sc = StringCarrier.new
364
+ sc.str = foo
365
+
366
+ expected = object_fixture("amf3-string-ref.bin")
367
+ input = [foo, bar, foo, bar, foo, sc]
368
+ output = RocketAMF.serialize(input, 3)
369
+ output.should == expected
370
+ end
371
+
372
+ it "should not reference the empty string" do
373
+ expected = object_fixture("amf3-empty-string-ref.bin")
374
+ input = ""
375
+ output = RocketAMF.serialize([input,input], 3)
376
+ output.should == expected
377
+ end
378
+
379
+ it "should keep references of duplicate dates" do
380
+ expected = object_fixture("amf3-date-ref.bin")
381
+ input = Time.utc 1970, 1, 1, 0
382
+ output = RocketAMF.serialize([input,input], 3)
383
+ output.should == expected
384
+ end
385
+
386
+ it "should keep reference of duplicate objects" do
387
+ class SimpleReferenceableObj
388
+ attr_accessor :foo
389
+ end
390
+ obj1 = SimpleReferenceableObj.new
391
+ obj1.foo = :bar
392
+ obj2 = SimpleReferenceableObj.new
393
+ obj2.foo = obj1.foo
394
+
395
+ expected = object_fixture("amf3-object-ref.bin")
396
+ input = [[obj1, obj2], "bar", [obj1, obj2]]
397
+ output = RocketAMF.serialize(input, 3)
398
+ output.should == expected
399
+ end
400
+
401
+ it "should keep reference of duplicate object traits" do
402
+ obj1 = RubyClass.new
403
+ obj1.foo = "foo"
404
+ def obj1.encode_amf serializer
405
+ serializer.write_object(self, nil, {:class_name => 'org.amf.ASClass', :dynamic => false, :externalizable => false, :members => ["baz", "foo"]})
406
+ end
407
+ obj2 = RubyClass.new
408
+ obj2.foo = "bar"
409
+ def obj2.encode_amf serializer
410
+ serializer.write_object(self, nil, {:class_name => 'org.amf.ASClass', :dynamic => false, :externalizable => false, :members => ["baz", "foo"]})
411
+ end
412
+ input = [obj1, obj2]
413
+
414
+ expected = object_fixture("amf3-trait-ref.bin")
415
+ output = RocketAMF.serialize(input, 3)
416
+ output.should == expected
417
+ end
418
+
419
+ it "should keep references of duplicate arrays" do
420
+ a = [1,2,3]
421
+ b = %w{ a b c }
422
+
423
+ expected = object_fixture("amf3-array-ref.bin")
424
+ input = [a, b, a, b]
425
+ output = RocketAMF.serialize(input, 3)
426
+ output.should == expected
427
+ end
428
+
429
+ it "should not keep references of duplicate empty arrays unless the object_id matches" do
430
+ a = []
431
+ b = []
432
+ a.should == b
433
+ a.object_id.should_not == b.object_id
434
+
435
+ expected = object_fixture("amf3-empty-array-ref.bin")
436
+ input = [a,b,a,b]
437
+ output = RocketAMF.serialize(input, 3)
438
+ output.should == expected
439
+ end
440
+
441
+ it "should keep references of duplicate byte arrays" do
442
+ b = StringIO.new "ASDF"
443
+
444
+ expected = object_fixture("amf3-byte-array-ref.bin")
445
+ input = [b, b]
446
+ output = RocketAMF.serialize(input, 3)
447
+ output.should == expected
448
+ end
449
+
450
+ it "should serialize a deep object graph with circular references" do
451
+ class GraphMember
452
+ attr_accessor :children
453
+ attr_accessor :parent
454
+
455
+ def initialize
456
+ self.children = []
457
+ end
458
+
459
+ def add_child child
460
+ children << child
461
+ child.parent = self
462
+ child
463
+ end
464
+ end
465
+
466
+ parent = GraphMember.new
467
+ level_1_child_1 = parent.add_child GraphMember.new
468
+ level_1_child_2 = parent.add_child GraphMember.new
469
+
470
+ expected = object_fixture("amf3-graph-member.bin")
471
+ input = parent
472
+ output = RocketAMF.serialize(input, 3)
473
+ output.should == expected
474
+ end
475
+ end
476
+
477
+ describe "and handling encodings", :if => "".respond_to?(:force_encoding) do
478
+ it "should support multiple encodings" do
479
+ shift_str = "\x53\x68\x69\x66\x74\x20\x83\x65\x83\x58\x83\x67".force_encoding("Shift_JIS") # "Shift テスト"
480
+ utf_str = "\x55\x54\x46\x20\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88".force_encoding("UTF-8") # "UTF テスト"
481
+ output = RocketAMF.serialize([5, shift_str, utf_str, 5], 3)
482
+ output.should == object_fixture("amf3-complex-encoded-string-array.bin")
483
+ end
484
+
485
+ it "should keep references of duplicate strings with different encodings" do
486
+ # String is "this is a テスト"
487
+ shift_str = "\x74\x68\x69\x73\x20\x69\x73\x20\x61\x20\x83\x65\x83\x58\x83\x67".force_encoding("Shift_JIS")
488
+ utf_str = "\x74\x68\x69\x73\x20\x69\x73\x20\x61\x20\xe3\x83\x86\xe3\x82\xb9\xe3\x83\x88".force_encoding("UTF-8")
489
+
490
+ expected = object_fixture("amf3-encoded-string-ref.bin")
491
+ output = RocketAMF.serialize([shift_str, utf_str], 3)
492
+ output.should == expected
493
+ end
494
+
495
+ it "should handle inappropriate UTF-8 characters in byte arrays" do
496
+ str = "\xff\xff\xff".force_encoding("ASCII-8BIT")
497
+ str.freeze # For added amusement
498
+ output = RocketAMF.serialize(StringIO.new(str), 3)
499
+ output.should == "\x0c\x07\xff\xff\xff".force_encoding("ASCII-8BIT")
500
+ end
501
+ end
502
+ end
503
+ end