Просмотр исходного кода

Merge pull request #247 from exercism/update-luhn

luhn: update tests and sample implementation
John Ryan 9 лет назад
Родитель
Сommit
06424a532a

+ 0
- 90
exercises/luhn/src/example/java/Luhn.java Просмотреть файл

1
-import java.util.stream.IntStream;
2
-
3
-public class Luhn {
4
-
5
-    private long number;
6
-    private long checkDigit;
7
-    private int[] addends;
8
-    private int checkSum;
9
-    private boolean isValid;
10
-
11
-    public Luhn(long number) {
12
-        this.number = number;
13
-        this.checkDigit = number % 10;
14
-        this.addends = generateAddends();
15
-        this.checkSum = IntStream.of(addends).sum();
16
-        this.isValid = checkSum % 10 == 0;
17
-    }
18
-
19
-    public long getCheckDigit() {
20
-        return checkDigit;
21
-    }
22
-
23
-    public int[] getAddends() {
24
-        return addends;
25
-    }
26
-
27
-    public int getCheckSum() {
28
-        return checkSum;
29
-    }
30
-
31
-    public boolean isValid() {
32
-        return isValid;
33
-    }
34
-
35
-    private int[] generateAddends() {
36
-        int[] reversedIntArray = splitToReversedIntArray(number);
37
-
38
-        for (int index = 1; index < reversedIntArray.length; index++) {
39
-            if (index % 2 != 0) {
40
-                reversedIntArray[index] = convertDigitForAddend(reversedIntArray[index]);
41
-            }
42
-        }
43
-
44
-        return reverseIntArray(reversedIntArray);
45
-    }
46
-
47
-    private static int[] splitToReversedIntArray(long value) {
48
-        int[] ints = new StringBuilder(Long.toString(value))
49
-                .reverse()
50
-                .toString()
51
-                .chars()
52
-                .map(x -> Character.getNumericValue(x))
53
-                .toArray();
54
-
55
-        return ints;
56
-    }
57
-
58
-    private static int convertDigitForAddend(int value) {
59
-        int doubled = value * 2;
60
-
61
-        return doubled < 10 ? doubled : doubled - 9;
62
-    }
63
-
64
-    public static long create(long number) {
65
-        long zeroCheckDigitNumber = number * 10;
66
-        Luhn luhn = new Luhn(zeroCheckDigitNumber);
67
-
68
-        if (luhn.isValid()) {
69
-            return zeroCheckDigitNumber;
70
-        }
71
-
72
-        return zeroCheckDigitNumber + createCheckDigit(luhn.getCheckSum());
73
-    }
74
-
75
-    private static int createCheckDigit(int value) {
76
-        int nearestTen = (int) (Math.ceil(value / 10.0) * 10);
77
-
78
-        return nearestTen - value;
79
-    }
80
-
81
-    private static int[] reverseIntArray(int[] array) {
82
-        int[] reversed = new int[array.length];
83
-
84
-        for (int index = 0; index < array.length; index++) {
85
-            reversed[index] = array[array.length - 1 - index];
86
-        }
87
-
88
-        return reversed;
89
-    }
90
-}

+ 43
- 0
exercises/luhn/src/example/java/LuhnValidator.java Просмотреть файл

1
+import java.util.ArrayList;
2
+import java.util.List;
3
+import java.util.regex.Pattern;
4
+
5
+final class LuhnValidator {
6
+
7
+    private static final Pattern SPACE_PATTERN = Pattern.compile("\\s+");
8
+
9
+    boolean isValid(final String candidate) {
10
+        final String sanitizedCandidate = SPACE_PATTERN.matcher(candidate).replaceAll("");
11
+
12
+        final List<Integer> computedDigits = new ArrayList<>();
13
+
14
+        for (int charIndex = 0; charIndex < sanitizedCandidate.length(); charIndex++) {
15
+            int inputDigit = Character.digit(sanitizedCandidate.charAt(charIndex), 10);
16
+
17
+            /*
18
+             * Character.digit returns a negative int if the supplied character does not represent a digit with respect
19
+             * to the given radix.
20
+             */
21
+            if (inputDigit < 0) {
22
+                return false;
23
+            }
24
+
25
+            if (charIndex % 2 == 1) {
26
+                /*
27
+                 * Since our doubled input digit must lie in [2, 18], the operation
28
+                 *
29
+                 *   "subtract 9 from the doubled input digit if it exceeds 9 in value"
30
+                 *
31
+                 * is equivalent to applying the modulo operation below universally.
32
+                 */
33
+                inputDigit = (2 * inputDigit) % 9;
34
+            }
35
+
36
+            computedDigits.add(inputDigit);
37
+        }
38
+
39
+        final int digitSum = computedDigits.stream().mapToInt(Integer::intValue).sum();
40
+        return digitSum > 0 && digitSum % 10 == 0;
41
+    }
42
+
43
+}

+ 0
- 95
exercises/luhn/src/test/java/LuhnTest.java Просмотреть файл

