/* * 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; iThe engine does not call this method directly. * *

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() ; }