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.
Files changed (93) hide show
  1. checksums.yaml +5 -13
  2. data/Gemfile +1 -2
  3. data/LICENSE +2 -2
  4. data/README.md +72 -16
  5. data/ardm.gemspec +1 -0
  6. data/lib/ardm.rb +2 -1
  7. data/lib/ardm/active_record.rb +8 -1
  8. data/lib/ardm/active_record/associations.rb +33 -4
  9. data/lib/ardm/active_record/base.rb +2 -0
  10. data/lib/ardm/active_record/collection.rb +5 -0
  11. data/lib/ardm/active_record/data_mapper_constant.rb +1 -0
  12. data/lib/ardm/active_record/data_mapper_constant_proxy.rb +24 -0
  13. data/lib/ardm/active_record/finalize.rb +18 -0
  14. data/lib/ardm/active_record/predicate_builder/array_handler.rb +10 -16
  15. data/lib/ardm/active_record/predicate_builder/rails3.rb +42 -15
  16. data/lib/ardm/active_record/predicate_builder/rails4.rb +39 -13
  17. data/lib/ardm/active_record/property.rb +24 -12
  18. data/lib/ardm/active_record/query.rb +9 -18
  19. data/lib/ardm/active_record/record.rb +54 -11
  20. data/lib/ardm/active_record/relation.rb +36 -6
  21. data/lib/ardm/active_record/repository.rb +6 -2
  22. data/lib/ardm/data_mapper.rb +2 -0
  23. data/lib/ardm/data_mapper/record.rb +3 -9
  24. data/lib/ardm/version.rb +1 -1
  25. data/spec/ardm/datamapper_constants_spec.rb +31 -0
  26. data/spec/fixtures/article.rb +2 -0
  27. data/spec/integration/api_key_spec.rb +3 -3
  28. data/spec/integration/bcrypt_hash_spec.rb +7 -7
  29. data/spec/integration/comma_separated_list_spec.rb +11 -11
  30. data/spec/integration/dirty_minder_spec.rb +23 -39
  31. data/spec/integration/enum_spec.rb +11 -11
  32. data/spec/integration/epoch_time_spec.rb +6 -6
  33. data/spec/integration/file_path_spec.rb +23 -23
  34. data/spec/integration/flag_spec.rb +11 -13
  35. data/spec/integration/ip_address_spec.rb +15 -15
  36. data/spec/integration/json_spec.rb +7 -7
  37. data/spec/integration/slug_spec.rb +6 -6
  38. data/spec/integration/uri_spec.rb +11 -11
  39. data/spec/integration/uuid_spec.rb +16 -16
  40. data/spec/integration/yaml_spec.rb +8 -8
  41. data/spec/public/model_spec.rb +193 -0
  42. data/spec/public/property/binary_spec.rb +4 -4
  43. data/spec/public/property/boolean_spec.rb +3 -3
  44. data/spec/public/property/class_spec.rb +2 -2
  45. data/spec/public/property/date_spec.rb +2 -2
  46. data/spec/public/property/date_time_spec.rb +2 -2
  47. data/spec/public/property/decimal_spec.rb +2 -2
  48. data/spec/public/property/discriminator_spec.rb +21 -20
  49. data/spec/public/property/float_spec.rb +2 -2
  50. data/spec/public/property/integer_spec.rb +2 -2
  51. data/spec/public/property/object_spec.rb +14 -13
  52. data/spec/public/property/serial_spec.rb +2 -2
  53. data/spec/public/property/string_spec.rb +2 -2
  54. data/spec/public/property/text_spec.rb +2 -2
  55. data/spec/public/property/time_spec.rb +2 -2
  56. data/spec/public/property_spec.rb +44 -48
  57. data/spec/public/resource_spec.rb +278 -0
  58. data/spec/schema.rb +33 -4
  59. data/spec/semipublic/property/boolean_spec.rb +5 -5
  60. data/spec/semipublic/property/class_spec.rb +3 -3
  61. data/spec/semipublic/property/date_spec.rb +8 -8
  62. data/spec/semipublic/property/date_time_spec.rb +9 -9
  63. data/spec/semipublic/property/decimal_spec.rb +16 -16
  64. data/spec/semipublic/property/float_spec.rb +16 -16
  65. data/spec/semipublic/property/integer_spec.rb +16 -16
  66. data/spec/semipublic/property/lookup_spec.rb +4 -4
  67. data/spec/semipublic/property/text_spec.rb +2 -2
  68. data/spec/semipublic/property/time_spec.rb +10 -10
  69. data/spec/semipublic/property_spec.rb +4 -4
  70. data/spec/shared/finder_shared_spec.rb +1151 -0
  71. data/spec/shared/flags_shared_spec.rb +6 -6
  72. data/spec/shared/identity_function_group.rb +1 -1
  73. data/spec/shared/public_property_spec.rb +26 -25
  74. data/spec/shared/resource_spec.rb +1218 -0
  75. data/spec/shared/semipublic_property_spec.rb +23 -22
  76. data/spec/spec_helper.rb +17 -0
  77. data/spec/unit/bcrypt_hash_spec.rb +15 -15
  78. data/spec/unit/csv_spec.rb +11 -11
  79. data/spec/unit/dirty_minder_spec.rb +3 -5
  80. data/spec/unit/enum_spec.rb +17 -17
  81. data/spec/unit/epoch_time_spec.rb +8 -8
  82. data/spec/unit/file_path_spec.rb +9 -9
  83. data/spec/unit/flag_spec.rb +9 -9
  84. data/spec/unit/ip_address_spec.rb +9 -9
  85. data/spec/unit/json_spec.rb +11 -11
  86. data/spec/unit/paranoid_boolean_spec.rb +19 -17
  87. data/spec/unit/paranoid_datetime_spec.rb +21 -19
  88. data/spec/unit/regexp_spec.rb +4 -4
  89. data/spec/unit/uri_spec.rb +8 -8
  90. data/spec/unit/yaml_spec.rb +9 -9
  91. metadata +35 -27
  92. data/lib/ardm/active_record/not_found.rb +0 -7
  93. data/lib/ardm/data_mapper/not_found.rb +0 -5
