Skip to content

Commit 80f8559

Browse files
committed
Add tests for sparse union find.
1 parent 7649b98 commit 80f8559

1 file changed

Lines changed: 173 additions & 0 deletions

File tree

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
//
2+
// Created by andreas on 08.02.26.
3+
//
4+
#include <gtest/gtest.h>
5+
6+
#include <string>
7+
#include <vector>
8+
#include <optional>
9+
10+
// Include your header (adjust path as needed)
11+
#include "union_find_disjoint_set/union_find_sparse.h"
12+
13+
// --------------------
14+
// Basic behavior tests
15+
// --------------------
16+
17+
TEST(UnionFindSparseInt, AddSetBasicAndDuplicate) {
18+
UnionFindSparse<int> union_find;
19+
20+
EXPECT_TRUE(union_find.add_set(1));
21+
EXPECT_TRUE(union_find.add_set(2));
22+
EXPECT_FALSE(union_find.add_set(1)); // duplicate
23+
24+
auto r1 = union_find.get_root(1);
25+
ASSERT_TRUE(r1.has_value());
26+
EXPECT_EQ(*r1, 1);
27+
28+
auto r2 = union_find.get_root(2);
29+
ASSERT_TRUE(r2.has_value());
30+
EXPECT_EQ(*r2, 2);
31+
}
32+
33+
TEST(UnionFindSparseInt, GetRootMissingReturnsNullopt) {
34+
UnionFindSparse<int> union_find;
35+
36+
EXPECT_FALSE(union_find.get_root(42).has_value());
37+
EXPECT_FALSE(union_find.get_root(-7).has_value());
38+
}
39+
40+
TEST(UnionFindSparseInt, UnionSetNoOpIfMissing) {
41+
UnionFindSparse<int> union_find;
42+
union_find.add_set(1);
43+
union_find.add_set(2);
44+
45+
// Missing element -> union does nothing
46+
union_find.union_set(1, 999);
47+
48+
EXPECT_FALSE(union_find.are_connected(1, 999));
49+
EXPECT_FALSE(union_find.get_root(999).has_value());
50+
51+
// Existing sets should remain unchanged
52+
EXPECT_EQ(*union_find.get_root(1), 1);
53+
EXPECT_EQ(*union_find.get_root(2), 2);
54+
EXPECT_FALSE(union_find.are_connected(1, 2));
55+
}
56+
57+
TEST(UnionFindSparseInt, AreConnectedMissingIsFalseEvenIfBothMissing) {
58+
UnionFindSparse<int> union_find;
59+
60+
EXPECT_FALSE(union_find.are_connected(1, 2)); // both missing
61+
union_find.add_set(1);
62+
EXPECT_FALSE(union_find.are_connected(1, 2)); // one missing
63+
}
64+
65+
// --------------------
66+
// Union + find behavior
67+
// --------------------
68+
69+
TEST(UnionFindSparseInt, UnionSetConnectsTwoSingletonsDeterministicRootOnTie) {
70+
UnionFindSparse<int> union_find;
71+
union_find.add_set(10);
72+
union_find.add_set(20);
73+
74+
union_find.union_set(10, 20);
75+
76+
EXPECT_TRUE(union_find.are_connected(10, 20));
77+
78+
EXPECT_EQ(*union_find.get_root(10), *union_find.get_root(20));
79+
}
80+
81+
TEST(UnionFindSparseInt, UnionSetTransitiveConnectivity) {
82+
UnionFindSparse<int> union_find;
83+
union_find.add_set(1);
84+
union_find.add_set(2);
85+
union_find.add_set(3);
86+
union_find.add_set(4);
87+
88+
union_find.union_set(1, 2);
89+
union_find.union_set(2, 3);
90+
91+
EXPECT_TRUE(union_find.are_connected(1, 3));
92+
EXPECT_TRUE(union_find.are_connected(2, 3));
93+
EXPECT_FALSE(union_find.are_connected(1, 4));
94+
EXPECT_FALSE(union_find.are_connected(2, 4));
95+
EXPECT_FALSE(union_find.are_connected(3, 4));
96+
97+
EXPECT_EQ(*union_find.get_root(1), 1);
98+
EXPECT_EQ(*union_find.get_root(2), 1);
99+
EXPECT_EQ(*union_find.get_root(3), 1);
100+
}
101+
102+
TEST(UnionFindSparseInt, UnionSetIdempotentAndSelfUnion) {
103+
UnionFindSparse<int> union_find;
104+
union_find.add_set(5);
105+
union_find.add_set(6);
106+
107+
union_find.union_set(5, 6);
108+
union_find.union_set(5, 6); // repeat
109+
union_find.union_set(6, 5); // reverse
110+
union_find.union_set(5, 5); // self-union
111+
112+
EXPECT_TRUE(union_find.are_connected(5, 6));
113+
EXPECT_EQ(*union_find.get_root(5), 5);
114+
EXPECT_EQ(*union_find.get_root(6), 5);
115+
}
116+
117+
TEST(UnionFindSparseInt, UnionSetMergeTwoComponents) {
118+
UnionFindSparse<int> union_find;
119+
for (int x : {1,2,3,4}) union_find.add_set(x);
120+
121+
union_find.union_set(1, 2);
122+
union_find.union_set(3, 4);
123+
124+
EXPECT_TRUE(union_find.are_connected(1, 2));
125+
EXPECT_TRUE(union_find.are_connected(3, 4));
126+
EXPECT_FALSE(union_find.are_connected(1, 3));
127+
128+
union_find.union_set(2, 3);
129+
130+
EXPECT_TRUE(union_find.are_connected(1, 4));
131+
EXPECT_TRUE(union_find.are_connected(1, 3));
132+
EXPECT_EQ(*union_find.get_root(4), *union_find.get_root(1));
133+
}
134+
135+
// --------------------
136+
// Sparse-domain motivation tests
137+
// --------------------
138+
139+
TEST(UnionFindSparseInt, SupportsNegativeAndLargeIds) {
140+
UnionFindSparse<int> union_find;
141+
union_find.add_set(-10);
142+
union_find.add_set(1'000'000);
143+
union_find.add_set(7);
144+
145+
EXPECT_EQ(*union_find.get_root(-10), -10);
146+
EXPECT_EQ(*union_find.get_root(1'000'000), 1'000'000);
147+
148+
union_find.union_set(-10, 1'000'000);
149+
EXPECT_TRUE(union_find.are_connected(-10, 1'000'000));
150+
EXPECT_EQ(*union_find.get_root(1'000'000), -10); // tie -> second attaches to first
151+
EXPECT_EQ(*union_find.get_root(-10), -10);
152+
153+
EXPECT_FALSE(union_find.are_connected(7, -10));
154+
}
155+
156+
// --------------------
157+
// Template works for other IdTypes
158+
// --------------------
159+
160+
TEST(UnionFindSparseString, WorksForStringIds) {
161+
UnionFindSparse<std::string> union_find;
162+
163+
EXPECT_TRUE(union_find.add_set("alice"));
164+
EXPECT_TRUE(union_find.add_set("bob"));
165+
EXPECT_TRUE(union_find.add_set("charlie"));
166+
167+
union_find.union_set("alice", "bob");
168+
169+
EXPECT_TRUE(union_find.are_connected("alice", "bob"));
170+
EXPECT_FALSE(union_find.are_connected("alice", "charlie"));
171+
172+
EXPECT_EQ(*union_find.get_root("bob"), "alice");
173+
}

0 commit comments

Comments
 (0)