mas01mj@732: package asunit.textui { mas01mj@732: import asunit.errors.AssertionFailedError; mas01mj@732: import asunit.framework.Test; mas01mj@732: import asunit.framework.TestFailure; mas01mj@732: import asunit.framework.TestListener; mas01mj@732: import asunit.framework.TestResult; mas01mj@732: import asunit.runner.BaseTestRunner; mas01mj@732: import asunit.runner.Version; mas01mj@732: mas01mj@732: import flash.display.Sprite; mas01mj@732: import flash.events.*; mas01mj@732: import flash.system.Capabilities; mas01mj@732: import flash.text.TextField; mas01mj@732: import flash.text.TextFormat; mas01mj@732: import flash.utils.getTimer; mas01mj@732: import flash.utils.setInterval; mas01mj@732: import flash.utils.setTimeout; mas01mj@732: mas01mj@732: /** mas01mj@732: * This is the base class for collecting test output and formatting for different mas01mj@732: * displays. mas01mj@732: * mas01mj@732: * This class simply presents test results as if they were being shown on a terminal. mas01mj@732: * mas01mj@732: * The XMLResultPrinter provides a good example of how this class can mas01mj@732: * be subclassed and used to emit different/additional output. mas01mj@732: * mas01mj@732: * @see XMLResultPrinter mas01mj@732: **/ mas01mj@732: public class ResultPrinter extends Sprite implements TestListener { mas01mj@732: private var fColumn:int = 0; mas01mj@732: private var textArea:TextField; mas01mj@732: private var gutter:uint = 0; mas01mj@732: private var backgroundColor:uint = 0x333333; mas01mj@732: private var bar:SuccessBar; mas01mj@732: private var barHeight:Number = 3; mas01mj@732: private var showTrace:Boolean; mas01mj@732: protected var startTime:Number; mas01mj@732: protected var testTimes:Array; mas01mj@732: mas01mj@732: public function ResultPrinter(showTrace:Boolean = false) { mas01mj@732: this.showTrace = showTrace; mas01mj@732: testTimes = new Array(); mas01mj@732: configureAssets(); mas01mj@732: println(); mas01mj@732: mas01mj@732: // Create a loop so that the FDBTask mas01mj@732: // can halt execution properly: mas01mj@732: setInterval(function():void { mas01mj@732: }, 500); mas01mj@732: } mas01mj@732: mas01mj@732: private function configureAssets():void { mas01mj@732: textArea = new TextField(); mas01mj@732: textArea.background = true; mas01mj@732: textArea.backgroundColor = backgroundColor; mas01mj@732: textArea.border = true; mas01mj@732: textArea.wordWrap = true; mas01mj@732: var format:TextFormat = new TextFormat(); mas01mj@732: format.font = "Verdana"; mas01mj@732: format.size = 10; mas01mj@732: format.color = 0xFFFFFF; mas01mj@732: textArea.defaultTextFormat = format; mas01mj@732: addChild(textArea); mas01mj@732: println("AsUnit " + Version.id() + " by Luke Bayes and Ali Mills"); mas01mj@732: println(""); mas01mj@732: println("Flash Player version: " + Capabilities.version); mas01mj@732: mas01mj@732: bar = new SuccessBar(); mas01mj@732: addChild(bar); mas01mj@732: } mas01mj@732: mas01mj@732: public function setShowTrace(showTrace:Boolean):void { mas01mj@732: this.showTrace = showTrace; mas01mj@732: } mas01mj@732: mas01mj@732: public override function set width(w:Number):void { mas01mj@732: textArea.x = gutter; mas01mj@732: textArea.width = w - gutter*2; mas01mj@732: bar.x = gutter; mas01mj@732: bar.width = textArea.width; mas01mj@732: } mas01mj@732: mas01mj@732: public override function set height(h:Number):void { mas01mj@732: textArea.height = h - ((gutter*2) + barHeight); mas01mj@732: textArea.y = gutter; mas01mj@732: bar.y = h - (gutter + barHeight); mas01mj@732: bar.height = barHeight; mas01mj@732: } mas01mj@732: mas01mj@732: public function println(...args:Array):void { mas01mj@732: textArea.appendText(args.toString() + "\n"); mas01mj@732: } mas01mj@732: mas01mj@732: public function print(...args:Array):void { mas01mj@732: textArea.appendText(args.toString()); mas01mj@732: } mas01mj@732: mas01mj@732: /** mas01mj@732: * API for use by textui.TestRunner mas01mj@732: */ mas01mj@732: mas01mj@732: public function run(test:Test):void { mas01mj@732: } mas01mj@732: mas01mj@732: public function printResult(result:TestResult, runTime:Number):void { mas01mj@732: printHeader(runTime); mas01mj@732: printErrors(result); mas01mj@732: printFailures(result); mas01mj@732: printFooter(result); mas01mj@732: mas01mj@732: bar.setSuccess(result.wasSuccessful()); mas01mj@732: if(showTrace) { mas01mj@732: trace(textArea.text.split("\r").join("\n")); mas01mj@732: } mas01mj@732: } mas01mj@732: mas01mj@732: /* Internal methods mas01mj@732: */ mas01mj@732: protected function printHeader(runTime:Number):void { mas01mj@732: println(); mas01mj@732: println(); mas01mj@732: println("Time: " + elapsedTimeAsString(runTime)); mas01mj@732: } mas01mj@732: mas01mj@732: protected function printErrors(result:TestResult):void { mas01mj@732: printDefects(result.errors(), result.errorCount(), "error"); mas01mj@732: } mas01mj@732: mas01mj@732: protected function printFailures(result:TestResult):void { mas01mj@732: printDefects(result.failures(), result.failureCount(), "failure"); mas01mj@732: } mas01mj@732: mas01mj@732: protected function printDefects(booBoos:Object, count:int, type:String):void { mas01mj@732: if (count == 0) { mas01mj@732: return; mas01mj@732: } mas01mj@732: if (count == 1) { mas01mj@732: println("There was " + count + " " + type + ":"); mas01mj@732: } mas01mj@732: else { mas01mj@732: println("There were " + count + " " + type + "s:"); mas01mj@732: } mas01mj@732: var i:uint; mas01mj@732: for each (var item:TestFailure in booBoos) { mas01mj@732: printDefect(TestFailure(item), i); mas01mj@732: i++; mas01mj@732: } mas01mj@732: } mas01mj@732: mas01mj@732: public function printDefect(booBoo:TestFailure, count:int ):void { // only public for testing purposes mas01mj@732: printDefectHeader(booBoo, count); mas01mj@732: printDefectTrace(booBoo); mas01mj@732: } mas01mj@732: mas01mj@732: protected function printDefectHeader(booBoo:TestFailure, count:int):void { mas01mj@732: // I feel like making this a println, then adding a line giving the throwable a chance to print something mas01mj@732: // before we get to the stack trace. mas01mj@732: var startIndex:uint = textArea.text.length; mas01mj@732: println(count + ") " + booBoo.failedFeature()); mas01mj@732: var endIndex:uint = textArea.text.length; mas01mj@732: mas01mj@732: var format:TextFormat = textArea.getTextFormat(); mas01mj@732: format.bold = true; mas01mj@732: mas01mj@732: // GROSS HACK because of bug in flash player - TextField isn't accepting formats... mas01mj@732: setTimeout(onFormatTimeout, 1, format, startIndex, endIndex); mas01mj@732: } mas01mj@732: mas01mj@732: public function onFormatTimeout(format:TextFormat, startIndex:uint, endIndex:uint):void { mas01mj@732: textArea.setTextFormat(format, startIndex, endIndex); mas01mj@732: } mas01mj@732: mas01mj@732: protected function printDefectTrace(booBoo:TestFailure):void { mas01mj@732: println(BaseTestRunner.getFilteredTrace(booBoo.thrownException().getStackTrace())); mas01mj@732: } mas01mj@732: mas01mj@732: protected function printFooter(result:TestResult):void { mas01mj@732: println(); mas01mj@732: if (result.wasSuccessful()) { mas01mj@732: print("OK"); mas01mj@732: println (" (" + result.runCount() + " test" + (result.runCount() == 1 ? "": "s") + ")"); mas01mj@732: } else { mas01mj@732: println("FAILURES!!!"); mas01mj@732: println("Tests run: " + result.runCount()+ mas01mj@732: ", Failures: "+result.failureCount()+ mas01mj@732: ", Errors: "+result.errorCount()); mas01mj@732: } mas01mj@732: mas01mj@732: printTimeSummary(); mas01mj@732: println(); mas01mj@732: } mas01mj@732: mas01mj@732: protected function printTimeSummary():void { mas01mj@732: testTimes.sortOn('duration', Array.NUMERIC | Array.DESCENDING); mas01mj@732: println(); mas01mj@732: println(); mas01mj@732: println('Time Summary:'); mas01mj@732: println(); mas01mj@732: var len:Number = testTimes.length; mas01mj@732: for(var i:Number = 0; i < len; i++) { mas01mj@732: println(testTimes[i].toString()); mas01mj@732: } mas01mj@732: } mas01mj@732: mas01mj@732: /** mas01mj@732: * Returns the formatted string of the elapsed time. mas01mj@732: * Duplicated from BaseTestRunner. Fix it. mas01mj@732: */ mas01mj@732: protected function elapsedTimeAsString(runTime:Number):String { mas01mj@732: return Number(runTime/1000).toString(); mas01mj@732: } mas01mj@732: mas01mj@732: /** mas01mj@732: * @see asunit.framework.TestListener#addError(Test, Throwable) mas01mj@732: */ mas01mj@732: public function addError(test:Test, t:Error):void { mas01mj@732: print("E"); mas01mj@732: } mas01mj@732: mas01mj@732: /** mas01mj@732: * @see asunit.framework.TestListener#addFailure(Test, AssertionFailedError) mas01mj@732: */ mas01mj@732: public function addFailure(test:Test, t:AssertionFailedError):void { mas01mj@732: print("F"); mas01mj@732: } mas01mj@732: mas01mj@732: /** mas01mj@732: * @see asunit.framework.TestListener#endTestMethod(test, testMethod); mas01mj@732: */ mas01mj@732: public function startTestMethod(test:Test, methodName:String):void { mas01mj@732: } mas01mj@732: mas01mj@732: /** mas01mj@732: * @see asunit.framework.TestListener#endTestMethod(test, testMethod); mas01mj@732: */ mas01mj@732: public function endTestMethod(test:Test, methodName:String):void { mas01mj@732: } mas01mj@732: mas01mj@732: /** mas01mj@732: * @see asunit.framework.TestListener#startTest(Test) mas01mj@732: */ mas01mj@732: public function startTest(test:Test):void { mas01mj@732: startTime = getTimer(); mas01mj@732: var count:uint = test.countTestCases(); mas01mj@732: for(var i:uint; i < count; i++) { mas01mj@732: print("."); mas01mj@732: if (fColumn++ >= 80) { mas01mj@732: println(); mas01mj@732: fColumn = 0; mas01mj@732: } mas01mj@732: } mas01mj@732: } mas01mj@732: mas01mj@732: /** mas01mj@732: * @see asunit.framework.TestListener#endTest(Test) mas01mj@732: */ mas01mj@732: public function endTest(test:Test):void { mas01mj@732: var duration:Number = getTimer() - startTime; mas01mj@732: testTimes.push(TestTime.create(test, duration)); mas01mj@732: } mas01mj@732: } mas01mj@732: } mas01mj@732: mas01mj@732: import flash.display.Sprite; mas01mj@732: mas01mj@732: class SuccessBar extends Sprite { mas01mj@732: private var myWidth:uint; mas01mj@732: private var myHeight:uint; mas01mj@732: private var bgColor:uint; mas01mj@732: private var passingColor:uint = 0x00FF00; mas01mj@732: private var failingColor:uint = 0xFD0000; mas01mj@732: mas01mj@732: public function SuccessBar() { mas01mj@732: } mas01mj@732: mas01mj@732: public function setSuccess(success:Boolean):void { mas01mj@732: bgColor = (success) ? passingColor : failingColor; mas01mj@732: draw(); mas01mj@732: } mas01mj@732: mas01mj@732: public override function set width(num:Number):void { mas01mj@732: myWidth = num; mas01mj@732: draw(); mas01mj@732: } mas01mj@732: mas01mj@732: public override function set height(num:Number):void { mas01mj@732: myHeight = num; mas01mj@732: draw(); mas01mj@732: } mas01mj@732: mas01mj@732: private function draw():void { mas01mj@732: graphics.clear(); mas01mj@732: graphics.beginFill(bgColor); mas01mj@732: graphics.drawRect(0, 0, myWidth, myHeight); mas01mj@732: graphics.endFill(); mas01mj@732: } mas01mj@732: }