deep_cloneable 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,509 +0,0 @@
1
- require 'test_helper'
2
-
3
- class TestDeepCloneable < MiniTest::Unit::TestCase
4
- def setup
5
- @jack = Pirate.create(:name => 'Jack Sparrow', :nick_name => 'Captain Jack', :age => 30)
6
- @polly = Parrot.create(:name => 'Polly', :age => 2, :pirate => @jack)
7
- @john = Matey.create(:name => 'John', :pirate => @jack)
8
- @treasure = Treasure.create(:found_at => 'Isla del Muerte', :pirate => @jack, :matey => @john)
9
- @gold_piece = GoldPiece.create(:treasure => @treasure)
10
- @ship = BattleShip.create(:name => 'Black Pearl', :pirates => [@jack])
11
- end
12
-
13
- def test_single_deep_clone_exception
14
- deep_clone = @jack.deep_clone(:except => :name)
15
- assert deep_clone.new_record?
16
- assert deep_clone.save
17
- assert_equal @jack.name, @jack.deep_clone.name
18
- assert_nil deep_clone.name
19
- assert_equal @jack.nick_name, deep_clone.nick_name
20
- end
21
-
22
- def test_multiple_deep_clone_exception
23
- deep_clone = @jack.deep_clone(:except => [:name, :nick_name])
24
- assert deep_clone.new_record?
25
- assert deep_clone.save
26
- assert_nil deep_clone.name
27
- assert_equal 'no nickname', deep_clone.nick_name
28
- assert_equal @jack.age, deep_clone.age
29
- end
30
-
31
- def test_single_deep_clone_onliness
32
- deep_clone = @jack.deep_clone(:only => :name)
33
- assert deep_clone.new_record?
34
- assert deep_clone.piastres, []
35
- assert deep_clone.save
36
- assert_equal @jack.name, deep_clone.name
37
- assert_equal 'no nickname', deep_clone.nick_name
38
- assert_nil deep_clone.age
39
- assert_nil deep_clone.ship_id
40
- assert_nil deep_clone.ship_type
41
- end
42
-
43
- def test_multiple_deep_clone_onliness
44
- deep_clone = @jack.deep_clone(:only => [:name, :nick_name])
45
- assert deep_clone.new_record?
46
- assert deep_clone.piastres, []
47
- assert deep_clone.save
48
- assert_equal @jack.name, deep_clone.name
49
- assert_equal @jack.nick_name, deep_clone.nick_name
50
- assert_nil deep_clone.age
51
- assert_nil deep_clone.ship_id
52
- assert_nil deep_clone.ship_type
53
- end
54
-
55
- def test_single_include_association
56
- deep_clone = @jack.deep_clone(:include => :mateys)
57
- assert deep_clone.new_record?
58
- assert deep_clone.save
59
- assert_equal 1, deep_clone.mateys.size
60
- end
61
-
62
- def test_single_include_belongs_to_polymorphic_association
63
- deep_clone = @jack.deep_clone(:include => :ship)
64
- assert deep_clone.new_record?
65
- assert deep_clone.save
66
- refute_nil deep_clone.ship
67
- refute_equal @jack.ship, deep_clone.ship
68
- end
69
-
70
- def test_single_include_has_many_polymorphic_association
71
- deep_clone = @ship.deep_clone(:include => :pirates)
72
- assert deep_clone.new_record?
73
- assert deep_clone.save
74
- assert deep_clone.pirates.any?
75
- end
76
-
77
- def test_multiple_include_association
78
- deep_clone = @jack.deep_clone(:include => [:mateys, :treasures])
79
- assert deep_clone.new_record?
80
- assert deep_clone.save
81
- assert_equal 1, deep_clone.mateys.size
82
- assert_equal 1, deep_clone.treasures.size
83
- end
84
-
85
- def test_deep_include_association
86
- deep_clone = @jack.deep_clone(:include => { :treasures => :gold_pieces })
87
- assert deep_clone.new_record?
88
- assert deep_clone.save
89
- assert_equal 1, deep_clone.treasures.size
90
- assert_equal 1, deep_clone.gold_pieces.size
91
- end
92
-
93
- def test_include_association_assignments
94
- deep_clone = @jack.deep_clone(:include => :treasures)
95
- assert deep_clone.new_record?
96
-
97
- deep_clone.treasures.each do |treasure|
98
- assert_equal deep_clone, treasure.pirate
99
- end
100
- end
101
-
102
- def test_include_association_assignments_with_inverse_of
103
- @jack.pirate_cages.build
104
- deep_clone = @jack.deep_clone(:include => :pirate_cages)
105
- assert deep_clone.new_record?
106
- deep_clone.pirate_cages.each do |cage|
107
- assert_equal deep_clone, cage.pirate
108
- end
109
- end
110
-
111
- def test_multiple_and_deep_include_association
112
- deep_clone = @jack.deep_clone(:include => { :treasures => :gold_pieces, :mateys => {} })
113
- assert deep_clone.new_record?
114
- assert deep_clone.save
115
- assert_equal 1, deep_clone.treasures.size
116
- assert_equal 1, deep_clone.gold_pieces.size
117
- assert_equal 1, deep_clone.mateys.size
118
- end
119
-
120
- def test_multiple_and_deep_include_association_with_array
121
- deep_clone = @jack.deep_clone(:include => [{ :treasures => :gold_pieces }, :mateys])
122
- assert deep_clone.new_record?
123
- assert deep_clone.save
124
- assert_equal 1, deep_clone.treasures.size
125
- assert_equal 1, deep_clone.gold_pieces.size
126
- assert_equal 1, deep_clone.mateys.size
127
- end
128
-
129
- def test_multiple_and_deep_include_association_with_array_and_multikey_hash
130
- deep_clone = @jack.deep_clone(:include => [:parrot, { :treasures => :gold_pieces, :mateys => {} }])
131
- assert deep_clone.new_record?
132
- assert deep_clone.save
133
- assert_equal 1, deep_clone.treasures.size
134
- assert_equal 1, deep_clone.gold_pieces.size
135
- assert_equal 1, deep_clone.mateys.size
136
- end
137
-
138
- def test_with_belongs_to_relation
139
- deep_clone = @jack.deep_clone(:include => :parrot)
140
- assert deep_clone.new_record?
141
- assert deep_clone.save
142
- refute_equal deep_clone.parrot, @jack.parrot
143
- end
144
-
145
- def test_should_pass_nested_exceptions
146
- deep_clone = @jack.deep_clone(:include => :parrot, :except => [:name, { :parrot => [:name] }])
147
- assert deep_clone.new_record?
148
- assert deep_clone.save
149
- refute_equal deep_clone.parrot, @jack.parrot
150
- assert_equal deep_clone.parrot.age, @jack.parrot.age
151
- refute_nil @jack.parrot.name
152
- assert_nil deep_clone.parrot.name
153
- end
154
-
155
- def test_should_pass_nested_exception_with_hash_value
156
- deep_clone = @jack.deep_clone(:include => :parrot, :except => { :parrot => [:name] })
157
- assert deep_clone.new_record?
158
- assert deep_clone.save
159
- refute_equal deep_clone.parrot, @jack.parrot
160
- assert_equal deep_clone.parrot.age, @jack.parrot.age
161
- refute_nil @jack.parrot.name
162
- assert_nil deep_clone.parrot.name
163
- end
164
-
165
- def test_should_pass_nested_onlinesses
166
- deep_clone = @jack.deep_clone(:include => :parrot, :only => [:name, { :parrot => [:name] }])
167
- assert deep_clone.new_record?
168
- assert deep_clone.piastres, []
169
- assert deep_clone.save
170
- refute_equal deep_clone.parrot, @jack.parrot
171
- assert_equal deep_clone.parrot.name, @jack.parrot.name
172
- assert_nil deep_clone.parrot.age
173
- end
174
-
175
- def test_should_pass_nested_onliness_with_hash_value
176
- deep_clone = @jack.deep_clone(:include => :parrot, :only => { :parrot => [:name] })
177
- assert deep_clone.new_record?
178
- assert deep_clone.piastres, []
179
- assert deep_clone.save
180
- refute_equal deep_clone.parrot, @jack.parrot
181
- assert_equal deep_clone.parrot.name, @jack.parrot.name
182
- assert_nil deep_clone.parrot.age
183
- end
184
-
185
- def test_should_not_double_deep_clone_when_using_dictionary
186
- current_matey_count = Matey.count
187
- deep_clone = @jack.deep_clone(:include => [:mateys, { :treasures => :matey }], :use_dictionary => true)
188
- assert deep_clone.new_record?
189
- deep_clone.save!
190
-
191
- assert_equal current_matey_count + 1, Matey.count
192
- end
193
-
194
- def test_should_not_double_deep_clone_when_using_manual_dictionary
195
- current_matey_count = Matey.count
196
-
197
- dict = { :mateys => {} }
198
- @jack.mateys.each { |m| dict[:mateys][m] = m.deep_clone }
199
-
200
- deep_clone = @jack.deep_clone(:include => [:mateys, { :treasures => :matey }], :dictionary => dict)
201
- assert deep_clone.new_record?
202
- deep_clone.save!
203
-
204
- assert_equal current_matey_count + 1, Matey.count
205
- end
206
-
207
- def test_should_support_ar_class_under_module
208
- @human = Animal::Human.create :name => 'Michael'
209
- @pig = Animal::Pig.create :human => @human, :name => 'big pig'
210
-
211
- deep_clone_human = @human.deep_clone(:include => [:pigs])
212
- assert deep_clone_human.new_record?
213
- assert deep_clone_human.save
214
- assert_equal 1, deep_clone_human.pigs.count
215
-
216
- @human2 = Animal::Human.create :name => 'John'
217
- @pig2 = @human2.pigs.create :name => 'small pig'
218
-
219
- deep_clone_human2 = @human.deep_clone(:include => [:pigs])
220
- assert deep_clone_human2.new_record?
221
- assert deep_clone_human2.save
222
- assert_equal 1, deep_clone_human2.pigs.count
223
- end
224
-
225
- def test_should_deep_clone_many_to_many_associations
226
- @human = Animal::Human.create :name => 'Michael'
227
- @human2 = Animal::Human.create :name => 'Jack'
228
- @chicken1 = Animal::Chicken.create :name => 'Chick1'
229
- @chicken2 = Animal::Chicken.create :name => 'Chick2'
230
- @human.chickens << [@chicken1, @chicken2]
231
- @human2.chickens << [@chicken1, @chicken2]
232
-
233
- deep_clone_human = @human.deep_clone(:include => :ownerships)
234
- assert deep_clone_human.new_record?
235
- assert deep_clone_human.save
236
- assert_equal 2, deep_clone_human.chickens.count
237
- end
238
-
239
- def test_should_skip_missing_associations
240
- @earth = Animal::Planet.create :name => 'Earth'
241
- @human = Animal::Human.create :name => 'Michael'
242
- @chicken = Animal::Chicken.create :name => 'Chick', :humans => [@human], :planet => @earth
243
- @dove = Animal::Dove.create :name => 'Dovey', :planet => @earth
244
-
245
- assert_raises ::DeepCloneable::AssociationNotFoundException do
246
- @earth.deep_clone(:include => { :birds => :ownerships })
247
- end
248
-
249
- deep_clone_earth = @earth.deep_clone(:include => { :birds => :ownerships }, :skip_missing_associations => true)
250
- assert_equal 2, deep_clone_earth.birds.size
251
- assert deep_clone_earth.birds.detect { |bird| bird.is_a?(Animal::Chicken) }.ownerships.any?
252
- end
253
-
254
- def test_should_deep_clone_with_block
255
- deep_clone = @jack.deep_clone(:include => :parrot) do |original, kopy|
256
- kopy.cloned_from_id = original.id
257
- end
258
-
259
- assert deep_clone.new_record?
260
- assert deep_clone.save
261
- assert_equal @jack.id, deep_clone.cloned_from_id
262
- assert_equal @jack.parrot.id, deep_clone.parrot.cloned_from_id
263
- end
264
-
265
- def test_should_deep_clone_habtm_associations
266
- @person1 = Person.create :name => 'Bill'
267
- @person2 = Person.create :name => 'Ted'
268
- @car1 = Car.create :name => 'Mustang'
269
- @car2 = Car.create :name => 'Camaro'
270
- @person1.cars << [@car1, @car2]
271
- @person2.cars << [@car1, @car2]
272
-
273
- deep_clone_person = @person1.deep_clone :include => :cars
274
-
275
- assert deep_clone_person.new_record?
276
- assert_equal [@person1, @person2, deep_clone_person], @car1.people
277
- assert_equal [@person1, @person2, deep_clone_person], @car2.people
278
-
279
- assert deep_clone_person.save
280
-
281
- # did NOT deep_clone the Car instances
282
- assert_equal 2, Car.all.count
283
-
284
- # did deep_clone the correct join table rows
285
- assert_equal @person1.cars, deep_clone_person.cars
286
- assert_equal 2, deep_clone_person.cars.count
287
- end
288
-
289
- def test_should_deep_clone_habtm_associations_with_missing_reverse_association
290
- @coin = Coin.create :value => 1
291
- @person = Person.create :name => 'Bill'
292
- @coin.people << @person
293
-
294
- deep_clone = @coin.deep_clone :include => :people
295
- assert deep_clone.new_record?
296
- assert_equal [@person], @coin.people
297
- assert deep_clone.save
298
- end
299
-
300
- def test_should_deep_clone_joined_association
301
- subject1 = Subject.create(:name => 'subject 1')
302
- subject2 = Subject.create(:name => 'subject 2')
303
- student = Student.create(:name => 'Parent', :subjects => [subject1, subject2])
304
-
305
- deep_clone = student.deep_clone :include => { :student_assignments => :subject }
306
- deep_clone.save # Subjects will have been set after save
307
- assert_equal 2, deep_clone.subjects.size
308
- [subject1, subject2].each { |subject| assert !deep_clone.subjects.include?(subject) }
309
- end
310
-
311
- def test_parent_validations_run_on_save_after_clone
312
- child = ChildWithValidation.create :name => 'Jimmy'
313
- parent = ParentWithValidation.new :children => [child]
314
- parent.save :validate => false
315
-
316
- deep_clone_parent = parent.deep_clone :include => :children
317
-
318
- assert !deep_clone_parent.save
319
- assert deep_clone_parent.new_record?
320
- assert !deep_clone_parent.valid?
321
- assert deep_clone_parent.children.first.valid?
322
- assert_equal deep_clone_parent.errors.messages, :name => ["can't be blank"]
323
- end
324
-
325
- def test_parent_validations_dont_run_on_save_after_clone
326
- child = ChildWithValidation.create :name => 'Jimmy'
327
- parent = ParentWithValidation.new :children => [child]
328
- parent.save :validate => false
329
-
330
- deep_clone_parent = parent.deep_clone :include => :children, :validate => false
331
-
332
- assert deep_clone_parent.save
333
- assert !deep_clone_parent.new_record?
334
- assert !deep_clone_parent.valid?
335
- assert deep_clone_parent.children.first.valid?
336
- assert_equal deep_clone_parent.errors.messages, :name => ["can't be blank"]
337
- end
338
-
339
- def test_child_validations_run_on_save_after_clone
340
- child = ChildWithValidation.new
341
- child.save :validate => false
342
- parent = ParentWithValidation.create :name => 'John', :children => [child]
343
-
344
- deep_clone_parent = parent.deep_clone :include => :children
345
-
346
- assert !deep_clone_parent.save
347
- assert deep_clone_parent.new_record?
348
- assert !deep_clone_parent.valid?
349
- assert !deep_clone_parent.children.first.valid?
350
- assert_equal deep_clone_parent.errors.messages, :children => ['is invalid']
351
- end
352
-
353
- def test_child_validations_dont_run_on_save_after_clone_without_validation
354
- child = ChildWithValidation.new
355
- child.save :validate => false
356
- parent = ParentWithValidation.create :name => 'John', :children => [child]
357
-
358
- deep_clone_parent = parent.deep_clone :include => :children, :validate => false
359
- deep_clone_child = deep_clone_parent.children.first
360
-
361
- assert deep_clone_parent.save
362
- assert !deep_clone_parent.new_record?
363
- assert !deep_clone_child.new_record?
364
- assert !deep_clone_child.valid?
365
- assert_equal deep_clone_child.errors.messages, :name => ["can't be blank"]
366
- end
367
-
368
- def test_self_join_has_many
369
- parent_part = Part.create(:name => 'Parent')
370
- Part.create(:name => 'Child 1', :parent_part_id => parent_part.id)
371
- Part.create(:name => 'Child 2', :parent_part_id => parent_part.id)
372
-
373
- deep_clone_part = parent_part.deep_clone :include => :child_parts
374
- assert deep_clone_part.save
375
- assert_equal 2, deep_clone_part.child_parts.size
376
- end
377
-
378
- def test_should_include_has_many_through_associations
379
- subject1 = Subject.create(:name => 'subject 1')
380
- subject2 = Subject.create(:name => 'subject 2')
381
- student = Student.create(:name => 'Parent', :subjects => [subject1, subject2])
382
-
383
- deep_clone = student.deep_clone :include => :subjects
384
- assert_equal 2, deep_clone.subjects.size
385
- assert_equal [[student, deep_clone], [student, deep_clone]], deep_clone.subjects.map(&:students)
386
- end
387
-
388
- def test_should_include_has_one_through_associations
389
- organization = Organization.create(:name => 'organization')
390
- contractor = Contractor.create(:name => 'contractor')
391
- Contract.create(:number => 12_345, :contractor => contractor, :organization => organization)
392
-
393
- deep_clone = organization.deep_clone(:include => :contractor)
394
- assert_equal organization.contractor, deep_clone.contractor
395
- end
396
-
397
- def test_should_deep_clone_unsaved_objects
398
- jack = Pirate.new(:name => 'Jack Sparrow', :nick_name => 'Captain Jack', :age => 30)
399
- jack.mateys.build(:name => 'John')
400
-
401
- deep_clone = jack.deep_clone(:include => :mateys)
402
- assert deep_clone.new_record?
403
- assert_equal 1, deep_clone.mateys.size
404
- assert_equal 'John', deep_clone.mateys.first.name
405
- end
406
-
407
- def test_should_reject_copies_if_conditionals_are_passed
408
- subject1 = Subject.create(:name => 'subject 1')
409
- subject2 = Subject.create(:name => 'subject 2')
410
- student = Student.create(:name => 'Parent', :subjects => [subject1, subject2])
411
-
412
- deep_clone = student.deep_clone :include => { :subjects => { :if => lambda { |subject| subject.name == 'subject 2' } } }
413
- assert_equal 1, deep_clone.subjects.size
414
- assert_equal 'subject 2', deep_clone.subjects.first.name
415
-
416
- deep_clone = @jack.deep_clone(:include => {
417
- :treasures => { :gold_pieces => { :unless => lambda { |piece| piece.is_a?(Parrot) } } },
418
- :mateys => { :if => lambda { |matey| matey.is_a?(GoldPiece) } }
419
- })
420
-
421
- assert deep_clone.new_record?
422
- assert deep_clone.save
423
- assert_equal 1, deep_clone.treasures.size
424
- assert_equal 1, deep_clone.gold_pieces.size
425
- assert_equal 0, deep_clone.mateys.size
426
- end
427
-
428
- def test_should_properly_read_conditions_in_arrays
429
- subject1 = Subject.create(:name => 'subject 1')
430
- subject2 = Subject.create(:name => 'subject 2')
431
- student = Student.create(:name => 'Parent', :subjects => [subject1, subject2])
432
-
433
- deep_clone = student.deep_clone(:include => [:subjects => [:if => lambda { |_subject| false }]])
434
- assert deep_clone.subjects.none?
435
-
436
- deep_clone = student.deep_clone(:include => [:subjects => [:if => lambda { |_subject| true }]])
437
- assert_equal 2, deep_clone.subjects.size
438
- end
439
-
440
- def test_should_set_association_to_nil_if_conditionals_fail
441
- deep_clone = @jack.deep_clone(:include => { :ship => { :unless => lambda { |ship| ship.name == 'Black Pearl' } } })
442
- assert_nil deep_clone.ship
443
- end
444
-
445
- def test_should_reject_copies_if_conditionals_are_passed_with_associations
446
- deep_clone = @ship.deep_clone(:include => [:pirates => [:treasures, :mateys, { :unless => lambda { |pirate| pirate.name == 'Jack Sparrow' } }]])
447
-
448
- assert deep_clone.new_record?
449
- assert deep_clone.save
450
- assert_equal 0, deep_clone.pirates.size
451
-
452
- deep_clone = @ship.deep_clone(:include => [:pirates => [:treasures, :mateys, { :if => lambda { |pirate| pirate.name == 'Jack Sparrow' } }]])
453
- assert deep_clone.new_record?
454
- assert deep_clone.save
455
- assert_equal 1, deep_clone.pirates.size
456
- end
457
-
458
- def test_should_reject_copies_if_conditionals_are_passed_with_nested_many_to_many_associations
459
- @user = User.create :name => 'Jack'
460
- @order1 = Order.create
461
- @order2 = Order.create
462
- @product1 = Product.create :name => 'Paper'
463
- @product2 = Product.create :name => 'Ink'
464
- @order2.products << [@product1, @product2]
465
- @user.orders << [@order1, @order2]
466
-
467
- deep_clone = @user.deep_clone(:include => [:orders => [:products => [{ :unless => lambda { |product| product.name == 'Ink' } }]]])
468
-
469
- assert deep_clone.new_record?
470
- assert deep_clone.save
471
- assert_equal 1, deep_clone.orders.second.products.size
472
-
473
- deep_clone = @user.deep_clone(:include => [:orders => [:products => [{ :if => lambda { |product| product.name == 'Ink' } }]]])
474
- assert deep_clone.new_record?
475
- assert deep_clone.save
476
- assert_equal 1, deep_clone.orders.second.products.size
477
- end
478
-
479
- def test_should_find_in_dict_for_habtm
480
- apt = Apartment.create(:number => '101')
481
- contractor = Contractor.create(:name => 'contractor', :apartments => [apt])
482
-
483
- apt.contractors = [contractor]
484
- apt.save!
485
-
486
- building = Building.create(:name => 'Tall Building', :contractors => [contractor], :apartments => [apt])
487
-
488
- deep_clone = building.deep_clone(:include => [
489
- :apartments,
490
- {
491
- :contractors => [
492
- :apartments
493
- ]
494
- }
495
- ],
496
- :use_dictionary => true)
497
-
498
- deep_clone.save!
499
-
500
- assert_equal deep_clone.contractors.first.apartments.first.id, deep_clone.apartments.first.id
501
- assert_equal deep_clone.apartments.first.contractors.first.id, deep_clone.contractors.first.id
502
- end
503
-
504
- def test_should_not_make_attributes_dirty_for_exceptions
505
- deep_clone = @jack.deep_clone(:except => :name)
506
- assert_nil deep_clone.name
507
- refute deep_clone.name_changed?
508
- end
509
- end