/*
* 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 ;
}
}