dm-hibernate-adapter 0.1pre-java

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 (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