/* * 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.Engines; import Sequenic.T2.Seq.* ; import java.util.* ; import java.lang.reflect.* ; /** * This is an abstract class for generators that try to combinatorically * generates sequences. It extends the abstract class {@link BaseEngineSeqGenerator}, * and proving a default implementation of the its primitives. Implementation * of this class now has to implement a different set, but more abstract, * primitives. The primitive {@link CombinatoricSeqGenerator#next_sequence()} * should implement the procedure that produces a test * sequence. The primitive {@link CombinatoricSeqGenerator#META_mkArguments(java.lang.Class[]) } * should implement the procedure for generating arguments for a method call. * *
The sequences generated by this generator are made of only from field
* updates and method calls targeting the target-object (so we don't include
* static methods in the scope).
*/
abstract public class AbstractCombinatoricSeqGenerator extends BaseEngineSeqGenerator {
private List currentSequence ;
private int currentStep ;
private boolean exhausted ;
static public boolean debug = false ;
abstract public void init() ;
@Override
public MkValStep META_mkTargetObject(Class C) {
// Redoing a sigma is requested:
if (sigma_to_redo != null) return sigma_to_redo.creation ;
currentStep = 0 ;
currentSequence = next_sequence() ;
exhausted = currentSequence==null ;
if (exhausted) return null ;
if (debug) assert currentSequence.size()>0 ;
Constructor con = (Constructor) currentSequence.get(0) ;
currentStep++ ;
return new CREATE_OBJECT(con, META_mkArguments(con.getParameterTypes()),-1) ;
}
// Helper
private TraceStep generate_teststep(Object abstractstep, int indexOfTargetObj){
if (abstractstep instanceof Field) {
Field field = (Field) abstractstep ;
MkValStep[] args = META_mkArguments(new Class[] {field.getType()}) ;
return new UPDATE_FIELD(field, args[0]) ;
}
// Else step is a method call:
Method meth = (Method) abstractstep;
setCurrentMethod(meth);
return new CALL_METHOD(meth,
new REF(indexOfTargetObj),
META_mkArguments(meth.getParameterTypes())
) ;
}
@Override
public TraceStep META_mkTestStep(Trace sigma) {
// Redoing a sigma is requested:
if (sigma_to_redo!=null) {
if (! sigma_to_redo.trace.isEmpty()) return sigma_to_redo.trace.removeFirst() ;
else {
sigma_to_redo = null ;
TraceStep step = generate_teststep(currentSequence.get(currentStep),sigma.indexOfTargetObj) ;
return step ;
}
}
assert currentSequence != null ;
// Case 1: we have complete traverse the current sequence:
if (currentStep >= currentSequence.size()) return null ;
// Else take the next step in the current sequence:
TraceStep step = generate_teststep(currentSequence.get(currentStep),sigma.indexOfTargetObj) ;
currentStep++ ;
return step ;
}
@Override
public boolean isExhausted() {
return exhausted ;
}
/**
* This implements the procedure to construct the arguments to the test
* steps. The default implementation here is to generate them randomly,
* using the procedure implemented in {@link BaseEngine}.
*/
public MkValStep[] META_mkArguments(Class[] argtypes) {
MkValStep[] args = new MkValStep[argtypes.length] ;
for (int i=0; i If a null is returned, then this is interpreted as the generator has
* no more sequence to generate (exhausted).
*/
abstract public List next_sequence() ;
abstract public int totalNumberOfCombinations() ;
}