1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle.checks;
21
22 import static com.google.common.truth.Truth.assertWithMessage;
23 import static com.puppycrawl.tools.checkstyle.checks.AvoidEscapedUnicodeCharactersCheck.MSG_KEY;
24
25 import java.util.Arrays;
26 import java.util.List;
27 import java.util.regex.Matcher;
28 import java.util.regex.Pattern;
29 import java.util.stream.IntStream;
30
31 import org.junit.jupiter.api.Test;
32
33 import com.google.common.base.Splitter;
34 import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
35 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
36 import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
37 import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
38
39 public class AvoidEscapedUnicodeCharactersCheckTest extends AbstractModuleTestSupport {
40
41
42
43 private static final int[] C0_CONTROL_CHARACTER_INDICES = {
44 0x0000,
45 0x0001,
46 0x0002,
47 0x0003,
48 0x0004,
49 0x0005,
50 0x0006,
51 0x0007,
52 0x0008,
53 0x0009,
54 0x000A,
55 0x000B,
56 0x000C,
57 0x000D,
58 0x000E,
59 0x000F,
60 0x0010,
61 0x0011,
62 0x0012,
63 0x0013,
64 0x0014,
65 0x0015,
66 0x0016,
67 0x0017,
68 0x0018,
69 0x0019,
70 0x001A,
71 0x001B,
72 0x001C,
73 0x001D,
74 0x001E,
75 0x001F,
76 };
77
78
79
80 private static final int[] C1_CONTROL_CHARACTER_INDICES = {
81 0x0080,
82 0x0081,
83 0x0082,
84 0x0083,
85 0x0084,
86 0x0085,
87 0x0086,
88 0x0087,
89 0x0088,
90 0x0089,
91 0x008A,
92 0x008B,
93 0x008C,
94 0x008D,
95 0x008E,
96 0x008F,
97 0x0090,
98 0x0091,
99 0x0092,
100 0x0093,
101 0x0094,
102 0x0095,
103 0x0096,
104 0x0097,
105 0x0098,
106 0x0099,
107 0x009A,
108 0x009B,
109 0x009C,
110 0x009D,
111 0x009E,
112 0x009F,
113 };
114
115
116
117 private static final int[] OTHER_CONTROL_CHARACTER_INDICES = {
118 0x00AD,
119 0x034F,
120 0x070F,
121 0x180E,
122 0x200B,
123 0x200C,
124 0x200D,
125 0x200E,
126 0x200F,
127 0x202A,
128 0x202B,
129 0x202C,
130 0x202D,
131 0x202E,
132 0x2060,
133 0x2061,
134 0x2062,
135 0x2063,
136 0x2064,
137 0x206A,
138 0x206B,
139 0x206C,
140 0x206D,
141 0x206E,
142 0x206F,
143 0xFEFF,
144 0xFFF9,
145 0xFFFA,
146 0xFFFB,
147 };
148
149 @Override
150 public String getPackageLocation() {
151 return "com/puppycrawl/tools/checkstyle/checks/avoidescapedunicodecharacters";
152 }
153
154 @Test
155 public void testGetRequiredTokens() {
156 final AvoidEscapedUnicodeCharactersCheck checkObj =
157 new AvoidEscapedUnicodeCharactersCheck();
158 final int[] expected = {
159 TokenTypes.STRING_LITERAL,
160 TokenTypes.CHAR_LITERAL,
161 TokenTypes.TEXT_BLOCK_CONTENT,
162 TokenTypes.SINGLE_LINE_COMMENT,
163 TokenTypes.BLOCK_COMMENT_BEGIN,
164 };
165 assertWithMessage("Required tokens differ from expected")
166 .that(checkObj.getRequiredTokens())
167 .isEqualTo(expected);
168 }
169
170 @Test
171 public void testDefaultOne() throws Exception {
172 final String[] expected = {
173 "17:38: " + getCheckMessage(MSG_KEY),
174 "19:38: " + getCheckMessage(MSG_KEY),
175 "21:38: " + getCheckMessage(MSG_KEY),
176 "25:38: " + getCheckMessage(MSG_KEY),
177 "27:38: " + getCheckMessage(MSG_KEY),
178 "32:24: " + getCheckMessage(MSG_KEY),
179 "37:36: " + getCheckMessage(MSG_KEY),
180 "39:36: " + getCheckMessage(MSG_KEY),
181 "42:24: " + getCheckMessage(MSG_KEY),
182 "47:38: " + getCheckMessage(MSG_KEY),
183 "49:38: " + getCheckMessage(MSG_KEY),
184 "51:38: " + getCheckMessage(MSG_KEY),
185 "53:47: " + getCheckMessage(MSG_KEY),
186 "62:32: " + getCheckMessage(MSG_KEY),
187 "80:35: " + getCheckMessage(MSG_KEY),
188 "82:35: " + getCheckMessage(MSG_KEY),
189 "84:35: " + getCheckMessage(MSG_KEY),
190 "86:35: " + getCheckMessage(MSG_KEY),
191 "97:24: " + getCheckMessage(MSG_KEY),
192 "98:24: " + getCheckMessage(MSG_KEY),
193 "99:24: " + getCheckMessage(MSG_KEY),
194 "100:24: " + getCheckMessage(MSG_KEY),
195 "101:24: " + getCheckMessage(MSG_KEY),
196 "102:24: " + getCheckMessage(MSG_KEY),
197 "104:24: " + getCheckMessage(MSG_KEY),
198 "107:31: " + getCheckMessage(MSG_KEY),
199 "107:48: " + getCheckMessage(MSG_KEY),
200 };
201 verifyWithInlineConfigParser(
202 getPath("InputAvoidEscapedUnicodeCharactersOne.java"), expected);
203 }
204
205 @Test
206 public void testDefaultTwo() throws Exception {
207 final String[] expected = {
208 "15:38: " + getCheckMessage(MSG_KEY),
209 "17:38: " + getCheckMessage(MSG_KEY),
210 "19:38: " + getCheckMessage(MSG_KEY),
211 "21:38: " + getCheckMessage(MSG_KEY),
212 "25:31: " + getCheckMessage(MSG_KEY),
213 "25:45: " + getCheckMessage(MSG_KEY),
214 "29:34: " + getCheckMessage(MSG_KEY),
215 "31:46: " + getCheckMessage(MSG_KEY),
216 "36:38: " + getCheckMessage(MSG_KEY),
217 "43:38: " + getCheckMessage(MSG_KEY),
218 "46:46: " + getCheckMessage(MSG_KEY),
219 "48:55: " + getCheckMessage(MSG_KEY),
220 "50:46: " + getCheckMessage(MSG_KEY),
221 "52:55: " + getCheckMessage(MSG_KEY),
222 "54:46: " + getCheckMessage(MSG_KEY),
223 "56:55: " + getCheckMessage(MSG_KEY),
224 "58:46: " + getCheckMessage(MSG_KEY),
225 "60:55: " + getCheckMessage(MSG_KEY),
226 "62:46: " + getCheckMessage(MSG_KEY),
227 "64:55: " + getCheckMessage(MSG_KEY),
228 "66:48: " + getCheckMessage(MSG_KEY),
229 "68:57: " + getCheckMessage(MSG_KEY),
230 };
231 verifyWithInlineConfigParser(
232 getPath("InputAvoidEscapedUnicodeCharactersTwo.java"), expected);
233 }
234
235 @Test
236 public void testAllowEscapesForControlCharacterSetOne() throws Exception {
237 final String[] expected = {
238 "17:38: " + getCheckMessage(MSG_KEY),
239 "19:38: " + getCheckMessage(MSG_KEY),
240 "21:38: " + getCheckMessage(MSG_KEY),
241 "25:38: " + getCheckMessage(MSG_KEY),
242 "27:38: " + getCheckMessage(MSG_KEY),
243 "36:36: " + getCheckMessage(MSG_KEY),
244 "38:36: " + getCheckMessage(MSG_KEY),
245 "45:38: " + getCheckMessage(MSG_KEY),
246 "47:38: " + getCheckMessage(MSG_KEY),
247 "49:38: " + getCheckMessage(MSG_KEY),
248 "51:47: " + getCheckMessage(MSG_KEY),
249 "60:32: " + getCheckMessage(MSG_KEY),
250 "78:35: " + getCheckMessage(MSG_KEY),
251 "80:35: " + getCheckMessage(MSG_KEY),
252 "82:35: " + getCheckMessage(MSG_KEY),
253 "84:35: " + getCheckMessage(MSG_KEY),
254 "96:24: " + getCheckMessage(MSG_KEY),
255 "97:24: " + getCheckMessage(MSG_KEY),
256 "98:24: " + getCheckMessage(MSG_KEY),
257 "99:24: " + getCheckMessage(MSG_KEY),
258 "100:24: " + getCheckMessage(MSG_KEY),
259 "102:24: " + getCheckMessage(MSG_KEY),
260 "105:31: " + getCheckMessage(MSG_KEY),
261 "105:48: " + getCheckMessage(MSG_KEY),
262 };
263 verifyWithInlineConfigParser(
264 getPath("InputAvoidEscapedUnicodeCharacters1One.java"), expected);
265 }
266
267 @Test
268 public void testAllowEscapesForControlCharacterSetTwo() throws Exception {
269 final String[] expected = {
270 "16:38: " + getCheckMessage(MSG_KEY),
271 "17:38: " + getCheckMessage(MSG_KEY),
272 "19:38: " + getCheckMessage(MSG_KEY),
273 "21:38: " + getCheckMessage(MSG_KEY),
274 "25:45: " + getCheckMessage(MSG_KEY),
275 "28:46: " + getCheckMessage(MSG_KEY),
276 "33:38: " + getCheckMessage(MSG_KEY),
277 "40:38: " + getCheckMessage(MSG_KEY),
278 "42:46: " + getCheckMessage(MSG_KEY),
279 "44:55: " + getCheckMessage(MSG_KEY),
280 "46:46: " + getCheckMessage(MSG_KEY),
281 "48:55: " + getCheckMessage(MSG_KEY),
282 "50:46: " + getCheckMessage(MSG_KEY),
283 "52:55: " + getCheckMessage(MSG_KEY),
284 "54:46: " + getCheckMessage(MSG_KEY),
285 "56:55: " + getCheckMessage(MSG_KEY),
286 "58:46: " + getCheckMessage(MSG_KEY),
287 "60:55: " + getCheckMessage(MSG_KEY),
288 "62:48: " + getCheckMessage(MSG_KEY),
289 "64:57: " + getCheckMessage(MSG_KEY),
290 };
291 verifyWithInlineConfigParser(
292 getPath("InputAvoidEscapedUnicodeCharacters1Two.java"), expected);
293 }
294
295 @Test
296 public void testAllowByTailCommentOne() throws Exception {
297 final String[] expected = {
298 "17:38: " + getCheckMessage(MSG_KEY),
299 "26:38: " + getCheckMessage(MSG_KEY),
300 "36:36: " + getCheckMessage(MSG_KEY),
301 "44:38: " + getCheckMessage(MSG_KEY),
302 "47:38: " + getCheckMessage(MSG_KEY),
303 "49:47: " + getCheckMessage(MSG_KEY),
304 "75:35: " + getCheckMessage(MSG_KEY),
305 "77:35: " + getCheckMessage(MSG_KEY),
306 "79:35: " + getCheckMessage(MSG_KEY),
307 "81:35: " + getCheckMessage(MSG_KEY),
308 "93:24: " + getCheckMessage(MSG_KEY),
309 "95:24: " + getCheckMessage(MSG_KEY),
310 "97:24: " + getCheckMessage(MSG_KEY),
311 "99:24: " + getCheckMessage(MSG_KEY),
312 "101:24: " + getCheckMessage(MSG_KEY),
313 "104:24: " + getCheckMessage(MSG_KEY),
314 "108:31: " + getCheckMessage(MSG_KEY),
315 "108:48: " + getCheckMessage(MSG_KEY),
316 };
317 verifyWithInlineConfigParser(
318 getPath("InputAvoidEscapedUnicodeCharacters2One.java"), expected);
319 }
320
321 @Test
322 public void testAllowByTailCommentTwo() throws Exception {
323 final String[] expected = {
324 "21:31: " + getCheckMessage(MSG_KEY),
325 "21:45: " + getCheckMessage(MSG_KEY),
326 "30:38: " + getCheckMessage(MSG_KEY),
327 "36:38: " + getCheckMessage(MSG_KEY),
328 "38:46: " + getCheckMessage(MSG_KEY),
329 "42:46: " + getCheckMessage(MSG_KEY),
330 "45:46: " + getCheckMessage(MSG_KEY),
331 "48:46: " + getCheckMessage(MSG_KEY),
332 "51:46: " + getCheckMessage(MSG_KEY),
333 "54:48: " + getCheckMessage(MSG_KEY),
334 };
335 verifyWithInlineConfigParser(
336 getPath("InputAvoidEscapedUnicodeCharacters2Two.java"), expected);
337 }
338
339 @Test
340 public void testAllowAllCharactersEscapedOne() throws Exception {
341 final String[] expected = {
342 "17:38: " + getCheckMessage(MSG_KEY),
343 "19:38: " + getCheckMessage(MSG_KEY),
344 "21:38: " + getCheckMessage(MSG_KEY),
345 "26:38: " + getCheckMessage(MSG_KEY),
346 "28:38: " + getCheckMessage(MSG_KEY),
347 "44:38: " + getCheckMessage(MSG_KEY),
348 "46:38: " + getCheckMessage(MSG_KEY),
349 "48:38: " + getCheckMessage(MSG_KEY),
350 "58:32: " + getCheckMessage(MSG_KEY),
351 };
352 verifyWithInlineConfigParser(
353 getPath("InputAvoidEscapedUnicodeCharacters3One.java"), expected);
354 }
355
356 @Test
357 public void testAllowAllCharactersEscapedTwo() throws Exception {
358 final String[] expected = {
359 "15:38: " + getCheckMessage(MSG_KEY),
360 "17:38: " + getCheckMessage(MSG_KEY),
361 "19:38: " + getCheckMessage(MSG_KEY),
362 "21:38: " + getCheckMessage(MSG_KEY),
363 "31:38: " + getCheckMessage(MSG_KEY),
364 "39:46: " + getCheckMessage(MSG_KEY),
365 "41:55: " + getCheckMessage(MSG_KEY),
366 "43:46: " + getCheckMessage(MSG_KEY),
367 "45:55: " + getCheckMessage(MSG_KEY),
368 "47:46: " + getCheckMessage(MSG_KEY),
369 "49:55: " + getCheckMessage(MSG_KEY),
370 "51:46: " + getCheckMessage(MSG_KEY),
371 "53:55: " + getCheckMessage(MSG_KEY),
372 "55:46: " + getCheckMessage(MSG_KEY),
373 "57:55: " + getCheckMessage(MSG_KEY),
374 "59:48: " + getCheckMessage(MSG_KEY),
375 "61:57: " + getCheckMessage(MSG_KEY),
376 };
377 verifyWithInlineConfigParser(
378 getPath("InputAvoidEscapedUnicodeCharacters3Two.java"), expected);
379 }
380
381 @Test
382 public void allowNonPrintableEscapesOne() throws Exception {
383 final String[] expected = {
384 "17:38: " + getCheckMessage(MSG_KEY),
385 "19:38: " + getCheckMessage(MSG_KEY),
386 "21:38: " + getCheckMessage(MSG_KEY),
387 "26:38: " + getCheckMessage(MSG_KEY),
388 "28:38: " + getCheckMessage(MSG_KEY),
389 "37:36: " + getCheckMessage(MSG_KEY),
390 "39:36: " + getCheckMessage(MSG_KEY),
391 "46:38: " + getCheckMessage(MSG_KEY),
392 "48:38: " + getCheckMessage(MSG_KEY),
393 "50:38: " + getCheckMessage(MSG_KEY),
394 "52:47: " + getCheckMessage(MSG_KEY),
395 "61:32: " + getCheckMessage(MSG_KEY),
396 };
397 verifyWithInlineConfigParser(
398 getPath("InputAvoidEscapedUnicodeCharacters4One.java"), expected);
399 }
400
401 @Test
402 public void allowNonPrintableEscapesTwo() throws Exception {
403 final String[] expected = {
404 "15:38: " + getCheckMessage(MSG_KEY),
405 "17:38: " + getCheckMessage(MSG_KEY),
406 "19:38: " + getCheckMessage(MSG_KEY),
407 "21:38: " + getCheckMessage(MSG_KEY),
408 "26:34: " + getCheckMessage(MSG_KEY),
409 "28:46: " + getCheckMessage(MSG_KEY),
410 "33:38: " + getCheckMessage(MSG_KEY),
411 "40:38: " + getCheckMessage(MSG_KEY),
412 "43:46: " + getCheckMessage(MSG_KEY),
413 "45:55: " + getCheckMessage(MSG_KEY),
414 "47:46: " + getCheckMessage(MSG_KEY),
415 "49:55: " + getCheckMessage(MSG_KEY),
416 "51:46: " + getCheckMessage(MSG_KEY),
417 "53:55: " + getCheckMessage(MSG_KEY),
418 "55:46: " + getCheckMessage(MSG_KEY),
419 "57:55: " + getCheckMessage(MSG_KEY),
420 "59:46: " + getCheckMessage(MSG_KEY),
421 "61:55: " + getCheckMessage(MSG_KEY),
422 "63:48: " + getCheckMessage(MSG_KEY),
423 "65:57: " + getCheckMessage(MSG_KEY),
424 };
425 verifyWithInlineConfigParser(
426 getPath("InputAvoidEscapedUnicodeCharacters4Two.java"), expected);
427 }
428
429 @Test
430 public void testAllowByTailCommentWithEmoji() throws Exception {
431 final String[] expected = {
432 "15:24: " + getCheckMessage(MSG_KEY),
433 "18:24: " + getCheckMessage(MSG_KEY),
434 "23:30: " + getCheckMessage(MSG_KEY),
435 "33:18: " + getCheckMessage(MSG_KEY),
436 "36:18: " + getCheckMessage(MSG_KEY),
437 "38:18: " + getCheckMessage(MSG_KEY),
438 "41:18: " + getCheckMessage(MSG_KEY),
439 };
440 verifyWithInlineConfigParser(
441 getPath("InputAvoidEscapedUnicodeCharacters5.java"), expected);
442 }
443
444 @Test
445 public void testAvoidEscapedUnicodeCharactersTextBlocksAllowByComment() throws Exception {
446 final String[] expected = {
447 "18:30: " + getCheckMessage(MSG_KEY),
448 "20:30: " + getCheckMessage(MSG_KEY),
449 "22:30: " + getCheckMessage(MSG_KEY),
450 "25:39: " + getCheckMessage(MSG_KEY),
451 "30:33: " + getCheckMessage(MSG_KEY),
452 "33:33: " + getCheckMessage(MSG_KEY),
453 "36:33: " + getCheckMessage(MSG_KEY),
454 "41:42: " + getCheckMessage(MSG_KEY),
455 };
456 verifyWithInlineConfigParser(
457 getPath(
458 "InputAvoidEscapedUnicodeCharactersTextBlocksAllowByComment.java"),
459 expected);
460 }
461
462 @Test
463 public void testAvoidEscapedUnicodeCharactersTextBlocks() throws Exception {
464 final String[] expected = {
465 "17:30: " + getCheckMessage(MSG_KEY),
466 "19:30: " + getCheckMessage(MSG_KEY),
467 "21:30: " + getCheckMessage(MSG_KEY),
468 "23:39: " + getCheckMessage(MSG_KEY),
469 "29:33: " + getCheckMessage(MSG_KEY),
470 "32:33: " + getCheckMessage(MSG_KEY),
471 "35:33: " + getCheckMessage(MSG_KEY),
472 "38:42: " + getCheckMessage(MSG_KEY),
473 };
474 verifyWithInlineConfigParser(
475 getPath("InputAvoidEscapedUnicodeCharactersTextBlocks.java"),
476 expected);
477 }
478
479 @Test
480 public void testAvoidEscapedUnicodeCharactersEscapedS() throws Exception {
481 final String[] expected = {
482 "17:21: " + getCheckMessage(MSG_KEY),
483 "19:22: " + getCheckMessage(MSG_KEY),
484 "31:33: " + getCheckMessage(MSG_KEY),
485 "35:33: " + getCheckMessage(MSG_KEY),
486 "39:33: " + getCheckMessage(MSG_KEY),
487 "43:22: " + getCheckMessage(MSG_KEY),
488 };
489 verifyWithInlineConfigParser(
490 getPath("InputAvoidEscapedUnicodeCharactersEscapedS.java"),
491 expected);
492 }
493
494 @Test
495 public void testBlockCommentAtAbsoluteEndOfFile() throws Exception {
496 final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
497 verifyWithInlineConfigParser(
498 getPath("InputAvoidEscapedUnicodeCharactersCommentEnd.java"),
499 expected);
500 }
501
502 @Test
503 public void testBeginTreeClearsPendingViolations() throws Exception {
504 final String file1 = getPath("InputAvoidEscapedUnicodeCharactersBeginTree1.java");
505 final String file2 = getPath("InputAvoidEscapedUnicodeCharactersBeginTree2.java");
506
507 final List<String> expected1 = List.of(
508 "15:17: " + getCheckMessage(MSG_KEY));
509 final List<String> expected2 = Arrays.asList(CommonUtil.EMPTY_STRING_ARRAY);
510
511 verifyWithInlineConfigParser(file1, file2, expected1, expected2);
512 }
513
514 @Test
515 public void testGetAcceptableTokens() {
516 final AvoidEscapedUnicodeCharactersCheck check = new AvoidEscapedUnicodeCharactersCheck();
517 final int[] actual = check.getAcceptableTokens();
518 final int[] expected = {
519 TokenTypes.STRING_LITERAL,
520 TokenTypes.CHAR_LITERAL,
521 TokenTypes.TEXT_BLOCK_CONTENT,
522 TokenTypes.SINGLE_LINE_COMMENT,
523 TokenTypes.BLOCK_COMMENT_BEGIN,
524 };
525 assertWithMessage("Acceptable tokens differ from expected")
526 .that(actual)
527 .isEqualTo(expected);
528 }
529
530 @Test
531 public void testAllowEscapesForControlCharacterSetForAllCharacters() throws Exception {
532
533 final int indexOfStartLineInInputFile = 16;
534 final String message = getCheckMessage(MSG_KEY);
535 final String[] expected = IntStream.rangeClosed(0, 0xFFFF)
536 .parallel()
537 .filter(val -> !isControlCharacter(val))
538 .mapToObj(msg -> indexOfStartLineInInputFile + msg + ":54: " + message)
539 .toArray(String[]::new);
540 verifyWithInlineConfigParser(
541 getPath("InputAvoidEscapedUnicodeCharactersAllEscapedUnicodeCharacters.java"),
542 expected);
543 }
544
545
546
547
548
549
550
551
552
553
554
555 @Test
556 public void testCountMatches() throws Exception {
557 final AvoidEscapedUnicodeCharactersCheck check = new AvoidEscapedUnicodeCharactersCheck();
558 final int actual = TestUtil.invokeMethod(check, "countMatches", Integer.class,
559 Pattern.compile("\\\\u[a-fA-F\\d]{4}"), "\\u1234");
560 assertWithMessage("Unexpected matches count")
561 .that(actual)
562 .isEqualTo(1);
563 }
564
565
566
567
568
569 @Test
570 public void testNonPrintableCharsAreSorted() {
571 String expression = TestUtil.getInternalStaticState(
572 AvoidEscapedUnicodeCharactersCheck.class,
573 "NON_PRINTABLE_CHARS", Pattern.class).pattern();
574
575
576 final String[] charExpressions = {"Aa", "Bb", "Cc", "Dd", "Ee", "Ff"};
577 for (String charExpression : charExpressions) {
578 final String regex = "\\[[" + charExpression + "]{2}]";
579 expression = expression.replaceAll(regex, charExpression.substring(0, 1));
580 }
581
582
583 for (int i = 4; i > 1; i--) {
584 final String regex = "([A-F])\\{" + i + "}";
585 String replacement = "$1$1{" + (i - 1) + "}";
586 if (i == 2) {
587 replacement = "$1$1";
588 }
589 expression = expression.replaceAll(regex, replacement);
590 }
591
592
593 final List<String> expressionParts = Splitter.on("|").splitToList(expression);
594 final Pattern unicodeCharPattern = Pattern.compile("^\\\\\\\\u[\\dA-F]{4}$");
595 String lastChar = null;
596 for (int i = 0; i < expressionParts.size(); i++) {
597 final String currentChar = expressionParts.get(i);
598 final Matcher matcher = unicodeCharPattern.matcher(currentChar);
599 if (!matcher.matches()) {
600 final String message = "Character '" + currentChar + "' (at position " + i
601 + ") doesn't match the pattern";
602 assertWithMessage(message)
603 .that(matcher.matches())
604 .isTrue();
605 }
606 if (lastChar != null) {
607 final String message = "Character '" + lastChar + "' should be after '"
608 + currentChar + "', position: " + i;
609 assertWithMessage(message)
610 .that(lastChar.compareTo(currentChar) < 0)
611 .isTrue();
612 }
613 lastChar = currentChar;
614 }
615 }
616
617 private static boolean isControlCharacter(final int character) {
618 return Arrays.binarySearch(C0_CONTROL_CHARACTER_INDICES, character) >= 0
619 || Arrays.binarySearch(C1_CONTROL_CHARACTER_INDICES, character) >= 0
620 || Arrays.binarySearch(OTHER_CONTROL_CHARACTER_INDICES, character) >= 0;
621 }
622
623 }