Skip to content

Commit 691a7bc

Browse files
committed
tests: rationalize rspec suites toward common API usage examples
Trim duplicated RSpec coverage for core tree families and keep specs focused on readable common API usage flows. Retain exhaustive edge-case and regression coverage in Test::Unit. Update README, spec/README, and CHANGELOG to reflect suite responsibilities. Validation: rake lint, rake test:all, rake doc:check.
1 parent 38b14c1 commit 691a7bc

10 files changed

Lines changed: 188 additions & 697 deletions

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ Changes section to scan for breaking or behavioral changes.
88

99
### 3.0.0pre / 2026-02-10
1010

11+
* Rationalize RSpec coverage for core tree families so specs emphasize common
12+
API usage readability, while exhaustive edge-case and regression coverage
13+
remains in the Test::Unit suite.
1114
* Add non-breaking API aliases for consistency:
1215
`Tree::AATree#lookup`, `Tree::BTree#lookup`,
1316
`Tree::FenwickTree#query`, `Tree::SegmentTree#query`,

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@ Development dependencies (not required for installing the gem):
180180
* [Bundler][] for creating the stable build environment
181181
* [Rake][] for building the package
182182
* [YARD][] for the documentation
183-
* [RSpec][] for additional Ruby Spec test files
183+
* Test::Unit for exhaustive edge-case and regression coverage in `test/`
184+
* [RSpec][] for readable common API usage examples in `spec/`
184185
* [RuboCop][] for linting the code
185186

186187
Note: `Tree::TreeNode.new` accepts `{ checks: false }` to disable validation

spec/README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# RSpec Coverage Notes
22

3-
RSpec examples in this repository focus on small, readable behavior checks
4-
such as initialization and cloning. API-level and regression coverage lives
3+
RSpec examples in this repository focus on readable, common API usage flows
4+
for each tree type (construction, typical mutations, and representative
5+
queries/traversals).
6+
7+
Edge-case matrices, exhaustive invariants, and regression contracts live
58
primarily in the Test::Unit suite under `test/`.

spec/tree/aa_tree_spec.rb

Lines changed: 33 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -9,143 +9,73 @@ def build_tree(entries)
99
described_class.new(entries)
1010
end
1111

12-
describe 'insert' do
13-
it 'keeps keys ordered' do
14-
tree = build_tree([[10, 'a'], [20, 'b'], [5, 'c'], [6, 'd'], [12, 'e']])
15-
expect(tree.keys).to eq(tree.keys.sort)
16-
end
17-
end
12+
describe 'common key/value usage' do
13+
let(:tree) { build_tree([[10, 'a'], [20, 'b'], [5, 'c']]) }
1814

19-
describe 'search' do
20-
it 'finds an existing key' do
21-
tree = build_tree([[10, 'a'], [20, 'b'], [5, 'c']])
15+
it 'supports lookup by key' do
2216
expect(tree.search(20)).to eq('b')
2317
end
2418

25-
it 'returns nil for a missing key' do
26-
tree = build_tree([[10, 'a'], [20, 'b']])
27-
expect(tree.search(99)).to be_nil
28-
end
29-
end
30-
31-
describe 'delete' do
32-
it 'removes a leaf key' do
33-
tree = build_tree([[10, 'a'], [20, 'b'], [5, 'c']])
34-
expect(tree.delete(5)).to eq('c')
35-
end
36-
37-
it 'removes the key from the tree' do
38-
tree = build_tree([[10, 'a'], [20, 'b'], [5, 'c']])
39-
tree.delete(5)
40-
expect(tree.search(5)).to be_nil
41-
end
42-
43-
it 'keeps keys ordered after delete' do
44-
tree = build_tree([[10, 'a'], [20, 'b'], [5, 'c'], [6, 'd'], [12, 'e']])
45-
tree.delete(10)
46-
expect(tree.keys).to eq(tree.keys.sort)
19+
it 'keeps keys in sorted order' do
20+
expect(tree.keys).to eq([5, 10, 20])
4721
end
4822
end
4923

50-
describe 'initialize' do
51-
it 'accepts array entries' do
52-
tree = build_tree([[1, 'a'], [2, 'b']])
53-
expect(tree.to_a).to eq([[1, 'a'], [2, 'b']])
54-
end
24+
describe 'index-style access' do
25+
let(:tree) { build_tree([[10, 'a'], [20, 'b']]) }
5526

56-
it 'accepts hash entries' do
57-
tree = build_tree([{ key: 2, value: 'b' }, { key: 1, value: 'a' }])
58-
expect(tree.to_a).to eq([[1, 'a'], [2, 'b']])
59-
end
60-
end
61-
62-
describe '[]' do
63-
it 'returns the value for a key' do
64-
tree = build_tree([[10, 'a'], [20, 'b']])
27+
it 'reads values with []' do
6528
expect(tree[20]).to eq('b')
6629
end
67-
end
6830

