mongo_nested_set 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/rails/init.rb ADDED
@@ -0,0 +1,3 @@
1
+ require "mongo_nested_set"
2
+
3
+ MongoMapper::Document.append_inclusions MongoNestedSet
@@ -0,0 +1,19 @@
1
+ class Category
2
+ include MongoMapper::Document
3
+
4
+ acts_as_nested_set
5
+
6
+ key :organization_id, String
7
+
8
+ def to_s
9
+ name
10
+ end
11
+
12
+ def recurse &block
13
+ block.call self, lambda{
14
+ self.children.each do |child|
15
+ child.recurse &block
16
+ end
17
+ }
18
+ end
19
+ end
@@ -0,0 +1,795 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class CategoryFixture
4
+ include MongoMapper::Document
5
+ set_collection_name 'categories'
6
+ end
7
+ class DepartmentFixture
8
+ include MongoMapper::Document
9
+ set_collection_name 'departments'
10
+ end
11
+ class NoteFixture
12
+ include MongoMapper::Document
13
+ set_collection_name 'notes'
14
+ end
15
+
16
+ class Note
17
+ include MongoMapper::Document
18
+ acts_as_nested_set :scope => [:notable_id, :notable_type]
19
+ end
20
+ class Default
21
+ include MongoMapper::Document
22
+ acts_as_nested_set
23
+ set_collection_name 'categories'
24
+ end
25
+ class ScopedCategory
26
+ include MongoMapper::Document
27
+ key :organization_id, String
28
+
29
+ acts_as_nested_set :scope => :organization
30
+ set_collection_name 'categories'
31
+ end
32
+ class RenamedColumns
33
+ include MongoMapper::Document
34
+ acts_as_nested_set :parent_column => 'mother_id', :left_column => 'red', :right_column => 'black'
35
+ end
36
+ class Department
37
+ include MongoMapper::Document
38
+ acts_as_nested_set
39
+ end
40
+
41
+ class AwesomeNestedSetTest < TestCaseClass
42
+ def setup
43
+ MongoMapper.database.collections.each(&:drop)
44
+ MongoMapper.database.create_collection "categories"
45
+
46
+ create_category :top_level, { :name => "Top Level", :lft => 1, :rgt => 10 }
47
+ create_category :child_1, { :name => "Child 1", :parent_id => categories(:top_level).id, :lft => 2, :rgt => 3 }
48
+ create_category :child_2, { :name => "Child 2", :parent_id => categories(:top_level).id, :lft => 4, :rgt => 7 }
49
+ create_category :child_2_1, { :name => "Child 2.1", :parent_id => categories(:child_2).id, :lft => 5, :rgt => 6 }
50
+ create_category :child_3, { :name => "Child 3", :parent_id => categories(:top_level).id, :lft => 8, :rgt => 9 }
51
+ create_category :top_level_2, { :name => "Top Level 2", :lft => 11, :rgt => 12 }
52
+ create_department :top, { :name => "Top" }
53
+ create_note :scope1, { :body => "Top Level", :lft => 1, :rgt => 10, :notable_id => categories(:top_level).id, :notable_type => "Category" }
54
+ create_note :scope1, { :body => "Top Level", :lft => 1, :rgt => 10, :notable_id => categories(:top_level).id, :notable_type => "Category" }
55
+ create_note :child_1, { :body => "Child 1", :parent_id => notes(:scope1).id, :lft => 2, :rgt => 3, :notable_id => categories(:top_level).id, :notable_type => "Category" }
56
+ create_note :child_2, { :body => "Child 2", :parent_id => notes(:scope1).id, :lft => 4, :rgt => 7, :notable_id => categories(:top_level).id, :notable_type => "Category" }
57
+ create_note :child_3, { :body => "Child 3", :parent_id => notes(:scope1).id, :lft => 8, :rgt => 9, :notable_id => categories(:top_level).id, :notable_type => "Category" }
58
+ create_note :scope2, { :body => "Top Level 2", :lft => 1, :rgt => 2, :notable_id => departments(:top).id, :notable_type => "Departments" }
59
+ end
60
+
61
+ def create_fixture(type, key, options = {})
62
+ @fixtures ||= {}
63
+ @fixtures[type] ||= {}
64
+ dummy = "#{type}_fixture".classify.constantize.create(options)
65
+ @fixtures[type][key] = type.to_s.classify.constantize.find dummy.id
66
+ end
67
+
68
+ def create_category(key, options = {})
69
+ create_fixture :category, key, options
70
+ end
71
+
72
+ def categories(key)
73
+ @fixtures[:category][key]
74
+ end
75
+
76
+ def create_department(key, options = {})
77
+ create_fixture :department, key, options
78
+ end
79
+
80
+ def departments(key)
81
+ @fixtures[:department][key]
82
+ end
83
+
84
+ def create_note(key, options = {})
85
+ create_fixture :note, key, options
86
+ end
87
+
88
+ def notes(key)
89
+ @fixtures[:note][key]
90
+ end
91
+
92
+ def test_left_column_default
93
+ assert_equal 'lft', Default.acts_as_nested_set_options[:left_column]
94
+ end
95
+
96
+ def test_right_column_default
97
+ assert_equal 'rgt', Default.acts_as_nested_set_options[:right_column]
98
+ end
99
+
100
+ def test_parent_column_default
101
+ assert_equal 'parent_id', Default.acts_as_nested_set_options[:parent_column]
102
+ end
103
+
104
+ def test_scope_default
105
+ assert_nil Default.acts_as_nested_set_options[:scope]
106
+ end
107
+
108
+ def test_left_column_name
109
+ assert_equal 'lft', Default.left_column_name
110
+ assert_equal 'lft', Default.new.left_column_name
111
+ assert_equal 'red', RenamedColumns.left_column_name
112
+ assert_equal 'red', RenamedColumns.new.left_column_name
113
+ end
114
+
115
+ def test_right_column_name
116
+ assert_equal 'rgt', Default.right_column_name
117
+ assert_equal 'rgt', Default.new.right_column_name
118
+ assert_equal 'black', RenamedColumns.right_column_name
119
+ assert_equal 'black', RenamedColumns.new.right_column_name
120
+ end
121
+
122
+ def test_parent_column_name
123
+ assert_equal 'parent_id', Default.parent_column_name
124
+ assert_equal 'parent_id', Default.new.parent_column_name
125
+ assert_equal 'mother_id', RenamedColumns.parent_column_name
126
+ assert_equal 'mother_id', RenamedColumns.new.parent_column_name
127
+ end
128
+
129
+ def test_creation_with_altered_column_names
130
+ assert_nothing_raised do
131
+ RenamedColumns.create!()
132
+ end
133
+ end
134
+
135
+ def test_scoped_appends_id
136
+ assert_equal :organization_id, ScopedCategory.acts_as_nested_set_options[:scope]
137
+ end
138
+
139
+ def test_roots_class_method
140
+ assert_equal Category.find_all_by_parent_id(nil), Category.roots
141
+ end
142
+
143
+ def test_root_class_method
144
+ assert_equal categories(:top_level), Category.root
145
+ end
146
+
147
+ def test_root
148
+ assert_equal categories(:top_level), categories(:child_3).root
149
+ end
150
+
151
+ def test_root?
152
+ assert categories(:top_level).root?
153
+ assert categories(:top_level_2).root?
154
+ end
155
+
156
+ # def test_leaves_class_method
157
+ # assert_equal Category.find(:all, :conditions => "#{Category.right_column_name} - #{Category.left_column_name} = 1"), Category.leaves
158
+ # assert_equal Category.leaves.count, 4
159
+ # assert (Category.leaves.include? categories(:child_1))
160
+ # assert (Category.leaves.include? categories(:child_2_1))
161
+ # assert (Category.leaves.include? categories(:child_3))
162
+ # assert (Category.leaves.include? categories(:top_level_2))
163
+ # end
164
+
165
+ def test_leaf
166
+ assert categories(:child_1).leaf?
167
+ assert categories(:child_2_1).leaf?
168
+ assert categories(:child_3).leaf?
169
+ assert categories(:top_level_2).leaf?
170
+
171
+ assert !categories(:top_level).leaf?
172
+ assert !categories(:child_2).leaf?
173
+ assert !Category.new.leaf?
174
+ end
175
+
176
+ def test_parent
177
+ assert_equal categories(:child_2), categories(:child_2_1).parent
178
+ end
179
+
180
+ def test_self_and_ancestors
181
+ child = categories(:child_2_1)
182
+ self_and_ancestors = [categories(:top_level), categories(:child_2), child]
183
+ assert_equal self_and_ancestors, child.self_and_ancestors
184
+ end
185
+
186
+ def test_ancestors
187
+ child = categories(:child_2_1)
188
+ ancestors = [categories(:top_level), categories(:child_2)]
189
+ assert_equal ancestors, child.ancestors
190
+ end
191
+
192
+ def test_self_and_siblings
193
+ child = categories(:child_2)
194
+ self_and_siblings = [categories(:child_1), child, categories(:child_3)]
195
+ assert_equal self_and_siblings, child.self_and_siblings
196
+ assert_nothing_raised do
197
+ tops = [categories(:top_level), categories(:top_level_2)]
198
+ assert_equal tops, categories(:top_level).self_and_siblings
199
+ end
200
+ end
201
+
202
+ def test_siblings
203
+ child = categories(:child_2)
204
+ siblings = [categories(:child_1), categories(:child_3)]
205
+ assert_equal siblings, child.siblings
206
+ end
207
+
208
+ #
209
+ # def test_leaves
210
+ # leaves = [categories(:child_1), categories(:child_2_1), categories(:child_3), categories(:top_level_2)]
211
+ # assert categories(:top_level).leaves, leaves
212
+ # end
213
+ #
214
+ def test_level
215
+ assert_equal 0, categories(:top_level).level
216
+ assert_equal 1, categories(:child_1).level
217
+ assert_equal 2, categories(:child_2_1).level
218
+ end
219
+
220
+ def test_has_children?
221
+ assert categories(:child_2_1).children.empty?
222
+ assert !categories(:child_2).children.empty?
223
+ assert !categories(:top_level).children.empty?
224
+ end
225
+
226
+ def test_self_and_descendents
227
+ parent = categories(:top_level)
228
+ self_and_descendants = [parent, categories(:child_1), categories(:child_2),
229
+ categories(:child_2_1), categories(:child_3)]
230
+ assert_equal self_and_descendants, parent.self_and_descendants
231
+ assert_equal self_and_descendants, parent.self_and_descendants.count
232
+ end
233
+
234
+ def test_descendents
235
+ lawyers = Category.create!(:name => "lawyers")
236
+ us = Category.create!(:name => "United States")
237
+ us.move_to_child_of(lawyers)
238
+ assert_not_nil us.lft
239
+ assert_not_nil us.rgt
240
+ patent = Category.create!(:name => "Patent Law")
241
+ patent.move_to_child_of(us)
242
+ lawyers.reload
243
+
244
+ assert_equal 1, lawyers.children.size
245
+ assert_equal 1, us.children.size
246
+ assert_equal 2, lawyers.descendants.size
247
+ end
248
+
249
+ def test_self_and_descendents
250
+ parent = categories(:top_level)
251
+ descendants = [categories(:child_1), categories(:child_2),
252
+ categories(:child_2_1), categories(:child_3)]
253
+ assert_equal descendants, parent.descendants
254
+ end
255
+
256
+ def test_children
257
+ category = categories(:top_level)
258
+ category.children.each {|c| assert_equal category.id, c.parent_id }
259
+ end
260
+
261
+ def test_order_of_children
262
+ categories(:child_2).move_left
263
+ assert_equal categories(:child_2), categories(:top_level).children[0]
264
+ assert_equal categories(:child_1), categories(:top_level).children[1]
265
+ assert_equal categories(:child_3), categories(:top_level).children[2]
266
+ end
267
+
268
+ def test_is_or_is_ancestor_of?
269
+ assert categories(:top_level).is_or_is_ancestor_of?(categories(:child_1))
270
+ assert categories(:top_level).is_or_is_ancestor_of?(categories(:child_2_1))
271
+ assert categories(:child_2).is_or_is_ancestor_of?(categories(:child_2_1))
272
+ assert !categories(:child_2_1).is_or_is_ancestor_of?(categories(:child_2))
273
+ assert !categories(:child_1).is_or_is_ancestor_of?(categories(:child_2))
274
+ assert categories(:child_1).is_or_is_ancestor_of?(categories(:child_1))
275
+ end
276
+
277
+ def test_is_ancestor_of?
278
+ assert categories(:top_level).is_ancestor_of?(categories(:child_1))
279
+ assert categories(:top_level).is_ancestor_of?(categories(:child_2_1))
280
+ assert categories(:child_2).is_ancestor_of?(categories(:child_2_1))
281
+ assert !categories(:child_2_1).is_ancestor_of?(categories(:child_2))
282
+ assert !categories(:child_1).is_ancestor_of?(categories(:child_2))
283
+ assert !categories(:child_1).is_ancestor_of?(categories(:child_1))
284
+ end
285
+
286
+ def test_is_or_is_ancestor_of_with_scope
287
+ root = ScopedCategory.root
288
+ child = root.children.first
289
+ assert root.is_or_is_ancestor_of?(child)
290
+ child.update_attributes :organization_id => 'different'
291
+ assert !root.is_or_is_ancestor_of?(child)
292
+ end
293
+
294
+ def test_is_or_is_descendant_of?
295
+ assert categories(:child_1).is_or_is_descendant_of?(categories(:top_level))
296
+ assert categories(:child_2_1).is_or_is_descendant_of?(categories(:top_level))
297
+ assert categories(:child_2_1).is_or_is_descendant_of?(categories(:child_2))
298
+ assert !categories(:child_2).is_or_is_descendant_of?(categories(:child_2_1))
299
+ assert !categories(:child_2).is_or_is_descendant_of?(categories(:child_1))
300
+ assert categories(:child_1).is_or_is_descendant_of?(categories(:child_1))
301
+ end
302
+
303
+ def test_is_descendant_of?
304
+ assert categories(:child_1).is_descendant_of?(categories(:top_level))
305
+ assert categories(:child_2_1).is_descendant_of?(categories(:top_level))
306
+ assert categories(:child_2_1).is_descendant_of?(categories(:child_2))
307
+ assert !categories(:child_2).is_descendant_of?(categories(:child_2_1))
308
+ assert !categories(:child_2).is_descendant_of?(categories(:child_1))
309
+ assert !categories(:child_1).is_descendant_of?(categories(:child_1))
310
+ end
311
+
312
+ def test_is_or_is_descendant_of_with_scope
313
+ root = ScopedCategory.root
314
+ child = root.children.first
315
+ assert child.is_or_is_descendant_of?(root)
316
+ child.update_attributes :organization_id => 'different'
317
+ assert !child.is_or_is_descendant_of?(root)
318
+ end
319
+
320
+ def test_same_scope?
321
+ root = ScopedCategory.root
322
+ child = root.children.first
323
+ assert child.same_scope?(root)
324
+ child.update_attributes :organization_id => 'different'
325
+ assert !child.same_scope?(root)
326
+ end
327
+
328
+ def test_left_sibling
329
+ assert_equal categories(:child_1), categories(:child_2).left_sibling
330
+ assert_equal categories(:child_2), categories(:child_3).left_sibling
331
+ end
332
+
333
+ def test_left_sibling_of_root
334
+ assert_nil categories(:top_level).left_sibling
335
+ end
336
+
337
+ def test_left_sibling_without_siblings
338
+ assert_nil categories(:child_2_1).left_sibling
339
+ end
340
+
341
+ def test_left_sibling_of_leftmost_node
342
+ assert_nil categories(:child_1).left_sibling
343
+ end
344
+
345
+ def test_right_sibling
346
+ assert_equal categories(:child_3), categories(:child_2).right_sibling
347
+ assert_equal categories(:child_2), categories(:child_1).right_sibling
348
+ end
349
+
350
+ def test_right_sibling_of_root
351
+ assert_equal categories(:top_level_2), categories(:top_level).right_sibling
352
+ assert_nil categories(:top_level_2).right_sibling
353
+ end
354
+
355
+ def test_right_sibling_without_siblings
356
+ assert_nil categories(:child_2_1).right_sibling
357
+ end
358
+
359
+ def test_right_sibling_of_rightmost_node
360
+ assert_nil categories(:child_3).right_sibling
361
+ end
362
+
363
+ def test_move_left
364
+ categories(:child_2).move_left
365
+ assert_nil categories(:child_2).left_sibling
366
+ assert_equal categories(:child_1), categories(:child_2).right_sibling
367
+ assert Category.valid?
368
+ end
369
+
370
+ def test_move_right
371
+ categories(:child_2).move_right
372
+ assert_nil categories(:child_2).right_sibling
373
+ assert_equal categories(:child_3), categories(:child_2).left_sibling
374
+ assert Category.valid?
375
+ end
376
+
377
+ def test_move_to_left_of
378
+ categories(:child_3).move_to_left_of(categories(:child_1))
379
+ assert_nil categories(:child_3).left_sibling
380
+ assert_equal categories(:child_1), categories(:child_3).right_sibling
381
+ assert Category.valid?
382
+ end
383
+
384
+ def test_move_to_right_of
385
+ categories(:child_1).move_to_right_of(categories(:child_3))
386
+ assert_nil categories(:child_1).right_sibling
387
+ assert_equal categories(:child_3), categories(:child_1).left_sibling
388
+ assert Category.valid?
389
+ end
390
+
391
+ def test_move_to_root
392
+ categories(:child_2).move_to_root
393
+ assert_nil categories(:child_2).parent
394
+ assert_equal 0, categories(:child_2).level
395
+ assert_equal 1, categories(:child_2_1).level
396
+ assert_equal 1, categories(:child_2).left
397
+ assert_equal 4, categories(:child_2).right
398
+ assert Category.valid?
399
+ end
400
+
401
+ def test_move_to_child_of
402
+ categories(:child_1).move_to_child_of(categories(:child_3))
403
+ assert_equal categories(:child_3).id, categories(:child_1).parent_id
404
+ assert Category.valid?
405
+ end
406
+
407
+ def test_move_to_child_of_appends_to_end
408
+ child = Category.create! :name => 'New Child'
409
+ child.move_to_child_of categories(:top_level)
410
+ assert_equal child, categories(:top_level).children.last
411
+ end
412
+
413
+ def test_subtree_move_to_child_of
414
+ assert_equal 4, categories(:child_2).left
415
+ assert_equal 7, categories(:child_2).right
416
+
417
+ assert_equal 2, categories(:child_1).left
418
+ assert_equal 3, categories(:child_1).right
419
+
420
+ categories(:child_2).move_to_child_of(categories(:child_1))
421
+ assert Category.valid?
422
+ assert_equal categories(:child_1).id, categories(:child_2).parent_id
423
+
424
+ assert_equal 3, categories(:child_2).left
425
+ assert_equal 6, categories(:child_2).right
426
+ assert_equal 2, categories(:child_1).left
427
+ assert_equal 7, categories(:child_1).right
428
+ end
429
+
430
+ def test_slightly_difficult_move_to_child_of
431
+ assert_equal 11, categories(:top_level_2).left
432
+ assert_equal 12, categories(:top_level_2).right
433
+
434
+ # create a new top-level node and move single-node top-level tree inside it.
435
+ new_top = Category.create(:name => 'New Top')
436
+ assert_equal 13, new_top.left
437
+ assert_equal 14, new_top.right
438
+
439
+ categories(:top_level_2).move_to_child_of(new_top)
440
+
441
+ assert Category.valid?
442
+ assert_equal new_top.id, categories(:top_level_2).parent_id
443
+
444
+ assert_equal 12, categories(:top_level_2).left
445
+ assert_equal 13, categories(:top_level_2).right
446
+ assert_equal 11, new_top.left
447
+ assert_equal 14, new_top.right
448
+ end
449
+
450
+ def test_difficult_move_to_child_of
451
+ assert_equal 1, categories(:top_level).left
452
+ assert_equal 10, categories(:top_level).right
453
+ assert_equal 5, categories(:child_2_1).left
454
+ assert_equal 6, categories(:child_2_1).right
455
+
456
+ # create a new top-level node and move an entire top-level tree inside it.
457
+ new_top = Category.create(:name => 'New Top')
458
+ categories(:top_level).move_to_child_of(new_top)
459
+ categories(:child_2_1).reload
460
+ assert Category.valid?
461
+ assert_equal new_top.id, categories(:top_level).parent_id
462
+
463
+ assert_equal 4, categories(:top_level).left
464
+ assert_equal 13, categories(:top_level).right
465
+ assert_equal 8, categories(:child_2_1).left
466
+ assert_equal 9, categories(:child_2_1).right
467
+ end
468
+
469
+ #rebuild swaps the position of the 2 children when added using move_to_child twice onto same parent
470
+ def test_move_to_child_more_than_once_per_parent_rebuild
471
+ root1 = Category.create(:name => 'Root1')
472
+ root2 = Category.create(:name => 'Root2')
473
+ root3 = Category.create(:name => 'Root3')
474
+
475
+ root2.move_to_child_of root1
476
+ root3.move_to_child_of root1
477
+
478
+ output = Category.roots.last.to_text
479
+ Category.collection.update({}, { :lft => nil, :rgt => nil }, :multi => true)
480
+ Category.rebuild!
481
+
482
+ assert_equal Category.roots.last.to_text, output
483
+ end
484
+
485
+ # doing move_to_child twice onto same parent from the furthest right first
486
+ def test_move_to_child_more_than_once_per_parent_outside_in
487
+ node1 = Category.create(:name => 'Node-1')
488
+ node2 = Category.create(:name => 'Node-2')
489
+ node3 = Category.create(:name => 'Node-3')
490
+
491
+ node2.move_to_child_of node1
492
+ node3.move_to_child_of node1
493
+
494
+ output = Category.roots.last.to_text
495
+ Category.collection.update({}, { :lft => nil, :rgt => nil }, :multi => true)
496
+ Category.rebuild!
497
+
498
+ assert_equal Category.roots.last.to_text, output
499
+ end
500
+
501
+ # def test_valid_with_null_lefts
502
+ # assert Category.valid?
503
+ # Category.collection.update({}, { :lft => nil }, :multi => true)
504
+ # assert !Category.valid?
505
+ # end
506
+ #
507
+ # def test_valid_with_null_rights
508
+ # assert Category.valid?
509
+ # Category.collection.update({}, { :rgt => nil }, :multi => true)
510
+ # assert !Category.valid?
511
+ # end
512
+
513
+ def test_valid_with_missing_intermediate_node
514
+ # Even though child_2_1 will still exist, it is a sign of a sloppy delete, not an invalid tree.
515
+ assert Category.valid?
516
+ Category.delete(categories(:child_2).id)
517
+ assert Category.valid?
518
+ end
519
+
520
+ def test_valid_with_overlapping_and_rights
521
+ assert Category.valid?
522
+ categories(:top_level_2)['lft'] = 0
523
+ categories(:top_level_2).save
524
+ assert !Category.valid?
525
+ end
526
+
527
+ def test_rebuild
528
+ assert Category.valid?
529
+ before_text = Category.root.to_text
530
+ Category.collection.update({}, { :lft => nil, :rgt => nil }, :multi => true)
531
+ Category.rebuild!
532
+ assert Category.valid?
533
+ assert_equal before_text, Category.root.to_text
534
+ end
535
+
536
+ def test_move_possible_for_sibling
537
+ assert categories(:child_2).move_possible?(categories(:child_1))
538
+ end
539
+
540
+ def test_move_not_possible_to_self
541
+ assert !categories(:top_level).move_possible?(categories(:top_level))
542
+ end
543
+
544
+ def test_move_not_possible_to_parent
545
+ categories(:top_level).descendants.each do |descendant|
546
+ assert !categories(:top_level).move_possible?(descendant)
547
+ assert descendant.move_possible?(categories(:top_level))
548
+ end
549
+ end
550
+
551
+ def test_is_or_is_ancestor_of?
552
+ [:child_1, :child_2, :child_2_1, :child_3].each do |c|
553
+ assert categories(:top_level).is_or_is_ancestor_of?(categories(c))
554
+ end
555
+ assert !categories(:top_level).is_or_is_ancestor_of?(categories(:top_level_2))
556
+ end
557
+
558
+ def test_left_and_rights_valid_with_blank_left
559
+ assert Category.left_and_rights_valid?
560
+ categories(:child_2)[:lft] = nil
561
+ categories(:child_2).save(:validate => false)
562
+ assert !Category.left_and_rights_valid?
563
+ end
564
+
565
+ def test_left_and_rights_valid_with_blank_right
566
+ assert Category.left_and_rights_valid?
567
+ categories(:child_2)[:rgt] = nil
568
+ categories(:child_2).save(:validate => false)
569
+ assert !Category.left_and_rights_valid?
570
+ end
571
+
572
+ def test_left_and_rights_valid_with_equal
573
+ assert Category.left_and_rights_valid?
574
+ categories(:top_level_2)[:lft] = categories(:top_level_2)[:rgt]
575
+ categories(:top_level_2).save(:validate => false)
576
+ assert !Category.left_and_rights_valid?
577
+ end
578
+
579
+ def test_left_and_rights_valid_with_left_equal_to_parent
580
+ assert Category.left_and_rights_valid?
581
+ categories(:child_2)[:lft] = categories(:top_level)[:lft]
582
+ categories(:child_2).save(:validate => false)
583
+ assert !Category.left_and_rights_valid?
584
+ end
585
+
586
+ def test_left_and_rights_valid_with_right_equal_to_parent
587
+ assert Category.left_and_rights_valid?
588
+ categories(:child_2)[:rgt] = categories(:top_level)[:rgt]
589
+ categories(:child_2).save(:validate => false)
590
+ assert !Category.left_and_rights_valid?
591
+ end
592
+
593
+ def test_moving_dirty_objects_doesnt_invalidate_tree
594
+ r1 = Category.create
595
+ r2 = Category.create
596
+ r3 = Category.create
597
+ r4 = Category.create
598
+ nodes = [r1, r2, r3, r4]
599
+
600
+ r2.move_to_child_of(r1)
601
+ assert Category.valid?
602
+
603
+ r3.move_to_child_of(r1)
604
+ assert Category.valid?
605
+
606
+ r4.move_to_child_of(r2)
607
+ assert Category.valid?
608
+ end
609
+
610
+ def test_multi_scoped_no_duplicates_for_columns?
611
+ assert_nothing_raised do
612
+ Note.no_duplicates_for_columns?
613
+ end
614
+ end
615
+
616
+ def test_multi_scoped_all_roots_valid?
617
+ assert_nothing_raised do
618
+ Note.all_roots_valid?
619
+ end
620
+ end
621
+
622
+ def test_multi_scoped
623
+ note1 = Note.create!(:body => "A", :notable_id => 2, :notable_type => 'Category')
624
+ note2 = Note.create!(:body => "B", :notable_id => 2, :notable_type => 'Category')
625
+ note3 = Note.create!(:body => "C", :notable_id => 2, :notable_type => 'Default')
626
+
627
+ assert_equal [note1, note2], note1.self_and_siblings
628
+ assert_equal [note3], note3.self_and_siblings
629
+ end
630
+
631
+ def test_multi_scoped_rebuild
632
+ root = Note.create!(:body => "A", :notable_id => 3, :notable_type => 'Category')
633
+ child1 = Note.create!(:body => "B", :notable_id => 3, :notable_type => 'Category')
634
+ child2 = Note.create!(:body => "C", :notable_id => 3, :notable_type => 'Category')
635
+
636
+ child1.move_to_child_of root
637
+ child2.move_to_child_of root
638
+
639
+ Note.collection.update({}, { :lft => nil, :rgt => nil }, :multi => true)
640
+ Note.rebuild!
641
+
642
+ assert_equal Note.find(:first, :parent_id => nil, :body => 'A'), root
643
+ assert_equal [child1, child2], Note.find(:first, :parent_id => nil, :body => 'A').children
644
+ end
645
+
646
+ def test_same_scope_with_multi_scopes
647
+ assert_nothing_raised do
648
+ notes(:scope1).same_scope?(notes(:child_1))
649
+ end
650
+ assert notes(:scope1).same_scope?(notes(:child_1))
651
+ assert notes(:child_1).same_scope?(notes(:scope1))
652
+ assert !notes(:scope1).same_scope?(notes(:scope2))
653
+ end
654
+
655
+ # def test_quoting_of_multi_scope_column_names
656
+ # assert_equal ["\"notable_id\"", "\"notable_type\""], Note.quoted_scope_column_names
657
+ # end
658
+
659
+ def test_equal_in_same_scope
660
+ assert_equal notes(:scope1), notes(:scope1)
661
+ assert_not_equal notes(:scope1), notes(:child_1)
662
+ end
663
+
664
+ def test_equal_in_different_scopes
665
+ assert_not_equal notes(:scope1), notes(:scope2)
666
+ end
667
+
668
+ def test_delete_does_not_invalidate
669
+ Category.acts_as_nested_set_options[:dependent] = :delete
670
+ categories(:child_2).destroy
671
+ assert Category.valid?
672
+ end
673
+
674
+ def test_destroy_does_not_invalidate
675
+ Category.acts_as_nested_set_options[:dependent] = :destroy
676
+ categories(:child_2).destroy
677
+ assert Category.valid?
678
+ end
679
+
680
+ def test_destroy_multiple_times_does_not_invalidate
681
+ Category.acts_as_nested_set_options[:dependent] = :destroy
682
+ categories(:child_2).destroy
683
+ categories(:child_2).destroy
684
+ assert Category.valid?
685
+ end
686
+
687
+ def test_assigning_parent_id_on_create
688
+ category = Category.create!(:name => "Child", :parent_id => categories(:child_2).id)
689
+ assert_equal categories(:child_2), category.parent
690
+ assert_equal categories(:child_2).id, category.parent_id
691
+ assert_not_nil category.left
692
+ assert_not_nil category.right
693
+ assert Category.valid?
694
+ end
695
+
696
+ def test_assigning_parent_on_create
697
+ category = Category.create!(:name => "Child", :parent => categories(:child_2))
698
+ assert_equal categories(:child_2), category.parent
699
+ assert_equal categories(:child_2).id, category.parent_id
700
+ assert_not_nil category.left
701
+ assert_not_nil category.right
702
+ assert Category.valid?
703
+ end
704
+
705
+ def test_assigning_parent_id_to_nil_on_create
706
+ category = Category.create!(:name => "New Root", :parent_id => nil)
707
+ assert_nil category.parent
708
+ assert_nil category.parent_id
709
+ assert_not_nil category.left
710
+ assert_not_nil category.right
711
+ assert Category.valid?
712
+ end
713
+
714
+ def test_assigning_parent_id_on_update
715
+ category = categories(:child_2_1)
716
+ category.parent_id = categories(:child_3).id
717
+ category.save
718
+ assert_equal categories(:child_3), category.parent
719
+ assert_equal categories(:child_3).id, category.parent_id
720
+ assert Category.valid?
721
+ end
722
+
723
+ def test_assigning_parent_on_update
724
+ category = categories(:child_2_1)
725
+ category.parent = categories(:child_3)
726
+ category.save
727
+ assert_equal categories(:child_3), category.parent
728
+ assert_equal categories(:child_3).id, category.parent_id
729
+ assert Category.valid?
730
+ end
731
+
732
+ def test_assigning_parent_id_to_nil_on_update
733
+ category = categories(:child_2_1)
734
+ category.parent_id = nil
735
+ category.save
736
+ assert_nil category.parent
737
+ assert_nil category.parent_id
738
+ assert Category.valid?
739
+ end
740
+
741
+ def test_creating_child_from_parent
742
+ category = categories(:child_2).children.create!(:name => "Child")
743
+ assert_equal categories(:child_2), category.parent
744
+ assert_equal categories(:child_2).id, category.parent_id
745
+ assert_not_nil category.left
746
+ assert_not_nil category.right
747
+ assert Category.valid?
748
+ end
749
+
750
+ def check_structure(entries, structure)
751
+ structure = structure.dup
752
+ Category.each_with_level(entries) do |category, level|
753
+ expected_level, expected_name = structure.shift
754
+ assert_equal expected_name, category.name, "wrong category"
755
+ assert_equal expected_level, level, "wrong level for #{category.name}"
756
+ end
757
+ end
758
+
759
+ def test_each_with_level
760
+ levels = [
761
+ [0, "Top Level"],
762
+ [1, "Child 1"],
763
+ [1, "Child 2"],
764
+ [2, "Child 2.1"],
765
+ [1, "Child 3" ]]
766
+
767
+ check_structure(Category.root.self_and_descendants, levels)
768
+
769
+ # test some deeper structures
770
+ category = Category.find_by_name("Child 1")
771
+ c1 = Category.new(:name => "Child 1.1")
772
+ c2 = Category.new(:name => "Child 1.1.1")
773
+ c3 = Category.new(:name => "Child 1.1.1.1")
774
+ c4 = Category.new(:name => "Child 1.2")
775
+ [c1, c2, c3, c4].each(&:save!)
776
+
777
+ c1.move_to_child_of(category)
778
+ c2.move_to_child_of(c1)
779
+ c3.move_to_child_of(c2)
780
+ c4.move_to_child_of(category)
781
+
782
+ levels = [
783
+ [0, "Top Level"],
784
+ [1, "Child 1"],
785
+ [2, "Child 1.1"],
786
+ [3, "Child 1.1.1"],
787
+ [4, "Child 1.1.1.1"],
788
+ [2, "Child 1.2"],
789
+ [1, "Child 2"],
790
+ [2, "Child 2.1"],
791
+ [1, "Child 3" ]]
792
+
793
+ check_structure(Category.root.self_and_descendants, levels)
794
+ end
795
+ end