acts_as_ordered_tree 1.3.1 → 2.0.0.beta3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. checksums.yaml +4 -4
  2. data/lib/acts_as_ordered_tree.rb +22 -100
  3. data/lib/acts_as_ordered_tree/adapters.rb +17 -0
  4. data/lib/acts_as_ordered_tree/adapters/abstract.rb +23 -0
  5. data/lib/acts_as_ordered_tree/adapters/postgresql.rb +150 -0
  6. data/lib/acts_as_ordered_tree/adapters/recursive.rb +157 -0
  7. data/lib/acts_as_ordered_tree/compatibility.rb +22 -0
  8. data/lib/acts_as_ordered_tree/compatibility/active_record/association_scope.rb +9 -0
  9. data/lib/acts_as_ordered_tree/compatibility/active_record/default_scoped.rb +19 -0
  10. data/lib/acts_as_ordered_tree/compatibility/active_record/null_relation.rb +71 -0
  11. data/lib/acts_as_ordered_tree/compatibility/features.rb +153 -0
  12. data/lib/acts_as_ordered_tree/deprecate.rb +24 -0
  13. data/lib/acts_as_ordered_tree/hooks.rb +38 -0
  14. data/lib/acts_as_ordered_tree/hooks/update.rb +86 -0
  15. data/lib/acts_as_ordered_tree/instance_methods.rb +92 -453
  16. data/lib/acts_as_ordered_tree/iterators/arranger.rb +35 -0
  17. data/lib/acts_as_ordered_tree/iterators/level_calculator.rb +52 -0
  18. data/lib/acts_as_ordered_tree/iterators/orphans_pruner.rb +58 -0
  19. data/lib/acts_as_ordered_tree/node.rb +78 -0
  20. data/lib/acts_as_ordered_tree/node/attributes.rb +48 -0
  21. data/lib/acts_as_ordered_tree/node/movement.rb +62 -0
  22. data/lib/acts_as_ordered_tree/node/movements.rb +111 -0
  23. data/lib/acts_as_ordered_tree/node/predicates.rb +98 -0
  24. data/lib/acts_as_ordered_tree/node/reloading.rb +49 -0
  25. data/lib/acts_as_ordered_tree/node/siblings.rb +139 -0
  26. data/lib/acts_as_ordered_tree/node/traversals.rb +53 -0
  27. data/lib/acts_as_ordered_tree/persevering_transaction.rb +93 -0
  28. data/lib/acts_as_ordered_tree/position.rb +143 -0
  29. data/lib/acts_as_ordered_tree/relation/arrangeable.rb +33 -0
  30. data/lib/acts_as_ordered_tree/relation/iterable.rb +41 -0
  31. data/lib/acts_as_ordered_tree/relation/preloaded.rb +46 -11
  32. data/lib/acts_as_ordered_tree/transaction/base.rb +57 -0
  33. data/lib/acts_as_ordered_tree/transaction/callbacks.rb +67 -0
  34. data/lib/acts_as_ordered_tree/transaction/create.rb +68 -0
  35. data/lib/acts_as_ordered_tree/transaction/destroy.rb +34 -0
  36. data/lib/acts_as_ordered_tree/transaction/dsl.rb +214 -0
  37. data/lib/acts_as_ordered_tree/transaction/factory.rb +67 -0
  38. data/lib/acts_as_ordered_tree/transaction/move.rb +70 -0
  39. data/lib/acts_as_ordered_tree/transaction/passthrough.rb +12 -0
  40. data/lib/acts_as_ordered_tree/transaction/reorder.rb +42 -0
  41. data/lib/acts_as_ordered_tree/transaction/save.rb +64 -0
  42. data/lib/acts_as_ordered_tree/transaction/update.rb +78 -0
  43. data/lib/acts_as_ordered_tree/tree.rb +148 -0
  44. data/lib/acts_as_ordered_tree/tree/association.rb +20 -0
  45. data/lib/acts_as_ordered_tree/tree/callbacks.rb +57 -0
  46. data/lib/acts_as_ordered_tree/tree/children_association.rb +120 -0
  47. data/lib/acts_as_ordered_tree/tree/columns.rb +102 -0
  48. data/lib/acts_as_ordered_tree/tree/deprecated_columns_accessors.rb +24 -0
  49. data/lib/acts_as_ordered_tree/tree/parent_association.rb +31 -0
  50. data/lib/acts_as_ordered_tree/tree/perseverance.rb +19 -0
  51. data/lib/acts_as_ordered_tree/tree/scopes.rb +56 -0
  52. data/lib/acts_as_ordered_tree/validators.rb +1 -1
  53. data/lib/acts_as_ordered_tree/version.rb +1 -1
  54. data/spec/acts_as_ordered_tree_spec.rb +80 -909
  55. data/spec/adapters/postgresql_spec.rb +14 -0
  56. data/spec/adapters/recursive_spec.rb +12 -0
  57. data/spec/adapters/shared.rb +272 -0
  58. data/spec/callbacks_spec.rb +177 -0
  59. data/spec/counter_cache_spec.rb +31 -0
  60. data/spec/create_spec.rb +110 -0
  61. data/spec/destroy_spec.rb +57 -0
  62. data/spec/inheritance_spec.rb +176 -0
  63. data/spec/move_spec.rb +94 -0
  64. data/spec/node/movements/concurrent_movements_spec.rb +354 -0
  65. data/spec/node/movements/move_higher_spec.rb +46 -0
  66. data/spec/node/movements/move_lower_spec.rb +46 -0
  67. data/spec/node/movements/move_to_child_of_spec.rb +147 -0
  68. data/spec/node/movements/move_to_child_with_index_spec.rb +124 -0
  69. data/spec/node/movements/move_to_child_with_position_spec.rb +85 -0
  70. data/spec/node/movements/move_to_left_of_spec.rb +120 -0
  71. data/spec/node/movements/move_to_right_of_spec.rb +120 -0
  72. data/spec/node/movements/move_to_root_spec.rb +67 -0
  73. data/spec/node/predicates_spec.rb +211 -0
  74. data/spec/node/reloading_spec.rb +42 -0
  75. data/spec/node/siblings_spec.rb +193 -0
  76. data/spec/node/traversals_spec.rb +71 -0
  77. data/spec/persevering_transaction_spec.rb +98 -0
  78. data/spec/relation/arrangeable_spec.rb +88 -0
  79. data/spec/relation/iterable_spec.rb +104 -0
  80. data/spec/relation/preloaded_spec.rb +57 -0
  81. data/spec/reorder_spec.rb +83 -0
  82. data/spec/spec_helper.rb +30 -38
  83. data/spec/support/db/boot.rb +22 -0
  84. data/spec/{db → support/db}/config.travis.yml +2 -0
  85. data/spec/{db → support/db}/config.yml +1 -0
  86. data/spec/{db → support/db}/schema.rb +9 -0
  87. data/spec/support/factories.rb +2 -2
  88. data/spec/support/matchers.rb +67 -58
  89. data/spec/support/models.rb +6 -14
  90. data/spec/support/tree_factory.rb +315 -0
  91. data/spec/tree/children_association_spec.rb +72 -0
  92. data/spec/tree/columns_spec.rb +65 -0
  93. data/spec/tree/scopes_spec.rb +39 -0
  94. metadata +161 -43
  95. data/lib/acts_as_ordered_tree/adapters/postgresql_adapter.rb +0 -104
  96. data/lib/acts_as_ordered_tree/arrangeable.rb +0 -80
  97. data/lib/acts_as_ordered_tree/class_methods.rb +0 -72
  98. data/lib/acts_as_ordered_tree/relation/base.rb +0 -26
  99. data/lib/acts_as_ordered_tree/tenacious_transaction.rb +0 -30
  100. data/spec/concurrency_support_spec.rb +0 -156
