jaxp/src/com/sun/org/apache/regexp/internal/RETest.java
changeset 12457 c348e06f0e82
parent 6 7f561c08de6b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jaxp/src/com/sun/org/apache/regexp/internal/RETest.java	Thu Apr 12 08:38:26 2012 -0700
@@ -0,0 +1,883 @@
+/*
+ * reserved comment block
+ * DO NOT REMOVE OR ALTER!
+ */
+/*
+ * Copyright 1999-2004 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.sun.org.apache.regexp.internal;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.io.File;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectOutputStream;
+import java.io.ByteArrayInputStream;
+import java.io.ObjectInputStream;
+import java.io.StringBufferInputStream;
+import java.io.StringReader;
+import java.io.IOException;
+
+/**
+ * Data driven (and optionally interactive) testing harness to exercise regular
+ * expression compiler and matching engine.
+ *
+ * @author <a href="mailto:jonl@muppetlabs.com">Jonathan Locke</a>
+ * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
+ * @author <a href="mailto:gholam@xtra.co.nz">Michael McCallum</a>
+ */
+public class RETest
+{
+    // True if we want to see output from success cases
+    static final boolean showSuccesses = false;
+
+    // A new line character.
+    static final String NEW_LINE = System.getProperty( "line.separator" );
+
+    // Construct a debug compiler
+    REDebugCompiler compiler = new REDebugCompiler();
+
+    /**
+     * Main program entrypoint.  If an argument is given, it will be compiled
+     * and interactive matching will ensue.  If no argument is given, the
+     * file RETest.txt will be used as automated testing input.
+     * @param args Command line arguments (optional regular expression)
+     */
+    public static void main(String[] args)
+    {
+        try
+        {
+            if (!test( args )) {
+                System.exit(1);
+            }
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+            System.exit(1);
+        }
+    }
+
+    /**
+     * Testing entrypoint.
+     * @param args Command line arguments
+     * @exception Exception thrown in case of error
+     */
+    public static boolean test( String[] args ) throws Exception
+    {
+        RETest test = new RETest();
+        // Run interactive tests against a single regexp
+        if (args.length == 2)
+        {
+            test.runInteractiveTests(args[1]);
+        }
+        else if (args.length == 1)
+        {
+            // Run automated tests
+            test.runAutomatedTests(args[0]);
+        }
+        else
+        {
+            System.out.println( "Usage: RETest ([-i] [regex]) ([/path/to/testfile.txt])" );
+            System.out.println( "By Default will run automated tests from file 'docs/RETest.txt' ..." );
+            System.out.println();
+            test.runAutomatedTests("docs/RETest.txt");
+        }
+        return test.failures == 0;
+    }
+
+    /**
+     * Constructor
+     */
+    public RETest()
+    {
+    }
+
+    /**
+     * Compile and test matching against a single expression
+     * @param expr Expression to compile and test
+     */
+    void runInteractiveTests(String expr)
+    {
+        RE r = new RE();
+        try
+        {
+            // Compile expression
+            r.setProgram(compiler.compile(expr));
+
+            // Show expression
+            say("" + NEW_LINE + "" + expr + "" + NEW_LINE + "");
+
+            // Show program for compiled expression
+            PrintWriter writer = new PrintWriter( System.out );
+            compiler.dumpProgram( writer );
+            writer.flush();
+
+            boolean running = true;
+            // Test matching against compiled expression
+            while ( running )
+            {
+                // Read from keyboard
+                BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
+                System.out.print("> ");
+                System.out.flush();
+                String match = br.readLine();
+
+                if ( match != null )
+                {
+                    // Try a match against the keyboard input
+                    if (r.match(match))
+                    {
+                        say("Match successful.");
+                    }
+                    else
+                    {
+                        say("Match failed.");
+                    }
+
+                    // Show subparen registers
+                    showParens(r);
+                }
+                else
+                {
+                    running = false;
+                    System.out.println();
+                }
+            }
+        }
+        catch (Exception e)
+        {
+            say("Error: " + e.toString());
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * Exit with a fatal error.
+     * @param s Last famous words before exiting
+     */
+    void die(String s)
+    {
+        say("FATAL ERROR: " + s);
+        System.exit(-1);
+    }
+
+    /**
+     * Fail with an error. Will print a big failure message to System.out.
+     *
+     * @param log Output before failure
+     * @param s Failure description
+     */
+    void fail(StringBuffer log, String s)
+    {
+        System.out.print(log.toString());
+        fail(s);
+    }
+
+    /**
+     * Fail with an error. Will print a big failure message to System.out.
+     *
+     * @param s Failure description
+     */
+    void fail(String s)
+    {
+        failures++;
+        say("" + NEW_LINE + "");
+        say("*******************************************************");
+        say("*********************  FAILURE!  **********************");
+        say("*******************************************************");
+        say("" + NEW_LINE + "");
+        say(s);
+        say("");
+        // make sure the writer gets flushed.
+        if (compiler != null) {
+            PrintWriter writer = new PrintWriter( System.out );
+            compiler.dumpProgram( writer );
+            writer.flush();
+            say("" + NEW_LINE + "");
+        }
+    }
+
+    /**
+     * Say something to standard out
+     * @param s What to say
+     */
+    void say(String s)
+    {
+        System.out.println(s);
+    }
+
+    /**
+     * Dump parenthesized subexpressions found by a regular expression matcher object
+     * @param r Matcher object with results to show
+     */
+    void showParens(RE r)
+    {
+        // Loop through each paren
+        for (int i = 0; i < r.getParenCount(); i++)
+        {
+            // Show paren register
+            say("$" + i + " = " + r.getParen(i));
+        }
+    }
+
+    /*
+     * number in automated test
+     */
+    int testCount = 0;
+
+    /*
+     * Count of failures in automated test
+     */
+    int failures = 0;
+
+    /**
+     * Run automated tests in RETest.txt file (from Perl 4.0 test battery)
+     * @exception Exception thrown in case of error
+     */
+    void runAutomatedTests(String testDocument) throws Exception
+    {
+        long ms = System.currentTimeMillis();
+
+        // Some unit tests
+        testPrecompiledRE();
+        testSplitAndGrep();
+        testSubst();
+        testOther();
+
+        // Test from script file
+        File testInput = new File(testDocument);
+        if (! testInput.exists()) {
+            throw new Exception ("Could not find: " + testDocument);
+        }
+
+        BufferedReader br = new BufferedReader(new FileReader(testInput));
+        try
+        {
+            // While input is available, parse lines
+            while (br.ready())
+            {
+                RETestCase testcase = getNextTestCase(br);
+                if (testcase != null) {
+                    testcase.runTest();
+                }
+            }
+        }
+        finally
+        {
+            br.close();
+        }
+
+        // Show match time
+        say(NEW_LINE + NEW_LINE + "Match time = " + (System.currentTimeMillis() - ms) + " ms.");
+
+        // Print final results
+        if (failures > 0) {
+            say("*************** THERE ARE FAILURES! *******************");
+        }
+        say("Tests complete.  " + testCount + " tests, " + failures + " failure(s).");
+    }
+
+    /**
+     * Run automated unit test
+     * @exception Exception thrown in case of error
+     */
+    void testOther() throws Exception
+    {
+        // Serialization test 1: Compile regexp and serialize/deserialize it
+        RE r = new RE("(a*)b");
+        say("Serialized/deserialized (a*)b");
+        ByteArrayOutputStream out = new ByteArrayOutputStream(128);
+        new ObjectOutputStream(out).writeObject(r);
+        ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
+        r = (RE)new ObjectInputStream(in).readObject();
+        if (!r.match("aaab"))
+        {
+            fail("Did not match 'aaab' with deserialized RE.");
+        } else {
+            say("aaaab = true");
+            showParens(r);
+        }
+
+        // Serialization test 2: serialize/deserialize used regexp
+        out.reset();
+        say("Deserialized (a*)b");
+        new ObjectOutputStream(out).writeObject(r);
+        in = new ByteArrayInputStream(out.toByteArray());
+        r = (RE)new ObjectInputStream(in).readObject();
+        if (r.getParenCount() != 0)
+        {
+            fail("Has parens after deserialization.");
+        }
+        if (!r.match("aaab"))
+        {
+            fail("Did not match 'aaab' with deserialized RE.");
+        } else {
+            say("aaaab = true");
+            showParens(r);
+        }
+
+        // Test MATCH_CASEINDEPENDENT
+        r = new RE("abc(\\w*)");
+        say("MATCH_CASEINDEPENDENT abc(\\w*)");
+        r.setMatchFlags(RE.MATCH_CASEINDEPENDENT);
+        say("abc(d*)");
+        if (!r.match("abcddd"))
+        {
+            fail("Did not match 'abcddd'.");
+        } else {
+            say("abcddd = true");
+            showParens(r);
+        }
+
+        if (!r.match("aBcDDdd"))
+        {
+            fail("Did not match 'aBcDDdd'.");
+        } else {
+            say("aBcDDdd = true");
+            showParens(r);
+        }
+
+        if (!r.match("ABCDDDDD"))
+        {
+            fail("Did not match 'ABCDDDDD'.");
+        } else {
+            say("ABCDDDDD = true");
+            showParens(r);
+        }
+
+        r = new RE("(A*)b\\1");
+        r.setMatchFlags(RE.MATCH_CASEINDEPENDENT);
+        if (!r.match("AaAaaaBAAAAAA"))
+        {
+            fail("Did not match 'AaAaaaBAAAAAA'.");
+        } else {
+            say("AaAaaaBAAAAAA = true");
+            showParens(r);
+        }
+
+        r = new RE("[A-Z]*");
+        r.setMatchFlags(RE.MATCH_CASEINDEPENDENT);
+        if (!r.match("CaBgDe12"))
+        {
+            fail("Did not match 'CaBgDe12'.");
+        } else {
+            say("CaBgDe12 = true");
+            showParens(r);
+        }
+
+        // Test MATCH_MULTILINE. Test for eol/bol symbols.
+        r = new RE("^abc$", RE.MATCH_MULTILINE);
+        if (!r.match("\nabc")) {
+            fail("\"\\nabc\" doesn't match \"^abc$\"");
+        }
+        if (!r.match("\rabc")) {
+            fail("\"\\rabc\" doesn't match \"^abc$\"");
+        }
+        if (!r.match("\r\nabc")) {
+            fail("\"\\r\\nabc\" doesn't match \"^abc$\"");
+        }
+        if (!r.match("\u0085abc")) {
+            fail("\"\\u0085abc\" doesn't match \"^abc$\"");
+        }
+        if (!r.match("\u2028abc")) {
+            fail("\"\\u2028abc\" doesn't match \"^abc$\"");
+        }
+        if (!r.match("\u2029abc")) {
+            fail("\"\\u2029abc\" doesn't match \"^abc$\"");
+        }
+
+        // Test MATCH_MULTILINE. Test that '.' does not matches new line.
+        r = new RE("^a.*b$", RE.MATCH_MULTILINE);
+        if (r.match("a\nb")) {
+            fail("\"a\\nb\" matches \"^a.*b$\"");
+        }
+        if (r.match("a\rb")) {
+            fail("\"a\\rb\" matches \"^a.*b$\"");
+        }
+        if (r.match("a\r\nb")) {
+            fail("\"a\\r\\nb\" matches \"^a.*b$\"");
+        }
+        if (r.match("a\u0085b")) {
+            fail("\"a\\u0085b\" matches \"^a.*b$\"");
+        }
+        if (r.match("a\u2028b")) {
+            fail("\"a\\u2028b\" matches \"^a.*b$\"");
+        }
+        if (r.match("a\u2029b")) {
+            fail("\"a\\u2029b\" matches \"^a.*b$\"");
+        }
+    }
+
+    private void testPrecompiledRE()
+    {
+        // Pre-compiled regular expression "a*b"
+        char[] re1Instructions =
+        {
+            0x007c, 0x0000, 0x001a, 0x007c, 0x0000, 0x000d, 0x0041,
+            0x0001, 0x0004, 0x0061, 0x007c, 0x0000, 0x0003, 0x0047,
+            0x0000, 0xfff6, 0x007c, 0x0000, 0x0003, 0x004e, 0x0000,
+            0x0003, 0x0041, 0x0001, 0x0004, 0x0062, 0x0045, 0x0000,
+            0x0000,
+        };
+
+        REProgram re1 = new REProgram(re1Instructions);
+
+        // Simple test of pre-compiled regular expressions
+        RE r = new RE(re1);
+        say("a*b");
+        boolean result = r.match("aaab");
+        say("aaab = " + result);
+        showParens(r);
+        if (!result) {
+            fail("\"aaab\" doesn't match to precompiled \"a*b\"");
+        }
+
+        result = r.match("b");
+        say("b = " + result);
+        showParens(r);
+        if (!result) {
+            fail("\"b\" doesn't match to precompiled \"a*b\"");
+        }
+
+        result = r.match("c");
+        say("c = " + result);
+        showParens(r);
+        if (result) {
+            fail("\"c\" matches to precompiled \"a*b\"");
+        }
+
+        result = r.match("ccccaaaaab");
+        say("ccccaaaaab = " + result);
+        showParens(r);
+        if (!result) {
+            fail("\"ccccaaaaab\" doesn't match to precompiled \"a*b\"");
+        }
+    }
+
+    private void testSplitAndGrep()
+    {
+        String[] expected = {"xxxx", "xxxx", "yyyy", "zzz"};
+        RE r = new RE("a*b");
+        String[] s = r.split("xxxxaabxxxxbyyyyaaabzzz");
+        for (int i = 0; i < expected.length && i < s.length; i++) {
+            assertEquals("Wrong splitted part", expected[i], s[i]);
+        }
+        assertEquals("Wrong number of splitted parts", expected.length,
+                     s.length);
+
+        r = new RE("x+");
+        expected = new String[] {"xxxx", "xxxx"};
+        s = r.grep(s);
+        for (int i = 0; i < s.length; i++)
+        {
+            say("s[" + i + "] = " + s[i]);
+            assertEquals("Grep fails", expected[i], s[i]);
+        }
+        assertEquals("Wrong number of string found by grep", expected.length,
+                     s.length);
+    }
+
+    private void testSubst()
+    {
+        RE r = new RE("a*b");
+        String expected = "-foo-garply-wacky-";
+        String actual = r.subst("aaaabfooaaabgarplyaaabwackyb", "-");
+        assertEquals("Wrong result of substitution in \"a*b\"", expected, actual);
+
+        // Test subst() with backreferences
+        r = new RE("http://[\\.\\w\\-\\?/~_@&=%]+");
+        actual = r.subst("visit us: http://www.apache.org!",
+                         "1234<a href=\"$0\">$0</a>", RE.REPLACE_BACKREFERENCES);
+        assertEquals("Wrong subst() result", "visit us: 1234<a href=\"http://www.apache.org\">http://www.apache.org</a>!", actual);
+
+        // Test subst() with backreferences without leading characters
+        // before first backreference
+        r = new RE("(.*?)=(.*)");
+        actual = r.subst("variable=value",
+                         "$1_test_$212", RE.REPLACE_BACKREFERENCES);
+        assertEquals("Wrong subst() result", "variable_test_value12", actual);
+
+        // Test subst() with NO backreferences
+        r = new RE("^a$");
+        actual = r.subst("a",
+                         "b", RE.REPLACE_BACKREFERENCES);
+        assertEquals("Wrong subst() result", "b", actual);
+
+        // Test subst() with NO backreferences
+        r = new RE("^a$", RE.MATCH_MULTILINE);
+        actual = r.subst("\r\na\r\n",
+                         "b", RE.REPLACE_BACKREFERENCES);
+        assertEquals("Wrong subst() result", "\r\nb\r\n", actual);
+    }
+
+    public void assertEquals(String message, String expected, String actual)
+    {
+        if (expected != null && !expected.equals(actual)
+            || actual != null && !actual.equals(expected))
+        {
+            fail(message + " (expected \"" + expected
+                 + "\", actual \"" + actual + "\")");
+        }
+    }
+
+    public void assertEquals(String message, int expected, int actual)
+    {
+        if (expected != actual) {
+            fail(message + " (expected \"" + expected
+                 + "\", actual \"" + actual + "\")");
+        }
+    }
+
+    /**
+     * Converts yesno string to boolean.
+     * @param yesno string representation of expected result
+     * @return true if yesno is "YES", false if yesno is "NO"
+     *         stops program otherwise.
+     */
+    private boolean getExpectedResult(String yesno)
+    {
+        if ("NO".equals(yesno))
+        {
+            return false;
+        }
+        else if ("YES".equals(yesno))
+        {
+            return true;
+        }
+        else
+        {
+            // Bad test script
+            die("Test script error!");
+            return false; //to please javac
+        }
+    }
+
+    /**
+     * Finds next test description in a given script.
+     * @param br <code>BufferedReader</code> for a script file
+     * @return strign tag for next test description
+     * @exception IOException if some io problems occured
+     */
+    private String findNextTest(BufferedReader br) throws IOException
+    {
+        String number = "";
+
+        while (br.ready())
+        {
+            number = br.readLine();
+            if (number == null)
+            {
+                break;
+            }
+            number = number.trim();
+            if (number.startsWith("#"))
+            {
+                break;
+            }
+            if (!number.equals(""))
+            {
+                say("Script error.  Line = " + number);
+                System.exit(-1);
+            }
+        }
+        return number;
+    }
+
+    /**
+     * Creates testcase for the next test description in the script file.
+     * @param br <code>BufferedReader</code> for script file.
+     * @return a new tescase or null.
+     * @exception IOException if some io problems occured
+     */
+    private RETestCase getNextTestCase(BufferedReader br) throws IOException
+    {
+        // Find next re test case
+        final String tag = findNextTest(br);
+
+        // Are we done?
+        if (!br.ready())
+        {
+            return null;
+        }
+
+        // Get expression
+        final String expr = br.readLine();
+
+        // Get test information
+        final String matchAgainst = br.readLine();
+        final boolean badPattern = "ERR".equals(matchAgainst);
+        boolean shouldMatch = false;
+        int expectedParenCount = 0;
+        String[] expectedParens = null;
+
+        if (!badPattern) {
+            shouldMatch = getExpectedResult(br.readLine().trim());
+            if (shouldMatch) {
+                expectedParenCount = Integer.parseInt(br.readLine().trim());
+                expectedParens = new String[expectedParenCount];
+                for (int i = 0; i < expectedParenCount; i++) {
+                    expectedParens[i] = br.readLine();
+                }
+            }
+        }
+
+        return new RETestCase(this, tag, expr, matchAgainst, badPattern,
+                              shouldMatch, expectedParens);
+    }
+}
+
+final class RETestCase
+{
+    final private StringBuffer log = new StringBuffer();
+    final private int number;
+    final private String tag; // number from script file
+    final private String pattern;
+    final private String toMatch;
+    final private boolean badPattern;
+    final private boolean shouldMatch;
+    final private String[] parens;
+    final private RETest test;
+    private RE regexp;
+
+    public RETestCase(RETest test, String tag, String pattern,
+                      String toMatch, boolean badPattern,
+                      boolean shouldMatch, String[] parens)
+    {
+        this.number = ++test.testCount;
+        this.test = test;
+        this.tag = tag;
+        this.pattern = pattern;
+        this.toMatch = toMatch;
+        this.badPattern = badPattern;
+        this.shouldMatch = shouldMatch;
+        if (parens != null) {
+            this.parens = new String[parens.length];
+            for (int i = 0; i < parens.length; i++) {
+                this.parens[i] = parens[i];
+            }
+        } else {
+            this.parens = null;
+        }
+    }
+
+    public void runTest()
+    {
+        test.say(tag + "(" + number + "): " + pattern);
+        if (testCreation()) {
+            testMatch();
+        }
+    }
+
+    boolean testCreation()
+    {
+        try
+        {
+            // Compile it
+            regexp = new RE();
+            regexp.setProgram(test.compiler.compile(pattern));
+            // Expression didn't cause an expected error
+            if (badPattern)
+            {
+                test.fail(log, "Was expected to be an error, but wasn't.");
+                return false;
+            }
+
+            return true;
+        }
+        // Some expressions *should* cause exceptions to be thrown
+        catch (Exception e)
+        {
+            // If it was supposed to be an error, report success and continue
+            if (badPattern)
+            {
+                log.append("   Match: ERR\n");
+                success("Produces an error (" + e.toString() + "), as expected.");
+                return false;
+            }
+
+            // Wasn't supposed to be an error
+            String message = (e.getMessage() == null) ? e.toString() : e.getMessage();
+            test.fail(log, "Produces an unexpected exception \"" + message + "\"");
+            e.printStackTrace();
+        }
+        catch (Error e)
+        {
+            // Internal error happened
+            test.fail(log, "Compiler threw fatal error \"" + e.getMessage() + "\"");
+            e.printStackTrace();
+        }
+
+        return false;
+    }
+
+    private void testMatch()
+    {
+        log.append("   Match against: '" + toMatch + "'\n");
+        // Try regular matching
+        try
+        {
+            // Match against the string
+            boolean result = regexp.match(toMatch);
+            log.append("   Matched: " + (result ? "YES" : "NO") + "\n");
+
+            // Check result, parens, and iterators
+            if (checkResult(result) && (!shouldMatch || checkParens()))
+            {
+                // test match(CharacterIterator, int)
+                // for every CharacterIterator implementation.
+                log.append("   Match using StringCharacterIterator\n");
+                if (!tryMatchUsingCI(new StringCharacterIterator(toMatch)))
+                    return;
+
+                log.append("   Match using CharacterArrayCharacterIterator\n");
+                if (!tryMatchUsingCI(new CharacterArrayCharacterIterator(toMatch.toCharArray(), 0, toMatch.length())))
+                    return;
+
+                log.append("   Match using StreamCharacterIterator\n");
+                if (!tryMatchUsingCI(new StreamCharacterIterator(new StringBufferInputStream(toMatch))))
+                    return;
+
+                log.append("   Match using ReaderCharacterIterator\n");
+                if (!tryMatchUsingCI(new ReaderCharacterIterator(new StringReader(toMatch))))
+                    return;
+            }
+        }
+        // Matcher blew it
+        catch(Exception e)
+        {
+            test.fail(log, "Matcher threw exception: " + e.toString());
+            e.printStackTrace();
+        }
+        // Internal error
+        catch(Error e)
+        {
+            test.fail(log, "Matcher threw fatal error \"" + e.getMessage() + "\"");
+            e.printStackTrace();
+        }
+    }
+
+    private boolean checkResult(boolean result)
+    {
+        // Write status
+        if (result == shouldMatch) {
+            success((shouldMatch ? "Matched" : "Did not match")
+                    + " \"" + toMatch + "\", as expected:");
+            return true;
+        } else {
+            if (shouldMatch) {
+                test.fail(log, "Did not match \"" + toMatch + "\", when expected to.");
+            } else {
+                test.fail(log, "Matched \"" + toMatch + "\", when not expected to.");
+            }
+            return false;
+        }
+    }
+
+    private boolean checkParens()
+    {
+        // Show subexpression registers
+        if (RETest.showSuccesses)
+        {
+            test.showParens(regexp);
+        }
+
+        log.append("   Paren count: " + regexp.getParenCount() + "\n");
+        if (!assertEquals(log, "Wrong number of parens", parens.length, regexp.getParenCount()))
+        {
+            return false;
+        }
+
+        // Check registers against expected contents
+        for (int p = 0; p < regexp.getParenCount(); p++)
+        {
+            log.append("   Paren " + p + ": " + regexp.getParen(p) + "\n");
+
+            // Compare expected result with actual
+            if ("null".equals(parens[p]) && regexp.getParen(p) == null)
+            {
+                // Consider "null" in test file equal to null
+                continue;
+            }
+            if (!assertEquals(log, "Wrong register " + p, parens[p], regexp.getParen(p)))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    boolean tryMatchUsingCI(CharacterIterator matchAgainst)
+    {
+        try {
+            boolean result = regexp.match(matchAgainst, 0);
+            log.append("   Match: " + (result ? "YES" : "NO") + "\n");
+            return checkResult(result) && (!shouldMatch || checkParens());
+        }
+        // Matcher blew it
+        catch(Exception e)
+        {
+            test.fail(log, "Matcher threw exception: " + e.toString());
+            e.printStackTrace();
+        }
+        // Internal error
+        catch(Error e)
+        {
+            test.fail(log, "Matcher threw fatal error \"" + e.getMessage() + "\"");
+            e.printStackTrace();
+        }
+        return false;
+    }
+
+    public boolean assertEquals(StringBuffer log, String message, String expected, String actual)
+    {
+        if (expected != null && !expected.equals(actual)
+            || actual != null && !actual.equals(expected))
+        {
+            test.fail(log, message + " (expected \"" + expected
+                      + "\", actual \"" + actual + "\")");
+            return false;
+        }
+        return true;
+    }
+
+    public boolean assertEquals(StringBuffer log, String message, int expected, int actual)
+    {
+        if (expected != actual) {
+            test.fail(log, message + " (expected \"" + expected
+                      + "\", actual \"" + actual + "\")");
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Show a success
+     * @param s Success story
+     */
+    void success(String s)
+    {
+        if (RETest.showSuccesses)
+        {
+            test.say("" + RETest.NEW_LINE + "-----------------------" + RETest.NEW_LINE + "");
+            test.say("Expression #" + (number) + " \"" + pattern + "\" ");
+            test.say("Success: " + s);
+        }
+    }
+}