/* * Copyright 2007 Wishnu Prasetya. * * This file is part of T2. * T2 is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License (GPL) as published by the * Free Software Foundation; either version 3 of the License, or any * later version. * * T2 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. * * A copy of the GNU General Public License can be found in T2 distribution. * If it is missing, see http://www.gnu.org/licenses. */ package Sequenic.T2.Seq; import Sequenic.T2.Pool; import Sequenic.T2.Obj.*; //import Sequenic.T2.Msg.*; //import Sequenic.T2.Reflection.* import java.util.*; import java.lang.reflect.*; import java.io.*; /** * A Trace is a meta representation of test, which is a sequence of test-steps. * A test-step is for example updating a field of a target object, or calling * one of its methods. Being a meta representation means that a Trace in itself * does not cause the test to execute. To execute it, we have to call a special * method that will interpret the trace, and turns it to an execution. The * advantage of having a meta representation of a test is that we can do things * with it, like saving it, reloading it, changing it, and so on. * See also the doc of the {@link Sequenic.T2 Sequenic.T2 package}. * *

To be more precise, a trace consists of a creation step, that creates a * target object (the object on which the test will be applied on), and a sequence of subsequent {@link * Sequenic.T2.Trace.TraceStep TraceStep objects}. The creation step is a * {@link Sequenic.T2.Trace.MkValStep MkVal object}. A * MkVal object is also a meta representation, which is ínterpreted can create an * object, whereas a trace step is * used to apply side effects on the target object. A trace step may * also consist of MkVal steps, e.g. when it needs to create objects * to pass as parameters to a method. */ public class Trace implements Serializable { /** * The creation step that starts this execution trace. */ public MkValStep creation = null; /** * The sequence of steps belonging to this trace. */ public LinkedList trace = new LinkedList(); /** * Implicitly there is a pool associated to a trace. The pool * is used to keep track of object generated when the trace * is generated. This field gives the index of the target object * in this pool. */ public int indexOfTargetObj = -1; /** * Is set to true when this trace is marked a violating. */ public boolean violating = false ; /** * Is set to true when this trace is marked as diverging. */ public boolean diverging = false ; /** * Used to classify different kind of traces, e.g. to distinguish * violating and non-violating traces. The purpose of this field is * mainly to quickly filter traces without having to execute them. */ //public String classification = null; /** * Currently these are the only classifications :) */ //public static final String VIOLATING_TRACE = "VIOLATING TRACE"; //public static final String DIVERGING_TRACE = "POSSIBLY NON TERMINATING TRACE"; /** * This method will try to execute *all* steps in this trace, even if * it is marked as DIVERGING. The execution is stopped when a violation * is detected. An trace execution report will be returned, from which * it can be inferred if e.g. the execution finds a new violation, * or if a violation that was found in the execution producing the trace * now disappears. * *

Particularly with divergence, this method in itself does not * implement a time out mechanism or such. So it cannot force a diverging * step to stop. Such a mechanism is assumed to be implemented in either * the step execution system, or on the external framework that uses this * method. * *

If no such stopping mechanism is present, then one should take into * account that this method may thus diverge. * * @param pool Pass here the same pool as used to produce this * execution trace. * * @param printIntermediateStepsOption When true (default) report will * include the report of intermediate steps in a trace. Else only the * creation of the target object and the last two steps will be reported. */ public TraceExecInfo execAllSteps(Class CUT, Pool pool, List classinvs, boolean printIntermediateStepsOption, ReportersPool reporters) { boolean produceReport = reporters != null; pool.reset(); TraceExecInfo info = new TraceExecInfo(this) ; Object targetObj = null; int stepNr = 0 ; boolean ok = true ; //System.out.println("***"+ Show.show(creation)) ; if (produceReport) reporters.reportTraceBegin(); ok = info.update_with_step(creation.MkTargetObject(CUT, pool, classinvs, reporters), stepNr) ; //System.out.println(">>> " + ok + info.new_violating_flag + info.lastStepResult.isAsmOrReqViolating()) ; stepNr++; if (ok) { // no violation found targetObj = pool.get(indexOfTargetObj) ; assert (targetObj == info.lastStepResult.targetObj) ; for (TraceStep step : trace) { //System.out.println(">>> " + trace.size()) ; if (!printIntermediateStepsOption && stepNr <= trace.size() - 2) { ok = info.update_with_step(step.exec(CUT, pool, targetObj, stepNr, classinvs, null), stepNr) ; } else { ok = info.update_with_step(step.exec(CUT, pool, targetObj, stepNr, classinvs, reporters), stepNr) ; } stepNr++ ; if (!ok) break; } } if (produceReport) { reporters.reportTraceEnd(); } return info; } /** * As either execAllSteps or execAllStepsButLastDiv, depending on the boolean * flag given. */ public TraceExecInfo exec(Class CUT, Pool pool, List classinvs, boolean assumeLastStepDiverging, boolean printIntermediateStepsOption, ReportersPool reporters ) { if (assumeLastStepDiverging) return execAllStepsButLastDiv(CUT,pool,classinvs,printIntermediateStepsOption,reporters) ; else return execAllSteps (CUT,pool,classinvs,printIntermediateStepsOption,reporters) ; } /** * This is as execAllSteps. BUT the last step in the trace is ASSUMED * to be diverging, and will not be executed. If no violation up to * this last-step, this method will provide a meta-reporting of the * last-step, and just assume that it is diverging (which will be * reflected in the info it returns). */ public TraceExecInfo execAllStepsButLastDiv(Class CUT, Pool pool, List classinvs, boolean printIntermediateStepsOption, ReportersPool reporters) { assert (creation != null) ; TraceExecInfo info = null ; int traceLength = this.trace.size() + 1 ; METARUN laststep = null ; if (trace.size()>0) { laststep = trace.removeLast() ; info = execAllSteps(CUT, pool,classinvs,printIntermediateStepsOption,reporters) ; if (info.found_new_violation()) return info ; } else laststep = creation ; // No new violation found; now only the last step remains. // We don't execute the last step, we just // make a meta-report of it, and ASSUMING it would be diverging: Object targetObj = null ; if (indexOfTargetObj >= 0) targetObj = pool.get(indexOfTargetObj) ; info.lastStepResult = new ExecResult(CUT,laststep,targetObj) ; info.lastStepResult.possiblyDiverging = true ; info.new_diverging_flag = true ; info.violation_location = traceLength - 1 ; if (reporters!=null) reporters.reportStep(info.lastStepResult,0) ; return info ; } }