jaxp/src/java.xml/share/classes/com/sun/org/apache/regexp/internal/RETest.java
changeset 37947 f69560487686
parent 37946 e420b9f05aaf
parent 37936 428ebc487445
child 37948 caf97b37ebec
equal deleted inserted replaced
37946:e420b9f05aaf 37947:f69560487686
     1 /*
       
     2  * reserved comment block
       
     3  * DO NOT REMOVE OR ALTER!
       
     4  */
       
     5 /*
       
     6  * Copyright 1999-2004 The Apache Software Foundation.
       
     7  *
       
     8  * Licensed under the Apache License, Version 2.0 (the "License");
       
     9  * you may not use this file except in compliance with the License.
       
    10  * You may obtain a copy of the License at
       
    11  *
       
    12  *     http://www.apache.org/licenses/LICENSE-2.0
       
    13  *
       
    14  * Unless required by applicable law or agreed to in writing, software
       
    15  * distributed under the License is distributed on an "AS IS" BASIS,
       
    16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    17  * See the License for the specific language governing permissions and
       
    18  * limitations under the License.
       
    19  */
       
    20 
       
    21 package com.sun.org.apache.regexp.internal;
       
    22 
       
    23 import java.io.BufferedReader;
       
    24 import java.io.FileReader;
       
    25 import java.io.InputStreamReader;
       
    26 import java.io.PrintWriter;
       
    27 import java.io.File;
       
    28 import java.io.ByteArrayOutputStream;
       
    29 import java.io.ObjectOutputStream;
       
    30 import java.io.ByteArrayInputStream;
       
    31 import java.io.ObjectInputStream;
       
    32 import java.io.StringBufferInputStream;
       
    33 import java.io.StringReader;
       
    34 import java.io.IOException;
       
    35 
       
    36 /**
       
    37  * Data driven (and optionally interactive) testing harness to exercise regular
       
    38  * expression compiler and matching engine.
       
    39  *
       
    40  * @author <a href="mailto:jonl@muppetlabs.com">Jonathan Locke</a>
       
    41  * @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
       
    42  * @author <a href="mailto:gholam@xtra.co.nz">Michael McCallum</a>
       
    43  */
       
    44 public class RETest
       
    45 {
       
    46     // True if we want to see output from success cases
       
    47     static final boolean showSuccesses = false;
       
    48 
       
    49     // A new line character.
       
    50     static final String NEW_LINE = System.getProperty( "line.separator" );
       
    51 
       
    52     // Construct a debug compiler
       
    53     REDebugCompiler compiler = new REDebugCompiler();
       
    54 
       
    55     /**
       
    56      * Main program entrypoint.  If an argument is given, it will be compiled
       
    57      * and interactive matching will ensue.  If no argument is given, the
       
    58      * file RETest.txt will be used as automated testing input.
       
    59      * @param args Command line arguments (optional regular expression)
       
    60      */
       
    61     public static void main(String[] args)
       
    62     {
       
    63         try
       
    64         {
       
    65             if (!test( args )) {
       
    66                 System.exit(1);
       
    67             }
       
    68         }
       
    69         catch (Exception e)
       
    70         {
       
    71             e.printStackTrace();
       
    72             System.exit(1);
       
    73         }
       
    74     }
       
    75 
       
    76     /**
       
    77      * Testing entrypoint.
       
    78      * @param args Command line arguments
       
    79      * @exception Exception thrown in case of error
       
    80      */
       
    81     public static boolean test( String[] args ) throws Exception
       
    82     {
       
    83         RETest test = new RETest();
       
    84         // Run interactive tests against a single regexp
       
    85         if (args.length == 2)
       
    86         {
       
    87             test.runInteractiveTests(args[1]);
       
    88         }
       
    89         else if (args.length == 1)
       
    90         {
       
    91             // Run automated tests
       
    92             test.runAutomatedTests(args[0]);
       
    93         }
       
    94         else
       
    95         {
       
    96             System.out.println( "Usage: RETest ([-i] [regex]) ([/path/to/testfile.txt])" );
       
    97             System.out.println( "By Default will run automated tests from file 'docs/RETest.txt' ..." );
       
    98             System.out.println();
       
    99             test.runAutomatedTests("docs/RETest.txt");
       
   100         }
       
   101         return test.failures == 0;
       
   102     }
       
   103 
       
   104     /**
       
   105      * Constructor
       
   106      */
       
   107     public RETest()
       
   108     {
       
   109     }
       
   110 
       
   111     /**
       
   112      * Compile and test matching against a single expression
       
   113      * @param expr Expression to compile and test
       
   114      */
       
   115     void runInteractiveTests(String expr)
       
   116     {
       
   117         RE r = new RE();
       
   118         try
       
   119         {
       
   120             // Compile expression
       
   121             r.setProgram(compiler.compile(expr));
       
   122 
       
   123             // Show expression
       
   124             say("" + NEW_LINE + "" + expr + "" + NEW_LINE + "");
       
   125 
       
   126             // Show program for compiled expression
       
   127             PrintWriter writer = new PrintWriter( System.out );
       
   128             compiler.dumpProgram( writer );
       
   129             writer.flush();
       
   130 
       
   131             boolean running = true;
       
   132             // Test matching against compiled expression
       
   133             while ( running )
       
   134             {
       
   135                 // Read from keyboard
       
   136                 BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
       
   137                 System.out.print("> ");
       
   138                 System.out.flush();
       
   139                 String match = br.readLine();
       
   140 
       
   141                 if ( match != null )
       
   142                 {
       
   143                     // Try a match against the keyboard input
       
   144                     if (r.match(match))
       
   145                     {
       
   146                         say("Match successful.");
       
   147                     }
       
   148                     else
       
   149                     {
       
   150                         say("Match failed.");
       
   151                     }
       
   152 
       
   153                     // Show subparen registers
       
   154                     showParens(r);
       
   155                 }
       
   156                 else
       
   157                 {
       
   158                     running = false;
       
   159                     System.out.println();
       
   160                 }
       
   161             }
       
   162         }
       
   163         catch (Exception e)
       
   164         {
       
   165             say("Error: " + e.toString());
       
   166             e.printStackTrace();
       
   167         }
       
   168     }
       
   169 
       
   170     /**
       
   171      * Exit with a fatal error.
       
   172      * @param s Last famous words before exiting
       
   173      */
       
   174     void die(String s)
       
   175     {
       
   176         say("FATAL ERROR: " + s);
       
   177         System.exit(-1);
       
   178     }
       
   179 
       
   180     /**
       
   181      * Fail with an error. Will print a big failure message to System.out.
       
   182      *
       
   183      * @param log Output before failure
       
   184      * @param s Failure description
       
   185      */
       
   186     void fail(StringBuffer log, String s)
       
   187     {
       
   188         System.out.print(log.toString());
       
   189         fail(s);
       
   190     }
       
   191 
       
   192     /**
       
   193      * Fail with an error. Will print a big failure message to System.out.
       
   194      *
       
   195      * @param s Failure description
       
   196      */
       
   197     void fail(String s)
       
   198     {
       
   199         failures++;
       
   200         say("" + NEW_LINE + "");
       
   201         say("*******************************************************");
       
   202         say("*********************  FAILURE!  **********************");
       
   203         say("*******************************************************");
       
   204         say("" + NEW_LINE + "");
       
   205         say(s);
       
   206         say("");
       
   207         // make sure the writer gets flushed.
       
   208         if (compiler != null) {
       
   209             PrintWriter writer = new PrintWriter( System.out );
       
   210             compiler.dumpProgram( writer );
       
   211             writer.flush();
       
   212             say("" + NEW_LINE + "");
       
   213         }
       
   214     }
       
   215 
       
   216     /**
       
   217      * Say something to standard out
       
   218      * @param s What to say
       
   219      */
       
   220     void say(String s)
       
   221     {
       
   222         System.out.println(s);
       
   223     }
       
   224 
       
   225     /**
       
   226      * Dump parenthesized subexpressions found by a regular expression matcher object
       
   227      * @param r Matcher object with results to show
       
   228      */
       
   229     void showParens(RE r)
       
   230     {
       
   231         // Loop through each paren
       
   232         for (int i = 0; i < r.getParenCount(); i++)
       
   233         {
       
   234             // Show paren register
       
   235             say("$" + i + " = " + r.getParen(i));
       
   236         }
       
   237     }
       
   238 
       
   239     /*
       
   240      * number in automated test
       
   241      */
       
   242     int testCount = 0;
       
   243 
       
   244     /*
       
   245      * Count of failures in automated test
       
   246      */
       
   247     int failures = 0;
       
   248 
       
   249     /**
       
   250      * Run automated tests in RETest.txt file (from Perl 4.0 test battery)
       
   251      * @exception Exception thrown in case of error
       
   252      */
       
   253     void runAutomatedTests(String testDocument) throws Exception
       
   254     {
       
   255         long ms = System.currentTimeMillis();
       
   256 
       
   257         // Some unit tests
       
   258         testPrecompiledRE();
       
   259         testSplitAndGrep();
       
   260         testSubst();
       
   261         testOther();
       
   262 
       
   263         // Test from script file
       
   264         File testInput = new File(testDocument);
       
   265         if (! testInput.exists()) {
       
   266             throw new Exception ("Could not find: " + testDocument);
       
   267         }
       
   268 
       
   269         BufferedReader br = new BufferedReader(new FileReader(testInput));
       
   270         try
       
   271         {
       
   272             // While input is available, parse lines
       
   273             while (br.ready())
       
   274             {
       
   275                 RETestCase testcase = getNextTestCase(br);
       
   276                 if (testcase != null) {
       
   277                     testcase.runTest();
       
   278                 }
       
   279             }
       
   280         }
       
   281         finally
       
   282         {
       
   283             br.close();
       
   284         }
       
   285 
       
   286         // Show match time
       
   287         say(NEW_LINE + NEW_LINE + "Match time = " + (System.currentTimeMillis() - ms) + " ms.");
       
   288 
       
   289         // Print final results
       
   290         if (failures > 0) {
       
   291             say("*************** THERE ARE FAILURES! *******************");
       
   292         }
       
   293         say("Tests complete.  " + testCount + " tests, " + failures + " failure(s).");
       
   294     }
       
   295 
       
   296     /**
       
   297      * Run automated unit test
       
   298      * @exception Exception thrown in case of error
       
   299      */
       
   300     void testOther() throws Exception
       
   301     {
       
   302         // Serialization test 1: Compile regexp and serialize/deserialize it
       
   303         RE r = new RE("(a*)b");
       
   304         say("Serialized/deserialized (a*)b");
       
   305         ByteArrayOutputStream out = new ByteArrayOutputStream(128);
       
   306         new ObjectOutputStream(out).writeObject(r);
       
   307         ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
       
   308         r = (RE)new ObjectInputStream(in).readObject();
       
   309         if (!r.match("aaab"))
       
   310         {
       
   311             fail("Did not match 'aaab' with deserialized RE.");
       
   312         } else {
       
   313             say("aaaab = true");
       
   314             showParens(r);
       
   315         }
       
   316 
       
   317         // Serialization test 2: serialize/deserialize used regexp
       
   318         out.reset();
       
   319         say("Deserialized (a*)b");
       
   320         new ObjectOutputStream(out).writeObject(r);
       
   321         in = new ByteArrayInputStream(out.toByteArray());
       
   322         r = (RE)new ObjectInputStream(in).readObject();
       
   323         if (r.getParenCount() != 0)
       
   324         {
       
   325             fail("Has parens after deserialization.");
       
   326         }
       
   327         if (!r.match("aaab"))
       
   328         {
       
   329             fail("Did not match 'aaab' with deserialized RE.");
       
   330         } else {
       
   331             say("aaaab = true");
       
   332             showParens(r);
       
   333         }
       
   334 
       
   335         // Test MATCH_CASEINDEPENDENT
       
   336         r = new RE("abc(\\w*)");
       
   337         say("MATCH_CASEINDEPENDENT abc(\\w*)");
       
   338         r.setMatchFlags(RE.MATCH_CASEINDEPENDENT);
       
   339         say("abc(d*)");
       
   340         if (!r.match("abcddd"))
       
   341         {
       
   342             fail("Did not match 'abcddd'.");
       
   343         } else {
       
   344             say("abcddd = true");
       
   345             showParens(r);
       
   346         }
       
   347 
       
   348         if (!r.match("aBcDDdd"))
       
   349         {
       
   350             fail("Did not match 'aBcDDdd'.");
       
   351         } else {
       
   352             say("aBcDDdd = true");
       
   353             showParens(r);
       
   354         }
       
   355 
       
   356         if (!r.match("ABCDDDDD"))
       
   357         {
       
   358             fail("Did not match 'ABCDDDDD'.");
       
   359         } else {
       
   360             say("ABCDDDDD = true");
       
   361             showParens(r);
       
   362         }
       
   363 
       
   364         r = new RE("(A*)b\\1");
       
   365         r.setMatchFlags(RE.MATCH_CASEINDEPENDENT);
       
   366         if (!r.match("AaAaaaBAAAAAA"))
       
   367         {
       
   368             fail("Did not match 'AaAaaaBAAAAAA'.");
       
   369         } else {
       
   370             say("AaAaaaBAAAAAA = true");
       
   371             showParens(r);
       
   372         }
       
   373 
       
   374         r = new RE("[A-Z]*");
       
   375         r.setMatchFlags(RE.MATCH_CASEINDEPENDENT);
       
   376         if (!r.match("CaBgDe12"))
       
   377         {
       
   378             fail("Did not match 'CaBgDe12'.");
       
   379         } else {
       
   380             say("CaBgDe12 = true");
       
   381             showParens(r);
       
   382         }
       
   383 
       
   384         // Test MATCH_MULTILINE. Test for eol/bol symbols.
       
   385         r = new RE("^abc$", RE.MATCH_MULTILINE);
       
   386         if (!r.match("\nabc")) {
       
   387             fail("\"\\nabc\" doesn't match \"^abc$\"");
       
   388         }
       
   389         if (!r.match("\rabc")) {
       
   390             fail("\"\\rabc\" doesn't match \"^abc$\"");
       
   391         }
       
   392         if (!r.match("\r\nabc")) {
       
   393             fail("\"\\r\\nabc\" doesn't match \"^abc$\"");
       
   394         }
       
   395         if (!r.match("\u0085abc")) {
       
   396             fail("\"\\u0085abc\" doesn't match \"^abc$\"");
       
   397         }
       
   398         if (!r.match("\u2028abc")) {
       
   399             fail("\"\\u2028abc\" doesn't match \"^abc$\"");
       
   400         }
       
   401         if (!r.match("\u2029abc")) {
       
   402             fail("\"\\u2029abc\" doesn't match \"^abc$\"");
       
   403         }
       
   404 
       
   405         // Test MATCH_MULTILINE. Test that '.' does not matches new line.
       
   406         r = new RE("^a.*b$", RE.MATCH_MULTILINE);
       
   407         if (r.match("a\nb")) {
       
   408             fail("\"a\\nb\" matches \"^a.*b$\"");
       
   409         }
       
   410         if (r.match("a\rb")) {
       
   411             fail("\"a\\rb\" matches \"^a.*b$\"");
       
   412         }
       
   413         if (r.match("a\r\nb")) {
       
   414             fail("\"a\\r\\nb\" matches \"^a.*b$\"");
       
   415         }
       
   416         if (r.match("a\u0085b")) {
       
   417             fail("\"a\\u0085b\" matches \"^a.*b$\"");
       
   418         }
       
   419         if (r.match("a\u2028b")) {
       
   420             fail("\"a\\u2028b\" matches \"^a.*b$\"");
       
   421         }
       
   422         if (r.match("a\u2029b")) {
       
   423             fail("\"a\\u2029b\" matches \"^a.*b$\"");
       
   424         }
       
   425     }
       
   426 
       
   427     private void testPrecompiledRE()
       
   428     {
       
   429         // Pre-compiled regular expression "a*b"
       
   430         char[] re1Instructions =
       
   431         {
       
   432             0x007c, 0x0000, 0x001a, 0x007c, 0x0000, 0x000d, 0x0041,
       
   433             0x0001, 0x0004, 0x0061, 0x007c, 0x0000, 0x0003, 0x0047,
       
   434             0x0000, 0xfff6, 0x007c, 0x0000, 0x0003, 0x004e, 0x0000,
       
   435             0x0003, 0x0041, 0x0001, 0x0004, 0x0062, 0x0045, 0x0000,
       
   436             0x0000,
       
   437         };
       
   438 
       
   439         REProgram re1 = new REProgram(re1Instructions);
       
   440 
       
   441         // Simple test of pre-compiled regular expressions
       
   442         RE r = new RE(re1);
       
   443         say("a*b");
       
   444         boolean result = r.match("aaab");
       
   445         say("aaab = " + result);
       
   446         showParens(r);
       
   447         if (!result) {
       
   448             fail("\"aaab\" doesn't match to precompiled \"a*b\"");
       
   449         }
       
   450 
       
   451         result = r.match("b");
       
   452         say("b = " + result);
       
   453         showParens(r);
       
   454         if (!result) {
       
   455             fail("\"b\" doesn't match to precompiled \"a*b\"");
       
   456         }
       
   457 
       
   458         result = r.match("c");
       
   459         say("c = " + result);
       
   460         showParens(r);
       
   461         if (result) {
       
   462             fail("\"c\" matches to precompiled \"a*b\"");
       
   463         }
       
   464 
       
   465         result = r.match("ccccaaaaab");
       
   466         say("ccccaaaaab = " + result);
       
   467         showParens(r);
       
   468         if (!result) {
       
   469             fail("\"ccccaaaaab\" doesn't match to precompiled \"a*b\"");
       
   470         }
       
   471     }
       
   472 
       
   473     private void testSplitAndGrep()
       
   474     {
       
   475         String[] expected = {"xxxx", "xxxx", "yyyy", "zzz"};
       
   476         RE r = new RE("a*b");
       
   477         String[] s = r.split("xxxxaabxxxxbyyyyaaabzzz");
       
   478         for (int i = 0; i < expected.length && i < s.length; i++) {
       
   479             assertEquals("Wrong splitted part", expected[i], s[i]);
       
   480         }
       
   481         assertEquals("Wrong number of splitted parts", expected.length,
       
   482                      s.length);
       
   483 
       
   484         r = new RE("x+");
       
   485         expected = new String[] {"xxxx", "xxxx"};
       
   486         s = r.grep(s);
       
   487         for (int i = 0; i < s.length; i++)
       
   488         {
       
   489             say("s[" + i + "] = " + s[i]);
       
   490             assertEquals("Grep fails", expected[i], s[i]);
       
   491         }
       
   492         assertEquals("Wrong number of string found by grep", expected.length,
       
   493                      s.length);
       
   494     }
       
   495 
       
   496     private void testSubst()
       
   497     {
       
   498         RE r = new RE("a*b");
       
   499         String expected = "-foo-garply-wacky-";
       
   500         String actual = r.subst("aaaabfooaaabgarplyaaabwackyb", "-");
       
   501         assertEquals("Wrong result of substitution in \"a*b\"", expected, actual);
       
   502 
       
   503         // Test subst() with backreferences
       
   504         r = new RE("http://[\\.\\w\\-\\?/~_@&=%]+");
       
   505         actual = r.subst("visit us: http://www.apache.org!",
       
   506                          "1234<a href=\"$0\">$0</a>", RE.REPLACE_BACKREFERENCES);
       
   507         assertEquals("Wrong subst() result", "visit us: 1234<a href=\"http://www.apache.org\">http://www.apache.org</a>!", actual);
       
   508 
       
   509         // Test subst() with backreferences without leading characters
       
   510         // before first backreference
       
   511         r = new RE("(.*?)=(.*)");
       
   512         actual = r.subst("variable=value",
       
   513                          "$1_test_$212", RE.REPLACE_BACKREFERENCES);
       
   514         assertEquals("Wrong subst() result", "variable_test_value12", actual);
       
   515 
       
   516         // Test subst() with NO backreferences
       
   517         r = new RE("^a$");
       
   518         actual = r.subst("a",
       
   519                          "b", RE.REPLACE_BACKREFERENCES);
       
   520         assertEquals("Wrong subst() result", "b", actual);
       
   521 
       
   522         // Test subst() with NO backreferences
       
   523         r = new RE("^a$", RE.MATCH_MULTILINE);
       
   524         actual = r.subst("\r\na\r\n",
       
   525                          "b", RE.REPLACE_BACKREFERENCES);
       
   526         assertEquals("Wrong subst() result", "\r\nb\r\n", actual);
       
   527     }
       
   528 
       
   529     public void assertEquals(String message, String expected, String actual)
       
   530     {
       
   531         if (expected != null && !expected.equals(actual)
       
   532             || actual != null && !actual.equals(expected))
       
   533         {
       
   534             fail(message + " (expected \"" + expected
       
   535                  + "\", actual \"" + actual + "\")");
       
   536         }
       
   537     }
       
   538 
       
   539     public void assertEquals(String message, int expected, int actual)
       
   540     {
       
   541         if (expected != actual) {
       
   542             fail(message + " (expected \"" + expected
       
   543                  + "\", actual \"" + actual + "\")");
       
   544         }
       
   545     }
       
   546 
       
   547     /**
       
   548      * Converts yesno string to boolean.
       
   549      * @param yesno string representation of expected result
       
   550      * @return true if yesno is "YES", false if yesno is "NO"
       
   551      *         stops program otherwise.
       
   552      */
       
   553     private boolean getExpectedResult(String yesno)
       
   554     {
       
   555         if ("NO".equals(yesno))
       
   556         {
       
   557             return false;
       
   558         }
       
   559         else if ("YES".equals(yesno))
       
   560         {
       
   561             return true;
       
   562         }
       
   563         else
       
   564         {
       
   565             // Bad test script
       
   566             die("Test script error!");
       
   567             return false; //to please javac
       
   568         }
       
   569     }
       
   570 
       
   571     /**
       
   572      * Finds next test description in a given script.
       
   573      * @param br <code>BufferedReader</code> for a script file
       
   574      * @return strign tag for next test description
       
   575      * @exception IOException if some io problems occured
       
   576      */
       
   577     private String findNextTest(BufferedReader br) throws IOException
       
   578     {
       
   579         String number = "";
       
   580 
       
   581         while (br.ready())
       
   582         {
       
   583             number = br.readLine();
       
   584             if (number == null)
       
   585             {
       
   586                 break;
       
   587             }
       
   588             number = number.trim();
       
   589             if (number.startsWith("#"))
       
   590             {
       
   591                 break;
       
   592             }
       
   593             if (!number.equals(""))
       
   594             {
       
   595                 say("Script error.  Line = " + number);
       
   596                 System.exit(-1);
       
   597             }
       
   598         }
       
   599         return number;
       
   600     }
       
   601 
       
   602     /**
       
   603      * Creates testcase for the next test description in the script file.
       
   604      * @param br <code>BufferedReader</code> for script file.
       
   605      * @return a new tescase or null.
       
   606      * @exception IOException if some io problems occured
       
   607      */
       
   608     private RETestCase getNextTestCase(BufferedReader br) throws IOException
       
   609     {
       
   610         // Find next re test case
       
   611         final String tag = findNextTest(br);
       
   612 
       
   613         // Are we done?
       
   614         if (!br.ready())
       
   615         {
       
   616             return null;
       
   617         }
       
   618 
       
   619         // Get expression
       
   620         final String expr = br.readLine();
       
   621 
       
   622         // Get test information
       
   623         final String matchAgainst = br.readLine();
       
   624         final boolean badPattern = "ERR".equals(matchAgainst);
       
   625         boolean shouldMatch = false;
       
   626         int expectedParenCount = 0;
       
   627         String[] expectedParens = null;
       
   628 
       
   629         if (!badPattern) {
       
   630             shouldMatch = getExpectedResult(br.readLine().trim());
       
   631             if (shouldMatch) {
       
   632                 expectedParenCount = Integer.parseInt(br.readLine().trim());
       
   633                 expectedParens = new String[expectedParenCount];
       
   634                 for (int i = 0; i < expectedParenCount; i++) {
       
   635                     expectedParens[i] = br.readLine();
       
   636                 }
       
   637             }
       
   638         }
       
   639 
       
   640         return new RETestCase(this, tag, expr, matchAgainst, badPattern,
       
   641                               shouldMatch, expectedParens);
       
   642     }
       
   643 }
       
   644 
       
   645 final class RETestCase
       
   646 {
       
   647     final private StringBuffer log = new StringBuffer();
       
   648     final private int number;
       
   649     final private String tag; // number from script file
       
   650     final private String pattern;
       
   651     final private String toMatch;
       
   652     final private boolean badPattern;
       
   653     final private boolean shouldMatch;
       
   654     final private String[] parens;
       
   655     final private RETest test;
       
   656     private RE regexp;
       
   657 
       
   658     public RETestCase(RETest test, String tag, String pattern,
       
   659                       String toMatch, boolean badPattern,
       
   660                       boolean shouldMatch, String[] parens)
       
   661     {
       
   662         this.number = ++test.testCount;
       
   663         this.test = test;
       
   664         this.tag = tag;
       
   665         this.pattern = pattern;
       
   666         this.toMatch = toMatch;
       
   667         this.badPattern = badPattern;
       
   668         this.shouldMatch = shouldMatch;
       
   669         if (parens != null) {
       
   670             this.parens = new String[parens.length];
       
   671             for (int i = 0; i < parens.length; i++) {
       
   672                 this.parens[i] = parens[i];
       
   673             }
       
   674         } else {
       
   675             this.parens = null;
       
   676         }
       
   677     }
       
   678 
       
   679     public void runTest()
       
   680     {
       
   681         test.say(tag + "(" + number + "): " + pattern);
       
   682         if (testCreation()) {
       
   683             testMatch();
       
   684         }
       
   685     }
       
   686 
       
   687     boolean testCreation()
       
   688     {
       
   689         try
       
   690         {
       
   691             // Compile it
       
   692             regexp = new RE();
       
   693             regexp.setProgram(test.compiler.compile(pattern));
       
   694             // Expression didn't cause an expected error
       
   695             if (badPattern)
       
   696             {
       
   697                 test.fail(log, "Was expected to be an error, but wasn't.");
       
   698                 return false;
       
   699             }
       
   700 
       
   701             return true;
       
   702         }
       
   703         // Some expressions *should* cause exceptions to be thrown
       
   704         catch (Exception e)
       
   705         {
       
   706             // If it was supposed to be an error, report success and continue
       
   707             if (badPattern)
       
   708             {
       
   709                 log.append("   Match: ERR\n");
       
   710                 success("Produces an error (" + e.toString() + "), as expected.");
       
   711                 return false;
       
   712             }
       
   713 
       
   714             // Wasn't supposed to be an error
       
   715             String message = (e.getMessage() == null) ? e.toString() : e.getMessage();
       
   716             test.fail(log, "Produces an unexpected exception \"" + message + "\"");
       
   717             e.printStackTrace();
       
   718         }
       
   719         catch (Error e)
       
   720         {
       
   721             // Internal error happened
       
   722             test.fail(log, "Compiler threw fatal error \"" + e.getMessage() + "\"");
       
   723             e.printStackTrace();
       
   724         }
       
   725 
       
   726         return false;
       
   727     }
       
   728 
       
   729     private void testMatch()
       
   730     {
       
   731         log.append("   Match against: '" + toMatch + "'\n");
       
   732         // Try regular matching
       
   733         try
       
   734         {
       
   735             // Match against the string
       
   736             boolean result = regexp.match(toMatch);
       
   737             log.append("   Matched: " + (result ? "YES" : "NO") + "\n");
       
   738 
       
   739             // Check result, parens, and iterators
       
   740             if (checkResult(result) && (!shouldMatch || checkParens()))
       
   741             {
       
   742                 // test match(CharacterIterator, int)
       
   743                 // for every CharacterIterator implementation.
       
   744                 log.append("   Match using StringCharacterIterator\n");
       
   745                 if (!tryMatchUsingCI(new StringCharacterIterator(toMatch)))
       
   746                     return;
       
   747 
       
   748                 log.append("   Match using CharacterArrayCharacterIterator\n");
       
   749                 if (!tryMatchUsingCI(new CharacterArrayCharacterIterator(toMatch.toCharArray(), 0, toMatch.length())))
       
   750                     return;
       
   751 
       
   752                 log.append("   Match using StreamCharacterIterator\n");
       
   753                 if (!tryMatchUsingCI(new StreamCharacterIterator(new StringBufferInputStream(toMatch))))
       
   754                     return;
       
   755 
       
   756                 log.append("   Match using ReaderCharacterIterator\n");
       
   757                 if (!tryMatchUsingCI(new ReaderCharacterIterator(new StringReader(toMatch))))
       
   758                     return;
       
   759             }
       
   760         }
       
   761         // Matcher blew it
       
   762         catch(Exception e)
       
   763         {
       
   764             test.fail(log, "Matcher threw exception: " + e.toString());
       
   765             e.printStackTrace();
       
   766         }
       
   767         // Internal error
       
   768         catch(Error e)
       
   769         {
       
   770             test.fail(log, "Matcher threw fatal error \"" + e.getMessage() + "\"");
       
   771             e.printStackTrace();
       
   772         }
       
   773     }
       
   774 
       
   775     private boolean checkResult(boolean result)
       
   776     {
       
   777         // Write status
       
   778         if (result == shouldMatch) {
       
   779             success((shouldMatch ? "Matched" : "Did not match")
       
   780                     + " \"" + toMatch + "\", as expected:");
       
   781             return true;
       
   782         } else {
       
   783             if (shouldMatch) {
       
   784                 test.fail(log, "Did not match \"" + toMatch + "\", when expected to.");
       
   785             } else {
       
   786                 test.fail(log, "Matched \"" + toMatch + "\", when not expected to.");
       
   787             }
       
   788             return false;
       
   789         }
       
   790     }
       
   791 
       
   792     private boolean checkParens()
       
   793     {
       
   794         // Show subexpression registers
       
   795         if (RETest.showSuccesses)
       
   796         {
       
   797             test.showParens(regexp);
       
   798         }
       
   799 
       
   800         log.append("   Paren count: " + regexp.getParenCount() + "\n");
       
   801         if (!assertEquals(log, "Wrong number of parens", parens.length, regexp.getParenCount()))
       
   802         {
       
   803             return false;
       
   804         }
       
   805 
       
   806         // Check registers against expected contents
       
   807         for (int p = 0; p < regexp.getParenCount(); p++)
       
   808         {
       
   809             log.append("   Paren " + p + ": " + regexp.getParen(p) + "\n");
       
   810 
       
   811             // Compare expected result with actual
       
   812             if ("null".equals(parens[p]) && regexp.getParen(p) == null)
       
   813             {
       
   814                 // Consider "null" in test file equal to null
       
   815                 continue;
       
   816             }
       
   817             if (!assertEquals(log, "Wrong register " + p, parens[p], regexp.getParen(p)))
       
   818             {
       
   819                 return false;
       
   820             }
       
   821         }
       
   822 
       
   823         return true;
       
   824     }
       
   825 
       
   826     boolean tryMatchUsingCI(CharacterIterator matchAgainst)
       
   827     {
       
   828         try {
       
   829             boolean result = regexp.match(matchAgainst, 0);
       
   830             log.append("   Match: " + (result ? "YES" : "NO") + "\n");
       
   831             return checkResult(result) && (!shouldMatch || checkParens());
       
   832         }
       
   833         // Matcher blew it
       
   834         catch(Exception e)
       
   835         {
       
   836             test.fail(log, "Matcher threw exception: " + e.toString());
       
   837             e.printStackTrace();
       
   838         }
       
   839         // Internal error
       
   840         catch(Error e)
       
   841         {
       
   842             test.fail(log, "Matcher threw fatal error \"" + e.getMessage() + "\"");
       
   843             e.printStackTrace();
       
   844         }
       
   845         return false;
       
   846     }
       
   847 
       
   848     public boolean assertEquals(StringBuffer log, String message, String expected, String actual)
       
   849     {
       
   850         if (expected != null && !expected.equals(actual)
       
   851             || actual != null && !actual.equals(expected))
       
   852         {
       
   853             test.fail(log, message + " (expected \"" + expected
       
   854                       + "\", actual \"" + actual + "\")");
       
   855             return false;
       
   856         }
       
   857         return true;
       
   858     }
       
   859 
       
   860     public boolean assertEquals(StringBuffer log, String message, int expected, int actual)
       
   861     {
       
   862         if (expected != actual) {
       
   863             test.fail(log, message + " (expected \"" + expected
       
   864                       + "\", actual \"" + actual + "\")");
       
   865             return false;
       
   866         }
       
   867         return true;
       
   868     }
       
   869 
       
   870     /**
       
   871      * Show a success
       
   872      * @param s Success story
       
   873      */
       
   874     void success(String s)
       
   875     {
       
   876         if (RETest.showSuccesses)
       
   877         {
       
   878             test.say("" + RETest.NEW_LINE + "-----------------------" + RETest.NEW_LINE + "");
       
   879             test.say("Expression #" + (number) + " \"" + pattern + "\" ");
       
   880             test.say("Success: " + s);
       
   881         }
       
   882     }
       
   883 }