/*
* #%~
* Overture Testing Framework
* %%
* Copyright (C) 2008 - 2014 Overture
* %%
* 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 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/gpl-3.0.html>.
* #~%
*/
package org.overture.core.testing;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import org.junit.Assert;
import org.junit.Test;
import org.overture.ast.node.INode;
import org.overture.parser.lex.LexException;
import org.overture.parser.syntax.ParserException;
/**
* Standard test in the new Overture test framework. This class runs testing on (correct) VDM sources and compares them
* with stored result files. It is meant to be subclassed as a way to quickly create your own test suites.<br>
* <br>
* A comparison method for results must be provided. JSON-based serialization of results is fully automated and
* deserialization is close to it.<br>
* <br>
* These testing are meant to be run as parameterized JUnit test and so any subclass must be annotated with
* <code>@RunWith(Parameterized.class)</code>. <br>
* <br>
* This class also has a type parameter <code>R</code> that represents the output of the functionality under test. You
* should create a specific <code>R</code> type for your functionality and write some kind of transformation between
* your native output type and <code>R</code>.
*
* @author ldc
* @param <R>
*/
public abstract class ParamStandardTest<R> extends AbsResultTest<R>
{
/**
* Constructor for the test. In order to use JUnit parameterized testing, the inputs for this class must be supplied
* by a public static method. Subclasses must implement this method themselves and annotate with
* <code>@Parameters(name = "{index} : {0}")</code>.<br>
* <br>
* The {@link PathsProvider#computePaths(String...)} method produces the correct input for this constructor and
* should be called with the root folder of your testing inputs as its argument.
*
* @param nameParameter
* the name of the test. Normally derived from the test input file
* @param inputParameter
* file path for the VDM source to test
* @param resultParameter
* test result file
*/
public ParamStandardTest(String nameParameter, String inputParameter,
String resultParameter)
{
this.testName = nameParameter;
this.modelPath = inputParameter;
this.resultPath = resultParameter;
updateResult = updateCheck();
}
/**
* Execute this test. Constructs the AST for the model and processes it via {@link #processModel(List)}. Then loads
* a stored result via {@link #deSerializeResult(String)}. Finally, the two results are compared with
* {@link #compareResults(Object, Object)}.<br>
* <br>
* If the test is run in update mode, then no comparison is made. Instead, the new result is saved. <br>
* <br>
* This test is not designed to run on VDM sources with syntax or type errors. The test will fail if the source
* fails to parse or type check. While this behavior can be overridden, we suggest looking at
* {@link ParamFineGrainTest} if you need to cope with these errors.
*
* @throws IOException
* @throws LexException
* @throws ParserException
*/
@Test
public void testCase() throws ParserException, LexException, IOException
{
checkAssumptions();
List<INode> ast = ParseTcFacade.typedAst(modelPath, testName);
R actual = processModel(ast);
if (updateResult)
{
this.testUpdate(actual);
} else
{
R expected = null;
try
{
expected = deSerializeResult(resultPath);
} catch (FileNotFoundException e)
{
Assert.fail("Test " + testName
+ " failed. No result file found. Use \"-D"
+ getUpdatePropertyString() + "." + testName
+ "\" to create an initial one."
+ "\n The test result was: " + actual.toString());
}
this.compareResults(actual, expected);
}
}
/**
* Analyse a model. This method is called during test execution to produce the actual result. It must, of course, be
* overridden to perform whatever analysis the functionality under test performs.<br>
* <br>
* The output of this method must be of type <code>R</code>, the result type this test runs on. You will will likely
* need to have a conversion method between the output of your analysis and <code>R</code>.
*
* @param ast
* the model to process
* @return the output of the analysis
*/
public abstract R processModel(List<INode> ast);
protected void checkAssumptions() {}
}