Skip to content

Commit 17af7a3

Browse files
committed
test: add white-box unit tests for Luhn.luhnCheck
Cover the loop (zero, one and many iterations), both outcomes of the `i % 2 == 0` and `temp > 9` decisions, boundary values (8 / 10 after doubling), valid and invalid checksums, input immutability and null input.
1 parent 9d9e348 commit 17af7a3

1 file changed

Lines changed: 111 additions & 0 deletions

File tree

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package com.thealgorithms.others;
2+
3+
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
4+
import static org.junit.jupiter.api.Assertions.assertFalse;
5+
import static org.junit.jupiter.api.Assertions.assertThrows;
6+
import static org.junit.jupiter.api.Assertions.assertTrue;
7+
8+
import org.junit.jupiter.api.Test;
9+
10+
/**
11+
* White-box tests for {@link Luhn#luhnCheck(int[])}.
12+
*
13+
* <p>The method has one loop and two decisions:
14+
* <ul>
15+
* <li>D1: {@code i % 2 == 0} - whether the digit at index i is doubled</li>
16+
* <li>D2: {@code temp > 9} - whether 9 is subtracted from the doubled digit</li>
17+
* </ul>
18+
* The tests below cover the loop executed zero, one and many times, both
19+
* outcomes of each decision, and both outcomes of the final {@code sum % 10 == 0}.
20+
*/
21+
class LuhnTest {
22+
23+
@Test
24+
void testEmptyArraySkipsLoopAndIsValid() {
25+
// Loop body never executes, sum stays 0
26+
assertTrue(Luhn.luhnCheck(new int[] {}));
27+
}
28+
29+
@Test
30+
void testSingleZeroDigitIsValid() {
31+
// One iteration: D1 true, D2 false (0 * 2 = 0)
32+
assertTrue(Luhn.luhnCheck(new int[] {0}));
33+
}
34+
35+
@Test
36+
void testSingleDigitDoubledWithoutSubtractionIsInvalid() {
37+
// One iteration: D1 true, D2 false (4 * 2 = 8, upper boundary of temp <= 9)
38+
assertFalse(Luhn.luhnCheck(new int[] {4}));
39+
}
40+
41+
@Test
42+
void testSingleDigitDoubledWithSubtractionIsInvalid() {
43+
// One iteration: D1 true, D2 true (5 * 2 = 10, lower boundary of temp > 9 -> 1)
44+
assertFalse(Luhn.luhnCheck(new int[] {5}));
45+
}
46+
47+
@Test
48+
void testTwoDigitsWithoutSubtraction() {
49+
// i = 1: D1 false -> 2; i = 0: D1 true, D2 false -> 8; sum = 10
50+
assertTrue(Luhn.luhnCheck(new int[] {4, 2}));
51+
}
52+
53+
@Test
54+
void testTwoDigitsWithSubtraction() {
55+
// i = 1: D1 false -> 9; i = 0: D1 true, D2 true -> 10 - 9 = 1; sum = 10
56+
assertTrue(Luhn.luhnCheck(new int[] {5, 9}));
57+
}
58+
59+
@Test
60+
void testTwoDigitsInvalidChecksum() {
61+
// i = 1: D1 false -> 3; i = 0: D1 true, D2 false -> 8; sum = 11
62+
assertFalse(Luhn.luhnCheck(new int[] {4, 3}));
63+
}
64+
65+
@Test
66+
void testMaxDigitDoubled() {
67+
// i = 1: D1 false -> 0; i = 0: D1 true, D2 true -> 18 - 9 = 9; sum = 9
68+
assertFalse(Luhn.luhnCheck(new int[] {9, 0}));
69+
// i = 1: D1 false -> 1; i = 0: D1 true, D2 true -> 9; sum = 10
70+
assertTrue(Luhn.luhnCheck(new int[] {9, 1}));
71+
}
72+
73+
@Test
74+
void testValidCardNumbers() {
75+
// Many iterations, all branch combinations exercised
76+
assertTrue(Luhn.luhnCheck(new int[] {4, 5, 6, 1, 2, 6, 1, 2, 1, 2, 3, 4, 5, 4, 6, 7}));
77+
assertTrue(Luhn.luhnCheck(new int[] {5, 2, 6, 5, 9, 2, 5, 1, 6, 1, 5, 1, 1, 4, 1, 2}));
78+
assertTrue(Luhn.luhnCheck(new int[] {4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}));
79+
}
80+
81+
@Test
82+
void testCardNumberWithTypoInLastDigitIsInvalid() {
83+
assertFalse(Luhn.luhnCheck(new int[] {4, 5, 6, 1, 2, 6, 1, 2, 1, 2, 3, 4, 5, 4, 6, 4}));
84+
}
85+
86+
@Test
87+
void testCardNumberWithSingleDigitErrorIsInvalid() {
88+
// Error in a doubled position (index 0)
89+
assertFalse(Luhn.luhnCheck(new int[] {3, 5, 6, 1, 2, 6, 1, 2, 1, 2, 3, 4, 5, 4, 6, 7}));
90+
// Error in a non-doubled position (index 1)
91+
assertFalse(Luhn.luhnCheck(new int[] {4, 6, 6, 1, 2, 6, 1, 2, 1, 2, 3, 4, 5, 4, 6, 7}));
92+
}
93+
94+
@Test
95+
void testAllZerosIsValid() {
96+
assertTrue(Luhn.luhnCheck(new int[16]));
97+
}
98+
99+
@Test
100+
void testInputArrayIsNotModified() {
101+
int[] digits = {5, 2, 6, 5, 9, 2, 5, 1, 6, 1, 5, 1, 1, 4, 1, 2};
102+
int[] copy = digits.clone();
103+
Luhn.luhnCheck(digits);
104+
assertArrayEquals(copy, digits);
105+
}
106+
107+
@Test
108+
void testNullInputThrowsNullPointerException() {
109+
assertThrows(NullPointerException.class, () -> Luhn.luhnCheck(null));
110+
}
111+
}

0 commit comments

Comments
 (0)