/*
* Copyright (C) 2011 Laurent Caillette
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation, either
* version 3 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, see <http://www.gnu.org/licenses/>.
*/
package org.novelang.parser.antlr;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.junit.Assert;
import org.novelang.common.Location;
import org.novelang.common.LocationFactory;
import org.novelang.common.SimpleTree;
import org.novelang.common.SyntacticTree;
import org.novelang.common.tree.Treepath;
import org.novelang.parser.NodeKind;
import org.novelang.treemangling.SeparatorsMangler;
/**
* Helps building {@link org.novelang.common.SyntacticTree}s for tests.
* Dependency towards {@link org.novelang.parser.antlr.CustomTree} is just for implementation,
* it helps tree comparison.
*
* @author Laurent Caillette
*/
public class TreeFixture {
public static final LocationFactory LOCATION_FACTORY = new LocationFactory() {
@Override
public Location createLocation( final int line, final int column ) {
return new Location( "", line, column ) ;
}
@Override
public Location createLocation() {
return new Location( "" ) ;
}
} ;
private TreeFixture() {}
public static SyntacticTree tree( final NodeKind nodeKind, final SyntacticTree... children ) {
return new SimpleTree( nodeKind, children ) ;
}
public static SyntacticTree tree( final NodeKind nodeKind, final String text ) {
return new SimpleTree( nodeKind, new SimpleTree( text ) ) ;
}
public static SyntacticTree tree( final NodeKind nodeKind ) {
return new SimpleTree( nodeKind ) ;
}
public static SyntacticTree tree(
final NodeKind nodeKind,
final Location location,
final SyntacticTree... children
) {
return new SimpleTree( nodeKind, location, children ) ;
}
public static SyntacticTree tree(
final NodeKind nodeKind,
final Location location,
final String text
) {
return new SimpleTree( nodeKind, location, new SimpleTree( text ) ) ;
}
public static SyntacticTree tree( final NodeKind nodeKind, final NodeKind... children ) {
final SyntacticTree[] childTrees = new SyntacticTree[ children.length ] ;
for( int i = 0; i < children.length ; i++ ) {
final NodeKind child = children[ i ] ;
childTrees[ i ] = new SimpleTree( child ) ;
}
return new SimpleTree( nodeKind, childTrees ) ;
}
public static SyntacticTree tree( final String text ) {
return new SimpleTree( text ) ;
}
public static SyntacticTree tree( final String text, final SyntacticTree... children ) {
return new SimpleTree( text, children ) ;
}
public static SyntacticTree multiTokenTree( final String text ) {
final SyntacticTree[] children = new SyntacticTree[ text.length() ] ;
for( int i = 0 ; i < text.length() ; i++ ) {
final String s = String.valueOf( text.charAt( i ) ) ;
children[ i ] = tree( s ) ;
}
return new SimpleTree( "", children ) ;
}
public static void assertEqualsWithSeparators(
final SyntacticTree expected,
final SyntacticTree actual
) {
assertEqualsWithSeparators( Treepath.create( expected ), Treepath.create( actual ) ) ;
}
public static void assertEqualsWithSeparators(
final Treepath< SyntacticTree > expected,
final Treepath< SyntacticTree > actual
) {
assertEqualsWithSeparators( expected, actual, false ) ;
}
public static void assertEqualsWithSeparators(
final Treepath< SyntacticTree > expected,
final Treepath< SyntacticTree > actual,
final boolean checkLocation
) {
final int expectedLength = expected.getLength();
final int actualLength = actual.getLength();
Assert.assertEquals( "Treepath height", expectedLength, actualLength ) ;
for( int i = 0 ; i < expected.getLength() ; i++ ) {
assertEquals(
expected.getTreeAtDistance( i ),
actual.getTreeAtDistance( i ),
checkLocation
) ;
}
}
public static void assertEqualsNoSeparators(
final SyntacticTree expected,
final SyntacticTree actual
) {
assertEquals( expected, SeparatorsMangler.removeSeparators( actual ) ) ;
}
public static void assertEquals( final SyntacticTree expected, final SyntacticTree actual ) {
assertEquals( expected, actual, false ) ;
}
public static void assertEquals(
final SyntacticTree expected,
final SyntacticTree actual,
final boolean checkLocation
) {
try {
assertEqualsNoMessage( expected, actual, checkLocation ) ;
} catch( AssertionError e ) {
final AssertionError assertionError = new AssertionError(
e.getMessage() +
"\nExpected:\n " + asString( expected ) +
"\nActual:\n " + asString( actual )
) ;
assertionError.setStackTrace( e.getStackTrace() ) ;
throw assertionError;
}
}
private static void assertEqualsNoMessage(
final SyntacticTree expected,
final SyntacticTree actual
) {
assertEqualsNoMessage( expected, actual, false ) ;
}
private static void assertEqualsNoMessage(
final SyntacticTree expected,
final SyntacticTree actual,
boolean checkLocation
) {
checkLocation = checkLocation && ! expected.isOneOf( NodeKind.WORD_ ) ;
if( NodeKind.LINES_OF_LITERAL == expected.getNodeKind()
&& NodeKind.LINES_OF_LITERAL == actual.getNodeKind()
) {
/*
Assert.assertEquals(
"Ill-formed test: expected LITERAL node must have exactly one child",
1,
expected.getChildCount()
) ;
Assert.assertEquals( 1, actual.getChildCount() ) ;
*/
Assert.assertTrue(
"Ill-formed test: expected LITERAL node must have at least one child",
expected.getChildCount() >= 1
) ;
Assert.assertEquals( expected.getChildCount(), actual.getChildCount() ) ;
final int lastIndex = expected.getChildCount() - 1 ;
for( int index = 0 ; index < expected.getChildCount() ; index++ ) {
final SyntacticTree expectedChild = expected.getChildAt( index ) ;
final SyntacticTree actualChild = actual.getChildAt( index ) ;
assertEqualsNoMessage( expectedChild, actualChild, checkLocation ) ;
}
assertPayloadEquals(
expected.getChildAt( lastIndex ),
actual.getChildAt( lastIndex ),
checkLocation
) ;
} else {
assertPayloadEquals( expected, actual, checkLocation ) ;
Assert.assertEquals( expected.getChildCount(), actual.getChildCount() ) ;
for( int index = 0 ; index < expected.getChildCount() ; index++ ) {
final SyntacticTree expectedChild = expected.getChildAt( index ) ;
final SyntacticTree actualChild = actual.getChildAt( index ) ;
assertEqualsNoMessage( expectedChild, actualChild, checkLocation ) ;
}
}
}
private static void assertPayloadEquals(
final SyntacticTree expected,
final SyntacticTree actual,
final boolean checkLocation
) {
Assert.assertEquals( expected.getText(), actual.getText() ) ;
if( checkLocation ) {
Assert.assertEquals(
"Unexpected location object on " + TreeFixture.asString( actual ),
expected.getLocation(),
actual.getLocation()
) ;
}
}
private static final Pattern SPACE_NORMALIZER_PATTERN = Pattern.compile( " +" ) ;
/**
* Replace sequence of spaces by a single one.
*/
public static String normalizeSpaces( final String s ) {
final Matcher matcher = SPACE_NORMALIZER_PATTERN.matcher( s ) ;
final StringBuffer buffer = new StringBuffer() ;
while( matcher.find() ) {
matcher.appendReplacement( buffer, " " ) ;
}
matcher.appendTail( buffer ) ;
return buffer.toString() ;
}
public static String asString( final SyntacticTree tree ) {
if( null == tree ) {
return "<null>" ;
} else {
return tree.toStringTree() ;
}
}
}