-
Notifications
You must be signed in to change notification settings - Fork 152
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Method AbstractCheckDigitTest.createInvalidCodes should return empty
array if checkDigitLth is 0. This applays to VATIN in DK and SK.
- Loading branch information
1 parent
e60169e
commit 18741c6
Showing
1 changed file
with
345 additions
and
0 deletions.
There are no files selected for viewing
345 changes: 345 additions & 0 deletions
345
src/test/java/org/apache/commons/validator/routines/checkdigit/AbstractCheckDigitTest2.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,345 @@ | ||
/* | ||
* Licensed to the Apache Software Foundation (ASF) under one or more | ||
* contributor license agreements. See the NOTICE file distributed with | ||
* this work for additional information regarding copyright ownership. | ||
* The ASF licenses this file to You under the Apache License, Version 2.0 | ||
* (the "License"); you may not use this file except in compliance with | ||
* the License. You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package org.apache.commons.validator.routines.checkdigit; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertFalse; | ||
import static org.junit.jupiter.api.Assertions.assertNotNull; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
import static org.junit.jupiter.api.Assertions.fail; | ||
import static org.junit.jupiter.api.Assumptions.assumeTrue; | ||
|
||
import java.io.ByteArrayInputStream; | ||
import java.io.ByteArrayOutputStream; | ||
import java.io.ObjectInputStream; | ||
import java.io.ObjectOutputStream; | ||
import java.io.Serializable; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
|
||
import org.apache.commons.logging.Log; | ||
import org.apache.commons.logging.LogFactory; | ||
import org.junit.jupiter.api.AfterEach; | ||
import org.junit.jupiter.api.Test; | ||
|
||
/** | ||
* Check Digit Test. | ||
*/ | ||
public abstract class AbstractCheckDigitTest2 { | ||
|
||
private static final String POSSIBLE_CHECK_DIGITS = "0123456789 ABCDEFHIJKLMNOPQRSTUVWXYZ\tabcdefghijklmnopqrstuvwxyz!@£$%^&*()_+"; | ||
|
||
/** Logging instance */ | ||
protected Log log = LogFactory.getLog(getClass()); | ||
|
||
/** Check digit routine being tested */ | ||
protected int checkDigitLth = 1; | ||
|
||
/** Check digit routine being tested */ | ||
protected CheckDigit routine; | ||
|
||
/** | ||
* Array of valid code values These must contain valid strings *including* the check digit. | ||
* | ||
* They are passed to: CheckDigit.isValid(expects string including checkdigit) which is expected to return true and | ||
* AbstractCheckDigitTest.createInvalidCodes() which mangles the last character to check that the result is now invalid. and the truncated string is passed | ||
* to CheckDigit.calculate(expects string without checkdigit) the result is compared with the last character | ||
*/ | ||
protected String[] valid; | ||
|
||
/** | ||
* Array of invalid code values | ||
* | ||
* These are currently passed to both CheckDigit.calculate(expects a string without checkdigit) which is expected to throw an exception However that only | ||
* applies if the string is syntactically incorrect; and CheckDigit.isValid(expects a string including checkdigit) which is expected to return false | ||
* | ||
* See https://issues.apache.org/jira/browse/VALIDATOR-344 for some dicussion on this | ||
*/ | ||
protected String[] invalid = { "12345678A" }; | ||
|
||
/** Code value which sums to zero */ | ||
protected String zeroSum = "0000000000"; | ||
|
||
/** Prefix for error messages */ | ||
protected String missingMessage = "Code is missing"; | ||
|
||
/** | ||
* Returns the check digit (i.e. last character) for a code. | ||
* | ||
* @param code The code | ||
* @return The check digit | ||
*/ | ||
protected String checkDigit(final String code) { | ||
if (code == null || code.length() <= checkDigitLth) { | ||
return ""; | ||
} | ||
final int start = code.length() - checkDigitLth; | ||
return code.substring(start); | ||
} | ||
|
||
// private static final String POSSIBLE_CHECK_DIGITS = "0123456789"; | ||
/** | ||
* Returns an array of codes with invalid check digits. | ||
* | ||
* @param codes Codes with valid check digits | ||
* @return Codes with invalid check digits | ||
*/ | ||
protected String[] createInvalidCodes(final String[] codes) { | ||
final List<String> list = new ArrayList<>(); | ||
if (checkDigitLth == 0) { | ||
return list.toArray(new String[0]); | ||
} | ||
|
||
// create invalid check digit values | ||
for (final String fullCode : codes) { | ||
final String code = removeCheckDigit(fullCode); | ||
final String check = checkDigit(fullCode); | ||
for (int i = 0; i < POSSIBLE_CHECK_DIGITS.length(); i++) { | ||
String c = checkDigitLth == 1 ? "" : POSSIBLE_CHECK_DIGITS.substring(i, i + 1); | ||
for (int j = 0; j < POSSIBLE_CHECK_DIGITS.length(); j++) { | ||
final String curr = POSSIBLE_CHECK_DIGITS.substring(j, j + 1) + c; | ||
if (!curr.equals(check)) { | ||
list.add(createCode(code, curr)); | ||
} | ||
} | ||
} | ||
} | ||
|
||
System.out.println("EUG " + list.size() + " createInvalidCodes created."); | ||
return list.toArray(new String[0]); | ||
} | ||
|
||
protected String createCode(final String code, final String cd) { | ||
return code + cd; | ||
} | ||
|
||
/** | ||
* Returns a code with the Check Digit (i.e. last character) removed. | ||
* | ||
* @param code The code | ||
* @return The code without the check digit | ||
*/ | ||
protected String removeCheckDigit(final String code) { | ||
if (code == null || code.length() <= checkDigitLth) { | ||
return null; | ||
} | ||
return code.substring(0, code.length() - checkDigitLth); | ||
} | ||
|
||
/** | ||
* Tear Down - clears routine and valid codes. | ||
*/ | ||
@AfterEach | ||
protected void tearDown() { | ||
valid = null; | ||
routine = null; | ||
} | ||
|
||
/** | ||
* Test calculate() for invalid values. | ||
*/ | ||
@Test | ||
public void testCalculateInvalid() { | ||
|
||
if (log.isDebugEnabled()) { | ||
log.debug("testCalculateInvalid() for " + routine.getClass().getName()); | ||
} | ||
|
||
// test invalid code values | ||
for (int i = 0; i < invalid.length; i++) { | ||
try { | ||
final String code = invalid[i]; | ||
if (log.isDebugEnabled()) { | ||
log.debug(" " + i + " Testing Invalid Check Digit, Code=[" + code + "]"); | ||
} | ||
System.out.println("EUG" + i + " Testing Invalid Check Digit, Code=[" + code + "]"); | ||
final String expected = checkDigit(code); | ||
final String codeWithNoCheckDigit = removeCheckDigit(code); | ||
if (codeWithNoCheckDigit == null) { | ||
throw new CheckDigitException("Invalid Code=[" + code + "]"); | ||
} | ||
final String actual = routine.calculate(codeWithNoCheckDigit); | ||
// If exception not thrown, check that the digit is incorrect instead | ||
if (expected.equals(actual)) { | ||
fail("Expected mismatch for " + code + " expected " + expected + " actual " + actual); | ||
} | ||
} catch (final CheckDigitException e) { | ||
System.out.println("EUG" + e.getMessage() ); | ||
// possible failure messages: | ||
// Invalid ISBN Length ... | ||
// Invalid Character[ ... | ||
// Are there any others? | ||
assertTrue(e.getMessage().startsWith("Invalid "), "Invalid Character[" + i + "]=" + e.getMessage()); | ||
// WAS assertTrue("Invalid Character[" +i +"]=" + e.getMessage(), e.getMessage().startsWith("Invalid Character[")); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Test calculate() for valid values. | ||
*/ | ||
@Test | ||
public void testCalculateValid() { | ||
if (log.isDebugEnabled()) { | ||
log.debug("testCalculateValid() for " + routine.getClass().getName()); | ||
} | ||
|
||
// test valid values | ||
for (int i = 0; i < valid.length; i++) { | ||
final String code = removeCheckDigit(valid[i]); | ||
final String expected = checkDigit(valid[i]); | ||
try { | ||
if (log.isDebugEnabled()) { | ||
log.debug(" " + i + " Testing Valid Check Digit, Code=[" + code + "] expected=[" + expected + "]"); | ||
} | ||
System.out.println(" " + i + " Testing calculate Valid Check Digit, Code=[" + code + "] expected=[" + expected + "]"); | ||
assertEquals(expected, routine.calculate(code), "valid[" + i + "]: " + valid[i]); | ||
} catch (final Exception e) { | ||
fail("valid[" + i + "]=" + valid[i] + " threw " + e); | ||
} | ||
} | ||
|
||
} | ||
|
||
/** | ||
* Test isValid() for invalid values. | ||
*/ | ||
@Test | ||
public void testIsValidFalse() { | ||
if (log.isDebugEnabled()) { | ||
log.debug("testIsValidFalse() for " + routine.getClass().getName()); | ||
} | ||
|
||
// test invalid code values | ||
for (int i = 0; i < invalid.length; i++) { | ||
if (log.isDebugEnabled()) { | ||
log.debug(" " + i + " Testing Invalid Code=[" + invalid[i] + "]"); | ||
} | ||
String invalidCode = invalid[i]; | ||
System.out.println(" " + i + " Testing Invalid Code=[" + invalidCode + "]"); | ||
assertFalse(routine.isValid(invalidCode), "invalid[" + i + "]: " + invalidCode); | ||
} | ||
|
||
// test invalid check digit values | ||
final String[] invalidCheckDigits = createInvalidCodes(valid); | ||
for (int i = 0; i < invalidCheckDigits.length; i++) { | ||
if (log.isDebugEnabled()) { | ||
log.debug(" " + i + " Testing Invalid Check Digit, Code=[" + invalidCheckDigits[i] + "]"); | ||
} | ||
boolean res = routine.isValid(invalidCheckDigits[i]); | ||
if (res) { | ||
log.warn(" " + i + " Testing Invalid Check Digit, Code=[" + invalidCheckDigits[i] + "]"); | ||
} else { | ||
//System.out.println(" " + i + " Testing Invalid Check Digit, Code=[" + invalidCheckDigits[i] + "]"); | ||
} | ||
assertFalse(res, "invalid check digit[" + i + "]: " + invalidCheckDigits[i]); | ||
} | ||
} | ||
|
||
/** | ||
* Test isValid() for valid values. | ||
*/ | ||
@Test | ||
public void testIsValidTrue() { | ||
if (log.isDebugEnabled()) { | ||
log.debug("testIsValidTrue() for " + routine.getClass().getName()); | ||
} | ||
|
||
// test valid values | ||
for (int i = 0; i < valid.length; i++) { | ||
if (log.isDebugEnabled()) { | ||
log.debug(" " + i + " Testing Valid Code=[" + valid[i] + "]"); | ||
} | ||
System.out.println(" " + i + " Testing Valid Code=[" + valid[i] + "]"); | ||
assertTrue(routine.isValid(valid[i]), "valid[" + i + "]: " + valid[i]); | ||
} | ||
} | ||
|
||
/** | ||
* Test missing code | ||
*/ | ||
@Test | ||
public void testMissingCode() { | ||
|
||
// isValid() null | ||
assertFalse(routine.isValid(null), "isValid() Null"); | ||
|
||
// isValid() zero length | ||
assertFalse(routine.isValid(""), "isValid() Zero Length"); | ||
|
||
// isValid() length 1 | ||
// Don't use 0, because that passes for Verhoef (not sure why yet) | ||
assertFalse(routine.isValid("9"), "isValid() Length 1"); | ||
|
||
// calculate() null | ||
try { | ||
routine.calculate(null); | ||
fail("calculate() Null - expected exception"); | ||
} catch (final Exception e) { | ||
assertEquals(missingMessage, e.getMessage(), "calculate() Null"); | ||
} | ||
|
||
// calculate() zero length | ||
try { | ||
routine.calculate(""); | ||
fail("calculate() Zero Length - expected exception"); | ||
} catch (final Exception e) { | ||
assertEquals(missingMessage, e.getMessage(), "calculate() Zero Length"); | ||
} | ||
} | ||
|
||
/** | ||
* Test check digit serialization. | ||
*/ | ||
@Test | ||
public void testSerialization() { | ||
assumeTrue(routine instanceof Serializable); | ||
// Serialize the check digit routine | ||
final ByteArrayOutputStream baos = new ByteArrayOutputStream(); | ||
try (ObjectOutputStream oos = new ObjectOutputStream(baos)) { | ||
oos.writeObject(routine); | ||
oos.flush(); | ||
} catch (final Exception e) { | ||
fail(routine.getClass().getName() + " error during serialization: " + e); | ||
} | ||
|
||
// Deserialize the test object | ||
Object result = null; | ||
try (ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray())) { | ||
final ObjectInputStream ois = new ObjectInputStream(bais); | ||
result = ois.readObject(); | ||
} catch (final Exception e) { | ||
fail(routine.getClass().getName() + " error during deserialization: " + e); | ||
} | ||
assertNotNull(result); | ||
} | ||
|
||
/** | ||
* Test zero sum | ||
*/ | ||
@Test | ||
public void testZeroSum() { | ||
assertFalse(routine.isValid(zeroSum), "isValid() Zero Sum"); | ||
try { | ||
routine.calculate(zeroSum); | ||
fail("Zero Sum - expected exception"); | ||
} catch (final Exception e) { | ||
assertEquals("Invalid code, sum is zero", e.getMessage(), "isValid() Zero Sum"); | ||
} | ||
} | ||
|
||
} |