better_nested_set 0.1.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.
- data/Gemfile +12 -0
- data/Gemfile.lock +18 -0
- data/LICENSE.txt +21 -0
- data/README.rdoc +224 -0
- data/Rakefile +59 -0
- data/VERSION +1 -0
- data/app/helpers/better_nested_set_helper.rb +121 -0
- data/better_nested_set.gemspec +75 -0
- data/lib/better_nested_set.rb +16 -0
- data/lib/symetrie_com/acts_as_better_nested_set.rb +1130 -0
- data/pkg/better_nested_set-0.1.0.gem +0 -0
- data/test/RUNNING_UNIT_TESTS +1 -0
- data/test/abstract_unit.rb +25 -0
- data/test/acts_as_nested_set_test.rb +1368 -0
- data/test/database.yml +15 -0
- data/test/fixtures/mixin.rb +33 -0
- data/test/fixtures/mixins.yml +66 -0
- data/test/mysql.rb +2 -0
- data/test/postgresql.rb +2 -0
- data/test/schema.rb +12 -0
- data/test/sqlite3.rb +2 -0
- metadata +141 -0
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
See instructions in ../README
|
@@ -0,0 +1,25 @@
|
|
1
|
+
ENV['RAILS_ENV'] = 'test'
|
2
|
+
require File.expand_path(File.join(File.dirname(__FILE__), '../../../../config/environment.rb'))
|
3
|
+
require 'test_help'
|
4
|
+
|
5
|
+
config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
|
6
|
+
ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + '/debug.log')
|
7
|
+
cs = ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'mysql'])
|
8
|
+
puts "Using #{cs.config[:adapter]} adapter"
|
9
|
+
load(File.dirname(__FILE__) + '/schema.rb')
|
10
|
+
|
11
|
+
Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + '/fixtures/'
|
12
|
+
$LOAD_PATH.unshift(Test::Unit::TestCase.fixture_path)
|
13
|
+
|
14
|
+
class Test::Unit::TestCase #:nodoc:
|
15
|
+
def create_fixtures(*table_names)
|
16
|
+
if block_given?
|
17
|
+
Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names) { yield }
|
18
|
+
else
|
19
|
+
Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
self.use_transactional_fixtures = true
|
24
|
+
self.use_instantiated_fixtures = false
|
25
|
+
end
|
@@ -0,0 +1,1368 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/abstract_unit'
|
2
|
+
require File.dirname(__FILE__) + '/fixtures/mixin'
|
3
|
+
require 'pp'
|
4
|
+
|
5
|
+
class MixinNestedSetTest < Test::Unit::TestCase
|
6
|
+
fixtures :mixins
|
7
|
+
|
8
|
+
def setup
|
9
|
+
# force so other tests besides test_destroy_dependent aren't affected
|
10
|
+
NestedSetWithStringScope.acts_as_nested_set_options[:dependent] = :delete_all
|
11
|
+
end
|
12
|
+
|
13
|
+
##########################################
|
14
|
+
# HIGH LEVEL TESTS
|
15
|
+
##########################################
|
16
|
+
def test_mixing_in_methods
|
17
|
+
ns = NestedSet.new
|
18
|
+
assert(ns.respond_to?(:all_children)) # test a random method
|
19
|
+
|
20
|
+
check_method_mixins(ns)
|
21
|
+
check_deprecated_method_mixins(ns)
|
22
|
+
check_class_method_mixins(NestedSet)
|
23
|
+
end
|
24
|
+
|
25
|
+
def check_method_mixins(obj)
|
26
|
+
[:<=>, :all_children, :all_children_count, :ancestors, :before_create, :before_destroy, :check_full_tree,
|
27
|
+
:check_subtree, :children, :children_count, :full_set, :leaves, :leaves_count, :left_col_name, :level, :move_to_child_of,
|
28
|
+
:move_to_left_of, :move_to_right_of, :parent, :parent_col_name, :renumber_full_tree, :right_col_name,
|
29
|
+
:root, :roots, :self_and_ancestors, :self_and_siblings, :siblings].each { |symbol| assert(obj.respond_to?(symbol)) }
|
30
|
+
end
|
31
|
+
|
32
|
+
def check_deprecated_method_mixins(obj)
|
33
|
+
[:add_child, :direct_children, :parent_column, :root?, :child?, :unknown?].each { |symbol| assert(obj.respond_to?(symbol)) }
|
34
|
+
end
|
35
|
+
|
36
|
+
def check_class_method_mixins(klass)
|
37
|
+
[:root, :roots, :check_all, :renumber_all].each { |symbol| assert(klass.respond_to?(symbol)) }
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_string_scope
|
41
|
+
ns = NestedSet.new
|
42
|
+
assert_equal("mixins.root_id IS NULL", ns.scope_condition)
|
43
|
+
|
44
|
+
ns = NestedSetWithStringScope.new
|
45
|
+
ns.root_id = 1
|
46
|
+
assert_equal("mixins.root_id = 1", ns.scope_condition)
|
47
|
+
ns.root_id = 42
|
48
|
+
assert_equal("mixins.root_id = 42", ns.scope_condition)
|
49
|
+
check_method_mixins ns
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_without_scope_condition
|
53
|
+
ns = NestedSet.new
|
54
|
+
assert_equal("mixins.root_id IS NULL", ns.scope_condition)
|
55
|
+
NestedSet.without_scope_condition do
|
56
|
+
assert_equal("(1 = 1)", ns.scope_condition)
|
57
|
+
end
|
58
|
+
assert_equal("mixins.root_id IS NULL", ns.scope_condition)
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_symbol_scope
|
62
|
+
ns = NestedSetWithSymbolScope.new
|
63
|
+
ns.root_id = 1
|
64
|
+
assert_equal("mixins.root_id = 1", ns.scope_condition)
|
65
|
+
ns.root_id = 42
|
66
|
+
assert_equal("mixins.root_id = 42", ns.scope_condition)
|
67
|
+
check_method_mixins ns
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_protected_attributes
|
71
|
+
ns = NestedSet.new(:parent_id => 2, :lft => 3, :rgt => 2)
|
72
|
+
[:parent_id, :lft, :rgt].each {|symbol| assert_equal(nil, ns.send(symbol))}
|
73
|
+
end
|
74
|
+
|
75
|
+
def test_really_protected_attributes
|
76
|
+
ns = NestedSet.new
|
77
|
+
assert_raise(ActiveRecord::ActiveRecordError) {ns.parent_id = 1}
|
78
|
+
assert_raise(ActiveRecord::ActiveRecordError) {ns.lft = 1}
|
79
|
+
assert_raise(ActiveRecord::ActiveRecordError) {ns.rgt = 1}
|
80
|
+
end
|
81
|
+
|
82
|
+
##########################################
|
83
|
+
# CLASS METHOD TESTS
|
84
|
+
##########################################
|
85
|
+
def test_class_root
|
86
|
+
NestedSetWithStringScope.roots.each {|r| r.destroy unless r.id == 4001}
|
87
|
+
assert_equal([NestedSetWithStringScope.find(4001)], NestedSetWithStringScope.roots)
|
88
|
+
NestedSetWithStringScope.find(4001).destroy
|
89
|
+
assert_equal(nil, NestedSetWithStringScope.root)
|
90
|
+
ns = NestedSetWithStringScope.create(:root_id => 2)
|
91
|
+
assert_equal(ns, NestedSetWithStringScope.root)
|
92
|
+
end
|
93
|
+
|
94
|
+
def test_class_root_again
|
95
|
+
NestedSetWithStringScope.roots.each {|r| r.destroy unless r.id == 101}
|
96
|
+
assert_equal(NestedSetWithStringScope.find(101), NestedSetWithStringScope.root)
|
97
|
+
end
|
98
|
+
|
99
|
+
def test_class_roots
|
100
|
+
assert_equal(2, NestedSetWithStringScope.roots.size)
|
101
|
+
assert_equal(10, NestedSet.roots.size) # May change if STI behavior changes
|
102
|
+
end
|
103
|
+
|
104
|
+
def test_check_all_1
|
105
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
106
|
+
NestedSetWithStringScope.update_all("lft = 3", "id = 103")
|
107
|
+
assert_raise(ActiveRecord::ActiveRecordError) {NestedSetWithStringScope.check_all}
|
108
|
+
end
|
109
|
+
|
110
|
+
def test_check_all_2
|
111
|
+
NestedSetWithStringScope.update_all("lft = lft + 1", "lft > 11 AND root_id = 101")
|
112
|
+
NestedSetWithStringScope.update_all("rgt = rgt + 1", "lft > 11 AND root_id = 101")
|
113
|
+
assert_raise(ActiveRecord::ActiveRecordError) {NestedSetWithStringScope.check_all}
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_check_all_3
|
117
|
+
NestedSetWithStringScope.update_all("lft = lft + 2", "lft > 11 AND root_id = 101")
|
118
|
+
NestedSetWithStringScope.update_all("rgt = rgt + 2", "lft > 11 AND root_id = 101")
|
119
|
+
assert_raise(ActiveRecord::ActiveRecordError) {NestedSetWithStringScope.check_all}
|
120
|
+
end
|
121
|
+
|
122
|
+
def test_check_all_4
|
123
|
+
ns = NestedSetWithStringScope.create(:root_id => 101) # virtual root
|
124
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
125
|
+
NestedSetWithStringScope.update_all("rgt = rgt + 2, lft = lft + 2", "id = #{ns.id}") # create a gap between virtual roots
|
126
|
+
assert_nothing_raised {ns.check_subtree}
|
127
|
+
assert_raise(ActiveRecord::ActiveRecordError) {NestedSetWithStringScope.check_all}
|
128
|
+
end
|
129
|
+
|
130
|
+
def test_renumber_all
|
131
|
+
NestedSetWithStringScope.update_all("lft = NULL, rgt = NULL")
|
132
|
+
assert_raise(ActiveRecord::ActiveRecordError) {NestedSetWithStringScope.check_all}
|
133
|
+
NestedSetWithStringScope.renumber_all
|
134
|
+
assert_nothing_raised(ActiveRecord::ActiveRecordError) {NestedSetWithStringScope.check_all}
|
135
|
+
NestedSetWithStringScope.update_all("lft = 1, rgt = 2")
|
136
|
+
assert_raise(ActiveRecord::ActiveRecordError) {NestedSetWithStringScope.check_all}
|
137
|
+
NestedSetWithStringScope.renumber_all
|
138
|
+
assert_nothing_raised(ActiveRecord::ActiveRecordError) {NestedSetWithStringScope.check_all}
|
139
|
+
end
|
140
|
+
|
141
|
+
def test_sql_for
|
142
|
+
assert_equal("1 != 1", Category.sql_for([]))
|
143
|
+
c = Category.new
|
144
|
+
assert_equal("1 != 1", Category.sql_for(c))
|
145
|
+
assert_equal("1 != 1", Category.sql_for([c]))
|
146
|
+
c.save
|
147
|
+
assert_equal("((mixins.lft BETWEEN 1 AND 2))", Category.sql_for(c))
|
148
|
+
assert_equal("((mixins.lft BETWEEN 1 AND 2))", Category.sql_for([c]))
|
149
|
+
assert_equal("((mixins.lft BETWEEN 1 AND 20))", NestedSetWithStringScope.sql_for(101))
|
150
|
+
assert_equal("((mixins.lft BETWEEN 1 AND 20) OR (mixins.lft BETWEEN 4 AND 11))", NestedSetWithStringScope.sql_for([101, set2(3)]))
|
151
|
+
assert_equal("((mixins.lft BETWEEN 5 AND 6) OR (mixins.lft BETWEEN 7 AND 8) OR (mixins.lft BETWEEN 9 AND 10))", NestedSetWithStringScope.sql_for(set2(3).children))
|
152
|
+
end
|
153
|
+
|
154
|
+
|
155
|
+
##########################################
|
156
|
+
# CALLBACK TESTS
|
157
|
+
##########################################
|
158
|
+
# If we change behavior of virtual roots, this test may change
|
159
|
+
def test_before_create
|
160
|
+
ns = NestedSetWithSymbolScope.create(:root_id => 1234)
|
161
|
+
assert_equal(1, ns.lft)
|
162
|
+
assert_equal(2, ns.rgt)
|
163
|
+
ns = NestedSetWithSymbolScope.create(:root_id => 1234)
|
164
|
+
assert_equal(3, ns.lft)
|
165
|
+
assert_equal(4, ns.rgt)
|
166
|
+
end
|
167
|
+
|
168
|
+
# test pruning a branch. only works if we allow the deletion of nodes with children
|
169
|
+
def test_destroy
|
170
|
+
big_tree = NestedSetWithStringScope.find(4001)
|
171
|
+
|
172
|
+
# Make sure we have the right one
|
173
|
+
assert_equal(3, big_tree.direct_children.length)
|
174
|
+
assert_equal(10, big_tree.full_set.length)
|
175
|
+
|
176
|
+
NestedSetWithStringScope.find(4005).destroy
|
177
|
+
|
178
|
+
big_tree = NestedSetWithStringScope.find(4001)
|
179
|
+
|
180
|
+
assert_equal(7, big_tree.full_set.length)
|
181
|
+
assert_equal(2, big_tree.direct_children.length)
|
182
|
+
|
183
|
+
assert_equal(1, NestedSetWithStringScope.find(4001).lft)
|
184
|
+
assert_equal(2, NestedSetWithStringScope.find(4002).lft)
|
185
|
+
assert_equal(3, NestedSetWithStringScope.find(4003).lft)
|
186
|
+
assert_equal(4, NestedSetWithStringScope.find(4003).rgt)
|
187
|
+
assert_equal(5, NestedSetWithStringScope.find(4004).lft)
|
188
|
+
assert_equal(6, NestedSetWithStringScope.find(4004).rgt)
|
189
|
+
assert_equal(7, NestedSetWithStringScope.find(4002).rgt)
|
190
|
+
assert_equal(8, NestedSetWithStringScope.find(4008).lft)
|
191
|
+
assert_equal(9, NestedSetWithStringScope.find(4009).lft)
|
192
|
+
assert_equal(10, NestedSetWithStringScope.find(4009).rgt)
|
193
|
+
assert_equal(11, NestedSetWithStringScope.find(4010).lft)
|
194
|
+
assert_equal(12, NestedSetWithStringScope.find(4010).rgt)
|
195
|
+
assert_equal(13, NestedSetWithStringScope.find(4008).rgt)
|
196
|
+
assert_equal(14, NestedSetWithStringScope.find(4001).rgt)
|
197
|
+
end
|
198
|
+
|
199
|
+
def test_destroy_2
|
200
|
+
assert_nothing_raised {set2(1).check_subtree}
|
201
|
+
assert set2(10).destroy
|
202
|
+
assert_nothing_raised {set2(1).reload.check_subtree}
|
203
|
+
assert set2(9).children.empty?
|
204
|
+
assert set2(9).destroy
|
205
|
+
assert_equal 15, set2(4).rgt
|
206
|
+
assert_nothing_raised {set2(1).reload.check_subtree}
|
207
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
208
|
+
end
|
209
|
+
|
210
|
+
def test_destroy_3
|
211
|
+
assert set2(3).destroy
|
212
|
+
assert_equal(2, set2(1).children.size)
|
213
|
+
assert_equal(0, NestedSetWithStringScope.find(:all, :conditions => "id > 104 and id < 108").size)
|
214
|
+
assert_equal(6, set2(1).full_set.size)
|
215
|
+
assert_equal(3, set2(2).rgt)
|
216
|
+
assert_equal(4, set2(4).lft)
|
217
|
+
assert_equal(12, set2(1).rgt)
|
218
|
+
assert_nothing_raised {set2(1).check_subtree}
|
219
|
+
end
|
220
|
+
|
221
|
+
def test_destroy_root
|
222
|
+
NestedSetWithStringScope.find(4001).destroy
|
223
|
+
assert_equal(0, NestedSetWithStringScope.count(:conditions => "root_id = 42"))
|
224
|
+
end
|
225
|
+
|
226
|
+
def test_destroy_dependent
|
227
|
+
NestedSetWithStringScope.acts_as_nested_set_options[:dependent] = :destroy
|
228
|
+
|
229
|
+
big_tree = NestedSetWithStringScope.find(4001)
|
230
|
+
|
231
|
+
# Make sure we have the right one
|
232
|
+
assert_equal(3, big_tree.direct_children.length)
|
233
|
+
assert_equal(10, big_tree.full_set.length)
|
234
|
+
|
235
|
+
NestedSetWithStringScope.find(4005).destroy
|
236
|
+
|
237
|
+
big_tree = NestedSetWithStringScope.find(4001)
|
238
|
+
|
239
|
+
assert_equal(7, big_tree.full_set.length)
|
240
|
+
assert_equal(2, big_tree.direct_children.length)
|
241
|
+
|
242
|
+
assert_equal(1, NestedSetWithStringScope.find(4001).lft)
|
243
|
+
assert_equal(2, NestedSetWithStringScope.find(4002).lft)
|
244
|
+
assert_equal(3, NestedSetWithStringScope.find(4003).lft)
|
245
|
+
assert_equal(4, NestedSetWithStringScope.find(4003).rgt)
|
246
|
+
assert_equal(5, NestedSetWithStringScope.find(4004).lft)
|
247
|
+
assert_equal(6, NestedSetWithStringScope.find(4004).rgt)
|
248
|
+
assert_equal(7, NestedSetWithStringScope.find(4002).rgt)
|
249
|
+
assert_equal(8, NestedSetWithStringScope.find(4008).lft)
|
250
|
+
assert_equal(9, NestedSetWithStringScope.find(4009).lft)
|
251
|
+
assert_equal(10, NestedSetWithStringScope.find(4009).rgt)
|
252
|
+
assert_equal(11, NestedSetWithStringScope.find(4010).lft)
|
253
|
+
assert_equal(12, NestedSetWithStringScope.find(4010).rgt)
|
254
|
+
assert_equal(13, NestedSetWithStringScope.find(4008).rgt)
|
255
|
+
assert_equal(14, NestedSetWithStringScope.find(4001).rgt)
|
256
|
+
end
|
257
|
+
|
258
|
+
##########################################
|
259
|
+
# QUERY METHOD TESTS
|
260
|
+
##########################################
|
261
|
+
def set(id) NestedSet.find(3000 + id) end # helper method
|
262
|
+
|
263
|
+
def set2(id) NestedSetWithStringScope.find(100 + id) end # helper method
|
264
|
+
|
265
|
+
def test_root?
|
266
|
+
assert NestedSetWithStringScope.find(4001).root?
|
267
|
+
assert !NestedSetWithStringScope.find(4002).root?
|
268
|
+
end
|
269
|
+
|
270
|
+
def test_child?
|
271
|
+
assert !NestedSetWithStringScope.find(4001).child?
|
272
|
+
assert NestedSetWithStringScope.find(4002).child?
|
273
|
+
end
|
274
|
+
|
275
|
+
# Deprecated, delete this test when we nuke the method
|
276
|
+
def test_unknown?
|
277
|
+
assert !NestedSetWithStringScope.find(4001).unknown?
|
278
|
+
assert !NestedSetWithStringScope.find(4002).unknown?
|
279
|
+
end
|
280
|
+
|
281
|
+
# Test the <=> method implicitly
|
282
|
+
def test_comparison
|
283
|
+
ar = NestedSetWithStringScope.find(:all, :conditions => "root_id = 42", :order => "lft")
|
284
|
+
ar2 = NestedSetWithStringScope.find(:all, :conditions => "root_id = 42", :order => "rgt")
|
285
|
+
assert_not_equal(ar, ar2)
|
286
|
+
assert_equal(ar, ar2.sort)
|
287
|
+
end
|
288
|
+
|
289
|
+
def test_root
|
290
|
+
assert_equal(NestedSetWithStringScope.find(4001), NestedSetWithStringScope.find(4007).root)
|
291
|
+
assert_equal(set2(1), set2(8).root)
|
292
|
+
assert_equal(set2(1), set2(1).root)
|
293
|
+
# test virtual roots
|
294
|
+
c1, c2, c3 = Category.create, Category.create, Category.create
|
295
|
+
c3.move_to_child_of(c2)
|
296
|
+
assert_equal(c2, c3.root)
|
297
|
+
end
|
298
|
+
|
299
|
+
def test_roots
|
300
|
+
assert_equal([set2(1)], set2(8).roots)
|
301
|
+
assert_equal([set2(1)], set2(1).roots)
|
302
|
+
assert_equal(NestedSet.find(:all, :conditions => "id > 3000 AND id < 4000").size, set(1).roots.size)
|
303
|
+
end
|
304
|
+
|
305
|
+
def test_parent
|
306
|
+
ns = NestedSetWithStringScope.create(:root_id => 45)
|
307
|
+
assert_equal(nil, ns.parent)
|
308
|
+
assert ns.save
|
309
|
+
assert_equal(nil, ns.parent)
|
310
|
+
assert_equal(set2(1), set2(2).parent)
|
311
|
+
assert_equal(set2(3), set2(7).parent)
|
312
|
+
end
|
313
|
+
|
314
|
+
def test_ancestors
|
315
|
+
assert_equal([], set2(1).ancestors)
|
316
|
+
assert_equal([set2(1), set2(4), set2(9)], set2(10).ancestors)
|
317
|
+
end
|
318
|
+
|
319
|
+
def test_self_and_ancestors
|
320
|
+
assert_equal([set2(1)], set2(1).self_and_ancestors)
|
321
|
+
assert_equal([set2(1), set2(4), set2(8)], set2(8).self_and_ancestors)
|
322
|
+
assert_equal([set2(1), set2(4), set2(9), set2(10)], set2(10).self_and_ancestors)
|
323
|
+
end
|
324
|
+
|
325
|
+
def test_siblings
|
326
|
+
assert_equal([], set2(1).siblings)
|
327
|
+
assert_equal([set2(2), set2(4)], set2(3).siblings)
|
328
|
+
end
|
329
|
+
|
330
|
+
def test_first_sibling
|
331
|
+
assert set2(2).first_sibling?
|
332
|
+
assert_equal(set2(2), set2(2).first_sibling)
|
333
|
+
assert_equal(set2(2), set2(3).first_sibling)
|
334
|
+
assert_equal(set2(2), set2(4).first_sibling)
|
335
|
+
end
|
336
|
+
|
337
|
+
def test_last_sibling
|
338
|
+
assert set2(4).last_sibling?
|
339
|
+
assert_equal(set2(4), set2(2).last_sibling)
|
340
|
+
assert_equal(set2(4), set2(3).last_sibling)
|
341
|
+
assert_equal(set2(4), set2(4).last_sibling)
|
342
|
+
end
|
343
|
+
|
344
|
+
def test_previous_siblings
|
345
|
+
assert_equal([], set2(2).previous_siblings)
|
346
|
+
assert_equal([set2(2)], set2(3).previous_siblings)
|
347
|
+
assert_equal([set2(3), set2(2)], set2(4).previous_siblings)
|
348
|
+
end
|
349
|
+
|
350
|
+
def test_previous_sibling
|
351
|
+
assert_equal(nil, set2(2).previous_sibling)
|
352
|
+
assert_equal(set2(2), set2(3).previous_sibling)
|
353
|
+
assert_equal(set2(3), set2(4).previous_sibling)
|
354
|
+
assert_equal([set2(3), set2(2)], set2(4).previous_sibling(2))
|
355
|
+
end
|
356
|
+
|
357
|
+
def test_next_siblings
|
358
|
+
assert_equal([], set2(4).next_siblings)
|
359
|
+
assert_equal([set2(4)], set2(3).next_siblings)
|
360
|
+
assert_equal([set2(3), set2(4)], set2(2).next_siblings)
|
361
|
+
end
|
362
|
+
|
363
|
+
def test_next_sibling
|
364
|
+
assert_equal(nil, set2(4).next_sibling)
|
365
|
+
assert_equal(set2(4), set2(3).next_sibling)
|
366
|
+
assert_equal(set2(3), set2(2).next_sibling)
|
367
|
+
assert_equal([set2(3), set2(4)], set2(2).next_sibling(2))
|
368
|
+
end
|
369
|
+
|
370
|
+
def test_self_and_siblings
|
371
|
+
assert_equal([set2(1)], set2(1).self_and_siblings)
|
372
|
+
assert_equal([set2(2), set2(3), set2(4)], set2(3).self_and_siblings)
|
373
|
+
end
|
374
|
+
|
375
|
+
def test_level
|
376
|
+
assert_equal(0, set2(1).level)
|
377
|
+
assert_equal(1, set2(3).level)
|
378
|
+
assert_equal(3, set2(10).level)
|
379
|
+
end
|
380
|
+
|
381
|
+
def test_all_children_count
|
382
|
+
assert_equal(0, set2(10).all_children_count)
|
383
|
+
assert_equal(1, set2(3).level)
|
384
|
+
assert_equal(3, set2(10).level)
|
385
|
+
end
|
386
|
+
|
387
|
+
def test_full_set
|
388
|
+
assert_equal(NestedSetWithStringScope.find(:all, :conditions => "root_id = 101", :order => "lft"), set2(1).full_set)
|
389
|
+
new_ns = NestedSetWithStringScope.new(:root_id => 101)
|
390
|
+
assert_equal([new_ns], new_ns.full_set)
|
391
|
+
assert_equal([set2(4), set2(8), set2(9), set2(10)], set2(4).full_set)
|
392
|
+
assert_equal([set2(2)], set2(2).full_set)
|
393
|
+
assert_equal([set2(2)], set2(2).full_set(:exclude => nil))
|
394
|
+
assert_equal([set2(2)], set2(2).full_set(:exclude => []))
|
395
|
+
assert_equal([], set2(1).full_set(:exclude => 101))
|
396
|
+
assert_equal([], set2(1).full_set(:exclude => set2(1)))
|
397
|
+
ns = NestedSetWithStringScope.create(:root_id => 234)
|
398
|
+
assert_equal([], ns.full_set(:exclude => ns))
|
399
|
+
assert_equal([set2(4), set2(8), set2(9)], set2(4).full_set(:exclude => set2(10)))
|
400
|
+
assert_equal([set2(4), set2(8)], set2(4).full_set(:exclude => set2(9)))
|
401
|
+
end
|
402
|
+
|
403
|
+
def test_all_children
|
404
|
+
assert_equal(NestedSetWithStringScope.find(:all, :conditions => "root_id = 101 AND id > 101", :order => "lft"), set2(1).all_children)
|
405
|
+
assert_equal([], NestedSetWithStringScope.new(:root_id => 101).all_children)
|
406
|
+
assert_equal([set2(8), set2(9), set2(10)], set2(4).all_children)
|
407
|
+
assert_equal([set2(8), set2(9)], set2(4).all_children(:exclude => set2(10)))
|
408
|
+
assert_equal([set2(8)], set2(4).all_children(:exclude => set2(9)))
|
409
|
+
assert_equal([set2(2), set2(4), set2(8)], set2(1).all_children(:exclude => [set2(9), 103]))
|
410
|
+
assert_equal([set2(2), set2(4), set2(8)], set2(1).all_children(:exclude => [set2(9), 103, 106]))
|
411
|
+
end
|
412
|
+
|
413
|
+
def test_children
|
414
|
+
assert_equal([], set2(10).children)
|
415
|
+
assert_equal([], set(1).children)
|
416
|
+
assert_equal([set2(2), set2(3), set2(4)], set2(1).children)
|
417
|
+
assert_equal([set2(5), set2(6), set2(7)], set2(3).children)
|
418
|
+
assert_equal([NestedSetWithStringScope.find(4006), NestedSetWithStringScope.find(4007)], NestedSetWithStringScope.find(4005).children)
|
419
|
+
end
|
420
|
+
|
421
|
+
def test_children_count
|
422
|
+
assert_equal(0, set2(10).children_count)
|
423
|
+
assert_equal(3, set2(1).children_count)
|
424
|
+
end
|
425
|
+
|
426
|
+
def test_leaves
|
427
|
+
assert_equal([set2(10)], set2(9).leaves)
|
428
|
+
assert_equal([set2(10)], set2(10).leaves)
|
429
|
+
assert_equal([set2(2), set2(5), set2(6), set2(7), set2(8), set2(10)], set2(1).leaves)
|
430
|
+
end
|
431
|
+
|
432
|
+
def test_leaves_count
|
433
|
+
assert_equal(1, set2(10).leaves_count)
|
434
|
+
assert_equal(1, set2(9).leaves_count)
|
435
|
+
assert_equal(6, set2(1).leaves_count)
|
436
|
+
end
|
437
|
+
|
438
|
+
##########################################
|
439
|
+
# CASTING RESULT TESTS
|
440
|
+
##########################################
|
441
|
+
|
442
|
+
def test_recurse_result_set
|
443
|
+
result = []
|
444
|
+
NestedSetWithStringScope.recurse_result_set(set2(1).full_set) do |node, level|
|
445
|
+
result << [level, node.id]
|
446
|
+
end
|
447
|
+
expected = [[0, 101], [1, 102], [1, 103], [2, 105], [2, 106], [2, 107], [1, 104], [2, 108], [2, 109], [3, 110]]
|
448
|
+
assert_equal expected, result
|
449
|
+
end
|
450
|
+
|
451
|
+
def test_disjointed_result_set
|
452
|
+
result_set = set2(1).full_set(:conditions => { :type => 'NestedSetWithStringScope' })
|
453
|
+
result = []
|
454
|
+
NestedSetWithStringScope.recurse_result_set(result_set) do |node, level|
|
455
|
+
result << [level, node.id]
|
456
|
+
end
|
457
|
+
expected = [[0, 102], [0, 104], [0, 105], [0, 106], [0, 107], [0, 110]]
|
458
|
+
assert_equal expected, result
|
459
|
+
end
|
460
|
+
|
461
|
+
def test_result_to_array
|
462
|
+
result = NestedSetWithStringScope.result_to_array(set2(1).full_set) do |node, level|
|
463
|
+
{ :id => node.id, :level => level }
|
464
|
+
end
|
465
|
+
expected = [{:level=>0, :children=>[{:level=>1, :id=>102}, {:level=>1,
|
466
|
+
:children=>[{:level=>2, :id=>105}, {:level=>2, :id=>106}, {:level=>2, :id=>107}], :id=>103}, {:level=>1,
|
467
|
+
:children=>[{:level=>2, :id=>108}, {:level=>2, :children=>[{:level=>3, :id=>110}], :id=>109}], :id=>104}], :id=>101}]
|
468
|
+
assert_equal expected, result
|
469
|
+
end
|
470
|
+
|
471
|
+
def test_result_to_array_with_method_calls
|
472
|
+
result = NestedSetWithStringScope.result_to_array(set2(1).full_set, :only => [:id], :methods => [:children_count])
|
473
|
+
expected = [{:children=>[{:children_count=>0, :id=>102}, {:children=>[{:children_count=>0, :id=>105}, {:children_count=>0, :id=>106},
|
474
|
+
{:children_count=>0, :id=>107}], :children_count=>3, :id=>103}, {:children=>[{:children_count=>0, :id=>108}, {:children=>[{:children_count=>0, :id=>110}],
|
475
|
+
:children_count=>1, :id=>109}], :children_count=>2, :id=>104}], :children_count=>3, :id=>101}]
|
476
|
+
assert_equal expected, result
|
477
|
+
end
|
478
|
+
|
479
|
+
def test_disjointed_result_to_array
|
480
|
+
result_set = set2(1).full_set(:conditions => { :type => 'NestedSetWithStringScope' })
|
481
|
+
result = NestedSetWithStringScope.result_to_array(result_set) do |node, level|
|
482
|
+
{ :id => node.id, :level => level }
|
483
|
+
end
|
484
|
+
expected = [{:level=>0, :id=>102}, {:level=>0, :id=>104}, {:level=>0, :id=>105}, {:level=>0, :id=>106}, {:level=>0, :id=>107}, {:level=>0, :id=>110}]
|
485
|
+
assert_equal expected, result
|
486
|
+
end
|
487
|
+
|
488
|
+
def test_result_to_array_flat
|
489
|
+
result = NestedSetWithStringScope.result_to_array(set2(1).full_set, :nested => false) do |node, level|
|
490
|
+
{ :id => node.id, :level => level }
|
491
|
+
end
|
492
|
+
expected = [{:level=>0, :id=>101}, {:level=>0, :id=>103}, {:level=>0, :id=>106}, {:level=>0, :id=>104}, {:level=>0, :id=>109},
|
493
|
+
{:level=>0, :id=>102}, {:level=>0, :id=>105}, {:level=>0, :id=>107}, {:level=>0, :id=>108}, {:level=>0, :id=>110}]
|
494
|
+
assert_equal expected, result
|
495
|
+
end
|
496
|
+
|
497
|
+
def test_result_to_xml
|
498
|
+
result = NestedSetWithStringScope.result_to_xml(set2(3).full_set, :record => 'node', :dasherize => false, :only => [:id]) do |options, subnode|
|
499
|
+
options[:builder].tag!('type', subnode[:type])
|
500
|
+
end
|
501
|
+
expected = '<?xml version="1.0" encoding="UTF-8"?>
|
502
|
+
<nodes>
|
503
|
+
<node>
|
504
|
+
<id type="integer">103</id>
|
505
|
+
<type>NS2</type>
|
506
|
+
<children>
|
507
|
+
<node>
|
508
|
+
<id type="integer">105</id>
|
509
|
+
<type>NestedSetWithStringScope</type>
|
510
|
+
<children>
|
511
|
+
</children>
|
512
|
+
</node>
|
513
|
+
<node>
|
514
|
+
<id type="integer">106</id>
|
515
|
+
<type>NestedSetWithStringScope</type>
|
516
|
+
<children>
|
517
|
+
</children>
|
518
|
+
</node>
|
519
|
+
<node>
|
520
|
+
<id type="integer">107</id>
|
521
|
+
<type>NestedSetWithStringScope</type>
|
522
|
+
<children>
|
523
|
+
</children>
|
524
|
+
</node>
|
525
|
+
</children>
|
526
|
+
</node>
|
527
|
+
</nodes>'
|
528
|
+
assert_equal expected, result.strip
|
529
|
+
end
|
530
|
+
|
531
|
+
def test_disjointed_result_to_xml
|
532
|
+
result_set = set2(1).full_set(:conditions => ['type IN(?)', ['NestedSetWithStringScope', 'NS2']])
|
533
|
+
result = NestedSetWithStringScope.result_to_xml(result_set, :only => [:id])
|
534
|
+
# note how nesting is preserved where possible; this is not always what you want though,
|
535
|
+
# so you can force a flattened set with :nested => false instead (see below)
|
536
|
+
expected = '<?xml version="1.0" encoding="UTF-8"?>
|
537
|
+
<nodes>
|
538
|
+
<nested-set-with-string-scope>
|
539
|
+
<id type="integer">102</id>
|
540
|
+
<children>
|
541
|
+
</children>
|
542
|
+
</nested-set-with-string-scope>
|
543
|
+
<ns2>
|
544
|
+
<id type="integer">103</id>
|
545
|
+
<children>
|
546
|
+
<nested-set-with-string-scope>
|
547
|
+
<id type="integer">105</id>
|
548
|
+
<children>
|
549
|
+
</children>
|
550
|
+
</nested-set-with-string-scope>
|
551
|
+
<nested-set-with-string-scope>
|
552
|
+
<id type="integer">106</id>
|
553
|
+
<children>
|
554
|
+
</children>
|
555
|
+
</nested-set-with-string-scope>
|
556
|
+
<nested-set-with-string-scope>
|
557
|
+
<id type="integer">107</id>
|
558
|
+
<children>
|
559
|
+
</children>
|
560
|
+
</nested-set-with-string-scope>
|
561
|
+
</children>
|
562
|
+
</ns2>
|
563
|
+
<nested-set-with-string-scope>
|
564
|
+
<id type="integer">104</id>
|
565
|
+
<children>
|
566
|
+
<ns2>
|
567
|
+
<id type="integer">108</id>
|
568
|
+
<children>
|
569
|
+
</children>
|
570
|
+
</ns2>
|
571
|
+
</children>
|
572
|
+
</nested-set-with-string-scope>
|
573
|
+
</nodes>'
|
574
|
+
assert_equal expected, result.strip
|
575
|
+
end
|
576
|
+
|
577
|
+
def test_result_to_xml_flat
|
578
|
+
result = NestedSetWithStringScope.result_to_xml(set2(3).full_set, :record => 'node', :dasherize => false, :only => [:id], :nested => false)
|
579
|
+
expected = '<?xml version="1.0" encoding="UTF-8"?>
|
580
|
+
<nodes>
|
581
|
+
<node>
|
582
|
+
<id type="integer">103</id>
|
583
|
+
</node>
|
584
|
+
<node>
|
585
|
+
<id type="integer">105</id>
|
586
|
+
</node>
|
587
|
+
<node>
|
588
|
+
<id type="integer">106</id>
|
589
|
+
</node>
|
590
|
+
<node>
|
591
|
+
<id type="integer">107</id>
|
592
|
+
</node>
|
593
|
+
</nodes>'
|
594
|
+
assert_equal expected, result.strip
|
595
|
+
end
|
596
|
+
|
597
|
+
def test_result_to_attribute_based_xml
|
598
|
+
result = NestedSetWithStringScope.result_to_attributes_xml(set2(1).full_set, :record => 'node', :only => [:id, :parent_id])
|
599
|
+
expected = '<?xml version="1.0" encoding="UTF-8"?>
|
600
|
+
<node id="101" parent_id="0">
|
601
|
+
<node id="102" parent_id="101"/>
|
602
|
+
<node id="103" parent_id="101">
|
603
|
+
<node id="105" parent_id="103"/>
|
604
|
+
<node id="106" parent_id="103"/>
|
605
|
+
<node id="107" parent_id="103"/>
|
606
|
+
</node>
|
607
|
+
<node id="104" parent_id="101">
|
608
|
+
<node id="108" parent_id="104"/>
|
609
|
+
<node id="109" parent_id="104">
|
610
|
+
<node id="110" parent_id="109"/>
|
611
|
+
</node>
|
612
|
+
</node>
|
613
|
+
</node>'
|
614
|
+
assert_equal expected, result.strip
|
615
|
+
end
|
616
|
+
|
617
|
+
def test_result_to_attribute_based_xml_flat
|
618
|
+
result = NestedSetWithStringScope.result_to_attributes_xml(set2(1).full_set, :only => [:id], :nested => false, :skip_instruct => true)
|
619
|
+
expected = '<ns1 id="101"/>
|
620
|
+
<ns2 id="103"/>
|
621
|
+
<nested_set_with_string_scope id="106"/>
|
622
|
+
<nested_set_with_string_scope id="104"/>
|
623
|
+
<ns1 id="109"/>
|
624
|
+
<nested_set_with_string_scope id="102"/>
|
625
|
+
<nested_set_with_string_scope id="105"/>
|
626
|
+
<nested_set_with_string_scope id="107"/>
|
627
|
+
<ns2 id="108"/>
|
628
|
+
<nested_set_with_string_scope id="110"/>'
|
629
|
+
assert_equal expected, result.strip
|
630
|
+
end
|
631
|
+
|
632
|
+
##########################################
|
633
|
+
# WITH_SCOPE QUERY TESTS
|
634
|
+
##########################################
|
635
|
+
|
636
|
+
def test_filtered_full_set
|
637
|
+
result_set = set2(1).full_set(:conditions => { :type => 'NestedSetWithStringScope' })
|
638
|
+
assert_equal [102, 105, 106, 107, 104, 110], result_set.map(&:id)
|
639
|
+
end
|
640
|
+
|
641
|
+
def test_reverse_result_set
|
642
|
+
result_set = set2(1).full_set(:reverse => true)
|
643
|
+
assert_equal [101, 104, 109, 110, 108, 103, 107, 106, 105, 102], result_set.map(&:id)
|
644
|
+
# NestedSetWithStringScope.recurse_result_set(result_set) { |node, level| puts "#{'--' * level}#{node.id}" }
|
645
|
+
end
|
646
|
+
|
647
|
+
def test_reordered_full_set
|
648
|
+
result_set = set2(1).full_set(:order => 'id DESC')
|
649
|
+
assert_equal [110, 109, 108, 107, 106, 105, 104, 103, 102, 101], result_set.map(&:id)
|
650
|
+
end
|
651
|
+
|
652
|
+
def test_filtered_siblings
|
653
|
+
node = set2(2)
|
654
|
+
result_set = node.siblings(:conditions => { :type => node[:type] })
|
655
|
+
assert_equal [104], result_set.map(&:id)
|
656
|
+
end
|
657
|
+
|
658
|
+
def test_include_option_with_full_set
|
659
|
+
result_set = set2(3).full_set(:include => :parent_node)
|
660
|
+
assert_equal [[103, 101], [105, 103], [106, 103], [107, 103]], result_set.map { |n| [n.id, n.parent_node.id] }
|
661
|
+
end
|
662
|
+
|
663
|
+
##########################################
|
664
|
+
# FIND UNTIL/THROUGH METHOD TESTS
|
665
|
+
##########################################
|
666
|
+
|
667
|
+
def test_ancestors_and_self_through
|
668
|
+
result = set2(10).ancestors_and_self_through(set2(4))
|
669
|
+
assert_equal [104, 109, 110], result.map(&:id)
|
670
|
+
result = set2(10).ancestors_through(set2(4))
|
671
|
+
assert_equal [104, 109], result.map(&:id)
|
672
|
+
end
|
673
|
+
|
674
|
+
def test_full_set_through
|
675
|
+
result = set2(4).full_set_through(set2(10))
|
676
|
+
assert_equal [104, 108, 109, 110], result.map(&:id)
|
677
|
+
end
|
678
|
+
|
679
|
+
def test_all_children_through
|
680
|
+
result = set2(4).all_children_through(set2(10))
|
681
|
+
assert_equal [108, 109, 110], result.map(&:id)
|
682
|
+
end
|
683
|
+
|
684
|
+
def test_siblings_through
|
685
|
+
result = set2(5).self_and_siblings_through(set2(7))
|
686
|
+
assert_equal [105, 106, 107], result.map(&:id)
|
687
|
+
result = set2(7).siblings_through(set2(5))
|
688
|
+
assert_equal [105, 106], result.map(&:id)
|
689
|
+
end
|
690
|
+
|
691
|
+
##########################################
|
692
|
+
# FIND CHILD BY ID METHOD TESTS
|
693
|
+
##########################################
|
694
|
+
|
695
|
+
def test_child_by_id
|
696
|
+
assert_equal set2(6), set2(3).child_by_id(set2(6).id)
|
697
|
+
assert_nil set2(3).child_by_id(set2(8).id)
|
698
|
+
end
|
699
|
+
|
700
|
+
def test_child_of
|
701
|
+
assert set2(6).child_of?(set2(3))
|
702
|
+
assert !set2(8).child_of?(set2(3))
|
703
|
+
assert set2(6).child_of?(set2(3), :conditions => '1 = 1')
|
704
|
+
end
|
705
|
+
|
706
|
+
def test_direct_child_by_id
|
707
|
+
assert_equal set2(9), set2(4).direct_child_by_id(set2(9).id)
|
708
|
+
assert_nil set2(4).direct_child_by_id(set2(10).id)
|
709
|
+
end
|
710
|
+
|
711
|
+
def test_direct_child_of
|
712
|
+
assert set2(9).direct_child_of?(set2(4))
|
713
|
+
assert !set2(10).direct_child_of?(set2(4))
|
714
|
+
assert set2(9).direct_child_of?(set2(4), :conditions => '1 = 1')
|
715
|
+
end
|
716
|
+
|
717
|
+
##########################################
|
718
|
+
# INDEX-CHECKING METHOD TESTS
|
719
|
+
##########################################
|
720
|
+
def test_check_subtree
|
721
|
+
root = set2(1)
|
722
|
+
assert_nothing_raised {root.check_subtree}
|
723
|
+
# need to use update_all to get around attr_protected
|
724
|
+
NestedSetWithStringScope.update_all("rgt = #{root.lft + 1}", "id = #{root.id}")
|
725
|
+
assert_raise(ActiveRecord::ActiveRecordError) {root.reload.check_subtree}
|
726
|
+
assert_nothing_raised {set2(4).check_subtree}
|
727
|
+
NestedSetWithStringScope.update_all("lft = 17", "id = 110")
|
728
|
+
assert_raise(ActiveRecord::ActiveRecordError) {set2(4).reload.check_subtree}
|
729
|
+
NestedSetWithStringScope.update_all("rgt = 18", "id = 110")
|
730
|
+
assert_nothing_raised {set2(10).check_subtree}
|
731
|
+
NestedSetWithStringScope.update_all("rgt = NULL", "id = 4002")
|
732
|
+
assert_raise(ActiveRecord::ActiveRecordError) {NestedSetWithStringScope.find(4001).reload.check_subtree}
|
733
|
+
# this method receives lots of additional testing through tests of check_full_tree and check_all
|
734
|
+
end
|
735
|
+
|
736
|
+
def test_check_full_tree
|
737
|
+
assert_nothing_raised {set2(1).check_full_tree}
|
738
|
+
assert_nothing_raised {NestedSetWithStringScope.find(4006).check_full_tree}
|
739
|
+
NestedSetWithStringScope.update_all("rgt = NULL", "id = 4002")
|
740
|
+
assert_raise(ActiveRecord::ActiveRecordError) {NestedSetWithStringScope.find(4006).check_full_tree}
|
741
|
+
NestedSetWithStringScope.update_all("rgt = 0", "id = 4001")
|
742
|
+
assert_raise(ActiveRecord::ActiveRecordError) {NestedSetWithStringScope.find(4006).check_full_tree}
|
743
|
+
NestedSetWithStringScope.update_all("rgt = rgt + 1", "id > 101")
|
744
|
+
NestedSetWithStringScope.update_all("lft = lft + 1", "id > 101")
|
745
|
+
assert_raise(ActiveRecord::ActiveRecordError) {set2(4).check_full_tree}
|
746
|
+
end
|
747
|
+
|
748
|
+
def test_check_full_tree_orphan
|
749
|
+
assert_raise(ActiveRecord::RecordNotFound) {NestedSetWithStringScope.find(99)} # make sure ID 99 doesn't exist
|
750
|
+
ns = NestedSetWithStringScope.create(:root_id => 101)
|
751
|
+
NestedSetWithStringScope.update_all("parent_id = 99", "id = #{ns.id}")
|
752
|
+
assert_raise(ActiveRecord::ActiveRecordError) {set2(3).check_full_tree}
|
753
|
+
end
|
754
|
+
|
755
|
+
def test_check_full_tree_endless_loop
|
756
|
+
ns = NestedSetWithStringScope.create(:root_id => 101)
|
757
|
+
NestedSetWithStringScope.update_all("parent_id = #{ns.id}", "id = #{ns.id}")
|
758
|
+
assert_raise(ActiveRecord::ActiveRecordError) {set2(6).check_full_tree}
|
759
|
+
end
|
760
|
+
|
761
|
+
def test_check_full_tree_virtual_roots
|
762
|
+
a = Category.create
|
763
|
+
b = Category.create
|
764
|
+
|
765
|
+
assert_nothing_raised {a.check_full_tree}
|
766
|
+
Category.update_all("rgt = rgt + 2, lft = lft + 2", "id = #{b.id}") # create a gap between virtual roots
|
767
|
+
assert_raise(ActiveRecord::ActiveRecordError) {a.check_full_tree}
|
768
|
+
end
|
769
|
+
|
770
|
+
# see also the tests of check_all under 'class method tests'
|
771
|
+
|
772
|
+
##########################################
|
773
|
+
# INDEX-ALTERING (UPDATE) METHOD TESTS
|
774
|
+
##########################################
|
775
|
+
def test_move_to_left_of # this method undergoes additional testing elsewhere
|
776
|
+
set2(2).move_to_left_of(set2(3)) # should cause no change
|
777
|
+
assert_equal(2, set2(2).lft)
|
778
|
+
assert_equal(4, set2(3).lft)
|
779
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
780
|
+
set2(3).move_to_left_of(set2(2))
|
781
|
+
assert_equal(9, set2(3).rgt)
|
782
|
+
set2(2).move_to_left_of(set2(3))
|
783
|
+
assert_equal(2, set2(2).lft)
|
784
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
785
|
+
set2(3).move_to_left_of(102) # pass an ID instead
|
786
|
+
assert_equal(2, set2(3).lft)
|
787
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
788
|
+
end
|
789
|
+
|
790
|
+
def test_move_to_right_of # this method undergoes additional testing elsewhere
|
791
|
+
set2(3).move_to_right_of(set2(2)) # should cause no change
|
792
|
+
set2(4).move_to_right_of(set2(3)) # should cause no change
|
793
|
+
assert_equal(11, set2(3).rgt)
|
794
|
+
assert_equal(19, set2(4).rgt)
|
795
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
796
|
+
set2(3).move_to_right_of(set2(4))
|
797
|
+
assert_equal(19, set2(3).rgt)
|
798
|
+
set2(4).move_to_right_of(set2(3))
|
799
|
+
assert_equal(4, set2(3).lft)
|
800
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
801
|
+
set2(3).move_to_right_of(104) # pass an ID instead
|
802
|
+
assert_equal(4, set2(4).lft)
|
803
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
804
|
+
end
|
805
|
+
|
806
|
+
def test_adding_children
|
807
|
+
assert(set(1).unknown?)
|
808
|
+
assert(set(2).unknown?)
|
809
|
+
set(1).add_child set(2)
|
810
|
+
|
811
|
+
# Did we maintain adding the parent_ids?
|
812
|
+
assert(set(1).root?)
|
813
|
+
assert(set(2).child?)
|
814
|
+
assert(set(2).parent_id == set(1).id)
|
815
|
+
|
816
|
+
# Check boundaries
|
817
|
+
assert_equal(set(1).lft, 1)
|
818
|
+
assert_equal(set(2).lft, 2)
|
819
|
+
assert_equal(set(2).rgt, 3)
|
820
|
+
assert_equal(set(1).rgt, 4)
|
821
|
+
|
822
|
+
# Check children cound
|
823
|
+
assert_equal(set(1).all_children_count, 1)
|
824
|
+
|
825
|
+
set(1).add_child set(3)
|
826
|
+
|
827
|
+
#check boundries
|
828
|
+
assert_equal(set(1).lft, 1)
|
829
|
+
assert_equal(set(2).lft, 2)
|
830
|
+
assert_equal(set(2).rgt, 3)
|
831
|
+
assert_equal(set(3).lft, 4)
|
832
|
+
assert_equal(set(3).rgt, 5)
|
833
|
+
assert_equal(set(1).rgt, 6)
|
834
|
+
|
835
|
+
# How is the count looking?
|
836
|
+
assert_equal(set(1).all_children_count, 2)
|
837
|
+
|
838
|
+
set(2).add_child set(4)
|
839
|
+
|
840
|
+
# boundries
|
841
|
+
assert_equal(set(1).lft, 1)
|
842
|
+
assert_equal(set(2).lft, 2)
|
843
|
+
assert_equal(set(4).lft, 3)
|
844
|
+
assert_equal(set(4).rgt, 4)
|
845
|
+
assert_equal(set(2).rgt, 5)
|
846
|
+
assert_equal(set(3).lft, 6)
|
847
|
+
assert_equal(set(3).rgt, 7)
|
848
|
+
assert_equal(set(1).rgt, 8)
|
849
|
+
|
850
|
+
# Children count
|
851
|
+
assert_equal(set(1).all_children_count, 3)
|
852
|
+
assert_equal(set(2).all_children_count, 1)
|
853
|
+
assert_equal(set(3).all_children_count, 0)
|
854
|
+
assert_equal(set(4).all_children_count, 0)
|
855
|
+
|
856
|
+
set(2).add_child set(5)
|
857
|
+
set(4).add_child set(6)
|
858
|
+
|
859
|
+
assert_equal(set(2).all_children_count, 3)
|
860
|
+
|
861
|
+
# Children accessors
|
862
|
+
assert_equal(set(1).full_set.length, 6)
|
863
|
+
assert_equal(set(2).full_set.length, 4)
|
864
|
+
assert_equal(set(4).full_set.length, 2)
|
865
|
+
|
866
|
+
assert_equal(set(1).all_children.length, 5)
|
867
|
+
assert_equal(set(6).all_children.length, 0)
|
868
|
+
|
869
|
+
assert_equal(set(1).direct_children.length, 2)
|
870
|
+
|
871
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
872
|
+
end
|
873
|
+
|
874
|
+
def test_common_usage
|
875
|
+
mixins(:set_1).add_child(mixins(:set_2))
|
876
|
+
assert_equal(1, mixins(:set_1).direct_children.length)
|
877
|
+
|
878
|
+
mixins(:set_2).add_child(mixins(:set_3))
|
879
|
+
assert_equal(1, mixins(:set_1).direct_children.length)
|
880
|
+
|
881
|
+
# Local cache is now out of date!
|
882
|
+
# Problem: the update_alls update all objects up the tree
|
883
|
+
mixins(:set_1).reload
|
884
|
+
assert_equal(2, mixins(:set_1).all_children.length)
|
885
|
+
|
886
|
+
assert_equal(1, mixins(:set_1).lft)
|
887
|
+
assert_equal(2, mixins(:set_2).lft)
|
888
|
+
assert_equal(3, mixins(:set_3).lft)
|
889
|
+
assert_equal(4, mixins(:set_3).rgt)
|
890
|
+
assert_equal(5, mixins(:set_2).rgt)
|
891
|
+
assert_equal(6, mixins(:set_1).rgt)
|
892
|
+
assert(mixins(:set_1).root?)
|
893
|
+
|
894
|
+
begin
|
895
|
+
mixins(:set_4).add_child(mixins(:set_1))
|
896
|
+
fail
|
897
|
+
rescue
|
898
|
+
end
|
899
|
+
|
900
|
+
assert_equal(2, mixins(:set_1).all_children.length)
|
901
|
+
mixins(:set_1).add_child mixins(:set_4)
|
902
|
+
assert_equal(3, mixins(:set_1).all_children.length)
|
903
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
904
|
+
end
|
905
|
+
|
906
|
+
def test_move_to_child_of_1
|
907
|
+
bill = NestedSetWithStringScope.new(:root_id => 101, :pos => 2)
|
908
|
+
assert_raise(ActiveRecord::ActiveRecordError) { bill.move_to_child_of(set2(1)) }
|
909
|
+
assert_raise(ActiveRecord::ActiveRecordError) { set2(1).move_to_child_of(set2(1)) }
|
910
|
+
assert_raise(ActiveRecord::ActiveRecordError) { set2(4).move_to_child_of(set2(9)) }
|
911
|
+
assert bill.save
|
912
|
+
assert_nothing_raised {set2(1).reload.check_subtree}
|
913
|
+
assert bill.move_to_left_of(set2(3))
|
914
|
+
assert_equal set2(1), bill.parent
|
915
|
+
assert_equal 4, bill.lft
|
916
|
+
assert_equal 5, bill.rgt
|
917
|
+
assert_equal 3, set2(2).reload.rgt
|
918
|
+
assert_equal 6, set2(3).reload.lft
|
919
|
+
assert_equal 22, set2(1).reload.rgt
|
920
|
+
assert_nothing_raised {set2(1).reload.check_subtree}
|
921
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
922
|
+
set2(9).move_to_child_of(101) # pass an ID instead
|
923
|
+
assert set2(1).children.include?(set2(9))
|
924
|
+
assert_equal(18, set2(9).lft) # to the right of existing children?
|
925
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
926
|
+
end
|
927
|
+
|
928
|
+
def test_move_to_child_of_2
|
929
|
+
bill = NestedSetWithStringScope.new(:root_id => 101)
|
930
|
+
assert_nothing_raised {set2(1).check_subtree}
|
931
|
+
assert bill.save
|
932
|
+
assert bill.move_to_child_of(set2(10))
|
933
|
+
assert_equal set2(10), bill.parent
|
934
|
+
assert_equal 17, bill.lft
|
935
|
+
assert_equal 18, bill.rgt
|
936
|
+
assert_equal 16, set2(10).reload.lft
|
937
|
+
assert_equal 19, set2(10).reload.rgt
|
938
|
+
assert_equal 15, set2(9).reload.lft
|
939
|
+
assert_equal 20, set2(9).reload.rgt
|
940
|
+
assert_equal 21, set2(4).reload.rgt
|
941
|
+
assert_nothing_raised {set2(9).reload.check_subtree}
|
942
|
+
assert_nothing_raised {set2(4).reload.check_subtree}
|
943
|
+
assert_nothing_raised {set2(1).reload.check_subtree}
|
944
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
945
|
+
end
|
946
|
+
|
947
|
+
def test_move_to_child_of_3
|
948
|
+
bill = NestedSetWithStringScope.new(:root_id => 101)
|
949
|
+
assert bill.save
|
950
|
+
assert bill.move_to_child_of(set2(3))
|
951
|
+
assert_equal(11, bill.lft) # to the right of existing children?
|
952
|
+
assert_nothing_raised {set2(1).reload.check_subtree}
|
953
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
954
|
+
end
|
955
|
+
|
956
|
+
def test_move_1
|
957
|
+
set2(4).move_to_child_of(set2(3))
|
958
|
+
assert_equal(set2(3), set2(4).reload.parent)
|
959
|
+
assert_equal(1, set2(1).reload.lft)
|
960
|
+
assert_equal(20, set2(1).reload.rgt)
|
961
|
+
assert_equal(4, set2(3).reload.lft)
|
962
|
+
assert_equal(19, set2(3).reload.rgt)
|
963
|
+
assert_nothing_raised {set2(1).reload.check_subtree}
|
964
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
965
|
+
end
|
966
|
+
|
967
|
+
def test_move_2
|
968
|
+
initial = set2(1).full_set
|
969
|
+
assert_raise(ActiveRecord::ActiveRecordError) { set2(3).move_to_child_of(set2(6)) } # can't set a current child as the parent-- creates a loop
|
970
|
+
assert_raise(ActiveRecord::ActiveRecordError) { set2(3).move_to_child_of(set2(3)) }
|
971
|
+
set2(2).move_to_child_of(set2(5))
|
972
|
+
set2(4).move_to_child_of(set2(2))
|
973
|
+
set2(10).move_to_right_of(set2(3))
|
974
|
+
|
975
|
+
assert_equal 105, set2(2).parent_id
|
976
|
+
assert_equal 102, set2(4).parent_id
|
977
|
+
assert_equal 101, set2(10).parent_id
|
978
|
+
set2(3).reload
|
979
|
+
set2(10).reload
|
980
|
+
assert_equal 19, set2(10).rgt
|
981
|
+
assert_equal 17, set2(3).rgt
|
982
|
+
assert_equal 2, set2(3).lft
|
983
|
+
set2(1).reload
|
984
|
+
assert_nothing_raised {set2(1).check_subtree}
|
985
|
+
set2(4).move_to_right_of(set2(3))
|
986
|
+
set2(10).move_to_child_of(set2(9))
|
987
|
+
set2(2).move_to_left_of(set2(3))
|
988
|
+
|
989
|
+
# now everything should be back where it started-- check against initial
|
990
|
+
final = set2(1).reload.full_set
|
991
|
+
assert_equal(initial, final)
|
992
|
+
for i in 0..9
|
993
|
+
assert_equal(initial[i]['parent_id'], final[i]['parent_id'])
|
994
|
+
assert_equal(initial[i]['lft'], final[i]['lft'])
|
995
|
+
assert_equal(initial[i]['rgt'], final[i]['rgt'])
|
996
|
+
end
|
997
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
998
|
+
end
|
999
|
+
|
1000
|
+
def test_scope_enforcement # prevent moves between trees
|
1001
|
+
assert_raise(ActiveRecord::ActiveRecordError) { set(3).move_to_child_of(set2(6)) }
|
1002
|
+
ns = NestedSetWithStringScope.create(:root_id => 214)
|
1003
|
+
assert_raise(ActiveRecord::ActiveRecordError) { ns.move_to_child_of(set2(1)) }
|
1004
|
+
end
|
1005
|
+
|
1006
|
+
##########################################
|
1007
|
+
# ACTS_AS_LIST-LIKE BEHAVIOUR TESTS
|
1008
|
+
##########################################
|
1009
|
+
|
1010
|
+
def test_swap
|
1011
|
+
set2(5).swap(set2(7))
|
1012
|
+
assert_equal [107, 106, 105], set2(3).children.map(&:id)
|
1013
|
+
assert_nothing_raised {set2(3).check_full_tree}
|
1014
|
+
assert_raise(ActiveRecord::ActiveRecordError) { set2(3).swap(set2(10)) } # isn't a sibling...
|
1015
|
+
end
|
1016
|
+
|
1017
|
+
def test_insert_at
|
1018
|
+
child = NestedSetWithStringScope.create(:root_id => 101)
|
1019
|
+
child.insert_at(set2(3), :last)
|
1020
|
+
assert_equal child, set2(3).children.last
|
1021
|
+
|
1022
|
+
child = NestedSetWithStringScope.create(:root_id => 101)
|
1023
|
+
child.insert_at(set2(3), :first)
|
1024
|
+
assert_equal child, set2(3).children.first
|
1025
|
+
|
1026
|
+
child = NestedSetWithStringScope.create(:root_id => 101)
|
1027
|
+
child.insert_at(set2(3), 2)
|
1028
|
+
assert_equal child, set2(3).children[2]
|
1029
|
+
|
1030
|
+
child = NestedSetWithStringScope.create(:root_id => 101)
|
1031
|
+
child.insert_at(set2(3), 1000)
|
1032
|
+
assert_equal child, set2(3).children.last
|
1033
|
+
|
1034
|
+
child = NestedSetWithStringScope.create(:root_id => 101)
|
1035
|
+
child.insert_at(set2(3), 1)
|
1036
|
+
assert_equal child, set2(3).children[1]
|
1037
|
+
end
|
1038
|
+
|
1039
|
+
def test_move_higher
|
1040
|
+
set2(7).move_higher
|
1041
|
+
assert_equal [105, 107, 106], set2(3).children.map(&:id)
|
1042
|
+
set2(7).move_higher
|
1043
|
+
assert_equal [107, 105, 106], set2(3).children.map(&:id)
|
1044
|
+
set2(7).move_higher
|
1045
|
+
assert_equal [107, 105, 106], set2(3).children.map(&:id)
|
1046
|
+
end
|
1047
|
+
|
1048
|
+
def test_move_lower
|
1049
|
+
set2(5).move_lower
|
1050
|
+
assert_equal [106, 105, 107], set2(3).children.map(&:id)
|
1051
|
+
set2(5).move_lower
|
1052
|
+
assert_equal [106, 107, 105], set2(3).children.map(&:id)
|
1053
|
+
set2(5).move_lower
|
1054
|
+
assert_equal [106, 107, 105], set2(3).children.map(&:id)
|
1055
|
+
end
|
1056
|
+
|
1057
|
+
def test_move_to_top
|
1058
|
+
set2(7).move_to_top
|
1059
|
+
assert_equal [107, 105, 106], set2(3).children.map(&:id)
|
1060
|
+
end
|
1061
|
+
|
1062
|
+
def test_move_to_bottom
|
1063
|
+
set2(5).move_to_bottom
|
1064
|
+
assert_equal [106, 107, 105], set2(3).children.map(&:id)
|
1065
|
+
end
|
1066
|
+
|
1067
|
+
def test_move_to_position
|
1068
|
+
set2(7).move_to_position(:first)
|
1069
|
+
assert_equal [107, 105, 106], set2(3).children.map(&:id)
|
1070
|
+
set2(7).move_to_position(:last)
|
1071
|
+
assert_equal [105, 106, 107], set2(3).children.map(&:id)
|
1072
|
+
end
|
1073
|
+
|
1074
|
+
def test_move_to_position_limits
|
1075
|
+
set2(7).move_to_position(0)
|
1076
|
+
assert_equal [107, 105, 106], set2(3).children.map(&:id)
|
1077
|
+
set2(7).move_to_position(100)
|
1078
|
+
assert_equal [105, 106, 107], set2(3).children.map(&:id)
|
1079
|
+
end
|
1080
|
+
|
1081
|
+
def test_move_to_position_index
|
1082
|
+
set2(7).move_to_position(0)
|
1083
|
+
assert_equal [107, 105, 106], set2(3).children.map(&:id)
|
1084
|
+
set2(7).move_to_position(1)
|
1085
|
+
assert_equal [105, 107, 106], set2(3).children.map(&:id)
|
1086
|
+
set2(7).move_to_position(2)
|
1087
|
+
assert_equal [105, 106, 107], set2(3).children.map(&:id)
|
1088
|
+
set2(5).move_to_position(2)
|
1089
|
+
assert_equal [106, 107, 105], set2(3).children.map(&:id)
|
1090
|
+
end
|
1091
|
+
|
1092
|
+
def test_scoped_move_to_position
|
1093
|
+
set2(7).move_to_position(0, :conditions => { :id => [105, 106, 107] })
|
1094
|
+
assert_equal [107, 105, 106], set2(3).children.map(&:id)
|
1095
|
+
set2(7).move_to_position(1, :conditions => { :id => [105, 107] })
|
1096
|
+
assert_equal [105, 107, 106], set2(3).children.map(&:id)
|
1097
|
+
set2(7).move_to_position(1, :conditions => { :id => [106, 107] })
|
1098
|
+
assert_equal [105, 106, 107], set2(3).children.map(&:id)
|
1099
|
+
end
|
1100
|
+
|
1101
|
+
def test_reorder_children
|
1102
|
+
assert_equal [105], set2(3).reorder_children(107, 106, 105).map(&:id)
|
1103
|
+
assert_equal [107, 106, 105], set2(3).children.map(&:id)
|
1104
|
+
assert_equal [107, 106], set2(3).reorder_children(106, 105, 107).map(&:id)
|
1105
|
+
assert_equal [106, 105, 107], set2(3).children.map(&:id)
|
1106
|
+
end
|
1107
|
+
|
1108
|
+
def test_reorder_children_with_random_samples
|
1109
|
+
10.times do
|
1110
|
+
child = NestedSetWithStringScope.create(:root_id => 101)
|
1111
|
+
child.move_to_child_of set2(3)
|
1112
|
+
end
|
1113
|
+
ordered_ids = set2(3).children.map(&:id).sort_by { rand }
|
1114
|
+
set2(3).reorder_children(ordered_ids)
|
1115
|
+
assert_equal ordered_ids, set2(3).children.map(&:id)
|
1116
|
+
end
|
1117
|
+
|
1118
|
+
def test_reorder_children_with_partial_id_set
|
1119
|
+
10.times do
|
1120
|
+
child = NestedSetWithStringScope.create(:root_id => 101)
|
1121
|
+
child.move_to_child_of set2(3)
|
1122
|
+
end
|
1123
|
+
child_ids = set2(3).children.map(&:id)
|
1124
|
+
set2(3).reorder_children(child_ids.last, child_ids.first)
|
1125
|
+
ordered_ids = set2(3).children.map(&:id)
|
1126
|
+
assert_equal ordered_ids.first, child_ids.last
|
1127
|
+
assert_equal ordered_ids.last, child_ids.first
|
1128
|
+
assert_equal child_ids[1, -2], ordered_ids[1, -2]
|
1129
|
+
end
|
1130
|
+
|
1131
|
+
##########################################
|
1132
|
+
# RENUMBERING TESTS
|
1133
|
+
##########################################
|
1134
|
+
# see also class method tests of renumber_all
|
1135
|
+
def test_renumber_full_tree_1
|
1136
|
+
NestedSetWithStringScope.update_all("lft = NULL, rgt = NULL", "root_id = 101")
|
1137
|
+
assert_raise(ActiveRecord::ActiveRecordError) {set2(1).check_full_tree}
|
1138
|
+
set2(1).renumber_full_tree
|
1139
|
+
set2(1).reload
|
1140
|
+
assert_equal 1, set2(1).lft
|
1141
|
+
assert_equal 20, set2(1).rgt
|
1142
|
+
assert_equal 4, set2(3).lft
|
1143
|
+
assert_equal 11, set2(3).rgt
|
1144
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
1145
|
+
end
|
1146
|
+
|
1147
|
+
def test_renumber_full_tree_2
|
1148
|
+
NestedSetWithStringScope.update_all("lft = lft + 1, rgt = rgt + 1", "root_id = 101")
|
1149
|
+
assert_raise(ActiveRecord::ActiveRecordError) {NestedSetWithStringScope.check_all}
|
1150
|
+
set2(1).renumber_full_tree
|
1151
|
+
assert_nothing_raised(ActiveRecord::ActiveRecordError) {NestedSetWithStringScope.check_all}
|
1152
|
+
NestedSetWithStringScope.update_all("rgt = 12", "id = 108")
|
1153
|
+
assert_raise(ActiveRecord::ActiveRecordError) {set2(8).check_subtree}
|
1154
|
+
set2(8).renumber_full_tree
|
1155
|
+
assert_nothing_raised(ActiveRecord::ActiveRecordError) {NestedSetWithStringScope.check_all}
|
1156
|
+
end
|
1157
|
+
|
1158
|
+
|
1159
|
+
##########################################
|
1160
|
+
# CONCURRENCY TESTS
|
1161
|
+
##########################################
|
1162
|
+
# what happens when multiple objects are being manipulated at the same time?
|
1163
|
+
def test_concurrent_save
|
1164
|
+
c1, c2, c3 = Category.create, Category.create, Category.create
|
1165
|
+
c1.move_to_right_of(c3)
|
1166
|
+
c2.save
|
1167
|
+
assert_nothing_raised {Category.check_all}
|
1168
|
+
|
1169
|
+
ns1 = set2(3)
|
1170
|
+
ns2 = set2(4)
|
1171
|
+
ns2.move_to_left_of(102) # ns1 is now out-of-date
|
1172
|
+
ns1.save
|
1173
|
+
assert_nothing_raised {set2(1).check_subtree}
|
1174
|
+
end
|
1175
|
+
|
1176
|
+
def test_concurrent_add_add
|
1177
|
+
c1 = Category.new
|
1178
|
+
c2 = Category.new
|
1179
|
+
c1.save
|
1180
|
+
c2.save
|
1181
|
+
c3 = Category.new
|
1182
|
+
c4 = Category.new
|
1183
|
+
c4.save # now in the opposite order
|
1184
|
+
c3.save
|
1185
|
+
assert_nothing_raised {Category.check_all}
|
1186
|
+
end
|
1187
|
+
|
1188
|
+
def test_concurrent_add_delete
|
1189
|
+
ns = set2(3)
|
1190
|
+
new_ns = NestedSetWithStringScope.create(:root_id => 101)
|
1191
|
+
ns.destroy
|
1192
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
1193
|
+
end
|
1194
|
+
|
1195
|
+
def test_concurrent_add_move
|
1196
|
+
ns = set2(3)
|
1197
|
+
new_ns = NestedSetWithStringScope.create(:root_id => 101)
|
1198
|
+
ns.move_to_left_of(102)
|
1199
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
1200
|
+
end
|
1201
|
+
|
1202
|
+
def test_concurrent_delete_add
|
1203
|
+
ns = set2(3)
|
1204
|
+
new_ns = NestedSetWithStringScope.new(:root_id => 101)
|
1205
|
+
ns.destroy
|
1206
|
+
new_ns.save
|
1207
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
1208
|
+
end
|
1209
|
+
|
1210
|
+
def test_concurrent_delete_delete
|
1211
|
+
ns1 = set2(3)
|
1212
|
+
ns2 = set2(4)
|
1213
|
+
ns1.destroy
|
1214
|
+
ns2.destroy
|
1215
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
1216
|
+
end
|
1217
|
+
|
1218
|
+
def test_concurrent_delete_move
|
1219
|
+
ns1 = set2(3)
|
1220
|
+
ns2 = set2(4)
|
1221
|
+
ns1.destroy
|
1222
|
+
ns2.move_to_left_of(102)
|
1223
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
1224
|
+
end
|
1225
|
+
|
1226
|
+
def test_concurrent_move_add
|
1227
|
+
ns = set2(3)
|
1228
|
+
new_ns = NestedSetWithStringScope.new(:root_id => 101)
|
1229
|
+
ns.move_to_left_of(102)
|
1230
|
+
new_ns.save
|
1231
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
1232
|
+
end
|
1233
|
+
|
1234
|
+
def test_concurrent_move_delete
|
1235
|
+
ns1 = set2(3)
|
1236
|
+
ns2 = set2(4)
|
1237
|
+
ns2.move_to_left_of(102)
|
1238
|
+
ns1.destroy
|
1239
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
1240
|
+
end
|
1241
|
+
|
1242
|
+
def test_concurrent_move_move
|
1243
|
+
ns1 = set2(3)
|
1244
|
+
ns2 = set2(4)
|
1245
|
+
ns1.move_to_left_of(102)
|
1246
|
+
ns2.move_to_child_of(102)
|
1247
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
1248
|
+
end
|
1249
|
+
|
1250
|
+
##########################################
|
1251
|
+
# CALLBACK TESTS
|
1252
|
+
##########################################
|
1253
|
+
# Because the nested set code relies heavily on callbacks, we
|
1254
|
+
# want to ensure that we aren't causing problems for user-defined callbacks
|
1255
|
+
def test_callbacks
|
1256
|
+
# 1) Do all user-defined callbacks work?
|
1257
|
+
$callbacks = []
|
1258
|
+
ns = NS2.new(:root_id => 101) # NS2 adds symbols to $callbacks when the callbacks fire
|
1259
|
+
assert_equal([], $callbacks)
|
1260
|
+
ns.save!
|
1261
|
+
assert_equal([:before_save, :before_create, :after_create, :after_save], $callbacks)
|
1262
|
+
$callbacks = []
|
1263
|
+
ns.pos = 2
|
1264
|
+
ns.save!
|
1265
|
+
assert_equal([:before_save, :before_update, :after_update, :after_save], $callbacks)
|
1266
|
+
$callbacks = []
|
1267
|
+
ns.destroy
|
1268
|
+
assert_equal([:before_destroy, :after_destroy], $callbacks)
|
1269
|
+
end
|
1270
|
+
|
1271
|
+
def test_callbacks2
|
1272
|
+
# 2) Do our callbacks still work, even when a programmer defines
|
1273
|
+
# their own callbacks in the overwriteable style?
|
1274
|
+
# (the NS2 model defines callbacks in the overwritable style)
|
1275
|
+
ns = NS2.create(:root_id => 101)
|
1276
|
+
assert ns.lft != nil && ns.rgt != nil
|
1277
|
+
child_ns = NS2.create(:root_id => 101)
|
1278
|
+
child_ns.move_to_child_of(ns)
|
1279
|
+
id = child_ns.id
|
1280
|
+
ns.destroy
|
1281
|
+
assert_equal(nil, NS2.find(:first, :conditions => "id = #{id}"))
|
1282
|
+
# lots of implicit testing occurs in other test methods
|
1283
|
+
end
|
1284
|
+
|
1285
|
+
##########################################
|
1286
|
+
# BUG-SPECIFIC TESTS
|
1287
|
+
##########################################
|
1288
|
+
def test_ticket_17
|
1289
|
+
main = Category.new
|
1290
|
+
main.save
|
1291
|
+
sub = Category.new
|
1292
|
+
sub.save
|
1293
|
+
sub.move_to_child_of main
|
1294
|
+
sub.save
|
1295
|
+
main.save
|
1296
|
+
|
1297
|
+
assert_equal(1, main.all_children_count)
|
1298
|
+
assert_equal([main, sub], main.full_set)
|
1299
|
+
assert_equal([sub], main.all_children)
|
1300
|
+
|
1301
|
+
assert_equal(1, main.lft)
|
1302
|
+
assert_equal(2, sub.lft)
|
1303
|
+
assert_equal(3, sub.rgt)
|
1304
|
+
assert_equal(4, main.rgt)
|
1305
|
+
end
|
1306
|
+
|
1307
|
+
def test_ticket_19
|
1308
|
+
# this test currently relies on the fact that objects are reloaded at the beginning of the move_to methods
|
1309
|
+
root = Category.create
|
1310
|
+
first = Category.create
|
1311
|
+
second = Category.create
|
1312
|
+
first.move_to_child_of(root)
|
1313
|
+
second.move_to_child_of(root)
|
1314
|
+
|
1315
|
+
# now we should have the situation described in the ticket
|
1316
|
+
assert_nothing_raised {first.move_to_child_of(second)}
|
1317
|
+
assert_raise(ActiveRecord::ActiveRecordError) {second.move_to_child_of(first)} # try illegal move
|
1318
|
+
first.move_to_child_of(root) # move it back
|
1319
|
+
assert_nothing_raised {first.move_to_child_of(second)} # try it the other way-- first is now on the other side of second
|
1320
|
+
assert_nothing_raised {Category.check_all}
|
1321
|
+
end
|
1322
|
+
|
1323
|
+
# Note that single-table inheritance recieves extensive implicit testing,
|
1324
|
+
# because one of the fixture trees contains a hodge-podge of classes.
|
1325
|
+
def test_ticket_10
|
1326
|
+
assert_equal(9, set2(1).all_children.size)
|
1327
|
+
NS2.find(103).move_to_right_of(104)
|
1328
|
+
assert_equal(4, set2(4).lft)
|
1329
|
+
assert_equal(10, set2(9).rgt)
|
1330
|
+
NS2.find(103).destroy
|
1331
|
+
assert_equal(12, set2(1).rgt)
|
1332
|
+
assert_equal(6, NestedSetWithStringScope.count(:conditions => "root_id = 101"))
|
1333
|
+
assert_nothing_raised {NestedSetWithStringScope.check_all}
|
1334
|
+
end
|
1335
|
+
|
1336
|
+
# the next virtual root was not starting with the correct lft value
|
1337
|
+
def test_ticket_29
|
1338
|
+
first = Category.create
|
1339
|
+
second = Category.create
|
1340
|
+
Category.renumber_all
|
1341
|
+
second.reload
|
1342
|
+
assert_equal(3, second.lft)
|
1343
|
+
end
|
1344
|
+
|
1345
|
+
end
|
1346
|
+
|
1347
|
+
|
1348
|
+
|
1349
|
+
###################################################################
|
1350
|
+
## Tests that don't pass yet or haven't been finished
|
1351
|
+
|
1352
|
+
## make #destroy set left & rgt to nil?
|
1353
|
+
|
1354
|
+
#def test_find_insertion_point
|
1355
|
+
# bill = NestedSetWithStringScope.create(:pos => 2, :root_id => 101)
|
1356
|
+
# assert_equal 3, bill.find_insertion_point(set2(1))
|
1357
|
+
# assert_equal 4, bill.find_insertion_point(set2(3))
|
1358
|
+
# aalfred = NestedSetWithStringScope.create(:pos => 0, :root_id => 101)
|
1359
|
+
# assert_equal 1, aalfred.find_insertion_point(set2(1))
|
1360
|
+
# assert_equal 2, aalfred.find_insertion_point(set2(2))
|
1361
|
+
# assert_equal 12, aalfred.find_insertion_point(set2(4))
|
1362
|
+
# zed = NestedSetWithStringScope.create(:pos => 99, :root_id => 101)
|
1363
|
+
# assert_equal 19, zed.find_insertion_point(set2(1))
|
1364
|
+
# assert_equal 17, zed.find_insertion_point(set2(9))
|
1365
|
+
# assert_equal 16, zed.find_insertion_point(set2(10))
|
1366
|
+
# assert_equal 10, set2(4).find_insertion_point(set2(3))
|
1367
|
+
#end
|
1368
|
+
#
|