package com.github.sommeri.less4j.grammar; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.Iterator; import java.util.List; import org.antlr.runtime.ANTLRStringStream; import org.antlr.runtime.CommonToken; import org.antlr.runtime.CommonTokenStream; import org.antlr.runtime.Token; import org.antlr.runtime.tree.CommonTree; import org.antlr.runtime.tree.TreeVisitor; import org.antlr.runtime.tree.TreeVisitorAction; import com.github.sommeri.less4j.core.parser.LessLexer; import com.github.sommeri.less4j.core.parser.ANTLRParser; import com.github.sommeri.less4j.core.parser.HiddenTokenAwareErrorTree; import com.github.sommeri.less4j.utils.PrintUtils; public class GrammarAsserts { public static void assertValidSelector(ANTLRParser.ParseResult result) { assertValid(result); assertEquals(LessLexer.SELECTOR, result.getTree().getGeneralType()); } public static void assertValidExpression(ANTLRParser.ParseResult result) { assertValid(result); assertEquals(LessLexer.EXPRESSION, result.getTree().getGeneralType()); } public static void assertValidTerm(ANTLRParser.ParseResult result) { assertValid(result); assertEquals(LessLexer.TERM, result.getTree().getGeneralType()); } public static void assertValid(ANTLRParser.ParseResult result) { assertTrue(result.getErrors().isEmpty()); } @SuppressWarnings("rawtypes") public static void assertChilds(CommonTree tree, int... childType) { Iterator kids = tree.getChildren().iterator(); for (int type : childType) { if (!kids.hasNext()) fail("Some children are missing."); CommonTree kid = (CommonTree) kids.next(); assertEquals("Should be: " + PrintUtils.toName(type)+" was: "+ PrintUtils.toName(kid.getType()), type, kid.getType()); } } public static void assertNoTokenMissing(String crashingSelector, CommonTree tree) { assertNoTokenMissing(crashingSelector, tree, 0); } public static void assertNoTokenMissing(String crashingSelector, CommonTree tree, int expectedDummies) { CommonTokenStream tokens = createTokenStream(crashingSelector); int onChannelTokens = countOnChannelTokes(tokens); int treeTokesCount = countAllTreeTokens(tokens, tree); assertEquals(onChannelTokens + expectedDummies, treeTokesCount); } private static int countOnChannelTokes(CommonTokenStream tokens) { int numberOfOnChannelTokens = tokens.getNumberOfOnChannelTokens(); //the above number includes also EOF, we substract that return numberOfOnChannelTokens - 1; } private static int countAllTreeTokens(CommonTokenStream tokens, CommonTree tree) { CountNodesAction action = new CountNodesAction(tokens); TreeVisitor visitor = new TreeVisitor(); visitor.visit(tree, action); return action.getCount(); } private static CommonTokenStream createTokenStream(String text) { ANTLRStringStream input = new ANTLRStringStream(text); LessLexer lexer = new LessLexer(input); return new CommonTokenStream(lexer); } } class CountNodesAction implements TreeVisitorAction { private int count = 0; private final CommonTokenStream tokens; public CountNodesAction(CommonTokenStream tokens) { super(); this.tokens = tokens; } @Override public Object pre(Object t) { if (t instanceof HiddenTokenAwareErrorTree) { HiddenTokenAwareErrorTree errorNode = (HiddenTokenAwareErrorTree)t; int startIndex = errorNode.getStart().getTokenIndex(); int stopIndex = errorNode.getStop().getTokenIndex(); int errorTokens = countOnChannelTokes(startIndex, stopIndex); count+=errorTokens; // System.out.println("Error tokens " + errorTokens); } else { if (!isDummy(((CommonTree)t).getToken())) { count++; // String string = DebugAndTestPrint.toString(count, ((CommonTree)t).getToken()); // System.out.println(string); } } return t; } public int getCount() { return count; } @Override public Object post(Object t) { return t; } private int countOnChannelTokes(int start, int end) { List<? extends Token> list = tokens.get(start, end); int count = 0; for (Token token : list) { CommonToken commonToken = CommonToken.class.cast(token); if (isOnChannel(commonToken) && !isDummy(commonToken)) count++; } return count; } private boolean isDummy(Token token) { return token.getType()<LessLexer.AT_NAME; } private boolean isOnChannel(CommonToken token) { return token.getChannel()==Token.DEFAULT_CHANNEL; } }