package org.overture.core.testing.samples; import static org.junit.Assert.fail; import java.io.Serializable; import java.util.Collection; import java.util.List; import java.util.Vector; import org.apache.commons.collections4.CollectionUtils; import org.junit.Assert; import org.overture.ast.definitions.PDefinition; import org.overture.ast.modules.AModuleModules; import org.overture.ast.node.INode; import org.overture.core.testing.AbsResultTest; /** * When setting up a test you need a specific result type for your test. You can reuse it for * multiple testing but it will typically be specific to a particular module. * </p> * There is no interface defining this result so you can use whatever you want, including the classes that represent * your module's output directly. But it's a good idea to have a dedicated result class. It should be as small as * possible and only contain data that is actually relevant for test purposes. * </p> * {@link SampleTestResult} is extremely simple. It's simply a collection of strings, implemented by extending * {@link Vector}. It also has a couple of utility methods. * * @author ldc */ public class SampleTestResult extends Vector<String> implements Serializable, List<String> { private static final long serialVersionUID = 1L; /** * One of the things you must do is convert the output of your analysis into a test result. You can do it either * in the constructor or in a static method, as we have done here. * </p> * * @param ast This will typically be the output of your analysis. The ID analysis does nothing so this is just the * AST itself. * @return a new instance of {@link SampleTestResult} */ public static SampleTestResult convert(List<INode> ast) { SampleTestResult r = new SampleTestResult(); for (INode n : ast) { if (n instanceof AModuleModules) // ModuleModules prints the file path so we skip it { for (PDefinition p : ((AModuleModules) n).getDefs()) { r.add(p.toString()); } } else { r.add(n.toString()); } } return r; } /** * By default, result comparison is based on an equality check as part of assertEquals. This * behavior can be overridden to provide more sophisticated result comparison. If the comparison is * to be reused in multiple testing, it should be placed in a separate class as we have done here. * </p> * When overriding the behavior, it is important to do things: calling JUnit assertions or failures to ensure * the test integrates correctly and using {@link AbsResultTest#testInfo()} in failure messages so the test results are easy to update. * In this case, since the comparison is done in an external class, it receives the info message as a parameter. * * @param actual actual result * @param expected expected result * @param infoMessage name of the test */ public static void compare(SampleTestResult actual, SampleTestResult expected, String infoMessage) { Collection<String> stored_notfound = CollectionUtils.removeAll(expected, actual); Collection<String> found_notstored = CollectionUtils.removeAll(actual, expected); if (stored_notfound.isEmpty() && found_notstored.isEmpty()) { // Results match, testing pass;do nothing } else { StringBuilder sb = new StringBuilder(); sb.append(infoMessage); sb.append(" "); if (!stored_notfound.isEmpty()) { sb.append("Expected (but not found) Strings: " + "\n"); for (String pr : stored_notfound) { sb.append(pr + "\n"); } } if (!found_notstored.isEmpty()) { sb.append("Found (but not expected) Strings: " + "\n"); for (String pr : found_notstored) { sb.append(pr + "\n"); } } Assert.fail(sb.toString()); } } }