awesome_nested_set 1.4.1

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