1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.validator.routines.checkdigit;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertFalse;
21 import static org.junit.jupiter.api.Assertions.assertNotNull;
22 import static org.junit.jupiter.api.Assertions.assertTrue;
23 import static org.junit.jupiter.api.Assertions.fail;
24
25 import java.io.ByteArrayInputStream;
26 import java.io.ByteArrayOutputStream;
27 import java.io.ObjectInputStream;
28 import java.io.ObjectOutputStream;
29 import java.util.ArrayList;
30 import java.util.List;
31
32 import org.apache.commons.logging.Log;
33 import org.apache.commons.logging.LogFactory;
34 import org.junit.jupiter.api.AfterEach;
35 import org.junit.jupiter.api.Test;
36
37
38
39
40 public abstract class AbstractCheckDigitTest {
41
42 private static final String POSSIBLE_CHECK_DIGITS = "0123456789 ABCDEFHIJKLMNOPQRSTUVWXYZ\tabcdefghijklmnopqrstuvwxyz!@£$%^&*()_+";
43
44
45 protected Log log = LogFactory.getLog(getClass());
46
47
48 protected int checkDigitLth = 1;
49
50
51 protected CheckDigit routine;
52
53
54
55
56
57
58
59
60 protected String[] valid;
61
62
63
64
65
66
67
68
69
70 protected String[] invalid = { "12345678A" };
71
72
73 protected String zeroSum = "0000000000";
74
75
76 protected String missingMessage = "Code is missing";
77
78
79
80
81
82
83
84 protected String checkDigit(final String code) {
85 if (code == null || code.length() <= checkDigitLth) {
86 return "";
87 }
88 final int start = code.length() - checkDigitLth;
89 return code.substring(start);
90 }
91
92
93
94
95
96
97
98
99 protected String[] createInvalidCodes(final String[] codes) {
100 final List<String> list = new ArrayList<>();
101
102
103 for (final String fullCode : codes) {
104 final String code = removeCheckDigit(fullCode);
105 final String check = checkDigit(fullCode);
106 for (int j = 0; j < POSSIBLE_CHECK_DIGITS.length(); j++) {
107 final String curr = POSSIBLE_CHECK_DIGITS.substring(j, j + 1);
108 if (!curr.equals(check)) {
109 list.add(code + curr);
110 }
111 }
112 }
113
114 return list.toArray(new String[0]);
115 }
116
117
118
119
120
121
122
123 protected String removeCheckDigit(final String code) {
124 if (code == null || code.length() <= checkDigitLth) {
125 return null;
126 }
127 return code.substring(0, code.length() - checkDigitLth);
128 }
129
130
131
132
133 @AfterEach
134 protected void tearDown() {
135 valid = null;
136 routine = null;
137 }
138
139
140
141
142 @Test
143 public void testCalculateInvalid() {
144
145 if (log.isDebugEnabled()) {
146 log.debug("testCalculateInvalid() for " + routine.getClass().getName());
147 }
148
149
150 for (int i = 0; i < invalid.length; i++) {
151 try {
152 final String code = invalid[i];
153 if (log.isDebugEnabled()) {
154 log.debug(" " + i + " Testing Invalid Check Digit, Code=[" + code + "]");
155 }
156 final String expected = checkDigit(code);
157 final String codeWithNoCheckDigit = removeCheckDigit(code);
158 if (codeWithNoCheckDigit == null) {
159 throw new CheckDigitException("Invalid Code=[" + code + "]");
160 }
161 final String actual = routine.calculate(codeWithNoCheckDigit);
162
163 if (expected.equals(actual)) {
164 fail("Expected mismatch for " + code + " expected " + expected + " actual " + actual);
165 }
166 } catch (final CheckDigitException e) {
167
168
169
170
171 assertTrue(e.getMessage().startsWith("Invalid "), "Invalid Character[" + i + "]=" + e.getMessage());
172
173 }
174 }
175 }
176
177
178
179
180 @Test
181 public void testCalculateValid() {
182 if (log.isDebugEnabled()) {
183 log.debug("testCalculateValid() for " + routine.getClass().getName());
184 }
185
186
187 for (int i = 0; i < valid.length; i++) {
188 final String code = removeCheckDigit(valid[i]);
189 final String expected = checkDigit(valid[i]);
190 try {
191 if (log.isDebugEnabled()) {
192 log.debug(" " + i + " Testing Valid Check Digit, Code=[" + code + "] expected=[" + expected + "]");
193 }
194 assertEquals(expected, routine.calculate(code), "valid[" + i + "]: " + valid[i]);
195 } catch (final Exception e) {
196 fail("valid[" + i + "]=" + valid[i] + " threw " + e);
197 }
198 }
199
200 }
201
202
203
204
205 @Test
206 public void testIsValidFalse() {
207 if (log.isDebugEnabled()) {
208 log.debug("testIsValidFalse() for " + routine.getClass().getName());
209 }
210
211
212 for (int i = 0; i < invalid.length; i++) {
213 if (log.isDebugEnabled()) {
214 log.debug(" " + i + " Testing Invalid Code=[" + invalid[i] + "]");
215 }
216 assertFalse(routine.isValid(invalid[i]), "invalid[" + i + "]: " + invalid[i]);
217 }
218
219
220 final String[] invalidCheckDigits = createInvalidCodes(valid);
221 for (int i = 0; i < invalidCheckDigits.length; i++) {
222 if (log.isDebugEnabled()) {
223 log.debug(" " + i + " Testing Invalid Check Digit, Code=[" + invalidCheckDigits[i] + "]");
224 }
225 assertFalse(routine.isValid(invalidCheckDigits[i]), "invalid check digit[" + i + "]: " + invalidCheckDigits[i]);
226 }
227 }
228
229
230
231
232 @Test
233 public void testIsValidTrue() {
234 if (log.isDebugEnabled()) {
235 log.debug("testIsValidTrue() for " + routine.getClass().getName());
236 }
237
238
239 for (int i = 0; i < valid.length; i++) {
240 if (log.isDebugEnabled()) {
241 log.debug(" " + i + " Testing Valid Code=[" + valid[i] + "]");
242 }
243 assertTrue(routine.isValid(valid[i]), "valid[" + i + "]: " + valid[i]);
244 }
245 }
246
247
248
249
250 @Test
251 public void testMissingCode() {
252
253
254 assertFalse(routine.isValid(null), "isValid() Null");
255
256
257 assertFalse(routine.isValid(""), "isValid() Zero Length");
258
259
260
261 assertFalse(routine.isValid("9"), "isValid() Length 1");
262
263
264 try {
265 routine.calculate(null);
266 fail("calculate() Null - expected exception");
267 } catch (final Exception e) {
268 assertEquals(missingMessage, e.getMessage(), "calculate() Null");
269 }
270
271
272 try {
273 routine.calculate("");
274 fail("calculate() Zero Length - expected exception");
275 } catch (final Exception e) {
276 assertEquals(missingMessage, e.getMessage(), "calculate() Zero Length");
277 }
278 }
279
280
281
282
283 @Test
284 public void testSerialization() {
285
286 final ByteArrayOutputStream baos = new ByteArrayOutputStream();
287 try (ObjectOutputStream oos = new ObjectOutputStream(baos)) {
288 oos.writeObject(routine);
289 oos.flush();
290 } catch (final Exception e) {
291 fail(routine.getClass().getName() + " error during serialization: " + e);
292 }
293
294
295 Object result = null;
296 try (ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray())) {
297 final ObjectInputStream ois = new ObjectInputStream(bais);
298 result = ois.readObject();
299 } catch (final Exception e) {
300 fail(routine.getClass().getName() + " error during deserialization: " + e);
301 }
302 assertNotNull(result);
303 }
304
305
306
307
308 @Test
309 public void testZeroSum() {
310 assertFalse(routine.isValid(zeroSum), "isValid() Zero Sum");
311 try {
312 routine.calculate(zeroSum);
313 fail("Zero Sum - expected exception");
314 } catch (final Exception e) {
315 assertEquals("Invalid code, sum is zero", e.getMessage(), "isValid() Zero Sum");
316 }
317 }
318
319 }