1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.text;
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.assertNotEquals;
22 import static org.junit.jupiter.api.Assertions.assertNull;
23 import static org.junit.jupiter.api.Assertions.assertThrows;
24 import static org.junit.jupiter.api.Assertions.assertTrue;
25
26 import java.io.UnsupportedEncodingException;
27 import java.util.Arrays;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31
32 import org.apache.commons.lang3.ArrayUtils;
33 import org.junit.jupiter.api.Test;
34
35
36
37
38 class AlphabetConverterTest {
39
40 private static final Character[] LOWER_CASE_ENGLISH = { ' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
41 't', 'u', 'v', 'w', 'x', 'y', 'z' };
42
43 private static final Character[] ENGLISH_AND_NUMBERS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
44 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
45 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ' ' };
46
47 private static final Character[] LOWER_CASE_ENGLISH_AND_NUMBERS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
48 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ' ' };
49
50 private static final Character[] NUMBERS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
51
52 private static final Character[] BINARY = { '0', '1' };
53
54 private static final Character[] HEBREW = { '_', ' ', '\u05e7', '\u05e8', '\u05d0', '\u05d8', '\u05d5', '\u05df', '\u05dd', '\u05e4', '\u05e9', '\u05d3',
55 '\u05d2', '\u05db', '\u05e2', '\u05d9', '\u05d7', '\u05dc', '\u05da', '\u05e3', '\u05d6', '\u05e1', '\u05d1', '\u05d4', '\u05e0', '\u05de',
56 '\u05e6', '\u05ea', '\u05e5' };
57
58 private static final Integer[] UNICODE = { 32, 35395, 35397, 36302, 36291, 35203, 35201, 35215, 35219, 35268, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106,
59 107, 108, 109, 110, 1001, 1002, 1003, 1004, 1005 };
60
61 private static final Integer[] LOWER_CASE_ENGLISH_CODEPOINTS = { 32, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114,
62 115, 116, 117, 118, 119, 120, 121, 122 };
63
64 private static final Integer[] DO_NOT_ENCODE_CODEPOINTS = { 32, 97, 98, 99 };
65
66 private AlphabetConverter createJavadocExample() {
67 final Character[] original = { 'a', 'b', 'c', 'd' };
68 final Character[] encoding = { '0', '1', 'd' };
69 final Character[] doNotEncode = { 'd' };
70
71 return AlphabetConverter.createConverterFromChars(original, encoding, doNotEncode);
72 }
73
74 private void test(final Character[] originalChars, final Character[] encodingChars, final Character[] doNotEncodeChars, final String... strings)
75 throws UnsupportedEncodingException {
76
77 final AlphabetConverter ac = AlphabetConverter.createConverterFromChars(originalChars, encodingChars, doNotEncodeChars);
78
79 final AlphabetConverter reconstructedAlphabetConverter = AlphabetConverter.createConverterFromMap(ac.getOriginalToEncoded());
80
81 assertEquals(ac, reconstructedAlphabetConverter);
82 assertEquals(ac.hashCode(), reconstructedAlphabetConverter.hashCode());
83 assertEquals(ac.toString(), reconstructedAlphabetConverter.toString());
84 assertNull(ac.encode(null));
85 assertEquals("", ac.encode(""));
86
87
88 for (final String s : strings) {
89 final String encoded = ac.encode(s);
90
91
92 final List<Character> originalEncodingChars = Arrays.asList(encodingChars);
93 for (int i = 0; i < encoded.length(); i++) {
94 assertTrue(originalEncodingChars.contains(encoded.charAt(i)));
95 }
96
97 final String decoded = ac.decode(encoded);
98
99
100 final List<Character> originalCharsList = Arrays.asList(originalChars);
101 for (int i = 0; i < decoded.length(); i++) {
102 assertTrue(originalCharsList.contains(decoded.charAt(i)));
103 }
104
105 assertEquals(s, decoded, () -> "Encoded '" + s + "' into '" + encoded + "', but decoded into '" + decoded + "'");
106 }
107 }
108
109 @Test
110 void testBinaryTest() throws UnsupportedEncodingException {
111 test(BINARY, NUMBERS, ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY, "0", "1", "10", "11");
112 test(NUMBERS, BINARY, ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY, "12345", "0");
113 test(LOWER_CASE_ENGLISH, BINARY, ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY, "abc", "a");
114 }
115
116 @Test
117 void testCreateConverterFromCharsAndEquals() {
118 final Character[] characterArray = new Character[2];
119 final char charOne = '+';
120 final char character = '+';
121 characterArray[0] = character;
122 characterArray[1] = characterArray[0];
123 final AlphabetConverter alphabetConverter = AlphabetConverter.createConverterFromChars(characterArray, characterArray, characterArray);
124
125 assertNotEquals(alphabetConverter, charOne);
126 }
127
128 @Test
129 void testCreateConverterFromCharsOne() {
130 final Character[] characterArray = new Character[2];
131 characterArray[0] = '5';
132 characterArray[1] = characterArray[0];
133 final AlphabetConverter alphabetConverter = AlphabetConverter.createConverterFromChars(characterArray, characterArray, characterArray);
134
135 assertEquals(1, alphabetConverter.getEncodedCharLength());
136 }
137
138 @Test
139 void testCreateConverterFromCharsWithNullAndNull() {
140 assertThrows(IllegalArgumentException.class, () -> {
141 final Character[] characterArray = new Character[2];
142 characterArray[0] = '$';
143 characterArray[1] = characterArray[0];
144 AlphabetConverter.createConverterFromChars(characterArray, null, null);
145 });
146 }
147
148 @Test
149 void testCreateConverterFromMapAndEquals() {
150 final Map<Integer, String> hashMap = new HashMap<>();
151 final AlphabetConverter alphabetConverter = AlphabetConverter.createConverterFromMap(hashMap);
152 hashMap.put(0, "CtDs");
153 final AlphabetConverter alphabetConverterTwo = AlphabetConverter.createConverterFromMap(hashMap);
154 assertNotEquals(alphabetConverter, alphabetConverterTwo);
155 assertEquals(1, alphabetConverter.getEncodedCharLength());
156 }
157
158 @Test
159 void testDecodeReturningNull() throws UnsupportedEncodingException {
160 final Map<Integer, String> map = new HashMap<>();
161 final AlphabetConverter alphabetConverter = AlphabetConverter.createConverterFromMap(map);
162 alphabetConverter.decode(null);
163 assertEquals(1, alphabetConverter.getEncodedCharLength());
164 }
165
166 @Test
167 void testDoNotEncodeTest() throws UnsupportedEncodingException {
168 test(ENGLISH_AND_NUMBERS, LOWER_CASE_ENGLISH_AND_NUMBERS, LOWER_CASE_ENGLISH, "1", "456", "abc", "ABC", "this will not be converted but THIS WILL");
169 test(ENGLISH_AND_NUMBERS, LOWER_CASE_ENGLISH_AND_NUMBERS, NUMBERS, "1", "456", "abc", "ABC", "this will be converted but 12345 and this will be");
170 }
171
172 @Test
173 void testEncodeFailureTest() {
174 assertEquals("Couldn't find encoding for '3' in 3",
175 assertThrows(UnsupportedEncodingException.class, () -> test(BINARY, NUMBERS, ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY, "3")).getMessage());
176 }
177
178 @Test
179 void testEquals() {
180 final Character[] characterArray = new Character[2];
181 final char character = 'R';
182 characterArray[0] = character;
183 characterArray[1] = character;
184 final AlphabetConverter alphabetConverter = AlphabetConverter.createConverterFromChars(characterArray, characterArray, characterArray);
185 final Map<Integer, String> map = new HashMap<>();
186 final AlphabetConverter alphabetConverterTwo = AlphabetConverter.createConverterFromMap(map);
187
188 assertEquals(1, alphabetConverterTwo.getEncodedCharLength());
189 assertNotEquals(alphabetConverter, alphabetConverterTwo);
190 }
191
192 @Test
193 void testEqualsWithNull() {
194 final Character[] characterArray = ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY;
195 final AlphabetConverter alphabetConverter = AlphabetConverter.createConverterFromChars(characterArray, null, null);
196
197 assertFalse(alphabetConverter.equals(null));
198 }
199
200 @Test
201 void testEqualsWithSameObject() {
202 final Character[] characterArray = new Character[2];
203 final char character = 'R';
204 characterArray[0] = character;
205 characterArray[1] = character;
206 final AlphabetConverter alphabetConverter = AlphabetConverter.createConverterFromChars(characterArray, characterArray, characterArray);
207
208 assertEquals(alphabetConverter, alphabetConverter);
209 }
210
211 @Test
212 void testHebrewTest() throws UnsupportedEncodingException {
213 test(HEBREW, BINARY, ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY, "\u05d0", "\u05e2",
214 "\u05d0\u05dc\u05e3_\u05d0\u05d5\u05d4\u05d1\u05dc_\u05d1\u05d9\u05ea_\u05d6\u05d4_\u05d1\u05d9\u05ea_"
215 + "\u05d2\u05d9\u05de\u05dc_\u05d6\u05d4_\u05db\u05de\u05dc_\u05d2\u05d3\u05d5\u05dc");
216 test(HEBREW, NUMBERS, ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY, "\u05d0", "\u05e2",
217 "\u05d0\u05dc\u05e3_\u05d0\u05d5\u05d4\u05d1\u05dc_\u05d1\u05d9\u05ea_\u05d6\u05d4_\u05d1\u05d9\u05ea_"
218 + "\u05d2\u05d9\u05de\u05dc_\u05d6\u05d4_\u05db\u05de\u05dc_\u05d2\u05d3\u05d5\u05dc");
219 test(NUMBERS, HEBREW, ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY, "123456789", "1", "5");
220 test(LOWER_CASE_ENGLISH, HEBREW, ArrayUtils.EMPTY_CHARACTER_OBJECT_ARRAY, "this is a test");
221 }
222
223
224
225
226 @Test
227 void testJavadocExampleTest() throws UnsupportedEncodingException {
228 final AlphabetConverter ac = createJavadocExample();
229
230 assertEquals("00", ac.encode("a"));
231 assertEquals("01", ac.encode("b"));
232 assertEquals("0d", ac.encode("c"));
233 assertEquals("d", ac.encode("d"));
234 assertEquals("00010dd", ac.encode("abcd"));
235 }
236
237 @Test
238 void testMissingDoNotEncodeLettersFromEncodingTest() {
239 assertEquals("Can not use 'do not encode' list because encoding alphabet does not contain '0'",
240 assertThrows(IllegalArgumentException.class, () -> AlphabetConverter.createConverterFromChars(ENGLISH_AND_NUMBERS, LOWER_CASE_ENGLISH, NUMBERS))
241 .getMessage());
242 }
243
244 @Test
245 void testMissingDoNotEncodeLettersFromOriginalTest() {
246 assertEquals("Can not use 'do not encode' list because original alphabet does not contain '0'",
247 assertThrows(IllegalArgumentException.class, () -> AlphabetConverter.createConverterFromChars(LOWER_CASE_ENGLISH, ENGLISH_AND_NUMBERS, NUMBERS))
248 .getMessage());
249 }
250
251 @Test
252 void testNoEncodingLettersTest() {
253 assertEquals("Must have at least two encoding characters (excluding those in the 'do not encode' list), but has 0",
254 assertThrows(IllegalArgumentException.class, () -> AlphabetConverter.createConverterFromChars(ENGLISH_AND_NUMBERS, NUMBERS, NUMBERS))
255 .getMessage());
256 }
257
258 @Test
259 void testOnlyOneEncodingLettersTest() {
260 assertEquals("Must have at least two encoding characters (excluding those in the 'do not encode' list), but has 1",
261 assertThrows(IllegalArgumentException.class, () -> {
262 final Character[] numbersPlusUnderscore = Arrays.copyOf(NUMBERS, NUMBERS.length + 1);
263 numbersPlusUnderscore[numbersPlusUnderscore.length - 1] = '_';
264
265 AlphabetConverter.createConverterFromChars(ENGLISH_AND_NUMBERS, numbersPlusUnderscore, NUMBERS);
266 }).getMessage());
267 }
268
269 @Test
270 void testUnexpectedEndWhileDecodingTest() {
271 final String toDecode = "00d01d0";
272 assertEquals("Unexpected end of string while decoding " + toDecode,
273 assertThrows(UnsupportedEncodingException.class, () -> createJavadocExample().decode(toDecode)).getMessage());
274 }
275
276 @Test
277 void testUnexpectedStringWhileDecodingTest() {
278 final String toDecode = "00XX";
279 assertEquals("Unexpected string without decoding (XX) in " + toDecode,
280 assertThrows(UnsupportedEncodingException.class, () -> createJavadocExample().decode(toDecode)).getMessage());
281 }
282
283
284
285
286 @Test
287 void testUnicodeTest() throws UnsupportedEncodingException {
288 final AlphabetConverter ac = AlphabetConverter.createConverter(UNICODE, LOWER_CASE_ENGLISH_CODEPOINTS, DO_NOT_ENCODE_CODEPOINTS);
289 assertEquals(2, ac.getEncodedCharLength());
290 final String original = "\u8a43\u8a45 \u8dce ab \u8dc3 c \u8983";
291 final String encoded = ac.encode(original);
292 final String decoded = ac.decode(encoded);
293 assertEquals(original, decoded, () -> "Encoded '" + original + "' into '" + encoded + "', but decoded into '" + decoded + "'");
294 }
295
296 }