rubyamf-ouvrages 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +6 -0
- data/Gemfile +22 -0
- data/README.rdoc +105 -0
- data/Rakefile +21 -0
- data/lib/rubyamf.rb +64 -0
- data/lib/rubyamf/class_mapping.rb +239 -0
- data/lib/rubyamf/configuration.rb +272 -0
- data/lib/rubyamf/envelope.rb +102 -0
- data/lib/rubyamf/fault.rb +31 -0
- data/lib/rubyamf/gateway.png +0 -0
- data/lib/rubyamf/intermediate_object.rb +18 -0
- data/lib/rubyamf/logger.rb +39 -0
- data/lib/rubyamf/model.rb +215 -0
- data/lib/rubyamf/rails/controller.rb +23 -0
- data/lib/rubyamf/rails/model.rb +151 -0
- data/lib/rubyamf/rails/rails2_bootstrap.rb +73 -0
- data/lib/rubyamf/rails/rails3_bootstrap.rb +53 -0
- data/lib/rubyamf/rails/request_processor.rb +90 -0
- data/lib/rubyamf/rails/routing.rb +97 -0
- data/lib/rubyamf/rails/time.rb +6 -0
- data/lib/rubyamf/request_parser.rb +99 -0
- data/lib/rubyamf/test.rb +61 -0
- data/lib/rubyamf/version.rb +3 -0
- data/rubyamf.gemspec +26 -0
- data/spec/class_mapping_spec.rb +147 -0
- data/spec/configuration_spec.rb +90 -0
- data/spec/envelope_spec.rb +106 -0
- data/spec/fixtures/remotingMessage.bin +0 -0
- data/spec/fixtures/requestWithNewCredentials.bin +0 -0
- data/spec/fixtures/requestWithOldCredentials.bin +0 -0
- data/spec/fixtures/rubyamf_config.rb +24 -0
- data/spec/model_spec.rb +281 -0
- data/spec/rails_integration_spec.rb +22 -0
- data/spec/rails_routing_spec.rb +75 -0
- data/spec/request_parser_spec.rb +52 -0
- data/spec/request_processor_spec.rb +119 -0
- data/spec/spec_helper.rb +58 -0
- metadata +103 -0
@@ -0,0 +1,147 @@
|
|
1
|
+
require "spec_helper.rb"
|
2
|
+
|
3
|
+
describe RubyAMF::MappingSet do
|
4
|
+
before :each do
|
5
|
+
@set = RubyAMF::MappingSet.new
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should have default mappings" do
|
9
|
+
@set.get_as_class_name('RocketAMF::Values::RemotingMessage').should == 'flex.messaging.messages.RemotingMessage'
|
10
|
+
@set.get_ruby_class_name('flex.messaging.messages.RemotingMessage').should == 'RocketAMF::Values::RemotingMessage'
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should store serialization attributes by scope" do
|
14
|
+
@set.map :as => 'A', :ruby => 'R', :default_scope => :scope_a, :except => ['a']
|
15
|
+
@set.map :as => 'A', :ruby => 'R', :scope => :scope_b, :except => ['b']
|
16
|
+
|
17
|
+
@set.serialization_config('R').should == {:except => ['a']}
|
18
|
+
@set.serialization_config('R', :scope_b).should == {:except => ['b']}
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should assume default scope if configuring attributes" do
|
22
|
+
@set.map :as => 'A', :ruby => 'R', :except => ['a']
|
23
|
+
|
24
|
+
@set.serialization_config('R').should == {:except => ['a']}
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should update scopes on change" do
|
28
|
+
@set.map :as => 'A', :ruby => 'R', :scope => :default, :only => ['a']
|
29
|
+
@set.map :as => 'A', :ruby => 'R', :scope => :default, :except => ['b']
|
30
|
+
|
31
|
+
@set.serialization_config('R').should == {:except => ['b']}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class UnmappedClass; end
|
36
|
+
class MappingTestClass
|
37
|
+
def initialize
|
38
|
+
@initialized = true
|
39
|
+
end
|
40
|
+
|
41
|
+
def initialized?
|
42
|
+
@initialized
|
43
|
+
end
|
44
|
+
end
|
45
|
+
class MappingModelTestClass < MappingTestClass
|
46
|
+
def rubyamf_init; end
|
47
|
+
end
|
48
|
+
|
49
|
+
describe RubyAMF::ClassMapping do
|
50
|
+
before :each do
|
51
|
+
RubyAMF::ClassMapping.reset
|
52
|
+
@set = RubyAMF::ClassMapping.mappings
|
53
|
+
@mapper = RubyAMF::ClassMapping.new
|
54
|
+
@conf = RubyAMF.configuration = RubyAMF::Configuration.new
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should auto-map class on deserialization correctly" do
|
58
|
+
@conf.auto_class_mapping = true
|
59
|
+
as_name = "com.test.UnmappedClass"
|
60
|
+
@set.get_ruby_class_name(as_name).should == nil
|
61
|
+
obj = @mapper.get_ruby_obj as_name
|
62
|
+
obj.class.should == UnmappedClass
|
63
|
+
@set.get_ruby_class_name(as_name).should == "UnmappedClass"
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should auto-map class on serialization correctly" do
|
67
|
+
@conf.auto_class_mapping = true
|
68
|
+
name = "UnmappedClass"
|
69
|
+
@set.get_as_class_name(name).should == nil
|
70
|
+
@mapper.get_as_class_name(UnmappedClass.new).should == name
|
71
|
+
@set.get_as_class_name(name).should == name
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should translate property case on deserialization correctly" do
|
75
|
+
@conf.translate_case = true
|
76
|
+
props = {'aProperty' => "asdf", 'aMoreComplexProperty' => "asdf"}
|
77
|
+
dynamic_props = {'aDynamicProperty' => "fdsa"}
|
78
|
+
obj = RocketAMF::Values::TypedHash.new("")
|
79
|
+
@mapper.populate_ruby_obj obj, props, dynamic_props
|
80
|
+
obj.should == {'a_property' => "asdf", 'a_more_complex_property' => "asdf", 'a_dynamic_property' => "fdsa"}
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should translate property case on serialization correctly" do
|
84
|
+
@conf.translate_case = true
|
85
|
+
obj = {"a_dynamic_property" => "asdf"}
|
86
|
+
props = @mapper.props_for_serialization(obj)
|
87
|
+
props.should == {"aDynamicProperty" => "asdf"}
|
88
|
+
end
|
89
|
+
|
90
|
+
it "should allow setting hash key type to symbol" do
|
91
|
+
@conf.hash_key_access = :symbol
|
92
|
+
props = {'asdf' => "asdf", 'fdsa' => "fdsa"}
|
93
|
+
obj = RocketAMF::Values::TypedHash.new("")
|
94
|
+
@mapper.populate_ruby_obj obj, props
|
95
|
+
obj.should == {:asdf => "asdf", :fdsa => "fdsa"}
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should return correct class name for IntermediateObject" do
|
99
|
+
obj = RubyAMF::IntermediateObject.new(MappingTestClass.new, {})
|
100
|
+
@set.map :as => "MappingTestClass", :ruby => "MappingTestClass"
|
101
|
+
@mapper.get_as_class_name(obj).should == "MappingTestClass"
|
102
|
+
end
|
103
|
+
|
104
|
+
it "should extract properties correctly for IntermediateObject" do
|
105
|
+
obj = RubyAMF::IntermediateObject.new(MappingTestClass.new, {:only => "asdf"})
|
106
|
+
obj.object.should_receive(:rubyamf_hash).with(obj.options).and_return({"asdf" => "fdsa"})
|
107
|
+
props = @mapper.props_for_serialization(obj)
|
108
|
+
props.should == {"asdf" => "fdsa"}
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should properly extract properties for mapped class" do
|
112
|
+
obj = MappingTestClass.new
|
113
|
+
@set.map :as => "MappingTestClass", :ruby => "MappingTestClass", :only => "asdf"
|
114
|
+
obj.should_receive(:rubyamf_hash).with({:only => "asdf"}).and_return({"asdf" => "fdsa"})
|
115
|
+
props = @mapper.props_for_serialization(obj)
|
116
|
+
props.should == {"asdf" => "fdsa"}
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should not call initialize on rubyamf_init implementors" do
|
120
|
+
@set.map :as => "MappingTestClass", :ruby => "MappingTestClass"
|
121
|
+
@set.map :as => "MappingModelTestClass", :ruby => "MappingModelTestClass"
|
122
|
+
|
123
|
+
obj = @mapper.get_ruby_obj("MappingTestClass")
|
124
|
+
obj.initialized?.should == true
|
125
|
+
|
126
|
+
obj = @mapper.get_ruby_obj("MappingModelTestClass")
|
127
|
+
obj.initialized?.should_not == true
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should skip properties on deserialize that are globally ignored" do
|
131
|
+
obj = MappingModelTestClass.new
|
132
|
+
@conf.ignore_fields = ["asdf"]
|
133
|
+
@set.map :as => "MappingModelTestClass", :ruby => "MappingModelTestClass"
|
134
|
+
|
135
|
+
obj.should_receive(:rubyamf_init).with({:fdsa => "fdsa"}, nil)
|
136
|
+
@mapper.populate_ruby_obj(obj, {:asdf => "asdf", :fdsa => "fdsa"})
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should skip properties on deserialize that are configured to be ignored" do
|
140
|
+
obj = MappingModelTestClass.new
|
141
|
+
@conf.ignore_fields = ["fdsa"]
|
142
|
+
@set.map :as => "MappingModelTestClass", :ruby => "MappingModelTestClass", :ignore_fields => "asdf"
|
143
|
+
|
144
|
+
obj.should_receive(:rubyamf_init).with({:fdsa => "fdsa"}, nil)
|
145
|
+
@mapper.populate_ruby_obj(obj, {:asdf => "asdf", :fdsa => "fdsa"})
|
146
|
+
end
|
147
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
require "spec_helper.rb"
|
2
|
+
|
3
|
+
describe RubyAMF::Configuration do
|
4
|
+
before :each do
|
5
|
+
RubyAMF::ClassMapping.reset
|
6
|
+
@conf = RubyAMF::Configuration.new
|
7
|
+
@legacy_path = File.dirname(__FILE__) + '/fixtures/rubyamf_config.rb'
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should read legacy files without errors" do
|
11
|
+
@conf.load_legacy(@legacy_path)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should properly map blank class mapping" do
|
15
|
+
@conf.load_legacy(@legacy_path)
|
16
|
+
mapset = RubyAMF::ClassMapping.mappings
|
17
|
+
mapset.get_ruby_class_name('Blank').should == 'Blank'
|
18
|
+
mapset.serialization_config('Blank').should == nil
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should properly map attribute setting" do
|
22
|
+
@conf.load_legacy(@legacy_path)
|
23
|
+
mapset = RubyAMF::ClassMapping.mappings
|
24
|
+
mapset.serialization_config('Attribute').should == {:only => ["prop_a", "prop_b"]}
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should properly map association setting" do
|
28
|
+
@conf.load_legacy(@legacy_path)
|
29
|
+
mapset = RubyAMF::ClassMapping.mappings
|
30
|
+
mapset.serialization_config('Association').should == {:include => ["assoc_a", "assoc_b"]}
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should properly map attribute and association setting" do
|
34
|
+
@conf.load_legacy(@legacy_path)
|
35
|
+
mapset = RubyAMF::ClassMapping.mappings
|
36
|
+
mapset.serialization_config('Both').should == {
|
37
|
+
:only => ["prop_a", "prop_b"],
|
38
|
+
:include => ["assoc_a", "assoc_b"]
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should properly map methods setting" do
|
43
|
+
@conf.load_legacy(@legacy_path)
|
44
|
+
mapset = RubyAMF::ClassMapping.mappings
|
45
|
+
mapset.serialization_config('Method').should == {:methods => ["meth_a"]}
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should properly map scoped attributes" do
|
49
|
+
@conf.load_legacy(@legacy_path)
|
50
|
+
mapset = RubyAMF::ClassMapping.mappings
|
51
|
+
mapset.serialization_config('Scoped1', :scope_1).should == {:only => ["prop_a", "prop_b"]}
|
52
|
+
mapset.serialization_config('Scoped1', "scope_2").should == {:only => ["prop_a"]}
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should properly map scoped associations" do
|
56
|
+
@conf.load_legacy(@legacy_path)
|
57
|
+
mapset = RubyAMF::ClassMapping.mappings
|
58
|
+
mapset.serialization_config('Scoped2', :scope_1).should == {:include => ["assoc_a", "assoc_b"]}
|
59
|
+
mapset.serialization_config('Scoped2', :scope_2).should == {:include => ["assoc_a"]}
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should properly map partially scoped settings" do
|
63
|
+
@conf.load_legacy(@legacy_path)
|
64
|
+
mapset = RubyAMF::ClassMapping.mappings
|
65
|
+
mapset.serialization_config('Scoped3', :scope_1).should == {
|
66
|
+
:only => ["prop_a", "prop_b"],
|
67
|
+
:include => ["assoc_a", "assoc_b"]
|
68
|
+
}
|
69
|
+
mapset.serialization_config('Scoped3', :scope_2).should == {
|
70
|
+
:only => ["prop_a"],
|
71
|
+
:include => ["assoc_a", "assoc_b"]
|
72
|
+
}
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should properly map both scoped settings" do
|
76
|
+
@conf.load_legacy(@legacy_path)
|
77
|
+
mapset = RubyAMF::ClassMapping.mappings
|
78
|
+
mapset.serialization_config('Scoped4', :scope_1).should == {
|
79
|
+
:only => ["prop_a", "prop_b"],
|
80
|
+
:include => ["assoc_a", "assoc_b"]
|
81
|
+
}
|
82
|
+
mapset.serialization_config('Scoped4', :scope_2).should == {:only => ["prop_a"]}
|
83
|
+
mapset.serialization_config('Scoped4', :scope_3).should == {:include => ["assoc_a"]}
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should properly store parameter mappings" do
|
87
|
+
@conf.load_legacy(@legacy_path)
|
88
|
+
@conf.param_mappings["Controller#action"].should == [:param_1, :param_2, nil, :param_4]
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,106 @@
|
|
1
|
+
require "spec_helper.rb"
|
2
|
+
|
3
|
+
describe RubyAMF::Envelope do
|
4
|
+
before :each do
|
5
|
+
@envelope = RubyAMF::Envelope.new
|
6
|
+
@logger = mock(RubyAMF::Logger)
|
7
|
+
@logger.stub!("log_error")
|
8
|
+
RubyAMF.configuration = RubyAMF::Configuration.new # Reset configuration
|
9
|
+
end
|
10
|
+
|
11
|
+
def create_envelope fixture
|
12
|
+
data = File.open(File.dirname(__FILE__) + '/fixtures/' + fixture).read
|
13
|
+
data.force_encoding("ASCII-8BIT") if data.respond_to?(:force_encoding)
|
14
|
+
RubyAMF::Envelope.new.populate_from_stream(StringIO.new(data))
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should raise and handle returned exception objects like RubyAMF::Fault" do
|
18
|
+
RubyAMF.should_receive("logger").and_return(@logger)
|
19
|
+
|
20
|
+
res = RubyAMF::Envelope.new
|
21
|
+
req = create_envelope('remotingMessage.bin')
|
22
|
+
res.each_method_call req do |method, args|
|
23
|
+
FaultObject.new('Error in call')
|
24
|
+
end
|
25
|
+
|
26
|
+
res.messages.length.should == 1
|
27
|
+
res.messages[0].data.should be_a(RocketAMF::Values::ErrorMessage)
|
28
|
+
res.messages[0].data.faultString.should == "Error in call"
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should clear backtrace from raised exceptions before serialization" do
|
32
|
+
RubyAMF.should_receive("logger").and_return(@logger)
|
33
|
+
|
34
|
+
res = RubyAMF::Envelope.new
|
35
|
+
req = create_envelope('remotingMessage.bin')
|
36
|
+
res.each_method_call req do |method, args|
|
37
|
+
raise 'Error in call'
|
38
|
+
end
|
39
|
+
|
40
|
+
res.messages.length.should == 1
|
41
|
+
res.messages[0].data.should be_a(RocketAMF::Values::ErrorMessage)
|
42
|
+
res.messages[0].data.faultDetail.should == ""
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should log exceptions in each_method_call handler" do
|
46
|
+
e = Exception.new('Error in call')
|
47
|
+
@logger.should_receive("log_error").with(e).and_return(nil)
|
48
|
+
RubyAMF.should_receive("logger").and_return(@logger)
|
49
|
+
|
50
|
+
res = RubyAMF::Envelope.new
|
51
|
+
req = create_envelope('remotingMessage.bin')
|
52
|
+
res.each_method_call req do |method, args|
|
53
|
+
raise e
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should calculate params hash from configuration" do
|
58
|
+
RubyAMF.configuration.map_params "c", "a", ["param1", :param2]
|
59
|
+
params = @envelope.params_hash "c", "a", ["asdf", "fdsa"]
|
60
|
+
params.should == {"param1" => "asdf", "param2" => "fdsa", 0 => "asdf", 1 => "fdsa"}
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should respect hash_key_access for params hash" do
|
64
|
+
RubyAMF.configuration.hash_key_access = :symbol
|
65
|
+
RubyAMF.configuration.map_params "c", "a", ["param1", :param2]
|
66
|
+
params = @envelope.params_hash "c", "a", ["asdf", "fdsa"]
|
67
|
+
params.should == {:param1 => "asdf", :param2 => "fdsa", 0 => "asdf", 1 => "fdsa"}
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should expose credentials set through NetConnection credentials header" do
|
71
|
+
req = create_envelope('requestWithOldCredentials.bin')
|
72
|
+
req.credentials.should == {'username' => "username", 'password' => "password"}
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should expose credentials set through setRemoteCredentials" do
|
76
|
+
req = create_envelope('requestWithNewCredentials.bin')
|
77
|
+
req.credentials.should == {'username' => "username", 'password' => "password"}
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should return empty credentials if unset" do
|
81
|
+
req = create_envelope('remotingMessage.bin')
|
82
|
+
req.credentials.should == {'username' => nil, 'password' => nil}
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should respect hash_key_access config for credentials" do
|
86
|
+
RubyAMF.configuration.hash_key_access = :symbol
|
87
|
+
req = create_envelope('requestWithOldCredentials.bin')
|
88
|
+
req.credentials.should == {:username => "username", :password => "password"}
|
89
|
+
req = create_envelope('requestWithNewCredentials.bin')
|
90
|
+
req.credentials.should == {:username => "username", :password => "password"}
|
91
|
+
req = create_envelope('remotingMessage.bin')
|
92
|
+
req.credentials.should == {:username => nil, :password => nil}
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should respect translate_case config for credentials" do
|
96
|
+
RubyAMF.configuration.translate_case = true
|
97
|
+
req = create_envelope('requestWithOldCredentials.bin')
|
98
|
+
req.credentials.should == {'username' => "username", 'password' => "password"}
|
99
|
+
req = create_envelope('requestWithNewCredentials.bin')
|
100
|
+
req.messages[0].data.messageId.should == "CA4F7056-317E-FC0C-BEDA-DFFC8B3AA791"
|
101
|
+
req.credentials.should == {'username' => "username", 'password' => "password"}
|
102
|
+
req = create_envelope('remotingMessage.bin')
|
103
|
+
req.messages[0].data.messageId.should == "FE4AF2BC-DD3C-5470-05D8-9971D51FF89D"
|
104
|
+
req.credentials.should == {'username' => nil, 'password' => nil}
|
105
|
+
end
|
106
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'app/configuration'
|
2
|
+
module RubyAMF
|
3
|
+
module Configuration
|
4
|
+
ClassMappings.ignore_fields = ['changed']
|
5
|
+
ClassMappings.translate_case = true
|
6
|
+
ClassMappings.hash_key_access = :string
|
7
|
+
ClassMappings.assume_types = true
|
8
|
+
ClassMappings.use_array_collection = true
|
9
|
+
ClassMappings.check_for_associations = false
|
10
|
+
ParameterMappings.always_add_to_params = false
|
11
|
+
|
12
|
+
ClassMappings.register(:actionscript => 'Blank', :ruby => 'Blank', :type => 'active_record')
|
13
|
+
ClassMappings.register(:actionscript => 'Attribute', :ruby => 'Attribute', :type => 'active_record', :attributes => ["prop_a", "prop_b"])
|
14
|
+
ClassMappings.register(:actionscript => 'Association', :ruby => 'Association', :type => 'active_record', :associations=> ["assoc_a", "assoc_b"])
|
15
|
+
ClassMappings.register(:actionscript => 'Both', :ruby => 'Both', :type => 'active_record', :attributes => ["prop_a", "prop_b"], :associations=> ["assoc_a", "assoc_b"])
|
16
|
+
ClassMappings.register(:actionscript => 'Method', :ruby => 'Method', :methods => ["meth_a"])
|
17
|
+
ClassMappings.register(:actionscript => 'Scoped1', :ruby => 'Scoped1', :attributes => {"scope_1" => ["prop_a", "prop_b"], "scope_2" => ["prop_a"]})
|
18
|
+
ClassMappings.register(:actionscript => 'Scoped2', :ruby => 'Scoped2', :associations => {:scope_1 => ["assoc_a", "assoc_b"], :scope_2 => ["assoc_a"]})
|
19
|
+
ClassMappings.register(:actionscript => 'Scoped3', :ruby => 'Scoped3', :attributes => {"scope_1" => ["prop_a", "prop_b"], "scope_2" => ["prop_a"]}, :associations => ["assoc_a", "assoc_b"])
|
20
|
+
ClassMappings.register(:actionscript => 'Scoped4', :ruby => 'Scoped4', :attributes => {"scope_1" => ["prop_a", "prop_b"], "scope_2" => ["prop_a"]}, :associations => {"scope_1" => ["assoc_a", "assoc_b"], "scope_3" => ["assoc_a"]})
|
21
|
+
|
22
|
+
ParameterMappings.register(:controller => :Controller, :action => :action, :params => {:param_1 => "[0]", :param_2 => "[1]", :param_4 => "[3]"})
|
23
|
+
end
|
24
|
+
end
|
data/spec/model_spec.rb
ADDED
@@ -0,0 +1,281 @@
|
|
1
|
+
require "spec_helper.rb"
|
2
|
+
|
3
|
+
# Include in ActiveRecord because rails bootstrap not triggered in specs
|
4
|
+
require "rubyamf/rails/model"
|
5
|
+
ActiveRecord::Base.send(:include, RubyAMF::Rails::Model)
|
6
|
+
|
7
|
+
describe RubyAMF::Model do
|
8
|
+
before :all do
|
9
|
+
class SimpleModelTestObject
|
10
|
+
include RubyAMF::Model
|
11
|
+
attr_accessor :prop_a, :prop_b
|
12
|
+
def initialize
|
13
|
+
@prop_a = "asdf"
|
14
|
+
@prop_b = "fdsa"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class ModelTestObject
|
19
|
+
include RubyAMF::Model
|
20
|
+
attr_accessor :attributes, :settable_method
|
21
|
+
def initialize
|
22
|
+
@attributes = {"prop_a" => "asdf", "prop_b" => "fdsa"}
|
23
|
+
end
|
24
|
+
def a_method
|
25
|
+
"result"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
p = Parent.create :name => "parent"
|
30
|
+
p.children.create :name => "child 1"
|
31
|
+
p.children.create :name => "child 2"
|
32
|
+
p.home = Home.create :address => "1234 Main St."
|
33
|
+
end
|
34
|
+
|
35
|
+
before :each do
|
36
|
+
RubyAMF::ClassMapper.reset
|
37
|
+
RubyAMF.configuration = RubyAMF::Configuration.new
|
38
|
+
end
|
39
|
+
|
40
|
+
describe 'configuration' do
|
41
|
+
it "should map ruby class to flash class" do
|
42
|
+
ModelTestObject.module_eval do
|
43
|
+
as_class "as"
|
44
|
+
actionscript_class "actionscript"
|
45
|
+
flash_class "flash"
|
46
|
+
end
|
47
|
+
m = RubyAMF::ClassMapper.mappings
|
48
|
+
m.get_as_class_name("ModelTestObject").should == "flash"
|
49
|
+
m.get_ruby_class_name("flash").should == "ModelTestObject"
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should save serialization configs to class mapper" do
|
53
|
+
ModelTestObject.module_eval do
|
54
|
+
as_class "com.test.ASClass"
|
55
|
+
map_amf :only => "prop_a"
|
56
|
+
map_amf :testing, :only => "prop_b"
|
57
|
+
map_amf :default_scope => :asdf, :only => "prop_c"
|
58
|
+
end
|
59
|
+
m = RubyAMF::ClassMapper.mappings
|
60
|
+
m.get_as_class_name("ModelTestObject").should == "com.test.ASClass"
|
61
|
+
m.get_ruby_class_name("com.test.ASClass").should == "ModelTestObject"
|
62
|
+
m.serialization_config("ModelTestObject", :default).should == {:only => "prop_a"}
|
63
|
+
m.serialization_config("ModelTestObject", :testing).should == {:only => "prop_b"}
|
64
|
+
m.serialization_config("ModelTestObject", :asdf).should == {:only => "prop_c"}
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should work with RocketAMF class mapper" do
|
68
|
+
# Swap out class mapper
|
69
|
+
old_mapper = RubyAMF.send(:remove_const, :ClassMapper)
|
70
|
+
RubyAMF.const_set(:ClassMapper, RocketAMF::ClassMapping)
|
71
|
+
|
72
|
+
# Test it
|
73
|
+
ModelTestObject.module_eval do
|
74
|
+
as_class "com.test.ASClass"
|
75
|
+
map_amf :only => "prop_a"
|
76
|
+
map_amf :testing, :only => "prop_b"
|
77
|
+
map_amf :default_scope => :asdf, :only => "prop_c"
|
78
|
+
end
|
79
|
+
m = RubyAMF::ClassMapper.mappings
|
80
|
+
m.get_as_class_name("ModelTestObject").should == "com.test.ASClass"
|
81
|
+
m.get_ruby_class_name("com.test.ASClass").should == "ModelTestObject"
|
82
|
+
|
83
|
+
# Swap old class mapper back in
|
84
|
+
RubyAMF.send(:remove_const, :ClassMapper)
|
85
|
+
RubyAMF.const_set(:ClassMapper, old_mapper)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe 'deserialization' do
|
90
|
+
it "should populate simple object properly from deserialization" do
|
91
|
+
t = SimpleModelTestObject.allocate
|
92
|
+
t.rubyamf_init({:prop_a => "seta", :prop_b => "setb"})
|
93
|
+
t.prop_a.should == "seta"
|
94
|
+
t.prop_b.should == "setb"
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should populate fully-conforming object properly from deserialization" do
|
98
|
+
t = ModelTestObject.allocate
|
99
|
+
t.rubyamf_init({"prop_a" => "seta"}, {"prop_b" => "setb"}) # classmapper would pass symbolic keys - oh well?
|
100
|
+
t.attributes.should == {"prop_a" => "seta", "prop_b" => "setb"}
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should call setters for non-attributes" do
|
104
|
+
t = ModelTestObject.allocate
|
105
|
+
t.rubyamf_init({"prop_a" => "seta", "settable_method" => "meth"})
|
106
|
+
t.attributes.should == {"prop_a" => "seta"}
|
107
|
+
t.settable_method.should == "meth"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe 'serialization' do
|
112
|
+
it "should return an IntermediateObject when to_amf is called" do
|
113
|
+
t = ModelTestObject.new
|
114
|
+
obj = t.to_amf({:only => "prop_a"})
|
115
|
+
obj.should be_a(RubyAMF::IntermediateObject)
|
116
|
+
obj.object.should == t
|
117
|
+
obj.options.should == {:only => "prop_a"}
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should convert simple object to serializable hash" do
|
121
|
+
t = SimpleModelTestObject.new
|
122
|
+
t.rubyamf_hash.should == {"prop_a" => "asdf", "prop_b" => "fdsa"}
|
123
|
+
t.rubyamf_hash(:only => "prop_a").should == {"prop_a" => "asdf"}
|
124
|
+
t.rubyamf_hash(:except => ["prop_a"]).should == {"prop_b" => "fdsa"}
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should convert fully-conforming object to serializable hash" do
|
128
|
+
t = ModelTestObject.new
|
129
|
+
t.rubyamf_hash.should == t.attributes
|
130
|
+
t.rubyamf_hash(:only => "prop_a").should == {"prop_a" => "asdf"}
|
131
|
+
t.rubyamf_hash(:except => ["prop_a"]).should == {"prop_b" => "fdsa"}
|
132
|
+
t.rubyamf_hash(:methods => :a_method).should == {"prop_a" => "asdf", "prop_b" => "fdsa", "a_method" => "result"}
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should properly process generic includes" do
|
136
|
+
t = ModelTestObject.new
|
137
|
+
t.should_receive(:courses).and_return([ModelTestObject.new])
|
138
|
+
h = t.rubyamf_hash(:except => "prop_a", :include => :courses)
|
139
|
+
h.keys.sort.should == ["courses", "prop_b"]
|
140
|
+
h["prop_b"].should == "fdsa"
|
141
|
+
h["courses"].length.should == 1
|
142
|
+
h["courses"][0].class.should == ModelTestObject
|
143
|
+
end
|
144
|
+
|
145
|
+
it "should convert configured includes to IntermediateObjects" do
|
146
|
+
t = ModelTestObject.new
|
147
|
+
t.should_receive(:courses).and_return([ModelTestObject.new])
|
148
|
+
h = t.rubyamf_hash(:except => "prop_a", :include => {:courses => {:except => "prop_b"}})
|
149
|
+
h.keys.sort.should == ["courses", "prop_b"]
|
150
|
+
h["prop_b"].should == "fdsa"
|
151
|
+
h["courses"].length.should == 1
|
152
|
+
h["courses"][0].options.should == {:except => "prop_b"}
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# Need to run these tests against rails 2.3, 3.0, and 3.1
|
157
|
+
describe 'ActiveRecord' do
|
158
|
+
describe 'deserialization' do
|
159
|
+
|
160
|
+
it "should create new records if no id given" do
|
161
|
+
c = Child.allocate
|
162
|
+
c.rubyamf_init({:name => "Foo Bar"})
|
163
|
+
c.name.should == "Foo Bar"
|
164
|
+
c.new_record?.should == true
|
165
|
+
c.changed.should == ["name"]
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should create new records if id is 'empty'" do
|
169
|
+
c = Child.allocate
|
170
|
+
c.rubyamf_init({:id => 0, :name => "Foo Bar"})
|
171
|
+
c.name.should == "Foo Bar"
|
172
|
+
c.new_record?.should == true
|
173
|
+
c.changed.should == ["name"]
|
174
|
+
|
175
|
+
c = Child.allocate
|
176
|
+
c.rubyamf_init({:id => nil, :name => "Foo Bar"})
|
177
|
+
c.name.should == "Foo Bar"
|
178
|
+
c.new_record?.should == true
|
179
|
+
c.changed.should == ["name"]
|
180
|
+
end
|
181
|
+
|
182
|
+
it "should determine whether a record is new if composite PK" do
|
183
|
+
# Create composite child in DB
|
184
|
+
c = CompositeChild.new
|
185
|
+
c.id = [10, "blah"]
|
186
|
+
c.save
|
187
|
+
|
188
|
+
# Check it
|
189
|
+
c = CompositeChild.allocate
|
190
|
+
c.rubyamf_init({:id => 10, :name => "blah"})
|
191
|
+
c.id.should == [10, "blah"]
|
192
|
+
c.new_record?.should == false
|
193
|
+
c.changed.should == []
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should properly initialize 'existing' objects" do
|
197
|
+
c = Child.allocate
|
198
|
+
c.rubyamf_init({:id => 5, :name => "Bar Foo"})
|
199
|
+
c.id.should == 5
|
200
|
+
c.name.should == "Bar Foo"
|
201
|
+
c.new_record?.should == false
|
202
|
+
c.changed.should == ["name"]
|
203
|
+
end
|
204
|
+
|
205
|
+
it "should properly initialize STI objects"
|
206
|
+
|
207
|
+
context "associations" do
|
208
|
+
let(:p) { Parent.allocate }
|
209
|
+
let(:c) { Child.allocate }
|
210
|
+
let(:p_with_associations) { Parent.allocate }
|
211
|
+
|
212
|
+
def create_deserialized_parent_with_associations children=nil, home=nil, save_parent=true
|
213
|
+
p_with_associations.rubyamf_init({:id => p.id, :name => "parent", :children => children, :home => home})
|
214
|
+
p_with_associations.save if save_parent
|
215
|
+
end
|
216
|
+
|
217
|
+
before :each do
|
218
|
+
c.rubyamf_init({:name => "Foo Bar"})
|
219
|
+
p.rubyamf_init({:name => "parent", :children => [c]})
|
220
|
+
p.children.length.should == 1
|
221
|
+
p.save
|
222
|
+
end
|
223
|
+
|
224
|
+
it "should deserialize associations" do
|
225
|
+
p.children[0].parent_id.should == p.id
|
226
|
+
end
|
227
|
+
|
228
|
+
it "should deserialize and not clear empty associations" do
|
229
|
+
create_deserialized_parent_with_associations []
|
230
|
+
p_with_associations.children(true).length.should == 1
|
231
|
+
end
|
232
|
+
|
233
|
+
it "should ignore nil associations" do
|
234
|
+
create_deserialized_parent_with_associations nil
|
235
|
+
p_with_associations.children(true).length.should == 1
|
236
|
+
end
|
237
|
+
|
238
|
+
it "should deserialize and not automatically save associations" do
|
239
|
+
c2 = Child.allocate
|
240
|
+
c2.rubyamf_init({:name => "Foo Bars"})
|
241
|
+
h = Home.allocate
|
242
|
+
h.rubyamf_init(:address => "1234 Here")
|
243
|
+
create_deserialized_parent_with_associations [c2], h, false
|
244
|
+
c2.should be_new_record
|
245
|
+
h.should be_new_record
|
246
|
+
p_with_associations.save
|
247
|
+
c2.should_not be_new_record
|
248
|
+
h.should_not be_new_record
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
describe 'serialization' do
|
254
|
+
it "should support serializing associations" do
|
255
|
+
h = Parent.first.rubyamf_hash(:include => [:children])
|
256
|
+
h["children"].length.should == 2
|
257
|
+
end
|
258
|
+
|
259
|
+
it "should support serializing associations with configurations" do
|
260
|
+
h = Parent.first.rubyamf_hash(:include => {:children => {:only => "name"}})
|
261
|
+
h["children"].length.should == 2
|
262
|
+
end
|
263
|
+
|
264
|
+
it "should support automatically including loaded relations without belongs_to" do
|
265
|
+
# No associations pre-loaded
|
266
|
+
p = Parent.first
|
267
|
+
p.rubyamf_hash.should == {"id" => 1, "name" => "parent"}
|
268
|
+
|
269
|
+
# Force associations to load
|
270
|
+
p.children.to_a
|
271
|
+
p.home
|
272
|
+
|
273
|
+
# Associations should be in hash
|
274
|
+
h = p.rubyamf_hash
|
275
|
+
h["children"].length.should == 2
|
276
|
+
h["children"][0].rubyamf_hash.should == {"id" => 1, "name" => "child 1", "parent_id" => 1}
|
277
|
+
h["home"].should == p.home
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
281
|
+
end
|