alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Java example source code file (RETest.java)

This example Java source code file (RETest.java) is included in the alvinalexander.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Learn more about this Java project at its project page.

Java - Java tags/keywords

abcddddd, bufferedreader, did, exception, match, matcher, new_line, printwriter, retest, retestcase, string, wrong

The RETest.java Java example source code

/*
 * 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
 * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens
 * @author <a href="mailto:gholam@xtra.co.nz">Michael McCallum
 */
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", RE.REPLACE_BACKREFERENCES);
        assertEquals("Wrong subst() result", "visit us: 1234<a href=\"http://www.apache.org\">http://www.apache.org!", 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 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 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);
        }
    }
}

Other Java examples (source code examples)

Here is a short list of links related to this Java RETest.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2024 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.