diff --git a/src/main/java/org/apache/commons/validator/routines/checkdigit/ABANumberCheckDigit.java b/src/main/java/org/apache/commons/validator/routines/checkdigit/ABANumberCheckDigit.java index 9b4eb33e6..e5d87beaf 100644 --- a/src/main/java/org/apache/commons/validator/routines/checkdigit/ABANumberCheckDigit.java +++ b/src/main/java/org/apache/commons/validator/routines/checkdigit/ABANumberCheckDigit.java @@ -55,12 +55,32 @@ public final class ABANumberCheckDigit extends ModulusCheckDigit { /** Weighting given to digits depending on their right position */ private static final int[] POSITION_WEIGHT = {3, 1, 7}; + /** An ABA number is exactly nine digits, the last being the check digit. */ + private static final int ABAN_LEN = 9; + /** * Constructs a modulus 10 Check Digit routine for ABA Numbers. */ public ABANumberCheckDigit() { } + /** + * {@inheritDoc} + * + *
+ * The weight is taken from {@code rightPos}, which does not change when a character is prepended, so + * {@code ModulusCheckDigit} would accept an over-length code whose leading digit lands on a no-op weight (for + * example {@code 0123456780}). The nine-character length is checked here before the check digit test. + *
+ */ + @Override + public boolean isValid(final String code) { + if (code != null && code.length() != ABAN_LEN) { + return false; + } + return super.isValid(code); + } + /** * Calculates the weighted value of a character in the * code at a specified position. diff --git a/src/main/java/org/apache/commons/validator/routines/checkdigit/CUSIPCheckDigit.java b/src/main/java/org/apache/commons/validator/routines/checkdigit/CUSIPCheckDigit.java index 3b56c6339..a02c08302 100644 --- a/src/main/java/org/apache/commons/validator/routines/checkdigit/CUSIPCheckDigit.java +++ b/src/main/java/org/apache/commons/validator/routines/checkdigit/CUSIPCheckDigit.java @@ -47,12 +47,32 @@ public final class CUSIPCheckDigit extends ModulusCheckDigit { /** Weighting given to digits depending on their right position */ private static final int[] POSITION_WEIGHT = { 2, 1 }; + /** A CUSIP is exactly nine characters, the last being the check digit. */ + private static final int CUSIP_LEN = 9; + /** * Constructs a CUSIP Identifier Check Digit routine. */ public CUSIPCheckDigit() { } + /** + * {@inheritDoc} + * + *+ * The weight is taken from {@code rightPos}, which does not change when a character is prepended, so + * {@code ModulusCheckDigit} would accept an over-length code whose leading character lands on a no-op weight (for + * example {@code 0037833100}). The nine-character length is checked here before the check digit test. + *
+ */ + @Override + public boolean isValid(final String code) { + if (code != null && code.length() != CUSIP_LEN) { + return false; + } + return super.isValid(code); + } + /** * Convert a character at a specified position to an integer value. * diff --git a/src/main/java/org/apache/commons/validator/routines/checkdigit/EAN13CheckDigit.java b/src/main/java/org/apache/commons/validator/routines/checkdigit/EAN13CheckDigit.java index cb814c884..5f0725999 100644 --- a/src/main/java/org/apache/commons/validator/routines/checkdigit/EAN13CheckDigit.java +++ b/src/main/java/org/apache/commons/validator/routines/checkdigit/EAN13CheckDigit.java @@ -53,12 +53,33 @@ public final class EAN13CheckDigit extends ModulusCheckDigit { /** Weighting given to digits depending on their right position */ private static final int[] POSITION_WEIGHT = {3, 1}; + /** An EAN-13 (and ISBN-13) code is exactly thirteen digits, the last being the check digit. */ + private static final int EAN13_LEN = 13; + /** * Constructs a modulus 10 Check Digit routine for EAN/UPC. */ public EAN13CheckDigit() { } + /** + * {@inheritDoc} + * + *+ * The weight is taken from {@code rightPos}, which does not change when a character is prepended, so + * {@code ModulusCheckDigit} would accept an over-length code whose leading digit lands on a no-op weight (for + * example a valid code with a {@code 0} prepended). The thirteen-character length is checked here before the check + * digit test. + *
+ */ + @Override + public boolean isValid(final String code) { + if (code != null && code.length() != EAN13_LEN) { + return false; + } + return super.isValid(code); + } + /** * Calculates the weighted value of a character in the code at a specified position. *diff --git a/src/main/java/org/apache/commons/validator/routines/checkdigit/ISBN10CheckDigit.java b/src/main/java/org/apache/commons/validator/routines/checkdigit/ISBN10CheckDigit.java index 70477065d..ab82c6290 100644 --- a/src/main/java/org/apache/commons/validator/routines/checkdigit/ISBN10CheckDigit.java +++ b/src/main/java/org/apache/commons/validator/routines/checkdigit/ISBN10CheckDigit.java @@ -49,6 +49,9 @@ public final class ISBN10CheckDigit extends ModulusCheckDigit { */ public static final CheckDigit ISBN10_CHECK_DIGIT = new ISBN10CheckDigit(); + /** An ISBN-10 is exactly ten characters, the last being the check digit. */ + private static final int ISBN10_LEN = 10; + /** * Constructs a modulus 11 Check Digit routine for ISBN-10. */ @@ -56,6 +59,24 @@ public ISBN10CheckDigit() { super(MODULUS_11); } + /** + * {@inheritDoc} + * + *
+ * The weight is {@code rightPos}, which does not change when a character is prepended, and modulus 11 makes the + * leading position weight a multiple of the modulus, so {@code ModulusCheckDigit} would accept an over-length code + * with any prepended digit (for example {@code 51930110995}). The ten-character length is checked here before the + * check digit test. + *
+ */ + @Override + public boolean isValid(final String code) { + if (code != null && code.length() != ISBN10_LEN) { + return false; + } + return super.isValid(code); + } + /** * Convert an integer value to a character at a specified position. *diff --git a/src/test/java/org/apache/commons/validator/routines/checkdigit/ABANumberCheckDigitTest.java b/src/test/java/org/apache/commons/validator/routines/checkdigit/ABANumberCheckDigitTest.java index a2a43f4e3..b92787089 100644 --- a/src/test/java/org/apache/commons/validator/routines/checkdigit/ABANumberCheckDigitTest.java +++ b/src/test/java/org/apache/commons/validator/routines/checkdigit/ABANumberCheckDigitTest.java @@ -16,7 +16,11 @@ */ package org.apache.commons.validator.routines.checkdigit; +import static org.junit.jupiter.api.Assertions.assertFalse; + import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; /** * ABA Number Check Digit Test. @@ -32,4 +36,14 @@ protected void setUp() { valid = new String[] { "123456780", "123123123", "011000015", "111000038", "231381116", "121181976" }; } + /** + * An ABA number is exactly nine digits. Prepending a zero to a valid code lands on a position weighted zero, so the + * modulus was unaffected and the over-length code validated. + */ + @ParameterizedTest + @ValueSource(strings = { "0123456780", "00123456780", "0011000015" }) + void testOverLengthRejected(final String code) { + assertFalse(routine.isValid(code), "Should fail (not nine digits): " + code); + } + } diff --git a/src/test/java/org/apache/commons/validator/routines/checkdigit/CUSIPCheckDigitTest.java b/src/test/java/org/apache/commons/validator/routines/checkdigit/CUSIPCheckDigitTest.java index 54b4b3f35..5b456124b 100644 --- a/src/test/java/org/apache/commons/validator/routines/checkdigit/CUSIPCheckDigitTest.java +++ b/src/test/java/org/apache/commons/validator/routines/checkdigit/CUSIPCheckDigitTest.java @@ -23,6 +23,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; /** * CUSIP Check Digit Test. @@ -63,4 +64,14 @@ void testValidator336InvalidCheckDigits(final String invalidCheckDigit) { void testValidator336ValidCheckDigits(final String validCheckDigit) { assertTrue(routine.isValid(validCheckDigit), "Should fail: " + validCheckDigit); } + + /** + * A CUSIP is exactly nine characters. Prepending a zero to a valid code lands on a position weighted zero, so the + * modulus was unaffected and the over-length code validated. + */ + @ParameterizedTest + @ValueSource(strings = { "0037833100", "0931142103" }) + void testOverLengthRejected(final String code) { + assertFalse(routine.isValid(code), "Should fail (not nine characters): " + code); + } } diff --git a/src/test/java/org/apache/commons/validator/routines/checkdigit/EAN13CheckDigitTest.java b/src/test/java/org/apache/commons/validator/routines/checkdigit/EAN13CheckDigitTest.java index 209b281f1..a876e3760 100644 --- a/src/test/java/org/apache/commons/validator/routines/checkdigit/EAN13CheckDigitTest.java +++ b/src/test/java/org/apache/commons/validator/routines/checkdigit/EAN13CheckDigitTest.java @@ -16,7 +16,11 @@ */ package org.apache.commons.validator.routines.checkdigit; +import static org.junit.jupiter.api.Assertions.assertFalse; + import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; /** * EAN-13 Check Digit Test. @@ -32,4 +36,14 @@ protected void setUp() { valid = new String[] { "9780072129519", "9780764558313", "4025515373438", "0095673400332" }; } + /** + * An EAN-13 code is exactly thirteen digits. Prepending a zero to a valid code lands on a position weighted by the + * routine so the leading digit contributes nothing, leaving the modulus unchanged and the over-length code valid. + */ + @ParameterizedTest + @ValueSource(strings = { "09780072129519", "00095673400332" }) + void testOverLengthRejected(final String code) { + assertFalse(routine.isValid(code), "Should fail (not thirteen digits): " + code); + } + } diff --git a/src/test/java/org/apache/commons/validator/routines/checkdigit/ISBN10CheckDigitTest.java b/src/test/java/org/apache/commons/validator/routines/checkdigit/ISBN10CheckDigitTest.java index 8752d47b7..0fe69e21c 100644 --- a/src/test/java/org/apache/commons/validator/routines/checkdigit/ISBN10CheckDigitTest.java +++ b/src/test/java/org/apache/commons/validator/routines/checkdigit/ISBN10CheckDigitTest.java @@ -16,7 +16,11 @@ */ package org.apache.commons.validator.routines.checkdigit; +import static org.junit.jupiter.api.Assertions.assertFalse; + import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; /** * ISBN-10 Check Digit Test. @@ -32,4 +36,15 @@ protected void setUp() { valid = new String[] { "1930110995", "020163385X", "1932394354", "1590596277" }; } + /** + * An ISBN-10 is exactly ten characters. Because the routine is modulus 11 and weights by position from the right, + * the prepended digit lands on a weight that is a multiple of the modulus, so any over-length code with a leading + * digit validated. + */ + @ParameterizedTest + @ValueSource(strings = { "01930110995", "51930110995", "91930110995", "0020163385X" }) + void testOverLengthRejected(final String code) { + assertFalse(routine.isValid(code), "Should fail (not ten characters): " + code); + } + }