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