awesome_nested_set 1.4.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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