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