@@ -0,0 +1,67 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe ActsAsOrderedTree::Node::Movements, '#move_to_root', :transactional do
6
+ shared_examples '#move_to_root' do |factory, attrs = {}|
7
+ describe "#move_to_root #{factory}" do
8
+ tree :factory => factory, :attributes => attrs do
9
+ root_1 {
10
+ node_1
11
+ node_2
12
+ node_3 {
13
+ node_4
14
+ }
15
+ }
16
+ root_2 {
17
+ node_5
18
+ }
19
+ end
20
+
21
+ context 'moving root node to root' do
22
+ before { root_2.move_to_root }
23
+
24
+ expect_tree_to_match {
25
+ root_1 {
26
+ node_1
27
+ node_2
28
+ node_3 {
29
+ node_4
30
+ }
31
+ }
32
+ root_2 {
33
+ node_5
34
+ }
35
+ }
36
+ end
37
+
38
+ context 'moving inner node to root' do
39
+ before { node_3.move_to_root }
40
+
41
+ expect_tree_to_match {
42
+ root_1 {
43
+ node_1
44
+ node_2
45
+ }
46
+ root_2 {
47
+ node_5
48
+ }
49
+ node_3 {
50
+ node_4
51
+ }
52
+ }
53
+ end
54
+
55
+ context 'when attribute, not related to tree changed' do
56
+ before { @old_name = node_2.name }
57
+ before { node_2.name = 'new name' }
58
+
59
+ it { expect{node_2.move_to_root}.to change(node_2, :name).to(@old_name) }
60
+ end
61
+ end
62
+ end
63
+
64
+ include_examples '#move_to_root', :default
65
+ include_examples '#move_to_root', :default_with_counter_cache
66
+ include_examples '#move_to_root', :scoped, :scope_type => 's'
67
+ end
@@ -0,0 +1,211 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe ActsAsOrderedTree::Node::Predicates, :transactional do
6
+ shared_examples 'ActsAsOrderedTree::Node predicates' do |model, attrs = {}|
7
+ describe model do
8
+ let!(:root) { create model, attrs }
9
+ let!(:child) { create model, attrs.merge(:parent => root) }
10
+ let!(:grandchild) { create model, attrs.merge(:parent => child) }
11
+
12
+ let(:counter_cached?) { root.class.ordered_tree.columns.counter_cache? }
13
+
14
+ before { [root, child, grandchild].each(&:reload) }
15
+
16
+ describe '#root?' do
17
+ it { expect(root).to be_root }
18
+ it { expect(child).not_to be_root }
19
+ it { expect(grandchild).not_to be_root }
20
+
21
+ it { expect{root.root?}.not_to query_database }
22
+ it { expect{child.root?}.not_to query_database }
23
+ it { expect{grandchild.root?}.not_to query_database }
24
+ end
25
+
26
+ describe '#has_parent?' do
27
+ it { expect(root).not_to have_parent }
28
+ it { expect(child).to have_parent }
29
+ it { expect(grandchild).to have_parent }
30
+
31
+ it { expect{root.has_parent?}.not_to query_database }
32
+ it { expect{child.has_parent?}.not_to query_database }
33
+ it { expect{grandchild.has_parent?}.not_to query_database }
34
+
35
+ it 'should be aliased but deprecated as #child?' do
36
+ expect(ActiveSupport::Deprecation).to receive(:warn)
37
+ expect(root).to receive(:has_parent?)
38
+ ActiveSupport::Deprecation.silence{root.child?}
39
+ end
40
+ end
41
+
42
+ describe '#leaf?' do
43
+ it { expect(root).not_to be_leaf }
44
+ it { expect(child).not_to be_leaf }
45
+ it { expect(grandchild).to be_leaf }
46
+
47
+ context 'when new record given' do
48
+ let(:record) { build model, attrs }
49
+
50
+ it { expect(record).not_to be_leaf }
51
+ it { expect{record.leaf?}.not_to query_database }
52
+ end
53
+
54
+ context 'when :children association is loaded' do
55
+ before { root.children << build(model, attrs) }
56
+ before { root.children.reload }
57
+
58
+ it { expect(root).not_to be_leaf }
59
+ it { expect{root.leaf?}.not_to query_database }
60
+ end
61
+
62
+ context 'when :children association is not loaded' do
63
+ before { root.children << build(model, attrs) }
64
+ before { root.reload }
65
+
66
+ it { expect(root).not_to be_leaf }
67
+ it do
68
+ if counter_cached?
69
+ expect{root.leaf?}.not_to query_database
70
+ else
71
+ # we must check that #leaf? is optimized
72
+ expect{root.leaf?}.not_to query_database(/COUNT/)
73
+ expect{root.leaf?}.to query_database(/LIMIT 1/i)
74
+ end
75
+ end
76
+ end
77
+ end
78
+
79
+ describe '#has_children?' do
80
+ # opposite of #leaf?
81
+ it { expect(root).to have_children }
82
+ it { expect(child).to have_children }
83
+ it { expect(grandchild).not_to have_children }
84
+
85
+ it 'should be aliased but deprecated as #branch?' do
86
+ expect(ActiveSupport::Deprecation).to receive(:warn)
87
+ expect(root).to receive(:has_children?)
88
+ ActiveSupport::Deprecation.silence{root.branch?}
89
+ end
90
+ end
91
+
92
+ describe '#is_descendant_of?' do
93
+ it { expect(root) }
94
+ end
95
+
96
+ describe '#is_(or_is)_(descendant|ancestor)_of?' do
97
+ matrix3d = Hash[
98
+ :is_descendant_of? => Hash[
99
+ :root => {:root => false, :child => false, :grandchild => false},
100
+ :child => {:root => true, :child => false, :grandchild => false},
101
+ :grandchild => {:root => true, :child => true, :grandchild => false}
102
+ ],
103
+ :is_or_is_descendant_of? => Hash[
104
+ :root => {:root => true, :child => false, :grandchild => false},
105
+ :child => {:root => true, :child => true, :grandchild => false},
106
+ :grandchild => {:root => true, :child => true, :grandchild => true}
107
+ ],
108
+ :is_ancestor_of? => Hash[
109
+ :root => {:root => false, :child => true, :grandchild => true},
110
+ :child => {:root => false, :child => false, :grandchild => true},
111
+ :grandchild => {:root => false, :child => false, :grandchild => false}
112
+ ],
113
+ :is_or_is_ancestor_of? => Hash[
114
+ :root => {:root => true, :child => true, :grandchild => true},
115
+ :child => {:root => false, :child => true, :grandchild => true},
116
+ :grandchild => {:root => false, :child => false, :grandchild => true}
117
+ ]
118
+ ]
119
+
120
+ matrix3d.each do |method, matrix|
121
+ matrix.each do |node, examples|
122
+ examples.each do |target, expectation|
123
+ it "expect that #{node}.#{method}(#{target}) == #{expectation.inspect}" do
124
+ expect(send(node).send(method, send(target))).to eq expectation
125
+ end
126
+ end
127
+ end
128
+ end
129
+
130
+ end
131
+ end
132
+
133
+ describe model do
134
+ let!(:list) { create_list model, 3, attrs }
135
+ let(:first) { list[0] }
136
+ let(:second) { list[1] }
137
+ let(:third) { list[2] }
138
+
139
+ describe '#first?' do
140
+ it { expect(first).to be_first }
141
+ it { expect(second).not_to be_first }
142
+ it { expect(third).not_to be_first }
143
+
144
+ it 'does not query database' do
145
+ list.each do |node|
146
+ expect{node.first?}.not_to query_database
147
+ end
148
+ end
149
+ end
150
+
151
+ describe '#last?' do
152
+ it { expect(first).not_to be_last }
153
+ it { expect(second).not_to be_last }
154
+ it { expect(third).to be_last }
155
+
156
+ it { expect{first.last?}.to query_database(/LIMIT 1/i).once }
157
+ end
158
+ end
159
+ end
160
+
161
+ include_examples 'ActsAsOrderedTree::Node predicates', :default
162
+ include_examples 'ActsAsOrderedTree::Node predicates', :default_with_counter_cache do
163
+ describe '#last?' do
164
+ context 'when node is child' do
165
+ let(:root) { create :default_with_counter_cache }
166
+ let!(:node) { create :default_with_counter_cache, :parent => root }
167
+
168
+ context 'when parent is loaded' do
169
+ before { node.association(:parent).reload }
170
+
171
+ it { expect(node).to be_last }
172
+ it { expect{node.last?}.not_to query_database }
173
+ end
174
+
175
+ context 'when parent is not loaded' do
176
+ before { node.reload }
177
+ it { expect(node).to be_last }
178
+ it { expect{node.last?}.to query_database.once }
179
+ end
180
+ end
181
+ end
182
+ end
183
+
184
+ include_examples 'ActsAsOrderedTree::Node predicates', :scoped, :scope_type => 's' do
185
+ describe '#is_(or_is)_(descendant|ancestor)_of?' do
186
+ context 'when nodes belong to different scopes' do
187
+ let(:root) { create :scoped, :scope_type => 'a' }
188
+ let(:child) { create :scoped, :parent => root }
189
+ # hack it
190
+ before { child.scope_type = 'b' }
191
+ before { child.class.where(:id => child.id).update_all(['scope_type = ?', 'b']) }
192
+
193
+ context 'when parent association is cached and cache is stale' do
194
+ it { expect(root.is_ancestor_of?(child)).to be false }
195
+ it { expect(root.is_or_is_ancestor_of?(child)).to be false }
196
+ it { expect(child.is_descendant_of?(root)).to be false }
197
+ it { expect(child.is_or_is_descendant_of?(root)).to be false }
198
+ end
199
+
200
+ context 'when parent association is not loaded' do
201
+ before { child.reload }
202
+
203
+ it { expect(root.is_ancestor_of?(child)).to be false }
204
+ it { expect(root.is_or_is_ancestor_of?(child)).to be false }
205
+ it { expect(child.is_descendant_of?(root)).to be false }
206
+ it { expect(child.is_or_is_descendant_of?(root)).to be false }
207
+ end
208
+ end
209
+ end
210
+ end
211
+ end
@@ -0,0 +1,42 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe ActsAsOrderedTree::Node::Reloading, :transactional do
6
+ shared_examples 'ActsAsOrderedTree::Node#reload' do |model, attrs = {}|
7
+ describe model.to_s.camelize, '#reload' do
8
+ let(:record) { create model, attrs }
9
+ let(:node) { record.ordered_tree_node }
10
+
11
+ # change all attributes
12
+ before { node.parent_id = create(model, attrs).id }
13
+ before { node.position = 3 }
14
+ before { node.depth = 2 if record.ordered_tree.columns.depth? }
15
+ before { record[record.ordered_tree.columns.counter_cache] = 5 if record.ordered_tree.columns.counter_cache? }
16
+ before { record.name = 'another name' }
17
+
18
+ it 'reloads attributes related to tree' do
19
+ node.reload
20
+
21
+ expect(node.parent_id).to eq nil
22
+ expect(node.position).to eq 1
23
+
24
+ if record.ordered_tree.columns.depth?
25
+ expect(node.depth).to eq 0
26
+ end
27
+
28
+ if record.class.ordered_tree.columns.counter_cache?
29
+ expect(record.children.size).to eq 0
30
+ end
31
+ end
32
+
33
+ it 'does not reload another attributes' do
34
+ expect{node.reload}.not_to change(record, :name)
35
+ end
36
+ end
37
+ end
38
+
39
+ include_examples 'ActsAsOrderedTree::Node#reload', :default
40
+ include_examples 'ActsAsOrderedTree::Node#reload', :default_with_counter_cache
41
+ include_examples 'ActsAsOrderedTree::Node#reload', :scoped
42
+ end
@@ -0,0 +1,193 @@
1
+ # coding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe ActsAsOrderedTree::Node::Siblings, :transactional do
6
+ shared_examples 'siblings' do |model|
7
+ # silence pending examples
8
+ #
9
+ # @todo fix all xits
10
+ def self.xit(*) end
11
+
12
+ let(:root) { create model }
13
+ let(:items) { create_list model, 3, :parent => root }
14
+
15
+ # first
16
+ it { expect(items.first.self_and_siblings).to eq items }
17
+ it { expect(items.first.siblings).to eq [items.second, items.last] }
18
+
19
+ it { expect(items.first.left_sibling).to be nil }
20
+ it { expect(items.first.right_sibling).to eq items.second }
21
+
22
+ it { expect(items.first.left_siblings).to be_empty }
23
+ it { expect(items.first.right_siblings).to eq [items.second, items.last] }
24
+
25
+ # second
26
+ it { expect(items.second.self_and_siblings).to eq items }
27
+ it { expect(items.second.siblings).to eq [items.first, items.last] }
28
+
29
+ it { expect(items.second.left_sibling).to eq items.first }
30
+ it { expect(items.second.right_sibling).to eq items.last }
31
+
32
+ it { expect(items.second.left_siblings).to eq [items.first] }
33
+ it { expect(items.second.right_siblings).to eq [items.last] }
34
+
35
+ # last
36
+ it { expect(items.last.self_and_siblings).to eq items }
37
+ it { expect(items.last.siblings).to eq [items.first, items.second] }
38
+
39
+ it { expect(items.last.left_sibling).to eq items.second }
40
+ it { expect(items.last.right_sibling).to be nil }
41
+
42
+ it { expect(items.last.left_siblings).to eq [items.first, items.second] }
43
+ it { expect(items.last.right_siblings).to be_empty }
44
+
45
+ context 'trying to set left or right sibling with random object' do
46
+ def self.expect_type_mismatch_on(value)
47
+ it "throws error when #{value.class} given" do
48
+ expect {
49
+ items.first.left_sibling = value
50
+ }.to raise_error ActiveRecord::AssociationTypeMismatch
51
+
52
+ expect {
53
+ items.first.right_sibling = value
54
+ }.to raise_error ActiveRecord::AssociationTypeMismatch
55
+ end
56
+ end
57
+
58
+ def self.generate_class
59
+ Class.new(ActiveRecord::Base){ self.table_name = 'categories' }
60
+ end
61
+
62
+ expect_type_mismatch_on(generate_class.new)
63
+ expect_type_mismatch_on(nil)
64
+ end
65
+
66
+ context 'when left sibling is set' do
67
+ context 'and new left sibling has same parent' do
68
+ context 'and new left sibling is higher' do
69
+ let(:item) { items.last }
70
+ before { item.left_sibling = items.first }
71
+
72
+ it { expect(item.parent).to eq items.first.parent }
73
+ it { expect(item.position).to eq 2 }
74
+
75
+ xit { expect(item.left_sibling).to eq items.first }
76
+ xit { expect(item.right_siblings).to eq [items.second] }
77
+ end
78
+
79
+ context 'and new left sibling is lower' do
80
+ let(:item) { items.first }
81
+ before { item.left_sibling = items.last }
82
+
83
+ it { expect(item.parent).to eq items.first.parent }
84
+ it { expect(item.position).to eq 3 }
85
+
86
+ xit { expect(item.left_sibling).to eq items.last }
87
+ xit { expect(item.left_siblings).to eq [items.second, items.last] }
88
+ end
89
+ end
90
+
91
+ context 'and new left sibling has other parent' do
92
+ let(:item) { items.first }
93
+ before { item.left_sibling = root }
94
+
95
+ it { expect(item.parent).to be nil }
96
+ it { expect(item.position).to eq 2 }
97
+
98
+ xit { expect(item.left_sibling).to eq root }
99
+ end
100
+
101
+ context 'via #left_sibling_id=' do
102
+ let(:item) { items.first }
103
+
104
+ it 'throws error when non-existent ID given' do
105
+ expect {
106
+ item.left_sibling_id = -1
107
+ }.to raise_error ActiveRecord::RecordNotFound
108
+ end
109
+
110
+ it 'delegates to #left_sibling=' do
111
+ new_sibling = items.last
112
+
113
+ expect(item.ordered_tree_node).to receive(:left_sibling=).with(new_sibling)
114
+ item.left_sibling_id = new_sibling.id
115
+ end
116
+ end
117
+ end
118
+
119
+ context 'when right sibling is set' do
120
+ context 'and new right sibling has same parent' do
121
+ context 'and new right sibling is higher' do
122
+ let(:item) { items.last }
123
+ before { item.right_sibling = items.first }
124
+
125
+ it { expect(item.parent).to eq items.first.parent }
126
+ it { expect(item.position).to eq 1 }
127
+
128
+ xit { expect(item.right_sibling).to eq item.first }
129
+ xit { expect(item.left_siblings).to be_empty }
130
+ xit { expect(item.right_siblings).to eq [items.first, items.second] }
131
+ end
132
+
133
+ context 'and new right sibling is lower' do
134
+ let(:item) { items.first }
135
+ before { item.right_sibling = items.last }
136
+
137
+ it { expect(item.parent).to eq items.first.parent }
138
+ it { expect(item.position).to eq 2 }
139
+
140
+ xit { expect(item.right_sibling).to eq items.last }
141
+ xit { expect(item.right_siblings).to eq [items.last] }
142
+
143
+ xit { expect(item.left_sibling).to eq items.first }
144
+ xit { expect(item.left_siblings).to eq [items.first] }
145
+ end
146
+ end
147
+
148
+ context 'and new right sibling has other parent' do
149
+ let(:item) { items.first }
150
+ before { item.right_sibling = root }
151
+
152
+ it { expect(item.parent).to be nil }
153
+ it { expect(item.position).to eq 1 }
154
+
155
+ xit { expect(item.right_sibling).to eq root }
156
+ end
157
+
158
+ context 'via #right_sibling_id=' do
159
+ let(:item) { items.first }
160
+
161
+ it 'throws error when non-existent ID given' do
162
+ expect {
163
+ item.right_sibling_id = -1
164
+ }.to raise_error ActiveRecord::RecordNotFound
165
+ end
166
+
167
+ it 'delegates to #right_sibling=' do
168
+ new_sibling = items.last
169
+
170
+ expect(item.ordered_tree_node).to receive(:right_sibling=).with(new_sibling)
171
+ item.right_sibling_id = new_sibling.id
172
+ end
173
+ end
174
+ end
175
+ end
176
+
177
+ context 'Tree without scopes' do
178
+ include_examples 'siblings', :default
179
+ include_examples 'siblings', :default_with_counter_cache
180
+ end
181
+
182
+ context 'Tree with scope' do
183
+ let!(:items_1) { create_list :scoped, 3, :scope_type => 's1' }
184
+ let!(:items_2) { create_list :scoped, 3, :scope_type => 's2' }
185
+
186
+ include_examples 'siblings', :scoped do
187
+ let(:items) { items_1 }
188
+ end
189
+ include_examples 'siblings', :scoped do
190
+ let(:items) { items_2 }
191
+ end
192
+ end
193
+ end