69-
describe '[]=' do
70-
it 'updates the value for a key' do
71-
tree = build_tree([[10, 'a'], [20, 'b']])
31+
it 'updates values with []=' do
7232
tree[20] = 'z'
7333
expect(tree.search(20)).to eq('z')
7434
end
7535
end
7636

77-
describe 'each' do
78-
it 'yields entries in key order' do
79-
tree = build_tree([[10, 'a'], [5, 'b'], [20, 'c']])
80-
expect(tree.map(&:key)).to eq([5, 10, 20])
81-
end
82-
end
83-
84-
describe 'preordered_each' do
85-
it 'yields all keys' do
86-
tree = build_tree([[10, 'a'], [5, 'b'], [20, 'c'], [15, 'd']])
87-
keys = tree.preordered_each.map(&:key)
88-
expect(keys.sort).to eq([5, 10, 15, 20])
89-
end
90-
end
37+
describe 'delete' do
38+
let(:tree) { build_tree([[10, 'a'], [20, 'b'], [5, 'c']]) }
9139

92-
describe 'postordered_each' do
93-
it 'yields all keys' do
94-
tree = build_tree([[10, 'a'], [5, 'b'], [20, 'c'], [15, 'd']])
95-
keys = tree.postordered_each.map(&:key)
96-
expect(keys.sort).to eq([5, 10, 15, 20])
40+
it 'returns the deleted value' do
41+
expect(tree.delete(5)).to eq('c')
9742
end
98-
end
9943

100-
describe 'breadth_each' do
101-
it 'yields all keys' do
102-
tree = build_tree([[10, 'a'], [5, 'b'], [20, 'c'], [15, 'd']])
103-
keys = tree.breadth_each.map(&:key)
104-
expect(keys.sort).to eq([5, 10, 15, 20])
44+
it 'removes the key from lookup results' do
45+
tree.delete(5)
46+
expect(tree.search(5)).to be_nil
10547
end
106-
end
10748

108-
describe 'keys' do
109-
it 'returns keys in order' do
110-
tree = build_tree([[10, 'a'], [5, 'b'], [20, 'c']])
111-
expect(tree.keys).to eq([5, 10, 20])
49+
it 'keeps ordered keys after deletion' do
50+
tree.delete(5)
51+
expect(tree.keys).to eq([10, 20])
11252
end
11353
end
11454

115-
describe 'values' do
116-
it 'returns values in key order' do
117-
tree = build_tree([[10, 'a'], [5, 'b'], [20, 'c']])
118-
expect(tree.values).to eq(%w[b a c])
119-
end
120-
end
55+
describe 'enumeration and serialization usage' do
56+
let(:tree) { build_tree([[10, 'a'], [5, 'b'], [20, 'c']]) }
12157

122-
describe 'to_a' do
123-
it 'returns key/value pairs in order' do
124-
tree = build_tree([[10, 'a'], [5, 'b'], [20, 'c']])
125-
expect(tree.to_a).to eq([[5, 'b'], [10, 'a'], [20, 'c']])
58+
it 'enumerates entries in key order' do
59+
pairs = tree.map { |entry| [entry.key, entry.value] }
60+
expect(pairs).to eq([[5, 'b'], [10, 'a'], [20, 'c']])
12661
end
127-
end
12862

129-
describe 'to_h and from_hash' do
130-
it 'round trips the tree' do
131-
tree = build_tree([[10, 'a'], [5, 'b'], [20, 'c']])
63+
it 'round-trips via hash conversion' do
13264
rebuilt = described_class.from_hash(tree.to_h)
13365
expect(rebuilt.to_a).to eq(tree.to_a)
13466
end
13567
end
13668

137-
describe 'as_json' do
138-
it 'returns a hash representation' do
139-
tree = build_tree([[10, 'a']])
140-
expect(tree.as_json).to be_a(Hash)
69+
describe 'shovel insertion' do
70+
let(:tree) { build_tree([]) }
71+
72+
it 'returns the inserted entry' do
73+
expect((tree << [10, 'a']).key).to eq(10)
14174
end
142-
end
14375

144-
describe '<=>' do
145-
it 'compares by ordered entries' do
146-
left = build_tree([[10, 'a'], [5, 'b']])
147-
right = build_tree([[10, 'a'], [5, 'c']])
148-
expect(left <=> right).to eq(-1)
76+
it 'stores the inserted value' do
77+
tree << [10, 'a']
78+
expect(tree.search(10)).to eq('a')
14979
end
15080
end
15181

