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