/* * #%~ * Combinatorial Testing Runtime * %% * 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.ct.ctruntime; import java.io.File; import java.io.IOException; import java.util.List; import java.util.Vector; import org.overture.ast.analysis.AnalysisException; import org.overture.ast.definitions.ANamedTraceDefinition; import org.overture.ast.definitions.PDefinition; import org.overture.ast.definitions.SClassDefinition; import org.overture.ast.modules.AModuleModules; import org.overture.ast.node.INode; import org.overture.ast.util.modules.CombinedDefaultModule; import org.overture.config.Settings; import org.overture.ct.utils.TraceXmlWrapper; import org.overture.interpreter.runtime.ClassInterpreter; import org.overture.interpreter.runtime.Context; import org.overture.interpreter.runtime.ContextException; import org.overture.interpreter.runtime.Interpreter; import org.overture.interpreter.runtime.ModuleInterpreter; import org.overture.interpreter.runtime.ValueException; import org.overture.interpreter.traces.CallSequence; import org.overture.interpreter.traces.TestSequence; import org.overture.interpreter.traces.TraceReductionType; import org.overture.interpreter.traces.Verdict; import org.overture.typechecker.Environment; import org.overture.typechecker.ModuleEnvironment; import org.overture.typechecker.PrivateClassEnvironment; import org.overture.typechecker.assistant.ITypeCheckerAssistantFactory; public class TraceInterpreter { private final static boolean DEBUG = false; private static class StopWatch { static long before = 0; public static void set() { before = System.currentTimeMillis(); } public static void stop(String msg) { if (DEBUG) { long after = System.currentTimeMillis(); long duration = after - before; System.out.println("Completed '" + msg + "' in " + (double) duration / 1000 + " secs. "); } } } protected long beginClass = 0; protected long beginTrace = 0; protected String activeClass = ""; protected String activeTrace; Interpreter interpreter; protected File coverage; boolean reduce = false; protected float subset; protected long seed = 999; protected TraceReductionType traceReductionType = TraceReductionType.NONE; IProgressMonitor monitor = null; private Integer currentPct = 0; public final ITypeCheckerAssistantFactory assistantFactory; public TraceInterpreter(IProgressMonitor monitor, ITypeCheckerAssistantFactory af) { this.monitor = monitor; this.assistantFactory = af; } public TraceInterpreter(IProgressMonitor monitor, float subset, TraceReductionType traceReductionType, long seed, ITypeCheckerAssistantFactory af) { this(monitor, af); this.reduce = true; this.seed = seed; this.traceReductionType = traceReductionType; this.subset = subset; } public void run(String moduleName, String traceName, Interpreter interpreter, TraceXmlWrapper store) throws Exception { this.interpreter = interpreter; List<PDefinition> definitions = null; if (interpreter instanceof ModuleInterpreter) { for (AModuleModules module : ((ModuleInterpreter) interpreter).modules) { if (module.getName().getName().equals(moduleName)) { definitions = module.getDefs(); } } } else { for (SClassDefinition classDefinition : ((ClassInterpreter) interpreter).getClasses()) { if (classDefinition.getName().getName().equals(moduleName)) { definitions = assistantFactory.createPDefinitionAssistant().getDefinitions(classDefinition); } } } processTraces(definitions, moduleName, traceName, store); } private void processTraces(List<PDefinition> definitions, String className, String traceName, TraceXmlWrapper storage) throws Exception { try { Settings.prechecks = true; Settings.postchecks = true; Settings.dynamictypechecks = true; if (storage != null) { storage.StartClass(className); } Integer numberOfTraces = 0; for (Object string : definitions) { if (string instanceof ANamedTraceDefinition) { numberOfTraces++; } } infoProcessingClass(className, numberOfTraces); List<ANamedTraceDefinition> traceDefs = getAllTraceDefinitions(definitions, traceName); for (ANamedTraceDefinition def : traceDefs) { evaluateTraceDefinition(className, storage, def); } infoCompleted(); if (DEBUG) { System.out.println("Completed"); } } catch (ContextException e) { error(e.getMessage()); throw e; } catch (ValueException e) { error(e.getMessage()); throw e; } catch (Exception e) { error(e.getMessage()); throw e; } finally { if (storage != null) { storage.Stop(); } } } /** * obtain all trace definitions, or just the one named * * @param definitions * @param traceName * null or a name of a trace * @return a list of named trace definitions */ private List<ANamedTraceDefinition> getAllTraceDefinitions( List<PDefinition> definitions, String traceName) { List<ANamedTraceDefinition> traceDefs = new Vector<ANamedTraceDefinition>(); for (Object definition : definitions) { if (definition instanceof ANamedTraceDefinition) { if (traceName == null || ((ANamedTraceDefinition) definition).getName().getName().equals(traceName)) { traceDefs.add((ANamedTraceDefinition) definition); } } } return traceDefs; } protected void evaluateTraceDefinition(String className, TraceXmlWrapper storage, Object definition) throws ValueException, AnalysisException, Exception { interpreter.init(null); Context ctxt = interpreter.getInitialTraceContext((ANamedTraceDefinition) definition, false); evaluateTests(className, storage, definition, ctxt); } private void evaluateTests(String className, TraceXmlWrapper storage, Object traceDefinition, Context ctxt) throws Exception { ANamedTraceDefinition mtd = (ANamedTraceDefinition) traceDefinition; TestSequence tests = null; if (!reduce) { subset = 1.0F; traceReductionType = TraceReductionType.NONE; seed = 999; } tests = ctxt.assistantFactory.createANamedTraceDefinitionAssistant().getTests(mtd, ctxt, subset, traceReductionType, seed); int size = tests.size(); infoProcessingTrace(className, mtd.getName().getName(), size); if (storage != null) { storage.StartTrace(mtd.getName().getName(), mtd.getLocation().getFile().getName(), mtd.getLocation().getStartLine(), mtd.getLocation().getStartPos(), size, new Float(subset), TraceReductionType.valueOf(traceReductionType.toString()), new Long(seed)); } INode traceContainer = null; Environment rootEnv = null; if (interpreter instanceof ClassInterpreter) { traceContainer = mtd.getClassDefinition(); rootEnv = new PrivateClassEnvironment(interpreter.getAssistantFactory(), mtd.getClassDefinition(), interpreter.getGlobalEnvironment()); ; } else { traceContainer = mtd.parent(); if(((AModuleModules)traceContainer).getIsFlat()) { //search for the combined module for(AModuleModules m : ((ModuleInterpreter)interpreter).modules) { if(m instanceof CombinedDefaultModule) { traceContainer = m; break; } } } rootEnv = new ModuleEnvironment(interpreter.getAssistantFactory(), (AModuleModules) traceContainer); } int n = 1; int faildCount = 0; int inconclusiveCount = 0; int skippedCount = 0; StopWatch.set(); for (CallSequence test : tests) { StopWatch.stop("Getting test"); infoProcessingTest(className, mtd.getName().getName(), n, size); List<Object> result = null; Verdict verdict = null; try { if (interpreter instanceof ClassInterpreter) { Interpreter.typeCheck(traceContainer, interpreter, test, rootEnv); } else { Interpreter.typeCheck(traceContainer, interpreter, test, rootEnv); } } catch (Exception e) { result = new Vector<Object>(); result.add(e); verdict = Verdict.FAILED; result.add(verdict); } StopWatch.set(); result = evaluateCallSequence(mtd, test); StopWatch.stop("Executing "); StopWatch.set(); verdict = (Verdict) result.get(result.size() - 1); if (verdict == Verdict.ERROR) { } else { tests.filter(result, test, n); } switch (verdict) { case FAILED: faildCount++; break; case INCONCLUSIVE: inconclusiveCount++; break; default: break; } if (storage != null) {/* * Bodge until we figure out how to not have explicit op names. */ String clean = test.toString().replaceAll("\\.\\w+`", "."); storage.StartTest(new Integer(n).toString(), clean); storage.StopElement(); } if (test.getFilter() > 0) { skippedCount++; infoTestFiltered(n, test.getFilter(), test); if (storage != null) { storage.AddSkippedResult(new Integer(n).toString()); } } else { if (verdict == Verdict.ERROR) { if (storage != null) { storage.AddResults(new Integer(n).toString(), result); storage.AddTraceStatus(Verdict.valueOf(Verdict.FAILED.toString()), size, skippedCount, faildCount, inconclusiveCount); storage.StopElement(); } Exception e = (Exception) result.get(result.size() - 2); result.remove(result.size() - 2); throw e; } if (storage != null) { storage.AddResults(new Integer(n).toString(), result); } } n++; StopWatch.stop("store&filter"); StopWatch.set(); } if (storage != null) { Verdict worstVerdict = Verdict.PASSED; if (faildCount > 0) { worstVerdict = Verdict.FAILED; } else if (inconclusiveCount > 0) { worstVerdict = Verdict.INCONCLUSIVE; } storage.AddTraceStatus(Verdict.valueOf(worstVerdict.toString()), size, skippedCount, faildCount, inconclusiveCount); storage.StopElement(); } infoProcessingTraceFinished(className, mtd.getName().getName(), size, faildCount, inconclusiveCount, skippedCount); } /** * interpret a test * * @param mtd * @param test * @return list of results or list of errors */ protected List<Object> evaluateCallSequence(ANamedTraceDefinition mtd, CallSequence test) { List<Object> result; try { interpreter.init(null); /* Initialize completely between every run... */ result = interpreter.runOneTrace(mtd, test, false); } catch (Exception e) { result = new Vector<Object>(); result.add(e.getMessage()); result.add(e); result.add(Verdict.ERROR); } return result; } protected void infoProcessingTraceFinished(String className, String name, int size, int faildCount, int inconclusiveCount, int skippedCount) { } private void infoProcessingClass(String className, Integer traceCount) { preProcessingClass(className, traceCount); } protected void preProcessingClass(String className, Integer traceCount) { } protected void infoProcessingTrace(String className, String traceName, Integer testCount) throws IOException { if (monitor != null) { monitor.progressStartTrace(className + "`" + traceName); currentPct = 0; } preProcessingTrace(className, traceName, testCount); } protected void preProcessingTrace(String className, String traceName, Integer testCount) { } protected void infoProcessingTest(String className, String traceName, Integer testNumber, Integer total) throws IOException { if (monitor != null) { Integer pct = new Double((double) testNumber / (double) total * 100).intValue(); if (currentPct + 10 <= pct) { monitor.progress(pct); currentPct = pct; } } if (DEBUG) { System.out.println(testNumber); } } protected void infoCompleted() throws IOException { if (monitor != null) { monitor.progressCompleted(); } infoPrintTraceStatus(); infoPreCompleted(); } protected void infoPreCompleted() { } protected void infoTestFiltered(Integer number, Integer filteredBy, CallSequence test) { } protected void error(String message) throws IOException { System.err.println(message); if (this.monitor != null) { this.monitor.progressError(message); } } protected void typeError(String message) { System.err.println(message); } protected void parseError(String message) { System.err.println(message); } protected void typeCheckStarted() { } private void infoPrintTraceStatus() { infoPrePrintTraceStatus(); } protected void infoPrePrintTraceStatus() { } public void setCoverageDir(File coverageDir) { this.coverage = coverageDir; } }