FlexUnit4/src/org/flexunit/experimental/runners/statements/AssignmentSequencer.as (172 lines of code) (raw):
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.flexunit.experimental.runners.statements {
import org.flexunit.experimental.theories.IPotentialAssignment;
import org.flexunit.experimental.theories.internals.Assignments;
import org.flexunit.internals.AssumptionViolatedException;
import org.flexunit.internals.runners.model.MultipleFailureException;
import org.flexunit.internals.runners.statements.AsyncStatementBase;
import org.flexunit.internals.runners.statements.IAsyncStatement;
import org.flexunit.runners.model.FrameworkMethod;
import org.flexunit.token.AsyncTestToken;
import org.flexunit.token.ChildResult;
import org.flexunit.utils.ClassNameUtil;
/**
* The <code>AssignmentSequencer</code> is responsible for the sequencing of parameters to be provided
* to a particular theory method test. It determines what potential parameters need to be provided to the
* parameters in the theory test method.<br/>
*
* Based on the number of parameters in the theory method test, additional <code>AssignmentSequencer</code>s will
* be created. If there are still parameters that need to be assigned a value and there are still potential values
* to assign to those parameters, assign an unused value to the next parameter and create a new
* <code>AssignmentSequencer</code>, determining if all parameters have then been assigned a value. Once all of the
* parameters in the theory method test have been assigned, that theory method will be run with that configuration.
* All permutations of potential parameters will be provided to the theory method.
*/
public class AssignmentSequencer extends AsyncStatementBase implements IAsyncStatement {
/**
* @private
*/
protected var potential:Array;
/**
* @private
*/
protected var parameterAssignment:Assignments;
/**
* @private
*/
protected var counter:int = 0;
/**
* @private
*/
protected var errors:Array;
/**
* @private
*/
protected var testClass:Class;
/**
* @private
*/
protected var anchor:TheoryAnchor;
/**
* @private
*/
protected var frameworkMethod:FrameworkMethod;
/**
* Constructor.
*
* @param parameterAssignment The current parameter assignments for a theory method test.
* @param frameworkMethod The theory method that is being tested.
* @param testClass The test class that contains the theory method.
* @param anchor The anchor for the theory method.
*/
public function AssignmentSequencer( parameterAssignment:Assignments, frameworkMethod:FrameworkMethod, testClass:Class, anchor:TheoryAnchor ) {
super();
this.parameterAssignment = parameterAssignment;
this.testClass = testClass;
this.anchor = anchor;
this.frameworkMethod = frameworkMethod;
this.errors = new Array();
//Create a new token that will alert this class when the provided statement has completed
myToken = new AsyncTestToken( ClassNameUtil.getLoggerFriendlyClassName( this ) );
myToken.addNotificationMethod( handleChildExecuteComplete );
}
/**
* Determines if all parameters have been assigned for a particular configuration of a theory method. If they have
* all been assigned, run the theory with the particular parameter configuration. If all parameter values have not
* been assinged, determine what parameters can be provided to the next unassigned parameter.
*
* @param parentToken The token to be notified when the theory method has finished running for a particluar permutation
* of parameters.
*/
public function evaluate( parentToken:AsyncTestToken ):void {
this.parentToken = parentToken;
//Determine if all parameters for a theory have been assigned a value
if (!parameterAssignment.complete ) {
//incomplete, determine what parameters can be supplied to the next unassigned parameter
potential = parameterAssignment.potentialsForNextUnassigned();
handleChildExecuteComplete( null );
} else {
//complete, run the theory with the provided parameter configuration
runWithCompleteAssignment( parameterAssignment );
}
}
/**
* Determine if any errors were encountered if the theory method test executed. If the error was not an
* <code>AssumptionViolatedException</code>, add it to the array of encountered errors and stop running the theory test.
*
* If there are still parameters that need to be assigned a value and there are still potential values to assign to
* those parameters, assign an unused value to the next parameter and create a new <code>AssignmentSequencer</code>,
* determining if all parameters have then been assigned a value.
*
* If there are no furuther potential values to assign a parameter or all values have already been assigned to a parameter,
* this <code>AssignmentSequencer</code> has finished its duty to sequence parameters.
*
* @param result A <code>ChildResult</code> that contains potential errors encountered during the theory's execution.
*/
public function handleChildExecuteComplete( result:ChildResult ):void {
var source:IPotentialAssignment;
if ( result && result.error && !( result.error is AssumptionViolatedException ) ) {
errors.push( result.error );
}
if ( errors.length ) {
//we received an error that was not an AssumptionViolation, we need to bail out of this case
sendComplete();
return;
}
//i think we need to stop here on this error
if ( ( potential ) && ( counter < potential.length ) ) {
//Obtain a value that has yet to be assigned to a parameter
source = potential[ counter ] as IPotentialAssignment;
counter++;
var statement:AssignmentSequencer = new AssignmentSequencer( parameterAssignment.assignNext( source ), frameworkMethod, testClass, anchor );
statement.evaluate( myToken );
} else {
sendComplete();
}
}
/**
* Reports to the parentToken that the current configuration of parameter assignments have finished running in the theory
* method test and determines if any error were encountered during execution of that test.
*
* @param error A potential error that was encountered during a configuration of the theory meethod.
*/
override protected function sendComplete( error:Error=null ):void {
var sendError:Error;
if ( error ) {
errors.push( error );
}
if (errors.length == 1)
sendError = errors[ 0 ];
else if ( errors.length > 1 ) {
sendError = new MultipleFailureException(errors);
}
super.sendComplete( sendError );
}
/**
* Runs the theory for the <code>complete</code> set of assigned parameters.
*
* @param complete Contains a permutation of current assigned parameter / value pairs to be supplied to the
* theory method test for this particular configuration.
*/
protected function runWithCompleteAssignment( complete:Assignments ):void {
//trace( "Complete" );
var runner:TheoryBlockRunner = new TheoryBlockRunner( testClass, anchor, complete );
runner.getMethodBlock( frameworkMethod ).evaluate( myToken );
}
}
}