1
-import org.junit.Test;
2
-import org.junit.Ignore;
3
-
4
-import static org.junit.Assert.assertArrayEquals;
5
-import static org.junit.Assert.assertEquals;
6
-
7
-public class LuhnTest {
8
-
9
-
10
-    @Test
11
-    public void checkDigitIsRightMostDigit() {
12
-        Luhn luhn = new Luhn(34567);
13
-        int expectedOutput = 7;
14
-
15
-        assertEquals(expectedOutput, luhn.getCheckDigit());
16
-    }
17
-
18
-    @Ignore
19
-    @Test
20
-    public void addendsDoublesEveryOtherNumberFromRight() {
21
-        Luhn luhn = new Luhn(12121);
22
-        int[] expectedOutput = new int[]{1, 4, 1, 4, 1};
23
-
24
-        assertArrayEquals(expectedOutput, luhn.getAddends());
25
-    }
26
-
27
-    @Ignore
28
-    @Test
29
-    public void addendsSubtracts9WhenDoubledNumberIsMoreThan9() {
30
-        Luhn luhn = new Luhn(8631);
31
-        int[] expectedOutput = new int[]{7, 6, 6, 1};
32
-
33
-        assertArrayEquals(expectedOutput, luhn.getAddends());
34
-    }
35
-
36
-    @Ignore
37
-    @Test
38
-    public void checkSumAddsAddendsTogether1() {
39
-        Luhn luhn = new Luhn(4913);
40
-        int expectedOutput = 22;
41
-
42
-        assertEquals(expectedOutput, luhn.getCheckSum());
43
-    }
44
-
45
-    @Ignore
46
-    @Test
47
-    public void checkSumAddsAddendsTogether2() {
48
-        Luhn luhn = new Luhn(201773);
49
-        int expectedOutput = 21;
50
-
51
-        assertEquals(expectedOutput, luhn.getCheckSum());
52
-    }
53
-
54
-    @Ignore
55
-    @Test
56
-    public void numberIsValidWhenChecksumMod10IsZero1() {
57
-        Luhn luhn = new Luhn(738);
58
-        boolean expectedOutput = false;
59
-
60
-        assertEquals(expectedOutput, luhn.isValid());
61
-    }
62
-
63
-    @Ignore
64
-    @Test
65
-    public void numberIsValidWhenChecksumMod10IsZero2() {
66
-        Luhn luhn = new Luhn(8739567);
67
-        boolean expectedOutput = true;
68
-
69
-        assertEquals(expectedOutput, luhn.isValid());
70
-    }
71
-
72
-    @Ignore
73
-    @Test
74
-    public void luhnCanCreateSimpleNumbersWithValidCheckDigit() {
75
-        long expectedOutput = 1230;
76
-
77
-        assertEquals(expectedOutput, Luhn.create(123));
78
-    }
79
-
80
-    @Ignore
81
-    @Test
82
-    public void luhnCanCreateLargeNumbersWithValidCheckDigit() {
83
-        long expectedOutput = 8739567;
84
-
85
-        assertEquals(expectedOutput, Luhn.create(873956));
86
-    }
87
-
88
-    @Ignore
89
-    @Test
90
-    public void luhnCanCreateHugeNumbersWithValidCheckDigit() {
91
-        long expectedOutput = 8372637564L;
92
-
93
-        assertEquals(expectedOutput, Luhn.create(837263756));
94
-    }
95
-}

+ 44
- 0
exercises/luhn/src/test/java/LuhnValidatorTest.java Просмотреть файл

1
+import org.junit.Ignore;
2
+import org.junit.Test;
3
+
4
+import static org.junit.Assert.assertFalse;
5
+import static org.junit.Assert.assertTrue;
6
+
7
+public class LuhnValidatorTest {
8
+
9
+    @Test
10
+    public void testThatSingleDigitStringIsNotValid() {
11
+        assertFalse(new LuhnValidator().isValid("1"));
12
+    }
13
+
14
+    @Ignore
15
+    @Test
16
+    public void testThatTheStringConsistingOfASingleZeroIsInvalid() {
17
+        assertFalse(new LuhnValidator().isValid("0"));
18
+    }
19
+
20
+    @Ignore
21
+    @Test
22
+    public void testThatAValidCanadianSocialInsuranceNumberIsIdentifiedAsValid() {
23
+        assertTrue(new LuhnValidator().isValid("046 454 286"));
24
+    }
25
+
26
+    @Ignore
27
+    @Test
28
+    public void testThatAnInvalidCanadianSocialInsuranceNumberIsIdentifiedAsInvalid() {
29
+        assertFalse(new LuhnValidator().isValid("046 454 287"));
30
+    }
31
+
32
+    @Ignore
33
+    @Test
34
+    public void testThatAnInvalidCreditCardIsIdentifiedAsInvalid() {
35
+        assertFalse(new LuhnValidator().isValid("8273 1232 7352 0569"));
36
+    }
37
+
38
+    @Ignore
39
+    @Test
40
+    public void testThatAddingANonDigitCharacterToAValidStringInvalidatesTheString() {
41
+        assertFalse(new LuhnValidator().isValid("046a 454 286"));
42
+    }
43
+
44
+}