PageRenderTime 73ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/vendor/plugins/betternestedset/test/acts_as_nested_set_test.rb

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