@@ -1,4 +1,4 @@
1
- share_examples_for "A property with flags" do
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].should_not be_nil
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.should include(:flags)
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.should respond_to(:generated_classes)
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.should respond_to(:flag_map)
30
+ expect(@property).to respond_to(:flag_map)
31
31
  end
32
32
 
33
33
  it "should be custom" do
34
- @property.custom?.should be(true)
34
+ expect(@property.custom?).to be(true)
35
35
  end
36
36
  end
@@ -1,5 +1,5 @@
1
1
  shared_examples_for "identity function" do
2
2
  it "returns value unchanged" do
3
- @result.should == @input
3
+ expect(@result).to eq(@input)
4
4
  end
5
5
  end
@@ -1,4 +1,4 @@
1
- share_examples_for 'A public Property' do
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.should eql(nil)
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).should be(true)
67
- type.accepted_options.include?(:bar).should be(true)
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.should respond_to(:foo)
74
- type.should respond_to(:bar)
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].should == true
87
- @property.options[:bar].should == 1
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.should == true
92
- @subtype.bar.should == 1
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).should be(true)
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.should be(@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.should be(Object)
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).should be(value)
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
- lambda {
135
+ expect {
135
136
  @property = @type.new(@model, @name, @options.merge(opt => true, :required => true))
136
- }.should raise_error(ArgumentError,
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).should be(value)
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?.should be(true)
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?.should be(false)
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 { should be(true) }
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 { should be(false) }
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 { should be(false) }
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 { should be(true) }
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 { should be(true) }
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 { should be(true) }
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