";
private static const END_OF_TEST_ACK : String ="";
private var _totalTests:uint = 0;
private var _totalErrors:uint = 0;
private var _totalFailures:uint = 0;
private var _numTestsRun:uint = 0;
public var test:Test;
private var reports : Object = new Object();
private var socket : XMLSocket;
private var connectionTries : int = 0;
private var connectionTryMax : int = 10;
public var reportXML : Boolean = true;
[Inspectable]
public var port : uint = 1024;
[Inspectable]
public var server : String = "127.0.0.1";
public function onCreationComplete():void
{
suiteMetaData = new Object();
}
public function startTest():void
{
flexunit.flexui.TestRunner.afterTest = afterTest;
flexunit.flexui.TestRunner.beforeTest = beforeTest;
if( test != null )
{
_totalTests = test.countTestCases();
progressBar.minimum = 0;
testFailures.dataProvider = new Array();
allTestsList.dataProvider = new Array();
updateLabels();
flexunit.flexui.TestRunner.run( test, this );
}
}
private function updateLabels():void
{
runLabel.htmlText = "Run: "+_numTestsRun.toString()+"/"+_totalTests.toString();
errorsLabel.htmlText = "Errors: "+_totalErrors.toString();
failuresLabel.htmlText = "Failures: "+_totalFailures.toString();
}
private function updateProgress():void
{
progressBar.setProgress( _numTestsRun, _totalTests );
if( _totalErrors > 0 || _totalFailures > 0 )
progressBar.setStyle("barColor",0xFF0000);
}
private function addFailureToList( test:Test, error:Error ):void
{
var t:TestCase = test as TestCase;
if( t != null )
{
ListCollectionView(testFailures.dataProvider).addItem( {label: t.toString(), error:error} );
testFailures.selectedIndex = testFailures.dataProvider.length;
testFailures.verticalScrollPosition = testFailures.maxVerticalScrollPosition;
onTestSelected();
}
}
private function onTestSelected():void
{
var list:List = (testTabs.selectedIndex == 0) ? testFailures : allTestsList;
var errorString:String;
if( list.selectedItem != null )
if( list.selectedItem.error != null )
{
this.currentState = "StackTraceView";
errorString = list.selectedItem.error.getStackTrace();
if (errorString == null)
{
errorString = list.selectedItem.error.message;
}
stackTrace.text = errorString;
testDetails.text = "Stack Trace";
}
else
{
this.currentState = "ResultsView";
//testDetails.text = "Test Details";
var dp_TestResults:ArrayCollection = new ArrayCollection();
var dp_MemUsage:ArrayCollection = new ArrayCollection();
resultsGrid.dataProvider = dp_TestResults;
rawMemGrid.dataProvider = dp_MemUsage;
var setUpDuration : String = list.selectedItem.setUpDuration.toFixed(3);
var middleDuration : String = list.selectedItem.middleDuration.toFixed(3);
var tearDownDuration : String = list.selectedItem.tearDownDuration.toFixed(3);
dp_TestResults.addItem({stage: "SetUp", duration: setUpDuration, memUsage: list.selectedItem.setUpMemFinal - list.selectedItem.setUpMemInitial});
dp_TestResults.addItem({stage: "Middle", duration: middleDuration, memUsage: list.selectedItem.middleMemFinal - list.selectedItem.middleMemInitial});
dp_TestResults.addItem({stage: "TearDown", duration: tearDownDuration, memUsage: list.selectedItem.tearDownMemFinal - list.selectedItem.tearDownMemInitial});
dp_MemUsage.addItem({initialMem: list.selectedItem.setUpMemInitial, finalMem: list.selectedItem.tearDownMemFinal, memDifference: (list.selectedItem.tearDownMemFinal - list.selectedItem.setUpMemInitial)});
dp_TestResults = null;
dp_MemUsage = null;
}
}
private function addTestToList( success:Boolean, test:Test, error:Error = null ):void
{
var t:TestCase = test as TestCase;
if( t != null )
{
var label:String = ( success ) ? "[PASS] " : "[FAIL] ";
// get mem data from test here - don't add it to the data provider
ListCollectionView(allTestsList.dataProvider).addItem( {label:label+t.toString(),
error:error,
setUpDuration:t.setUpDuration,
middleDuration:t.middleDuration,
tearDownDuration:t.tearDownDuration,
setUpMemInitial:t.setUpMemInitial,
setUpMemFinal:t.setUpMemFinal,
middleMemInitial:t.middleMemInitial,
middleMemFinal:t.middleMemFinal,
tearDownMemInitial:t.tearDownMemInitial,
tearDownMemFinal:t.tearDownMemFinal
} );
allTestsList.selectedIndex = allTestsList.dataProvider.length;
allTestsList.verticalScrollPosition = allTestsList.maxVerticalScrollPosition;
onTestSelected();
}
}
//---------------------------------------------------------------------
// IFlexWriter Methods
//---------------------------------------------------------------------
public function onTestStart( test:Test ) : void
{
titlePanel.title = "Test Runner (running: " + test.toString() + ")";
if (reportXML)
addMethod( test );
}
public function onTestEnd( test:Test ) : void
{
//only run if reportXML is enabled
if (reportXML)
{
if (test is TestCase)
{
var time : Number = TestCase(test).setUpDuration + TestCase(test).middleDuration + TestCase(test).tearDownDuration;
// Add time to the method.
var methodObject : Object = getMethod( test );
methodObject.time = time;
methodObject.setuptime = TestCase(test).setUpDuration;
methodObject.setupmeminitial = TestCase(test).setUpMemInitial;
methodObject.setupmemfinal = TestCase(test).setUpMemFinal;
methodObject.middletime = TestCase(test).middleDuration;
methodObject.middlememinitial = TestCase(test).middleMemInitial;
methodObject.middlememfinal = TestCase(test).middleMemFinal;
methodObject.teardowntime = TestCase(test).tearDownDuration;
methodObject.teardownmeminitial = TestCase(test).tearDownMemInitial;
methodObject.teardownmemfinal = TestCase(test).tearDownMemFinal;
}
Security.loadPolicyFile("xmlsocket:\\" + server + ":" + port);
// If we have finished running all the tests send the results.
if ( (_numTestsRun+1) == _totalTests )
{
sendResults();
}
}
_numTestsRun++;
updateLabels();
updateProgress();
titlePanel.title = "Test Runner";
}
public function onAllTestsEnd() : void
{
progressBar.setProgress(100,100);
if( _totalErrors == 0 && _totalFailures == 0 )
progressBar.setStyle("barColor",0x00FF00);
}
public function onSuccess( test:Test ):void
{
addTestToList( true, test );
}
public function onError( test:Test, error:Error ) : void
{
_totalErrors++;
addFailureToList( test, error );
addTestToList( false, test, error );
if (reportXML)
addError( test, error);
}
public function onFailure( test:Test, error:AssertionFailedError ) : void
{
_totalFailures++;
addFailureToList( test, error );
addTestToList( false, test, error );
if (reportXML)
addFailure( test, AssertionFailedError(error));
}
//---------------------------------------------------------------------
// JUnitRunner Methods
//---------------------------------------------------------------------
/**
* Add the currently executing method on a Test to the internal report
* model.
* @param test the Test.
*/
private function addMethod( test : Test ) : void
{
var reportObject : Object = getReport( test );
reportObject.tests++;
var methodName : String = TestCase(test).toString();
var methodsObject : Object = reportObject.methods;
var methodObject : Object = new Object();
methodsObject[ methodName ] = methodObject;
methodObject.classname = test.className;
methodObject.metaData = TestCase(test).metaData;
methodObject.name = methodName;
methodObject.time = 0.0;
methodObject.setuptime = 0.0;
methodObject.setupmeminitial = 0.0;
methodObject.setupmemfinal = 0.0;
methodObject.middletime = 0.0;
methodObject.middlememinitial = 0.0;
methodObject.middlememfinal = 0.0;
methodObject.teardowntime = 0.0;
methodObject.teardownmeminitial = 0.0;
methodObject.teardownmemfinal = 0.0;
}
/**
* Called when an error occurs.
* @param test the Test that generated the error.
* @param error the Error.
*/
public function addError( test : Test, error : Error ) : void
{
// Increment error count.
var report : Object = getReport( test );
report.errors++;
// Add the error to the method.
var methodObject : Object = getMethod( test );
var errorObject : Object = new Object();
methodObject.error = errorObject;
errorObject.type = getClassName( error );
errorObject.message = error.message;
}
/**
* Called when a failure occurs.
* @param test the Test that generated the failure.
* @param error the failure.
*/
public function addFailure( test : Test, error : AssertionFailedError ) : void
{
// Increment failure count.
var report : Object = getReport( test );
report.failures++;
// Add the failure to the method.
var methodObject : Object = getMethod( test );
var failureObject : Object = new Object();
methodObject.failure = failureObject;
failureObject.type = getClassName( error );
failureObject.message = error.message;
}
/**
* Return the fully qualified class name for an Object.
* @param obj the Object.
* @return the class name.
*/
private function getClassName( obj : Object ) : String
{
var description : XML = describeType( obj );
var className : Object = description.@name;
return className[ 0 ];
}
/**
* Return the method Object from the internal report model for the
* currently executing method on a Test.
* @param test the Test.
* @return the method Object.
*/
private function getMethod( test : Test ) : Object
{
var reportObject : Object = getReport( test );
var methodsObject : Object = reportObject.methods;
var methodName : String = TestCase(test).toString()
return methodsObject[ methodName ];
}
/**
* Return the report Object from the internal report model for the
* currently executing Test.
* @param Test the test.
*/
private function getReport( test : Test ) : Object
{
var reportObject : Object;
var className : String = test.className;
// Check we have a report Object for the executing Test, if not
// create a new one.
if ( reports[ className ] )
{
reportObject = reports[ className ];
}
else
{
reportObject = new Object();
reportObject.name = className;
reportObject.errors = 0;
reportObject.failures = 0;
reportObject.tests = 0;
reportObject.time = getTimer()/1000;
reportObject.methods = new Object();
reports[ className ] = reportObject;
}
return reportObject;
}
/**
* Sends the results. This sends the reports back to the controlling Ant
* task using an XMLSocket.
*/
public function sendResults() : void
{
// Open an XML socket.
socket = new XMLSocket();
socket.addEventListener( Event.CONNECT, handleConnect );
socket.addEventListener( DataEvent.DATA, dataHandler );
socket.addEventListener( IOErrorEvent.IO_ERROR, handleIOError );
socket.addEventListener( SecurityErrorEvent.SECURITY_ERROR, handleSecurityError );
socket.connect( server, port );
}
private function handleSecurityError( event : Event ) : void
{
var e:SecurityErrorEvent = event as SecurityErrorEvent;
throw new Error("SecurityErrorEvent on Connect-> " + e.target + ": " +
e.type + ". " + e.text + ".");
}
private function handleIOError( event : Event ) : void
{
if(connectionTries <= connectionTryMax){
connectionTries++;
sendResults();
}else{
var e:IOErrorEvent = event as IOErrorEvent;
throw new Error("IOErrorEvent on Connect-> " + e.target + ": " +
e.type + ". " + e.text + ". " + socket.connected + " " + server + ":" + port);
}
}
/**
* Event listener to handle data received on the socket.
* @param event the DataEvent.
*/
private function dataHandler( event : DataEvent ) : void
{
var data : String = event.data;
// If we received an acknowledgement finish-up.
if ( data == END_OF_TEST_ACK )
{
exit();
}
}
private function handleConnect( event : Event ) : void
{
for ( var className : String in reports )
{
// Create the XML report.
var xml : XML = createXMLReport( reports[ className ] );
// Send the XML report.
socket.send( xml.toXMLString() );
}
// Send the end of reports terminator.
socket.send( END_OF_TEST_RUN );
}
/**
* Create the XML report.
* @param obj the report Object.
* @return the XML report.
*/
private function createXMLReport( obj : Object ) : XML
{
// Create the test suite element.
var testSuite : XML = createTestSuite( obj );
// Create the test case elements.
var methodsObject : Object = obj.methods;
for ( var methodName : String in methodsObject )
{
var methodObject : Object = methodsObject[ methodName ];
var testCase : XML = createTestCase( methodObject );
// Create the failure element.
if ( methodObject.failure )
{
var failureObject : Object = methodObject.failure;
var failure : XML = createFailure( failureObject );
testCase = testCase.appendChild( failure );
}
// Create the error element.
if ( methodObject.error )
{
var errorObject : Object = methodObject.error;
var error : XML = createError( errorObject );
testCase = testCase.appendChild( error );
}
testSuite = testSuite.appendChild( testCase );
}
return testSuite;
}
/**
* Create the test suite XML.
* @return the XML.
*/
private function createTestSuite( obj : Object ) : XML
{
var name : String = obj.name;
var errors : uint = obj.errors;
var failures : uint = obj.failures;
var tests : uint = obj.tests;
var time : int = getTimer()/1000 - obj.time;
var methods : Object = obj.methods;
var flashVersion : String = Capabilities.version;
var flashLanguage : String = Capabilities.language;
var flashPlayerType : String = Capabilities.playerType;
var flashConfig : String;
setDebugFlag();
if (debugMode)
{
flashConfig = "release debugger";
}
else
{
flashConfig = "release";
}
var xml : XML =
;
// Add any other meta-data
for (var attrib:Object in suiteMetaData)
{
xml.@[attrib] = suiteMetaData[attrib];
}
return xml;
}
/**
* Create the test case XML.
* @return the XML.
*/
private function createTestCase( obj : Object ) : XML
{
var classname : String = obj.classname;
var name : String = obj.name;
var time : Number = obj.time;
var setuptime : Number = obj.setuptime;
var setupmeminitial : Number = obj.setupmeminitial;
var setupmemfinal : Number = obj.setupmemfinal;
var middletime : Number = obj.middletime;
var middlememinitial : Number = obj.middlememinitial;
var middlememfinal : Number = obj.middlememfinal;
var teardowntime : Number = obj.teardowntime;
var teardownmeminitial : Number = obj.teardownmeminitial;
var teardownmemfinal : Number = obj.teardownmemfinal;
var xml : XML =
;
// Add any other meta-data
for (var attrib:Object in obj.metaData)
{
xml.@[attrib] = obj.metaData[attrib];
}
return xml;
}
/**
* Create the failure XML.
* @return the XML.
*/
private function createFailure( obj : Object ) : XML
{
var type : String = obj.type;
var message : String = obj.message;
var xml : XML =
{ message }
;
return xml;
}
/**
* Create the test error XML.
* @return the XML.
*/
private function createError( obj : Object ) : XML
{
var type : String = obj.type;
var message : String = obj.message;
var xml : XML =
{ message }
;
return xml;
}
/**
* Exit the test runner and close the player.
*/
private function exit() : void
{
// Close the socket.
socket.close();
}
private function formatQualifiedClassName( className : String ) : String
{
var pattern : RegExp = /::/;
return className.replace( pattern, "." );
}
private function setDebugFlag(): void
{
var e:Error = new Error();
var s:String = e.getStackTrace();
try
{
var i:int = s.indexOf("setDebugFlag");
if (s.charAt(i + 14) == '[')
debugMode = true;
}
catch (err:Error) // error is thrown in release player
{
debugMode = false;
}
}
private var debugMode : Boolean = false;
]]>