/*
* Copyright 2016, Red Hat Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.infinispan.objectfilter.impl.ql.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.util.List;
import java.util.concurrent.Callable;
import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.Token;
import org.antlr.runtime.tree.CommonTree;
import org.infinispan.objectfilter.impl.ql.parse.IckleLexer;
import org.infinispan.objectfilter.impl.ql.parse.IckleParser;
/**
* @author anistor@redhat.com
* @since 9.0
*/
abstract class TestBase {
protected void expectParserSuccess(String inputText) {
parse(inputText, false, null, false);
}
protected void expectParserSuccess(String inputText, String expectedOut) {
parse(inputText, false, expectedOut, false);
}
protected void expectParserFailure(String inputText) {
parse(inputText, true, null, false);
}
protected void expectLexerSuccess(String inputText) {
parse(inputText, false, null, true);
}
protected void expectLexerSuccess(String inputText, String expectedOut) {
parse(inputText, false, expectedOut, true);
}
protected void expectLexerFailure(String inputText) {
parse(inputText, true, null, true);
}
private void parse(String inputText, boolean expectFailure, String expectedTreeOut, boolean lexerOnly) {
if (expectFailure && expectedTreeOut != null) {
throw new IllegalArgumentException("If failure is expected then expectedTreeOut must be null");
}
IckleLexer lexer = new IckleLexer(new ANTLRStringStream(inputText));
CommonTokenStream tokens = new CommonTokenStream(lexer);
try {
Object[] pair;
if (lexerOnly) {
pair = executeAndCaptureErrOut(() -> lexer.nextToken());
} else {
pair = executeAndCaptureErrOut(() -> {
IckleParser parser = new IckleParser(tokens);
IckleParser.statement_return statement = parser.statement();
return statement.getTree();
});
}
if (pair[1] != null) {
// we have an error message
if (expectFailure) {
return;
} else {
fail((String) pair[1]);
}
}
if (expectedTreeOut != null) {
if (lexerOnly) {
int expectedTokenType;
try {
// expectedTreeOut is assumed to be a token name
Field tokenTypeConstant = lexer.getClass().getDeclaredField(expectedTreeOut);
expectedTokenType = (Integer) tokenTypeConstant.get(null);
} catch (IllegalAccessException | NoSuchFieldException e) {
throw new RuntimeException("Could not determine the type of token: " + expectedTreeOut, e);
}
Token token = (Token) pair[0];
assertEquals("Token type", expectedTokenType, token.getType());
} else {
CommonTree tree = (CommonTree) pair[0];
assertEquals(expectedTreeOut, tree.toStringTree());
}
}
String unconsumedTokens = getUnconsumedTokens(tokens);
if (unconsumedTokens != null) {
if (expectFailure) {
return;
} else {
fail("Found unconsumed tokens: \"" + unconsumedTokens + "\".");
}
}
} catch (Exception e) {
if (expectFailure) {
return;
} else {
fail(e.getMessage());
}
}
if (expectFailure) {
fail("Parsing was expected to fail but it actually succeeded.");
}
}
private Object[] executeAndCaptureErrOut(Callable<?> callable) throws Exception {
PrintStream oldErrStream = System.err;
try {
// no way to register an error handler so we capture any output written to System.err by the lexer/parser
ByteArrayOutputStream errorStream = new ByteArrayOutputStream();
System.setErr(new PrintStream(errorStream));
Object retVal = callable.call();
String errMsg = errorStream.size() > 0 ? errorStream.toString() : null;
return new Object[]{retVal, errMsg};
} finally {
System.setErr(oldErrStream);
}
}
private String getUnconsumedTokens(CommonTokenStream tokens) {
// ensure we've buffered all tokens from the underlying TokenSource
tokens.fill();
if (tokens.index() == tokens.size() - 1) {
return null;
}
StringBuilder sb = new StringBuilder();
@SuppressWarnings("unchecked")
List<Token> unconsumed = (List<Token>) tokens.getTokens(tokens.index(), tokens.size() - 1);
for (Token t : unconsumed) {
if (t.getType() != Token.EOF) {
sb.append(t.getText());
}
}
return sb.length() > 0 ? sb.toString() : null;
}
}