1/*
2 * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24/**
25 * @test
26 * @summary tests RegExp framework (use -Dseed=X to set PRNG seed)
27 * @author Mike McCloskey
28 * @bug 4481568 4482696 4495089 4504687 4527731 4599621 4631553 4619345
29 * 4630911 4672616 4711773 4727935 4750573 4792284 4803197 4757029 4808962
30 * 4872664 4803179 4892980 4900747 4945394 4938995 4979006 4994840 4997476
31 * 5013885 5003322 4988891 5098443 5110268 6173522 4829857 5027748 6376940
32 * 6358731 6178785 6284152 6231989 6497148 6486934 6233084 6504326 6635133
33 * 6350801 6676425 6878475 6919132 6931676 6948903 6990617 7014645 7039066
34 * 7067045 7014640 7189363 8007395 8013252 8013254 8012646 8023647 6559590
35 * 8027645 8035076 8039124 8035975 8074678 6854417 8143854 8147531 7071819
36 * 8151481 4867170 7080302 6728861 6995635 6736245 4916384
37 * 6328855 6192895 6345469 6988218 6693451 7006761 8140212 8143282 8158482
38 * 8176029
39 *
40 * @library /lib/testlibrary
41 * @build jdk.testlibrary.*
42 * @run main RegExTest
43 * @key randomness
44 */
45
46import java.util.function.Function;
47import java.util.regex.*;
48import java.util.Random;
49import java.util.Scanner;
50import java.io.*;
51import java.nio.file.*;
52import java.util.*;
53import java.nio.CharBuffer;
54import java.util.function.Predicate;
55import jdk.testlibrary.RandomFactory;
56
57/**
58 * This is a test class created to check the operation of
59 * the Pattern and Matcher classes.
60 */
61public class RegExTest {
62
63    private static Random generator = RandomFactory.getRandom();
64    private static boolean failure = false;
65    private static int failCount = 0;
66    private static String firstFailure = null;
67
68    /**
69     * Main to interpret arguments and run several tests.
70     *
71     */
72    public static void main(String[] args) throws Exception {
73        // Most of the tests are in a file
74        processFile("TestCases.txt");
75        //processFile("PerlCases.txt");
76        processFile("BMPTestCases.txt");
77        processFile("SupplementaryTestCases.txt");
78
79        // These test many randomly generated char patterns
80        bm();
81        slice();
82
83        // These are hard to put into the file
84        escapes();
85        blankInput();
86
87        // Substitition tests on randomly generated sequences
88        globalSubstitute();
89        stringbufferSubstitute();
90        stringbuilderSubstitute();
91
92        substitutionBasher();
93        substitutionBasher2();
94
95        // Canonical Equivalence
96        ceTest();
97
98        // Anchors
99        anchorTest();
100
101        // boolean match calls
102        matchesTest();
103        lookingAtTest();
104
105        // Pattern API
106        patternMatchesTest();
107
108        // Misc
109        lookbehindTest();
110        nullArgumentTest();
111        backRefTest();
112        groupCaptureTest();
113        caretTest();
114        charClassTest();
115        emptyPatternTest();
116        findIntTest();
117        group0Test();
118        longPatternTest();
119        octalTest();
120        ampersandTest();
121        negationTest();
122        splitTest();
123        appendTest();
124        caseFoldingTest();
125        commentsTest();
126        unixLinesTest();
127        replaceFirstTest();
128        gTest();
129        zTest();
130        serializeTest();
131        reluctantRepetitionTest();
132        multilineDollarTest();
133        dollarAtEndTest();
134        caretBetweenTerminatorsTest();
135        // This RFE rejected in Tiger numOccurrencesTest();
136        javaCharClassTest();
137        nonCaptureRepetitionTest();
138        notCapturedGroupCurlyMatchTest();
139        escapedSegmentTest();
140        literalPatternTest();
141        literalReplacementTest();
142        regionTest();
143        toStringTest();
144        negatedCharClassTest();
145        findFromTest();
146        boundsTest();
147        unicodeWordBoundsTest();
148        caretAtEndTest();
149        wordSearchTest();
150        hitEndTest();
151        toMatchResultTest();
152        toMatchResultTest2();
153        surrogatesInClassTest();
154        removeQEQuotingTest();
155        namedGroupCaptureTest();
156        nonBmpClassComplementTest();
157        unicodePropertiesTest();
158        unicodeHexNotationTest();
159        unicodeClassesTest();
160        unicodeCharacterNameTest();
161        horizontalAndVerticalWSTest();
162        linebreakTest();
163        branchTest();
164        groupCurlyNotFoundSuppTest();
165        groupCurlyBackoffTest();
166        patternAsPredicate();
167        invalidFlags();
168        embeddedFlags();
169        grapheme();
170        expoBacktracking();
171
172        if (failure) {
173            throw new
174                RuntimeException("RegExTest failed, 1st failure: " +
175                                 firstFailure);
176        } else {
177            System.err.println("OKAY: All tests passed.");
178        }
179    }
180
181    // Utility functions
182
183    private static String getRandomAlphaString(int length) {
184        StringBuffer buf = new StringBuffer(length);
185        for (int i=0; i<length; i++) {
186            char randChar = (char)(97 + generator.nextInt(26));
187            buf.append(randChar);
188        }
189        return buf.toString();
190    }
191
192    private static void check(Matcher m, String expected) {
193        m.find();
194        if (!m.group().equals(expected))
195            failCount++;
196    }
197
198    private static void check(Matcher m, String result, boolean expected) {
199        m.find();
200        if (m.group().equals(result) != expected)
201            failCount++;
202    }
203
204    private static void check(Pattern p, String s, boolean expected) {
205        if (p.matcher(s).find() != expected)
206            failCount++;
207    }
208
209    private static void check(String p, String s, boolean expected) {
210        Matcher matcher = Pattern.compile(p).matcher(s);
211        if (matcher.find() != expected)
212            failCount++;
213    }
214
215    private static void check(String p, char c, boolean expected) {
216        String propertyPattern = expected ? "\\p" + p : "\\P" + p;
217        Pattern pattern = Pattern.compile(propertyPattern);
218        char[] ca = new char[1]; ca[0] = c;
219        Matcher matcher = pattern.matcher(new String(ca));
220        if (!matcher.find())
221            failCount++;
222    }
223
224    private static void check(String p, int codePoint, boolean expected) {
225        String propertyPattern = expected ? "\\p" + p : "\\P" + p;
226        Pattern pattern = Pattern.compile(propertyPattern);
227        char[] ca = Character.toChars(codePoint);
228        Matcher matcher = pattern.matcher(new String(ca));
229        if (!matcher.find())
230            failCount++;
231    }
232
233    private static void check(String p, int flag, String input, String s,
234                              boolean expected)
235    {
236        Pattern pattern = Pattern.compile(p, flag);
237        Matcher matcher = pattern.matcher(input);
238        if (expected)
239            check(matcher, s, expected);
240        else
241            check(pattern, input, false);
242    }
243
244    private static void report(String testName) {
245        int spacesToAdd = 30 - testName.length();
246        StringBuffer paddedNameBuffer = new StringBuffer(testName);
247        for (int i=0; i<spacesToAdd; i++)
248            paddedNameBuffer.append(" ");
249        String paddedName = paddedNameBuffer.toString();
250        System.err.println(paddedName + ": " +
251                           (failCount==0 ? "Passed":"Failed("+failCount+")"));
252        if (failCount > 0) {
253            failure = true;
254
255            if (firstFailure == null) {
256                firstFailure = testName;
257            }
258        }
259
260        failCount = 0;
261    }
262
263    /**
264     * Converts ASCII alphabet characters [A-Za-z] in the given 's' to
265     * supplementary characters. This method does NOT fully take care
266     * of the regex syntax.
267     */
268    private static String toSupplementaries(String s) {
269        int length = s.length();
270        StringBuffer sb = new StringBuffer(length * 2);
271
272        for (int i = 0; i < length; ) {
273            char c = s.charAt(i++);
274            if (c == '\\') {
275                sb.append(c);
276                if (i < length) {
277                    c = s.charAt(i++);
278                    sb.append(c);
279                    if (c == 'u') {
280                        // assume no syntax error
281                        sb.append(s.charAt(i++));
282                        sb.append(s.charAt(i++));
283                        sb.append(s.charAt(i++));
284                        sb.append(s.charAt(i++));
285                    }
286                }
287            } else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) {
288                sb.append('\ud800').append((char)('\udc00'+c));
289            } else {
290                sb.append(c);
291            }
292        }
293        return sb.toString();
294    }
295
296    // Regular expression tests
297
298    // This is for bug 6178785
299    // Test if an expected NPE gets thrown when passing in a null argument
300    private static boolean check(Runnable test) {
301        try {
302            test.run();
303            failCount++;
304            return false;
305        } catch (NullPointerException npe) {
306            return true;
307        }
308    }
309
310    private static void nullArgumentTest() {
311        check(() -> Pattern.compile(null));
312        check(() -> Pattern.matches(null, null));
313        check(() -> Pattern.matches("xyz", null));
314        check(() -> Pattern.quote(null));
315        check(() -> Pattern.compile("xyz").split(null));
316        check(() -> Pattern.compile("xyz").matcher(null));
317
318        final Matcher m = Pattern.compile("xyz").matcher("xyz");
319        m.matches();
320        check(() -> m.appendTail((StringBuffer) null));
321        check(() -> m.appendTail((StringBuilder)null));
322        check(() -> m.replaceAll((String) null));
323        check(() -> m.replaceAll((Function<MatchResult, String>)null));
324        check(() -> m.replaceFirst((String)null));
325        check(() -> m.replaceFirst((Function<MatchResult, String>) null));
326        check(() -> m.appendReplacement((StringBuffer)null, null));
327        check(() -> m.appendReplacement((StringBuilder)null, null));
328        check(() -> m.reset(null));
329        check(() -> Matcher.quoteReplacement(null));
330        //check(() -> m.usePattern(null));
331
332        report("Null Argument");
333    }
334
335    // This is for bug6635133
336    // Test if surrogate pair in Unicode escapes can be handled correctly.
337    private static void surrogatesInClassTest() throws Exception {
338        Pattern pattern = Pattern.compile("[\\ud834\\udd21-\\ud834\\udd24]");
339        Matcher matcher = pattern.matcher("\ud834\udd22");
340        if (!matcher.find())
341            failCount++;
342
343        report("Surrogate pair in Unicode escape");
344    }
345
346    // This is for bug6990617
347    // Test if Pattern.RemoveQEQuoting works correctly if the octal unicode
348    // char encoding is only 2 or 3 digits instead of 4 and the first quoted
349    // char is an octal digit.
350    private static void removeQEQuotingTest() throws Exception {
351        Pattern pattern =
352            Pattern.compile("\\011\\Q1sometext\\E\\011\\Q2sometext\\E");
353        Matcher matcher = pattern.matcher("\t1sometext\t2sometext");
354        if (!matcher.find())
355            failCount++;
356
357        report("Remove Q/E Quoting");
358    }
359
360    // This is for bug 4988891
361    // Test toMatchResult to see that it is a copy of the Matcher
362    // that is not affected by subsequent operations on the original
363    private static void toMatchResultTest() throws Exception {
364        Pattern pattern = Pattern.compile("squid");
365        Matcher matcher = pattern.matcher(
366            "agiantsquidofdestinyasmallsquidoffate");
367        matcher.find();
368        int matcherStart1 = matcher.start();
369        MatchResult mr = matcher.toMatchResult();
370        if (mr == matcher)
371            failCount++;
372        int resultStart1 = mr.start();
373        if (matcherStart1 != resultStart1)
374            failCount++;
375        matcher.find();
376        int matcherStart2 = matcher.start();
377        int resultStart2 = mr.start();
378        if (matcherStart2 == resultStart2)
379            failCount++;
380        if (resultStart1 != resultStart2)
381            failCount++;
382        MatchResult mr2 = matcher.toMatchResult();
383        if (mr == mr2)
384            failCount++;
385        if (mr2.start() != matcherStart2)
386            failCount++;
387        report("toMatchResult is a copy");
388    }
389
390    private static void checkExpectedISE(Runnable test) {
391        try {
392            test.run();
393            failCount++;
394        } catch (IllegalStateException x) {
395        } catch (IndexOutOfBoundsException xx) {
396            failCount++;
397        }
398    }
399
400    private static void checkExpectedIOOE(Runnable test) {
401        try {
402            test.run();
403            failCount++;
404        } catch (IndexOutOfBoundsException x) {}
405    }
406
407    // This is for bug 8074678
408    // Test the result of toMatchResult throws ISE if no match is availble
409    private static void toMatchResultTest2() throws Exception {
410        Matcher matcher = Pattern.compile("nomatch").matcher("hello world");
411        matcher.find();
412        MatchResult mr = matcher.toMatchResult();
413
414        checkExpectedISE(() -> mr.start());
415        checkExpectedISE(() -> mr.start(2));
416        checkExpectedISE(() -> mr.end());
417        checkExpectedISE(() -> mr.end(2));
418        checkExpectedISE(() -> mr.group());
419        checkExpectedISE(() -> mr.group(2));
420
421        matcher = Pattern.compile("(match)").matcher("there is a match");
422        matcher.find();
423        MatchResult mr2 = matcher.toMatchResult();
424        checkExpectedIOOE(() -> mr2.start(2));
425        checkExpectedIOOE(() -> mr2.end(2));
426        checkExpectedIOOE(() -> mr2.group(2));
427
428        report("toMatchResult2 appropriate exceptions");
429    }
430
431    // This is for bug 5013885
432    // Must test a slice to see if it reports hitEnd correctly
433    private static void hitEndTest() throws Exception {
434        // Basic test of Slice node
435        Pattern p = Pattern.compile("^squidattack");
436        Matcher m = p.matcher("squack");
437        m.find();
438        if (m.hitEnd())
439            failCount++;
440        m.reset("squid");
441        m.find();
442        if (!m.hitEnd())
443            failCount++;
444
445        // Test Slice, SliceA and SliceU nodes
446        for (int i=0; i<3; i++) {
447            int flags = 0;
448            if (i==1) flags = Pattern.CASE_INSENSITIVE;
449            if (i==2) flags = Pattern.UNICODE_CASE;
450            p = Pattern.compile("^abc", flags);
451            m = p.matcher("ad");
452            m.find();
453            if (m.hitEnd())
454                failCount++;
455            m.reset("ab");
456            m.find();
457            if (!m.hitEnd())
458                failCount++;
459        }
460
461        // Test Boyer-Moore node
462        p = Pattern.compile("catattack");
463        m = p.matcher("attack");
464        m.find();
465        if (!m.hitEnd())
466            failCount++;
467
468        p = Pattern.compile("catattack");
469        m = p.matcher("attackattackattackcatatta");
470        m.find();
471        if (!m.hitEnd())
472            failCount++;
473        report("hitEnd from a Slice");
474    }
475
476    // This is for bug 4997476
477    // It is weird code submitted by customer demonstrating a regression
478    private static void wordSearchTest() throws Exception {
479        String testString = new String("word1 word2 word3");
480        Pattern p = Pattern.compile("\\b");
481        Matcher m = p.matcher(testString);
482        int position = 0;
483        int start = 0;
484        while (m.find(position)) {
485            start = m.start();
486            if (start == testString.length())
487                break;
488            if (m.find(start+1)) {
489                position = m.start();
490            } else {
491                position = testString.length();
492            }
493            if (testString.substring(start, position).equals(" "))
494                continue;
495            if (!testString.substring(start, position-1).startsWith("word"))
496                failCount++;
497        }
498        report("Customer word search");
499    }
500
501    // This is for bug 4994840
502    private static void caretAtEndTest() throws Exception {
503        // Problem only occurs with multiline patterns
504        // containing a beginning-of-line caret "^" followed
505        // by an expression that also matches the empty string.
506        Pattern pattern = Pattern.compile("^x?", Pattern.MULTILINE);
507        Matcher matcher = pattern.matcher("\r");
508        matcher.find();
509        matcher.find();
510        report("Caret at end");
511    }
512
513    // This test is for 4979006
514    // Check to see if word boundary construct properly handles unicode
515    // non spacing marks
516    private static void unicodeWordBoundsTest() throws Exception {
517        String spaces = "  ";
518        String wordChar = "a";
519        String nsm = "\u030a";
520
521        assert (Character.getType('\u030a') == Character.NON_SPACING_MARK);
522
523        Pattern pattern = Pattern.compile("\\b");
524        Matcher matcher = pattern.matcher("");
525        // S=other B=word character N=non spacing mark .=word boundary
526        // SS.BB.SS
527        String input = spaces + wordChar + wordChar + spaces;
528        twoFindIndexes(input, matcher, 2, 4);
529        // SS.BBN.SS
530        input = spaces + wordChar +wordChar + nsm + spaces;
531        twoFindIndexes(input, matcher, 2, 5);
532        // SS.BN.SS
533        input = spaces + wordChar + nsm + spaces;
534        twoFindIndexes(input, matcher, 2, 4);
535        // SS.BNN.SS
536        input = spaces + wordChar + nsm + nsm + spaces;
537        twoFindIndexes(input, matcher, 2, 5);
538        // SSN.BB.SS
539        input = spaces + nsm + wordChar + wordChar + spaces;
540        twoFindIndexes(input, matcher, 3, 5);
541        // SS.BNB.SS
542        input = spaces + wordChar + nsm + wordChar + spaces;
543        twoFindIndexes(input, matcher, 2, 5);
544        // SSNNSS
545        input = spaces + nsm + nsm + spaces;
546        matcher.reset(input);
547        if (matcher.find())
548            failCount++;
549        // SSN.BBN.SS
550        input = spaces + nsm + wordChar + wordChar + nsm + spaces;
551        twoFindIndexes(input, matcher, 3, 6);
552
553        report("Unicode word boundary");
554    }
555
556    private static void twoFindIndexes(String input, Matcher matcher, int a,
557                                       int b) throws Exception
558    {
559        matcher.reset(input);
560        matcher.find();
561        if (matcher.start() != a)
562            failCount++;
563        matcher.find();
564        if (matcher.start() != b)
565            failCount++;
566    }
567
568    // This test is for 6284152
569    static void check(String regex, String input, String[] expected) {
570        List<String> result = new ArrayList<String>();
571        Pattern p = Pattern.compile(regex);
572        Matcher m = p.matcher(input);
573        while (m.find()) {
574            result.add(m.group());
575        }
576        if (!Arrays.asList(expected).equals(result))
577            failCount++;
578    }
579
580    private static void lookbehindTest() throws Exception {
581        //Positive
582        check("(?<=%.{0,5})foo\\d",
583              "%foo1\n%bar foo2\n%bar  foo3\n%blahblah foo4\nfoo5",
584              new String[]{"foo1", "foo2", "foo3"});
585
586        //boundary at end of the lookbehind sub-regex should work consistently
587        //with the boundary just after the lookbehind sub-regex
588        check("(?<=.*\\b)foo", "abcd foo", new String[]{"foo"});
589        check("(?<=.*)\\bfoo", "abcd foo", new String[]{"foo"});
590        check("(?<!abc )\\bfoo", "abc foo", new String[0]);
591        check("(?<!abc \\b)foo", "abc foo", new String[0]);
592
593        //Negative
594        check("(?<!%.{0,5})foo\\d",
595              "%foo1\n%bar foo2\n%bar  foo3\n%blahblah foo4\nfoo5",
596              new String[] {"foo4", "foo5"});
597
598        //Positive greedy
599        check("(?<=%b{1,4})foo", "%bbbbfoo", new String[] {"foo"});
600
601        //Positive reluctant
602        check("(?<=%b{1,4}?)foo", "%bbbbfoo", new String[] {"foo"});
603
604        //supplementary
605        check("(?<=%b{1,4})fo\ud800\udc00o", "%bbbbfo\ud800\udc00o",
606              new String[] {"fo\ud800\udc00o"});
607        check("(?<=%b{1,4}?)fo\ud800\udc00o", "%bbbbfo\ud800\udc00o",
608              new String[] {"fo\ud800\udc00o"});
609        check("(?<!%b{1,4})fo\ud800\udc00o", "%afo\ud800\udc00o",
610              new String[] {"fo\ud800\udc00o"});
611        check("(?<!%b{1,4}?)fo\ud800\udc00o", "%afo\ud800\udc00o",
612              new String[] {"fo\ud800\udc00o"});
613        report("Lookbehind");
614    }
615
616    // This test is for 4938995
617    // Check to see if weak region boundaries are transparent to
618    // lookahead and lookbehind constructs
619    private static void boundsTest() throws Exception {
620        String fullMessage = "catdogcat";
621        Pattern pattern = Pattern.compile("(?<=cat)dog(?=cat)");
622        Matcher matcher = pattern.matcher("catdogca");
623        matcher.useTransparentBounds(true);
624        if (matcher.find())
625            failCount++;
626        matcher.reset("atdogcat");
627        if (matcher.find())
628            failCount++;
629        matcher.reset(fullMessage);
630        if (!matcher.find())
631            failCount++;
632        matcher.reset(fullMessage);
633        matcher.region(0,9);
634        if (!matcher.find())
635            failCount++;
636        matcher.reset(fullMessage);
637        matcher.region(0,6);
638        if (!matcher.find())
639            failCount++;
640        matcher.reset(fullMessage);
641        matcher.region(3,6);
642        if (!matcher.find())
643            failCount++;
644        matcher.useTransparentBounds(false);
645        if (matcher.find())
646            failCount++;
647
648        // Negative lookahead/lookbehind
649        pattern = Pattern.compile("(?<!cat)dog(?!cat)");
650        matcher = pattern.matcher("dogcat");
651        matcher.useTransparentBounds(true);
652        matcher.region(0,3);
653        if (matcher.find())
654            failCount++;
655        matcher.reset("catdog");
656        matcher.region(3,6);
657        if (matcher.find())
658            failCount++;
659        matcher.useTransparentBounds(false);
660        matcher.reset("dogcat");
661        matcher.region(0,3);
662        if (!matcher.find())
663            failCount++;
664        matcher.reset("catdog");
665        matcher.region(3,6);
666        if (!matcher.find())
667            failCount++;
668
669        report("Region bounds transparency");
670    }
671
672    // This test is for 4945394
673    private static void findFromTest() throws Exception {
674        String message = "This is 40 $0 message.";
675        Pattern pat = Pattern.compile("\\$0");
676        Matcher match = pat.matcher(message);
677        if (!match.find())
678            failCount++;
679        if (match.find())
680            failCount++;
681        if (match.find())
682            failCount++;
683        report("Check for alternating find");
684    }
685
686    // This test is for 4872664 and 4892980
687    private static void negatedCharClassTest() throws Exception {
688        Pattern pattern = Pattern.compile("[^>]");
689        Matcher matcher = pattern.matcher("\u203A");
690        if (!matcher.matches())
691            failCount++;
692        pattern = Pattern.compile("[^fr]");
693        matcher = pattern.matcher("a");
694        if (!matcher.find())
695            failCount++;
696        matcher.reset("\u203A");
697        if (!matcher.find())
698            failCount++;
699        String s = "for";
700        String result[] = s.split("[^fr]");
701        if (!result[0].equals("f"))
702            failCount++;
703        if (!result[1].equals("r"))
704            failCount++;
705        s = "f\u203Ar";
706        result = s.split("[^fr]");
707        if (!result[0].equals("f"))
708            failCount++;
709        if (!result[1].equals("r"))
710            failCount++;
711
712        // Test adding to bits, subtracting a node, then adding to bits again
713        pattern = Pattern.compile("[^f\u203Ar]");
714        matcher = pattern.matcher("a");
715        if (!matcher.find())
716            failCount++;
717        matcher.reset("f");
718        if (matcher.find())
719            failCount++;
720        matcher.reset("\u203A");
721        if (matcher.find())
722            failCount++;
723        matcher.reset("r");
724        if (matcher.find())
725            failCount++;
726        matcher.reset("\u203B");
727        if (!matcher.find())
728            failCount++;
729
730        // Test subtracting a node, adding to bits, subtracting again
731        pattern = Pattern.compile("[^\u203Ar\u203B]");
732        matcher = pattern.matcher("a");
733        if (!matcher.find())
734            failCount++;
735        matcher.reset("\u203A");
736        if (matcher.find())
737            failCount++;
738        matcher.reset("r");
739        if (matcher.find())
740            failCount++;
741        matcher.reset("\u203B");
742        if (matcher.find())
743            failCount++;
744        matcher.reset("\u203C");
745        if (!matcher.find())
746            failCount++;
747
748        report("Negated Character Class");
749    }
750
751    // This test is for 4628291
752    private static void toStringTest() throws Exception {
753        Pattern pattern = Pattern.compile("b+");
754        if (pattern.toString() != "b+")
755            failCount++;
756        Matcher matcher = pattern.matcher("aaabbbccc");
757        String matcherString = matcher.toString(); // unspecified
758        matcher.find();
759        matcherString = matcher.toString(); // unspecified
760        matcher.region(0,3);
761        matcherString = matcher.toString(); // unspecified
762        matcher.reset();
763        matcherString = matcher.toString(); // unspecified
764        report("toString");
765    }
766
767    // This test is for 4808962
768    private static void literalPatternTest() throws Exception {
769        int flags = Pattern.LITERAL;
770
771        Pattern pattern = Pattern.compile("abc\\t$^", flags);
772        check(pattern, "abc\\t$^", true);
773
774        pattern = Pattern.compile(Pattern.quote("abc\\t$^"));
775        check(pattern, "abc\\t$^", true);
776
777        pattern = Pattern.compile("\\Qa^$bcabc\\E", flags);
778        check(pattern, "\\Qa^$bcabc\\E", true);
779        check(pattern, "a^$bcabc", false);
780
781        pattern = Pattern.compile("\\\\Q\\\\E");
782        check(pattern, "\\Q\\E", true);
783
784        pattern = Pattern.compile("\\Qabc\\Eefg\\\\Q\\\\Ehij");
785        check(pattern, "abcefg\\Q\\Ehij", true);
786
787        pattern = Pattern.compile("\\\\\\Q\\\\E");
788        check(pattern, "\\\\\\\\", true);
789
790        pattern = Pattern.compile(Pattern.quote("\\Qa^$bcabc\\E"));
791        check(pattern, "\\Qa^$bcabc\\E", true);
792        check(pattern, "a^$bcabc", false);
793
794        pattern = Pattern.compile(Pattern.quote("\\Qabc\\Edef"));
795        check(pattern, "\\Qabc\\Edef", true);
796        check(pattern, "abcdef", false);
797
798        pattern = Pattern.compile(Pattern.quote("abc\\Edef"));
799        check(pattern, "abc\\Edef", true);
800        check(pattern, "abcdef", false);
801
802        pattern = Pattern.compile(Pattern.quote("\\E"));
803        check(pattern, "\\E", true);
804
805        pattern = Pattern.compile("((((abc.+?:)", flags);
806        check(pattern, "((((abc.+?:)", true);
807
808        flags |= Pattern.MULTILINE;
809
810        pattern = Pattern.compile("^cat$", flags);
811        check(pattern, "abc^cat$def", true);
812        check(pattern, "cat", false);
813
814        flags |= Pattern.CASE_INSENSITIVE;
815
816        pattern = Pattern.compile("abcdef", flags);
817        check(pattern, "ABCDEF", true);
818        check(pattern, "AbCdEf", true);
819
820        flags |= Pattern.DOTALL;
821
822        pattern = Pattern.compile("a...b", flags);
823        check(pattern, "A...b", true);
824        check(pattern, "Axxxb", false);
825
826        flags |= Pattern.CANON_EQ;
827
828        Pattern p = Pattern.compile("testa\u030a", flags);
829        check(pattern, "testa\u030a", false);
830        check(pattern, "test\u00e5", false);
831
832        // Supplementary character test
833        flags = Pattern.LITERAL;
834
835        pattern = Pattern.compile(toSupplementaries("abc\\t$^"), flags);
836        check(pattern, toSupplementaries("abc\\t$^"), true);
837
838        pattern = Pattern.compile(Pattern.quote(toSupplementaries("abc\\t$^")));
839        check(pattern, toSupplementaries("abc\\t$^"), true);
840
841        pattern = Pattern.compile(toSupplementaries("\\Qa^$bcabc\\E"), flags);
842        check(pattern, toSupplementaries("\\Qa^$bcabc\\E"), true);
843        check(pattern, toSupplementaries("a^$bcabc"), false);
844
845        pattern = Pattern.compile(Pattern.quote(toSupplementaries("\\Qa^$bcabc\\E")));
846        check(pattern, toSupplementaries("\\Qa^$bcabc\\E"), true);
847        check(pattern, toSupplementaries("a^$bcabc"), false);
848
849        pattern = Pattern.compile(Pattern.quote(toSupplementaries("\\Qabc\\Edef")));
850        check(pattern, toSupplementaries("\\Qabc\\Edef"), true);
851        check(pattern, toSupplementaries("abcdef"), false);
852
853        pattern = Pattern.compile(Pattern.quote(toSupplementaries("abc\\Edef")));
854        check(pattern, toSupplementaries("abc\\Edef"), true);
855        check(pattern, toSupplementaries("abcdef"), false);
856
857        pattern = Pattern.compile(toSupplementaries("((((abc.+?:)"), flags);
858        check(pattern, toSupplementaries("((((abc.+?:)"), true);
859
860        flags |= Pattern.MULTILINE;
861
862        pattern = Pattern.compile(toSupplementaries("^cat$"), flags);
863        check(pattern, toSupplementaries("abc^cat$def"), true);
864        check(pattern, toSupplementaries("cat"), false);
865
866        flags |= Pattern.DOTALL;
867
868        // note: this is case-sensitive.
869        pattern = Pattern.compile(toSupplementaries("a...b"), flags);
870        check(pattern, toSupplementaries("a...b"), true);
871        check(pattern, toSupplementaries("axxxb"), false);
872
873        flags |= Pattern.CANON_EQ;
874
875        String t = toSupplementaries("test");
876        p = Pattern.compile(t + "a\u030a", flags);
877        check(pattern, t + "a\u030a", false);
878        check(pattern, t + "\u00e5", false);
879
880        report("Literal pattern");
881    }
882
883    // This test is for 4803179
884    // This test is also for 4808962, replacement parts
885    private static void literalReplacementTest() throws Exception {
886        int flags = Pattern.LITERAL;
887
888        Pattern pattern = Pattern.compile("abc", flags);
889        Matcher matcher = pattern.matcher("zzzabczzz");
890        String replaceTest = "$0";
891        String result = matcher.replaceAll(replaceTest);
892        if (!result.equals("zzzabczzz"))
893            failCount++;
894
895        matcher.reset();
896        String literalReplacement = matcher.quoteReplacement(replaceTest);
897        result = matcher.replaceAll(literalReplacement);
898        if (!result.equals("zzz$0zzz"))
899            failCount++;
900
901        matcher.reset();
902        replaceTest = "\\t$\\$";
903        literalReplacement = matcher.quoteReplacement(replaceTest);
904        result = matcher.replaceAll(literalReplacement);
905        if (!result.equals("zzz\\t$\\$zzz"))
906            failCount++;
907
908        // Supplementary character test
909        pattern = Pattern.compile(toSupplementaries("abc"), flags);
910        matcher = pattern.matcher(toSupplementaries("zzzabczzz"));
911        replaceTest = "$0";
912        result = matcher.replaceAll(replaceTest);
913        if (!result.equals(toSupplementaries("zzzabczzz")))
914            failCount++;
915
916        matcher.reset();
917        literalReplacement = matcher.quoteReplacement(replaceTest);
918        result = matcher.replaceAll(literalReplacement);
919        if (!result.equals(toSupplementaries("zzz$0zzz")))
920            failCount++;
921
922        matcher.reset();
923        replaceTest = "\\t$\\$";
924        literalReplacement = matcher.quoteReplacement(replaceTest);
925        result = matcher.replaceAll(literalReplacement);
926        if (!result.equals(toSupplementaries("zzz\\t$\\$zzz")))
927            failCount++;
928
929        // IAE should be thrown if backslash or '$' is the last character
930        // in replacement string
931        try {
932            "\uac00".replaceAll("\uac00", "$");
933            failCount++;
934        } catch (IllegalArgumentException iie) {
935        } catch (Exception e) {
936            failCount++;
937        }
938        try {
939            "\uac00".replaceAll("\uac00", "\\");
940            failCount++;
941        } catch (IllegalArgumentException iie) {
942        } catch (Exception e) {
943            failCount++;
944        }
945        report("Literal replacement");
946    }
947
948    // This test is for 4757029
949    private static void regionTest() throws Exception {
950        Pattern pattern = Pattern.compile("abc");
951        Matcher matcher = pattern.matcher("abcdefabc");
952
953        matcher.region(0,9);
954        if (!matcher.find())
955            failCount++;
956        if (!matcher.find())
957            failCount++;
958        matcher.region(0,3);
959        if (!matcher.find())
960           failCount++;
961        matcher.region(3,6);
962        if (matcher.find())
963           failCount++;
964        matcher.region(0,2);
965        if (matcher.find())
966           failCount++;
967
968        expectRegionFail(matcher, 1, -1);
969        expectRegionFail(matcher, -1, -1);
970        expectRegionFail(matcher, -1, 1);
971        expectRegionFail(matcher, 5, 3);
972        expectRegionFail(matcher, 5, 12);
973        expectRegionFail(matcher, 12, 12);
974
975        pattern = Pattern.compile("^abc$");
976        matcher = pattern.matcher("zzzabczzz");
977        matcher.region(0,9);
978        if (matcher.find())
979            failCount++;
980        matcher.region(3,6);
981        if (!matcher.find())
982           failCount++;
983        matcher.region(3,6);
984        matcher.useAnchoringBounds(false);
985        if (matcher.find())
986           failCount++;
987
988        // Supplementary character test
989        pattern = Pattern.compile(toSupplementaries("abc"));
990        matcher = pattern.matcher(toSupplementaries("abcdefabc"));
991        matcher.region(0,9*2);
992        if (!matcher.find())
993            failCount++;
994        if (!matcher.find())
995            failCount++;
996        matcher.region(0,3*2);
997        if (!matcher.find())
998           failCount++;
999        matcher.region(1,3*2);
1000        if (matcher.find())
1001           failCount++;
1002        matcher.region(3*2,6*2);
1003        if (matcher.find())
1004           failCount++;
1005        matcher.region(0,2*2);
1006        if (matcher.find())
1007           failCount++;
1008        matcher.region(0,2*2+1);
1009        if (matcher.find())
1010           failCount++;
1011
1012        expectRegionFail(matcher, 1*2, -1);
1013        expectRegionFail(matcher, -1, -1);
1014        expectRegionFail(matcher, -1, 1*2);
1015        expectRegionFail(matcher, 5*2, 3*2);
1016        expectRegionFail(matcher, 5*2, 12*2);
1017        expectRegionFail(matcher, 12*2, 12*2);
1018
1019        pattern = Pattern.compile(toSupplementaries("^abc$"));
1020        matcher = pattern.matcher(toSupplementaries("zzzabczzz"));
1021        matcher.region(0,9*2);
1022        if (matcher.find())
1023            failCount++;
1024        matcher.region(3*2,6*2);
1025        if (!matcher.find())
1026           failCount++;
1027        matcher.region(3*2+1,6*2);
1028        if (matcher.find())
1029           failCount++;
1030        matcher.region(3*2,6*2-1);
1031        if (matcher.find())
1032           failCount++;
1033        matcher.region(3*2,6*2);
1034        matcher.useAnchoringBounds(false);
1035        if (matcher.find())
1036           failCount++;
1037        report("Regions");
1038    }
1039
1040    private static void expectRegionFail(Matcher matcher, int index1,
1041                                         int index2)
1042    {
1043        try {
1044            matcher.region(index1, index2);
1045            failCount++;
1046        } catch (IndexOutOfBoundsException ioobe) {
1047            // Correct result
1048        } catch (IllegalStateException ise) {
1049            // Correct result
1050        }
1051    }
1052
1053    // This test is for 4803197
1054    private static void escapedSegmentTest() throws Exception {
1055
1056        Pattern pattern = Pattern.compile("\\Qdir1\\dir2\\E");
1057        check(pattern, "dir1\\dir2", true);
1058
1059        pattern = Pattern.compile("\\Qdir1\\dir2\\\\E");
1060        check(pattern, "dir1\\dir2\\", true);
1061
1062        pattern = Pattern.compile("(\\Qdir1\\dir2\\\\E)");
1063        check(pattern, "dir1\\dir2\\", true);
1064
1065        // Supplementary character test
1066        pattern = Pattern.compile(toSupplementaries("\\Qdir1\\dir2\\E"));
1067        check(pattern, toSupplementaries("dir1\\dir2"), true);
1068
1069        pattern = Pattern.compile(toSupplementaries("\\Qdir1\\dir2")+"\\\\E");
1070        check(pattern, toSupplementaries("dir1\\dir2\\"), true);
1071
1072        pattern = Pattern.compile(toSupplementaries("(\\Qdir1\\dir2")+"\\\\E)");
1073        check(pattern, toSupplementaries("dir1\\dir2\\"), true);
1074
1075        report("Escaped segment");
1076    }
1077
1078    // This test is for 4792284
1079    private static void nonCaptureRepetitionTest() throws Exception {
1080        String input = "abcdefgh;";
1081
1082        String[] patterns = new String[] {
1083            "(?:\\w{4})+;",
1084            "(?:\\w{8})*;",
1085            "(?:\\w{2}){2,4};",
1086            "(?:\\w{4}){2,};",   // only matches the
1087            ".*?(?:\\w{5})+;",   //     specified minimum
1088            ".*?(?:\\w{9})*;",   //     number of reps - OK
1089            "(?:\\w{4})+?;",     // lazy repetition - OK
1090            "(?:\\w{4})++;",     // possessive repetition - OK
1091            "(?:\\w{2,}?)+;",    // non-deterministic - OK
1092            "(\\w{4})+;",        // capturing group - OK
1093        };
1094
1095        for (int i = 0; i < patterns.length; i++) {
1096            // Check find()
1097            check(patterns[i], 0, input, input, true);
1098            // Check matches()
1099            Pattern p = Pattern.compile(patterns[i]);
1100            Matcher m = p.matcher(input);
1101
1102            if (m.matches()) {
1103                if (!m.group(0).equals(input))
1104                    failCount++;
1105            } else {
1106                failCount++;
1107            }
1108        }
1109
1110        report("Non capturing repetition");
1111    }
1112
1113    // This test is for 6358731
1114    private static void notCapturedGroupCurlyMatchTest() throws Exception {
1115        Pattern pattern = Pattern.compile("(abc)+|(abcd)+");
1116        Matcher matcher = pattern.matcher("abcd");
1117        if (!matcher.matches() ||
1118             matcher.group(1) != null ||
1119             !matcher.group(2).equals("abcd")) {
1120            failCount++;
1121        }
1122        report("Not captured GroupCurly");
1123    }
1124
1125    // This test is for 4706545
1126    private static void javaCharClassTest() throws Exception {
1127        for (int i=0; i<1000; i++) {
1128            char c = (char)generator.nextInt();
1129            check("{javaLowerCase}", c, Character.isLowerCase(c));
1130            check("{javaUpperCase}", c, Character.isUpperCase(c));
1131            check("{javaUpperCase}+", c, Character.isUpperCase(c));
1132            check("{javaTitleCase}", c, Character.isTitleCase(c));
1133            check("{javaDigit}", c, Character.isDigit(c));
1134            check("{javaDefined}", c, Character.isDefined(c));
1135            check("{javaLetter}", c, Character.isLetter(c));
1136            check("{javaLetterOrDigit}", c, Character.isLetterOrDigit(c));
1137            check("{javaJavaIdentifierStart}", c,
1138                  Character.isJavaIdentifierStart(c));
1139            check("{javaJavaIdentifierPart}", c,
1140                  Character.isJavaIdentifierPart(c));
1141            check("{javaUnicodeIdentifierStart}", c,
1142                  Character.isUnicodeIdentifierStart(c));
1143            check("{javaUnicodeIdentifierPart}", c,
1144                  Character.isUnicodeIdentifierPart(c));
1145            check("{javaIdentifierIgnorable}", c,
1146                  Character.isIdentifierIgnorable(c));
1147            check("{javaSpaceChar}", c, Character.isSpaceChar(c));
1148            check("{javaWhitespace}", c, Character.isWhitespace(c));
1149            check("{javaISOControl}", c, Character.isISOControl(c));
1150            check("{javaMirrored}", c, Character.isMirrored(c));
1151
1152        }
1153
1154        // Supplementary character test
1155        for (int i=0; i<1000; i++) {
1156            int c = generator.nextInt(Character.MAX_CODE_POINT
1157                                      - Character.MIN_SUPPLEMENTARY_CODE_POINT)
1158                        + Character.MIN_SUPPLEMENTARY_CODE_POINT;
1159            check("{javaLowerCase}", c, Character.isLowerCase(c));
1160            check("{javaUpperCase}", c, Character.isUpperCase(c));
1161            check("{javaUpperCase}+", c, Character.isUpperCase(c));
1162            check("{javaTitleCase}", c, Character.isTitleCase(c));
1163            check("{javaDigit}", c, Character.isDigit(c));
1164            check("{javaDefined}", c, Character.isDefined(c));
1165            check("{javaLetter}", c, Character.isLetter(c));
1166            check("{javaLetterOrDigit}", c, Character.isLetterOrDigit(c));
1167            check("{javaJavaIdentifierStart}", c,
1168                  Character.isJavaIdentifierStart(c));
1169            check("{javaJavaIdentifierPart}", c,
1170                  Character.isJavaIdentifierPart(c));
1171            check("{javaUnicodeIdentifierStart}", c,
1172                  Character.isUnicodeIdentifierStart(c));
1173            check("{javaUnicodeIdentifierPart}", c,
1174                  Character.isUnicodeIdentifierPart(c));
1175            check("{javaIdentifierIgnorable}", c,
1176                  Character.isIdentifierIgnorable(c));
1177            check("{javaSpaceChar}", c, Character.isSpaceChar(c));
1178            check("{javaWhitespace}", c, Character.isWhitespace(c));
1179            check("{javaISOControl}", c, Character.isISOControl(c));
1180            check("{javaMirrored}", c, Character.isMirrored(c));
1181        }
1182
1183        report("Java character classes");
1184    }
1185
1186    // This test is for 4523620
1187    /*
1188    private static void numOccurrencesTest() throws Exception {
1189        Pattern pattern = Pattern.compile("aaa");
1190
1191        if (pattern.numOccurrences("aaaaaa", false) != 2)
1192            failCount++;
1193        if (pattern.numOccurrences("aaaaaa", true) != 4)
1194            failCount++;
1195
1196        pattern = Pattern.compile("^");
1197        if (pattern.numOccurrences("aaaaaa", false) != 1)
1198            failCount++;
1199        if (pattern.numOccurrences("aaaaaa", true) != 1)
1200            failCount++;
1201
1202        report("Number of Occurrences");
1203    }
1204    */
1205
1206    // This test is for 4776374
1207    private static void caretBetweenTerminatorsTest() throws Exception {
1208        int flags1 = Pattern.DOTALL;
1209        int flags2 = Pattern.DOTALL | Pattern.UNIX_LINES;
1210        int flags3 = Pattern.DOTALL | Pattern.UNIX_LINES | Pattern.MULTILINE;
1211        int flags4 = Pattern.DOTALL | Pattern.MULTILINE;
1212
1213        check("^....", flags1, "test\ntest", "test", true);
1214        check(".....^", flags1, "test\ntest", "test", false);
1215        check(".....^", flags1, "test\n", "test", false);
1216        check("....^", flags1, "test\r\n", "test", false);
1217
1218        check("^....", flags2, "test\ntest", "test", true);
1219        check("....^", flags2, "test\ntest", "test", false);
1220        check(".....^", flags2, "test\n", "test", false);
1221        check("....^", flags2, "test\r\n", "test", false);
1222
1223        check("^....", flags3, "test\ntest", "test", true);
1224        check(".....^", flags3, "test\ntest", "test\n", true);
1225        check(".....^", flags3, "test\u0085test", "test\u0085", false);
1226        check(".....^", flags3, "test\n", "test", false);
1227        check(".....^", flags3, "test\r\n", "test", false);
1228        check("......^", flags3, "test\r\ntest", "test\r\n", true);
1229
1230        check("^....", flags4, "test\ntest", "test", true);
1231        check(".....^", flags3, "test\ntest", "test\n", true);
1232        check(".....^", flags4, "test\u0085test", "test\u0085", true);
1233        check(".....^", flags4, "test\n", "test\n", false);
1234        check(".....^", flags4, "test\r\n", "test\r", false);
1235
1236        // Supplementary character test
1237        String t = toSupplementaries("test");
1238        check("^....", flags1, t+"\n"+t, t, true);
1239        check(".....^", flags1, t+"\n"+t, t, false);
1240        check(".....^", flags1, t+"\n", t, false);
1241        check("....^", flags1, t+"\r\n", t, false);
1242
1243        check("^....", flags2, t+"\n"+t, t, true);
1244        check("....^", flags2, t+"\n"+t, t, false);
1245        check(".....^", flags2, t+"\n", t, false);
1246        check("....^", flags2, t+"\r\n", t, false);
1247
1248        check("^....", flags3, t+"\n"+t, t, true);
1249        check(".....^", flags3, t+"\n"+t, t+"\n", true);
1250        check(".....^", flags3, t+"\u0085"+t, t+"\u0085", false);
1251        check(".....^", flags3, t+"\n", t, false);
1252        check(".....^", flags3, t+"\r\n", t, false);
1253        check("......^", flags3, t+"\r\n"+t, t+"\r\n", true);
1254
1255        check("^....", flags4, t+"\n"+t, t, true);
1256        check(".....^", flags3, t+"\n"+t, t+"\n", true);
1257        check(".....^", flags4, t+"\u0085"+t, t+"\u0085", true);
1258        check(".....^", flags4, t+"\n", t+"\n", false);
1259        check(".....^", flags4, t+"\r\n", t+"\r", false);
1260
1261        report("Caret between terminators");
1262    }
1263
1264    // This test is for 4727935
1265    private static void dollarAtEndTest() throws Exception {
1266        int flags1 = Pattern.DOTALL;
1267        int flags2 = Pattern.DOTALL | Pattern.UNIX_LINES;
1268        int flags3 = Pattern.DOTALL | Pattern.MULTILINE;
1269
1270        check("....$", flags1, "test\n", "test", true);
1271        check("....$", flags1, "test\r\n", "test", true);
1272        check(".....$", flags1, "test\n", "test\n", true);
1273        check(".....$", flags1, "test\u0085", "test\u0085", true);
1274        check("....$", flags1, "test\u0085", "test", true);
1275
1276        check("....$", flags2, "test\n", "test", true);
1277        check(".....$", flags2, "test\n", "test\n", true);
1278        check(".....$", flags2, "test\u0085", "test\u0085", true);
1279        check("....$", flags2, "test\u0085", "est\u0085", true);
1280
1281        check("....$.blah", flags3, "test\nblah", "test\nblah", true);
1282        check(".....$.blah", flags3, "test\n\nblah", "test\n\nblah", true);
1283        check("....$blah", flags3, "test\nblah", "!!!!", false);
1284        check(".....$blah", flags3, "test\nblah", "!!!!", false);
1285
1286        // Supplementary character test
1287        String t = toSupplementaries("test");
1288        String b = toSupplementaries("blah");
1289        check("....$", flags1, t+"\n", t, true);
1290        check("....$", flags1, t+"\r\n", t, true);
1291        check(".....$", flags1, t+"\n", t+"\n", true);
1292        check(".....$", flags1, t+"\u0085", t+"\u0085", true);
1293        check("....$", flags1, t+"\u0085", t, true);
1294
1295        check("....$", flags2, t+"\n", t, true);
1296        check(".....$", flags2, t+"\n", t+"\n", true);
1297        check(".....$", flags2, t+"\u0085", t+"\u0085", true);
1298        check("....$", flags2, t+"\u0085", toSupplementaries("est\u0085"), true);
1299
1300        check("....$."+b, flags3, t+"\n"+b, t+"\n"+b, true);
1301        check(".....$."+b, flags3, t+"\n\n"+b, t+"\n\n"+b, true);
1302        check("....$"+b, flags3, t+"\n"+b, "!!!!", false);
1303        check(".....$"+b, flags3, t+"\n"+b, "!!!!", false);
1304
1305        report("Dollar at End");
1306    }
1307
1308    // This test is for 4711773
1309    private static void multilineDollarTest() throws Exception {
1310        Pattern findCR = Pattern.compile("$", Pattern.MULTILINE);
1311        Matcher matcher = findCR.matcher("first bit\nsecond bit");
1312        matcher.find();
1313        if (matcher.start(0) != 9)
1314            failCount++;
1315        matcher.find();
1316        if (matcher.start(0) != 20)
1317            failCount++;
1318
1319        // Supplementary character test
1320        matcher = findCR.matcher(toSupplementaries("first  bit\n second  bit")); // double BMP chars
1321        matcher.find();
1322        if (matcher.start(0) != 9*2)
1323            failCount++;
1324        matcher.find();
1325        if (matcher.start(0) != 20*2)
1326            failCount++;
1327
1328        report("Multiline Dollar");
1329    }
1330
1331    private static void reluctantRepetitionTest() throws Exception {
1332        Pattern p = Pattern.compile("1(\\s\\S+?){1,3}?[\\s,]2");
1333        check(p, "1 word word word 2", true);
1334        check(p, "1 wor wo w 2", true);
1335        check(p, "1 word word 2", true);
1336        check(p, "1 word 2", true);
1337        check(p, "1 wo w w 2", true);
1338        check(p, "1 wo w 2", true);
1339        check(p, "1 wor w 2", true);
1340
1341        p = Pattern.compile("([a-z])+?c");
1342        Matcher m = p.matcher("ababcdefdec");
1343        check(m, "ababc");
1344
1345        // Supplementary character test
1346        p = Pattern.compile(toSupplementaries("([a-z])+?c"));
1347        m = p.matcher(toSupplementaries("ababcdefdec"));
1348        check(m, toSupplementaries("ababc"));
1349
1350        report("Reluctant Repetition");
1351    }
1352
1353    private static void serializeTest() throws Exception {
1354        String patternStr = "(b)";
1355        String matchStr = "b";
1356        Pattern pattern = Pattern.compile(patternStr);
1357        ByteArrayOutputStream baos = new ByteArrayOutputStream();
1358        ObjectOutputStream oos = new ObjectOutputStream(baos);
1359        oos.writeObject(pattern);
1360        oos.close();
1361        ObjectInputStream ois = new ObjectInputStream(
1362            new ByteArrayInputStream(baos.toByteArray()));
1363        Pattern serializedPattern = (Pattern)ois.readObject();
1364        ois.close();
1365        Matcher matcher = serializedPattern.matcher(matchStr);
1366        if (!matcher.matches())
1367            failCount++;
1368        if (matcher.groupCount() != 1)
1369            failCount++;
1370
1371        report("Serialization");
1372    }
1373
1374    private static void gTest() {
1375        Pattern pattern = Pattern.compile("\\G\\w");
1376        Matcher matcher = pattern.matcher("abc#x#x");
1377        matcher.find();
1378        matcher.find();
1379        matcher.find();
1380        if (matcher.find())
1381            failCount++;
1382
1383        pattern = Pattern.compile("\\GA*");
1384        matcher = pattern.matcher("1A2AA3");
1385        matcher.find();
1386        if (matcher.find())
1387            failCount++;
1388
1389        pattern = Pattern.compile("\\GA*");
1390        matcher = pattern.matcher("1A2AA3");
1391        if (!matcher.find(1))
1392            failCount++;
1393        matcher.find();
1394        if (matcher.find())
1395            failCount++;
1396
1397        report("\\G");
1398    }
1399
1400    private static void zTest() {
1401        Pattern pattern = Pattern.compile("foo\\Z");
1402        // Positives
1403        check(pattern, "foo\u0085", true);
1404        check(pattern, "foo\u2028", true);
1405        check(pattern, "foo\u2029", true);
1406        check(pattern, "foo\n", true);
1407        check(pattern, "foo\r", true);
1408        check(pattern, "foo\r\n", true);
1409        // Negatives
1410        check(pattern, "fooo", false);
1411        check(pattern, "foo\n\r", false);
1412
1413        pattern = Pattern.compile("foo\\Z", Pattern.UNIX_LINES);
1414        // Positives
1415        check(pattern, "foo", true);
1416        check(pattern, "foo\n", true);
1417        // Negatives
1418        check(pattern, "foo\r", false);
1419        check(pattern, "foo\u0085", false);
1420        check(pattern, "foo\u2028", false);
1421        check(pattern, "foo\u2029", false);
1422
1423        report("\\Z");
1424    }
1425
1426    private static void replaceFirstTest() {
1427        Pattern pattern = Pattern.compile("(ab)(c*)");
1428        Matcher matcher = pattern.matcher("abccczzzabcczzzabccc");
1429        if (!matcher.replaceFirst("test").equals("testzzzabcczzzabccc"))
1430            failCount++;
1431
1432        matcher.reset("zzzabccczzzabcczzzabccczzz");
1433        if (!matcher.replaceFirst("test").equals("zzztestzzzabcczzzabccczzz"))
1434            failCount++;
1435
1436        matcher.reset("zzzabccczzzabcczzzabccczzz");
1437        String result = matcher.replaceFirst("$1");
1438        if (!result.equals("zzzabzzzabcczzzabccczzz"))
1439            failCount++;
1440
1441        matcher.reset("zzzabccczzzabcczzzabccczzz");
1442        result = matcher.replaceFirst("$2");
1443        if (!result.equals("zzzccczzzabcczzzabccczzz"))
1444            failCount++;
1445
1446        pattern = Pattern.compile("a*");
1447        matcher = pattern.matcher("aaaaaaaaaa");
1448        if (!matcher.replaceFirst("test").equals("test"))
1449            failCount++;
1450
1451        pattern = Pattern.compile("a+");
1452        matcher = pattern.matcher("zzzaaaaaaaaaa");
1453        if (!matcher.replaceFirst("test").equals("zzztest"))
1454            failCount++;
1455
1456        // Supplementary character test
1457        pattern = Pattern.compile(toSupplementaries("(ab)(c*)"));
1458        matcher = pattern.matcher(toSupplementaries("abccczzzabcczzzabccc"));
1459        if (!matcher.replaceFirst(toSupplementaries("test"))
1460                .equals(toSupplementaries("testzzzabcczzzabccc")))
1461            failCount++;
1462
1463        matcher.reset(toSupplementaries("zzzabccczzzabcczzzabccczzz"));
1464        if (!matcher.replaceFirst(toSupplementaries("test")).
1465            equals(toSupplementaries("zzztestzzzabcczzzabccczzz")))
1466            failCount++;
1467
1468        matcher.reset(toSupplementaries("zzzabccczzzabcczzzabccczzz"));
1469        result = matcher.replaceFirst("$1");
1470        if (!result.equals(toSupplementaries("zzzabzzzabcczzzabccczzz")))
1471            failCount++;
1472
1473        matcher.reset(toSupplementaries("zzzabccczzzabcczzzabccczzz"));
1474        result = matcher.replaceFirst("$2");
1475        if (!result.equals(toSupplementaries("zzzccczzzabcczzzabccczzz")))
1476            failCount++;
1477
1478        pattern = Pattern.compile(toSupplementaries("a*"));
1479        matcher = pattern.matcher(toSupplementaries("aaaaaaaaaa"));
1480        if (!matcher.replaceFirst(toSupplementaries("test")).equals(toSupplementaries("test")))
1481            failCount++;
1482
1483        pattern = Pattern.compile(toSupplementaries("a+"));
1484        matcher = pattern.matcher(toSupplementaries("zzzaaaaaaaaaa"));
1485        if (!matcher.replaceFirst(toSupplementaries("test")).equals(toSupplementaries("zzztest")))
1486            failCount++;
1487
1488        report("Replace First");
1489    }
1490
1491    private static void unixLinesTest() {
1492        Pattern pattern = Pattern.compile(".*");
1493        Matcher matcher = pattern.matcher("aa\u2028blah");
1494        matcher.find();
1495        if (!matcher.group(0).equals("aa"))
1496            failCount++;
1497
1498        pattern = Pattern.compile(".*", Pattern.UNIX_LINES);
1499        matcher = pattern.matcher("aa\u2028blah");
1500        matcher.find();
1501        if (!matcher.group(0).equals("aa\u2028blah"))
1502            failCount++;
1503
1504        pattern = Pattern.compile("[az]$",
1505                                  Pattern.MULTILINE | Pattern.UNIX_LINES);
1506        matcher = pattern.matcher("aa\u2028zz");
1507        check(matcher, "a\u2028", false);
1508
1509        // Supplementary character test
1510        pattern = Pattern.compile(".*");
1511        matcher = pattern.matcher(toSupplementaries("aa\u2028blah"));
1512        matcher.find();
1513        if (!matcher.group(0).equals(toSupplementaries("aa")))
1514            failCount++;
1515
1516        pattern = Pattern.compile(".*", Pattern.UNIX_LINES);
1517        matcher = pattern.matcher(toSupplementaries("aa\u2028blah"));
1518        matcher.find();
1519        if (!matcher.group(0).equals(toSupplementaries("aa\u2028blah")))
1520            failCount++;
1521
1522        pattern = Pattern.compile(toSupplementaries("[az]$"),
1523                                  Pattern.MULTILINE | Pattern.UNIX_LINES);
1524        matcher = pattern.matcher(toSupplementaries("aa\u2028zz"));
1525        check(matcher, toSupplementaries("a\u2028"), false);
1526
1527        report("Unix Lines");
1528    }
1529
1530    private static void commentsTest() {
1531        int flags = Pattern.COMMENTS;
1532
1533        Pattern pattern = Pattern.compile("aa \\# aa", flags);
1534        Matcher matcher = pattern.matcher("aa#aa");
1535        if (!matcher.matches())
1536            failCount++;
1537
1538        pattern = Pattern.compile("aa  # blah", flags);
1539        matcher = pattern.matcher("aa");
1540        if (!matcher.matches())
1541            failCount++;
1542
1543        pattern = Pattern.compile("aa blah", flags);
1544        matcher = pattern.matcher("aablah");
1545        if (!matcher.matches())
1546             failCount++;
1547
1548        pattern = Pattern.compile("aa  # blah blech  ", flags);
1549        matcher = pattern.matcher("aa");
1550        if (!matcher.matches())
1551            failCount++;
1552
1553        pattern = Pattern.compile("aa  # blah\n  ", flags);
1554        matcher = pattern.matcher("aa");
1555        if (!matcher.matches())
1556            failCount++;
1557
1558        pattern = Pattern.compile("aa  # blah\nbc # blech", flags);
1559        matcher = pattern.matcher("aabc");
1560        if (!matcher.matches())
1561             failCount++;
1562
1563        pattern = Pattern.compile("aa  # blah\nbc# blech", flags);
1564        matcher = pattern.matcher("aabc");
1565        if (!matcher.matches())
1566             failCount++;
1567
1568        pattern = Pattern.compile("aa  # blah\nbc\\# blech", flags);
1569        matcher = pattern.matcher("aabc#blech");
1570        if (!matcher.matches())
1571             failCount++;
1572
1573        // Supplementary character test
1574        pattern = Pattern.compile(toSupplementaries("aa \\# aa"), flags);
1575        matcher = pattern.matcher(toSupplementaries("aa#aa"));
1576        if (!matcher.matches())
1577            failCount++;
1578
1579        pattern = Pattern.compile(toSupplementaries("aa  # blah"), flags);
1580        matcher = pattern.matcher(toSupplementaries("aa"));
1581        if (!matcher.matches())
1582            failCount++;
1583
1584        pattern = Pattern.compile(toSupplementaries("aa blah"), flags);
1585        matcher = pattern.matcher(toSupplementaries("aablah"));
1586        if (!matcher.matches())
1587             failCount++;
1588
1589        pattern = Pattern.compile(toSupplementaries("aa  # blah blech  "), flags);
1590        matcher = pattern.matcher(toSupplementaries("aa"));
1591        if (!matcher.matches())
1592            failCount++;
1593
1594        pattern = Pattern.compile(toSupplementaries("aa  # blah\n  "), flags);
1595        matcher = pattern.matcher(toSupplementaries("aa"));
1596        if (!matcher.matches())
1597            failCount++;
1598
1599        pattern = Pattern.compile(toSupplementaries("aa  # blah\nbc # blech"), flags);
1600        matcher = pattern.matcher(toSupplementaries("aabc"));
1601        if (!matcher.matches())
1602             failCount++;
1603
1604        pattern = Pattern.compile(toSupplementaries("aa  # blah\nbc# blech"), flags);
1605        matcher = pattern.matcher(toSupplementaries("aabc"));
1606        if (!matcher.matches())
1607             failCount++;
1608
1609        pattern = Pattern.compile(toSupplementaries("aa  # blah\nbc\\# blech"), flags);
1610        matcher = pattern.matcher(toSupplementaries("aabc#blech"));
1611        if (!matcher.matches())
1612             failCount++;
1613
1614        report("Comments");
1615    }
1616
1617    private static void caseFoldingTest() { // bug 4504687
1618        int flags = Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE;
1619        Pattern pattern = Pattern.compile("aa", flags);
1620        Matcher matcher = pattern.matcher("ab");
1621        if (matcher.matches())
1622            failCount++;
1623
1624        pattern = Pattern.compile("aA", flags);
1625        matcher = pattern.matcher("ab");
1626        if (matcher.matches())
1627            failCount++;
1628
1629        pattern = Pattern.compile("aa", flags);
1630        matcher = pattern.matcher("aB");
1631        if (matcher.matches())
1632            failCount++;
1633        matcher = pattern.matcher("Ab");
1634        if (matcher.matches())
1635            failCount++;
1636
1637        // ASCII               "a"
1638        // Latin-1 Supplement  "a" + grave
1639        // Cyrillic            "a"
1640        String[] patterns = new String[] {
1641            //single
1642            "a", "\u00e0", "\u0430",
1643            //slice
1644            "ab", "\u00e0\u00e1", "\u0430\u0431",
1645            //class single
1646            "[a]", "[\u00e0]", "[\u0430]",
1647            //class range
1648            "[a-b]", "[\u00e0-\u00e5]", "[\u0430-\u0431]",
1649            //back reference
1650            "(a)\\1", "(\u00e0)\\1", "(\u0430)\\1"
1651        };
1652
1653        String[] texts = new String[] {
1654            "A", "\u00c0", "\u0410",
1655            "AB", "\u00c0\u00c1", "\u0410\u0411",
1656            "A", "\u00c0", "\u0410",
1657            "B", "\u00c2", "\u0411",
1658            "aA", "\u00e0\u00c0", "\u0430\u0410"
1659        };
1660
1661        boolean[] expected = new boolean[] {
1662            true, false, false,
1663            true, false, false,
1664            true, false, false,
1665            true, false, false,
1666            true, false, false
1667        };
1668
1669        flags = Pattern.CASE_INSENSITIVE;
1670        for (int i = 0; i < patterns.length; i++) {
1671            pattern = Pattern.compile(patterns[i], flags);
1672            matcher = pattern.matcher(texts[i]);
1673            if (matcher.matches() != expected[i]) {
1674                System.out.println("<1> Failed at " + i);
1675                failCount++;
1676            }
1677        }
1678
1679        flags = Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE;
1680        for (int i = 0; i < patterns.length; i++) {
1681            pattern = Pattern.compile(patterns[i], flags);
1682            matcher = pattern.matcher(texts[i]);
1683            if (!matcher.matches()) {
1684                System.out.println("<2> Failed at " + i);
1685                failCount++;
1686            }
1687        }
1688        // flag unicode_case alone should do nothing
1689        flags = Pattern.UNICODE_CASE;
1690        for (int i = 0; i < patterns.length; i++) {
1691            pattern = Pattern.compile(patterns[i], flags);
1692            matcher = pattern.matcher(texts[i]);
1693            if (matcher.matches()) {
1694                System.out.println("<3> Failed at " + i);
1695                failCount++;
1696            }
1697        }
1698
1699        // Special cases: i, I, u+0131 and u+0130
1700        flags = Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE;
1701        pattern = Pattern.compile("[h-j]+", flags);
1702        if (!pattern.matcher("\u0131\u0130").matches())
1703            failCount++;
1704        report("Case Folding");
1705    }
1706
1707    private static void appendTest() {
1708        Pattern pattern = Pattern.compile("(ab)(cd)");
1709        Matcher matcher = pattern.matcher("abcd");
1710        String result = matcher.replaceAll("$2$1");
1711        if (!result.equals("cdab"))
1712            failCount++;
1713
1714        String  s1 = "Swap all: first = 123, second = 456";
1715        String  s2 = "Swap one: first = 123, second = 456";
1716        String  r  = "$3$2$1";
1717        pattern = Pattern.compile("([a-z]+)( *= *)([0-9]+)");
1718        matcher = pattern.matcher(s1);
1719
1720        result = matcher.replaceAll(r);
1721        if (!result.equals("Swap all: 123 = first, 456 = second"))
1722            failCount++;
1723
1724        matcher = pattern.matcher(s2);
1725
1726        if (matcher.find()) {
1727            StringBuffer sb = new StringBuffer();
1728            matcher.appendReplacement(sb, r);
1729            matcher.appendTail(sb);
1730            result = sb.toString();
1731            if (!result.equals("Swap one: 123 = first, second = 456"))
1732                failCount++;
1733        }
1734
1735        // Supplementary character test
1736        pattern = Pattern.compile(toSupplementaries("(ab)(cd)"));
1737        matcher = pattern.matcher(toSupplementaries("abcd"));
1738        result = matcher.replaceAll("$2$1");
1739        if (!result.equals(toSupplementaries("cdab")))
1740            failCount++;
1741
1742        s1 = toSupplementaries("Swap all: first = 123, second = 456");
1743        s2 = toSupplementaries("Swap one: first = 123, second = 456");
1744        r  = toSupplementaries("$3$2$1");
1745        pattern = Pattern.compile(toSupplementaries("([a-z]+)( *= *)([0-9]+)"));
1746        matcher = pattern.matcher(s1);
1747
1748        result = matcher.replaceAll(r);
1749        if (!result.equals(toSupplementaries("Swap all: 123 = first, 456 = second")))
1750            failCount++;
1751
1752        matcher = pattern.matcher(s2);
1753
1754        if (matcher.find()) {
1755            StringBuffer sb = new StringBuffer();
1756            matcher.appendReplacement(sb, r);
1757            matcher.appendTail(sb);
1758            result = sb.toString();
1759            if (!result.equals(toSupplementaries("Swap one: 123 = first, second = 456")))
1760                failCount++;
1761        }
1762        report("Append");
1763    }
1764
1765    private static void splitTest() {
1766        Pattern pattern = Pattern.compile(":");
1767        String[] result = pattern.split("foo:and:boo", 2);
1768        if (!result[0].equals("foo"))
1769            failCount++;
1770        if (!result[1].equals("and:boo"))
1771            failCount++;
1772        // Supplementary character test
1773        Pattern patternX = Pattern.compile(toSupplementaries("X"));
1774        result = patternX.split(toSupplementaries("fooXandXboo"), 2);
1775        if (!result[0].equals(toSupplementaries("foo")))
1776            failCount++;
1777        if (!result[1].equals(toSupplementaries("andXboo")))
1778            failCount++;
1779
1780        CharBuffer cb = CharBuffer.allocate(100);
1781        cb.put("foo:and:boo");
1782        cb.flip();
1783        result = pattern.split(cb);
1784        if (!result[0].equals("foo"))
1785            failCount++;
1786        if (!result[1].equals("and"))
1787            failCount++;
1788        if (!result[2].equals("boo"))
1789            failCount++;
1790
1791        // Supplementary character test
1792        CharBuffer cbs = CharBuffer.allocate(100);
1793        cbs.put(toSupplementaries("fooXandXboo"));
1794        cbs.flip();
1795        result = patternX.split(cbs);
1796        if (!result[0].equals(toSupplementaries("foo")))
1797            failCount++;
1798        if (!result[1].equals(toSupplementaries("and")))
1799            failCount++;
1800        if (!result[2].equals(toSupplementaries("boo")))
1801            failCount++;
1802
1803        String source = "0123456789";
1804        for (int limit=-2; limit<3; limit++) {
1805            for (int x=0; x<10; x++) {
1806                result = source.split(Integer.toString(x), limit);
1807                int expectedLength = limit < 1 ? 2 : limit;
1808
1809                if ((limit == 0) && (x == 9)) {
1810                    // expected dropping of ""
1811                    if (result.length != 1)
1812                        failCount++;
1813                    if (!result[0].equals("012345678")) {
1814                        failCount++;
1815                    }
1816                } else {
1817                    if (result.length != expectedLength) {
1818                        failCount++;
1819                    }
1820                    if (!result[0].equals(source.substring(0,x))) {
1821                        if (limit != 1) {
1822                            failCount++;
1823                        } else {
1824                            if (!result[0].equals(source.substring(0,10))) {
1825                                failCount++;
1826                            }
1827                        }
1828                    }
1829                    if (expectedLength > 1) { // Check segment 2
1830                        if (!result[1].equals(source.substring(x+1,10)))
1831                            failCount++;
1832                    }
1833                }
1834            }
1835        }
1836        // Check the case for no match found
1837        for (int limit=-2; limit<3; limit++) {
1838            result = source.split("e", limit);
1839            if (result.length != 1)
1840                failCount++;
1841            if (!result[0].equals(source))
1842                failCount++;
1843        }
1844        // Check the case for limit == 0, source = "";
1845        // split() now returns 0-length for empty source "" see #6559590
1846        source = "";
1847        result = source.split("e", 0);
1848        if (result.length != 1)
1849            failCount++;
1850        if (!result[0].equals(source))
1851            failCount++;
1852
1853        // Check both split() and splitAsStraem(), especially for zero-lenth
1854        // input and zero-lenth match cases
1855        String[][] input = new String[][] {
1856            { " ",           "Abc Efg Hij" },   // normal non-zero-match
1857            { " ",           " Abc Efg Hij" },  // leading empty str for non-zero-match
1858            { " ",           "Abc  Efg Hij" },  // non-zero-match in the middle
1859            { "(?=\\p{Lu})", "AbcEfgHij" },     // no leading empty str for zero-match
1860            { "(?=\\p{Lu})", "AbcEfg" },
1861            { "(?=\\p{Lu})", "Abc" },
1862            { " ",           "" },              // zero-length input
1863            { ".*",          "" },
1864
1865            // some tests from PatternStreamTest.java
1866            { "4",       "awgqwefg1fefw4vssv1vvv1" },
1867            { "\u00a3a", "afbfq\u00a3abgwgb\u00a3awngnwggw\u00a3a\u00a3ahjrnhneerh" },
1868            { "1",       "awgqwefg1fefw4vssv1vvv1" },
1869            { "1",       "a\u4ebafg1fefw\u4eba4\u9f9cvssv\u9f9c1v\u672c\u672cvv" },
1870            { "\u56da",  "1\u56da23\u56da456\u56da7890" },
1871            { "\u56da",  "1\u56da23\u9f9c\u672c\u672c\u56da456\u56da\u9f9c\u672c7890" },
1872            { "\u56da",  "" },
1873            { "[ \t,:.]","This is,testing: with\tdifferent separators." }, //multiple septs
1874            { "o",       "boo:and:foo" },
1875            { "o",       "booooo:and:fooooo" },
1876            { "o",       "fooooo:" },
1877        };
1878
1879        String[][] expected = new String[][] {
1880            { "Abc", "Efg", "Hij" },
1881            { "", "Abc", "Efg", "Hij" },
1882            { "Abc", "", "Efg", "Hij" },
1883            { "Abc", "Efg", "Hij" },
1884            { "Abc", "Efg" },
1885            { "Abc" },
1886            { "" },
1887            { "" },
1888
1889            { "awgqwefg1fefw", "vssv1vvv1" },
1890            { "afbfq", "bgwgb", "wngnwggw", "", "hjrnhneerh" },
1891            { "awgqwefg", "fefw4vssv", "vvv" },
1892            { "a\u4ebafg", "fefw\u4eba4\u9f9cvssv\u9f9c", "v\u672c\u672cvv" },
1893            { "1", "23", "456", "7890" },
1894            { "1", "23\u9f9c\u672c\u672c", "456", "\u9f9c\u672c7890" },
1895            { "" },
1896            { "This", "is", "testing", "", "with", "different", "separators" },
1897            { "b", "", ":and:f" },
1898            { "b", "", "", "", "", ":and:f" },
1899            { "f", "", "", "", "", ":" },
1900        };
1901        for (int i = 0; i < input.length; i++) {
1902            pattern = Pattern.compile(input[i][0]);
1903            if (!Arrays.equals(pattern.split(input[i][1]), expected[i])) {
1904                failCount++;
1905            }
1906            if (input[i][1].length() > 0 &&  // splitAsStream() return empty resulting
1907                                             // array for zero-length input for now
1908                !Arrays.equals(pattern.splitAsStream(input[i][1]).toArray(),
1909                               expected[i])) {
1910                failCount++;
1911            }
1912        }
1913        report("Split");
1914    }
1915
1916    private static void negationTest() {
1917        Pattern pattern = Pattern.compile("[\\[@^]+");
1918        Matcher matcher = pattern.matcher("@@@@[[[[^^^^");
1919        if (!matcher.find())
1920            failCount++;
1921        if (!matcher.group(0).equals("@@@@[[[[^^^^"))
1922            failCount++;
1923        pattern = Pattern.compile("[@\\[^]+");
1924        matcher = pattern.matcher("@@@@[[[[^^^^");
1925        if (!matcher.find())
1926            failCount++;
1927        if (!matcher.group(0).equals("@@@@[[[[^^^^"))
1928            failCount++;
1929        pattern = Pattern.compile("[@\\[^@]+");
1930        matcher = pattern.matcher("@@@@[[[[^^^^");
1931        if (!matcher.find())
1932            failCount++;
1933        if (!matcher.group(0).equals("@@@@[[[[^^^^"))
1934            failCount++;
1935
1936        pattern = Pattern.compile("\\)");
1937        matcher = pattern.matcher("xxx)xxx");
1938        if (!matcher.find())
1939            failCount++;
1940
1941        report("Negation");
1942    }
1943
1944    private static void ampersandTest() {
1945        Pattern pattern = Pattern.compile("[&@]+");
1946        check(pattern, "@@@@&&&&", true);
1947
1948        pattern = Pattern.compile("[@&]+");
1949        check(pattern, "@@@@&&&&", true);
1950
1951        pattern = Pattern.compile("[@\\&]+");
1952        check(pattern, "@@@@&&&&", true);
1953
1954        report("Ampersand");
1955    }
1956
1957    private static void octalTest() throws Exception {
1958        Pattern pattern = Pattern.compile("\\u0007");
1959        Matcher matcher = pattern.matcher("\u0007");
1960        if (!matcher.matches())
1961            failCount++;
1962        pattern = Pattern.compile("\\07");
1963        matcher = pattern.matcher("\u0007");
1964        if (!matcher.matches())
1965            failCount++;
1966        pattern = Pattern.compile("\\007");
1967        matcher = pattern.matcher("\u0007");
1968        if (!matcher.matches())
1969            failCount++;
1970        pattern = Pattern.compile("\\0007");
1971        matcher = pattern.matcher("\u0007");
1972        if (!matcher.matches())
1973            failCount++;
1974        pattern = Pattern.compile("\\040");
1975        matcher = pattern.matcher("\u0020");
1976        if (!matcher.matches())
1977            failCount++;
1978        pattern = Pattern.compile("\\0403");
1979        matcher = pattern.matcher("\u00203");
1980        if (!matcher.matches())
1981            failCount++;
1982        pattern = Pattern.compile("\\0103");
1983        matcher = pattern.matcher("\u0043");
1984        if (!matcher.matches())
1985            failCount++;
1986
1987        report("Octal");
1988    }
1989
1990    private static void longPatternTest() throws Exception {
1991        try {
1992            Pattern pattern = Pattern.compile(
1993                "a 32-character-long pattern xxxx");
1994            pattern = Pattern.compile("a 33-character-long pattern xxxxx");
1995            pattern = Pattern.compile("a thirty four character long regex");
1996            StringBuffer patternToBe = new StringBuffer(101);
1997            for (int i=0; i<100; i++)
1998                patternToBe.append((char)(97 + i%26));
1999            pattern = Pattern.compile(patternToBe.toString());
2000        } catch (PatternSyntaxException e) {
2001            failCount++;
2002        }
2003
2004        // Supplementary character test
2005        try {
2006            Pattern pattern = Pattern.compile(
2007                toSupplementaries("a 32-character-long pattern xxxx"));
2008            pattern = Pattern.compile(toSupplementaries("a 33-character-long pattern xxxxx"));
2009            pattern = Pattern.compile(toSupplementaries("a thirty four character long regex"));
2010            StringBuffer patternToBe = new StringBuffer(101*2);
2011            for (int i=0; i<100; i++)
2012                patternToBe.append(Character.toChars(Character.MIN_SUPPLEMENTARY_CODE_POINT
2013                                                     + 97 + i%26));
2014            pattern = Pattern.compile(patternToBe.toString());
2015        } catch (PatternSyntaxException e) {
2016            failCount++;
2017        }
2018        report("LongPattern");
2019    }
2020
2021    private static void group0Test() throws Exception {
2022        Pattern pattern = Pattern.compile("(tes)ting");
2023        Matcher matcher = pattern.matcher("testing");
2024        check(matcher, "testing");
2025
2026        matcher.reset("testing");
2027        if (matcher.lookingAt()) {
2028            if (!matcher.group(0).equals("testing"))
2029                failCount++;
2030        } else {
2031            failCount++;
2032        }
2033
2034        matcher.reset("testing");
2035        if (matcher.matches()) {
2036            if (!matcher.group(0).equals("testing"))
2037                failCount++;
2038        } else {
2039            failCount++;
2040        }
2041
2042        pattern = Pattern.compile("(tes)ting");
2043        matcher = pattern.matcher("testing");
2044        if (matcher.lookingAt()) {
2045            if (!matcher.group(0).equals("testing"))
2046                failCount++;
2047        } else {
2048            failCount++;
2049        }
2050
2051        pattern = Pattern.compile("^(tes)ting");
2052        matcher = pattern.matcher("testing");
2053        if (matcher.matches()) {
2054            if (!matcher.group(0).equals("testing"))
2055                failCount++;
2056        } else {
2057            failCount++;
2058        }
2059
2060        // Supplementary character test
2061        pattern = Pattern.compile(toSupplementaries("(tes)ting"));
2062        matcher = pattern.matcher(toSupplementaries("testing"));
2063        check(matcher, toSupplementaries("testing"));
2064
2065        matcher.reset(toSupplementaries("testing"));
2066        if (matcher.lookingAt()) {
2067            if (!matcher.group(0).equals(toSupplementaries("testing")))
2068                failCount++;
2069        } else {
2070            failCount++;
2071        }
2072
2073        matcher.reset(toSupplementaries("testing"));
2074        if (matcher.matches()) {
2075            if (!matcher.group(0).equals(toSupplementaries("testing")))
2076                failCount++;
2077        } else {
2078            failCount++;
2079        }
2080
2081        pattern = Pattern.compile(toSupplementaries("(tes)ting"));
2082        matcher = pattern.matcher(toSupplementaries("testing"));
2083        if (matcher.lookingAt()) {
2084            if (!matcher.group(0).equals(toSupplementaries("testing")))
2085                failCount++;
2086        } else {
2087            failCount++;
2088        }
2089
2090        pattern = Pattern.compile(toSupplementaries("^(tes)ting"));
2091        matcher = pattern.matcher(toSupplementaries("testing"));
2092        if (matcher.matches()) {
2093            if (!matcher.group(0).equals(toSupplementaries("testing")))
2094                failCount++;
2095        } else {
2096            failCount++;
2097        }
2098
2099        report("Group0");
2100    }
2101
2102    private static void findIntTest() throws Exception {
2103        Pattern p = Pattern.compile("blah");
2104        Matcher m = p.matcher("zzzzblahzzzzzblah");
2105        boolean result = m.find(2);
2106        if (!result)
2107            failCount++;
2108
2109        p = Pattern.compile("$");
2110        m = p.matcher("1234567890");
2111        result = m.find(10);
2112        if (!result)
2113            failCount++;
2114        try {
2115            result = m.find(11);
2116            failCount++;
2117        } catch (IndexOutOfBoundsException e) {
2118            // correct result
2119        }
2120
2121        // Supplementary character test
2122        p = Pattern.compile(toSupplementaries("blah"));
2123        m = p.matcher(toSupplementaries("zzzzblahzzzzzblah"));
2124        result = m.find(2);
2125        if (!result)
2126            failCount++;
2127
2128        report("FindInt");
2129    }
2130
2131    private static void emptyPatternTest() throws Exception {
2132        Pattern p = Pattern.compile("");
2133        Matcher m = p.matcher("foo");
2134
2135        // Should find empty pattern at beginning of input
2136        boolean result = m.find();
2137        if (result != true)
2138            failCount++;
2139        if (m.start() != 0)
2140            failCount++;
2141
2142        // Should not match entire input if input is not empty
2143        m.reset();
2144        result = m.matches();
2145        if (result == true)
2146            failCount++;
2147
2148        try {
2149            m.start(0);
2150            failCount++;
2151        } catch (IllegalStateException e) {
2152            // Correct result
2153        }
2154
2155        // Should match entire input if input is empty
2156        m.reset("");
2157        result = m.matches();
2158        if (result != true)
2159            failCount++;
2160
2161        result = Pattern.matches("", "");
2162        if (result != true)
2163            failCount++;
2164
2165        result = Pattern.matches("", "foo");
2166        if (result == true)
2167            failCount++;
2168        report("EmptyPattern");
2169    }
2170
2171    private static void charClassTest() throws Exception {
2172        Pattern pattern = Pattern.compile("blah[ab]]blech");
2173        check(pattern, "blahb]blech", true);
2174
2175        pattern = Pattern.compile("[abc[def]]");
2176        check(pattern, "b", true);
2177
2178        // Supplementary character tests
2179        pattern = Pattern.compile(toSupplementaries("blah[ab]]blech"));
2180        check(pattern, toSupplementaries("blahb]blech"), true);
2181
2182        pattern = Pattern.compile(toSupplementaries("[abc[def]]"));
2183        check(pattern, toSupplementaries("b"), true);
2184
2185        try {
2186            // u00ff when UNICODE_CASE
2187            pattern = Pattern.compile("[ab\u00ffcd]",
2188                                      Pattern.CASE_INSENSITIVE|
2189                                      Pattern.UNICODE_CASE);
2190            check(pattern, "ab\u00ffcd", true);
2191            check(pattern, "Ab\u0178Cd", true);
2192
2193            // u00b5 when UNICODE_CASE
2194            pattern = Pattern.compile("[ab\u00b5cd]",
2195                                      Pattern.CASE_INSENSITIVE|
2196                                      Pattern.UNICODE_CASE);
2197            check(pattern, "ab\u00b5cd", true);
2198            check(pattern, "Ab\u039cCd", true);
2199        } catch (Exception e) { failCount++; }
2200
2201        /* Special cases
2202           (1)LatinSmallLetterLongS u+017f
2203           (2)LatinSmallLetterDotlessI u+0131
2204           (3)LatineCapitalLetterIWithDotAbove u+0130
2205           (4)KelvinSign u+212a
2206           (5)AngstromSign u+212b
2207        */
2208        int flags = Pattern.UNICODE_CASE | Pattern.CASE_INSENSITIVE;
2209        pattern = Pattern.compile("[sik\u00c5]+", flags);
2210        if (!pattern.matcher("\u017f\u0130\u0131\u212a\u212b").matches())
2211            failCount++;
2212
2213        report("CharClass");
2214    }
2215
2216    private static void caretTest() throws Exception {
2217        Pattern pattern = Pattern.compile("\\w*");
2218        Matcher matcher = pattern.matcher("a#bc#def##g");
2219        check(matcher, "a");
2220        check(matcher, "");
2221        check(matcher, "bc");
2222        check(matcher, "");
2223        check(matcher, "def");
2224        check(matcher, "");
2225        check(matcher, "");
2226        check(matcher, "g");
2227        check(matcher, "");
2228        if (matcher.find())
2229            failCount++;
2230
2231        pattern = Pattern.compile("^\\w*");
2232        matcher = pattern.matcher("a#bc#def##g");
2233        check(matcher, "a");
2234        if (matcher.find())
2235            failCount++;
2236
2237        pattern = Pattern.compile("\\w");
2238        matcher = pattern.matcher("abc##x");
2239        check(matcher, "a");
2240        check(matcher, "b");
2241        check(matcher, "c");
2242        check(matcher, "x");
2243        if (matcher.find())
2244            failCount++;
2245
2246        pattern = Pattern.compile("^\\w");
2247        matcher = pattern.matcher("abc##x");
2248        check(matcher, "a");
2249        if (matcher.find())
2250            failCount++;
2251
2252        pattern = Pattern.compile("\\A\\p{Alpha}{3}");
2253        matcher = pattern.matcher("abcdef-ghi\njklmno");
2254        check(matcher, "abc");
2255        if (matcher.find())
2256            failCount++;
2257
2258        pattern = Pattern.compile("^\\p{Alpha}{3}", Pattern.MULTILINE);
2259        matcher = pattern.matcher("abcdef-ghi\njklmno");
2260        check(matcher, "abc");
2261        check(matcher, "jkl");
2262        if (matcher.find())
2263            failCount++;
2264
2265        pattern = Pattern.compile("^", Pattern.MULTILINE);
2266        matcher = pattern.matcher("this is some text");
2267        String result = matcher.replaceAll("X");
2268        if (!result.equals("Xthis is some text"))
2269            failCount++;
2270
2271        pattern = Pattern.compile("^");
2272        matcher = pattern.matcher("this is some text");
2273        result = matcher.replaceAll("X");
2274        if (!result.equals("Xthis is some text"))
2275            failCount++;
2276
2277        pattern = Pattern.compile("^", Pattern.MULTILINE | Pattern.UNIX_LINES);
2278        matcher = pattern.matcher("this is some text\n");
2279        result = matcher.replaceAll("X");
2280        if (!result.equals("Xthis is some text\n"))
2281            failCount++;
2282
2283        report("Caret");
2284    }
2285
2286    private static void groupCaptureTest() throws Exception {
2287        // Independent group
2288        Pattern pattern = Pattern.compile("x+(?>y+)z+");
2289        Matcher matcher = pattern.matcher("xxxyyyzzz");
2290        matcher.find();
2291        try {
2292            String blah = matcher.group(1);
2293            failCount++;
2294        } catch (IndexOutOfBoundsException ioobe) {
2295            // Good result
2296        }
2297        // Pure group
2298        pattern = Pattern.compile("x+(?:y+)z+");
2299        matcher = pattern.matcher("xxxyyyzzz");
2300        matcher.find();
2301        try {
2302            String blah = matcher.group(1);
2303            failCount++;
2304        } catch (IndexOutOfBoundsException ioobe) {
2305            // Good result
2306        }
2307
2308        // Supplementary character tests
2309        // Independent group
2310        pattern = Pattern.compile(toSupplementaries("x+(?>y+)z+"));
2311        matcher = pattern.matcher(toSupplementaries("xxxyyyzzz"));
2312        matcher.find();
2313        try {
2314            String blah = matcher.group(1);
2315            failCount++;
2316        } catch (IndexOutOfBoundsException ioobe) {
2317            // Good result
2318        }
2319        // Pure group
2320        pattern = Pattern.compile(toSupplementaries("x+(?:y+)z+"));
2321        matcher = pattern.matcher(toSupplementaries("xxxyyyzzz"));
2322        matcher.find();
2323        try {
2324            String blah = matcher.group(1);
2325            failCount++;
2326        } catch (IndexOutOfBoundsException ioobe) {
2327            // Good result
2328        }
2329
2330        report("GroupCapture");
2331    }
2332
2333    private static void backRefTest() throws Exception {
2334        Pattern pattern = Pattern.compile("(a*)bc\\1");
2335        check(pattern, "zzzaabcazzz", true);
2336
2337        pattern = Pattern.compile("(a*)bc\\1");
2338        check(pattern, "zzzaabcaazzz", true);
2339
2340        pattern = Pattern.compile("(abc)(def)\\1");
2341        check(pattern, "abcdefabc", true);
2342
2343        pattern = Pattern.compile("(abc)(def)\\3");
2344        check(pattern, "abcdefabc", false);
2345
2346        try {
2347            for (int i = 1; i < 10; i++) {
2348                // Make sure backref 1-9 are always accepted
2349                pattern = Pattern.compile("abcdef\\" + i);
2350                // and fail to match if the target group does not exit
2351                check(pattern, "abcdef", false);
2352            }
2353        } catch(PatternSyntaxException e) {
2354            failCount++;
2355        }
2356
2357        pattern = Pattern.compile("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)\\11");
2358        check(pattern, "abcdefghija", false);
2359        check(pattern, "abcdefghija1", true);
2360
2361        pattern = Pattern.compile("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\11");
2362        check(pattern, "abcdefghijkk", true);
2363
2364        pattern = Pattern.compile("(a)bcdefghij\\11");
2365        check(pattern, "abcdefghija1", true);
2366
2367        // Supplementary character tests
2368        pattern = Pattern.compile(toSupplementaries("(a*)bc\\1"));
2369        check(pattern, toSupplementaries("zzzaabcazzz"), true);
2370
2371        pattern = Pattern.compile(toSupplementaries("(a*)bc\\1"));
2372        check(pattern, toSupplementaries("zzzaabcaazzz"), true);
2373
2374        pattern = Pattern.compile(toSupplementaries("(abc)(def)\\1"));
2375        check(pattern, toSupplementaries("abcdefabc"), true);
2376
2377        pattern = Pattern.compile(toSupplementaries("(abc)(def)\\3"));
2378        check(pattern, toSupplementaries("abcdefabc"), false);
2379
2380        pattern = Pattern.compile(toSupplementaries("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)\\11"));
2381        check(pattern, toSupplementaries("abcdefghija"), false);
2382        check(pattern, toSupplementaries("abcdefghija1"), true);
2383
2384        pattern = Pattern.compile(toSupplementaries("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(k)\\11"));
2385        check(pattern, toSupplementaries("abcdefghijkk"), true);
2386
2387        report("BackRef");
2388    }
2389
2390    /**
2391     * Unicode Technical Report #18, section 2.6 End of Line
2392     * There is no empty line to be matched in the sequence \u000D\u000A
2393     * but there is an empty line in the sequence \u000A\u000D.
2394     */
2395    private static void anchorTest() throws Exception {
2396        Pattern p = Pattern.compile("^.*$", Pattern.MULTILINE);
2397        Matcher m = p.matcher("blah1\r\nblah2");
2398        m.find();
2399        m.find();
2400        if (!m.group().equals("blah2"))
2401            failCount++;
2402
2403        m.reset("blah1\n\rblah2");
2404        m.find();
2405        m.find();
2406        m.find();
2407        if (!m.group().equals("blah2"))
2408            failCount++;
2409
2410        // Test behavior of $ with \r\n at end of input
2411        p = Pattern.compile(".+$");
2412        m = p.matcher("blah1\r\n");
2413        if (!m.find())
2414            failCount++;
2415       if (!m.group().equals("blah1"))
2416            failCount++;
2417        if (m.find())
2418            failCount++;
2419
2420        // Test behavior of $ with \r\n at end of input in multiline
2421        p = Pattern.compile(".+$", Pattern.MULTILINE);
2422        m = p.matcher("blah1\r\n");
2423        if (!m.find())
2424            failCount++;
2425        if (m.find())
2426            failCount++;
2427
2428        // Test for $ recognition of \u0085 for bug 4527731
2429        p = Pattern.compile(".+$", Pattern.MULTILINE);
2430        m = p.matcher("blah1\u0085");
2431        if (!m.find())
2432            failCount++;
2433
2434        // Supplementary character test
2435        p = Pattern.compile("^.*$", Pattern.MULTILINE);
2436        m = p.matcher(toSupplementaries("blah1\r\nblah2"));
2437        m.find();
2438        m.find();
2439        if (!m.group().equals(toSupplementaries("blah2")))
2440            failCount++;
2441
2442        m.reset(toSupplementaries("blah1\n\rblah2"));
2443        m.find();
2444        m.find();
2445        m.find();
2446        if (!m.group().equals(toSupplementaries("blah2")))
2447            failCount++;
2448
2449        // Test behavior of $ with \r\n at end of input
2450        p = Pattern.compile(".+$");
2451        m = p.matcher(toSupplementaries("blah1\r\n"));
2452        if (!m.find())
2453            failCount++;
2454        if (!m.group().equals(toSupplementaries("blah1")))
2455            failCount++;
2456        if (m.find())
2457            failCount++;
2458
2459        // Test behavior of $ with \r\n at end of input in multiline
2460        p = Pattern.compile(".+$", Pattern.MULTILINE);
2461        m = p.matcher(toSupplementaries("blah1\r\n"));
2462        if (!m.find())
2463            failCount++;
2464        if (m.find())
2465            failCount++;
2466
2467        // Test for $ recognition of \u0085 for bug 4527731
2468        p = Pattern.compile(".+$", Pattern.MULTILINE);
2469        m = p.matcher(toSupplementaries("blah1\u0085"));
2470        if (!m.find())
2471            failCount++;
2472
2473        report("Anchors");
2474    }
2475
2476    /**
2477     * A basic sanity test of Matcher.lookingAt().
2478     */
2479    private static void lookingAtTest() throws Exception {
2480        Pattern p = Pattern.compile("(ab)(c*)");
2481        Matcher m = p.matcher("abccczzzabcczzzabccc");
2482
2483        if (!m.lookingAt())
2484            failCount++;
2485
2486        if (!m.group().equals(m.group(0)))
2487            failCount++;
2488
2489        m = p.matcher("zzzabccczzzabcczzzabccczzz");
2490        if (m.lookingAt())
2491            failCount++;
2492
2493        // Supplementary character test
2494        p = Pattern.compile(toSupplementaries("(ab)(c*)"));
2495        m = p.matcher(toSupplementaries("abccczzzabcczzzabccc"));
2496
2497        if (!m.lookingAt())
2498            failCount++;
2499
2500        if (!m.group().equals(m.group(0)))
2501            failCount++;
2502
2503        m = p.matcher(toSupplementaries("zzzabccczzzabcczzzabccczzz"));
2504        if (m.lookingAt())
2505            failCount++;
2506
2507        report("Looking At");
2508    }
2509
2510    /**
2511     * A basic sanity test of Matcher.matches().
2512     */
2513    private static void matchesTest() throws Exception {
2514        // matches()
2515        Pattern p = Pattern.compile("ulb(c*)");
2516        Matcher m = p.matcher("ulbcccccc");
2517        if (!m.matches())
2518            failCount++;
2519
2520        // find() but not matches()
2521        m.reset("zzzulbcccccc");
2522        if (m.matches())
2523            failCount++;
2524
2525        // lookingAt() but not matches()
2526        m.reset("ulbccccccdef");
2527        if (m.matches())
2528            failCount++;
2529
2530        // matches()
2531        p = Pattern.compile("a|ad");
2532        m = p.matcher("ad");
2533        if (!m.matches())
2534            failCount++;
2535
2536        // Supplementary character test
2537        // matches()
2538        p = Pattern.compile(toSupplementaries("ulb(c*)"));
2539        m = p.matcher(toSupplementaries("ulbcccccc"));
2540        if (!m.matches())
2541            failCount++;
2542
2543        // find() but not matches()
2544        m.reset(toSupplementaries("zzzulbcccccc"));
2545        if (m.matches())
2546            failCount++;
2547
2548        // lookingAt() but not matches()
2549        m.reset(toSupplementaries("ulbccccccdef"));
2550        if (m.matches())
2551            failCount++;
2552
2553        // matches()
2554        p = Pattern.compile(toSupplementaries("a|ad"));
2555        m = p.matcher(toSupplementaries("ad"));
2556        if (!m.matches())
2557            failCount++;
2558
2559        report("Matches");
2560    }
2561
2562    /**
2563     * A basic sanity test of Pattern.matches().
2564     */
2565    private static void patternMatchesTest() throws Exception {
2566        // matches()
2567        if (!Pattern.matches(toSupplementaries("ulb(c*)"),
2568                             toSupplementaries("ulbcccccc")))
2569            failCount++;
2570
2571        // find() but not matches()
2572        if (Pattern.matches(toSupplementaries("ulb(c*)"),
2573                            toSupplementaries("zzzulbcccccc")))
2574            failCount++;
2575
2576        // lookingAt() but not matches()
2577        if (Pattern.matches(toSupplementaries("ulb(c*)"),
2578                            toSupplementaries("ulbccccccdef")))
2579            failCount++;
2580
2581        // Supplementary character test
2582        // matches()
2583        if (!Pattern.matches(toSupplementaries("ulb(c*)"),
2584                             toSupplementaries("ulbcccccc")))
2585            failCount++;
2586
2587        // find() but not matches()
2588        if (Pattern.matches(toSupplementaries("ulb(c*)"),
2589                            toSupplementaries("zzzulbcccccc")))
2590            failCount++;
2591
2592        // lookingAt() but not matches()
2593        if (Pattern.matches(toSupplementaries("ulb(c*)"),
2594                            toSupplementaries("ulbccccccdef")))
2595            failCount++;
2596
2597        report("Pattern Matches");
2598    }
2599
2600    /**
2601     * Canonical equivalence testing. Tests the ability of the engine
2602     * to match sequences that are not explicitly specified in the
2603     * pattern when they are considered equivalent by the Unicode Standard.
2604     */
2605    private static void ceTest() throws Exception {
2606        // Decomposed char outside char classes
2607        Pattern p = Pattern.compile("testa\u030a", Pattern.CANON_EQ);
2608        Matcher m = p.matcher("test\u00e5");
2609        if (!m.matches())
2610            failCount++;
2611
2612        m.reset("testa\u030a");
2613        if (!m.matches())
2614            failCount++;
2615
2616        // Composed char outside char classes
2617        p = Pattern.compile("test\u00e5", Pattern.CANON_EQ);
2618        m = p.matcher("test\u00e5");
2619        if (!m.matches())
2620            failCount++;
2621
2622        m.reset("testa\u030a");
2623        if (!m.find())
2624            failCount++;
2625
2626        // Decomposed char inside a char class
2627        p = Pattern.compile("test[abca\u030a]", Pattern.CANON_EQ);
2628        m = p.matcher("test\u00e5");
2629        if (!m.find())
2630            failCount++;
2631
2632        m.reset("testa\u030a");
2633        if (!m.find())
2634            failCount++;
2635
2636        // Composed char inside a char class
2637        p = Pattern.compile("test[abc\u00e5def\u00e0]", Pattern.CANON_EQ);
2638        m = p.matcher("test\u00e5");
2639        if (!m.find())
2640            failCount++;
2641
2642        m.reset("testa\u0300");
2643        if (!m.find())
2644            failCount++;
2645
2646        m.reset("testa\u030a");
2647        if (!m.find())
2648            failCount++;
2649
2650        // Marks that cannot legally change order and be equivalent
2651        p = Pattern.compile("testa\u0308\u0300", Pattern.CANON_EQ);
2652        check(p, "testa\u0308\u0300", true);
2653        check(p, "testa\u0300\u0308", false);
2654
2655        // Marks that can legally change order and be equivalent
2656        p = Pattern.compile("testa\u0308\u0323", Pattern.CANON_EQ);
2657        check(p, "testa\u0308\u0323", true);
2658        check(p, "testa\u0323\u0308", true);
2659
2660        // Test all equivalences of the sequence a\u0308\u0323\u0300
2661        p = Pattern.compile("testa\u0308\u0323\u0300", Pattern.CANON_EQ);
2662        check(p, "testa\u0308\u0323\u0300", true);
2663        check(p, "testa\u0323\u0308\u0300", true);
2664        check(p, "testa\u0308\u0300\u0323", true);
2665        check(p, "test\u00e4\u0323\u0300", true);
2666        check(p, "test\u00e4\u0300\u0323", true);
2667
2668        Object[][] data = new Object[][] {
2669
2670        // JDK-4867170
2671        { "[\u1f80-\u1f82]", "ab\u1f80cd",             "f", true },
2672        { "[\u1f80-\u1f82]", "ab\u1f81cd",             "f", true },
2673        { "[\u1f80-\u1f82]", "ab\u1f82cd",             "f", true },
2674        { "[\u1f80-\u1f82]", "ab\u03b1\u0314\u0345cd", "f", true },
2675        { "[\u1f80-\u1f82]", "ab\u03b1\u0345\u0314cd", "f", true },
2676        { "[\u1f80-\u1f82]", "ab\u1f01\u0345cd",       "f", true },
2677        { "[\u1f80-\u1f82]", "ab\u1f00\u0345cd",       "f", true },
2678
2679        { "\\p{IsGreek}",    "ab\u1f80cd",             "f", true },
2680        { "\\p{IsGreek}",    "ab\u1f81cd",             "f", true },
2681        { "\\p{IsGreek}",    "ab\u1f82cd",             "f", true },
2682        { "\\p{IsGreek}",    "ab\u03b1\u0314\u0345cd", "f", true },
2683        { "\\p{IsGreek}",    "ab\u1f01\u0345cd",       "f", true },
2684
2685        // backtracking, force to match "\u1f80", instead of \u1f82"
2686        { "ab\\p{IsGreek}\u0300cd", "ab\u03b1\u0313\u0345\u0300cd", "m", true },
2687
2688        { "[\\p{IsGreek}]",  "\u03b1\u0314\u0345",     "m", true },
2689        { "\\p{IsGreek}",    "\u03b1\u0314\u0345",     "m", true },
2690
2691        { "[^\u1f80-\u1f82]","\u1f81",                 "m", false },
2692        { "[^\u1f80-\u1f82]","\u03b1\u0314\u0345",     "m", false },
2693        { "[^\u1f01\u0345]", "\u1f81",                 "f", false },
2694
2695        { "[^\u1f81]+",      "\u1f80\u1f82",           "f", true },
2696        { "[\u1f80]",        "ab\u1f80cd",             "f", true },
2697        { "\u1f80",          "ab\u1f80cd",             "f", true },
2698        { "\u1f00\u0345\u0300",  "\u1f82", "m", true },
2699        { "\u1f80",          "-\u1f00\u0345\u0300-",   "f", true },
2700        { "\u1f82",          "\u1f00\u0345\u0300",     "m", true },
2701        { "\u1f82",          "\u1f80\u0300",           "m", true },
2702
2703        // JDK-7080302       # compile failed
2704        { "a(\u0041\u0301\u0328)", "a\u0041\u0301\u0328", "m", true},
2705
2706        // JDK-6728861, same cause as above one
2707        { "\u00e9\u00e9n", "e\u0301e\u0301n", "m", true},
2708
2709        // JDK-6995635
2710        { "(\u00e9)", "e\u0301", "m", true },
2711
2712        // JDK-6736245
2713        // intereting special case, nfc(u2add+u0338) -> u2add+u0338) NOT u2adc
2714        { "\u2ADC", "\u2ADC", "m", true},          // NFC
2715        { "\u2ADC", "\u2ADD\u0338", "m", true},    // NFD
2716
2717        //  4916384.
2718        // Decomposed hangul (jamos) works inside clazz
2719        { "[\u1100\u1161]", "\u1100\u1161", "m", true},
2720        { "[\u1100\u1161]", "\uac00", "m", true},
2721
2722        { "[\uac00]", "\u1100\u1161", "m", true},
2723        { "[\uac00]", "\uac00", "m", true},
2724
2725        // Decomposed hangul (jamos)
2726        { "\u1100\u1161", "\u1100\u1161", "m", true},
2727        { "\u1100\u1161", "\uac00", "m", true},
2728
2729        // Composed hangul
2730        { "\uac00",  "\u1100\u1161", "m", true },
2731        { "\uac00",  "\uac00", "m", true },
2732
2733        /* Need a NFDSlice to nfd the source to solve this issue
2734           u+1d1c0 -> nfd: <u+1d1ba><u+1d165><u+1d16f>  -> nfc: <u+1d1ba><u+1d165><u+1d16f>
2735           u+1d1bc -> nfd: <u+1d1ba><u+1d165>           -> nfc: <u+1d1ba><u+1d165>
2736           <u+1d1bc><u+1d16f> -> nfd: <u+1d1ba><u+1d165><u+1d16f> -> nfc: <u+1d1ba><u+1d165><u+1d16f>
2737
2738        // Decomposed supplementary outside char classes
2739        // { "test\ud834\uddbc\ud834\udd6f", "test\ud834\uddc0", "m", true },
2740        // Composed supplementary outside char classes
2741        // { "test\ud834\uddc0", "test\ud834\uddbc\ud834\udd6f", "m", true },
2742        */
2743        { "test\ud834\uddbc\ud834\udd6f", "test\ud834\uddbc\ud834\udd6f", "m", true },
2744        { "test\ud834\uddc0",             "test\ud834\uddbc\ud834\udd6f", "m", true },
2745
2746        { "test\ud834\uddc0",             "test\ud834\uddc0",             "m", true },
2747        { "test\ud834\uddbc\ud834\udd6f", "test\ud834\uddc0",             "m", true },
2748        };
2749
2750        int failCount = 0;
2751        for (Object[] d : data) {
2752            String pn = (String)d[0];
2753            String tt = (String)d[1];
2754            boolean isFind = "f".equals(((String)d[2]));
2755            boolean expected = (boolean)d[3];
2756            boolean ret = isFind ? Pattern.compile(pn, Pattern.CANON_EQ).matcher(tt).find()
2757                                 : Pattern.compile(pn, Pattern.CANON_EQ).matcher(tt).matches();
2758            if (ret != expected) {
2759                failCount++;
2760                continue;
2761            }
2762        }
2763        report("Canonical Equivalence");
2764    }
2765
2766    /**
2767     * A basic sanity test of Matcher.replaceAll().
2768     */
2769    private static void globalSubstitute() throws Exception {
2770        // Global substitution with a literal
2771        Pattern p = Pattern.compile("(ab)(c*)");
2772        Matcher m = p.matcher("abccczzzabcczzzabccc");
2773        if (!m.replaceAll("test").equals("testzzztestzzztest"))
2774            failCount++;
2775
2776        m.reset("zzzabccczzzabcczzzabccczzz");
2777        if (!m.replaceAll("test").equals("zzztestzzztestzzztestzzz"))
2778            failCount++;
2779
2780        // Global substitution with groups
2781        m.reset("zzzabccczzzabcczzzabccczzz");
2782        String result = m.replaceAll("$1");
2783        if (!result.equals("zzzabzzzabzzzabzzz"))
2784            failCount++;
2785
2786        // Supplementary character test
2787        // Global substitution with a literal
2788        p = Pattern.compile(toSupplementaries("(ab)(c*)"));
2789        m = p.matcher(toSupplementaries("abccczzzabcczzzabccc"));
2790        if (!m.replaceAll(toSupplementaries("test")).
2791            equals(toSupplementaries("testzzztestzzztest")))
2792            failCount++;
2793
2794        m.reset(toSupplementaries("zzzabccczzzabcczzzabccczzz"));
2795        if (!m.replaceAll(toSupplementaries("test")).
2796            equals(toSupplementaries("zzztestzzztestzzztestzzz")))
2797            failCount++;
2798
2799        // Global substitution with groups
2800        m.reset(toSupplementaries("zzzabccczzzabcczzzabccczzz"));
2801        result = m.replaceAll("$1");
2802        if (!result.equals(toSupplementaries("zzzabzzzabzzzabzzz")))
2803            failCount++;
2804
2805        report("Global Substitution");
2806    }
2807
2808    /**
2809     * Tests the usage of Matcher.appendReplacement() with literal
2810     * and group substitutions.
2811     */
2812    private static void stringbufferSubstitute() throws Exception {
2813        // SB substitution with literal
2814        String blah = "zzzblahzzz";
2815        Pattern p = Pattern.compile("blah");
2816        Matcher m = p.matcher(blah);
2817        StringBuffer result = new StringBuffer();
2818        try {
2819            m.appendReplacement(result, "blech");
2820            failCount++;
2821        } catch (IllegalStateException e) {
2822        }
2823        m.find();
2824        m.appendReplacement(result, "blech");
2825        if (!result.toString().equals("zzzblech"))
2826            failCount++;
2827
2828        m.appendTail(result);
2829        if (!result.toString().equals("zzzblechzzz"))
2830            failCount++;
2831
2832        // SB substitution with groups
2833        blah = "zzzabcdzzz";
2834        p = Pattern.compile("(ab)(cd)*");
2835        m = p.matcher(blah);
2836        result = new StringBuffer();
2837        try {
2838            m.appendReplacement(result, "$1");
2839            failCount++;
2840        } catch (IllegalStateException e) {
2841        }
2842        m.find();
2843        m.appendReplacement(result, "$1");
2844        if (!result.toString().equals("zzzab"))
2845            failCount++;
2846
2847        m.appendTail(result);
2848        if (!result.toString().equals("zzzabzzz"))
2849            failCount++;
2850
2851        // SB substitution with 3 groups
2852        blah = "zzzabcdcdefzzz";
2853        p = Pattern.compile("(ab)(cd)*(ef)");
2854        m = p.matcher(blah);
2855        result = new StringBuffer();
2856        try {
2857            m.appendReplacement(result, "$1w$2w$3");
2858            failCount++;
2859        } catch (IllegalStateException e) {
2860        }
2861        m.find();
2862        m.appendReplacement(result, "$1w$2w$3");
2863        if (!result.toString().equals("zzzabwcdwef"))
2864            failCount++;
2865
2866        m.appendTail(result);
2867        if (!result.toString().equals("zzzabwcdwefzzz"))
2868            failCount++;
2869
2870        // SB substitution with groups and three matches
2871        // skipping middle match
2872        blah = "zzzabcdzzzabcddzzzabcdzzz";
2873        p = Pattern.compile("(ab)(cd*)");
2874        m = p.matcher(blah);
2875        result = new StringBuffer();
2876        try {
2877            m.appendReplacement(result, "$1");
2878            failCount++;
2879        } catch (IllegalStateException e) {
2880        }
2881        m.find();
2882        m.appendReplacement(result, "$1");
2883        if (!result.toString().equals("zzzab"))
2884            failCount++;
2885
2886        m.find();
2887        m.find();
2888        m.appendReplacement(result, "$2");
2889        if (!result.toString().equals("zzzabzzzabcddzzzcd"))
2890            failCount++;
2891
2892        m.appendTail(result);
2893        if (!result.toString().equals("zzzabzzzabcddzzzcdzzz"))
2894            failCount++;
2895
2896        // Check to make sure escaped $ is ignored
2897        blah = "zzzabcdcdefzzz";
2898        p = Pattern.compile("(ab)(cd)*(ef)");
2899        m = p.matcher(blah);
2900        result = new StringBuffer();
2901        m.find();
2902        m.appendReplacement(result, "$1w\\$2w$3");
2903        if (!result.toString().equals("zzzabw$2wef"))
2904            failCount++;
2905
2906        m.appendTail(result);
2907        if (!result.toString().equals("zzzabw$2wefzzz"))
2908            failCount++;
2909
2910        // Check to make sure a reference to nonexistent group causes error
2911        blah = "zzzabcdcdefzzz";
2912        p = Pattern.compile("(ab)(cd)*(ef)");
2913        m = p.matcher(blah);
2914        result = new StringBuffer();
2915        m.find();
2916        try {
2917            m.appendReplacement(result, "$1w$5w$3");
2918            failCount++;
2919        } catch (IndexOutOfBoundsException ioobe) {
2920            // Correct result
2921        }
2922
2923        // Check double digit group references
2924        blah = "zzz123456789101112zzz";
2925        p = Pattern.compile("(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)");
2926        m = p.matcher(blah);
2927        result = new StringBuffer();
2928        m.find();
2929        m.appendReplacement(result, "$1w$11w$3");
2930        if (!result.toString().equals("zzz1w11w3"))
2931            failCount++;
2932
2933        // Check to make sure it backs off $15 to $1 if only three groups
2934        blah = "zzzabcdcdefzzz";
2935        p = Pattern.compile("(ab)(cd)*(ef)");
2936        m = p.matcher(blah);
2937        result = new StringBuffer();
2938        m.find();
2939        m.appendReplacement(result, "$1w$15w$3");
2940        if (!result.toString().equals("zzzabwab5wef"))
2941            failCount++;
2942
2943
2944        // Supplementary character test
2945        // SB substitution with literal
2946        blah = toSupplementaries("zzzblahzzz");
2947        p = Pattern.compile(toSupplementaries("blah"));
2948        m = p.matcher(blah);
2949        result = new StringBuffer();
2950        try {
2951            m.appendReplacement(result, toSupplementaries("blech"));
2952            failCount++;
2953        } catch (IllegalStateException e) {
2954        }
2955        m.find();
2956        m.appendReplacement(result, toSupplementaries("blech"));
2957        if (!result.toString().equals(toSupplementaries("zzzblech")))
2958            failCount++;
2959
2960        m.appendTail(result);
2961        if (!result.toString().equals(toSupplementaries("zzzblechzzz")))
2962            failCount++;
2963
2964        // SB substitution with groups
2965        blah = toSupplementaries("zzzabcdzzz");
2966        p = Pattern.compile(toSupplementaries("(ab)(cd)*"));
2967        m = p.matcher(blah);
2968        result = new StringBuffer();
2969        try {
2970            m.appendReplacement(result, "$1");
2971            failCount++;
2972        } catch (IllegalStateException e) {
2973        }
2974        m.find();
2975        m.appendReplacement(result, "$1");
2976        if (!result.toString().equals(toSupplementaries("zzzab")))
2977            failCount++;
2978
2979        m.appendTail(result);
2980        if (!result.toString().equals(toSupplementaries("zzzabzzz")))
2981            failCount++;
2982
2983        // SB substitution with 3 groups
2984        blah = toSupplementaries("zzzabcdcdefzzz");
2985        p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)"));
2986        m = p.matcher(blah);
2987        result = new StringBuffer();
2988        try {
2989            m.appendReplacement(result, toSupplementaries("$1w$2w$3"));
2990            failCount++;
2991        } catch (IllegalStateException e) {
2992        }
2993        m.find();
2994        m.appendReplacement(result, toSupplementaries("$1w$2w$3"));
2995        if (!result.toString().equals(toSupplementaries("zzzabwcdwef")))
2996            failCount++;
2997
2998        m.appendTail(result);
2999        if (!result.toString().equals(toSupplementaries("zzzabwcdwefzzz")))
3000            failCount++;
3001
3002        // SB substitution with groups and three matches
3003        // skipping middle match
3004        blah = toSupplementaries("zzzabcdzzzabcddzzzabcdzzz");
3005        p = Pattern.compile(toSupplementaries("(ab)(cd*)"));
3006        m = p.matcher(blah);
3007        result = new StringBuffer();
3008        try {
3009            m.appendReplacement(result, "$1");
3010            failCount++;
3011        } catch (IllegalStateException e) {
3012        }
3013        m.find();
3014        m.appendReplacement(result, "$1");
3015        if (!result.toString().equals(toSupplementaries("zzzab")))
3016            failCount++;
3017
3018        m.find();
3019        m.find();
3020        m.appendReplacement(result, "$2");
3021        if (!result.toString().equals(toSupplementaries("zzzabzzzabcddzzzcd")))
3022            failCount++;
3023
3024        m.appendTail(result);
3025        if (!result.toString().equals(toSupplementaries("zzzabzzzabcddzzzcdzzz")))
3026            failCount++;
3027
3028        // Check to make sure escaped $ is ignored
3029        blah = toSupplementaries("zzzabcdcdefzzz");
3030        p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)"));
3031        m = p.matcher(blah);
3032        result = new StringBuffer();
3033        m.find();
3034        m.appendReplacement(result, toSupplementaries("$1w\\$2w$3"));
3035        if (!result.toString().equals(toSupplementaries("zzzabw$2wef")))
3036            failCount++;
3037
3038        m.appendTail(result);
3039        if (!result.toString().equals(toSupplementaries("zzzabw$2wefzzz")))
3040            failCount++;
3041
3042        // Check to make sure a reference to nonexistent group causes error
3043        blah = toSupplementaries("zzzabcdcdefzzz");
3044        p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)"));
3045        m = p.matcher(blah);
3046        result = new StringBuffer();
3047        m.find();
3048        try {
3049            m.appendReplacement(result, toSupplementaries("$1w$5w$3"));
3050            failCount++;
3051        } catch (IndexOutOfBoundsException ioobe) {
3052            // Correct result
3053        }
3054
3055        // Check double digit group references
3056        blah = toSupplementaries("zzz123456789101112zzz");
3057        p = Pattern.compile("(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)");
3058        m = p.matcher(blah);
3059        result = new StringBuffer();
3060        m.find();
3061        m.appendReplacement(result, toSupplementaries("$1w$11w$3"));
3062        if (!result.toString().equals(toSupplementaries("zzz1w11w3")))
3063            failCount++;
3064
3065        // Check to make sure it backs off $15 to $1 if only three groups
3066        blah = toSupplementaries("zzzabcdcdefzzz");
3067        p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)"));
3068        m = p.matcher(blah);
3069        result = new StringBuffer();
3070        m.find();
3071        m.appendReplacement(result, toSupplementaries("$1w$15w$3"));
3072        if (!result.toString().equals(toSupplementaries("zzzabwab5wef")))
3073            failCount++;
3074
3075        // Check nothing has been appended into the output buffer if
3076        // the replacement string triggers IllegalArgumentException.
3077        p = Pattern.compile("(abc)");
3078        m = p.matcher("abcd");
3079        result = new StringBuffer();
3080        m.find();
3081        try {
3082            m.appendReplacement(result, ("xyz$g"));
3083            failCount++;
3084        } catch (IllegalArgumentException iae) {
3085            if (result.length() != 0)
3086                failCount++;
3087        }
3088
3089        report("SB Substitution");
3090    }
3091
3092    /**
3093     * Tests the usage of Matcher.appendReplacement() with literal
3094     * and group substitutions.
3095     */
3096    private static void stringbuilderSubstitute() throws Exception {
3097        // SB substitution with literal
3098        String blah = "zzzblahzzz";
3099        Pattern p = Pattern.compile("blah");
3100        Matcher m = p.matcher(blah);
3101        StringBuilder result = new StringBuilder();
3102        try {
3103            m.appendReplacement(result, "blech");
3104            failCount++;
3105        } catch (IllegalStateException e) {
3106        }
3107        m.find();
3108        m.appendReplacement(result, "blech");
3109        if (!result.toString().equals("zzzblech"))
3110            failCount++;
3111
3112        m.appendTail(result);
3113        if (!result.toString().equals("zzzblechzzz"))
3114            failCount++;
3115
3116        // SB substitution with groups
3117        blah = "zzzabcdzzz";
3118        p = Pattern.compile("(ab)(cd)*");
3119        m = p.matcher(blah);
3120        result = new StringBuilder();
3121        try {
3122            m.appendReplacement(result, "$1");
3123            failCount++;
3124        } catch (IllegalStateException e) {
3125        }
3126        m.find();
3127        m.appendReplacement(result, "$1");
3128        if (!result.toString().equals("zzzab"))
3129            failCount++;
3130
3131        m.appendTail(result);
3132        if (!result.toString().equals("zzzabzzz"))
3133            failCount++;
3134
3135        // SB substitution with 3 groups
3136        blah = "zzzabcdcdefzzz";
3137        p = Pattern.compile("(ab)(cd)*(ef)");
3138        m = p.matcher(blah);
3139        result = new StringBuilder();
3140        try {
3141            m.appendReplacement(result, "$1w$2w$3");
3142            failCount++;
3143        } catch (IllegalStateException e) {
3144        }
3145        m.find();
3146        m.appendReplacement(result, "$1w$2w$3");
3147        if (!result.toString().equals("zzzabwcdwef"))
3148            failCount++;
3149
3150        m.appendTail(result);
3151        if (!result.toString().equals("zzzabwcdwefzzz"))
3152            failCount++;
3153
3154        // SB substitution with groups and three matches
3155        // skipping middle match
3156        blah = "zzzabcdzzzabcddzzzabcdzzz";
3157        p = Pattern.compile("(ab)(cd*)");
3158        m = p.matcher(blah);
3159        result = new StringBuilder();
3160        try {
3161            m.appendReplacement(result, "$1");
3162            failCount++;
3163        } catch (IllegalStateException e) {
3164        }
3165        m.find();
3166        m.appendReplacement(result, "$1");
3167        if (!result.toString().equals("zzzab"))
3168            failCount++;
3169
3170        m.find();
3171        m.find();
3172        m.appendReplacement(result, "$2");
3173        if (!result.toString().equals("zzzabzzzabcddzzzcd"))
3174            failCount++;
3175
3176        m.appendTail(result);
3177        if (!result.toString().equals("zzzabzzzabcddzzzcdzzz"))
3178            failCount++;
3179
3180        // Check to make sure escaped $ is ignored
3181        blah = "zzzabcdcdefzzz";
3182        p = Pattern.compile("(ab)(cd)*(ef)");
3183        m = p.matcher(blah);
3184        result = new StringBuilder();
3185        m.find();
3186        m.appendReplacement(result, "$1w\\$2w$3");
3187        if (!result.toString().equals("zzzabw$2wef"))
3188            failCount++;
3189
3190        m.appendTail(result);
3191        if (!result.toString().equals("zzzabw$2wefzzz"))
3192            failCount++;
3193
3194        // Check to make sure a reference to nonexistent group causes error
3195        blah = "zzzabcdcdefzzz";
3196        p = Pattern.compile("(ab)(cd)*(ef)");
3197        m = p.matcher(blah);
3198        result = new StringBuilder();
3199        m.find();
3200        try {
3201            m.appendReplacement(result, "$1w$5w$3");
3202            failCount++;
3203        } catch (IndexOutOfBoundsException ioobe) {
3204            // Correct result
3205        }
3206
3207        // Check double digit group references
3208        blah = "zzz123456789101112zzz";
3209        p = Pattern.compile("(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)");
3210        m = p.matcher(blah);
3211        result = new StringBuilder();
3212        m.find();
3213        m.appendReplacement(result, "$1w$11w$3");
3214        if (!result.toString().equals("zzz1w11w3"))
3215            failCount++;
3216
3217        // Check to make sure it backs off $15 to $1 if only three groups
3218        blah = "zzzabcdcdefzzz";
3219        p = Pattern.compile("(ab)(cd)*(ef)");
3220        m = p.matcher(blah);
3221        result = new StringBuilder();
3222        m.find();
3223        m.appendReplacement(result, "$1w$15w$3");
3224        if (!result.toString().equals("zzzabwab5wef"))
3225            failCount++;
3226
3227
3228        // Supplementary character test
3229        // SB substitution with literal
3230        blah = toSupplementaries("zzzblahzzz");
3231        p = Pattern.compile(toSupplementaries("blah"));
3232        m = p.matcher(blah);
3233        result = new StringBuilder();
3234        try {
3235            m.appendReplacement(result, toSupplementaries("blech"));
3236            failCount++;
3237        } catch (IllegalStateException e) {
3238        }
3239        m.find();
3240        m.appendReplacement(result, toSupplementaries("blech"));
3241        if (!result.toString().equals(toSupplementaries("zzzblech")))
3242            failCount++;
3243        m.appendTail(result);
3244        if (!result.toString().equals(toSupplementaries("zzzblechzzz")))
3245            failCount++;
3246
3247        // SB substitution with groups
3248        blah = toSupplementaries("zzzabcdzzz");
3249        p = Pattern.compile(toSupplementaries("(ab)(cd)*"));
3250        m = p.matcher(blah);
3251        result = new StringBuilder();
3252        try {
3253            m.appendReplacement(result, "$1");
3254            failCount++;
3255        } catch (IllegalStateException e) {
3256        }
3257        m.find();
3258        m.appendReplacement(result, "$1");
3259        if (!result.toString().equals(toSupplementaries("zzzab")))
3260            failCount++;
3261
3262        m.appendTail(result);
3263        if (!result.toString().equals(toSupplementaries("zzzabzzz")))
3264            failCount++;
3265
3266        // SB substitution with 3 groups
3267        blah = toSupplementaries("zzzabcdcdefzzz");
3268        p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)"));
3269        m = p.matcher(blah);
3270        result = new StringBuilder();
3271        try {
3272            m.appendReplacement(result, toSupplementaries("$1w$2w$3"));
3273            failCount++;
3274        } catch (IllegalStateException e) {
3275        }
3276        m.find();
3277        m.appendReplacement(result, toSupplementaries("$1w$2w$3"));
3278        if (!result.toString().equals(toSupplementaries("zzzabwcdwef")))
3279            failCount++;
3280
3281        m.appendTail(result);
3282        if (!result.toString().equals(toSupplementaries("zzzabwcdwefzzz")))
3283            failCount++;
3284
3285        // SB substitution with groups and three matches
3286        // skipping middle match
3287        blah = toSupplementaries("zzzabcdzzzabcddzzzabcdzzz");
3288        p = Pattern.compile(toSupplementaries("(ab)(cd*)"));
3289        m = p.matcher(blah);
3290        result = new StringBuilder();
3291        try {
3292            m.appendReplacement(result, "$1");
3293            failCount++;
3294        } catch (IllegalStateException e) {
3295        }
3296        m.find();
3297        m.appendReplacement(result, "$1");
3298        if (!result.toString().equals(toSupplementaries("zzzab")))
3299            failCount++;
3300
3301        m.find();
3302        m.find();
3303        m.appendReplacement(result, "$2");
3304        if (!result.toString().equals(toSupplementaries("zzzabzzzabcddzzzcd")))
3305            failCount++;
3306
3307        m.appendTail(result);
3308        if (!result.toString().equals(toSupplementaries("zzzabzzzabcddzzzcdzzz")))
3309            failCount++;
3310
3311        // Check to make sure escaped $ is ignored
3312        blah = toSupplementaries("zzzabcdcdefzzz");
3313        p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)"));
3314        m = p.matcher(blah);
3315        result = new StringBuilder();
3316        m.find();
3317        m.appendReplacement(result, toSupplementaries("$1w\\$2w$3"));
3318        if (!result.toString().equals(toSupplementaries("zzzabw$2wef")))
3319            failCount++;
3320
3321        m.appendTail(result);
3322        if (!result.toString().equals(toSupplementaries("zzzabw$2wefzzz")))
3323            failCount++;
3324
3325        // Check to make sure a reference to nonexistent group causes error
3326        blah = toSupplementaries("zzzabcdcdefzzz");
3327        p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)"));
3328        m = p.matcher(blah);
3329        result = new StringBuilder();
3330        m.find();
3331        try {
3332            m.appendReplacement(result, toSupplementaries("$1w$5w$3"));
3333            failCount++;
3334        } catch (IndexOutOfBoundsException ioobe) {
3335            // Correct result
3336        }
3337        // Check double digit group references
3338        blah = toSupplementaries("zzz123456789101112zzz");
3339        p = Pattern.compile("(1)(2)(3)(4)(5)(6)(7)(8)(9)(10)(11)");
3340        m = p.matcher(blah);
3341        result = new StringBuilder();
3342        m.find();
3343        m.appendReplacement(result, toSupplementaries("$1w$11w$3"));
3344        if (!result.toString().equals(toSupplementaries("zzz1w11w3")))
3345            failCount++;
3346
3347        // Check to make sure it backs off $15 to $1 if only three groups
3348        blah = toSupplementaries("zzzabcdcdefzzz");
3349        p = Pattern.compile(toSupplementaries("(ab)(cd)*(ef)"));
3350        m = p.matcher(blah);
3351        result = new StringBuilder();
3352        m.find();
3353        m.appendReplacement(result, toSupplementaries("$1w$15w$3"));
3354        if (!result.toString().equals(toSupplementaries("zzzabwab5wef")))
3355            failCount++;
3356        // Check nothing has been appended into the output buffer if
3357        // the replacement string triggers IllegalArgumentException.
3358        p = Pattern.compile("(abc)");
3359        m = p.matcher("abcd");
3360        result = new StringBuilder();
3361        m.find();
3362        try {
3363            m.appendReplacement(result, ("xyz$g"));
3364            failCount++;
3365        } catch (IllegalArgumentException iae) {
3366            if (result.length() != 0)
3367                failCount++;
3368        }
3369        report("SB Substitution 2");
3370    }
3371
3372    /*
3373     * 5 groups of characters are created to make a substitution string.
3374     * A base string will be created including random lead chars, the
3375     * substitution string, and random trailing chars.
3376     * A pattern containing the 5 groups is searched for and replaced with:
3377     * random group + random string + random group.
3378     * The results are checked for correctness.
3379     */
3380    private static void substitutionBasher() {
3381        for (int runs = 0; runs<1000; runs++) {
3382            // Create a base string to work in
3383            int leadingChars = generator.nextInt(10);
3384            StringBuffer baseBuffer = new StringBuffer(100);
3385            String leadingString = getRandomAlphaString(leadingChars);
3386            baseBuffer.append(leadingString);
3387
3388            // Create 5 groups of random number of random chars
3389            // Create the string to substitute
3390            // Create the pattern string to search for
3391            StringBuffer bufferToSub = new StringBuffer(25);
3392            StringBuffer bufferToPat = new StringBuffer(50);
3393            String[] groups = new String[5];
3394            for(int i=0; i<5; i++) {
3395                int aGroupSize = generator.nextInt(5)+1;
3396                groups[i] = getRandomAlphaString(aGroupSize);
3397                bufferToSub.append(groups[i]);
3398                bufferToPat.append('(');
3399                bufferToPat.append(groups[i]);
3400                bufferToPat.append(')');
3401            }
3402            String stringToSub = bufferToSub.toString();
3403            String pattern = bufferToPat.toString();
3404
3405            // Place sub string into working string at random index
3406            baseBuffer.append(stringToSub);
3407
3408            // Append random chars to end
3409            int trailingChars = generator.nextInt(10);
3410            String trailingString = getRandomAlphaString(trailingChars);
3411            baseBuffer.append(trailingString);
3412            String baseString = baseBuffer.toString();
3413
3414            // Create test pattern and matcher
3415            Pattern p = Pattern.compile(pattern);
3416            Matcher m = p.matcher(baseString);
3417
3418            // Reject candidate if pattern happens to start early
3419            m.find();
3420            if (m.start() < leadingChars)
3421                continue;
3422
3423            // Reject candidate if more than one match
3424            if (m.find())
3425                continue;
3426
3427            // Construct a replacement string with :
3428            // random group + random string + random group
3429            StringBuffer bufferToRep = new StringBuffer();
3430            int groupIndex1 = generator.nextInt(5);
3431            bufferToRep.append("$" + (groupIndex1 + 1));
3432            String randomMidString = getRandomAlphaString(5);
3433            bufferToRep.append(randomMidString);
3434            int groupIndex2 = generator.nextInt(5);
3435            bufferToRep.append("$" + (groupIndex2 + 1));
3436            String replacement = bufferToRep.toString();
3437
3438            // Do the replacement
3439            String result = m.replaceAll(replacement);
3440
3441            // Construct expected result
3442            StringBuffer bufferToRes = new StringBuffer();
3443            bufferToRes.append(leadingString);
3444            bufferToRes.append(groups[groupIndex1]);
3445            bufferToRes.append(randomMidString);
3446            bufferToRes.append(groups[groupIndex2]);
3447            bufferToRes.append(trailingString);
3448            String expectedResult = bufferToRes.toString();
3449
3450            // Check results
3451            if (!result.equals(expectedResult))
3452                failCount++;
3453        }
3454
3455        report("Substitution Basher");
3456    }
3457
3458    /*
3459     * 5 groups of characters are created to make a substitution string.
3460     * A base string will be created including random lead chars, the
3461     * substitution string, and random trailing chars.
3462     * A pattern containing the 5 groups is searched for and replaced with:
3463     * random group + random string + random group.
3464     * The results are checked for correctness.
3465     */
3466    private static void substitutionBasher2() {
3467        for (int runs = 0; runs<1000; runs++) {
3468            // Create a base string to work in
3469            int leadingChars = generator.nextInt(10);
3470            StringBuilder baseBuffer = new StringBuilder(100);
3471            String leadingString = getRandomAlphaString(leadingChars);
3472            baseBuffer.append(leadingString);
3473
3474            // Create 5 groups of random number of random chars
3475            // Create the string to substitute
3476            // Create the pattern string to search for
3477            StringBuilder bufferToSub = new StringBuilder(25);
3478            StringBuilder bufferToPat = new StringBuilder(50);
3479            String[] groups = new String[5];
3480            for(int i=0; i<5; i++) {
3481                int aGroupSize = generator.nextInt(5)+1;
3482                groups[i] = getRandomAlphaString(aGroupSize);
3483                bufferToSub.append(groups[i]);
3484                bufferToPat.append('(');
3485                bufferToPat.append(groups[i]);
3486                bufferToPat.append(')');
3487            }
3488            String stringToSub = bufferToSub.toString();
3489            String pattern = bufferToPat.toString();
3490
3491            // Place sub string into working string at random index
3492            baseBuffer.append(stringToSub);
3493
3494            // Append random chars to end
3495            int trailingChars = generator.nextInt(10);
3496            String trailingString = getRandomAlphaString(trailingChars);
3497            baseBuffer.append(trailingString);
3498            String baseString = baseBuffer.toString();
3499
3500            // Create test pattern and matcher
3501            Pattern p = Pattern.compile(pattern);
3502            Matcher m = p.matcher(baseString);
3503
3504            // Reject candidate if pattern happens to start early
3505            m.find();
3506            if (m.start() < leadingChars)
3507                continue;
3508
3509            // Reject candidate if more than one match
3510            if (m.find())
3511                continue;
3512
3513            // Construct a replacement string with :
3514            // random group + random string + random group
3515            StringBuilder bufferToRep = new StringBuilder();
3516            int groupIndex1 = generator.nextInt(5);
3517            bufferToRep.append("$" + (groupIndex1 + 1));
3518            String randomMidString = getRandomAlphaString(5);
3519            bufferToRep.append(randomMidString);
3520            int groupIndex2 = generator.nextInt(5);
3521            bufferToRep.append("$" + (groupIndex2 + 1));
3522            String replacement = bufferToRep.toString();
3523
3524            // Do the replacement
3525            String result = m.replaceAll(replacement);
3526
3527            // Construct expected result
3528            StringBuilder bufferToRes = new StringBuilder();
3529            bufferToRes.append(leadingString);
3530            bufferToRes.append(groups[groupIndex1]);
3531            bufferToRes.append(randomMidString);
3532            bufferToRes.append(groups[groupIndex2]);
3533            bufferToRes.append(trailingString);
3534            String expectedResult = bufferToRes.toString();
3535
3536            // Check results
3537            if (!result.equals(expectedResult)) {
3538                failCount++;
3539            }
3540        }
3541
3542        report("Substitution Basher 2");
3543    }
3544
3545    /**
3546     * Checks the handling of some escape sequences that the Pattern
3547     * class should process instead of the java compiler. These are
3548     * not in the file because the escapes should be be processed
3549     * by the Pattern class when the regex is compiled.
3550     */
3551    private static void escapes() throws Exception {
3552        Pattern p = Pattern.compile("\\043");
3553        Matcher m = p.matcher("#");
3554        if (!m.find())
3555            failCount++;
3556
3557        p = Pattern.compile("\\x23");
3558        m = p.matcher("#");
3559        if (!m.find())
3560            failCount++;
3561
3562        p = Pattern.compile("\\u0023");
3563        m = p.matcher("#");
3564        if (!m.find())
3565            failCount++;
3566
3567        report("Escape sequences");
3568    }
3569
3570    /**
3571     * Checks the handling of blank input situations. These
3572     * tests are incompatible with my test file format.
3573     */
3574    private static void blankInput() throws Exception {
3575        Pattern p = Pattern.compile("abc", Pattern.CASE_INSENSITIVE);
3576        Matcher m = p.matcher("");
3577        if (m.find())
3578            failCount++;
3579
3580        p = Pattern.compile("a*", Pattern.CASE_INSENSITIVE);
3581        m = p.matcher("");
3582        if (!m.find())
3583            failCount++;
3584
3585        p = Pattern.compile("abc");
3586        m = p.matcher("");
3587        if (m.find())
3588            failCount++;
3589
3590        p = Pattern.compile("a*");
3591        m = p.matcher("");
3592        if (!m.find())
3593            failCount++;
3594
3595        report("Blank input");
3596    }
3597
3598    /**
3599     * Tests the Boyer-Moore pattern matching of a character sequence
3600     * on randomly generated patterns.
3601     */
3602    private static void bm() throws Exception {
3603        doBnM('a');
3604        report("Boyer Moore (ASCII)");
3605
3606        doBnM(Character.MIN_SUPPLEMENTARY_CODE_POINT - 10);
3607        report("Boyer Moore (Supplementary)");
3608    }
3609
3610    private static void doBnM(int baseCharacter) throws Exception {
3611        int achar=0;
3612
3613        for (int i=0; i<100; i++) {
3614            // Create a short pattern to search for
3615            int patternLength = generator.nextInt(7) + 4;
3616            StringBuffer patternBuffer = new StringBuffer(patternLength);
3617            String pattern;
3618            retry: for (;;) {
3619                for (int x=0; x<patternLength; x++) {
3620                    int ch = baseCharacter + generator.nextInt(26);
3621                    if (Character.isSupplementaryCodePoint(ch)) {
3622                        patternBuffer.append(Character.toChars(ch));
3623                    } else {
3624                        patternBuffer.append((char)ch);
3625                    }
3626                }
3627                pattern = patternBuffer.toString();
3628
3629                // Avoid patterns that start and end with the same substring
3630                // See JDK-6854417
3631                for (int x=1; x < pattern.length(); x++) {
3632                    if (pattern.startsWith(pattern.substring(x)))
3633                        continue retry;
3634                }
3635                break;
3636            }
3637            Pattern p = Pattern.compile(pattern);
3638
3639            // Create a buffer with random ASCII chars that does
3640            // not match the sample
3641            String toSearch = null;
3642            StringBuffer s = null;
3643            Matcher m = p.matcher("");
3644            do {
3645                s = new StringBuffer(100);
3646                for (int x=0; x<100; x++) {
3647                    int ch = baseCharacter + generator.nextInt(26);
3648                    if (Character.isSupplementaryCodePoint(ch)) {
3649                        s.append(Character.toChars(ch));
3650                    } else {
3651                        s.append((char)ch);
3652                    }
3653                }
3654                toSearch = s.toString();
3655                m.reset(toSearch);
3656            } while (m.find());
3657
3658            // Insert the pattern at a random spot
3659            int insertIndex = generator.nextInt(99);
3660            if (Character.isLowSurrogate(s.charAt(insertIndex)))
3661                insertIndex++;
3662            s = s.insert(insertIndex, pattern);
3663            toSearch = s.toString();
3664
3665            // Make sure that the pattern is found
3666            m.reset(toSearch);
3667            if (!m.find())
3668                failCount++;
3669
3670            // Make sure that the match text is the pattern
3671            if (!m.group().equals(pattern))
3672                failCount++;
3673
3674            // Make sure match occured at insertion point
3675            if (m.start() != insertIndex)
3676                failCount++;
3677        }
3678    }
3679
3680    /**
3681     * Tests the matching of slices on randomly generated patterns.
3682     * The Boyer-Moore optimization is not done on these patterns
3683     * because it uses unicode case folding.
3684     */
3685    private static void slice() throws Exception {
3686        doSlice(Character.MAX_VALUE);
3687        report("Slice");
3688
3689        doSlice(Character.MAX_CODE_POINT);
3690        report("Slice (Supplementary)");
3691    }
3692
3693    private static void doSlice(int maxCharacter) throws Exception {
3694        Random generator = new Random();
3695        int achar=0;
3696
3697        for (int i=0; i<100; i++) {
3698            // Create a short pattern to search for
3699            int patternLength = generator.nextInt(7) + 4;
3700            StringBuffer patternBuffer = new StringBuffer(patternLength);
3701            for (int x=0; x<patternLength; x++) {
3702                int randomChar = 0;
3703                while (!Character.isLetterOrDigit(randomChar))
3704                    randomChar = generator.nextInt(maxCharacter);
3705                if (Character.isSupplementaryCodePoint(randomChar)) {
3706                    patternBuffer.append(Character.toChars(randomChar));
3707                } else {
3708                    patternBuffer.append((char) randomChar);
3709                }
3710            }
3711            String pattern =  patternBuffer.toString();
3712            Pattern p = Pattern.compile(pattern, Pattern.UNICODE_CASE);
3713
3714            // Create a buffer with random chars that does not match the sample
3715            String toSearch = null;
3716            StringBuffer s = null;
3717            Matcher m = p.matcher("");
3718            do {
3719                s = new StringBuffer(100);
3720                for (int x=0; x<100; x++) {
3721                    int randomChar = 0;
3722                    while (!Character.isLetterOrDigit(randomChar))
3723                        randomChar = generator.nextInt(maxCharacter);
3724                    if (Character.isSupplementaryCodePoint(randomChar)) {
3725                        s.append(Character.toChars(randomChar));
3726                    } else {
3727                        s.append((char) randomChar);
3728                    }
3729                }
3730                toSearch = s.toString();
3731                m.reset(toSearch);
3732            } while (m.find());
3733
3734            // Insert the pattern at a random spot
3735            int insertIndex = generator.nextInt(99);
3736            if (Character.isLowSurrogate(s.charAt(insertIndex)))
3737                insertIndex++;
3738            s = s.insert(insertIndex, pattern);
3739            toSearch = s.toString();
3740
3741            // Make sure that the pattern is found
3742            m.reset(toSearch);
3743            if (!m.find())
3744                failCount++;
3745
3746            // Make sure that the match text is the pattern
3747            if (!m.group().equals(pattern))
3748                failCount++;
3749
3750            // Make sure match occured at insertion point
3751            if (m.start() != insertIndex)
3752                failCount++;
3753        }
3754    }
3755
3756    private static void explainFailure(String pattern, String data,
3757                                       String expected, String actual) {
3758        System.err.println("----------------------------------------");
3759        System.err.println("Pattern = "+pattern);
3760        System.err.println("Data = "+data);
3761        System.err.println("Expected = " + expected);
3762        System.err.println("Actual   = " + actual);
3763    }
3764
3765    private static void explainFailure(String pattern, String data,
3766                                       Throwable t) {
3767        System.err.println("----------------------------------------");
3768        System.err.println("Pattern = "+pattern);
3769        System.err.println("Data = "+data);
3770        t.printStackTrace(System.err);
3771    }
3772
3773    // Testing examples from a file
3774
3775    /**
3776     * Goes through the file "TestCases.txt" and creates many patterns
3777     * described in the file, matching the patterns against input lines in
3778     * the file, and comparing the results against the correct results
3779     * also found in the file. The file format is described in comments
3780     * at the head of the file.
3781     */
3782    private static void processFile(String fileName) throws Exception {
3783        File testCases = new File(System.getProperty("test.src", "."),
3784                                  fileName);
3785        FileInputStream in = new FileInputStream(testCases);
3786        BufferedReader r = new BufferedReader(new InputStreamReader(in));
3787
3788        // Process next test case.
3789        String aLine;
3790        while((aLine = r.readLine()) != null) {
3791            // Read a line for pattern
3792            String patternString = grabLine(r);
3793            Pattern p = null;
3794            try {
3795                p = compileTestPattern(patternString);
3796            } catch (PatternSyntaxException e) {
3797                String dataString = grabLine(r);
3798                String expectedResult = grabLine(r);
3799                if (expectedResult.startsWith("error"))
3800                    continue;
3801                explainFailure(patternString, dataString, e);
3802                failCount++;
3803                continue;
3804            }
3805
3806            // Read a line for input string
3807            String dataString = grabLine(r);
3808            Matcher m = p.matcher(dataString);
3809            StringBuffer result = new StringBuffer();
3810
3811            // Check for IllegalStateExceptions before a match
3812            failCount += preMatchInvariants(m);
3813
3814            boolean found = m.find();
3815
3816            if (found)
3817                failCount += postTrueMatchInvariants(m);
3818            else
3819                failCount += postFalseMatchInvariants(m);
3820
3821            if (found) {
3822                result.append("true ");
3823                result.append(m.group(0) + " ");
3824            } else {
3825                result.append("false ");
3826            }
3827
3828            result.append(m.groupCount());
3829
3830            if (found) {
3831                for (int i=1; i<m.groupCount()+1; i++)
3832                    if (m.group(i) != null)
3833                        result.append(" " +m.group(i));
3834            }
3835
3836            // Read a line for the expected result
3837            String expectedResult = grabLine(r);
3838
3839            if (!result.toString().equals(expectedResult)) {
3840                explainFailure(patternString, dataString, expectedResult, result.toString());
3841                failCount++;
3842            }
3843        }
3844
3845        report(fileName);
3846    }
3847
3848    private static int preMatchInvariants(Matcher m) {
3849        int failCount = 0;
3850        try {
3851            m.start();
3852            failCount++;
3853        } catch (IllegalStateException ise) {}
3854        try {
3855            m.end();
3856            failCount++;
3857        } catch (IllegalStateException ise) {}
3858        try {
3859            m.group();
3860            failCount++;
3861        } catch (IllegalStateException ise) {}
3862        return failCount;
3863    }
3864
3865    private static int postFalseMatchInvariants(Matcher m) {
3866        int failCount = 0;
3867        try {
3868            m.group();
3869            failCount++;
3870        } catch (IllegalStateException ise) {}
3871        try {
3872            m.start();
3873            failCount++;
3874        } catch (IllegalStateException ise) {}
3875        try {
3876            m.end();
3877            failCount++;
3878        } catch (IllegalStateException ise) {}
3879        return failCount;
3880    }
3881
3882    private static int postTrueMatchInvariants(Matcher m) {
3883        int failCount = 0;
3884        //assert(m.start() = m.start(0);
3885        if (m.start() != m.start(0))
3886            failCount++;
3887        //assert(m.end() = m.end(0);
3888        if (m.start() != m.start(0))
3889            failCount++;
3890        //assert(m.group() = m.group(0);
3891        if (!m.group().equals(m.group(0)))
3892            failCount++;
3893        try {
3894            m.group(50);
3895            failCount++;
3896        } catch (IndexOutOfBoundsException ise) {}
3897
3898        return failCount;
3899    }
3900
3901    private static Pattern compileTestPattern(String patternString) {
3902        if (!patternString.startsWith("'")) {
3903            return Pattern.compile(patternString);
3904        }
3905        int break1 = patternString.lastIndexOf("'");
3906        String flagString = patternString.substring(
3907                                          break1+1, patternString.length());
3908        patternString = patternString.substring(1, break1);
3909
3910        if (flagString.equals("i"))
3911            return Pattern.compile(patternString, Pattern.CASE_INSENSITIVE);
3912
3913        if (flagString.equals("m"))
3914            return Pattern.compile(patternString, Pattern.MULTILINE);
3915
3916        return Pattern.compile(patternString);
3917    }
3918
3919    /**
3920     * Reads a line from the input file. Keeps reading lines until a non
3921     * empty non comment line is read. If the line contains a \n then
3922     * these two characters are replaced by a newline char. If a \\uxxxx
3923     * sequence is read then the sequence is replaced by the unicode char.
3924     */
3925    private static String grabLine(BufferedReader r) throws Exception {
3926        int index = 0;
3927        String line = r.readLine();
3928        while (line.startsWith("//") || line.length() < 1)
3929            line = r.readLine();
3930        while ((index = line.indexOf("\\n")) != -1) {
3931            StringBuffer temp = new StringBuffer(line);
3932            temp.replace(index, index+2, "\n");
3933            line = temp.toString();
3934        }
3935        while ((index = line.indexOf("\\u")) != -1) {
3936            StringBuffer temp = new StringBuffer(line);
3937            String value = temp.substring(index+2, index+6);
3938            char aChar = (char)Integer.parseInt(value, 16);
3939            String unicodeChar = "" + aChar;
3940            temp.replace(index, index+6, unicodeChar);
3941            line = temp.toString();
3942        }
3943
3944        return line;
3945    }
3946
3947    private static void check(Pattern p, String s, String g, String expected) {
3948        Matcher m = p.matcher(s);
3949        m.find();
3950        if (!m.group(g).equals(expected) ||
3951            s.charAt(m.start(g)) != expected.charAt(0) ||
3952            s.charAt(m.end(g) - 1) != expected.charAt(expected.length() - 1))
3953            failCount++;
3954    }
3955
3956    private static void checkReplaceFirst(String p, String s, String r, String expected)
3957    {
3958        if (!expected.equals(Pattern.compile(p)
3959                                    .matcher(s)
3960                                    .replaceFirst(r)))
3961            failCount++;
3962    }
3963
3964    private static void checkReplaceAll(String p, String s, String r, String expected)
3965    {
3966        if (!expected.equals(Pattern.compile(p)
3967                                    .matcher(s)
3968                                    .replaceAll(r)))
3969            failCount++;
3970    }
3971
3972    private static void checkExpectedFail(String p) {
3973        try {
3974            Pattern.compile(p);
3975        } catch (PatternSyntaxException pse) {
3976            //pse.printStackTrace();
3977            return;
3978        }
3979        failCount++;
3980    }
3981
3982    private static void checkExpectedIAE(Matcher m, String g) {
3983        m.find();
3984        try {
3985            m.group(g);
3986        } catch (IllegalArgumentException x) {
3987            //iae.printStackTrace();
3988            try {
3989                m.start(g);
3990            } catch (IllegalArgumentException xx) {
3991                try {
3992                    m.start(g);
3993                } catch (IllegalArgumentException xxx) {
3994                    return;
3995                }
3996            }
3997        }
3998        failCount++;
3999    }
4000
4001    private static void checkExpectedNPE(Matcher m) {
4002        m.find();
4003        try {
4004            m.group(null);
4005        } catch (NullPointerException x) {
4006            try {
4007                m.start(null);
4008            } catch (NullPointerException xx) {
4009                try {
4010                    m.end(null);
4011                } catch (NullPointerException xxx) {
4012                    return;
4013                }
4014            }
4015        }
4016        failCount++;
4017    }
4018
4019    private static void namedGroupCaptureTest() throws Exception {
4020        check(Pattern.compile("x+(?<gname>y+)z+"),
4021              "xxxyyyzzz",
4022              "gname",
4023              "yyy");
4024
4025        check(Pattern.compile("x+(?<gname8>y+)z+"),
4026              "xxxyyyzzz",
4027              "gname8",
4028              "yyy");
4029
4030        //backref
4031        Pattern pattern = Pattern.compile("(a*)bc\\1");
4032        check(pattern, "zzzaabcazzz", true);  // found "abca"
4033
4034        check(Pattern.compile("(?<gname>a*)bc\\k<gname>"),
4035              "zzzaabcaazzz", true);
4036
4037        check(Pattern.compile("(?<gname>abc)(def)\\k<gname>"),
4038              "abcdefabc", true);
4039
4040        check(Pattern.compile("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)(?<gname>k)\\k<gname>"),
4041              "abcdefghijkk", true);
4042
4043        // Supplementary character tests
4044        check(Pattern.compile("(?<gname>" + toSupplementaries("a*)bc") + "\\k<gname>"),
4045              toSupplementaries("zzzaabcazzz"), true);
4046
4047        check(Pattern.compile("(?<gname>" + toSupplementaries("a*)bc") + "\\k<gname>"),
4048              toSupplementaries("zzzaabcaazzz"), true);
4049
4050        check(Pattern.compile("(?<gname>" + toSupplementaries("abc)(def)") + "\\k<gname>"),
4051              toSupplementaries("abcdefabc"), true);
4052
4053        check(Pattern.compile(toSupplementaries("(a)(b)(c)(d)(e)(f)(g)(h)(i)(j)") +
4054                              "(?<gname>" +
4055                              toSupplementaries("k)") + "\\k<gname>"),
4056              toSupplementaries("abcdefghijkk"), true);
4057
4058        check(Pattern.compile("x+(?<gname>y+)z+\\k<gname>"),
4059              "xxxyyyzzzyyy",
4060              "gname",
4061              "yyy");
4062
4063        //replaceFirst/All
4064        checkReplaceFirst("(?<gn>ab)(c*)",
4065                          "abccczzzabcczzzabccc",
4066                          "${gn}",
4067                          "abzzzabcczzzabccc");
4068
4069        checkReplaceAll("(?<gn>ab)(c*)",
4070                        "abccczzzabcczzzabccc",
4071                        "${gn}",
4072                        "abzzzabzzzab");
4073
4074
4075        checkReplaceFirst("(?<gn>ab)(c*)",
4076                          "zzzabccczzzabcczzzabccczzz",
4077                          "${gn}",
4078                          "zzzabzzzabcczzzabccczzz");
4079
4080        checkReplaceAll("(?<gn>ab)(c*)",
4081                        "zzzabccczzzabcczzzabccczzz",
4082                        "${gn}",
4083                        "zzzabzzzabzzzabzzz");
4084
4085        checkReplaceFirst("(?<gn1>ab)(?<gn2>c*)",
4086                          "zzzabccczzzabcczzzabccczzz",
4087                          "${gn2}",
4088                          "zzzccczzzabcczzzabccczzz");
4089
4090        checkReplaceAll("(?<gn1>ab)(?<gn2>c*)",
4091                        "zzzabccczzzabcczzzabccczzz",
4092                        "${gn2}",
4093                        "zzzccczzzcczzzccczzz");
4094
4095        //toSupplementaries("(ab)(c*)"));
4096        checkReplaceFirst("(?<gn1>" + toSupplementaries("ab") +
4097                           ")(?<gn2>" + toSupplementaries("c") + "*)",
4098                          toSupplementaries("abccczzzabcczzzabccc"),
4099                          "${gn1}",
4100                          toSupplementaries("abzzzabcczzzabccc"));
4101
4102
4103        checkReplaceAll("(?<gn1>" + toSupplementaries("ab") +
4104                        ")(?<gn2>" + toSupplementaries("c") + "*)",
4105                        toSupplementaries("abccczzzabcczzzabccc"),
4106                        "${gn1}",
4107                        toSupplementaries("abzzzabzzzab"));
4108
4109        checkReplaceFirst("(?<gn1>" + toSupplementaries("ab") +
4110                           ")(?<gn2>" + toSupplementaries("c") + "*)",
4111                          toSupplementaries("abccczzzabcczzzabccc"),
4112                          "${gn2}",
4113                          toSupplementaries("ccczzzabcczzzabccc"));
4114
4115
4116        checkReplaceAll("(?<gn1>" + toSupplementaries("ab") +
4117                        ")(?<gn2>" + toSupplementaries("c") + "*)",
4118                        toSupplementaries("abccczzzabcczzzabccc"),
4119                        "${gn2}",
4120                        toSupplementaries("ccczzzcczzzccc"));
4121
4122        checkReplaceFirst("(?<dog>Dog)AndCat",
4123                          "zzzDogAndCatzzzDogAndCatzzz",
4124                          "${dog}",
4125                          "zzzDogzzzDogAndCatzzz");
4126
4127
4128        checkReplaceAll("(?<dog>Dog)AndCat",
4129                          "zzzDogAndCatzzzDogAndCatzzz",
4130                          "${dog}",
4131                          "zzzDogzzzDogzzz");
4132
4133        // backref in Matcher & String
4134        if (!"abcdefghij".replaceFirst("cd(?<gn>ef)gh", "${gn}").equals("abefij") ||
4135            !"abbbcbdbefgh".replaceAll("(?<gn>[a-e])b", "${gn}").equals("abcdefgh"))
4136            failCount++;
4137
4138        // negative
4139        checkExpectedFail("(?<groupnamehasnoascii.in>abc)(def)");
4140        checkExpectedFail("(?<groupnamehasnoascii_in>abc)(def)");
4141        checkExpectedFail("(?<6groupnamestartswithdigit>abc)(def)");
4142        checkExpectedFail("(?<gname>abc)(def)\\k<gnameX>");
4143        checkExpectedFail("(?<gname>abc)(?<gname>def)\\k<gnameX>");
4144        checkExpectedIAE(Pattern.compile("(?<gname>abc)(def)").matcher("abcdef"),
4145                         "gnameX");
4146        checkExpectedNPE(Pattern.compile("(?<gname>abc)(def)").matcher("abcdef"));
4147        report("NamedGroupCapture");
4148    }
4149
4150    // This is for bug 6919132
4151    private static void nonBmpClassComplementTest() throws Exception {
4152        Pattern p = Pattern.compile("\\P{Lu}");
4153        Matcher m = p.matcher(new String(new int[] {0x1d400}, 0, 1));
4154
4155        if (m.find() && m.start() == 1)
4156            failCount++;
4157
4158        // from a unicode category
4159        p = Pattern.compile("\\P{Lu}");
4160        m = p.matcher(new String(new int[] {0x1d400}, 0, 1));
4161        if (m.find())
4162            failCount++;
4163        if (!m.hitEnd())
4164            failCount++;
4165
4166        // block
4167        p = Pattern.compile("\\P{InMathematicalAlphanumericSymbols}");
4168        m = p.matcher(new String(new int[] {0x1d400}, 0, 1));
4169        if (m.find() && m.start() == 1)
4170            failCount++;
4171
4172        p = Pattern.compile("\\P{sc=GRANTHA}");
4173        m = p.matcher(new String(new int[] {0x11350}, 0, 1));
4174        if (m.find() && m.start() == 1)
4175            failCount++;
4176
4177        report("NonBmpClassComplement");
4178    }
4179
4180    private static void unicodePropertiesTest() throws Exception {
4181        // different forms
4182        if (!Pattern.compile("\\p{IsLu}").matcher("A").matches() ||
4183            !Pattern.compile("\\p{Lu}").matcher("A").matches() ||
4184            !Pattern.compile("\\p{gc=Lu}").matcher("A").matches() ||
4185            !Pattern.compile("\\p{general_category=Lu}").matcher("A").matches() ||
4186            !Pattern.compile("\\p{IsLatin}").matcher("B").matches() ||
4187            !Pattern.compile("\\p{sc=Latin}").matcher("B").matches() ||
4188            !Pattern.compile("\\p{script=Latin}").matcher("B").matches() ||
4189            !Pattern.compile("\\p{InBasicLatin}").matcher("c").matches() ||
4190            !Pattern.compile("\\p{blk=BasicLatin}").matcher("c").matches() ||
4191            !Pattern.compile("\\p{block=BasicLatin}").matcher("c").matches())
4192            failCount++;
4193
4194        Matcher common  = Pattern.compile("\\p{script=Common}").matcher("");
4195        Matcher unknown = Pattern.compile("\\p{IsUnknown}").matcher("");
4196        Matcher lastSM  = common;
4197        Character.UnicodeScript lastScript = Character.UnicodeScript.of(0);
4198
4199        Matcher latin  = Pattern.compile("\\p{block=basic_latin}").matcher("");
4200        Matcher greek  = Pattern.compile("\\p{InGreek}").matcher("");
4201        Matcher lastBM = latin;
4202        Character.UnicodeBlock lastBlock = Character.UnicodeBlock.of(0);
4203
4204        for (int cp = 1; cp < Character.MAX_CODE_POINT; cp++) {
4205            if (cp >= 0x30000 && (cp & 0x70) == 0){
4206                continue;  // only pick couple code points, they are the same
4207            }
4208
4209            // Unicode Script
4210            Character.UnicodeScript script = Character.UnicodeScript.of(cp);
4211            Matcher m;
4212            String str = new String(Character.toChars(cp));
4213            if (script == lastScript) {
4214                 m = lastSM;
4215                 m.reset(str);
4216            } else {
4217                 m  = Pattern.compile("\\p{Is" + script.name() + "}").matcher(str);
4218            }
4219            if (!m.matches()) {
4220                failCount++;
4221            }
4222            Matcher other = (script == Character.UnicodeScript.COMMON)? unknown : common;
4223            other.reset(str);
4224            if (other.matches()) {
4225                failCount++;
4226            }
4227            lastSM = m;
4228            lastScript = script;
4229
4230            // Unicode Block
4231            Character.UnicodeBlock block = Character.UnicodeBlock.of(cp);
4232            if (block == null) {
4233                //System.out.printf("Not a Block: cp=%x%n", cp);
4234                continue;
4235            }
4236            if (block == lastBlock) {
4237                 m = lastBM;
4238                 m.reset(str);
4239            } else {
4240                 m  = Pattern.compile("\\p{block=" + block.toString() + "}").matcher(str);
4241            }
4242            if (!m.matches()) {
4243                failCount++;
4244            }
4245            other = (block == Character.UnicodeBlock.BASIC_LATIN)? greek : latin;
4246            other.reset(str);
4247            if (other.matches()) {
4248                failCount++;
4249            }
4250            lastBM = m;
4251            lastBlock = block;
4252        }
4253        report("unicodeProperties");
4254    }
4255
4256    private static void unicodeHexNotationTest() throws Exception {
4257
4258        // negative
4259        checkExpectedFail("\\x{-23}");
4260        checkExpectedFail("\\x{110000}");
4261        checkExpectedFail("\\x{}");
4262        checkExpectedFail("\\x{AB[ef]");
4263
4264        // codepoint
4265        check("^\\x{1033c}$",              "\uD800\uDF3C", true);
4266        check("^\\xF0\\x90\\x8C\\xBC$",    "\uD800\uDF3C", false);
4267        check("^\\x{D800}\\x{DF3c}+$",     "\uD800\uDF3C", false);
4268        check("^\\xF0\\x90\\x8C\\xBC$",    "\uD800\uDF3C", false);
4269
4270        // in class
4271        check("^[\\x{D800}\\x{DF3c}]+$",   "\uD800\uDF3C", false);
4272        check("^[\\xF0\\x90\\x8C\\xBC]+$", "\uD800\uDF3C", false);
4273        check("^[\\x{D800}\\x{DF3C}]+$",   "\uD800\uDF3C", false);
4274        check("^[\\x{DF3C}\\x{D800}]+$",   "\uD800\uDF3C", false);
4275        check("^[\\x{D800}\\x{DF3C}]+$",   "\uDF3C\uD800", true);
4276        check("^[\\x{DF3C}\\x{D800}]+$",   "\uDF3C\uD800", true);
4277
4278        for (int cp = 0; cp <= 0x10FFFF; cp++) {
4279             String s = "A" + new String(Character.toChars(cp)) + "B";
4280             String hexUTF16 = (cp <= 0xFFFF)? String.format("\\u%04x", cp)
4281                                             : String.format("\\u%04x\\u%04x",
4282                                               (int) Character.toChars(cp)[0],
4283                                               (int) Character.toChars(cp)[1]);
4284             String hexCodePoint = "\\x{" + Integer.toHexString(cp) + "}";
4285             if (!Pattern.matches("A" + hexUTF16 + "B", s))
4286                 failCount++;
4287             if (!Pattern.matches("A[" + hexUTF16 + "]B", s))
4288                 failCount++;
4289             if (!Pattern.matches("A" + hexCodePoint + "B", s))
4290                 failCount++;
4291             if (!Pattern.matches("A[" + hexCodePoint + "]B", s))
4292                 failCount++;
4293         }
4294         report("unicodeHexNotation");
4295    }
4296
4297    private static void unicodeClassesTest() throws Exception {
4298
4299        Matcher lower  = Pattern.compile("\\p{Lower}").matcher("");
4300        Matcher upper  = Pattern.compile("\\p{Upper}").matcher("");
4301        Matcher ASCII  = Pattern.compile("\\p{ASCII}").matcher("");
4302        Matcher alpha  = Pattern.compile("\\p{Alpha}").matcher("");
4303        Matcher digit  = Pattern.compile("\\p{Digit}").matcher("");
4304        Matcher alnum  = Pattern.compile("\\p{Alnum}").matcher("");
4305        Matcher punct  = Pattern.compile("\\p{Punct}").matcher("");
4306        Matcher graph  = Pattern.compile("\\p{Graph}").matcher("");
4307        Matcher print  = Pattern.compile("\\p{Print}").matcher("");
4308        Matcher blank  = Pattern.compile("\\p{Blank}").matcher("");
4309        Matcher cntrl  = Pattern.compile("\\p{Cntrl}").matcher("");
4310        Matcher xdigit = Pattern.compile("\\p{XDigit}").matcher("");
4311        Matcher space  = Pattern.compile("\\p{Space}").matcher("");
4312        Matcher bound  = Pattern.compile("\\b").matcher("");
4313        Matcher word   = Pattern.compile("\\w++").matcher("");
4314        // UNICODE_CHARACTER_CLASS
4315        Matcher lowerU  = Pattern.compile("\\p{Lower}", Pattern.UNICODE_CHARACTER_CLASS).matcher("");
4316        Matcher upperU  = Pattern.compile("\\p{Upper}", Pattern.UNICODE_CHARACTER_CLASS).matcher("");
4317        Matcher ASCIIU  = Pattern.compile("\\p{ASCII}", Pattern.UNICODE_CHARACTER_CLASS).matcher("");
4318        Matcher alphaU  = Pattern.compile("\\p{Alpha}", Pattern.UNICODE_CHARACTER_CLASS).matcher("");
4319        Matcher digitU  = Pattern.compile("\\p{Digit}", Pattern.UNICODE_CHARACTER_CLASS).matcher("");
4320        Matcher alnumU  = Pattern.compile("\\p{Alnum}", Pattern.UNICODE_CHARACTER_CLASS).matcher("");
4321        Matcher punctU  = Pattern.compile("\\p{Punct}", Pattern.UNICODE_CHARACTER_CLASS).matcher("");
4322        Matcher graphU  = Pattern.compile("\\p{Graph}", Pattern.UNICODE_CHARACTER_CLASS).matcher("");
4323        Matcher printU  = Pattern.compile("\\p{Print}", Pattern.UNICODE_CHARACTER_CLASS).matcher("");
4324        Matcher blankU  = Pattern.compile("\\p{Blank}", Pattern.UNICODE_CHARACTER_CLASS).matcher("");
4325        Matcher cntrlU  = Pattern.compile("\\p{Cntrl}", Pattern.UNICODE_CHARACTER_CLASS).matcher("");
4326        Matcher xdigitU = Pattern.compile("\\p{XDigit}", Pattern.UNICODE_CHARACTER_CLASS).matcher("");
4327        Matcher spaceU  = Pattern.compile("\\p{Space}", Pattern.UNICODE_CHARACTER_CLASS).matcher("");
4328        Matcher boundU  = Pattern.compile("\\b", Pattern.UNICODE_CHARACTER_CLASS).matcher("");
4329        Matcher wordU   = Pattern.compile("\\w", Pattern.UNICODE_CHARACTER_CLASS).matcher("");
4330        // embedded flag (?U)
4331        Matcher lowerEU  = Pattern.compile("(?U)\\p{Lower}", Pattern.UNICODE_CHARACTER_CLASS).matcher("");
4332        Matcher graphEU  = Pattern.compile("(?U)\\p{Graph}", Pattern.UNICODE_CHARACTER_CLASS).matcher("");
4333        Matcher wordEU   = Pattern.compile("(?U)\\w", Pattern.UNICODE_CHARACTER_CLASS).matcher("");
4334
4335        Matcher bwb    = Pattern.compile("\\b\\w\\b").matcher("");
4336        Matcher bwbU   = Pattern.compile("\\b\\w++\\b", Pattern.UNICODE_CHARACTER_CLASS).matcher("");
4337        Matcher bwbEU  = Pattern.compile("(?U)\\b\\w++\\b", Pattern.UNICODE_CHARACTER_CLASS).matcher("");
4338        // properties
4339        Matcher lowerP  = Pattern.compile("\\p{IsLowerCase}").matcher("");
4340        Matcher upperP  = Pattern.compile("\\p{IsUpperCase}").matcher("");
4341        Matcher titleP  = Pattern.compile("\\p{IsTitleCase}").matcher("");
4342        Matcher letterP = Pattern.compile("\\p{IsLetter}").matcher("");
4343        Matcher alphaP  = Pattern.compile("\\p{IsAlphabetic}").matcher("");
4344        Matcher ideogP  = Pattern.compile("\\p{IsIdeographic}").matcher("");
4345        Matcher cntrlP  = Pattern.compile("\\p{IsControl}").matcher("");
4346        Matcher spaceP  = Pattern.compile("\\p{IsWhiteSpace}").matcher("");
4347        Matcher definedP = Pattern.compile("\\p{IsAssigned}").matcher("");
4348        Matcher nonCCPP = Pattern.compile("\\p{IsNoncharacterCodePoint}").matcher("");
4349        Matcher joinCrtl = Pattern.compile("\\p{IsJoinControl}").matcher("");
4350        // javaMethod
4351        Matcher lowerJ  = Pattern.compile("\\p{javaLowerCase}").matcher("");
4352        Matcher upperJ  = Pattern.compile("\\p{javaUpperCase}").matcher("");
4353        Matcher alphaJ  = Pattern.compile("\\p{javaAlphabetic}").matcher("");
4354        Matcher ideogJ  = Pattern.compile("\\p{javaIdeographic}").matcher("");
4355        // GC/C
4356        Matcher gcC  = Pattern.compile("\\p{C}").matcher("");
4357
4358        for (int cp = 1; cp < 0x30000; cp++) {
4359            String str = new String(Character.toChars(cp));
4360            int type = Character.getType(cp);
4361            if (// lower
4362                POSIX_ASCII.isLower(cp)   != lower.reset(str).matches()  ||
4363                Character.isLowerCase(cp) != lowerU.reset(str).matches() ||
4364                Character.isLowerCase(cp) != lowerP.reset(str).matches() ||
4365                Character.isLowerCase(cp) != lowerEU.reset(str).matches()||
4366                Character.isLowerCase(cp) != lowerJ.reset(str).matches()||
4367                // upper
4368                POSIX_ASCII.isUpper(cp)   != upper.reset(str).matches()  ||
4369                POSIX_Unicode.isUpper(cp) != upperU.reset(str).matches() ||
4370                Character.isUpperCase(cp) != upperP.reset(str).matches() ||
4371                Character.isUpperCase(cp) != upperJ.reset(str).matches() ||
4372                // alpha
4373                POSIX_ASCII.isAlpha(cp)   != alpha.reset(str).matches()  ||
4374                POSIX_Unicode.isAlpha(cp) != alphaU.reset(str).matches() ||
4375                Character.isAlphabetic(cp)!= alphaP.reset(str).matches() ||
4376                Character.isAlphabetic(cp)!= alphaJ.reset(str).matches() ||
4377                // digit
4378                POSIX_ASCII.isDigit(cp)   != digit.reset(str).matches()  ||
4379                Character.isDigit(cp)     != digitU.reset(str).matches() ||
4380                // alnum
4381                POSIX_ASCII.isAlnum(cp)   != alnum.reset(str).matches()  ||
4382                POSIX_Unicode.isAlnum(cp) != alnumU.reset(str).matches() ||
4383                // punct
4384                POSIX_ASCII.isPunct(cp)   != punct.reset(str).matches()  ||
4385                POSIX_Unicode.isPunct(cp) != punctU.reset(str).matches() ||
4386                // graph
4387                POSIX_ASCII.isGraph(cp)   != graph.reset(str).matches()  ||
4388                POSIX_Unicode.isGraph(cp) != graphU.reset(str).matches() ||
4389                POSIX_Unicode.isGraph(cp) != graphEU.reset(str).matches()||
4390                // blank
4391                POSIX_ASCII.isType(cp, POSIX_ASCII.BLANK)
4392                                          != blank.reset(str).matches()  ||
4393                POSIX_Unicode.isBlank(cp) != blankU.reset(str).matches() ||
4394                // print
4395                POSIX_ASCII.isPrint(cp)   != print.reset(str).matches()  ||
4396                POSIX_Unicode.isPrint(cp) != printU.reset(str).matches() ||
4397                // cntrl
4398                POSIX_ASCII.isCntrl(cp)   != cntrl.reset(str).matches()  ||
4399                POSIX_Unicode.isCntrl(cp) != cntrlU.reset(str).matches() ||
4400                (Character.CONTROL == type) != cntrlP.reset(str).matches() ||
4401                // hexdigit
4402                POSIX_ASCII.isHexDigit(cp)   != xdigit.reset(str).matches()  ||
4403                POSIX_Unicode.isHexDigit(cp) != xdigitU.reset(str).matches() ||
4404                // space
4405                POSIX_ASCII.isSpace(cp)   != space.reset(str).matches()  ||
4406                POSIX_Unicode.isSpace(cp) != spaceU.reset(str).matches() ||
4407                POSIX_Unicode.isSpace(cp) != spaceP.reset(str).matches() ||
4408                // word
4409                POSIX_ASCII.isWord(cp)   != word.reset(str).matches()  ||
4410                POSIX_Unicode.isWord(cp) != wordU.reset(str).matches() ||
4411                POSIX_Unicode.isWord(cp) != wordEU.reset(str).matches()||
4412                // bwordb
4413                POSIX_ASCII.isWord(cp) != bwb.reset(str).matches() ||
4414                POSIX_Unicode.isWord(cp) != bwbU.reset(str).matches() ||
4415                // properties
4416                Character.isTitleCase(cp) != titleP.reset(str).matches() ||
4417                Character.isLetter(cp)    != letterP.reset(str).matches()||
4418                Character.isIdeographic(cp) != ideogP.reset(str).matches() ||
4419                Character.isIdeographic(cp) != ideogJ.reset(str).matches() ||
4420                (Character.UNASSIGNED == type) == definedP.reset(str).matches() ||
4421                POSIX_Unicode.isNoncharacterCodePoint(cp) != nonCCPP.reset(str).matches() ||
4422                POSIX_Unicode.isJoinControl(cp) != joinCrtl.reset(str).matches() ||
4423                // gc_C
4424                (Character.CONTROL == type || Character.FORMAT == type ||
4425                 Character.PRIVATE_USE == type || Character.SURROGATE == type ||
4426                 Character.UNASSIGNED == type)
4427                != gcC.reset(str).matches()) {
4428                failCount++;
4429            }
4430        }
4431
4432        // bounds/word align
4433        twoFindIndexes(" \u0180sherman\u0400 ", bound, 1, 10);
4434        if (!bwbU.reset("\u0180sherman\u0400").matches())
4435            failCount++;
4436        twoFindIndexes(" \u0180sh\u0345erman\u0400 ", bound, 1, 11);
4437        if (!bwbU.reset("\u0180sh\u0345erman\u0400").matches())
4438            failCount++;
4439        twoFindIndexes(" \u0724\u0739\u0724 ", bound, 1, 4);
4440        if (!bwbU.reset("\u0724\u0739\u0724").matches())
4441            failCount++;
4442        if (!bwbEU.reset("\u0724\u0739\u0724").matches())
4443            failCount++;
4444        report("unicodePredefinedClasses");
4445    }
4446
4447    private static void unicodeCharacterNameTest() throws Exception {
4448
4449        for (int cp = 0; cp < Character.MAX_CODE_POINT; cp++) {
4450            if (!Character.isValidCodePoint(cp) ||
4451                Character.getType(cp) == Character.UNASSIGNED)
4452                continue;
4453            String str = new String(Character.toChars(cp));
4454            // single
4455            String p = "\\N{" + Character.getName(cp) + "}";
4456            if (!Pattern.compile(p).matcher(str).matches()) {
4457                failCount++;
4458            }
4459            // class[c]
4460            p = "[\\N{" + Character.getName(cp) + "}]";
4461            if (!Pattern.compile(p).matcher(str).matches()) {
4462                failCount++;
4463            }
4464        }
4465
4466        // range
4467        for (int i = 0; i < 10; i++) {
4468            int start = generator.nextInt(20);
4469            int end = start + generator.nextInt(200);
4470            String p = "[\\N{" + Character.getName(start) + "}-\\N{" + Character.getName(end) + "}]";
4471            String str;
4472            for (int cp = start; cp < end; cp++) {
4473                str = new String(Character.toChars(cp));
4474                if (!Pattern.compile(p).matcher(str).matches()) {
4475                    failCount++;
4476                }
4477            }
4478            str = new String(Character.toChars(end + 10));
4479            if (Pattern.compile(p).matcher(str).matches()) {
4480                failCount++;
4481            }
4482        }
4483
4484        // slice
4485        for (int i = 0; i < 10; i++) {
4486            int n = generator.nextInt(256);
4487            int[] buf = new int[n];
4488            StringBuffer sb = new StringBuffer(1024);
4489            for (int j = 0; j < n; j++) {
4490                int cp = generator.nextInt(1000);
4491                if (!Character.isValidCodePoint(cp) ||
4492                    Character.getType(cp) == Character.UNASSIGNED)
4493                    cp = 0x4e00;    // just use 4e00
4494                sb.append("\\N{" + Character.getName(cp) + "}");
4495                buf[j] = cp;
4496            }
4497            String p = sb.toString();
4498            String str = new String(buf, 0, buf.length);
4499            if (!Pattern.compile(p).matcher(str).matches()) {
4500                failCount++;
4501            }
4502        }
4503        report("unicodeCharacterName");
4504    }
4505
4506    private static void horizontalAndVerticalWSTest() throws Exception {
4507        String hws = new String (new char[] {
4508                                     0x09, 0x20, 0xa0, 0x1680, 0x180e,
4509                                     0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005,
4510                                     0x2006, 0x2007, 0x2008, 0x2009, 0x200a,
4511                                     0x202f, 0x205f, 0x3000 });
4512        String vws = new String (new char[] {
4513                                     0x0a, 0x0b, 0x0c, 0x0d, 0x85, 0x2028, 0x2029 });
4514        if (!Pattern.compile("\\h+").matcher(hws).matches() ||
4515            !Pattern.compile("[\\h]+").matcher(hws).matches())
4516            failCount++;
4517        if (Pattern.compile("\\H").matcher(hws).find() ||
4518            Pattern.compile("[\\H]").matcher(hws).find())
4519            failCount++;
4520        if (!Pattern.compile("\\v+").matcher(vws).matches() ||
4521            !Pattern.compile("[\\v]+").matcher(vws).matches())
4522            failCount++;
4523        if (Pattern.compile("\\V").matcher(vws).find() ||
4524            Pattern.compile("[\\V]").matcher(vws).find())
4525            failCount++;
4526        String prefix = "abcd";
4527        String suffix = "efgh";
4528        String ng = "A";
4529        for (int i = 0; i < hws.length(); i++) {
4530            String c = String.valueOf(hws.charAt(i));
4531            Matcher m = Pattern.compile("\\h").matcher(prefix + c + suffix);
4532            if (!m.find() || !c.equals(m.group()))
4533                failCount++;
4534            m = Pattern.compile("[\\h]").matcher(prefix + c + suffix);
4535            if (!m.find() || !c.equals(m.group()))
4536                failCount++;
4537
4538            m = Pattern.compile("\\H").matcher(hws.substring(0, i) + ng + hws.substring(i));
4539            if (!m.find() || !ng.equals(m.group()))
4540                failCount++;
4541            m = Pattern.compile("[\\H]").matcher(hws.substring(0, i) + ng + hws.substring(i));
4542            if (!m.find() || !ng.equals(m.group()))
4543                failCount++;
4544        }
4545        for (int i = 0; i < vws.length(); i++) {
4546            String c = String.valueOf(vws.charAt(i));
4547            Matcher m = Pattern.compile("\\v").matcher(prefix + c + suffix);
4548            if (!m.find() || !c.equals(m.group()))
4549                failCount++;
4550            m = Pattern.compile("[\\v]").matcher(prefix + c + suffix);
4551            if (!m.find() || !c.equals(m.group()))
4552                failCount++;
4553
4554            m = Pattern.compile("\\V").matcher(vws.substring(0, i) + ng + vws.substring(i));
4555            if (!m.find() || !ng.equals(m.group()))
4556                failCount++;
4557            m = Pattern.compile("[\\V]").matcher(vws.substring(0, i) + ng + vws.substring(i));
4558            if (!m.find() || !ng.equals(m.group()))
4559                failCount++;
4560        }
4561        // \v in range is interpreted as 0x0B. This is the undocumented behavior
4562        if (!Pattern.compile("[\\v-\\v]").matcher(String.valueOf((char)0x0B)).matches())
4563            failCount++;
4564        report("horizontalAndVerticalWSTest");
4565    }
4566
4567    private static void linebreakTest() throws Exception {
4568        String linebreaks = new String (new char[] {
4569            0x0A, 0x0B, 0x0C, 0x0D, 0x85, 0x2028, 0x2029 });
4570        String crnl = "\r\n";
4571        if (!(Pattern.compile("\\R+").matcher(linebreaks).matches() &&
4572              Pattern.compile("\\R").matcher(crnl).matches() &&
4573              Pattern.compile("\\Rabc").matcher(crnl + "abc").matches() &&
4574              Pattern.compile("\\Rabc").matcher("\rabc").matches() &&
4575              Pattern.compile("\\R\\R").matcher(crnl).matches() &&  // backtracking
4576              Pattern.compile("\\R\\n").matcher(crnl).matches()) && // backtracking
4577              !Pattern.compile("((?<!\\R)\\s)*").matcher(crnl).matches()) { // #8176029
4578            failCount++;
4579        }
4580        report("linebreakTest");
4581    }
4582
4583    // #7189363
4584    private static void branchTest() throws Exception {
4585        if (!Pattern.compile("(a)?bc|d").matcher("d").find() ||     // greedy
4586            !Pattern.compile("(a)+bc|d").matcher("d").find() ||
4587            !Pattern.compile("(a)*bc|d").matcher("d").find() ||
4588            !Pattern.compile("(a)??bc|d").matcher("d").find() ||    // reluctant
4589            !Pattern.compile("(a)+?bc|d").matcher("d").find() ||
4590            !Pattern.compile("(a)*?bc|d").matcher("d").find() ||
4591            !Pattern.compile("(a)?+bc|d").matcher("d").find() ||    // possessive
4592            !Pattern.compile("(a)++bc|d").matcher("d").find() ||
4593            !Pattern.compile("(a)*+bc|d").matcher("d").find() ||
4594            !Pattern.compile("(a)?bc|d").matcher("d").matches() ||  // greedy
4595            !Pattern.compile("(a)+bc|d").matcher("d").matches() ||
4596            !Pattern.compile("(a)*bc|d").matcher("d").matches() ||
4597            !Pattern.compile("(a)??bc|d").matcher("d").matches() || // reluctant
4598            !Pattern.compile("(a)+?bc|d").matcher("d").matches() ||
4599            !Pattern.compile("(a)*?bc|d").matcher("d").matches() ||
4600            !Pattern.compile("(a)?+bc|d").matcher("d").matches() || // possessive
4601            !Pattern.compile("(a)++bc|d").matcher("d").matches() ||
4602            !Pattern.compile("(a)*+bc|d").matcher("d").matches() ||
4603            !Pattern.compile("(a)?bc|de").matcher("de").find() ||   // others
4604            !Pattern.compile("(a)??bc|de").matcher("de").find() ||
4605            !Pattern.compile("(a)?bc|de").matcher("de").matches() ||
4606            !Pattern.compile("(a)??bc|de").matcher("de").matches())
4607            failCount++;
4608        report("branchTest");
4609    }
4610
4611    // This test is for 8007395
4612    private static void groupCurlyNotFoundSuppTest() throws Exception {
4613        String input = "test this as \ud83d\ude0d";
4614        for (String pStr : new String[] { "test(.)+(@[a-zA-Z.]+)",
4615                                          "test(.)*(@[a-zA-Z.]+)",
4616                                          "test([^B])+(@[a-zA-Z.]+)",
4617                                          "test([^B])*(@[a-zA-Z.]+)",
4618                                          "test(\\P{IsControl})+(@[a-zA-Z.]+)",
4619                                          "test(\\P{IsControl})*(@[a-zA-Z.]+)",
4620                                        }) {
4621            Matcher m = Pattern.compile(pStr, Pattern.CASE_INSENSITIVE)
4622                               .matcher(input);
4623            try {
4624                if (m.find()) {
4625                    failCount++;
4626                }
4627            } catch (Exception x) {
4628                failCount++;
4629            }
4630        }
4631        report("GroupCurly NotFoundSupp");
4632    }
4633
4634    // This test is for 8023647
4635    private static void groupCurlyBackoffTest() throws Exception {
4636        if (!"abc1c".matches("(\\w)+1\\1") ||
4637            "abc11".matches("(\\w)+1\\1")) {
4638            failCount++;
4639        }
4640        report("GroupCurly backoff");
4641    }
4642
4643    // This test is for 8012646
4644    private static void patternAsPredicate() throws Exception {
4645        Predicate<String> p = Pattern.compile("[a-z]+").asPredicate();
4646
4647        if (p.test("")) {
4648            failCount++;
4649        }
4650        if (!p.test("word")) {
4651            failCount++;
4652        }
4653        if (p.test("1234")) {
4654            failCount++;
4655        }
4656        report("Pattern.asPredicate");
4657    }
4658
4659    // This test is for 8035975
4660    private static void invalidFlags() throws Exception {
4661        for (int flag = 1; flag != 0; flag <<= 1) {
4662            switch (flag) {
4663            case Pattern.CASE_INSENSITIVE:
4664            case Pattern.MULTILINE:
4665            case Pattern.DOTALL:
4666            case Pattern.UNICODE_CASE:
4667            case Pattern.CANON_EQ:
4668            case Pattern.UNIX_LINES:
4669            case Pattern.LITERAL:
4670            case Pattern.UNICODE_CHARACTER_CLASS:
4671            case Pattern.COMMENTS:
4672                // valid flag, continue
4673                break;
4674            default:
4675                try {
4676                    Pattern.compile(".", flag);
4677                    failCount++;
4678                } catch (IllegalArgumentException expected) {
4679                }
4680            }
4681        }
4682        report("Invalid compile flags");
4683    }
4684
4685    // This test is for 8158482
4686    private static void embeddedFlags() throws Exception {
4687        try {
4688            Pattern.compile("(?i).(?-i).");
4689            Pattern.compile("(?m).(?-m).");
4690            Pattern.compile("(?s).(?-s).");
4691            Pattern.compile("(?d).(?-d).");
4692            Pattern.compile("(?u).(?-u).");
4693            Pattern.compile("(?c).(?-c).");
4694            Pattern.compile("(?x).(?-x).");
4695            Pattern.compile("(?U).(?-U).");
4696            Pattern.compile("(?imsducxU).(?-imsducxU).");
4697        } catch (PatternSyntaxException x) {
4698            failCount++;
4699        }
4700        report("Embedded flags");
4701    }
4702
4703    private static void grapheme() throws Exception {
4704        Files.lines(Paths.get(System.getProperty("test.src", "."),
4705                              "GraphemeBreakTest.txt"))
4706            .filter( ln -> ln.length() != 0 && !ln.startsWith("#") )
4707            .forEach( ln -> {
4708                    ln = ln.replaceAll("\\s+|\\([a-zA-Z]+\\)|\\[[a-zA-Z]]+\\]|#.*", "");
4709                    // System.out.println(str);
4710                    String[] strs = ln.split("\u00f7|\u00d7");
4711                    StringBuilder src = new StringBuilder();
4712                    ArrayList<String> graphemes = new ArrayList<>();
4713                    StringBuilder buf = new StringBuilder();
4714                    int offBk = 0;
4715                    for (String str : strs) {
4716                        if (str.length() == 0)  // first empty str
4717                            continue;
4718                        int cp = Integer.parseInt(str, 16);
4719                        src.appendCodePoint(cp);
4720                        buf.appendCodePoint(cp);
4721                        offBk += (str.length() + 1);
4722                        if (ln.charAt(offBk) == '\u00f7') {    // DIV
4723                            graphemes.add(buf.toString());
4724                            buf = new StringBuilder();
4725                        }
4726                    }
4727                    Pattern p = Pattern.compile("\\X");
4728                    Matcher m = p.matcher(src.toString());
4729                    Scanner s = new Scanner(src.toString()).useDelimiter("\\b{g}");
4730                    for (String g : graphemes) {
4731                        // System.out.printf("     grapheme:=[%s]%n", g);
4732                        // (1) test \\X directly
4733                        if (!m.find() || !m.group().equals(g)) {
4734                            System.out.println("Failed \\X [" + ln + "] : " + g);
4735                            failCount++;
4736                        }
4737                        // (2) test \\b{g} + \\X  via Scanner
4738                        boolean hasNext = s.hasNext(p);
4739                        // if (!s.hasNext() || !s.next().equals(next)) {
4740                        if (!s.hasNext(p) || !s.next(p).equals(g)) {
4741                            System.out.println("Failed b{g} [" + ln + "] : " + g);
4742                            failCount++;
4743                        }
4744                    }
4745                });
4746        // some sanity checks
4747        if (!Pattern.compile("\\X{10}").matcher("abcdefghij").matches() ||
4748            !Pattern.compile("\\b{g}(?:\\X\\b{g}){5}\\b{g}").matcher("abcde").matches() ||
4749            !Pattern.compile("(?:\\X\\b{g}){2}").matcher("\ud800\udc00\ud801\udc02").matches())
4750            failCount++;
4751        // make sure "\b{n}" still works
4752        if (!Pattern.compile("\\b{1}hello\\b{1} \\b{1}world\\b{1}").matcher("hello world").matches())
4753            failCount++;
4754        report("Unicode extended grapheme cluster");
4755    }
4756
4757    // hangup/timeout if go into exponential backtracking
4758    private static void expoBacktracking() throws Exception {
4759
4760        Object[][] patternMatchers = {
4761            // 6328855
4762            { "(.*\n*)*",
4763              "this little fine string lets\r\njava.lang.String.matches\r\ncrash\r\n(We don't know why but adding \r* to the regex makes it work again)",
4764              false },
4765            // 6192895
4766            { " *([a-zA-Z0-9/\\-\\?:\\(\\)\\.,'\\+\\{\\}]+ *)+",
4767              "Hello World this is a test this is a test this is a test A",
4768              true },
4769            { " *([a-zA-Z0-9/\\-\\?:\\(\\)\\.,'\\+\\{\\}]+ *)+",
4770              "Hello World this is a test this is a test this is a test \u4e00 ",
4771              false },
4772            { " *([a-z0-9]+ *)+",
4773              "hello world this is a test this is a test this is a test A",
4774              false },
4775            // 4771934 [FIXED] #5013651?
4776            { "^(\\w+([\\.-]?\\w+)*@\\w+([\\.-]?\\w+)*(\\.\\w{2,4})+[,;]?)+$",
4777              "abc@efg.abc,efg@abc.abc,abc@xyz.mno;abc@sdfsd.com",
4778              true },
4779            // 4866249 [FIXED]
4780            { "<\\s*" + "(meta|META)" + "(\\s|[^>])+" + "(CHARSET|charset)=" + "(\\s|[^>])+>",
4781              "<META http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-5\">",
4782              true },
4783            { "^(\\w+([\\.-]?\\w+)*@\\w+([\\.-]?\\w+)*(\\.\\w{2,4})+[,;]?)+$",
4784              "abc@efg.abc,efg@abc.abc,abc@xyz.mno;sdfsd.com",
4785              false },
4786            // 6345469
4787            { "((<[^>]+>)?(((\\s)?)*(\\&nbsp;)?)*((\\s)?)*)+",
4788              "&nbsp;&nbsp; < br/> &nbsp; < / p> <p> <html> <adfasfdasdf>&nbsp; </p>",
4789              true }, // --> matched
4790            { "((<[^>]+>)?(((\\s)?)*(\\&nbsp;)?)*((\\s)?)*)+",
4791              "&nbsp;&nbsp; < br/> &nbsp; < / p> <p> <html> <adfasfdasdf>&nbsp; p </p>",
4792              false },
4793            // 5026912
4794            { "^\\s*" + "(\\w|\\d|[\\xC0-\\xFF]|/)+" + "\\s+|$",
4795              "156580451111112225588087755221111111566969655555555",
4796              false},
4797            // 6988218
4798            { "^([+-]?((0[xX](\\p{XDigit}+))|(((\\p{Digit}+)(\\.)?((\\p{Digit}+)?)([eE][+-]?(\\p{Digit}+))?)|(\\.((\\p{Digit}+))([eE][+-]?(\\p{Digit}+))?)))|[n|N]?'([^']*(?:'')*[^']*)*')",
4799              "'%)) order by ANGEBOT.ID",
4800              false},    // find
4801            // 6693451
4802            { "^(\\s*foo\\s*)*$",
4803              "foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo",
4804              true },
4805            { "^(\\s*foo\\s*)*$",
4806              "foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo foo fo",
4807              false
4808            },
4809            // 7006761
4810            { "(([0-9A-Z]+)([_]?+)*)*", "FOOOOO_BAAAR_FOOOOOOOOO_BA_", true},
4811            { "(([0-9A-Z]+)([_]?+)*)*", "FOOOOO_BAAAR_FOOOOOOOOO_BA_ ", false},
4812            // 8140212
4813            { "(?<before>.*)\\{(?<reflection>\\w+):(?<innerMethod>\\w+(\\.?\\w+(\\(((?<args>(('[^']*')|((/|\\w)+))(,(('[^']*')|((/|\\w)+)))*))?\\))?)*)\\}(?<after>.*)",
4814              "{CeGlobal:getSodCutoff.getGui.getAmqp.getSimpleModeEnabled()",
4815              false
4816            },
4817            { "^(a+)+$", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", true},
4818            { "^(a+)+$", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa!", false},
4819
4820            { "(x+)*y",  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxy", true },
4821            { "(x+)*y",  "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxz", false},
4822
4823            { "(x+x+)+y", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxy", true},
4824            { "(x+x+)+y", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxz", false},
4825
4826            { "(([0-9A-Z]+)([_]?+)*)*", "--------------------------------------", false},
4827
4828            /* not fixed
4829            //8132141   --->    second level exponential backtracking
4830            { "(h|h|ih(((i|a|c|c|a|i|i|j|b|a|i|b|a|a|j))+h)ahbfhba|c|i)*",
4831              "hchcchicihcchciiicichhcichcihcchiihichiciiiihhcchicchhcihchcihiihciichhccciccichcichiihcchcihhicchcciicchcccihiiihhihihihichicihhcciccchihhhcchichchciihiicihciihcccciciccicciiiiiiiiicihhhiiiihchccchchhhhiiihchihcccchhhiiiiiiiicicichicihcciciihichhhhchihciiihhiccccccciciihhichiccchhicchicihihccichicciihcichccihhiciccccccccichhhhihihhcchchihihiihhihihihicichihiiiihhhhihhhchhichiicihhiiiiihchccccchichci" },
4832            */
4833        };
4834
4835        for (Object[] pm : patternMatchers) {
4836            String p = (String)pm[0];
4837            String s = (String)pm[1];
4838            boolean r = (Boolean)pm[2];
4839            if (r != Pattern.compile(p).matcher(s).matches()) {
4840                failCount++;
4841            }
4842        }
4843    }
4844}
4845