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))
0 commit comments