dm-hibernate-adapter 0.1pre-java

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