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