/* * $Id: NestedParenthesesTest.java,v 1.5 2006/03/16 03:04:06 ian Exp $ * $Name: gxparse-sf-alpha-2_0 $ * * JUnit tests for ca.gorman.util.scan. * * This file is part of the JUnit tests for package ca.gorman.util.scan. * Copyright (C) 2004 Ian E. Gorman * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * or go to http://www.gnu.org/ * * Ian E. Gorman http://gorman.ca/ */ package ca.gorman.util.scan.junit; import junit.framework.*; import java.io.*; import ca.gorman.util.scan.*; /**
* Test scanning of nested parentheses (recursive pattern matching). * * @author Ian E. Gorman */ public class NestedParenthesesTest extends TestCase { private final static RegexFactory regexFactory = RegexFactory.newInstance(); private final static Modifier modifier = Modifier.newInstance(); public static void main(String [] arg) { junit.textui.TestRunner.run(NestedParenthesesTest.class); } public void setUp() { } public void tearDown() { } public static Test suite() { return new TestSuite(NestedParenthesesTest.class, "Recursive scan and match, nested parentheses"); } // the tests public void testNestedParentheses() { StringReader input = new StringReader( "xxx(print (only\nthis) part), but not this"); try { ScanningReader scanningReader = new ScanningReader(input, new PrintRule(), new SkipRule()); StringWriter output = new StringWriter(); for ( int chr = scanningReader.read() ; chr >= 0 ; chr = scanningReader.read() ) { output.write(chr); } assertEquals("(print (only\nthis) part)", output.toString()); } catch(IOException iox) { fail(iox.toString()); } catch(InterruptedException ix) { fail(ix.toString()); } } // test support // The ScanRule subclasses below can be used recursively because each // instance is immutable and the methods are reentrant. /** Match parentheses (and nested parentheses) and print the matched text. */ private static class PrintRule implements ScanRule { private final static ScanMatch parenText = new ParenText(); public MatchedText match(ScanBuffer scanBuffer) throws IOException { return parenText.match(scanBuffer); } // inherit javadoc public void action(ScanState scanState, MatchedText matchedText) throws IOException { scanState.out().append(matchedText); } } /** Match text outside pairs of parentheses and discard the matched text. */ private static class SkipRule extends AbstractScanRule { private final static ScanMatch scanMatch = modifier.anyOf(new TextExceptParen(), new TextCloseParen(), new TextOpenParen()); public MatchedText match(ScanBuffer scanBuffer) throws IOException { return scanMatch.match(scanBuffer); } } // All of the ScanMatch subclasses below can be used recursively because // each instance is immutable and the methods are reentrant. /** * Match parentheses and nested parentheses. */ private static class ParenText extends AbstractScanRule { private final static ScanMatch scanMatch = modifier.concat(new TextOpenParen(), new ParenInterior(), new TextCloseParen()); public MatchedText match(ScanBuffer scanBuffer) throws IOException { return scanMatch.match(scanBuffer); } } /** match any text except parentheses. */ private static class TextExceptParen extends AbstractScanRule { private static ScanMatch regexMatch = regexFactory.newRegexScanRule("[^()]+"); public MatchedText match(ScanBuffer scanBuffer) throws IOException { return regexMatch.match(scanBuffer); } } /** Match one "open" parenthesis character. */ private static class TextOpenParen extends AbstractScanRule { private static ScanMatch regexMatch = regexFactory.newRegexScanRule("\\("); public MatchedText match(ScanBuffer scanBuffer) throws IOException { return regexMatch.match(scanBuffer); } } /** Match one "close" parenthesis character. */ private static class TextCloseParen extends AbstractScanRule { private static ScanMatch regexMatch = regexFactory.newRegexScanRule("\\)"); public MatchedText match(ScanBuffer scanBuffer) throws IOException { return regexMatch.match(scanBuffer); } } /** Match the interior of parenthesized text, including any nested * parenthesized text. Interior may be of zero length. */ private static class ParenInterior extends AbstractScanRule { private final static ScanMatch scanMatch = modifier.zeroOrMore( modifier.anyOf(new ParenText(), new TextExceptParen())); public MatchedText match(ScanBuffer scanBuffer) throws IOException { return scanMatch.match(scanBuffer); } } }