Skip to content

Commit 2bf4a18

Browse files
committed
Improve test quality
1 parent e95314e commit 2bf4a18

File tree

3 files changed

+287
-58
lines changed

3 files changed

+287
-58
lines changed

common/src/main/kotlin/com/lambda/util/GraphUtil.kt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,8 @@ object GraphUtil {
7979
val neighbor = fastVectorOf(origin.x + dx, origin.y + dy, origin.z + dz)
8080
val cost = when (distSq) {
8181
1 -> 1.0
82-
2 -> sqrt(2.0)
83-
3 -> sqrt(3.0)
82+
2 -> COST_SQRT_2
83+
3 -> COST_SQRT_3
8484
else -> error("Unexpected squared distance: $distSq")
8585
}
8686
neighbor to cost
@@ -91,4 +91,7 @@ object GraphUtil {
9191

9292
fun List<FastVector>.string() = joinToString(" -> ") { it.string }
9393
fun List<FastVector>.length() = zipWithNext { a, b -> a dist b }.sum()
94+
95+
private const val COST_SQRT_2 = 1.4142135623730951
96+
private const val COST_SQRT_3 = 1.7320508075688772
9497
}
Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
/*
2+
* Copyright 2025 Lambda
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* This program is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with this program. If not, see <http://www.gnu.org/licenses/>.
16+
*/
17+
18+
package com.lambda.util
19+
20+
import com.lambda.util.GraphUtil.n6
21+
import com.lambda.util.GraphUtil.n18
22+
import com.lambda.util.GraphUtil.n26
23+
import com.lambda.util.GraphUtil.neighborhood
24+
import com.lambda.util.world.FastVector
25+
import com.lambda.util.world.fastVectorOf
26+
import kotlin.math.sqrt
27+
import kotlin.test.Test
28+
import kotlin.test.assertEquals
29+
import kotlin.test.assertTrue
30+
31+
/**
32+
* Unit tests for the neighbor functions in GraphUtil.
33+
*/
34+
class GraphUtilTest {
35+
36+
/**
37+
* Test for n6 function which should return 6-connectivity neighbors
38+
* (only axis-aligned moves).
39+
*/
40+
@Test
41+
fun `test n6 connectivity`() {
42+
val origin = fastVectorOf(0, 0, 0)
43+
val neighbors = n6(origin)
44+
45+
// Should have exactly 6 neighbors
46+
assertEquals(6, neighbors.size, "n6 should return exactly 6 neighbors")
47+
48+
// Expected neighbors (axis-aligned)
49+
val expectedNeighbors = setOf(
50+
fastVectorOf(1, 0, 0),
51+
fastVectorOf(-1, 0, 0),
52+
fastVectorOf(0, 1, 0),
53+
fastVectorOf(0, -1, 0),
54+
fastVectorOf(0, 0, 1),
55+
fastVectorOf(0, 0, -1)
56+
)
57+
58+
// Check that all expected neighbors are present
59+
for (neighbor in expectedNeighbors) {
60+
assertTrue(neighbor in neighbors.keys, "Expected neighbor $neighbor not found")
61+
assertEquals(1.0, neighbors[neighbor], "Cost for axis-aligned neighbor should be 1.0")
62+
}
63+
}
64+
65+
/**
66+
* Test for n18 function which should return 18-connectivity neighbors
67+
* (axis-aligned + face diagonal moves).
68+
*/
69+
@Test
70+
fun `test n18 connectivity`() {
71+
val origin = fastVectorOf(0, 0, 0)
72+
val neighbors = n18(origin)
73+
74+
// Should have exactly 18 neighbors
75+
assertEquals(18, neighbors.size, "n18 should return exactly 18 neighbors")
76+
77+
// Expected axis-aligned neighbors (6)
78+
val expectedAxisNeighbors = setOf(
79+
fastVectorOf(1, 0, 0),
80+
fastVectorOf(-1, 0, 0),
81+
fastVectorOf(0, 1, 0),
82+
fastVectorOf(0, -1, 0),
83+
fastVectorOf(0, 0, 1),
84+
fastVectorOf(0, 0, -1)
85+
)
86+
87+
// Expected face diagonal neighbors (12)
88+
val expectedFaceDiagonalNeighbors = setOf(
89+
// XY plane diagonals
90+
fastVectorOf(1, 1, 0),
91+
fastVectorOf(1, -1, 0),
92+
fastVectorOf(-1, 1, 0),
93+
fastVectorOf(-1, -1, 0),
94+
// XZ plane diagonals
95+
fastVectorOf(1, 0, 1),
96+
fastVectorOf(1, 0, -1),
97+
fastVectorOf(-1, 0, 1),
98+
fastVectorOf(-1, 0, -1),
99+
// YZ plane diagonals
100+
fastVectorOf(0, 1, 1),
101+
fastVectorOf(0, 1, -1),
102+
fastVectorOf(0, -1, 1),
103+
fastVectorOf(0, -1, -1)
104+
)
105+
106+
// Check that all expected axis-aligned neighbors are present
107+
for (neighbor in expectedAxisNeighbors) {
108+
assertTrue(neighbor in neighbors.keys, "Expected axis-aligned neighbor $neighbor not found")
109+
assertEquals(1.0, neighbors[neighbor], "Cost for axis-aligned neighbor should be 1.0")
110+
}
111+
112+
// Check that all expected face diagonal neighbors are present
113+
for (neighbor in expectedFaceDiagonalNeighbors) {
114+
assertTrue(neighbor in neighbors.keys, "Expected face diagonal neighbor $neighbor not found")
115+
assertEquals(sqrt(2.0), neighbors[neighbor], "Cost for face diagonal neighbor should be sqrt(2.0)")
116+
}
117+
}
118+
119+
/**
120+
* Test for n26 function which should return 26-connectivity neighbors
121+
* (axis-aligned + face diagonal + cube diagonal moves).
122+
*/
123+
@Test
124+
fun `test n26 connectivity`() {
125+
val origin = fastVectorOf(0, 0, 0)
126+
val neighbors = n26(origin)
127+
128+
// Should have exactly 26 neighbors
129+
assertEquals(26, neighbors.size, "n26 should return exactly 26 neighbors")
130+
131+
// Expected axis-aligned neighbors (6)
132+
val expectedAxisNeighbors = setOf(
133+
fastVectorOf(1, 0, 0),
134+
fastVectorOf(-1, 0, 0),
135+
fastVectorOf(0, 1, 0),
136+
fastVectorOf(0, -1, 0),
137+
fastVectorOf(0, 0, 1),
138+
fastVectorOf(0, 0, -1)
139+
)
140+
141+
// Expected face diagonal neighbors (12)
142+
val expectedFaceDiagonalNeighbors = setOf(
143+
// XY plane diagonals
144+
fastVectorOf(1, 1, 0),
145+
fastVectorOf(1, -1, 0),
146+
fastVectorOf(-1, 1, 0),
147+
fastVectorOf(-1, -1, 0),
148+
// XZ plane diagonals
149+
fastVectorOf(1, 0, 1),
150+
fastVectorOf(1, 0, -1),
151+
fastVectorOf(-1, 0, 1),
152+
fastVectorOf(-1, 0, -1),
153+
// YZ plane diagonals
154+
fastVectorOf(0, 1, 1),
155+
fastVectorOf(0, 1, -1),
156+
fastVectorOf(0, -1, 1),
157+
fastVectorOf(0, -1, -1)
158+
)
159+
160+
// Expected cube diagonal neighbors (8)
161+
val expectedCubeDiagonalNeighbors = setOf(
162+
fastVectorOf(1, 1, 1),
163+
fastVectorOf(1, 1, -1),
164+
fastVectorOf(1, -1, 1),
165+
fastVectorOf(1, -1, -1),
166+
fastVectorOf(-1, 1, 1),
167+
fastVectorOf(-1, 1, -1),
168+
fastVectorOf(-1, -1, 1),
169+
fastVectorOf(-1, -1, -1)
170+
)
171+
172+
// Check that all expected axis-aligned neighbors are present
173+
for (neighbor in expectedAxisNeighbors) {
174+
assertTrue(neighbor in neighbors.keys, "Expected axis-aligned neighbor $neighbor not found")
175+
assertEquals(1.0, neighbors[neighbor], "Cost for axis-aligned neighbor should be 1.0")
176+
}
177+
178+
// Check that all expected face diagonal neighbors are present
179+
for (neighbor in expectedFaceDiagonalNeighbors) {
180+
assertTrue(neighbor in neighbors.keys, "Expected face diagonal neighbor $neighbor not found")
181+
assertEquals(sqrt(2.0), neighbors[neighbor], "Cost for face diagonal neighbor should be sqrt(2.0)")
182+
}
183+
184+
// Check that all expected cube diagonal neighbors are present
185+
for (neighbor in expectedCubeDiagonalNeighbors) {
186+
assertTrue(neighbor in neighbors.keys, "Expected cube diagonal neighbor $neighbor not found")
187+
assertEquals(sqrt(3.0), neighbors[neighbor], "Cost for cube diagonal neighbor should be sqrt(3.0)")
188+
}
189+
}
190+
191+
/**
192+
* Test for the neighborhood function with custom distance parameters.
193+
*/
194+
@Test
195+
fun `test neighborhood with custom parameters`() {
196+
val origin = fastVectorOf(0, 0, 0)
197+
198+
// Test with minDistSq=2, maxDistSq=2 (should only return face diagonals)
199+
val faceDiagonalNeighbors = neighborhood(origin, minDistSq = 2, maxDistSq = 2)
200+
assertEquals(12, faceDiagonalNeighbors.size, "Should return exactly 12 face diagonal neighbors")
201+
202+
// Test with minDistSq=3, maxDistSq=3 (should only return cube diagonals)
203+
val cubeDiagonalNeighbors = neighborhood(origin, minDistSq = 3, maxDistSq = 3)
204+
assertEquals(8, cubeDiagonalNeighbors.size, "Should return exactly 8 cube diagonal neighbors")
205+
206+
// Test with minDistSq=1, maxDistSq=3 (should return all neighbors, same as n26)
207+
val allNeighbors = neighborhood(origin, minDistSq = 1, maxDistSq = 3)
208+
assertEquals(26, allNeighbors.size, "Should return exactly 26 neighbors (same as n26)")
209+
210+
// Test with invalid range (should return empty map)
211+
val emptyNeighbors = neighborhood(origin, minDistSq = 4, maxDistSq = 5)
212+
assertEquals(0, emptyNeighbors.size, "Should return empty map for invalid distance range")
213+
}
214+
215+
/**
216+
* Test for the neighborhood function with non-origin center point.
217+
*/
218+
@Test
219+
fun `test neighborhood with non-origin center`() {
220+
val center = fastVectorOf(10, 20, 30)
221+
val neighbors = n6(center)
222+
223+
// Should have exactly 6 neighbors
224+
assertEquals(6, neighbors.size, "n6 should return exactly 6 neighbors")
225+
226+
// Expected neighbors (axis-aligned)
227+
val expectedNeighbors = setOf(
228+
fastVectorOf(11, 20, 30),
229+
fastVectorOf(9, 20, 30),
230+
fastVectorOf(10, 21, 30),
231+
fastVectorOf(10, 19, 30),
232+
fastVectorOf(10, 20, 31),
233+
fastVectorOf(10, 20, 29)
234+
)
235+
236+
// Check that all expected neighbors are present
237+
for (neighbor in expectedNeighbors) {
238+
assertTrue(neighbor in neighbors.keys, "Expected neighbor $neighbor not found")
239+
assertEquals(1.0, neighbors[neighbor], "Cost for axis-aligned neighbor should be 1.0")
240+
}
241+
}
242+
}

0 commit comments

Comments
 (0)