couchrest_model 2.1.0.rc1 → 2.2.0.beta1
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 +4 -4
- data/.gitignore +1 -1
- data/.travis.yml +15 -4
- data/Gemfile.activesupport-4.x +4 -0
- data/Gemfile.activesupport-5.x +4 -0
- data/README.md +2 -0
- data/VERSION +1 -1
- data/couchrest_model.gemspec +3 -2
- data/history.md +14 -1
- data/lib/couchrest/model/associations.rb +3 -8
- data/lib/couchrest/model/base.rb +15 -7
- data/lib/couchrest/model/casted_array.rb +22 -34
- data/lib/couchrest/model/configuration.rb +2 -0
- data/lib/couchrest/model/design.rb +4 -3
- data/lib/couchrest/model/designs/view.rb +37 -32
- data/lib/couchrest/model/dirty.rb +93 -19
- data/lib/couchrest/model/embeddable.rb +2 -14
- data/lib/couchrest/model/extended_attachments.rb +2 -4
- data/lib/couchrest/model/persistence.rb +14 -17
- data/lib/couchrest/model/properties.rb +46 -54
- data/lib/couchrest/model/property.rb +0 -3
- data/lib/couchrest/model/proxyable.rb +20 -4
- data/lib/couchrest/model/validations/uniqueness.rb +4 -1
- data/lib/couchrest_model.rb +2 -2
- data/spec/fixtures/models/article.rb +1 -1
- data/spec/fixtures/models/card.rb +2 -1
- data/spec/fixtures/models/person.rb +1 -0
- data/spec/fixtures/models/project.rb +3 -0
- data/spec/unit/assocations_spec.rb +73 -73
- data/spec/unit/attachment_spec.rb +34 -34
- data/spec/unit/base_spec.rb +102 -102
- data/spec/unit/casted_array_spec.rb +7 -7
- data/spec/unit/casted_spec.rb +7 -7
- data/spec/unit/configuration_spec.rb +11 -11
- data/spec/unit/connection_spec.rb +30 -30
- data/spec/unit/core_extensions/{time_parsing.rb → time_parsing_spec.rb} +21 -21
- data/spec/unit/design_spec.rb +38 -38
- data/spec/unit/designs/design_mapper_spec.rb +26 -26
- data/spec/unit/designs/migrations_spec.rb +13 -13
- data/spec/unit/designs/view_spec.rb +319 -274
- data/spec/unit/designs_spec.rb +39 -39
- data/spec/unit/dirty_spec.rb +188 -103
- data/spec/unit/embeddable_spec.rb +119 -117
- data/spec/unit/inherited_spec.rb +4 -4
- data/spec/unit/persistence_spec.rb +122 -122
- data/spec/unit/properties_spec.rb +466 -16
- data/spec/unit/property_protection_spec.rb +32 -32
- data/spec/unit/property_spec.rb +45 -436
- data/spec/unit/proxyable_spec.rb +140 -82
- data/spec/unit/subclass_spec.rb +14 -14
- data/spec/unit/translations_spec.rb +5 -5
- data/spec/unit/typecast_spec.rb +131 -131
- data/spec/unit/utils/migrate_spec.rb +2 -2
- data/spec/unit/validations_spec.rb +31 -31
- metadata +27 -12
- data/lib/couchrest/model/casted_hash.rb +0 -84
@@ -3,20 +3,470 @@ require "spec_helper"
|
|
3
3
|
|
4
4
|
describe CouchRest::Model::Properties do
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
context "general functionality" do
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
reset_test_db!
|
10
|
+
@card = Card.new(:first_name => "matt")
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should be accessible from the object" do
|
14
|
+
expect(@card.properties).to be_an_instance_of(Array)
|
15
|
+
expect(@card.properties.map{|p| p.name}).to include("first_name")
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should list object properties with values" do
|
19
|
+
expect(@card.attributes).to be_an_instance_of(Hash)
|
20
|
+
expect(@card.read_attributes).to be_an_instance_of(Hash)
|
21
|
+
expect(@card.attributes["first_name"]).to eql("matt")
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should let you access a property value (getter)" do
|
25
|
+
expect(@card.first_name).to eql("matt")
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should let you set a property value (setter)" do
|
29
|
+
@card.last_name = "Aimonetti"
|
30
|
+
expect(@card.last_name).to eq("Aimonetti")
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should not let you set a property value if it's read only" do
|
34
|
+
expect{@card.read_only_value = "test"}.to raise_error(NoMethodError)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should let you use an alias for an attribute" do
|
38
|
+
@card.last_name = "Aimonetti"
|
39
|
+
expect(@card.family_name).to eq("Aimonetti")
|
40
|
+
expect(@card.family_name).to eq(@card.last_name)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should let you use an alias for a casted attribute" do
|
44
|
+
@card.cast_alias = Person.new(:name => ["Aimonetti"])
|
45
|
+
expect(@card.cast_alias.name).to eq(["Aimonetti"])
|
46
|
+
expect(@card.calias.name).to eq(["Aimonetti"])
|
47
|
+
card = Card.new(:first_name => "matt", :cast_alias => {:name => ["Aimonetti"]})
|
48
|
+
expect(card.cast_alias.name).to eq(["Aimonetti"])
|
49
|
+
expect(card.calias.name).to eq(["Aimonetti"])
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should raise error if property name coincides with model type key" do
|
53
|
+
expect { Cat.property(Cat.model_type_key) }.to raise_error(/already used/)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should not raise error if property name coincides with model type key on non-model" do
|
57
|
+
expect { Person.property(Article.model_type_key) }.not_to raise_error
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should be auto timestamped" do
|
61
|
+
expect(@card.created_at).to be_nil
|
62
|
+
expect(@card.updated_at).to be_nil
|
63
|
+
expect(@card.save).to be_truthy
|
64
|
+
expect(@card.created_at).not_to be_nil
|
65
|
+
expect(@card.updated_at).not_to be_nil
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#as_couch_json" do
|
69
|
+
|
70
|
+
it "should provide a simple hash from model" do
|
71
|
+
expect(@card.as_couch_json.class).to eql(Hash)
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should remove properties from Hash if value is nil" do
|
75
|
+
@card.last_name = nil
|
76
|
+
expect(@card.as_couch_json.keys.include?('last_name')).to be_falsey
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "#as_json" do
|
82
|
+
|
83
|
+
it "should provide a simple hash from model" do
|
84
|
+
expect(@card.as_json.class).to eql(Hash)
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should pass options to Active Support's as_json" do
|
88
|
+
@card.last_name = "Aimonetti"
|
89
|
+
expect(@card.as_json(:only => 'last_name')).to eql('last_name' => 'Aimonetti')
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
describe '#read_attribute' do
|
95
|
+
it "should let you use read_attribute method" do
|
96
|
+
@card.last_name = "Aimonetti"
|
97
|
+
expect(@card.read_attribute(:last_name)).to eql('Aimonetti')
|
98
|
+
expect(@card.read_attribute('last_name')).to eql('Aimonetti')
|
99
|
+
last_name_prop = @card.properties.find{|p| p.name == 'last_name'}
|
100
|
+
expect(@card.read_attribute(last_name_prop)).to eql('Aimonetti')
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'should raise an error if the property does not exist' do
|
104
|
+
expect { @card.read_attribute(:this_property_should_not_exist) }.to raise_error(ArgumentError)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe '#write_attribute' do
|
109
|
+
it "should let you use write_attribute method" do
|
110
|
+
@card.write_attribute(:last_name, 'Aimonetti 1')
|
111
|
+
expect(@card.last_name).to eql('Aimonetti 1')
|
112
|
+
@card.write_attribute('last_name', 'Aimonetti 2')
|
113
|
+
expect(@card.last_name).to eql('Aimonetti 2')
|
114
|
+
last_name_prop = @card.properties.find{|p| p.name == 'last_name'}
|
115
|
+
@card.write_attribute(last_name_prop, 'Aimonetti 3')
|
116
|
+
expect(@card.last_name).to eql('Aimonetti 3')
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'should raise an error if the property does not exist' do
|
120
|
+
expect { @card.write_attribute(:this_property_should_not_exist, 823) }.to raise_error(ArgumentError)
|
121
|
+
end
|
122
|
+
|
123
|
+
it "should let you use write_attribute on readonly properties" do
|
124
|
+
expect {
|
125
|
+
@card.read_only_value = "foo"
|
126
|
+
}.to raise_error(NoMethodError)
|
127
|
+
@card.write_attribute(:read_only_value, "foo")
|
128
|
+
expect(@card.read_only_value).to eq('foo')
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should cast via write_attribute" do
|
132
|
+
@card.write_attribute(:cast_alias, {:name => ["Sam", "Lown"]})
|
133
|
+
expect(@card.cast_alias.class).to eql(Person)
|
134
|
+
expect(@card.cast_alias.name.last).to eql("Lown")
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should not cast via write_attribute if property not casted" do
|
138
|
+
@card.write_attribute(:first_name, {:name => "Sam"})
|
139
|
+
expect(@card.first_name.class).to eql(Hash)
|
140
|
+
expect(@card.first_name[:name]).to eql("Sam")
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
# These tests are light as functionality is covered elsewhere
|
145
|
+
describe "#write_attributes" do
|
146
|
+
|
147
|
+
let :obj do
|
148
|
+
Card.new(:first_name => "matt")
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should update attributes" do
|
152
|
+
obj.write_attributes( :last_name => 'foo' )
|
153
|
+
expect(obj.last_name).to eql('foo')
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should not update protected attributes" do
|
157
|
+
obj.write_attributes(:bg_color => '#000000')
|
158
|
+
expect(obj.bg_color).to_not eql('#000000')
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should not update read_only attributes" do
|
162
|
+
obj.write_attributes(:read_only_value => 'bar')
|
163
|
+
expect(obj.read_only_value).to_not eql('bar')
|
164
|
+
end
|
165
|
+
|
166
|
+
it "should have an #attributes= alias" do
|
167
|
+
expect {
|
168
|
+
obj.attributes = { :last_name => 'foo' }
|
169
|
+
}.to_not raise_error
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
# These tests are light as functionality is covered elsewhere
|
175
|
+
describe "#write_all_attributes" do
|
176
|
+
|
177
|
+
let :obj do
|
178
|
+
Card.new(:first_name => "matt")
|
179
|
+
end
|
180
|
+
|
181
|
+
it "should set regular properties" do
|
182
|
+
obj.write_all_attributes(:last_name => 'foo')
|
183
|
+
expect(obj.last_name).to eql('foo')
|
184
|
+
end
|
185
|
+
|
186
|
+
it "should set read-only and protected properties" do
|
187
|
+
obj.write_all_attributes(
|
188
|
+
:read_only_value => 'foo',
|
189
|
+
:bg_color => '#111111'
|
190
|
+
)
|
191
|
+
expect(obj.read_only_value).to eql('foo')
|
192
|
+
expect(obj.bg_color).to eql('#111111')
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
|
198
|
+
describe "mass updating attributes without property" do
|
199
|
+
|
200
|
+
describe "when mass_assign_any_attribute false" do
|
201
|
+
|
202
|
+
it "should not allow them to be set" do
|
203
|
+
@card.attributes = {:test => 'fooobar'}
|
204
|
+
expect(@card['test']).to be_nil
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'should not allow them to be updated with update_attributes' do
|
208
|
+
@card.update_attributes(:test => 'fooobar')
|
209
|
+
expect(@card['test']).to be_nil
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'should not have a different revision after update_attributes' do
|
213
|
+
@card.save
|
214
|
+
rev = @card.rev
|
215
|
+
@card.update_attributes(:test => 'fooobar')
|
216
|
+
expect(@card.rev).to eql(rev)
|
217
|
+
end
|
218
|
+
|
219
|
+
it 'should not have a different revision after save' do
|
220
|
+
@card.save
|
221
|
+
rev = @card.rev
|
222
|
+
@card.attributes = {:test => 'fooobar'}
|
223
|
+
@card.save
|
224
|
+
expect(@card.rev).to eql(rev)
|
225
|
+
end
|
226
|
+
|
227
|
+
end
|
228
|
+
|
229
|
+
describe "when mass_assign_any_attribute true" do
|
230
|
+
before(:each) do
|
231
|
+
# dup Card class so that no other tests are effected
|
232
|
+
card_class = Card.dup
|
233
|
+
card_class.class_eval do
|
234
|
+
mass_assign_any_attribute true
|
235
|
+
end
|
236
|
+
@card = card_class.new(:first_name => 'Sam')
|
237
|
+
end
|
238
|
+
|
239
|
+
it 'should allow them to be updated' do
|
240
|
+
@card.attributes = {:testing => 'fooobar'}
|
241
|
+
expect(@card['testing']).to eql('fooobar')
|
242
|
+
end
|
243
|
+
|
244
|
+
it 'should allow them to be updated with update_attributes' do
|
245
|
+
@card.update_attributes(:testing => 'fooobar')
|
246
|
+
expect(@card['testing']).to eql('fooobar')
|
247
|
+
end
|
248
|
+
|
249
|
+
it 'should have a different revision after update_attributes' do
|
250
|
+
@card.save
|
251
|
+
rev = @card.rev
|
252
|
+
@card.update_attributes(:testing => 'fooobar')
|
253
|
+
expect(@card.rev).not_to eql(rev)
|
254
|
+
end
|
255
|
+
|
256
|
+
it 'should have a different revision after save' do
|
257
|
+
@card.save
|
258
|
+
rev = @card.rev
|
259
|
+
@card.attributes = {:testing => 'fooobar'}
|
260
|
+
@card.save
|
261
|
+
expect(@card.rev).not_to eql(rev)
|
262
|
+
end
|
263
|
+
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
describe "mass assignment protection" do
|
268
|
+
|
269
|
+
it "should not store protected attribute using mass assignment" do
|
270
|
+
cat_toy = CatToy.new(:name => "Zorro")
|
271
|
+
cat = Cat.create(:name => "Helena", :toys => [cat_toy], :favorite_toy => cat_toy, :number => 1)
|
272
|
+
expect(cat.number).to be_nil
|
273
|
+
cat.number = 1
|
274
|
+
cat.save
|
275
|
+
expect(cat.number).to eq(1)
|
276
|
+
end
|
277
|
+
|
278
|
+
it "should not store protected attribute when 'declare accessible poperties, assume all the rest are protected'" do
|
279
|
+
user = User.create(:name => "Marcos Tapajós", :admin => true)
|
280
|
+
expect(user.admin).to be_nil
|
281
|
+
end
|
282
|
+
|
283
|
+
it "should not store protected attribute when 'declare protected properties, assume all the rest are accessible'" do
|
284
|
+
user = SpecialUser.create(:name => "Marcos Tapajós", :admin => true)
|
285
|
+
expect(user.admin).to be_nil
|
286
|
+
end
|
287
|
+
|
288
|
+
end
|
289
|
+
|
290
|
+
describe "validation" do
|
291
|
+
before(:each) do
|
292
|
+
@invoice = Invoice.new(:client_name => "matt", :employee_name => "Chris", :location => "San Diego, CA")
|
293
|
+
end
|
294
|
+
|
295
|
+
it "should be able to be validated" do
|
296
|
+
expect(@card.valid?).to eq(true)
|
297
|
+
end
|
298
|
+
|
299
|
+
it "should let you validate the presence of an attribute" do
|
300
|
+
@card.first_name = nil
|
301
|
+
expect(@card).not_to be_valid
|
302
|
+
expect(@card.errors).not_to be_empty
|
303
|
+
expect(@card.errors[:first_name]).to eq(["can't be blank"])
|
304
|
+
end
|
305
|
+
|
306
|
+
it "should let you look up errors for a field by a string name" do
|
307
|
+
@card.first_name = nil
|
308
|
+
expect(@card).not_to be_valid
|
309
|
+
expect(@card.errors['first_name']).to eq(["can't be blank"])
|
310
|
+
end
|
311
|
+
|
312
|
+
it "should validate the presence of 2 attributes" do
|
313
|
+
@invoice.clear
|
314
|
+
expect(@invoice).not_to be_valid
|
315
|
+
expect(@invoice.errors).not_to be_empty
|
316
|
+
expect(@invoice.errors[:client_name]).to eq(["can't be blank"])
|
317
|
+
expect(@invoice.errors[:employee_name]).not_to be_empty
|
318
|
+
end
|
319
|
+
|
320
|
+
it "should let you set an error message" do
|
321
|
+
@invoice.location = nil
|
322
|
+
@invoice.valid?
|
323
|
+
expect(@invoice.errors[:location]).to eq(["Hey stupid!, you forgot the location"])
|
324
|
+
end
|
325
|
+
|
326
|
+
it "should validate before saving" do
|
327
|
+
@invoice.location = nil
|
328
|
+
expect(@invoice).not_to be_valid
|
329
|
+
expect(@invoice.save).to be_falsey
|
330
|
+
expect(@invoice).to be_new
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
8
334
|
end
|
335
|
+
|
336
|
+
context "casting" do
|
337
|
+
|
338
|
+
describe "properties of hash of casted models" do
|
339
|
+
it "should be able to assign a casted hash to a hash property" do
|
340
|
+
chain = KeyChain.new
|
341
|
+
keys = {"House" => "8==$", "Office" => "<>==U"}
|
342
|
+
chain.keys = keys
|
343
|
+
chain.keys = chain.keys
|
344
|
+
expect(chain.keys).to eq(keys)
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
describe "properties of array of casted models" do
|
349
|
+
|
350
|
+
before(:each) do
|
351
|
+
@course = Course.new :title => 'Test Course'
|
352
|
+
end
|
353
|
+
|
354
|
+
it "should allow attribute to be set from an array of objects" do
|
355
|
+
@course.questions = [Question.new(:q => "works?"), Question.new(:q => "Meaning of Life?")]
|
356
|
+
expect(@course.questions.length).to eql(2)
|
357
|
+
end
|
358
|
+
|
359
|
+
it "should allow attribute to be set from an array of hashes" do
|
360
|
+
@course.questions = [{:q => "works?"}, {:q => "Meaning of Life?"}]
|
361
|
+
expect(@course.questions.length).to eql(2)
|
362
|
+
expect(@course.questions.last.q).to eql("Meaning of Life?")
|
363
|
+
expect(@course.questions.last.class).to eql(Question) # typecasting
|
364
|
+
end
|
365
|
+
|
366
|
+
it "should allow attribute to be set from hash with ordered keys and objects" do
|
367
|
+
@course.questions = { '0' => Question.new(:q => "Test1"), '1' => Question.new(:q => 'Test2') }
|
368
|
+
expect(@course.questions.length).to eql(2)
|
369
|
+
expect(@course.questions.last.q).to eql('Test2')
|
370
|
+
expect(@course.questions.last.class).to eql(Question)
|
371
|
+
end
|
372
|
+
|
373
|
+
it "should allow attribute to be set from hash with ordered keys and sub-hashes" do
|
374
|
+
@course.questions = { '10' => {:q => 'Test10'}, '0' => {:q => "Test1"}, '1' => {:q => 'Test2'} }
|
375
|
+
expect(@course.questions.length).to eql(3)
|
376
|
+
expect(@course.questions.last.q).to eql('Test10')
|
377
|
+
expect(@course.questions.last.class).to eql(Question)
|
378
|
+
end
|
379
|
+
|
380
|
+
it "should allow attribute to be set from hash with ordered keys and HashWithIndifferentAccess" do
|
381
|
+
# This is similar to what you'd find in an HTML POST parameters
|
382
|
+
hash = HashWithIndifferentAccess.new({ '0' => {:q => "Test1"}, '1' => {:q => 'Test2'} })
|
383
|
+
@course.questions = hash
|
384
|
+
expect(@course.questions.length).to eql(2)
|
385
|
+
expect(@course.questions.last.q).to eql('Test2')
|
386
|
+
expect(@course.questions.last.class).to eql(Question)
|
387
|
+
end
|
388
|
+
|
389
|
+
it "should allow attribute to be set from Hash subclass with ordered keys" do
|
390
|
+
ourhash = Class.new(HashWithIndifferentAccess)
|
391
|
+
hash = ourhash.new({ '0' => {:q => "Test1"}, '1' => {:q => 'Test2'} })
|
392
|
+
@course.questions = hash
|
393
|
+
expect(@course.questions.length).to eql(2)
|
394
|
+
expect(@course.questions.last.q).to eql('Test2')
|
395
|
+
expect(@course.questions.last.class).to eql(Question)
|
396
|
+
end
|
397
|
+
|
398
|
+
it "should raise an error if attempting to set single value for array type" do
|
399
|
+
expect {
|
400
|
+
@course.questions = Question.new(:q => 'test1')
|
401
|
+
}.to raise_error(/Expecting an array/)
|
402
|
+
end
|
403
|
+
|
404
|
+
|
405
|
+
end
|
406
|
+
|
407
|
+
describe "a casted model retrieved from the database" do
|
408
|
+
before(:each) do
|
409
|
+
reset_test_db!
|
410
|
+
@cat = Cat.new(:name => 'Stimpy')
|
411
|
+
@cat.favorite_toy = CatToy.new(:name => 'Stinky')
|
412
|
+
@cat.toys << CatToy.new(:name => 'Feather')
|
413
|
+
@cat.toys << CatToy.new(:name => 'Mouse')
|
414
|
+
@cat.save
|
415
|
+
@cat = Cat.get(@cat.id)
|
416
|
+
end
|
417
|
+
|
418
|
+
describe "as a casted property" do
|
419
|
+
it "should already be casted_by its parent" do
|
420
|
+
expect(@cat.favorite_toy.casted_by).to be === @cat
|
421
|
+
end
|
422
|
+
end
|
423
|
+
|
424
|
+
describe "from a casted collection" do
|
425
|
+
it "should already be casted_by its parent" do
|
426
|
+
expect(@cat.toys[0].casted_by).to be === @cat
|
427
|
+
expect(@cat.toys[1].casted_by).to be === @cat
|
428
|
+
end
|
429
|
+
end
|
430
|
+
end
|
431
|
+
|
432
|
+
describe "nested models (not casted)" do
|
433
|
+
before(:each) do
|
434
|
+
reset_test_db!
|
435
|
+
@cat = ChildCat.new(:name => 'Stimpy')
|
436
|
+
@cat.mother = {:name => 'Stinky'}
|
437
|
+
@cat.siblings = [{:name => 'Feather'}, {:name => 'Felix'}]
|
438
|
+
@cat.save
|
439
|
+
@cat = ChildCat.get(@cat.id)
|
440
|
+
end
|
441
|
+
|
442
|
+
it "should correctly save single relation" do
|
443
|
+
expect(@cat.mother.name).to eql('Stinky')
|
444
|
+
expect(@cat.mother.casted_by).to eql(@cat)
|
445
|
+
end
|
446
|
+
|
447
|
+
it "should correctly save collection" do
|
448
|
+
expect(@cat.siblings.first.name).to eql("Feather")
|
449
|
+
expect(@cat.siblings.last.casted_by).to eql(@cat)
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
end
|
454
|
+
|
455
|
+
context "multipart attributes" do
|
456
|
+
|
457
|
+
before(:each) do
|
458
|
+
@obj = WithDefaultValues.new
|
459
|
+
end
|
9
460
|
|
10
|
-
describe "multipart attributes" do
|
11
461
|
context "with valid params" do
|
12
462
|
it "should parse a legal date" do
|
13
463
|
valid_date_params = { "exec_date(1i)"=>"2011",
|
14
464
|
"exec_date(2i)"=>"10",
|
15
465
|
"exec_date(3i)"=>"18"}
|
16
466
|
@obj = WithDateAndTime.new valid_date_params
|
17
|
-
@obj.exec_date.
|
18
|
-
@obj.exec_date.
|
19
|
-
@obj.exec_date.
|
467
|
+
expect(@obj.exec_date).not_to be_nil
|
468
|
+
expect(@obj.exec_date).to be_kind_of(Date)
|
469
|
+
expect(@obj.exec_date).to eq(Date.new(2011, 10 ,18))
|
20
470
|
end
|
21
471
|
|
22
472
|
it "should parse a legal time" do
|
@@ -27,9 +477,9 @@ describe CouchRest::Model::Properties do
|
|
27
477
|
"exec_time(5i)"=>"15",
|
28
478
|
"exec_time(6i)"=>"15",}
|
29
479
|
@obj = WithDateAndTime.new valid_time_params
|
30
|
-
@obj.exec_time.
|
31
|
-
@obj.exec_time.
|
32
|
-
@obj.exec_time.
|
480
|
+
expect(@obj.exec_time).not_to be_nil
|
481
|
+
expect(@obj.exec_time).to be_kind_of(Time)
|
482
|
+
expect(@obj.exec_time).to eq(Time.utc(2011, 10 ,18, 15, 15, 15))
|
33
483
|
end
|
34
484
|
end
|
35
485
|
|
@@ -41,15 +491,15 @@ describe CouchRest::Model::Properties do
|
|
41
491
|
end
|
42
492
|
it "should still create a model if there are invalid attributes" do
|
43
493
|
@obj = WithDateAndTime.new @invalid_date_params
|
44
|
-
@obj.
|
45
|
-
@obj.
|
494
|
+
expect(@obj).not_to be_nil
|
495
|
+
expect(@obj).to be_kind_of(WithDateAndTime)
|
46
496
|
end
|
47
497
|
it "should not crash because of an empty value" do
|
48
498
|
@invalid_date_params["exec_date(2i)"] = ""
|
49
499
|
@obj = WithDateAndTime.new @invalid_date_params
|
50
|
-
@obj.
|
51
|
-
@obj.exec_date.
|
52
|
-
@obj.
|
500
|
+
expect(@obj).not_to be_nil
|
501
|
+
expect(@obj.exec_date).not_to be_kind_of(Date)
|
502
|
+
expect(@obj).to be_kind_of(WithDateAndTime)
|
53
503
|
end
|
54
504
|
end
|
55
505
|
|
@@ -64,9 +514,9 @@ describe CouchRest::Model::Properties do
|
|
64
514
|
end
|
65
515
|
|
66
516
|
it "should be accepted" do
|
67
|
-
|
517
|
+
expect {
|
68
518
|
@obj = klass.new(:name => 'test (object)')
|
69
|
-
}.
|
519
|
+
}.not_to raise_error
|
70
520
|
end
|
71
521
|
|
72
522
|
end
|