http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/flex/CompareBitmap.as ---------------------------------------------------------------------- diff --git a/mustella/src/main/flex/CompareBitmap.as b/mustella/src/main/flex/CompareBitmap.as new file mode 100644 index 0000000..52c4df8 --- /dev/null +++ b/mustella/src/main/flex/CompareBitmap.as @@ -0,0 +1,1603 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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 { + +import flash.display.BitmapData; +import flash.display.DisplayObject; +import flash.display.DisplayObjectContainer; +import flash.display.IBitmapDrawable; +import flash.display.Loader; +import flash.events.Event; +import flash.events.IOErrorEvent; +import flash.events.SecurityErrorEvent; +import flash.events.StatusEvent; +import flash.geom.ColorTransform; +import flash.geom.Matrix; +import flash.geom.Point; +import flash.geom.Rectangle; +import flash.net.LocalConnection; +import flash.net.URLLoader; +import flash.net.URLRequest; +import flash.text.TextField; +import flash.text.TextFormat; +import flash.text.engine.ContentElement; +import flash.text.engine.TextBlock; +import flash.text.engine.TextLine; +import flash.utils.ByteArray; +import flash.utils.getQualifiedClassName; + +import mx.core.IChildList; +import mx.core.IRawChildrenContainer; +import mx.core.mx_internal; + +use namespace mx_internal; + +/** +* Vector of conditionalValue objects. +**/ +[DefaultProperty("conditionalValues")] + +/** + * The test step that compares a bitmap against a reference bitmap + * MXML attributes: + * target + * url + * timeout (optional); + * maxColorVariance + * numColorVariances + * waitTarget Do Not Use + * waitEvent Do Not Use + * stageText - placeholder, does nothing + * + * + * Do not set waitEvent or waitTarget on this step. They are set internally + * to manage the loading of the reference bitmap. The step prior to this + * step must wait for the system to synch up. + * + * CompareBitmap will parse the url attribute for $testID, replacing with the current testID + */ +public class CompareBitmap extends Assert +{ + public static var useRemoteDiffer:Boolean = false; + + private static var identityMatrix:String = new Matrix().toString(); + private static var identityColorTransform:String = new ColorTransform().toString(); + + public static var DEFAULT_MAX_COLOR_VARIANCE:int = 0; + public static var DEFAULT_NUM_COLOR_VARIANCES:int = 0; + public static var DEFAULT_MAX_MATRIX_VARIANCE:Number = 0.1; + + // This is the default property. + public var conditionalValues:Vector.<ConditionalValue> = null; + + /** + * The url of the file to read. If UnitTester.createBitmapReferences = true, + * the url to store the bitmap + */ + public var url:String; + + + /** + * placeHolder for stageText, does nothing + */ + public var stageText:String; + + private var _maxColorVariance:int = 0; + /** + * The maximum color variation allowed in a bitmap compare. + * Some machines render slightly differently and thus we have + * to allow the the compare to not be exact. + */ + public function get maxColorVariance():int + { + if (_maxColorVariance) + return _maxColorVariance; + + return DEFAULT_MAX_COLOR_VARIANCE; + } + public function set maxColorVariance(value:int):void + { + _maxColorVariance = value; + } + + private var _ignoreMaxColorVariance:Boolean = false; + + /** + * Sometimes you have numColorVariance defined and you don't really care by how much the pixel really differ. + * as long as the number of mismatching pixels is <= numColorVariance + * Setting this to true will skip the maxColorVariance check (and take the guess work out of picture). default is false + */ + public function get ignoreMaxColorVariance():Boolean + { + return _ignoreMaxColorVariance; + } + + public function set ignoreMaxColorVariance(value:Boolean):void + { + _ignoreMaxColorVariance = value; + } + + + private var _numColorVariances:int = 0; + /** + * The number of color variation allowed in a bitmap compare. + * Some machines render slightly differently and thus we have + * to allow the the compare to not be exact. + */ + public function get numColorVariances():int + { + if (_numColorVariances) + return _numColorVariances; + + return DEFAULT_NUM_COLOR_VARIANCES; + } + public function set numColorVariances(value:int):void + { + _numColorVariances = value; + } + + private var _maxMatrixVariance:Number = 0.1; + /** + * The maximum color variation allowed in a bitmap compare. + * Some machines render slightly differently and thus we have + * to allow the the compare to not be exact. + */ + public function get maxMatrixVariance():Number + { + if (_maxMatrixVariance) + return _maxMatrixVariance; + + return DEFAULT_MAX_MATRIX_VARIANCE; + } + public function set maxMatrixVariance(value:Number):void + { + _maxMatrixVariance = value; + } + + /** + * Suffix to add to the file being written out (the case of a compare failure) + */ + public static var fileSuffix:String = ""; + + private var reader:Loader; + private var xmlreader:URLLoader; + private var writer:URLLoader; + + private static var connection:LocalConnection; + private static var commandconnection:LocalConnection; + + private var baselineMissing:Boolean = false; + private var baselineMissingMessage:String = "Baseline image could not be read. Created image file as a .bad.png."; + private var baselineMissingMessageFail:String = "Baseline image could not be read, and we failed to write the .bad.png"; + + private function statusHandler(event:Event):void + { + } + + /** + * Constructor + */ + public function CompareBitmap() + { + if (useRemoteDiffer) + { + if (!connection) + { + connection = new LocalConnection(); + connection.allowDomain("*"); + connection.addEventListener(StatusEvent.STATUS, statusHandler); + + commandconnection = new LocalConnection(); + commandconnection.allowDomain("*"); + + try + { + commandconnection.connect("_ImageDifferCommands"); + } + catch (e:Error) + { + trace("connection failed"); + } + } + } + } + + override public function execute(root:DisplayObject, context:UnitTester, testCase:TestCase, testResult:TestResult):Boolean + { + var cv:ConditionalValue = null; + var configID:String = null; + + // Use MultiResult to determine the proper URL. + if(conditionalValues){ + cv = new MultiResult().chooseCV(conditionalValues); + if(cv){ + // This way, we use CompareBitmap's url (directory) if the CV's is not set. + if( cv.url != null ){ + url = cv.url; + } + } + }else{ + // We do not have ConditionalValues. If the current config is unknown, it is probably + // a desktop AIR run, and we should just let things take the course they always have. + // If a config is known, then we want to use the new config ID suffix mechanism later. + configID = TargetConfigurations.getTargetConfigID( UnitTester.cv ); + if( configID ){ + trace( "CompareBitmap: No ConditionalValues found. configID is " + configID.toString() ); + }else{ + trace( "CompareBitmap: No ConditionalValues found. configID is " + configID ); + } + } + + if( url == null ){ + if( cv == null ){ + throw new Error("Found no url on the CompareBitmap for test case " + testCase.testID); + }else{ + throw new Error("Found no url on the ConditionalValue for test case " + testCase.testID + ", ConditionalValue: " + cv.toString()); + } + } + + // See if url ends with .png. If not, create a file name. + if( url.lastIndexOf( ".png" ) != url.length - 4 ){ + + // Add a path separator if necessary. + if( url.lastIndexOf( "/" ) != url.length - 1 ){ + url += "/"; + } + + // Decide on a file name. + if( conditionalValues ){ + // If we ended up with a matching CV, ask it to create a file name. + // Otherwise, go with the test ID. + // Keep this path alive until (if ever) ConditionalValues in CompareBitmaps have all been removed. + if(cv){ + trace( "CompareBitmap: Asking the ConditionalValue to create the file name." ); + url += cv.createFilename( testCase.testID ); + } else { + trace( "CompareBitmap: Creating the file name from the testID." ); + url += testCase.testID + ".png"; + } + }else if( configID ){ + // We have no ConditionalValues and we're running a known config, + // so use the config id in the suffix. + trace( "CompareBitmap: Creating the file name from the configID." ); + url += testCase.testID + "@" + configID + ".png"; + }else{ + trace( "There is no file name, there are no Conditional Values, and there is no configID. There's not much we can do now, is there?" ); + } + } + + if (url != null && url.indexOf ("$testID") != -1) { + trace ("SAW THE REF, I'll plug it"); + url = url.replace ("$testID", UnitTester.currentTestID); + trace ("result 2: " + url); + } + + if (url == null) + trace ("URL was null at execute time"); + + if (commandconnection) + commandconnection.client = this; + + var actualTarget:DisplayObject = DisplayObject(context.stringToObject(target)); + if (!actualTarget) + { + testResult.doFail("Target " + target + " not found"); + return true; + } + + if (stageText) + updateStageTexts(actualTarget); + + this.root = root; + this.context = context; + this.testResult = testResult; + + if (UnitTester.createBitmapReferences) + { + if (UnitTester.checkEmbeddedFonts) + { + if (!checkEmbeddedFonts(actualTarget)) + { + testResult.doFail ("Target " + actualTarget + " is using non-embedded or advanced anti-aliased fonts"); + return true; + } + } + + writeBaselines(actualTarget); + return false; + } + else + { + readPNG(); + return false; + } + + } + + // there are a few mobile tests that use StageText in the bitmaps + // which are TextFields in the emulator. This makes them use + // embedded fonts to get consistency across platforms. + private function updateStageTexts(target:DisplayObject):void + { + var doc:DisplayObjectContainer = target as DisplayObjectContainer; + var tf:Object; + tf = findTextWidget(doc); + if (tf) + { + var n:int = target.stage.numChildren; + for (var i:int = 0; i < n; i++) + { + var stf:TextField = target.stage.getChildAt(i) as TextField; + if (stf) + { + var stfm:TextFormat = new TextFormat(tf.getStyle("fontFamily"), + tf.getStyle("fontSize"), + tf.getStyle("color"), + tf.getStyle("fontWeight") == "bold", + tf.getStyle("fontStyle") == "italic" + ); + stf.defaultTextFormat = stfm; + stf.embedFonts = true; + } + } + } + } + + private function findTextWidget(doc:DisplayObjectContainer):Object + { + if (!doc) return null; + var n:int = doc.numChildren; + for (var i:int = 0; i < n; i++) + { + var child:DisplayObject = doc.getChildAt(i); + var className:String = getQualifiedClassName(child); + if (className.indexOf("StyleableStageText") > -1) + return child; + else if (child is DisplayObjectContainer) + { + var tf:Object = findTextWidget(child as DisplayObjectContainer); + if (tf) return tf; + } + } + return null; + } + + private function getTargetSize(target:DisplayObject):Point + { + var width:Number; + var height:Number; + + try + { + width = target["getUnscaledWidth"]() * Math.abs(target.scaleX) * target.root.scaleX; + height = target["getUnscaledHeight"]() * Math.abs(target.scaleY) * target.root.scaleY; + } + catch(e:ReferenceError) + { + width = target.width * target.root.scaleX; + height = target.height * target.root.scaleY; + } + trace("getTargetSize: height: ", target.height); + trace("getTargetSize: root.height: ", target.root.height); + trace("getTargetSize: stageHeight: ", target.stage.stageHeight); + try { + trace("getTargetSize: loaderInfo.height: ", target.loaderInfo.height); + } catch (e:Error) {}; + + return new Point(width, height); + } + + // Given a displayObject, sets up the screenBits. + private function getScreenBits(target:DisplayObject):void{ + try + { + var targetSize:Point = getTargetSize(target); + var stagePt:Point = target.localToGlobal(new Point(0, 0)); + var altPt:Point = target.localToGlobal(targetSize); + stagePt.x = Math.min(stagePt.x, altPt.x); + stagePt.y = Math.min(stagePt.y, altPt.y); + screenBits = new BitmapData(targetSize.x, targetSize.y); + screenBits.draw(target.stage, new Matrix(1, 0, 0, 1, -stagePt.x, -stagePt.y)); + } + catch (se:SecurityError) + { + UnitTester.hideSandboxes(); + try + { + screenBits.draw(target.stage, new Matrix(1, 0, 0, 1, -stagePt.x, -stagePt.y)); + } + catch (se2:Error) + { + try + { + // if we got a security error and ended up here, assume we're in the + // genericLoader loads us scenario + screenBits.draw(target.root, new Matrix(1, 0, 0, 1, -stagePt.x, -stagePt.y)); + } + catch (se3:Error) + { + } + } + UnitTester.showSandboxes(); + var sb:Array = UnitTester.getSandboxBitmaps(); + var n:int = sb.length; + for (var i:int = 0; i < n; i++) + { + mergeSandboxBitmap(target, stagePt, screenBits, sb[i]); + } + } + catch (e:Error) + { + testResult.doFail (e.getStackTrace()); + } + } + + private var MAX_LC:int = 12000; + private var screenBits:BitmapData; + private var baselineBits:BitmapData; + + private var compareVal:Object; + + public function comparePNG(target:DisplayObject):Boolean + { + if (UnitTester.checkEmbeddedFonts) + { + if (!checkEmbeddedFonts(target)) + { + testResult.doFail ("Target " + target + " is using non-embedded or advanced anti-aliased fonts"); + return true; + } + } + + try { + if (!reader.content) + { + testResult.doFail ("baseline image not available"); + return true; + } + } catch( e:Error ) { + testResult.doFail ("CompareBitmap BIG FAIL! Content reader is null!"); + return true; + } + + getScreenBits(target); + + try + { + baselineBits = new BitmapData(reader.content.width, reader.content.height); + baselineBits.draw(reader.content, new Matrix()); + + compareVal = baselineBits.compare (screenBits); + + if (compareVal is BitmapData && numColorVariances) + compareVal = compareWithVariances(compareVal as BitmapData) + + if (compareVal != 0) + { + trace ("compare returned" + compareVal); + + var req:URLRequest = new URLRequest(); + if (UnitTester.isApollo) + { + req.url = encodeURI2(CompareBitmap.adjustPath (url)); + } + else + { + req.url = url; + var base:String = normalizeURL(context.application.url); + base = base.substring(0, base.lastIndexOf("/")); + while (req.url.indexOf("../") == 0) + { + base = base.substring(0, base.lastIndexOf("/")); + req.url = req.url.substring(3); + } + + req.url = encodeURI2(base + "/" + req.url); + } + + req.url += ".xml"; + xmlreader = new URLLoader(); + xmlreader.addEventListener(Event.COMPLETE, readXMLCompleteHandler); + xmlreader.addEventListener(SecurityErrorEvent.SECURITY_ERROR, readErrorHandler); + xmlreader.addEventListener(IOErrorEvent.IO_ERROR, readXMLIOErrorHandler); + xmlreader.load (req); + return false; + } + } + catch (e:Error) + { + testResult.doFail (e.getStackTrace()); + } + return true; + } + + private function readXMLCompleteHandler(event:Event):void + { + var actualTarget:DisplayObject = DisplayObject(context.stringToObject(target)); + var s:String = getDisplayListXML(actualTarget).toXMLString(); + var t:String = xmlreader.data; + s = s.replace(/\r/g, ""); + t = t.replace(/\r/g, ""); + if (s !== t && xmldiffer(s, t)) + { + testResult.doFail ("compare returned" + compareVal, absolutePathResult(url) + ".bad.png"); + + if (useRemoteDiffer) + { + sendImagesToDiffer(); + } + else if (fileSuffix != "") + { + writeBaselines (actualTarget); + } + } + else + stepComplete(); + } + + private function readXMLIOErrorHandler(event:Event):void + { + if (useRemoteDiffer) + { + sendImagesToDiffer(); + } + else if (fileSuffix != "") + { + testResult.doFail ("compare returned" + compareVal, absolutePathResult(url) + ".bad.png"); + var actualTarget:DisplayObject = DisplayObject(context.stringToObject(target)); + writePNG (actualTarget); + } + } + + private function mergeSandboxBitmap(target:DisplayObject, pt:Point, bm:BitmapData, obj:Object):void + { + var targetSize:Point = getTargetSize(target); + var sbm:BitmapData = new BitmapData(obj.width, obj.height); + var srcRect:Rectangle = new Rectangle(0, 0, obj.width, obj.height); + sbm.setPixels(srcRect, obj.bits); + var targetRect:Rectangle = new Rectangle(pt.x, pt.y, targetSize.x, targetSize.y); + var sbRect:Rectangle = new Rectangle(obj.x, obj.y, obj.width, obj.height); + var area:Rectangle = targetRect.intersection(sbRect); + if (area) + bm.copyPixels(sbm, srcRect, target.globalToLocal(area.topLeft)); + } + + private function sendImagesToDiffer():void + { + UnitTester.callback = stringifyScreen; + } + + private var ba:ByteArray; + private function stringifyScreen():void + { + ba = screenBits.getPixels(screenBits.rect); + ba.position = 0; + connection.send("_ImageDiffer", "startScreenData", screenBits.width, screenBits.height, ba.length, UnitTester.currentTestID, UnitTester.currentScript); + UnitTester.callback = sendScreen; + } + + private function sendScreen():void + { + if (ba.position + MAX_LC < ba.length) + { + connection.send("_ImageDiffer", "addScreenData", stringify(ba)); + UnitTester.callback = sendScreen; + } + else + { + connection.send("_ImageDiffer", "addScreenData", stringify(ba)); + UnitTester.callback = stringifyBase; + } + } + + private function stringifyBase():void + { + ba = baselineBits.getPixels(baselineBits.rect); + ba.position = 0; + connection.send("_ImageDiffer", "startBaseData", baselineBits.width, baselineBits.height, ba.length); + UnitTester.callback = sendBase; + } + + private function sendBase():void + { + if (ba.position + MAX_LC < ba.length) + { + connection.send("_ImageDiffer", "addBaseData", stringify(ba)); + UnitTester.callback = sendBase; + } + else + { + connection.send("_ImageDiffer", "addBaseData", stringify(ba)); + connection.send("_ImageDiffer", "compareBitmaps"); + } + } + + private function stringify(ba:ByteArray):String + { + var n:int = Math.min(ba.length - ba.position, MAX_LC); + var arr:Array = []; + for (var i:int = 0; i < n; i++) + { + var b:int = ba.readUnsignedByte(); + arr.push(b.toString(16)) + } + return arr.toString(); + } + + private function readCompleteHandler(event:Event):void + { + var actualTarget:DisplayObject = DisplayObject(context.stringToObject(target)); + if (comparePNG(actualTarget)) + preStepComplete(); + } + + private function readErrorHandler(event:Event):void + { + var actualTarget:DisplayObject = DisplayObject(context.stringToObject(target)); + getScreenBits(actualTarget); + + baselineMissing = true; + writePNG(actualTarget); + // writePNG() creates error handlers which will handle the fail and stepComplete(). + } + + public function readPNG():void + { + var req:URLRequest = new URLRequest(); + if (UnitTester.isApollo) + { + req.url = encodeURI2(CompareBitmap.adjustPath (url)); + } + else + { + req.url = url; + var base:String = normalizeURL(context.application.url); + base = base.substring(0, base.lastIndexOf("/")); + while (req.url.indexOf("../") == 0) + { + base = base.substring(0, base.lastIndexOf("/")); + req.url = req.url.substring(3); + } + + req.url = encodeURI2(base + "/" + req.url); + } + // req.url = encodeURI2(url); + // } + + reader = new Loader(); + + trace ("readPNG:requesting url: " + req.url); + reader.contentLoaderInfo.addEventListener(Event.COMPLETE, readCompleteHandler); + reader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, readErrorHandler); + reader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, readErrorHandler); + + reader.load (req); + } + + + public static var adjustPath:Function = function(url:String):String { return url; }; + + + + + public function getPngByteArray(target:DisplayObject, bitmapData:BitmapData):ByteArray + { + // add png headers + if (UnitTester.createBitmapReferences) + { + var targetSize:Point = getTargetSize(target); + var stagePt:Point = target.localToGlobal(new Point(0, 0)); + var altPt:Point = target.localToGlobal(targetSize); + stagePt.x = Math.min(stagePt.x, altPt.x); + stagePt.y = Math.min(stagePt.y, altPt.y); + bitmapData = new BitmapData(targetSize.x, targetSize.y); + bitmapData.draw(target.stage, new Matrix(1, 0, 0, 1, -stagePt.x, -stagePt.y)); + + } + var png:MustellaPNGEncoder = new MustellaPNGEncoder(); + var ba:ByteArray = png.encode (bitmapData); + + return ba; + } + + public function writeBaselines(target:DisplayObject, writeDisplayList:Boolean = true):void + { + var req:URLRequest = new URLRequest(); + writer = new URLLoader(); + req.method = "POST"; + + /** + * either we got called here to write new baselines + * or to save a .bad.png for investigation + * in addition, with failures, we upload baseline and failure to a server + */ + if (UnitTester.createBitmapReferences) + { + fileSuffix = ""; + } + + + if (writeDisplayList) + { + var s:String = getDisplayListXML(target).toXMLString(); + // request data goes on the URL Request + req.data = s; + + req.contentType = "text/xml"; + if (UnitTester.isApollo) + { + req.url = encodeURI2(UnitTester.bitmapServerPrefix + adjustWriteURI(adjustPath(url))) + fileSuffix + ".xml"; + } else + { + req.url = encodeURI2(UnitTester.bitmapServerPrefix + absolutePath(url)) + fileSuffix + ".xml"; + } + trace ("writing url: " + req.url); + writer.addEventListener(Event.COMPLETE, writeXMLCompleteHandler); + writer.addEventListener(SecurityErrorEvent.SECURITY_ERROR, writeErrorHandler); + writer.addEventListener(IOErrorEvent.IO_ERROR, writeErrorHandler); + + writer.load (req); + } + } + + private function writeXMLCompleteHandler(event:Event):void + { + var actualTarget:DisplayObject = DisplayObject(context.stringToObject(target)); + writePNG(actualTarget); + } + + private function writePNG(target:DisplayObject):void + { + var req:URLRequest = new URLRequest(); + writer = new URLLoader(); + req.method = "POST"; + + var ba:ByteArray = getPngByteArray(target, screenBits); + trace ("image size: " + ba.length); + // request data goes on the URL Request + req.data = ba; + // can't send this, don't need to anyway var rhArray:Array = new Array(new URLRequestHeader("Content-Length", new String(ba.length) )); + + req.contentType = "image/png"; + + if (UnitTester.isApollo) + { + req.url = encodeURI2(UnitTester.bitmapServerPrefix + adjustWriteURI(adjustPath(url))) + fileSuffix; + } else + { + req.url = encodeURI2(UnitTester.bitmapServerPrefix + absolutePath(url)) + fileSuffix; + } + trace ("writing url: " + req.url); + writer.addEventListener(Event.COMPLETE, writeCompleteHandler); + writer.addEventListener(SecurityErrorEvent.SECURITY_ERROR, writeErrorHandler); + writer.addEventListener(IOErrorEvent.IO_ERROR, writeErrorHandler); + + writer.load (req); + + + /// If this is about creating bitmaps, skip the upload, we're done + if (UnitTester.createBitmapReferences || UnitTester.run_id == "-1" || baselineMissing) + return; + + //// Upload + var writer2:URLLoader = new URLLoader(); + var reqScreen:URLRequest = new URLRequest(); + + reqScreen.method = "POST"; + + /// we already have the screen data in hand: + reqScreen.data = ba; + + /// fill in the blanks + reqScreen.contentType = "image/png"; + reqScreen.url = UnitTester.urlAssemble ("screen", + context.testDir, context.scriptName, this.testResult.testID, UnitTester.run_id); + + trace ("upload: " + reqScreen.url); + writer2.addEventListener(Event.COMPLETE, uploadCompleteHandler); + writer2.addEventListener(SecurityErrorEvent.SECURITY_ERROR, uploadErrorHandler); + writer2.addEventListener(IOErrorEvent.IO_ERROR, uploadErrorHandler); + writer2.load (reqScreen); + + + /// get the baseline stuff: + var writer3:URLLoader = new URLLoader(); + var reqBaseline:URLRequest = new URLRequest(); + /// needed? + var baBase:ByteArray = getPngByteArray(target, baselineBits); + + reqBaseline.data = baBase; + reqBaseline.contentType = "image/png"; + reqBaseline.method = "POST"; + + reqBaseline.url = UnitTester.urlAssemble ("baseline", + context.testDir, context.scriptName, this.testResult.testID, UnitTester.run_id); + + trace ("upload: " + reqBaseline.url); + writer3.addEventListener(Event.COMPLETE, upload2CompleteHandler); + writer3.addEventListener(SecurityErrorEvent.SECURITY_ERROR, upload2ErrorHandler); + writer3.addEventListener(IOErrorEvent.IO_ERROR, upload2ErrorHandler); + writer3.load (reqBaseline); + + + } + + private function adjustWriteURI(url:String):String + { + var pos:int = url.indexOf("file:///"); + if (pos != 0) + { + return url; + } + url = url.substring(8); + pos = url.indexOf("|"); + + if (pos != 1) + { + return url; + } + + var drive:String = url.substring(0, 1); + drive = drive.toLowerCase(); + return drive + ":" + url.substring(2); + } + + private var screenDone:Boolean = false; + private var baselineDone:Boolean = false; + + private function writeCompleteHandler(event:Event):void + { + trace("baseline write successful " + event); + if( baselineMissing ){ + baselineMissing = false; + testResult.doFail( baselineMissingMessage ); + } + stepComplete(); + } + + private function uploadCompleteHandler(event:Event):void + { + trace("screen image upload successful " + event); + screenDone = true; + checkForStepComplete(); + } + + private function upload2CompleteHandler(event:Event):void + { + trace("baseline image upload successful " + event); + baselineDone = true; + checkForStepComplete(); + } + + private function writeErrorHandler(event:Event):void + { + if( baselineMissing ){ + baselineMissing = false; + testResult.doFail( baselineMissingMessageFail ); + stepComplete(); + }else{ + testResult.doFail ("error on baseline write: " + event); + trace("Image baseline write failed " + event); + if (UnitTester.createBitmapReferences) + stepComplete(); + } + } + private function uploadErrorHandler(event:Event):void + { + testResult.doFail ("error on baseline write: " + event); + trace("Image screen upload failed " + event); + screenDone = true; + checkForStepComplete(); + } + + private function upload2ErrorHandler(event:Event):void + { + testResult.doFail ("error on baseline write: " + event); + trace("Image baseline upload failed " + event); + baselineDone = true; + checkForStepComplete(); + } + + private function checkForStepComplete():void + { + + if (baselineDone && screenDone) + preStepComplete(); + + + } + + /** + * customize string representation + */ + override public function toString():String + { + var s:String = (UnitTester.createBitmapReferences) ? "CreateBitmap: " : "CompareBitmap"; + if (target) + s += ": target = " + target; + if (url) + s += ", url = " + url; + return s; + } + + private function absolutePathResult(url:String):String + { + + var base:String = null; + + if (UnitTester.isApollo) + { + base = adjustWriteURI(adjustPath (url)); + } else + { + base = context.application.url; + + } + + base = normalizeURL(base); + base = base.substring (base.indexOf ("mustella/tests")+14); + + + if (!UnitTester.isApollo) + { + base = base.substring(0, base.lastIndexOf("/")); + + var tmp:String = url; + + while (tmp.indexOf("../") == 0) + { + base = base.substring(0, base.lastIndexOf("/")); + tmp = tmp.substring(3); + } + + return base +"/" + tmp; + } else + { + return base; + + } + + + + } + + private function absolutePathHttp(url:String):String + { + + if (url.indexOf ("..") == 0) + return url.substring (3); + else + return url; + + + } + + + + private function absolutePath(url:String):String + { + var swf:String = normalizeURL(root.loaderInfo.url); + + var pos:int = swf.indexOf("file:///"); + + + if (pos != 0) + { + + var posH:int = swf.indexOf("http://"); + if (posH == 0) + { + return absolutePathHttp (url); + } else + { + + trace("WARNING: unexpected swf url format, no file:/// at offset 0"); + return url; + } + } + swf = swf.substring(8); + pos = swf.indexOf("|"); + if (pos != 1) + { + trace("WARNING: unexpected swf url format, no | at offset 1 in: " + swf); + // assume we're on a mac or other unix box, it will do no harm + return "/" + swf.substring(0, swf.lastIndexOf ("/")+1) + url; + } + + var drive:String = swf.substring(0, 1); + drive = drive.toLowerCase(); + return drive + ":" + swf.substring(2, swf.lastIndexOf("/") + 1) + url; + } + + + public static function normalizeURL(url:String):String + { + var results:Array = url.split("/[[DYNAMIC]]/"); + return results[0]; + } + + + public function keepGoing():void + { + trace("keepgoing", url, hasEventListener("stepComplete")); + preStepComplete(); + } + + private function encodeURI2(s:String):String + { + var pos:int = s.lastIndexOf("/"); + if (pos != -1) + { + var fragment:String = s.substring(pos + 1); + s = s.substring(0, pos + 1); + fragment= encodeURIComponent(fragment); + s = s + fragment; + } + return s; + } + + private function compareWithVariances(bm:BitmapData):Object + { + + var totalAllowed:int = numColorVariances * UnitTester.pixelToleranceMultiplier; + var allowed:int = totalAllowed; + var n:int = bm.height; + var m:int = bm.width; + + for (var i:int = 0; i < n; i++) + { + for (var j:int = 0; j < m; j++) + { + var pix:int = bm.getPixel(j, i); + if (pix) + { + if(!ignoreMaxColorVariance) + { + var red:int = pix >> 16 & 0xff; + var green:int = pix >> 8 & 0xff; + var blue:int = pix & 0xff; + if (red & 0x80) + red = 256 - red; + if (blue & 0x80) + blue = 256 - blue; + if (green & 0x80) + green = 256 - green; + if (red > maxColorVariance || + blue > maxColorVariance || + green > maxColorVariance) + { + var max:int = Math.max(Math.max(red, blue), green); + trace("CompareBitmap: exceeded maxColorVariance=" + maxColorVariance + " max(red,green,blue)=" + max); + return bm; + } + } + allowed--; + if (allowed < 0) + { + trace("CompareBitmap: exceeded numColorVariances=" + numColorVariances); + return bm; + } + } + } + } + + trace("CompareBitmap: numColorVariances seen=" + String(totalAllowed - allowed)); + return 0; + } + + private function checkEmbeddedFonts(target:Object):Boolean + { + if ("rawChildren" in target) + target = target.rawChildren; + + if (target is TextField) + { + if (target.embedFonts == false) + return false; + if (target.antiAliasType == "advanced") + return false; + return true; + } + else if ("numChildren" in target) + { + var n:int = target.numChildren; + for (var i:int = 0; i < n; i++) + { + if (!checkEmbeddedFonts(target.getChildAt(i))) + return false; + } + } + + return true; + } + + protected function preStepComplete():void + { + if (baselineBits != null) + baselineBits.dispose(); + if (screenBits != null) + screenBits.dispose(); + + reader=null; + writer=null; + + stepComplete(); + } + + /* this was sometimes getting called before the image was loaded into + 'reader' which made it null and then the readCompleteHandler failed. + override protected function stepComplete():void + { + + if (baselineBits != null) + baselineBits.dispose(); + if (screenBits != null) + screenBits.dispose(); + + reader=null; + writer=null; + + super.stepComplete(); + + + }*/ + + /****** DisplayList Comparision ******/ + protected function getDisplayListProperties(d:DisplayObject, noMask:Boolean = false):XML + { + var xml:XML; + var n:int; + var i:int; + var childXML:XML; + var s:String = getQualifiedClassName(d); + s = s.replace("::", "."); + xml = new XML("<" + s + "/>"); + s = d.transform.concatenatedColorTransform.toString(); + if (s != identityColorTransform) + xml.@concatenatedColorTransform = s; + if (d.transform.matrix) + { + s = d.transform.matrix.toString(); + if (s != identityMatrix) + { + if (s.indexOf("(a=1, b=0, c=0, d=1, ") == -1) + xml.@matrix = s; + } + } + else + { + s = d.transform.matrix3D.rawData.toString(); + xml.@matrix3D = s; + } + if (d.x != 0) + xml.@x = d.x; + if (d.y != 0) + xml.@y = d.y; + xml.@width = d.width; + xml.@height = d.height; + if (xml.visible == false) + xml.@visible = "false"; + if (d.mask && d.mask != d.parent && !noMask) + { + xml.mask = <mask/>; + childXML = getDisplayListProperties(d.mask, true); + xml.mask.appendChild = childXML; + } + if (d.scrollRect) + { + s = d.scrollRect.toString(); + xml.@scrollRect = s; + } + if (d.blendMode && d.blendMode != "normal") + xml.@blendMode = d.blendMode; + if (d.cacheAsBitmap) + xml.@cacheAsBitmap = "true"; + try { + if (d.filters && d.filters.length > 0) + { + s = d.filters.toString(); + xml.@filters = s; + } + } catch (e:Error) + { + // seems to throw arg error when Shader applied + } + if (d.opaqueBackground) + xml.@opaqueBackground = "true"; + if (d.scale9Grid) + { + s = d.scale9Grid.toString(); + xml.@scale9Grid = s; + } + if (d is TextField) + { + xml.@underline = TextField(d).defaultTextFormat.underline; + xml.htmlText = TextField(d).htmlText; + } + if (d is Loader && Loader(d).contentLoaderInfo.contentType.indexOf("image") != -1) + { + s = Loader(d).contentLoaderInfo.url; + s = s.substring(s.lastIndexOf("/") + 1); + xml.@loaderbitmap = s; + } + if (d is TextLine) + { + var tl:TextLine = TextLine(d); + xml.@ascent = tl.ascent; + xml.@descent = tl.descent; + xml.@atomCount = tl.atomCount; + xml.@hasGraphicElement = tl.hasGraphicElement; + if (tl.textBlock) + { + var tb:TextBlock = TextLine(d).textBlock; + var ce:ContentElement = tb.content; + s = ce.rawText.substr(tl.textBlockBeginIndex, tl.rawTextLength); + xml.@text = s; + } + } + + if (d is IRawChildrenContainer) + { + var rawChildren:IChildList = IRawChildrenContainer(d).rawChildren; + n = rawChildren.numChildren; + for (i = 0; i < n; i++) + { + childXML = getDisplayListProperties(rawChildren.getChildAt(i)); + xml.appendChild(childXML); + } + } + else if (d is DisplayObjectContainer) + { + var doc:DisplayObjectContainer = d as DisplayObjectContainer; + n = doc.numChildren; + for (i = 0; i < n; i++) + { + var child:DisplayObject = doc.getChildAt(i); + if (child) // was null in an FCK test. + { + childXML = getDisplayListProperties(child); + xml.appendChild(childXML); + } + else + xml.appendChild(<NullChild />); + } + } + return xml; + } + + // scan entire display list, but only dump objects intersecting target + protected function getDisplayListXML(target:DisplayObject):XML + { + var i:int; + var n:int; + var child:DisplayObject; + var childXML:XML; + + var doc:DisplayObjectContainer = DisplayObjectContainer(target.root); + var xml:XML = <DisplayList />; + if (doc is IRawChildrenContainer) + { + var rawChildren:IChildList = IRawChildrenContainer(doc).rawChildren; + n = rawChildren.numChildren; + for (i = 0; i < n; i++) + { + child = rawChildren.getChildAt(i); + if (target.hitTestObject(child)) + { + childXML = getDisplayListProperties(child); + xml.appendChild(childXML); + } + } + } + else + { + n = doc.numChildren; + for (i = 0; i < n; i++) + { + child = doc.getChildAt(i); + if (target.hitTestObject(child)) + { + childXML = getDisplayListProperties(child); + xml.appendChild(childXML); + } + } + } + return xml; + } + + private function differ(s:String, t:String):Boolean + { + var retval:Boolean = false; + + var sl:Array = s.split("\n"); + var tl:Array = t.split("\n"); + trace(sl.length, tl.length); + var n:int = Math.max(sl.length, tl.length); + for (var i:int = 0; i < n; i++) + { + var a:String = (i < sl.length) ? sl[i] : ""; + var b:String = (i < tl.length) ? tl[i] : ""; + if (a != b) + { + a = trimTag(a); + b = trimTag(b); + if (a != b && !nullChildOrStaticText(a, b)) + { + retval = true; + var c:String = ""; + var d:String = ""; + trace(i, "cur: ", a); + trace(i, "xml: ", b); + var m:int = Math.max(a.length, b.length); + for (var j:int = 0; j < m; j++) + { + c += a.charCodeAt(j) + " "; + d += b.charCodeAt(j) + " "; + } + trace(i, "cur: ", c); + trace(i, "xml: ", d); + } + } + } + return retval; + } + + // attempt to strip off random unique name chars for embedded assets + private function trimTag(a:String):String + { + var c:int; + var d:int; + + d = a.indexOf("<"); + if (d != -1) + { + c = a.indexOf(" ", d); + if (c == -1 && a.length > d + 2 && a.charAt(d + 1) == '/') + c = a.indexOf(">"); // closing tag + if (c != -1) + { + var rest:String = a.substring(c); + for (var i:int = c - 1;i > 0; i--) + { + var ch:String = a.charAt(i); + if ((ch >= '0' && ch <= '9') || ch == '_') + { + // assume it is a random char + } + else + break; + } + return a.substring(0, i + 1) + rest; + } + } + return a; + } + + // attempt to strip off random unique name chars for embedded assets + private function trimName(a:String):String + { + var c:int; + var d:int; + + c = a.length; + for (var i:int = c - 1;i >= 0; i--) + { + var ch:String = a.charAt(i); + if ((ch >= '0' && ch <= '9') || ch == '_') + { + // assume it is a random char + } + else + break; + } + return a.substring(0, i + 1); + } + + // static text seems to float around a bit so ignore it. + private function nullChildOrStaticText(a:String, b:String):Boolean + { + if (a.indexOf("<NullChild") != -1) + return true; + if (b.indexOf("<NullChild") != -1) + return true; + if (a.indexOf("<flash.text.StaticText") != -1) + return true; + if (b.indexOf("<flash.text.StaticText") != -1) + return true; + return false; + } + + private function xmldiffer(s:String, t:String):Boolean + { + var retval:Boolean = false; + + var xmls:XML = XML(s); + var xmlt:XML = XML(t); + retval = compareNodes(xmls, xmlt); + if (retval) + differ(s, t); + return retval; + } + + private static var xywidthheight:Object = { x: 1, y: 1, width: 1, height: 1}; + + private function compareNodes(s:XML, t:XML):Boolean + { + var retval:Boolean = false; + var q:String; + var i:int; + var j:int; + var n:int; + var m:int; + var st:String; + var tt:String; + var sv:String; + var tv:String; + + if (s.toXMLString() == t.toXMLString()) + return false; + + // compare tag names + var sn:String = s.name().toString(); + var tn:String = t.name().toString(); + var sparts:Array = sn.split("."); + var tparts:Array = tn.split("."); + n = sparts.length; + for (i = 0; i < n; i++) + sparts[i] = trimName(sparts[i]); + n = tparts.length; + for (i = 0; i < n; i++) + tparts[i] = trimName(tparts[i]); + sn = sparts.join("."); + tn = tparts.join("."); + if (tn != sn) + { + if (sn == "NullChild" || sn == "flash.display.StaticText" || + tn == "NullChild" || tn == "flash.display.StaticText") + { + // inconsistent behavior around StaticText + return false; + } + else if (!oneMoreNameCompare(sn, tn)) + { + trace("tag name mismatch: cur=", sn, "xml=", tn); + retval = true; + } + } + + var sa:XMLList = s.attributes(); + var ta:XMLList = t.attributes(); + n = sa.length(); + m = ta.length(); + if (n != m) + { + trace(sn, "different number of attributes: cur=", n, "xml=", m); + retval = true; + } + else + { + for (i = 0; i < n; i++) + { + st = sa[i].name().toString(); + tt = ta[i].name().toString(); + if (st != tt) + { + trace(sn, "attribute name mismatch: cur=", st, "xml=", tt); + retval = true; + } + else + { + sv = s['@' + st].toString(); + tv = t['@' + tt].toString(); + if (sv != tv) + { + if (xywidthheight[st] == 1) + { + var sf:Number = Number(sv); + var tf:Number = Number(tv); + if (Math.abs(tf - sf) > maxMatrixVariance) + { + trace(sn + '@' + st, "attribute value mismatch: cur=", sv, "xml=", tv); + retval = true; + } + } + else if (st == "matrix") + { + // strip parens + sv = sv.substring(1, sv.length - 2); + tv = tv.substring(1, tv.length - 2); + sparts = sv.split(","); + tparts = tv.split(","); + m = sparts.length; + for (j = 0; j < m; j++) + { + sv = sparts[j]; + tv = tparts[j]; + sv = sv.split("=")[1]; + tv = tv.split("=")[1]; + sf = Number(sv); + tf = Number(tv); + if (Math.abs(tf - sf) > maxMatrixVariance) + { + trace(sn + '@' + st, "matrix value mismatch: cur=", sv, "xml=", tv); + retval = true; + } + } + } + else + { + trace(sn + '@' + st, "attribute value mismatch: cur=", sv, "xml=", tv); + retval = true; + } + } + } + } + } + + var sl:XMLList = s.children(); + var tl:XMLList = t.children(); + n = sl.length(); + m = tl.length(); + if (n != m) + { + trace(sn, "different number of children: cur=", n, "xml=", m); + retval = true; + } + else + { + for (i = 0; i < n; i++) + { + var nk:String = sl[i].nodeKind(); + if (nk == "text") + { + if (sl[i].text() != tl[i].text()) + { + trace(sn, "different number of text nodes: cur=", sl[i].text(), "xml=", tl[i].text()); + retval = true; + } + } + else if (nk == "element") + { + if (compareNodes(sl[i], tl[i])) + retval = true; + } + } + } + return retval; + } + + private function oneMoreNameCompare(a:String, b:String):Boolean + { + var aParts:Array = a.split("_"); + var bParts:Array = b.split("_"); + var i:int; + var n:int; + n = aParts.length; + for (i = 0; i < n; i++) + aParts[i] = trimName(aParts[i]); + n = bParts.length; + for (i = 0; i < n; i++) + bParts[i] = trimName(bParts[i]); + a = aParts.join("_"); + b = bParts.join("_"); + return a == b; + } +} + +}
http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/flex/ConditionalValue.as ---------------------------------------------------------------------- diff --git a/mustella/src/main/flex/ConditionalValue.as b/mustella/src/main/flex/ConditionalValue.as new file mode 100644 index 0000000..b5edc4d --- /dev/null +++ b/mustella/src/main/flex/ConditionalValue.as @@ -0,0 +1,356 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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 +{ +COMPILE::SWF +{ + import flash.events.*; + import mx.utils.*; +} +COMPILE::JS +{ + import org.apache.flex.events.EventDispatcher; +} + + [Event(name="valueExpression", type="RunCodeEvent")] + public class ConditionalValue extends EventDispatcher + { + // Asserts such as AssertPropertyValue use value=... + public var value:Object = null; + + // CompareBitmap uses url=... + public var url:String = null; + + + /** + * These are possibilities for the environment. + * Use Inspectable so that test authoring is a little easier. + * For details: https://zerowing.corp.adobe.com/display/flexmobile/Multiple+Device%2C+DPI%2C+OS+Support + **/ + + [Inspectable(enumeration="win,mac,android,iphone,ios,qnx")] + public var os:String = null; + + [Inspectable(enumeration="android22,android23,android234,android31,iphone421,iphone50,ios4,ios5,ios6")] + public var osVersion:String = null; + + /** + * The targetOS is either null or set in the UnitTester's cv as the value to match + * against the os properties from <ConditionalValue> elements present in the test + * cases. See MultiResult.chooseCV() + */ + [Inspectable(enumeration="android,ios")] + public var targetOS:String = null; + + // General, "marketing number" pixel density + [Inspectable(enumeration="120,160,240,320,480,640")] + public var deviceDensity:Number = -1; + + // Exact pixel density reported by AIR's Capabilities.screenDPI + public var screenDPI:Number = -1; + + // Exact + public var deviceWidth:Number = -1; + + // Exact + public var deviceHeight:Number = -1; + + [Inspectable(enumeration="16,32")] + public var color:Number = -1; + + [Inspectable(enumeration="air,desire,droid,droid2,droidPro,droidX,evo,incredible,iPad,iPad2,iPodTouch3GS,iPodTouch4G,nexusOne,playbook,xoom")] + public var device:String = null; + + /** + * These are used to make file name legible to humans and allow + * parsing of them. + **/ + public static const SCREENDPI_SUFFIX:String = "scrDPI"; + public static const DENSITY_SUFFIX:String = "ppi"; + public static const WIDTH_SUFFIX:String = "w"; + public static const HEIGHT_SUFFIX:String = "h"; + public static const COLOR_SUFFIX:String = "bit"; + public static const PNG_SUFFIX:String = ".png"; + public static const DELIMITER1:String = "@"; // between testID and settings + public static const DELIMITER2:String = "_"; // between settings + + /** + * Constructor + **/ + public function ConditionalValue(){} + + /** + * Returns true if all items are at default values (e.g. the default, catch-all CV). + **/ + public function isDefault():Boolean{ + return ((os == null) && + (osVersion == null) && + (screenDPI == -1) && + (deviceDensity == -1) && + (deviceWidth == -1) && + (deviceHeight == -1) && + (color == -1) && + (device == null) && + (targetOS == null) + ); + } + + /** + * Uses the properties which are set to create a file name for a baseline image. + **/ + public function createFilename(testID:String):String{ + var ret:String = null; + var consistent:Boolean = false; + var testCV:ConditionalValue = new ConditionalValue(); + + ret = testID + DELIMITER1; + + if( os != null ) { + ret += os + DELIMITER2; + } + +/* if( targetOS != null ) { + ret += targetOS + DELIMITER2; + }*/ + + if( osVersion != null ){ + ret += osVersion + DELIMITER2; + } + + if( screenDPI > -1 ){ + ret += screenDPI.toString() + SCREENDPI_SUFFIX + DELIMITER2; + } + + if( deviceDensity > -1 ){ + ret += deviceDensity.toString() + DENSITY_SUFFIX + DELIMITER2; + } + + if( deviceWidth > -1 ){ + ret += deviceWidth.toString() + WIDTH_SUFFIX + DELIMITER2; + } + + if( deviceHeight > -1 ){ + ret += deviceHeight.toString() + HEIGHT_SUFFIX + DELIMITER2; + } + + if( color > -1 ){ + ret += color.toString() + COLOR_SUFFIX + DELIMITER2; + } + + if( device != null ){ + ret += device; + }else{ + // Remove last DELIMITER2. + if( ret.lastIndexOf(DELIMITER2) == ret.length - 1 ){ + ret = ret.substr(0, ret.length - 1); + } + } + + ret += PNG_SUFFIX; + + trace("ConditionalValue ret="+ret+"; screenDPI="+screenDPI+"; density="+deviceDensity); + + // Be sure we'll be able to parse what we wrote when we read it later. + if( testCV.parseFilename( ret ) ){ + consistent = (testCV.os == os && + testCV.osVersion == osVersion && + testCV.screenDPI == screenDPI && + testCV.deviceDensity == deviceDensity && + testCV.deviceWidth == deviceWidth && + testCV.deviceHeight == deviceHeight && + testCV.color == color && + testCV.device == device ); + } + + if( consistent ){ + return ret; + }else{ + trace("ConditionalValue inconsistency:"); + trace("\twhat\ttestCV\tactualCV"); + trace("\tos\t" + testCV.os + "\t" + os); + trace("\tosVersion\t" + testCV.osVersion + "\t" + osVersion); + trace("\tscreenDPI\t" + testCV.screenDPI + "\t" + screenDPI); + trace("\tdeviceDensity\t" + testCV.deviceDensity + "\t" + deviceDensity); + trace("\tdeviceWidth\t" + testCV.deviceWidth + "\t" + deviceWidth); + trace("\tdeviceHeight\t" + testCV.deviceHeight + "\t" + deviceHeight); + trace("\tcolor\t" + testCV.color + "\t" + color); + trace("\tdevice\t" + testCV.device + "\t" + device); + + return null; + } + } + + /** + * Populate values from a filename. + **/ + public function parseFilename(filename:String):Boolean{ + COMPILE::SWF + { + var tokens:Array = null; + var curToken:String = null; + var tokenDone:Boolean = false; + var i:int = 0; + var j:int = 0; + + + if( filename != null ){ + // Remove the extension. + if( filename.indexOf( PNG_SUFFIX ) > -1 ){ + filename = filename.substring( 0, filename.indexOf( PNG_SUFFIX ) ); + } + + if( (filename != null) && (StringUtil.trim( filename ) != "") ){ + tokens = filename.split( DELIMITER1 ); + } + + // tokens[0] is the test case, and tokens[1] is the data. + tokens = tokens[1].split( DELIMITER2 ); + + if( (tokens != null) && (tokens.length > 0) ){ + for( i = 0; i < tokens.length; ++i ){ + curToken = tokens[ i ]; + tokenDone = false; + + // Look for os. + for( j = 0; j < DeviceNames.OS_VALUES.length; ++j ){ + if( curToken == DeviceNames.OS_VALUES[ j ] ){ + os = curToken; + targetOS = curToken; + tokenDone = true; + break; + } + } + + if( !tokenDone ){ + // Look for os version. + for( j = 0; j < DeviceNames.OS_VERSION_VALUES.length; ++j ){ + if( curToken == DeviceNames.OS_VERSION_VALUES[ j ] ){ + osVersion = curToken; + tokenDone = true; + break; + } + } + } + + if( !tokenDone ){ + // Look for screenDPI + if( curToken.indexOf( SCREENDPI_SUFFIX ) > -1 ){ + curToken = curToken.substring( 0, curToken.indexOf( SCREENDPI_SUFFIX ) ); + if( (curToken != null) && (StringUtil.trim( curToken ) != "") ){ + screenDPI = new Number( curToken ); + tokenDone = true; + } + } + } + + if( !tokenDone ){ + // Look for density. + if( curToken.indexOf( DENSITY_SUFFIX ) > -1 ){ + curToken = curToken.substring( 0, curToken.indexOf( DENSITY_SUFFIX ) ); + if( (curToken != null) && (StringUtil.trim( curToken ) != "") ){ + deviceDensity = new Number( curToken ); + tokenDone = true; + } + } + } + + if( !tokenDone ){ + // Look for width. + if( curToken.indexOf( WIDTH_SUFFIX ) > -1 ){ + curToken = curToken.substring( 0, curToken.indexOf( WIDTH_SUFFIX ) ); + if( (curToken != null) && (StringUtil.trim( curToken ) != "") ){ + deviceWidth = new Number( curToken ); + tokenDone = true; + } + } + } + + if( !tokenDone ){ + // Look for height. + if( curToken.indexOf( HEIGHT_SUFFIX ) > -1 ){ + curToken = curToken.substring( 0, curToken.indexOf( HEIGHT_SUFFIX ) ); + if( (curToken != null) && (StringUtil.trim( curToken ) != "") ){ + deviceHeight = new Number( curToken ); + tokenDone = true; + } + } + } + + if( !tokenDone ){ + // Look for color. + if( curToken.indexOf( COLOR_SUFFIX ) > -1 ){ + curToken = curToken.substring( 0, curToken.indexOf( COLOR_SUFFIX ) ); + if( (curToken != null) && (StringUtil.trim( curToken ) != "") ){ + color = new Number( curToken ); + tokenDone = true; + } + } + } + + if( !tokenDone ){ + // Look for device. + for( j = 0; j < DeviceNames.DEVICE_VALUES.length; ++j ){ + if( curToken == DeviceNames.DEVICE_VALUES[ j ] ){ + device = curToken; + tokenDone = true; + break; + } + } + } + + if( !tokenDone ){ + trace("trouble with token: " + curToken); + } + } + } + } + + // If anything went wrong, tokenDone will be false. + return tokenDone; + } + COMPILE::JS + { + return false; + } + } + + /** + * Return a list of the properties. + **/ + COMPILE::SWF + override public function toString():String{ + var ret:String; + + ret = "\tvalue=" + String(value); + ret += "\n\turl=" + url; + ret += "\n\tos=" + os; + ret += "\n\ttargetOS=" + targetOS; + ret += "\n\tosVersion=" + osVersion; + ret += "\n\tscreenDPI=" + screenDPI; + ret += "\n\tdeviceDensity=" + deviceDensity; + ret += "\n\tdeviceWidth=" + deviceWidth; + ret += "\n\tdeviceHeight=" + deviceHeight; + ret += "\n\tcolor=" + color; + ret += "\n\tdevice=" + device; + + return ret; + } + + } +} http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.ICO ---------------------------------------------------------------------- diff --git a/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.ICO b/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.ICO new file mode 100644 index 0000000..b1afed3 Binary files /dev/null and b/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.ICO differ http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.cpp ---------------------------------------------------------------------- diff --git a/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.cpp b/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.cpp new file mode 100644 index 0000000..16e09a9 --- /dev/null +++ b/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.cpp @@ -0,0 +1,362 @@ +/* + * + * 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. + * + */ +// ContinueAfterRuntimeException.cpp : Defines the entry point for the application. +// + +#include "stdafx.h" +#include "resource.h" + +#define MAX_LOADSTRING 100 + +// Global Variables: +HINSTANCE hInst; // current instance +TCHAR szTitle[MAX_LOADSTRING]; // The title bar text +TCHAR szWindowClass[MAX_LOADSTRING]; // The title bar text +TCHAR szPlayer[] = "Adobe Flash Player 9"; +TCHAR szPlayer10[] = "Adobe Flash Player 10"; + +UINT timer; + +// Foward declarations of functions included in this code module: +ATOM MyRegisterClass(HINSTANCE hInstance); +BOOL InitInstance(HINSTANCE, int); +LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); +LRESULT CALLBACK About(HWND, UINT, WPARAM, LPARAM); + +WSADATA wsaData; + +hostent* localHost; +char* localIP; +struct sockaddr_in sockaddr; +SOCKADDR connaddr; +int addrlen = sizeof(connaddr); + +int iResult; +SOCKET ConnectSocket = INVALID_SOCKET; +SOCKET ListenSocket = INVALID_SOCKET; + + +int APIENTRY WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) +{ + // TODO: Place code here. + MSG msg; + HACCEL hAccelTable; + + // Initialize global strings + LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); + LoadString(hInstance, IDC_CONTINUEAFTERRUNTIMEEXCEPTION, szWindowClass, MAX_LOADSTRING); + MyRegisterClass(hInstance); + + // Initialize Winsock + iResult = WSAStartup(MAKEWORD(2,2), &wsaData); + if (iResult != 0) { + return 1; + } + + // Perform application initialization: + if (!InitInstance (hInstance, nCmdShow)) + { + return FALSE; + } + + hAccelTable = LoadAccelerators(hInstance, (LPCTSTR)IDC_CONTINUEAFTERRUNTIMEEXCEPTION); + + // Main message loop: + while (GetMessage(&msg, NULL, 0, 0)) + { + if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + // shutdown the connection since no more data will be sent + iResult = shutdown(ListenSocket, SD_BOTH); + closesocket(ListenSocket); + ListenSocket = INVALID_SOCKET; + + WSACleanup(); + return msg.wParam; +} + + + +// +// FUNCTION: MyRegisterClass() +// +// PURPOSE: Registers the window class. +// +// COMMENTS: +// +// This function and its usage is only necessary if you want this code +// to be compatible with Win32 systems prior to the 'RegisterClassEx' +// function that was added to Windows 95. It is important to call this function +// so that the application will get 'well formed' small icons associated +// with it. +// +ATOM MyRegisterClass(HINSTANCE hInstance) +{ + WNDCLASSEX wcex; + + wcex.cbSize = sizeof(WNDCLASSEX); + + wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.lpfnWndProc = (WNDPROC)WndProc; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = hInstance; + wcex.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_CONTINUEAFTERRUNTIMEEXCEPTION); + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = (LPCSTR)IDC_CONTINUEAFTERRUNTIMEEXCEPTION; + wcex.lpszClassName = szWindowClass; + wcex.hIconSm = LoadIcon(wcex.hInstance, (LPCTSTR)IDI_SMALL); + + return RegisterClassEx(&wcex); +} + +// +// FUNCTION: InitInstance(HANDLE, int) +// +// PURPOSE: Saves instance handle and creates main window +// +// COMMENTS: +// +// In this function, we save the instance handle in a global variable and +// create and display the main program window. +// +BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) +{ + HWND hWnd; + + hInst = hInstance; // Store instance handle in our global variable + + hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); + + if (!hWnd) + { + return FALSE; + } + + timer = SetTimer(hWnd, 1, 1000, NULL); + + localHost = gethostbyname(""); + localIP = "127.0.0.1"; //inet_ntoa (*(struct in_addr *)*localHost->h_addr_list); + +#ifdef _DEBUG + OutputDebugString("Listening on socket "); + OutputDebugString(localIP); + OutputDebugString("\n"); +#endif + + ShowWindow(hWnd, nCmdShow); + UpdateWindow(hWnd); + + + ZeroMemory( &sockaddr, sizeof(sockaddr) ); + // Set up the sockaddr structure + sockaddr.sin_family = AF_INET; + sockaddr.sin_addr.s_addr = inet_addr(localIP); + sockaddr.sin_port = htons(2561); + + // Create a SOCKET for connecting to server + ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_IP); + if (ListenSocket == INVALID_SOCKET) + { + return FALSE; + } + iResult = bind(ListenSocket, (SOCKADDR *)&sockaddr, sizeof(sockaddr)); + if (iResult == SOCKET_ERROR) + { + closesocket(ListenSocket); + ListenSocket = INVALID_SOCKET; + return FALSE; + } + iResult = listen(ListenSocket, 1); + if (iResult == SOCKET_ERROR) + { + closesocket(ListenSocket); + ListenSocket = INVALID_SOCKET; + return FALSE; + } + + WSAAsyncSelect(ListenSocket, hWnd, EM_SETSEL, FD_CLOSE); + + return TRUE; +} + +void CheckForExceptionDialog(HWND hWnd) +{ + hWnd = GetWindow(hWnd, GW_HWNDFIRST); + while (hWnd) + { + char szTitle[1024]; + GetWindowText(hWnd, szTitle, 256); + if (lstrcmp(szTitle, szPlayer) == 0 || lstrcmp(szTitle, szPlayer10) == 0) + { + HWND hDlg = hWnd; + HWND hChild = GetWindow(hWnd, GW_CHILD); + char szError[1024]; + szError[0] = '\0'; + HWND hButton = (HWND)INVALID_HANDLE_VALUE; + LONG idButton = 0; + while (hChild) + { + GetWindowText(hChild, szTitle, 1024); + if (lstrcmp(szTitle, "&Continue") == 0) + { + idButton = GetWindowLong(hChild, GWL_ID); + hButton = hChild; + } + else + { + char szClassName[256]; + GetClassName(hChild, szClassName, 256); + if (lstrcmp(szClassName, "Edit") == 0) + { + SendMessage(hChild, WM_GETTEXT, MAKELONG(LOWORD(1024), 0), (LONG)szError); + } + } + hChild = GetWindow(hChild, GW_HWNDNEXT); + } + if (hButton != INVALID_HANDLE_VALUE) + { + if (ConnectSocket != INVALID_SOCKET) + { + // Send an initial buffer + iResult = send( ConnectSocket, szError, (int)strlen(szError), 0 ); + if (iResult == SOCKET_ERROR) + { +#ifdef _DEBUG + OutputDebugString("Error sending to socket\n"); +#endif + closesocket(ConnectSocket); + ConnectSocket = INVALID_SOCKET; + return; + } +#ifdef _DEBUG + else + OutputDebugString(szError); +#endif + + } + + SendMessage(hDlg, WM_COMMAND, MAKELONG(LOWORD(idButton), BN_CLICKED), (LONG)hButton); + + return; + } + } + hWnd = GetWindow(hWnd, GW_HWNDNEXT); + } +} + +// +// FUNCTION: WndProc(HWND, unsigned, WORD, LONG) +// +// PURPOSE: Processes messages for the main window. +// +// WM_COMMAND - process the application menu +// WM_PAINT - Paint the main window +// WM_DESTROY - post a quit message and return +// +// +LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + int wmId, wmEvent; + PAINTSTRUCT ps; + HDC hdc; + TCHAR szHello[MAX_LOADSTRING]; + LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING); + + switch (message) + { + case WM_COMMAND: + wmId = LOWORD(wParam); + wmEvent = HIWORD(wParam); + // Parse the menu selections: + switch (wmId) + { + case IDM_ABOUT: + DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About); + break; + case IDM_EXIT: + DestroyWindow(hWnd); + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + break; + case WM_PAINT: + hdc = BeginPaint(hWnd, &ps); + // TODO: Add any drawing code here... + RECT rt; + GetClientRect(hWnd, &rt); + if (localIP) + DrawText(hdc, localIP, strlen(localIP), &rt, DT_CENTER); + EndPaint(hWnd, &ps); + break; + case WM_TIMER: + if (ConnectSocket == INVALID_SOCKET) + { + ConnectSocket = accept(ListenSocket, &connaddr, &addrlen); + if (ConnectSocket != INVALID_SOCKET) + { +#ifdef _DEBUG + OutputDebugString("Connected to socket\n"); +#endif + } + } + CheckForExceptionDialog(hWnd); + break; + case WM_DESTROY: + PostQuitMessage(0); + break; + case EM_SETSEL: + ConnectSocket = INVALID_SOCKET; + break; + default: + return DefWindowProc(hWnd, message, wParam, lParam); + } + return 0; +} + +// Mesage handler for about box. +LRESULT CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + return TRUE; + + case WM_COMMAND: + if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) + { + EndDialog(hDlg, LOWORD(wParam)); + return TRUE; + } + break; + } + return FALSE; +} + http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.dsp ---------------------------------------------------------------------- diff --git a/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.dsp b/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.dsp new file mode 100644 index 0000000..93d2a67 --- /dev/null +++ b/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.dsp @@ -0,0 +1,140 @@ +# Microsoft Developer Studio Project File - Name="ContinueAfterRuntimeException" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +CFG=ContinueAfterRuntimeException - Win32 Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "ContinueAfterRuntimeException.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "ContinueAfterRuntimeException.mak" CFG="ContinueAfterRuntimeException - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "ContinueAfterRuntimeException - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "ContinueAfterRuntimeException - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "ContinueAfterRuntimeException - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib /nologo /subsystem:windows /machine:I386 + +!ELSEIF "$(CFG)" == "ContinueAfterRuntimeException - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c +# ADD CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib ws2_32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "ContinueAfterRuntimeException - Win32 Release" +# Name "ContinueAfterRuntimeException - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\ContinueAfterRuntimeException.cpp +# End Source File +# Begin Source File + +SOURCE=.\ContinueAfterRuntimeException.rc +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.cpp +# ADD CPP /Yc"stdafx.h" +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\ContinueAfterRuntimeException.h +# End Source File +# Begin Source File + +SOURCE=.\resource.h +# End Source File +# Begin Source File + +SOURCE=.\StdAfx.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# Begin Source File + +SOURCE=.\ContinueAfterRuntimeException.ico +# End Source File +# Begin Source File + +SOURCE=.\small.ico +# End Source File +# End Group +# Begin Source File + +SOURCE=.\ReadMe.txt +# End Source File +# End Target +# End Project http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.dsw ---------------------------------------------------------------------- diff --git a/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.dsw b/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.dsw new file mode 100644 index 0000000..128f914 --- /dev/null +++ b/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "ContinueAfterRuntimeException"=.\ContinueAfterRuntimeException.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.h ---------------------------------------------------------------------- diff --git a/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.h b/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.h new file mode 100644 index 0000000..84c0736 --- /dev/null +++ b/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.h @@ -0,0 +1,30 @@ +/* + * + * 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. + * + */ + +#if !defined(AFX_CONTINUEAFTERRUNTIMEEXCEPTION_H__DC8E8327_5E0B_4EE3_9891_6C46447FEBFD__INCLUDED_) +#define AFX_CONTINUEAFTERRUNTIMEEXCEPTION_H__DC8E8327_5E0B_4EE3_9891_6C46447FEBFD__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "resource.h" + + +#endif // !defined(AFX_CONTINUEAFTERRUNTIMEEXCEPTION_H__DC8E8327_5E0B_4EE3_9891_6C46447FEBFD__INCLUDED_) http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.rc ---------------------------------------------------------------------- diff --git a/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.rc b/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.rc new file mode 100644 index 0000000..b6518fa --- /dev/null +++ b/mustella/src/main/flex/ContinueAfterRuntimeException/ContinueAfterRuntimeException.rc @@ -0,0 +1,140 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#define APSTUDIO_HIDDEN_SYMBOLS +#include "windows.h" +#undef APSTUDIO_HIDDEN_SYMBOLS +#include "resource.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_CONTINUEAFTERRUNTIMEEXCEPTION ICON DISCARDABLE "ContinueAfterRuntimeException.ICO" +IDI_SMALL ICON DISCARDABLE "SMALL.ICO" + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDC_CONTINUEAFTERRUNTIMEEXCEPTION MENU DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "E&xit", IDM_EXIT + END + POPUP "&Help" + BEGIN + MENUITEM "&About ...", IDM_ABOUT + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDC_CONTINUEAFTERRUNTIMEEXCEPTION ACCELERATORS MOVEABLE PURE +BEGIN + "?", IDM_ABOUT, ASCII, ALT + "/", IDM_ABOUT, ASCII, ALT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUTBOX DIALOG DISCARDABLE 22, 17, 230, 75 +STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "About" +FONT 8, "System" +BEGIN + ICON IDI_CONTINUEAFTERRUNTIMEEXCEPTION,IDC_MYICON,14,9,16,16 + LTEXT "ContinueAfterRuntimeException Version 1.0",IDC_STATIC, + 49,10,119,8,SS_NOPREFIX + LTEXT "Copyright (C) 2006",IDC_STATIC,49,20,119,8 + DEFPUSHBUTTON "OK",IDOK,195,6,30,11,WS_GROUP +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#define APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""windows.h""\r\n" + "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n" + "#include ""resource.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// String Table +// + +STRINGTABLE DISCARDABLE +BEGIN + IDS_APP_TITLE "ContinueAfterRuntimeException" + IDS_HELLO "I watch for the Flash Player's\nexception dialog and will hit Continue\n when it appears." + IDC_CONTINUEAFTERRUNTIMEEXCEPTION "CONTINUEAFTERRUNTIMEEXCEPTION" +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/flex/ContinueAfterRuntimeException/SMALL.ICO ---------------------------------------------------------------------- diff --git a/mustella/src/main/flex/ContinueAfterRuntimeException/SMALL.ICO b/mustella/src/main/flex/ContinueAfterRuntimeException/SMALL.ICO new file mode 100644 index 0000000..3323086 Binary files /dev/null and b/mustella/src/main/flex/ContinueAfterRuntimeException/SMALL.ICO differ http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/flex/ContinueAfterRuntimeException/StdAfx.cpp ---------------------------------------------------------------------- diff --git a/mustella/src/main/flex/ContinueAfterRuntimeException/StdAfx.cpp b/mustella/src/main/flex/ContinueAfterRuntimeException/StdAfx.cpp new file mode 100644 index 0000000..d90fe4a --- /dev/null +++ b/mustella/src/main/flex/ContinueAfterRuntimeException/StdAfx.cpp @@ -0,0 +1,26 @@ +/* + * + * 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. + * + */ +// stdafx.cpp : source file that includes just the standard includes +// ContinueAfterRuntimeException.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/flex/ContinueAfterRuntimeException/StdAfx.h ---------------------------------------------------------------------- diff --git a/mustella/src/main/flex/ContinueAfterRuntimeException/StdAfx.h b/mustella/src/main/flex/ContinueAfterRuntimeException/StdAfx.h new file mode 100644 index 0000000..68f06d7 --- /dev/null +++ b/mustella/src/main/flex/ContinueAfterRuntimeException/StdAfx.h @@ -0,0 +1,52 @@ +/* + * + * 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. + * + */ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) +#define AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers + + +// Windows Header Files: +#include <windows.h> +#include <winsock2.h> +#include <ws2tcpip.h> + +// C RunTime Header Files +#include <stdlib.h> +#include <malloc.h> +#include <memory.h> +#include <tchar.h> + +// Local Header Files + +// TODO: reference additional headers your program requires here + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__A9DB83DB_A9FD_11D0_BFD1_444553540000__INCLUDED_) http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/flex/ContinueAfterRuntimeException/resource.h ---------------------------------------------------------------------- diff --git a/mustella/src/main/flex/ContinueAfterRuntimeException/resource.h b/mustella/src/main/flex/ContinueAfterRuntimeException/resource.h new file mode 100644 index 0000000..475cd6c --- /dev/null +++ b/mustella/src/main/flex/ContinueAfterRuntimeException/resource.h @@ -0,0 +1,45 @@ +/* + * + * 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. + * + */ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by CONTINUEAFTERRUNTIMEEXCEPTION.RC +// +#define IDR_MAINFRAME 128 +#define IDD_CONTINUEAFTERRUNTIMEEXCEPTION_DIALOG 102 +#define IDD_ABOUTBOX 103 +#define IDS_APP_TITLE 103 +#define IDM_ABOUT 104 +#define IDM_EXIT 105 +#define IDS_HELLO 106 +#define IDI_CONTINUEAFTERRUNTIMEEXCEPTION 107 +#define IDI_SMALL 108 +#define IDC_CONTINUEAFTERRUNTIMEEXCEPTION 109 +#define IDC_MYICON 2 +#define IDC_STATIC -1 +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS + +#define _APS_NEXT_RESOURCE_VALUE 129 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 110 +#endif +#endif http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/flex/CoverageTimeout.as ---------------------------------------------------------------------- diff --git a/mustella/src/main/flex/CoverageTimeout.as b/mustella/src/main/flex/CoverageTimeout.as new file mode 100644 index 0000000..01e6b75 --- /dev/null +++ b/mustella/src/main/flex/CoverageTimeout.as @@ -0,0 +1,43 @@ +//////////////////////////////////////////////////////////////////////////////// +// +// 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 { + +import flash.display.DisplayObject; +import flash.net.*; +import flash.events.Event; + +[Mixin] +/** + * set a timeout to linger around for coverage data + */ +public class CoverageTimeout +{ + + /** + * Mixin callback that gets everything ready to go. + * The UnitTester waits for an event before starting + */ + public static function init(root:DisplayObject):void + { + UnitTester.coverageTimeout = 30000; + } + + +} +}