@@ -155,20 +85,4 @@ def build_tree(entries)
15585
expect { tree.insert(nil, 'a') }.to raise_error(ArgumentError)
15686
end
15787
end
158-
159-
describe '<<' do
160-
it 'returns the inserted entry' do
161-
tree = build_tree([])
162-
inserted = tree << [10, 'a']
163-
164-
expect(inserted.key).to eq(10)
165-
end
166-
167-
it 'stores the inserted key/value pair' do
168-
tree = build_tree([])
169-
tree << [10, 'a']
170-
171-
expect(tree.search(10)).to eq('a')
172-
end
173-
end
17488
end

spec/tree/avl_tree_node_spec.rb

Lines changed: 18 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -42,88 +42,42 @@ def height_of(node)
4242

4343
def build_tree(values)
4444
root = described_class.new('root', values.first)
45-
values.drop(1).each_with_index do |value, idx|
46-
root.insert("n#{idx}", value)
45+
values.drop(1).each_with_index do |value, index|
46+
root.insert("n#{index}", value)
4747
end
4848
root
4949
end
5050

51-
describe 'inserts' do
52-
let(:root) { build_tree([10, 5, 15, 12, 18, 2, 8, 6, 1]) }
51+
let(:root) { build_tree([10, 5, 15, 12, 18, 2, 8]) }
5352

54-
it 'keeps in-order traversal sorted' do
55-
expect(inorder_contents(root)).to eq(inorder_contents(root).sort)
56-
end
57-
58-
it 'maintains AVL invariants' do
59-
expect(avl_valid?(root)).to be(true)
60-
end
53+
it 'finds inserted keys' do
54+
expect(root.search(15).content).to eq(15)
6155
end
6256

63-
describe 'search' do
64-
let(:root) { build_tree([10, 5, 15]) }
65-
66-
it 'finds an existing key' do
67-
expect(root.search(15).content).to eq(15)
68-
end
69-
70-
it 'returns nil for a missing key' do
71-
expect(root.search(7)).to be_nil
72-
end
57+
it 'returns nil for missing keys' do
58+
expect(root.search(7)).to be_nil
7359
end
7460

75-
describe 'delete leaf' do
76-
let(:root) { build_tree([10, 5, 15, 2]) }
77-
78-
before { root.delete(2) }
79-
80-
it 'keeps in-order traversal sorted' do
81-
expect(inorder_contents(root)).to eq(inorder_contents(root).sort)
82-
end
83-
84-
it 'maintains AVL invariants' do
85-
expect(avl_valid?(root)).to be(true)
86-
end
61+
it 'keeps in-order traversal sorted' do
62+
expect(inorder_contents(root)).to eq(inorder_contents(root).sort)
8763
end
8864

89-
describe 'delete node with one child' do
90-
let(:root) { build_tree([10, 5, 2]) }
91-
92-
before { root.delete(5) }
93-
94-
it 'keeps in-order traversal sorted' do
95-
expect(inorder_contents(root)).to eq(inorder_contents(root).sort)
96-
end
97-
98-
it 'maintains AVL invariants' do
99-
expect(avl_valid?(root)).to be(true)
100-
end
65+
it 'maintains AVL invariants after inserts' do
66+
expect(avl_valid?(root)).to be(true)
10167
end
10268

103-
describe 'delete node with two children' do
104-
let(:root) { build_tree([10, 5, 15, 12, 18, 2]) }
105-
106-
before { root.delete(15) }
69+
describe 'delete usage' do
70+
before { root.delete(12) }
10771

108-
it 'keeps in-order traversal sorted' do
109-
expect(inorder_contents(root)).to eq(inorder_contents(root).sort)
110-
end
111-
112-
it 'maintains AVL invariants' do
113-
expect(avl_valid?(root)).to be(true)
72+
it 'removes deleted keys from search' do
73+
expect(root.search(12)).to be_nil
11474
end
115-
end
116-
117-
describe 'delete root' do
118-
let(:root) { build_tree([10, 5, 15, 12]) }
11975

120-
before { root.delete(10) }
121-
122-
it 'keeps in-order traversal sorted' do
123-
expect(inorder_contents(root.root)).to eq(inorder_contents(root.root).sort)
76+
it 'keeps in-order traversal sorted after delete' do
77+
expect(inorder_contents(root)).to eq(inorder_contents(root).sort)
12478
end
12579

126-
it 'maintains AVL invariants' do
80+
it 'maintains AVL invariants after delete' do
12781
expect(avl_valid?(root)).to be(true)
12882
end
12983
end

0 commit comments

Comments
 (0)