/**
* Copyright (c) 2009-2011, The HATS Consortium. All rights reserved.
* This file is licensed under the terms of the Modified BSD License.
*/
package abs;
import static org.junit.Assert.fail;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Set;
import abs.frontend.analyser.SemanticCondition;
import abs.frontend.analyser.SemanticConditionList;
import abs.common.WrongProgramArgumentException;
import abs.frontend.ast.Model;
import abs.frontend.parser.Main;
import abs.frontend.typechecker.locationtypes.infer.LocationTypeInferrerExtension;
import static abs.ABSTest.Config.*;
public class ABSTest {
public static enum Config {
NONE,
WITH_STD_LIB,
WITHOUT_MODULE_NAME,
WITH_LOC_INF,
EXPECT_PARSE_ERROR,
EXPECT_TYPE_ERROR,
EXPECT_WARNING,
ALLOW_INCOMPLETE_EXPR,
TYPE_CHECK
}
public static class ABSFileNameFilter implements FilenameFilter {
@Override
public boolean accept(File dir, String name) {
return name.endsWith(".abs");
}
}
static protected boolean isSet(Config c, Config...configs) {
if (configs == null)
throw new IllegalArgumentException("Must give an array of configs");
for (Config c2: configs) {
if (c2 == c)
return true;
}
return false;
}
/**
* Take a file name and returns that name if it points to an existing file,
* otherwise if {@link File#getAbsoluteFile()} returns a file that points to
* an existing file, this method returns {@link File#getAbsolutePath()}.
*
* @param fileName
* @return a valid file name from the input file name
* @throws IllegalArgumentException
* if neither the input file name nor
* {@link File#getAbsoluteFile()} points to a valid file.
*/
static protected String resolveFileName(String fileName) {
File f = new File(fileName);
if (f.exists()) {
return fileName;
}
f = f.getAbsoluteFile();
if (f.exists()) {
return f.getAbsolutePath();
}
throw new IllegalArgumentException("File "+fileName+" cannot be read");
}
protected Model assertParseOk(String s, Config... config) {
return assertParse(s,config);
}
protected Model assertParse(String s, Config... config) {
String preamble = "module UnitTest; export *; ";
if (isSet(WITH_STD_LIB, config))
preamble = preamble + " import * from ABS.StdLib;";
if (!isSet(WITHOUT_MODULE_NAME, config))
s = preamble + s;
try {
Model p = Main.parseString(s, isSet(WITH_STD_LIB, config),
isSet(ALLOW_INCOMPLETE_EXPR, config));
Main.exceptionHack(p);
if (isSet(EXPECT_PARSE_ERROR,config)) {
if (!p.hasParserErrors())
fail("Expected to find parse error");
} else {
if (p.hasParserErrors()) {
fail("Failed to parse: " + s + "\n" + p.getParserErrors().get(0).getMessage());
} else {
if (isSet(TYPE_CHECK, config)) {
if (isSet(WITH_LOC_INF, config)) {
LocationTypeInferrerExtension ltie = new LocationTypeInferrerExtension(p);
p.registerTypeSystemExtension(ltie);
}
SemanticConditionList l = p.typeCheck();
if (isSet(EXPECT_TYPE_ERROR,config)) {
if (!l.containsErrors()) {
fail("Expected type errors, but none appeared");
}
} else {
if (l.containsErrors()) {
fail("Failed to typecheck: " + s + "\n" + l.getFirstError().getMessage());
}
}
}
}
}
return p;
} catch (Exception t) {
throw new RuntimeException(t); // TODO: remove
}
}
protected Model assertParseError(String absCode) {
return assertParse(absCode, EXPECT_PARSE_ERROR);
}
/**
* Note: does not handle EXPECT_*.
*/
static public Model assertParseFileOk(String fileName, Config... config) throws IOException, WrongProgramArgumentException {
Main main = new Main();
main.setWithStdLib(isSet(WITH_STD_LIB,config));
Model m = main.parseFiles(resolveFileName(fileName));
m.evaluateAllProductDeclarations();
return assertParseModelOk(m, config);
}
protected Model assertParseFilesOk(Set<String> fileNames, Config... config) throws IOException {
Main main = new Main();
main.setWithStdLib(isSet(WITH_STD_LIB,config));
Model m = main.parseFiles(fileNames.toArray(new String[0]));
return assertParseModelOk(m, config);
}
static public Model assertParseModelOk(Model m, Config... config) throws IOException {
if (m != null) {
final StringBuffer errs;
String fileNames = m.getCompilationUnit(0).getFileName();
for (int i = 1; i < m.getCompilationUnits().getNumChild(); i++)
fileNames += " & " + m.getCompilationUnit(i).getFileName();
int parseErrs = m.getParserErrors().size();
if (parseErrs > 0) {
errs = new StringBuffer("Parse errors: " + parseErrs + ". First error:\n");
errs.append(m.getParserErrors().get(0));
fail("Failed to parse: " + fileNames + "\n" + errs.toString());
return m;
}
int numSemErrs = m.getErrors().getErrorCount();
errs = new StringBuffer("Semantic errors: " + numSemErrs + "\n");
if (numSemErrs > 0) {
for (SemanticCondition error : m.getErrors())
errs.append(error.getHelpMessage() + "\n");
fail("Failed to parse: " + fileNames + "\n" + errs.toString());
} else if (isSet(TYPE_CHECK, config)) {
SemanticConditionList l = m.typeCheck();
if (l.containsErrors()) {
for (SemanticCondition error : l)
errs.append(error.getHelpMessage() + "\n");
fail("Failed to typecheck: " + fileNames + "\n" + errs.toString());
}
}
}
return m;
}
}