Skip to content

Instantly share code, notes, and snippets.

@wolever
Created February 10, 2010 00:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wolever/299871 to your computer and use it in GitHub Desktop.
Save wolever/299871 to your computer and use it in GitHub Desktop.
// (c) 2010 David Wolever <david@wolever.net> and Verso Furniture Inc.
// See the bottom of this file for copyright details.
package utils.testrunners {
import flash.utils.getQualifiedClassName;
import org.flexunit.internals.runners.model.EachTestNotifier;
import org.flexunit.internals.runners.statements.IAsyncStatement;
import org.flexunit.runner.*;
import org.flexunit.runner.notification.IRunNotifier;
import org.flexunit.runners.BlockFlexUnit4ClassRunner;
import org.flexunit.runners.ParentRunner;
import org.flexunit.runners.model.FrameworkMethod;
import org.flexunit.token.AsyncTestToken;
import org.flexunit.token.ChildResult;
import org.flexunit.utils.ClassNameUtil;
/**
* Extends the BlockFlexUnit4ClassRunner, allowing children to specify
* arguments which will be passed to the test methods.
* Children returned by 'computeTestMethods' are expected to look something
* like this:
* child = {
* method:FrameworkMethod = the method to run,
* args:Array = arguments to pass to the method,
* description:String = an optional description of the test,
* }
*/
public class BlockWithArgumentsRunner extends BlockFlexUnit4ClassRunner {
public function BlockWithArgumentsRunner(klass:Class) {
super(klass);
}
override protected function runChild(child:*, notifier:IRunNotifier,
childRunnerToken:AsyncTestToken):void {
var method:FrameworkMethod = FrameworkMethod(child.method);
var eachNotifier:EachTestNotifier;
eachNotifier = new EachTestNotifier(notifier, describeChild(child));
if (method.hasMetaData("Ignore")) {
eachNotifier.fireTestIgnored();
childRunnerToken.sendResult();
return;
}
var token:AsyncTestToken;
token = new AsyncTestToken(ClassNameUtil.getLoggerFriendlyClassName(this));
token.parentToken = childRunnerToken;
token.addNotificationMethod(handleBlockComplete);
token[ParentRunner.EACH_NOTIFIER] = eachNotifier;
var error:Error;
eachNotifier.fireTestStarted();
try {
var block:IAsyncStatement;
_hackyArguments = child.args;
block = methodBlock(method);
_hackyArguments = null;
block.evaluate(token);
} catch (e:Error) {
error = e;
eachNotifier.addFailure(e);
}
if (error) {
eachNotifier.fireTestFinished();
childRunnerToken.sendResult();
}
}
// These hacky arguments are required
protected var _hackyArguments:Array;
override protected function methodInvoker(method:FrameworkMethod,
test:Object):IAsyncStatement {
return new InvokeMethodWithArgs(method, test, _hackyArguments);
}
protected function handleBlockComplete(result:ChildResult):void {
var error:Error = result.error;
var token:AsyncTestToken = result.token;
var eachNotifier:EachTestNotifier = result.token[EACH_NOTIFIER];
if (error) {
eachNotifier.addFailure(error);
}
eachNotifier.fireTestFinished();
token.parentToken.sendResult();
}
override protected function computeTestMethods():Array {
return super.computeTestMethods().map(
function(method:FrameworkMethod, ..._):Object {
return { args: [], method: method };
});
}
protected var ARG_LENGTH:int = 25;
protected function describeArgs(args:Array):String {
return args.map(function(arg:*, ..._):String {
var argStr:String = arg.toString();
argStr = argStr.replace(/^[ \t\n]*/, "");
return truncate(argStr, ARG_LENGTH);
}).join(", ");
}
override protected function describeChild(child:*):IDescription {
var description:String;
description = getQualifiedClassName(testClass.asClass) + ".";
description += child.method.name + "(";
description += child.description? child.description :
describeArgs(child.args);
description += ")";
return new Description(description, child.method.metadata);
}
protected function truncate(string:String, maxLength:int,
removeEnd:Boolean=true):String {
if (string.length <= maxLength) {
return string;
}
if (removeEnd)
return string.substr(0, maxLength - 1) + "…";
else
return "…" + string.substring(string.length-maxLength+1, string.length);
}
}
}
/*
tl;dr: this code is licensed under simplified BSD.
Copyright 2010 David Wolever <david@wolever.net> and Verso Furniture Inc. All
rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of <copyright holder>.
*/
// (c) 2010 David Wolever <david@wolever.net> and Verso Furniture Inc.
// See the bottom of this file for copyright details.
package utils.testrunners {
import org.flexunit.internals.runners.statements.InvokeMethod;
import org.flexunit.token.AsyncTestToken;
import org.flexunit.runners.model.FrameworkMethod;
import org.flexunit.internals.runners.statements.IAsyncStatement;
import org.flexunit.internals.runners.statements.AsyncStatementBase;
import flexunit.framework.Test;
import org.flexunit.utils.ClassNameUtil;
public class InvokeMethodWithArgs extends AsyncStatementBase
implements IAsyncStatement {
protected var args:Array;
protected var testMethod:FrameworkMethod;
protected var target:Object;
public function InvokeMethodWithArgs(testMethod:FrameworkMethod,
target:Object, args:Array) {
this.args = args;
this.testMethod = testMethod;
this.target = target;
}
public function evaluate(parentToken:AsyncTestToken):void {
var myToken:AsyncTestToken;
myToken = new AsyncTestToken(ClassNameUtil.getLoggerFriendlyClassName(this));
myToken.addNotificationMethod(function(_:*):void {
parentToken.sendResult(null);
});
this.parentToken = parentToken;
//Invoke the test method
try {
testMethod.invokeExplosivelyAsync.apply(testMethod,
[myToken, target].concat(args));
} catch (error:Error) {
parentToken.sendResult(error);
}
}
}
}
/*
tl;dr: this code is licensed under simplified BSD.
Copyright 2010 David Wolever <david@wolever.net> and Verso Furniture Inc. All
rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of <copyright holder>.
*/
// (c) 2010 David Wolever <david@wolever.net> and Verso Furniture Inc.
// See the bottom of this file for copyright details.
// The most recent version can, until I get a better repository, be found
// at: http://gist.github.com/299871
package utils.testrunners {
import flash.utils.getQualifiedClassName;
import flex.lang.reflect.metadata.MetaDataAnnotation;
import org.flexunit.internals.runners.model.EachTestNotifier;
import org.flexunit.internals.runners.statements.IAsyncStatement;
import org.flexunit.runner.notification.IRunNotifier;
import org.flexunit.runners.ParentRunner;
import org.flexunit.runners.model.FrameworkMethod;
import org.flexunit.token.AsyncTestToken;
import org.flexunit.token.ChildResult;
import org.flexunit.utils.ClassNameUtil;
/**
* Parameterize a testcase.
* (this class is still in development and will have a few rough edges)
* For example:
*
* [RunWith("utils.testrunners.ParameterizedRunner")]
* class AdditionTests {
* // Force the MXMLC to link in the ParameterizedRunner class
* protected var _forceMXMLCToLinkRunner:ParameterizedRunner;
*
* // Note: parameters must be a public static class variable
* public static var numbersToTest:Array = [
* [1, 2, 3],
* [4, 5, 9],
* [-1, 1, 0]
* };
*
* [Parameterized("numbersToTest")]
* public function testAddition(a:int, b:int, expected:int):void {
* assertEqual(a+b, expected);
* }
* }
*
* Will cause three tests to be executed.
*/
public class ParameterizedRunner extends BlockWithArgumentsRunner {
public function ParameterizedRunner(klass:Class) {
super(klass);
}
override protected function computeTestMethods():Array {
var children:Array = [];
var method:FrameworkMethod;
var paramName:String;
for each (method in testClass.getMetaDataMethods("Parameterized")) {
var allParams:Array;
var thisTestParams:*;
for each (var metadata:MetaDataAnnotation in method.metadata) {
if (metadata.name == "Parameterized") {
paramName = metadata.arguments[0].key;
break;
}
}
if (!(paramName in testClass.asClass))
throw Error("Class " + testClass.asClass + " doesn't have " +
" property " + paramName);
allParams = testClass.asClass[paramName];
for each (thisTestParams in allParams) {
if (!(thisTestParams is Array))
thisTestParams = [thisTestParams];
children.push({ args: thisTestParams, method: method });
}
}
return children.concat(super.computeTestMethods());
}
}
}
/*
tl;dr: this code is licensed under simplified BSD.
Copyright 2010 David Wolever <david@wolever.net> and Verso Furniture Inc. All
rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY EXPRESS OR
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
EVENT SHALL <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
The views and conclusions contained in the software and documentation are those
of the authors and should not be interpreted as representing official policies,
either expressed or implied, of <copyright holder>.
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment