Skip to content

Commit 8269cba

Browse files
committed
Add tests for insert
1 parent c76bdb5 commit 8269cba

File tree

2 files changed

+175
-0
lines changed

2 files changed

+175
-0
lines changed
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
namespace Algorithms.Tests.DataStructures
2+
3+
open Microsoft.VisualStudio.TestTools.UnitTesting
4+
open Algorithms.DataStructures.AVLTree
5+
6+
[<TestClass>]
7+
type AVLTreeTests() =
8+
9+
let rec verifyBalance (maybeNode: Option<AVLNode>) =
10+
match maybeNode with
11+
| None -> ()
12+
| Some node ->
13+
let bf = AVLNode.balanceFactor node
14+
Assert.IsTrue(bf >= -1 && bf <= 1, $"Balance factor {bf} is out of range")
15+
verifyBalance node.LeftChild
16+
verifyBalance node.RightChild
17+
18+
let rec verifyHeights (maybeNode: Option<AVLNode>) =
19+
match maybeNode with
20+
| None -> ()
21+
| Some node ->
22+
let leftHeight = AVLNode.height node.LeftChild
23+
let rightHeight = AVLNode.height node.RightChild
24+
Assert.AreEqual(node.Height, 1 + max leftHeight rightHeight)
25+
26+
verifyHeights node.LeftChild
27+
verifyHeights node.RightChild
28+
29+
let rec verifyBST (maybeNode: Option<AVLNode>) : Option< (* Min *) int * (* Max*) int> =
30+
match maybeNode with
31+
| None -> None
32+
| Some node ->
33+
let maybeLeftMinMax = verifyBST node.LeftChild
34+
let maybeRightMinMax = verifyBST node.RightChild
35+
maybeLeftMinMax
36+
|> Option.iter (fun (_, leftMax) ->
37+
Assert.IsTrue(leftMax < node.Value, $"Left child {leftMax} is greater than parent {node.Value}")
38+
)
39+
maybeRightMinMax
40+
|> Option.iter (fun (rightMin, _) ->
41+
Assert.IsTrue(rightMin > node.Value, $"Right child {rightMin} is less than parent {node.Value}")
42+
)
43+
let minValue =
44+
maybeLeftMinMax
45+
|> Option.map fst
46+
|> Option.defaultValue node.Value
47+
let maxValue =
48+
maybeRightMinMax
49+
|> Option.map snd
50+
|> Option.defaultValue node.Value
51+
Some (minValue, maxValue)
52+
53+
let verifyProperties (tree: AVLTree) =
54+
verifyBalance tree.Root
55+
verifyHeights tree.Root
56+
verifyBST tree.Root |> ignore
57+
tree
58+
59+
[<TestMethod>]
60+
member _.``Empty tree has no root``() =
61+
let tree =
62+
empty
63+
|> verifyProperties
64+
65+
Assert.IsTrue(tree.Root.IsNone)
66+
67+
[<TestMethod>]
68+
member _.``Insert maintains AVL properties``() =
69+
let tree =
70+
empty
71+
|> verifyProperties
72+
|> insert 5
73+
|> verifyProperties
74+
|> insert 3
75+
|> verifyProperties
76+
|> insert 7
77+
|> verifyProperties
78+
|> insert 1
79+
|> verifyProperties
80+
|> insert 9
81+
|> verifyProperties
82+
|> insert 1
83+
|> verifyProperties
84+
()
85+
86+
[<TestMethod>]
87+
member _.``Right-heavy case triggers rotation``() =
88+
let tree =
89+
empty
90+
|> verifyProperties
91+
|> insert 1
92+
|> verifyProperties
93+
|> insert 2
94+
|> verifyProperties
95+
|> insert 3
96+
|> verifyProperties
97+
98+
Assert.IsTrue(tree.Root.IsSome)
99+
let root = tree.Root.Value
100+
Assert.AreEqual(2, root.Value)
101+
Assert.AreEqual(Some 1, root.LeftChild |> Option.map (fun n -> n.Value))
102+
Assert.AreEqual(Some 3, root.RightChild |> Option.map (fun n -> n.Value))
103+
104+
[<TestMethod>]
105+
member _.``Left-heavy case triggers rotation``() =
106+
let tree =
107+
empty
108+
|> verifyProperties
109+
|> insert 3
110+
|> verifyProperties
111+
|> insert 2
112+
|> verifyProperties
113+
|> insert 1
114+
|> verifyProperties
115+
116+
Assert.IsTrue(tree.Root.IsSome)
117+
let root = tree.Root.Value
118+
Assert.AreEqual(2, root.Value)
119+
Assert.AreEqual(Some 1, root.LeftChild |> Option.map (fun n -> n.Value))
120+
Assert.AreEqual(Some 3, root.RightChild |> Option.map (fun n -> n.Value))
121+
122+
[<TestMethod>]
123+
member _.``Double rotation for right-left case``() =
124+
let tree =
125+
empty
126+
|> verifyProperties
127+
|> insert 1
128+
|> verifyProperties
129+
|> insert 3
130+
|> verifyProperties
131+
|> insert 2
132+
|> verifyProperties
133+
134+
Assert.IsTrue(tree.Root.IsSome)
135+
let root = tree.Root.Value
136+
Assert.AreEqual(2, root.Value)
137+
Assert.AreEqual(Some 1, root.LeftChild |> Option.map (fun n -> n.Value))
138+
Assert.AreEqual(Some 3, root.RightChild |> Option.map (fun n -> n.Value))
139+
140+
[<TestMethod>]
141+
member _.``Double rotation for left-right case``() =
142+
let tree =
143+
empty
144+
|> verifyProperties
145+
|> insert 3
146+
|> verifyProperties
147+
|> insert 1
148+
|> verifyProperties
149+
|> insert 2
150+
|> verifyProperties
151+
152+
Assert.IsTrue(tree.Root.IsSome)
153+
let root = tree.Root.Value
154+
Assert.AreEqual(2, root.Value)
155+
Assert.AreEqual(Some 1, root.LeftChild |> Option.map (fun n -> n.Value))
156+
Assert.AreEqual(Some 3, root.RightChild |> Option.map (fun n -> n.Value))
157+
158+
[<TestMethod>]
159+
member _.``Duplicate insert is idempotent``() =
160+
let tree1 =
161+
empty
162+
|> verifyProperties
163+
|> insert 1
164+
|> verifyProperties
165+
|> insert 2
166+
|> verifyProperties
167+
168+
let tree2 =
169+
insert 2 tree1
170+
|> verifyProperties
171+
172+
Assert.AreEqual(tree1.Root |> Option.map (fun n -> n.Value),
173+
tree2.Root |> Option.map (fun n -> n.Value))

Algorithms/DataStructures/AVLTree.fs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ module AVLTree =
5959
Root: Option<AVLNode>
6060
}
6161

62+
let empty = { Root = None }
63+
6264
let insert (value: int) (tree: AVLTree) : AVLTree =
6365
let rec insertImpl (maybeNode: Option<AVLNode>) : AVLNode =
6466
match maybeNode with

0 commit comments

Comments
 (0)