/*
* #%~
* 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.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Type;
import org.apache.commons.io.IOUtils;
import org.junit.Assert;
import org.overture.parser.lex.LexException;
import org.overture.parser.syntax.ParserException;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
/**
* Top level class for new testing framework. Provides common result handling code to all other test classes. This class
* should <b>not</b> be subclassed directly. Use one of its existing subclasses instead. Test results are always stored
* with UTF-8 encoding.
*
* @param <R> the (user-provided) type of results this test operates on
* @author ldc
* @see ParamExternalsTest
* @see ParamFineGrainTest
* @see ParamStandardTest
*/
public abstract class AbsResultTest<R> {
protected boolean updateResult;
protected String resultPath;
protected String testName;
protected String modelPath;
/**
* Deserialize test results. This method is capable of deserializing most results, provided the correct type
* information is provided via getResultType(). If your results are too complex for this method or if you are not
* using JSON to store then, them you must override the entire method.
*
* @param resultPath the file path to the stored result file
* @return the deserialized stored result
* @throws IOException
* @throws FileNotFoundException
*/
public R deSerializeResult(String resultPath) throws FileNotFoundException,
IOException {
Gson gson = new Gson();
Type resultType = getResultType();
// check if exists
File f = new File(resultPath);
if (!f.exists()) {
f.getParentFile().mkdirs();
throw new FileNotFoundException(resultPath);
}
InputStreamReader reader = new InputStreamReader(new FileInputStream(new File(resultPath)), ParseTcFacade.UTF8);
String json = IOUtils.toString(reader);
R result = gson.fromJson(json, resultType);
return result;
}
/**
* Calculate the type of the test result. This method must be overridden to provide the specific result type for
* each test. When doing so, you can use the snippet below (replacing <code>R</code> with the actual type of your
* result). Keep in mind this does not work for wildcards or type parameters. You <b>must</b> declare the actual
* type. <pre>{@code
* Type resultType = new TypeToken< R >() {}.getType(); <br>
* return resultType;
* }</pre>
*
* @return the {@link Type} of the result file
* @see TypeToken
*/
abstract public Type getResultType();
/**
* Return the Java System property to update this set of testing. Should have the following naming scheme:
* <code>testing.update.[maven-module].[test-class].[testcase/input-file]>. <br>
* <br>
* The test ID <b>must</b> be unique to each test.
* the module is enough.
*
* @return the test Update Property, as a {@link String}
*/
protected abstract String getUpdatePropertyString();
/**
* Returns a message on how to update test results. Should be used in {@link #compareResults(Object, Object)}. * @return
* the result update message.
* <p/>>
* This method is deprecated. Use testInfo instead.
*/
@Deprecated
protected String getTestResultUpdateMessage() {
StringBuilder sb = new StringBuilder();
sb.append("Use -D\"");
sb.append(getUpdatePropertyString());
sb.append("\" to update the result file");
return sb.toString();
}
/**
* Update the result file for this test. Result serialization is done with JSON and this should adequate for most
* users. If you need an alternative format, you may override this method.
*
* @param actual the new result to be saved
* @throws ParserException
* @throws LexException
* @throws IOException
*/
protected void testUpdate(R actual) throws ParserException, LexException,
IOException {
Gson gson = new Gson();
String json = gson.toJson(actual);
// Make sure file can be created
File f = new File(resultPath);
if (!f.exists()) {
f.getParentFile().mkdirs();
}
IOUtils.write(json, new FileOutputStream(resultPath), ParseTcFacade.UTF8);
}
/**
* Computes an information message to be used with test failures. This message reports
* on:
* <li>Test Input Source path</li>
* <li>Result File path</li>
* <li>Test Override property</li>
*
* @return the information message, as a {@link String}
*/
protected String testInfo() {
StringBuilder sb = new StringBuilder();
sb.append("[Input: ");
sb.append(modelPath);
sb.append(", Result:");
sb.append(resultPath);
sb.append(", Update Property:");
sb.append(getUpdatePropertyString());
sb.append(".");
sb.append(testName);
sb.append("]");
return sb.toString();
}
/**
* Check if test running in result update mode. This is done by consulting the update property as returned by {
* {@link #getUpdatePropertyString()}.
*
* @return True if test is running in update mode. False otherwise
*/
protected boolean updateCheck() {
String update_results_property = getUpdatePropertyString();
// check update this test
if (System.getProperty(update_results_property + "." + testName) != null) {
return true;
}
// check update all
if (System.getProperty(update_results_property) != null) {
return true;
}
return false;
}
/**
* This is the first method to be invoked in the test case. It provides a convenient place to place
* {@link org.junit.Assume} assumptions.
*/
protected void checkAssumptions() {
}
/**
* Compare output of the processed model with previously stored result. This method may be overridden to implement
* more sophisticated result comparison behavior. By default, it applies assertEquals. If you override
* this method, please call {@link #testInfo()} in the failure message.
*
* @param actual the result processed model
* @param expected the stored result
*/
public void compareResults(R actual, R expected){
Assert.assertEquals(this.testInfo(),actual,expected);
}
}