rubyamf-ouvrages 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.
- 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
|