ardm 0.0.1 → 0.1.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 +5 -13
- data/Gemfile +1 -2
- data/LICENSE +2 -2
- data/README.md +72 -16
- data/ardm.gemspec +1 -0
- data/lib/ardm.rb +2 -1
- data/lib/ardm/active_record.rb +8 -1
- data/lib/ardm/active_record/associations.rb +33 -4
- data/lib/ardm/active_record/base.rb +2 -0
- data/lib/ardm/active_record/collection.rb +5 -0
- data/lib/ardm/active_record/data_mapper_constant.rb +1 -0
- data/lib/ardm/active_record/data_mapper_constant_proxy.rb +24 -0
- data/lib/ardm/active_record/finalize.rb +18 -0
- data/lib/ardm/active_record/predicate_builder/array_handler.rb +10 -16
- data/lib/ardm/active_record/predicate_builder/rails3.rb +42 -15
- data/lib/ardm/active_record/predicate_builder/rails4.rb +39 -13
- data/lib/ardm/active_record/property.rb +24 -12
- data/lib/ardm/active_record/query.rb +9 -18
- data/lib/ardm/active_record/record.rb +54 -11
- data/lib/ardm/active_record/relation.rb +36 -6
- data/lib/ardm/active_record/repository.rb +6 -2
- data/lib/ardm/data_mapper.rb +2 -0
- data/lib/ardm/data_mapper/record.rb +3 -9
- data/lib/ardm/version.rb +1 -1
- data/spec/ardm/datamapper_constants_spec.rb +31 -0
- data/spec/fixtures/article.rb +2 -0
- data/spec/integration/api_key_spec.rb +3 -3
- data/spec/integration/bcrypt_hash_spec.rb +7 -7
- data/spec/integration/comma_separated_list_spec.rb +11 -11
- data/spec/integration/dirty_minder_spec.rb +23 -39
- data/spec/integration/enum_spec.rb +11 -11
- data/spec/integration/epoch_time_spec.rb +6 -6
- data/spec/integration/file_path_spec.rb +23 -23
- data/spec/integration/flag_spec.rb +11 -13
- data/spec/integration/ip_address_spec.rb +15 -15
- data/spec/integration/json_spec.rb +7 -7
- data/spec/integration/slug_spec.rb +6 -6
- data/spec/integration/uri_spec.rb +11 -11
- data/spec/integration/uuid_spec.rb +16 -16
- data/spec/integration/yaml_spec.rb +8 -8
- data/spec/public/model_spec.rb +193 -0
- data/spec/public/property/binary_spec.rb +4 -4
- data/spec/public/property/boolean_spec.rb +3 -3
- data/spec/public/property/class_spec.rb +2 -2
- data/spec/public/property/date_spec.rb +2 -2
- data/spec/public/property/date_time_spec.rb +2 -2
- data/spec/public/property/decimal_spec.rb +2 -2
- data/spec/public/property/discriminator_spec.rb +21 -20
- data/spec/public/property/float_spec.rb +2 -2
- data/spec/public/property/integer_spec.rb +2 -2
- data/spec/public/property/object_spec.rb +14 -13
- data/spec/public/property/serial_spec.rb +2 -2
- data/spec/public/property/string_spec.rb +2 -2
- data/spec/public/property/text_spec.rb +2 -2
- data/spec/public/property/time_spec.rb +2 -2
- data/spec/public/property_spec.rb +44 -48
- data/spec/public/resource_spec.rb +278 -0
- data/spec/schema.rb +33 -4
- data/spec/semipublic/property/boolean_spec.rb +5 -5
- data/spec/semipublic/property/class_spec.rb +3 -3
- data/spec/semipublic/property/date_spec.rb +8 -8
- data/spec/semipublic/property/date_time_spec.rb +9 -9
- data/spec/semipublic/property/decimal_spec.rb +16 -16
- data/spec/semipublic/property/float_spec.rb +16 -16
- data/spec/semipublic/property/integer_spec.rb +16 -16
- data/spec/semipublic/property/lookup_spec.rb +4 -4
- data/spec/semipublic/property/text_spec.rb +2 -2
- data/spec/semipublic/property/time_spec.rb +10 -10
- data/spec/semipublic/property_spec.rb +4 -4
- data/spec/shared/finder_shared_spec.rb +1151 -0
- data/spec/shared/flags_shared_spec.rb +6 -6
- data/spec/shared/identity_function_group.rb +1 -1
- data/spec/shared/public_property_spec.rb +26 -25
- data/spec/shared/resource_spec.rb +1218 -0
- data/spec/shared/semipublic_property_spec.rb +23 -22
- data/spec/spec_helper.rb +17 -0
- data/spec/unit/bcrypt_hash_spec.rb +15 -15
- data/spec/unit/csv_spec.rb +11 -11
- data/spec/unit/dirty_minder_spec.rb +3 -5
- data/spec/unit/enum_spec.rb +17 -17
- data/spec/unit/epoch_time_spec.rb +8 -8
- data/spec/unit/file_path_spec.rb +9 -9
- data/spec/unit/flag_spec.rb +9 -9
- data/spec/unit/ip_address_spec.rb +9 -9
- data/spec/unit/json_spec.rb +11 -11
- data/spec/unit/paranoid_boolean_spec.rb +19 -17
- data/spec/unit/paranoid_datetime_spec.rb +21 -19
- data/spec/unit/regexp_spec.rb +4 -4
- data/spec/unit/uri_spec.rb +8 -8
- data/spec/unit/yaml_spec.rb +9 -9
- metadata +35 -27
- data/lib/ardm/active_record/not_found.rb +0 -7
- data/lib/ardm/data_mapper/not_found.rb +0 -5
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
shared_examples "A property with flags" do
|
2
2
|
before do
|
3
3
|
%w[ @property_klass ].each do |ivar|
|
4
4
|
raise "+#{ivar}+ should be defined in before block" unless instance_variable_defined?(ivar)
|
@@ -14,23 +14,23 @@ share_examples_for "A property with flags" do
|
|
14
14
|
|
15
15
|
describe ".generated_classes" do
|
16
16
|
it "should cache the generated class" do
|
17
|
-
@property_klass.generated_classes[@flags].
|
17
|
+
expect(@property_klass.generated_classes[@flags]).not_to be_nil
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
21
|
it "should include :flags in accepted_options" do
|
22
|
-
@property_klass.accepted_options.
|
22
|
+
expect(@property_klass.accepted_options).to include(:flags)
|
23
23
|
end
|
24
24
|
|
25
25
|
it "should respond to :generated_classes" do
|
26
|
-
@property_klass.
|
26
|
+
expect(@property_klass).to respond_to(:generated_classes)
|
27
27
|
end
|
28
28
|
|
29
29
|
it "should respond to :flag_map" do
|
30
|
-
@property.
|
30
|
+
expect(@property).to respond_to(:flag_map)
|
31
31
|
end
|
32
32
|
|
33
33
|
it "should be custom" do
|
34
|
-
@property.custom
|
34
|
+
expect(@property.custom?).to be(true)
|
35
35
|
end
|
36
36
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
shared_examples 'A public Property' do
|
2
2
|
before do
|
3
3
|
%w[ @type @load_as @name @value @other_value ].each do |ivar|
|
4
4
|
raise "+#{ivar}+ should be defined in before block" unless instance_variable_defined?(ivar)
|
@@ -8,6 +8,7 @@ share_examples_for 'A public Property' do
|
|
8
8
|
class Article < Ardm::Record
|
9
9
|
self.table_name = "articles"
|
10
10
|
property :id, Serial
|
11
|
+
timestamps :at
|
11
12
|
end
|
12
13
|
end
|
13
14
|
|
@@ -49,7 +50,7 @@ share_examples_for 'A public Property' do
|
|
49
50
|
end
|
50
51
|
|
51
52
|
it "should not override the child's type setting" do
|
52
|
-
@child_subtype.default.
|
53
|
+
expect(@child_subtype.default).to eql(nil)
|
53
54
|
end
|
54
55
|
end
|
55
56
|
end
|
@@ -63,15 +64,15 @@ share_examples_for 'A public Property' do
|
|
63
64
|
describe "when provided :foo, :bar" do
|
64
65
|
it "should add new options" do
|
65
66
|
[@type, @subtype].each do |type|
|
66
|
-
type.accepted_options.include?(:foo).
|
67
|
-
type.accepted_options.include?(:bar).
|
67
|
+
expect(type.accepted_options.include?(:foo)).to be(true)
|
68
|
+
expect(type.accepted_options.include?(:bar)).to be(true)
|
68
69
|
end
|
69
70
|
end
|
70
71
|
|
71
72
|
it "should create predefined option setters" do
|
72
73
|
[@type, @subtype].each do |type|
|
73
|
-
type.
|
74
|
-
type.
|
74
|
+
expect(type).to respond_to(:foo)
|
75
|
+
expect(type).to respond_to(:bar)
|
75
76
|
end
|
76
77
|
end
|
77
78
|
|
@@ -83,13 +84,13 @@ share_examples_for 'A public Property' do
|
|
83
84
|
end
|
84
85
|
|
85
86
|
it "should set the pre-defined option values" do
|
86
|
-
@property.options[:foo].
|
87
|
-
@property.options[:bar].
|
87
|
+
expect(@property.options[:foo]).to eq(true)
|
88
|
+
expect(@property.options[:bar]).to eq(1)
|
88
89
|
end
|
89
90
|
|
90
91
|
it "should ask the superclass for the value if unknown" do
|
91
|
-
@subtype.foo.
|
92
|
-
@subtype.bar.
|
92
|
+
expect(@subtype.foo).to eq(true)
|
93
|
+
expect(@subtype.bar).to eq(1)
|
93
94
|
end
|
94
95
|
end
|
95
96
|
end
|
@@ -97,20 +98,20 @@ share_examples_for 'A public Property' do
|
|
97
98
|
|
98
99
|
describe ".descendants" do
|
99
100
|
it "should include the sub-type" do
|
100
|
-
@type.descendants.include?(SubType).
|
101
|
+
expect(@type.descendants.include?(SubType)).to be(true)
|
101
102
|
end
|
102
103
|
end
|
103
104
|
|
104
105
|
describe ".load_as" do
|
105
106
|
it "should return the load_as" do
|
106
107
|
[@type, @subtype].each do |type|
|
107
|
-
type.load_as.
|
108
|
+
expect(type.load_as).to be(@load_as)
|
108
109
|
end
|
109
110
|
end
|
110
111
|
|
111
112
|
it "should change the load_as class" do
|
112
113
|
@subtype.load_as Object
|
113
|
-
@subtype.load_as.
|
114
|
+
expect(@subtype.load_as).to be(Object)
|
114
115
|
end
|
115
116
|
end
|
116
117
|
end
|
@@ -124,16 +125,16 @@ share_examples_for 'A public Property' do
|
|
124
125
|
end
|
125
126
|
|
126
127
|
it "should return #{value}" do
|
127
|
-
@property.send(method).
|
128
|
+
expect(@property.send(method)).to be(value)
|
128
129
|
end
|
129
130
|
end
|
130
131
|
end
|
131
132
|
|
132
133
|
describe "when created with :#{opt} => true and :required => true" do
|
133
134
|
it "should fail with ArgumentError" do
|
134
|
-
|
135
|
+
expect {
|
135
136
|
@property = @type.new(@model, @name, @options.merge(opt => true, :required => true))
|
136
|
-
}.
|
137
|
+
}.to raise_error(ArgumentError,
|
137
138
|
"options[:required] cannot be mixed with :allow_nil or :allow_blank")
|
138
139
|
end
|
139
140
|
end
|
@@ -150,7 +151,7 @@ share_examples_for 'A public Property' do
|
|
150
151
|
end
|
151
152
|
|
152
153
|
it "should return #{value}" do
|
153
|
-
@property.send(method).
|
154
|
+
expect(@property.send(method)).to be(value)
|
154
155
|
end
|
155
156
|
end
|
156
157
|
end
|
@@ -164,7 +165,7 @@ share_examples_for 'A public Property' do
|
|
164
165
|
end
|
165
166
|
|
166
167
|
it "should return true" do
|
167
|
-
@property.lazy
|
168
|
+
expect(@property.lazy?).to be(true)
|
168
169
|
end
|
169
170
|
end
|
170
171
|
|
@@ -174,7 +175,7 @@ share_examples_for 'A public Property' do
|
|
174
175
|
end
|
175
176
|
|
176
177
|
it "should return false" do
|
177
|
-
@property.lazy
|
178
|
+
expect(@property.lazy?).to be(false)
|
178
179
|
end
|
179
180
|
end
|
180
181
|
end
|
@@ -187,19 +188,19 @@ share_examples_for 'A public Property' do
|
|
187
188
|
context 'when provided the property class' do
|
188
189
|
let(:klass) { @type }
|
189
190
|
|
190
|
-
it {
|
191
|
+
it { is_expected.to be(true) }
|
191
192
|
end
|
192
193
|
|
193
194
|
context 'when provided the property superclass' do
|
194
195
|
let(:klass) { @type.superclass }
|
195
196
|
|
196
|
-
it {
|
197
|
+
it { is_expected.to be(false) }
|
197
198
|
end
|
198
199
|
|
199
200
|
context 'when provided the Ardm::Property class' do
|
200
201
|
let(:klass) { Ardm::Property }
|
201
202
|
|
202
|
-
it {
|
203
|
+
it { is_expected.to be(false) }
|
203
204
|
end
|
204
205
|
end
|
205
206
|
|
@@ -211,19 +212,19 @@ share_examples_for 'A public Property' do
|
|
211
212
|
context 'when provided the property class' do
|
212
213
|
let(:klass) { @type }
|
213
214
|
|
214
|
-
it {
|
215
|
+
it { is_expected.to be(true) }
|
215
216
|
end
|
216
217
|
|
217
218
|
context 'when provided the property superclass' do
|
218
219
|
let(:klass) { @type.superclass }
|
219
220
|
|
220
|
-
it {
|
221
|
+
it { is_expected.to be(true) }
|
221
222
|
end
|
222
223
|
|
223
224
|
context 'when provided the Ardm::Property class' do
|
224
225
|
let(:klass) { Ardm::Property }
|
225
226
|
|
226
|
-
it {
|
227
|
+
it { is_expected.to be(true) }
|
227
228
|
end
|
228
229
|
end
|
229
230
|
end
|
@@ -0,0 +1,1218 @@
|
|
1
|
+
shared_examples 'A public Resource' do
|
2
|
+
before :all do
|
3
|
+
@no_join = defined?(Ardm::Adapters::InMemoryAdapter) && @adapter.kind_of?(Ardm::Adapters::InMemoryAdapter) ||
|
4
|
+
defined?(Ardm::Adapters::YamlAdapter) && @adapter.kind_of?(Ardm::Adapters::YamlAdapter)
|
5
|
+
|
6
|
+
relationship = @user_model.relationships[:referrer]
|
7
|
+
@one_to_one_through = relationship.kind_of?(Ardm::Associations::OneToOne::Relationship) && relationship.respond_to?(:through)
|
8
|
+
|
9
|
+
@skip = @no_join && @one_to_one_through
|
10
|
+
end
|
11
|
+
|
12
|
+
before :all do
|
13
|
+
unless @skip
|
14
|
+
%w[ @user_model @user @comment_model ].each do |ivar|
|
15
|
+
raise "+#{ivar}+ should be defined in before block" unless instance_variable_get(ivar)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
before do
|
21
|
+
skip if @skip
|
22
|
+
end
|
23
|
+
|
24
|
+
[ :==, :=== ].each do |method|
|
25
|
+
it { expect(@user).to respond_to(method) }
|
26
|
+
|
27
|
+
describe "##{method}" do
|
28
|
+
describe 'when comparing to the same resource' do
|
29
|
+
before :all do
|
30
|
+
@other = @user
|
31
|
+
@return = @user.__send__(method, @other)
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should return true' do
|
35
|
+
expect(@return).to be(true)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'when comparing to an resource that does not respond to resource methods' do
|
40
|
+
before :all do
|
41
|
+
@other = Object.new
|
42
|
+
@return = @user.__send__(method, @other)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should return false' do
|
46
|
+
expect(@return).to be(false)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe 'when comparing to a resource with the same properties, but the model is a subclass' do
|
51
|
+
before :all do
|
52
|
+
rescue_if @skip do
|
53
|
+
@other = @author_model.new(@user.attributes)
|
54
|
+
@return = @user.__send__(method, @other)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should return true' do
|
59
|
+
expect(@return).to be(true)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'when comparing to a resource with the same repository, key and neither self or the other resource is dirty' do
|
64
|
+
before :all do
|
65
|
+
rescue_if @skip do
|
66
|
+
@other = @user_model.get(*@user.key)
|
67
|
+
@return = @user.__send__(method, @other)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should return true' do
|
72
|
+
expect(@return).to be(true)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe 'when comparing to a resource with the same repository, key but either self or the other resource is dirty' do
|
77
|
+
before :all do
|
78
|
+
rescue_if @skip do
|
79
|
+
@user.age = 20
|
80
|
+
@other = @user_model.get(*@user.key)
|
81
|
+
@return = @user.__send__(method, @other)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should return false' do
|
86
|
+
expect(@return).to be(false)
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe 'when comparing to a resource with the same properties' do
|
91
|
+
before :all do
|
92
|
+
rescue_if @skip do
|
93
|
+
@other = @user_model.new(@user.attributes)
|
94
|
+
@return = @user.__send__(method, @other)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should return true' do
|
99
|
+
expect(@return).to be(true)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
with_alternate_adapter do
|
104
|
+
before :all do
|
105
|
+
if @user_model.respond_to?(:auto_migrate!)
|
106
|
+
# force the user model to be available in the alternate repository
|
107
|
+
@user_model.auto_migrate!(@adapter.name)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe 'when comparing to a resource with a different repository, but the same properties' do
|
112
|
+
before :all do
|
113
|
+
rescue_if @skip do
|
114
|
+
@other = @repository.scope { @user_model.create(@user.attributes) }
|
115
|
+
@return = @user.__send__(method, @other)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'should return false' do
|
120
|
+
expect(@return).to be(false)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
it { expect(@user).to respond_to(:<=>) }
|
128
|
+
|
129
|
+
describe '#<=>' do
|
130
|
+
describe 'when the default order properties are equal with another resource' do
|
131
|
+
before :all do
|
132
|
+
rescue_if @skip && RUBY_VERSION < '1.9.2' do
|
133
|
+
@other = @user_model.new(:name => 'dbussink')
|
134
|
+
@return = @user <=> @other
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'should return 0' do
|
139
|
+
expect(@return).to eq(0)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe 'when the default order property values are sorted before another resource' do
|
144
|
+
before :all do
|
145
|
+
rescue_if @skip && RUBY_VERSION < '1.9.2' do
|
146
|
+
@other = @user_model.new(:name => 'c')
|
147
|
+
@return = @user <=> @other
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'should return 1' do
|
152
|
+
expect(@return).to eq(1)
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe 'when the default order property values are sorted after another resource' do
|
157
|
+
before :all do
|
158
|
+
rescue_if @skip && RUBY_VERSION < '1.9.2' do
|
159
|
+
@other = @user_model.new(:name => 'e')
|
160
|
+
@return = @user <=> @other
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'should return -1' do
|
165
|
+
expect(@return).to eq(-1)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
describe 'when comparing an unrelated type of Object' do
|
170
|
+
it 'should raise an exception' do
|
171
|
+
expect { @user <=> @comment_model.new }.to raise_error(ArgumentError, "Cannot compare a #{@comment_model} instance with a #{@user_model} instance")
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
it { expect(@user).to respond_to(:attribute_get) }
|
177
|
+
|
178
|
+
describe '#attribute_get' do
|
179
|
+
|
180
|
+
it { expect(@user.attribute_get(:name)).to eq('dbussink') }
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
it { expect(@user).to respond_to(:attribute_set) }
|
185
|
+
|
186
|
+
describe '#attribute_set' do
|
187
|
+
|
188
|
+
before { @user.attribute_set(:name, 'dkubb') }
|
189
|
+
|
190
|
+
it { expect(@user.name).to eq('dkubb') }
|
191
|
+
|
192
|
+
end
|
193
|
+
|
194
|
+
it { expect(@user).to respond_to(:attributes) }
|
195
|
+
|
196
|
+
describe '#attributes' do
|
197
|
+
describe 'with a new resource' do
|
198
|
+
before :all do
|
199
|
+
rescue_if @skip do
|
200
|
+
@user = @user.model.new
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
it 'should return the expected values' do
|
205
|
+
expect(@user.attributes).to eq({})
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
describe 'with a new resource with a property set' do
|
210
|
+
before :all do
|
211
|
+
rescue_if @skip do
|
212
|
+
@user = @user.model.new
|
213
|
+
@user.name = 'dbussink'
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
it 'should return the expected values' do
|
218
|
+
expect(@user.attributes).to eq({:name => 'dbussink'})
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
describe 'with a saved resource' do
|
223
|
+
it 'should return the expected values' do
|
224
|
+
expect(Ardm::Ext::Hash.only(@user.attributes, :name, :description, :age)).to eq(
|
225
|
+
{ :name => 'dbussink', :description => 'Test', :age => 25 }
|
226
|
+
)
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
it { expect(@user).to respond_to(:attributes=) }
|
232
|
+
|
233
|
+
describe '#attributes=' do
|
234
|
+
describe 'when a public mutator is specified' do
|
235
|
+
before :all do
|
236
|
+
rescue_if @skip do
|
237
|
+
@user.attributes = { :name => 'dkubb' }
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
it 'should set the value' do
|
242
|
+
expect(@user.name).to eql('dkubb')
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
describe 'when a non-public mutator is specified' do
|
247
|
+
it 'should raise an exception' do
|
248
|
+
expect {
|
249
|
+
@user.attributes = { :admin => true }
|
250
|
+
}.to raise_error(ArgumentError, "The attribute \'admin\' is not accessible in #{@user_model}")
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
[ :destroy, :destroy! ].each do |method|
|
256
|
+
it { expect(@user).to respond_to(:destroy) }
|
257
|
+
|
258
|
+
describe "##{method}" do
|
259
|
+
describe 'on a single resource' do
|
260
|
+
before :all do
|
261
|
+
@resource = @user_model.create(:name => 'hacker', :age => 20, :comment => @comment)
|
262
|
+
|
263
|
+
@return = @resource.__send__(method)
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'should successfully remove a resource' do
|
267
|
+
expect(@return).to be(true)
|
268
|
+
end
|
269
|
+
|
270
|
+
it 'should mark the destroyed resource as readonly' do
|
271
|
+
expect(@resource).to be_readonly
|
272
|
+
end
|
273
|
+
|
274
|
+
it "should return true when calling #{method} on a destroyed resource" do
|
275
|
+
expect(@resource.__send__(method)).to be(true)
|
276
|
+
end
|
277
|
+
|
278
|
+
it 'should remove resource from persistent storage' do
|
279
|
+
expect(@user_model.get(*@resource.key)).to be_nil
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
describe 'with has relationship resources' do
|
284
|
+
it 'should raise an exception'
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
it { expect(@user).to respond_to(:dirty?) }
|
290
|
+
|
291
|
+
describe '#dirty?' do
|
292
|
+
describe 'on a record, with dirty attributes' do
|
293
|
+
before { @user.age = 100 }
|
294
|
+
|
295
|
+
it { expect(@user).to be_dirty }
|
296
|
+
end
|
297
|
+
|
298
|
+
describe 'on a record, with no dirty attributes, and dirty parents' do
|
299
|
+
before :all do
|
300
|
+
rescue_if @skip do
|
301
|
+
expect(@user).not_to be_dirty
|
302
|
+
|
303
|
+
parent = @user.parent = @user_model.new(:name => 'Parent')
|
304
|
+
expect(parent).to be_dirty
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
it { expect(@user).to be_dirty }
|
309
|
+
end
|
310
|
+
|
311
|
+
describe 'on a record, with no dirty attributes, and dirty children' do
|
312
|
+
before :all do
|
313
|
+
rescue_if @skip do
|
314
|
+
expect(@user).not_to be_dirty
|
315
|
+
|
316
|
+
child = @user.children.new(:name => 'Child')
|
317
|
+
expect(child).to be_dirty
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
it { expect(@user).to be_dirty }
|
322
|
+
end
|
323
|
+
|
324
|
+
describe 'on a record, with no dirty attributes, and dirty siblings' do
|
325
|
+
before :all do
|
326
|
+
rescue_if @skip do
|
327
|
+
expect(@user).not_to be_dirty
|
328
|
+
|
329
|
+
parent = @user_model.create(:name => 'Parent', :comment => @comment)
|
330
|
+
expect(parent).not_to be_dirty
|
331
|
+
|
332
|
+
@user.update(:parent => parent)
|
333
|
+
expect(@user).not_to be_dirty
|
334
|
+
|
335
|
+
sibling = parent.children.new(:name => 'Sibling')
|
336
|
+
expect(sibling).to be_dirty
|
337
|
+
expect(parent).to be_dirty
|
338
|
+
end
|
339
|
+
end
|
340
|
+
|
341
|
+
it { expect(@user).not_to be_dirty }
|
342
|
+
end
|
343
|
+
|
344
|
+
describe 'on a saved record, with no dirty attributes' do
|
345
|
+
it { expect(@user).not_to be_dirty }
|
346
|
+
end
|
347
|
+
|
348
|
+
describe 'on a new record, with no dirty attributes, no default attributes, and no identity field' do
|
349
|
+
before { @user = @user_model.new }
|
350
|
+
|
351
|
+
it { expect(@user).not_to be_dirty }
|
352
|
+
end
|
353
|
+
|
354
|
+
describe 'on a new record, with no dirty attributes, no default attributes, and an identity field' do
|
355
|
+
before { @comment = @comment_model.new }
|
356
|
+
|
357
|
+
it { expect(@comment).to be_dirty }
|
358
|
+
end
|
359
|
+
|
360
|
+
describe 'on a new record, with no dirty attributes, default attributes, and no identity field' do
|
361
|
+
before { @default = Default.new }
|
362
|
+
|
363
|
+
it { expect(@default).to be_dirty }
|
364
|
+
end
|
365
|
+
|
366
|
+
describe 'on a record with itself as a parent (circular dependency)' do
|
367
|
+
before :all do
|
368
|
+
rescue_if @skip do
|
369
|
+
@user.parent = @user
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
it 'should not raise an exception' do
|
374
|
+
expect {
|
375
|
+
expect(@user.dirty?).to be(true)
|
376
|
+
}.not_to raise_error
|
377
|
+
end
|
378
|
+
end
|
379
|
+
|
380
|
+
describe 'on a record with itself as a child (circular dependency)' do
|
381
|
+
before :all do
|
382
|
+
rescue_if @skip do
|
383
|
+
@user.children = [ @user ]
|
384
|
+
end
|
385
|
+
end
|
386
|
+
|
387
|
+
it 'should not raise an exception' do
|
388
|
+
expect {
|
389
|
+
expect(@user.dirty?).to be(true)
|
390
|
+
}.not_to raise_error
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
394
|
+
describe 'on a record with a parent as a child (circular dependency)' do
|
395
|
+
before :all do
|
396
|
+
rescue_if @skip do
|
397
|
+
@user.children = [ @user.parent = @user_model.new(:name => 'Parent', :comment => @comment) ]
|
398
|
+
expect(@user.save).to be(true)
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
it 'should not raise an exception' do
|
403
|
+
expect {
|
404
|
+
expect(@user.dirty?).to be(true)
|
405
|
+
}.not_to raise_error
|
406
|
+
end
|
407
|
+
end
|
408
|
+
end
|
409
|
+
|
410
|
+
it { expect(@user).to respond_to(:eql?) }
|
411
|
+
|
412
|
+
describe '#eql?' do
|
413
|
+
describe 'when comparing to the same resource' do
|
414
|
+
before :all do
|
415
|
+
@other = @user
|
416
|
+
@return = @user.eql?(@other)
|
417
|
+
end
|
418
|
+
|
419
|
+
it 'should return true' do
|
420
|
+
expect(@return).to be(true)
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
describe 'when comparing to an resource that does not respond to model' do
|
425
|
+
before :all do
|
426
|
+
@other = Object.new
|
427
|
+
@return = @user.eql?(@other)
|
428
|
+
end
|
429
|
+
|
430
|
+
it 'should return false' do
|
431
|
+
expect(@return).to be(false)
|
432
|
+
end
|
433
|
+
end
|
434
|
+
|
435
|
+
describe 'when comparing to a resource with the same properties, but the model is a subclass' do
|
436
|
+
before :all do
|
437
|
+
rescue_if @skip do
|
438
|
+
@other = @author_model.new(@user.attributes)
|
439
|
+
@return = @user.eql?(@other)
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
it 'should return false' do
|
444
|
+
expect(@return).to be(false)
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
describe 'when comparing to a resource with a different key' do
|
449
|
+
before :all do
|
450
|
+
@other = @user_model.create(:name => 'dkubb', :age => 33, :comment => @comment)
|
451
|
+
@return = @user.eql?(@other)
|
452
|
+
end
|
453
|
+
|
454
|
+
it 'should return false' do
|
455
|
+
expect(@return).to be(false)
|
456
|
+
end
|
457
|
+
end
|
458
|
+
|
459
|
+
describe 'when comparing to a resource with the same repository, key and neither self or the other resource is dirty' do
|
460
|
+
before :all do
|
461
|
+
rescue_if @skip do
|
462
|
+
@other = @user_model.get(*@user.key)
|
463
|
+
@return = @user.eql?(@other)
|
464
|
+
end
|
465
|
+
end
|
466
|
+
|
467
|
+
it 'should return true' do
|
468
|
+
expect(@return).to be(true)
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
describe 'when comparing to a resource with the same repository, key but either self or the other resource is dirty' do
|
473
|
+
before :all do
|
474
|
+
rescue_if @skip do
|
475
|
+
@user.age = 20
|
476
|
+
@other = @user_model.get(*@user.key)
|
477
|
+
@return = @user.eql?(@other)
|
478
|
+
end
|
479
|
+
end
|
480
|
+
|
481
|
+
it 'should return false' do
|
482
|
+
expect(@return).to be(false)
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
describe 'when comparing to a resource with the same properties' do
|
487
|
+
before :all do
|
488
|
+
rescue_if @skip do
|
489
|
+
@other = @user_model.new(@user.attributes)
|
490
|
+
@return = @user.eql?(@other)
|
491
|
+
end
|
492
|
+
end
|
493
|
+
|
494
|
+
it 'should return true' do
|
495
|
+
expect(@return).to be(true)
|
496
|
+
end
|
497
|
+
end
|
498
|
+
|
499
|
+
with_alternate_adapter do
|
500
|
+
before :all do
|
501
|
+
if @user_model.respond_to?(:auto_migrate!)
|
502
|
+
# force the user model to be available in the alternate repository
|
503
|
+
@user_model.auto_migrate!(@adapter.name)
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
describe 'when comparing to a resource with a different repository, but the same properties' do
|
508
|
+
before :all do
|
509
|
+
rescue_if @skip do
|
510
|
+
@other = @repository.scope { @user_model.create(@user.attributes) }
|
511
|
+
@return = @user.eql?(@other)
|
512
|
+
end
|
513
|
+
end
|
514
|
+
|
515
|
+
it 'should return false' do
|
516
|
+
expect(@return).to be(false)
|
517
|
+
end
|
518
|
+
end
|
519
|
+
end
|
520
|
+
end
|
521
|
+
|
522
|
+
it { expect(@user).to respond_to(:inspect) }
|
523
|
+
|
524
|
+
describe '#inspect' do
|
525
|
+
|
526
|
+
before :all do
|
527
|
+
rescue_if @skip do
|
528
|
+
@user = @user_model.get(*@user.key)
|
529
|
+
@inspected = @user.inspect
|
530
|
+
end
|
531
|
+
end
|
532
|
+
|
533
|
+
it { expect(@inspected).to match(/^#<#{@user_model}/) }
|
534
|
+
|
535
|
+
it { expect(@inspected).to match(/name="dbussink"/) }
|
536
|
+
|
537
|
+
it { expect(@inspected).to match(/age=25/) }
|
538
|
+
|
539
|
+
it { expect(@inspected).to match(/description=<not loaded>/) }
|
540
|
+
|
541
|
+
end
|
542
|
+
|
543
|
+
it { expect(@user).to respond_to(:key) }
|
544
|
+
|
545
|
+
describe '#key' do
|
546
|
+
|
547
|
+
before :all do
|
548
|
+
rescue_if @skip do
|
549
|
+
@key = @user.key
|
550
|
+
@user.name = 'dkubb'
|
551
|
+
end
|
552
|
+
end
|
553
|
+
|
554
|
+
it { expect(@key).to be_kind_of(Array) }
|
555
|
+
|
556
|
+
it 'should always return the key value persisted in the back end' do
|
557
|
+
expect(@key.first).to eql("dbussink")
|
558
|
+
end
|
559
|
+
|
560
|
+
it { expect(@user.key).to eql(@key) }
|
561
|
+
|
562
|
+
end
|
563
|
+
|
564
|
+
it { expect(@user).to respond_to(:new?) }
|
565
|
+
|
566
|
+
describe '#new?' do
|
567
|
+
|
568
|
+
describe 'on an existing record' do
|
569
|
+
|
570
|
+
it { expect(@user).not_to be_new }
|
571
|
+
|
572
|
+
end
|
573
|
+
|
574
|
+
describe 'on a new record' do
|
575
|
+
|
576
|
+
before { @user = @user_model.new }
|
577
|
+
|
578
|
+
it { expect(@user).to be_new }
|
579
|
+
|
580
|
+
end
|
581
|
+
|
582
|
+
end
|
583
|
+
|
584
|
+
it { expect(@user).to respond_to(:reload) }
|
585
|
+
|
586
|
+
describe '#reload' do
|
587
|
+
before do
|
588
|
+
# reset the user for each spec
|
589
|
+
rescue_if(@skip) do
|
590
|
+
@user.update(:name => 'dbussink', :age => 25, :description => 'Test')
|
591
|
+
end
|
592
|
+
end
|
593
|
+
|
594
|
+
subject { rescue_if(@skip) { @user.reload } }
|
595
|
+
|
596
|
+
describe 'on a resource not persisted' do
|
597
|
+
before do
|
598
|
+
@user.attributes = { :description => 'Changed' }
|
599
|
+
end
|
600
|
+
|
601
|
+
it { is_expected.to be_kind_of(Ardm::Resource) }
|
602
|
+
|
603
|
+
it { is_expected.to equal(@user) }
|
604
|
+
|
605
|
+
it { is_expected.to be_clean }
|
606
|
+
|
607
|
+
it 'reset the changed attributes' do
|
608
|
+
expect(method(:subject)).to change(@user, :description).from('Changed').to('Test')
|
609
|
+
end
|
610
|
+
end
|
611
|
+
|
612
|
+
describe 'on a resource where the key is changed, but not persisted' do
|
613
|
+
before do
|
614
|
+
@user.attributes = { :name => 'dkubb' }
|
615
|
+
end
|
616
|
+
|
617
|
+
it { is_expected.to be_kind_of(Ardm::Resource) }
|
618
|
+
|
619
|
+
it { is_expected.to equal(@user) }
|
620
|
+
|
621
|
+
it { is_expected.to be_clean }
|
622
|
+
|
623
|
+
it 'reset the changed attributes' do
|
624
|
+
expect(method(:subject)).to change(@user, :name).from('dkubb').to('dbussink')
|
625
|
+
end
|
626
|
+
end
|
627
|
+
|
628
|
+
describe 'on a resource that is changed outside another resource' do
|
629
|
+
before do
|
630
|
+
rescue_if @skip do
|
631
|
+
@user.dup.update(:description => 'Changed')
|
632
|
+
end
|
633
|
+
end
|
634
|
+
|
635
|
+
it { is_expected.to be_kind_of(Ardm::Resource) }
|
636
|
+
|
637
|
+
it { is_expected.to equal(@user) }
|
638
|
+
|
639
|
+
it { is_expected.to be_clean }
|
640
|
+
|
641
|
+
it 'should reload the resource from the data store' do
|
642
|
+
expect(method(:subject)).to change(@user, :description).from('Test').to('Changed')
|
643
|
+
end
|
644
|
+
end
|
645
|
+
|
646
|
+
describe 'on an anonymous resource' do
|
647
|
+
before do
|
648
|
+
rescue_if @skip do
|
649
|
+
@user = @user.model.first(:fields => [ :description ])
|
650
|
+
expect(@user.description).to eq('Test')
|
651
|
+
end
|
652
|
+
end
|
653
|
+
|
654
|
+
it { is_expected.to be_kind_of(Ardm::Resource) }
|
655
|
+
|
656
|
+
it { is_expected.to equal(@user) }
|
657
|
+
|
658
|
+
it { is_expected.to be_clean }
|
659
|
+
|
660
|
+
it 'should not reload any attributes' do
|
661
|
+
expect(method(:subject)).not_to change(@user, :attributes)
|
662
|
+
end
|
663
|
+
end
|
664
|
+
end
|
665
|
+
|
666
|
+
it { expect(@user).to respond_to(:readonly?) }
|
667
|
+
|
668
|
+
describe '#readonly?' do
|
669
|
+
describe 'on a new resource' do
|
670
|
+
before :all do
|
671
|
+
rescue_if @skip do
|
672
|
+
@user = @user.model.new
|
673
|
+
end
|
674
|
+
end
|
675
|
+
|
676
|
+
it 'should return false' do
|
677
|
+
expect(@user.readonly?).to be(false)
|
678
|
+
end
|
679
|
+
end
|
680
|
+
|
681
|
+
describe 'on a saved resource' do
|
682
|
+
before :all do
|
683
|
+
rescue_if @skip do
|
684
|
+
expect(@user).to be_saved
|
685
|
+
end
|
686
|
+
end
|
687
|
+
|
688
|
+
it 'should return false' do
|
689
|
+
expect(@user.readonly?).to be(false)
|
690
|
+
end
|
691
|
+
end
|
692
|
+
|
693
|
+
describe 'on a destroyed resource' do
|
694
|
+
before :all do
|
695
|
+
rescue_if @skip do
|
696
|
+
expect(@user.destroy).to be(true)
|
697
|
+
end
|
698
|
+
end
|
699
|
+
|
700
|
+
it 'should return true' do
|
701
|
+
expect(@user.readonly?).to be(true)
|
702
|
+
end
|
703
|
+
end
|
704
|
+
|
705
|
+
describe 'on an anonymous resource' do
|
706
|
+
before :all do
|
707
|
+
rescue_if @skip do
|
708
|
+
# load the user without a key
|
709
|
+
@user = @user.model.first(:fields => @user_model.properties - @user_model.key)
|
710
|
+
end
|
711
|
+
end
|
712
|
+
|
713
|
+
it 'should return true' do
|
714
|
+
expect(@user.readonly?).to be(true)
|
715
|
+
end
|
716
|
+
end
|
717
|
+
end
|
718
|
+
|
719
|
+
[ :save, :save! ].each do |method|
|
720
|
+
it { expect(@user).to respond_to(method) }
|
721
|
+
|
722
|
+
describe "##{method}" do
|
723
|
+
before :all do
|
724
|
+
@user_model.class_eval do
|
725
|
+
attr_accessor :save_hook_call_count
|
726
|
+
|
727
|
+
before :save do
|
728
|
+
@save_hook_call_count ||= 0
|
729
|
+
@save_hook_call_count += 1
|
730
|
+
end
|
731
|
+
end
|
732
|
+
end
|
733
|
+
|
734
|
+
describe 'on a new, not dirty resource' do
|
735
|
+
before :all do
|
736
|
+
@user = @user_model.new
|
737
|
+
@return = @user.__send__(method)
|
738
|
+
end
|
739
|
+
|
740
|
+
it 'should return false' do
|
741
|
+
expect(@return).to be(false)
|
742
|
+
end
|
743
|
+
|
744
|
+
it 'should call save hook expected number of times' do
|
745
|
+
expect(@user.save_hook_call_count).to be_nil
|
746
|
+
end
|
747
|
+
end
|
748
|
+
|
749
|
+
describe 'on a not new, not dirty resource' do
|
750
|
+
before :all do
|
751
|
+
rescue_if @skip do
|
752
|
+
@return = @user.__send__(method)
|
753
|
+
end
|
754
|
+
end
|
755
|
+
|
756
|
+
it 'should return true even when resource is not dirty' do
|
757
|
+
expect(@return).to be(true)
|
758
|
+
end
|
759
|
+
|
760
|
+
it 'should call save hook expected number of times' do
|
761
|
+
expect(@user.save_hook_call_count).to be_nil
|
762
|
+
end
|
763
|
+
end
|
764
|
+
|
765
|
+
describe 'on a not new, dirty resource' do
|
766
|
+
before :all do
|
767
|
+
rescue_if @skip do
|
768
|
+
@user.age = 26
|
769
|
+
@return = @user.__send__(method)
|
770
|
+
end
|
771
|
+
end
|
772
|
+
|
773
|
+
it 'should save a resource succesfully when dirty' do
|
774
|
+
expect(@return).to be(true)
|
775
|
+
end
|
776
|
+
|
777
|
+
it 'should actually store the changes to persistent storage' do
|
778
|
+
expect(@user.attributes).to eq(@user.reload.attributes)
|
779
|
+
end
|
780
|
+
|
781
|
+
it 'should call save hook expected number of times' do
|
782
|
+
expect(@user.save_hook_call_count).to eq(method == :save ? 1 : nil)
|
783
|
+
end
|
784
|
+
end
|
785
|
+
|
786
|
+
describe 'on a new, invalid resource' do
|
787
|
+
before :all do
|
788
|
+
@user = @user_model.new(:name => nil)
|
789
|
+
expect { @user.__send__(method) }.to(raise_error(Ardm::Property::InvalidValueError) do |error|
|
790
|
+
expect(error.property).to eq(@user_model.properties[:name])
|
791
|
+
end)
|
792
|
+
end
|
793
|
+
|
794
|
+
it 'should call save hook expected number of times' do
|
795
|
+
expect(@user.save_hook_call_count).to eq(method == :save ? 1 : nil)
|
796
|
+
end
|
797
|
+
end
|
798
|
+
|
799
|
+
describe 'on a dirty invalid resource' do
|
800
|
+
before :all do
|
801
|
+
rescue_if @skip do
|
802
|
+
@user.name = nil
|
803
|
+
end
|
804
|
+
end
|
805
|
+
|
806
|
+
it 'should not save an invalid resource' do
|
807
|
+
expect { @user.__send__(method) }.to(raise_error(Ardm::Property::InvalidValueError) do |error|
|
808
|
+
expect(error.property).to eq(@user_model.properties[:name])
|
809
|
+
end)
|
810
|
+
end
|
811
|
+
|
812
|
+
it 'should call save hook expected number of times' do
|
813
|
+
expect(@user.save_hook_call_count).to eq(method == :save ? 1 : nil)
|
814
|
+
end
|
815
|
+
end
|
816
|
+
|
817
|
+
describe 'with new resources in a has relationship' do
|
818
|
+
before do
|
819
|
+
rescue_if 'TODO: fix for one to one association', !@user.respond_to?(:comments) do
|
820
|
+
@initial_comments = @user.comments.size
|
821
|
+
@first_comment = @user.comments.new(:body => "DM is great!")
|
822
|
+
@second_comment = @comment_model.new(:user => @user, :body => "is it really?")
|
823
|
+
@return = @user.__send__(method)
|
824
|
+
end
|
825
|
+
end
|
826
|
+
|
827
|
+
it 'should save resource' do
|
828
|
+
pending_if !@user.respond_to?(:comments)
|
829
|
+
expect(@return).to be(true)
|
830
|
+
end
|
831
|
+
|
832
|
+
it 'should save the first resource created through new' do
|
833
|
+
pending_if !@user.respond_to?(:comments)
|
834
|
+
expect(@first_comment.new?).to be(false)
|
835
|
+
end
|
836
|
+
|
837
|
+
it 'should save the correct foreign key for the first resource' do
|
838
|
+
pending_if !@user.respond_to?(:comments)
|
839
|
+
expect(@first_comment.user).to eql(@user)
|
840
|
+
end
|
841
|
+
|
842
|
+
it 'should save the second resource created through the constructor' do
|
843
|
+
skip "Changing a belongs_to parent should add the resource to the correct association"
|
844
|
+
expect(@second_comment.new?).to be(false)
|
845
|
+
end
|
846
|
+
|
847
|
+
it 'should save the correct foreign key for the second resource' do
|
848
|
+
pending_if !@user.respond_to?(:comments)
|
849
|
+
expect(@second_comment.user).to eql(@user)
|
850
|
+
end
|
851
|
+
|
852
|
+
it 'should create 2 extra resources in persistent storage' do
|
853
|
+
skip "Changing a belongs_to parent should add the resource to the correct association"
|
854
|
+
expect(@user.comments.size).to eq(@initial_comments + 2)
|
855
|
+
end
|
856
|
+
end
|
857
|
+
|
858
|
+
describe 'with dirty resources in a has relationship' do
|
859
|
+
before :all do
|
860
|
+
rescue_if 'TODO: fix for one to one association', !@user.respond_to?(:comments) do
|
861
|
+
@first_comment = @user.comments.create(:body => 'DM is great!')
|
862
|
+
@second_comment = @comment_model.create(:user => @user, :body => 'is it really?')
|
863
|
+
|
864
|
+
@first_comment.body = 'It still has rough edges'
|
865
|
+
@second_comment.body = 'But these cool specs help fixing that'
|
866
|
+
@second_comment.user = @user_model.create(:name => 'dkubb')
|
867
|
+
|
868
|
+
@return = @user.__send__(method)
|
869
|
+
end
|
870
|
+
end
|
871
|
+
|
872
|
+
it 'should return true' do
|
873
|
+
pending_if !@user.respond_to?(:comments)
|
874
|
+
expect(@return).to be(true)
|
875
|
+
end
|
876
|
+
|
877
|
+
it 'should not be dirty' do
|
878
|
+
expect(@user).not_to be_dirty
|
879
|
+
end
|
880
|
+
|
881
|
+
it 'should have saved the first child resource' do
|
882
|
+
pending_if !@user.respond_to?(:comments)
|
883
|
+
expect(@first_comment.model.get(*@first_comment.key).body).to eq('It still has rough edges')
|
884
|
+
end
|
885
|
+
|
886
|
+
it 'should not have saved the second child resource' do
|
887
|
+
pending_if !@user.respond_to?(:comments)
|
888
|
+
expect(@second_comment.model.get(*@second_comment.key).body).to eq('is it really?')
|
889
|
+
end
|
890
|
+
end
|
891
|
+
|
892
|
+
describe 'with a new dependency' do
|
893
|
+
before :all do
|
894
|
+
@first_comment = @comment_model.new(:body => "DM is great!")
|
895
|
+
@first_comment.user = @user_model.new(:name => 'dkubb')
|
896
|
+
end
|
897
|
+
|
898
|
+
it 'should not raise an exception when saving the resource' do
|
899
|
+
skip
|
900
|
+
expect { expect(@first_comment.send(method)).to be(false) }.not_to raise_error
|
901
|
+
end
|
902
|
+
end
|
903
|
+
|
904
|
+
describe 'with a dirty dependency' do
|
905
|
+
before :all do
|
906
|
+
rescue_if @skip do
|
907
|
+
@user.name = 'dbussink-the-second'
|
908
|
+
|
909
|
+
@first_comment = @comment_model.new(:body => 'DM is great!')
|
910
|
+
@first_comment.user = @user
|
911
|
+
|
912
|
+
@return = @first_comment.__send__(method)
|
913
|
+
end
|
914
|
+
end
|
915
|
+
|
916
|
+
it 'should succesfully save the resource' do
|
917
|
+
expect(@return).to be(true)
|
918
|
+
end
|
919
|
+
|
920
|
+
it 'should not have a dirty dependency' do
|
921
|
+
expect(@user).not_to be_dirty
|
922
|
+
end
|
923
|
+
|
924
|
+
it 'should succesfully save the dependency' do
|
925
|
+
expect(@user.name).to eq(@user_model.get(*@user.key).name)
|
926
|
+
end
|
927
|
+
end
|
928
|
+
|
929
|
+
describe 'with a new resource and new relations' do
|
930
|
+
before :all do
|
931
|
+
@article = @article_model.new(:body => "Main")
|
932
|
+
rescue_if 'TODO: fix for one to one association', (!@article.respond_to?(:paragraphs)) do
|
933
|
+
@paragraph = @article.paragraphs.new(:text => 'Content')
|
934
|
+
|
935
|
+
@article.__send__(method)
|
936
|
+
end
|
937
|
+
end
|
938
|
+
|
939
|
+
it 'should not be dirty' do
|
940
|
+
pending_if !@article.respond_to?(:paragraphs)
|
941
|
+
expect(@article).not_to be_dirty
|
942
|
+
end
|
943
|
+
|
944
|
+
it 'should not be dirty' do
|
945
|
+
pending_if !@article.respond_to?(:paragraphs)
|
946
|
+
expect(@paragraph).not_to be_dirty
|
947
|
+
end
|
948
|
+
|
949
|
+
it 'should set the related resource' do
|
950
|
+
pending_if !@article.respond_to?(:paragraphs)
|
951
|
+
expect(@paragraph.article).to eq(@article)
|
952
|
+
end
|
953
|
+
|
954
|
+
it 'should set the foreign key properly' do
|
955
|
+
pending_if !@article.respond_to?(:paragraphs)
|
956
|
+
expect(@paragraph.article_id).to eq(@article.id)
|
957
|
+
end
|
958
|
+
end
|
959
|
+
|
960
|
+
describe 'with a dirty resource with a changed key' do
|
961
|
+
before :all do
|
962
|
+
rescue_if @skip do
|
963
|
+
@original_key = @user.key
|
964
|
+
@user.name = 'dkubb'
|
965
|
+
@return = @user.__send__(method)
|
966
|
+
end
|
967
|
+
end
|
968
|
+
|
969
|
+
it 'should save a resource succesfully when dirty' do
|
970
|
+
expect(@return).to be(true)
|
971
|
+
end
|
972
|
+
|
973
|
+
it 'should actually store the changes to persistent storage' do
|
974
|
+
expect(@user.name).to eq(@user.reload.name)
|
975
|
+
end
|
976
|
+
|
977
|
+
it 'should update the identity map' do
|
978
|
+
expect(@user.repository.identity_map(@user_model)).to have_key(%w[ dkubb ])
|
979
|
+
end
|
980
|
+
|
981
|
+
it 'should remove the old entry from the identity map' do
|
982
|
+
expect(@user.repository.identity_map(@user_model)).not_to have_key(@original_key)
|
983
|
+
end
|
984
|
+
end
|
985
|
+
|
986
|
+
describe 'on a new resource with unsaved parent and grandparent' do
|
987
|
+
before :all do
|
988
|
+
@grandparent = @user_model.new(:name => 'dkubb', :comment => @comment)
|
989
|
+
@parent = @user_model.new(:name => 'ashleymoran', :comment => @comment, :referrer => @grandparent)
|
990
|
+
@child = @user_model.new(:name => 'mrship', :comment => @comment, :referrer => @parent)
|
991
|
+
|
992
|
+
@response = @child.__send__(method)
|
993
|
+
end
|
994
|
+
|
995
|
+
it 'should return true' do
|
996
|
+
expect(@response).to be(true)
|
997
|
+
end
|
998
|
+
|
999
|
+
it 'should save the child' do
|
1000
|
+
expect(@child).to be_saved
|
1001
|
+
end
|
1002
|
+
|
1003
|
+
it 'should save the parent' do
|
1004
|
+
expect(@parent).to be_saved
|
1005
|
+
end
|
1006
|
+
|
1007
|
+
it 'should save the grandparent' do
|
1008
|
+
expect(@grandparent).to be_saved
|
1009
|
+
end
|
1010
|
+
|
1011
|
+
it 'should relate the child to the parent' do
|
1012
|
+
expect(@child.model.get(*@child.key).referrer).to eq(@parent)
|
1013
|
+
end
|
1014
|
+
|
1015
|
+
it 'should relate the parent to the grandparent' do
|
1016
|
+
expect(@parent.model.get(*@parent.key).referrer).to eq(@grandparent)
|
1017
|
+
end
|
1018
|
+
|
1019
|
+
it 'should relate the grandparent to nothing' do
|
1020
|
+
expect(@grandparent.model.get(*@grandparent.key).referrer).to be_nil
|
1021
|
+
end
|
1022
|
+
end
|
1023
|
+
|
1024
|
+
describe 'on a destroyed resource' do
|
1025
|
+
before :all do
|
1026
|
+
rescue_if @skip do
|
1027
|
+
@user.destroy
|
1028
|
+
end
|
1029
|
+
end
|
1030
|
+
|
1031
|
+
it 'should raise an exception' do
|
1032
|
+
expect {
|
1033
|
+
@user.__send__(method)
|
1034
|
+
}.to raise_error(Ardm::PersistenceError, "#{@user.model}##{method} cannot be called on a destroyed resource")
|
1035
|
+
end
|
1036
|
+
end
|
1037
|
+
|
1038
|
+
describe 'on a record with itself as a parent (circular dependency)' do
|
1039
|
+
before :all do
|
1040
|
+
rescue_if @skip do
|
1041
|
+
@user.parent = @user
|
1042
|
+
end
|
1043
|
+
end
|
1044
|
+
|
1045
|
+
it 'should not raise an exception' do
|
1046
|
+
expect {
|
1047
|
+
expect(@user.__send__(method)).to be(true)
|
1048
|
+
}.not_to raise_error
|
1049
|
+
end
|
1050
|
+
end
|
1051
|
+
|
1052
|
+
describe 'on a record with itself as a child (circular dependency)' do
|
1053
|
+
before :all do
|
1054
|
+
rescue_if @skip do
|
1055
|
+
@user.children = [ @user ]
|
1056
|
+
end
|
1057
|
+
end
|
1058
|
+
|
1059
|
+
it 'should not raise an exception' do
|
1060
|
+
expect {
|
1061
|
+
expect(@user.__send__(method)).to be(true)
|
1062
|
+
}.not_to raise_error
|
1063
|
+
end
|
1064
|
+
end
|
1065
|
+
|
1066
|
+
describe 'on a record with a parent as a child (circular dependency)' do
|
1067
|
+
before :all do
|
1068
|
+
rescue_if @skip do
|
1069
|
+
@user.children = [ @user.parent = @user_model.new(:name => 'Parent', :comment => @comment) ]
|
1070
|
+
end
|
1071
|
+
end
|
1072
|
+
|
1073
|
+
it 'should not raise an exception' do
|
1074
|
+
expect {
|
1075
|
+
expect(@user.__send__(method)).to be(true)
|
1076
|
+
}.not_to raise_error
|
1077
|
+
end
|
1078
|
+
end
|
1079
|
+
end
|
1080
|
+
end
|
1081
|
+
|
1082
|
+
it { expect(@user).to respond_to(:saved?) }
|
1083
|
+
|
1084
|
+
describe '#saved?' do
|
1085
|
+
|
1086
|
+
describe 'on an existing record' do
|
1087
|
+
|
1088
|
+
it { expect(@user).to be_saved }
|
1089
|
+
|
1090
|
+
end
|
1091
|
+
|
1092
|
+
describe 'on a new record' do
|
1093
|
+
|
1094
|
+
before { @user = @user_model.new }
|
1095
|
+
|
1096
|
+
it { expect(@user).not_to be_saved }
|
1097
|
+
|
1098
|
+
end
|
1099
|
+
|
1100
|
+
end
|
1101
|
+
|
1102
|
+
[ :update, :update! ].each do |method|
|
1103
|
+
it { expect(@user).to respond_to(method) }
|
1104
|
+
|
1105
|
+
describe "##{method}" do
|
1106
|
+
describe 'with attributes' do
|
1107
|
+
before :all do
|
1108
|
+
rescue_if @skip do
|
1109
|
+
@attributes = { :description => 'Changed' }
|
1110
|
+
@return = @user.__send__(method, @attributes)
|
1111
|
+
end
|
1112
|
+
end
|
1113
|
+
|
1114
|
+
it 'should return true' do
|
1115
|
+
expect(@return).to be(true)
|
1116
|
+
end
|
1117
|
+
|
1118
|
+
it 'should update attributes of Resource' do
|
1119
|
+
@attributes.each { |key, value| expect(@user.__send__(key)).to eq(value) }
|
1120
|
+
end
|
1121
|
+
|
1122
|
+
it 'should persist the changes' do
|
1123
|
+
resource = @user_model.get(*@user.key)
|
1124
|
+
@attributes.each { |key, value| expect(resource.__send__(key)).to eq(value) }
|
1125
|
+
end
|
1126
|
+
end
|
1127
|
+
|
1128
|
+
describe 'with attributes where one is a parent association' do
|
1129
|
+
before :all do
|
1130
|
+
rescue_if @skip do
|
1131
|
+
@attributes = { :referrer => @user_model.create(:name => 'dkubb', :age => 33, :comment => @comment) }
|
1132
|
+
@return = @user.__send__(method, @attributes)
|
1133
|
+
end
|
1134
|
+
end
|
1135
|
+
|
1136
|
+
it 'should return true' do
|
1137
|
+
expect(@return).to be(true)
|
1138
|
+
end
|
1139
|
+
|
1140
|
+
it 'should update attributes of Resource' do
|
1141
|
+
@attributes.each { |key, value| expect(@user.__send__(key)).to eq(value) }
|
1142
|
+
end
|
1143
|
+
|
1144
|
+
it 'should persist the changes' do
|
1145
|
+
resource = @user_model.get(*@user.key)
|
1146
|
+
@attributes.each { |key, value| expect(resource.__send__(key)).to eq(value) }
|
1147
|
+
end
|
1148
|
+
end
|
1149
|
+
|
1150
|
+
describe 'with attributes where a value is nil for a property that does not allow nil' do
|
1151
|
+
before do
|
1152
|
+
expect { @user.__send__(method, :name => nil) }.to(raise_error(Ardm::Property::InvalidValueError) do |error|
|
1153
|
+
expect(error.property).to eq(@user_model.properties[:name])
|
1154
|
+
end)
|
1155
|
+
end
|
1156
|
+
|
1157
|
+
it 'should not persist the changes' do
|
1158
|
+
expect(@user.reload.name).not_to be_nil
|
1159
|
+
end
|
1160
|
+
end
|
1161
|
+
|
1162
|
+
describe 'on a new resource' do
|
1163
|
+
before :all do
|
1164
|
+
rescue_if @skip do
|
1165
|
+
@user = @user.model.new(@user.attributes)
|
1166
|
+
@user.age = 99
|
1167
|
+
end
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
it 'should raise an exception' do
|
1171
|
+
expect {
|
1172
|
+
@user.__send__(method, :admin => true)
|
1173
|
+
}.to raise_error(Ardm::UpdateConflictError, "#{@user.model}##{method} cannot be called on a new resource")
|
1174
|
+
end
|
1175
|
+
end
|
1176
|
+
|
1177
|
+
describe 'on a dirty resource' do
|
1178
|
+
before :all do
|
1179
|
+
rescue_if @skip do
|
1180
|
+
@user.age = 99
|
1181
|
+
end
|
1182
|
+
end
|
1183
|
+
|
1184
|
+
it 'should raise an exception' do
|
1185
|
+
expect {
|
1186
|
+
@user.__send__(method, :admin => true)
|
1187
|
+
}.to raise_error(Ardm::UpdateConflictError, "#{@user.model}##{method} cannot be called on a dirty resource")
|
1188
|
+
end
|
1189
|
+
end
|
1190
|
+
end
|
1191
|
+
end
|
1192
|
+
|
1193
|
+
describe 'lazy loading' do
|
1194
|
+
before :all do
|
1195
|
+
rescue_if @skip do
|
1196
|
+
@user.name = 'dkubb'
|
1197
|
+
@user.age = 33
|
1198
|
+
@user.summary = 'Programmer'
|
1199
|
+
|
1200
|
+
# lazy load the description
|
1201
|
+
@user.description
|
1202
|
+
end
|
1203
|
+
end
|
1204
|
+
|
1205
|
+
it 'should not overwrite dirty attribute' do
|
1206
|
+
expect(@user.age).to eq(33)
|
1207
|
+
end
|
1208
|
+
|
1209
|
+
it 'should not overwrite dirty lazy attribute' do
|
1210
|
+
expect(@user.summary).to eq('Programmer')
|
1211
|
+
end
|
1212
|
+
|
1213
|
+
it 'should not overwrite dirty key' do
|
1214
|
+
skip
|
1215
|
+
expect(@user.name).to eq('dkubb')
|
1216
|
+
end
|
1217
|
+
end
|
1218
|
+
end
|