You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by ah...@apache.org on 2012/05/03 00:45:08 UTC

svn commit: r1333232 [12/34] - in /incubator/flex/trunk: ./ frameworks/tests/ frameworks/tests/basicTests/ frameworks/tests/basicTests/dmv/ frameworks/tests/basicTests/dmv/scripts/ frameworks/tests/basicTests/dmv/views/ frameworks/tests/basicTests/fxg/...

Added: incubator/flex/trunk/mustella/MustellaResultsParser.java
URL: http://svn.apache.org/viewvc/incubator/flex/trunk/mustella/MustellaResultsParser.java?rev=1333232&view=auto
==============================================================================
--- incubator/flex/trunk/mustella/MustellaResultsParser.java (added)
+++ incubator/flex/trunk/mustella/MustellaResultsParser.java Wed May  2 22:44:38 2012
@@ -0,0 +1,162 @@
+package mustella;
+
+import java.util.*;
+import java.io.File;
+import java.io.FileReader;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.LineNumberReader;
+
+/**
+ * User: aharui
+ * Date: Jun 21, 2005
+ * Time: 2:55:16 PM
+ * read flashlog.txt, look for failures, return 0 if none, otherwise some exit code
+ */
+public class MustellaResultsParser {
+
+    public static void main(String args[]) {
+        
+        String filename;
+        String flashlog = "/Macromedia/Flash Player/Logs/flashlog.txt";
+        
+        String osname = System.getProperty("os.name");
+        if (osname.indexOf("Windows") != -1) {
+            filename = System.getProperty("APPDATA") + flashlog;
+        } else if (osname.indexOf("Mac OS") != -1) {
+            filename = System.getProperty("user.home") + "/Library/Preferences" + flashlog;
+        } else if (osname.indexOf("Unix") != -1 || osname.indexOf("Linux") != -1){
+            filename = System.getProperty("user.home") + "/.macromedia/Flash_Player/Logs/flashlog.txt";
+        } else {
+            filename = System.getProperty("APPDATA") + flashlog;
+        }
+        
+	
+        boolean result = false;
+				
+        if (new File(filename).exists() == false) {
+            System.out.println("result file not found: " + filename);
+        } else {
+			try {
+				MustellaResultsParser p = new MustellaResultsParser(filename);
+				result = p.parse();
+			} catch(IOException e) {}
+        }
+        int exitValue = result ? 0 : 1;
+        System.out.println("results: "+(result?"PASSED":"FAILED"));
+
+		if (exitValue > 0)
+			System.exit(exitValue);
+    }
+
+	private File file;
+
+    public MustellaResultsParser(String filename) throws IOException {
+		file = new File(filename);
+        if (!file.isFile()) {
+	        System.out.println("file " + filename + " not a file");
+        }
+    }
+
+    public boolean parse() {
+        boolean passed = true;
+
+		LineNumberReader lnr;
+		try {
+			lnr = new LineNumberReader(new FileReader(file));
+		} catch (FileNotFoundException fnfe) {
+	        System.out.println("problem creating reader");
+			return false;
+		}
+
+		String s;
+		boolean scriptComplete = false;
+		int numResults = 0;
+
+		try {
+			while ((s = lnr.readLine()) != null) {
+				if (s.startsWith("RESULT: ")) {
+					numResults++;
+					int index = s.indexOf("result=") + 7;
+					String result = s.substring(index, index + 4);
+					if (!result.equals("pass")) {
+						passed = false;
+						index = s.indexOf("id=") + 3;
+						int endIndex = s.indexOf(" ", index);
+						result = s.substring(s.indexOf("id=") + 3, endIndex);
+						System.out.println("test case " + result + " failed");
+					}
+				}
+				else if (s.startsWith("OK: Root-level SWF loaded"))
+				{
+				}
+				else if (s.startsWith("TestCase Start:"))
+				{
+				}
+				else if (s.startsWith("requesting url:"))
+				{
+				}
+				else if (s.startsWith("testComplete"))
+				{
+				}
+				else if (s.startsWith("ScriptComplete:"))
+				{
+					scriptComplete = true;
+				}
+				else if (s.startsWith("Created new test output instance"))
+				{
+				}
+				else if (s.startsWith("Send ScriptComplete"))
+				{
+				}
+				else if (s.startsWith("Paused for"))
+				{
+				}
+				else if (s.startsWith("Warning:"))
+				{
+				}
+				else if (s.startsWith("LengthOfTestcases:"))
+				{
+				}		
+				else if (s.startsWith("Created new test output"))
+				{
+				}		
+				else if (s.startsWith("Send ScriptComplete"))
+				{
+				}		
+				else if (s.startsWith("readPNG:requesting"))
+				{
+				}
+				else if (s.startsWith("runid.properties ERROR handler with: [IOErrorEvent"))
+				{
+				}
+				else if (s.startsWith("[IOErrorEvent type=\"ioError\"") && s.contains("localhost:9999/ScriptComplete"))
+				{
+				}
+				else if (s.trim().equals(""))
+				{
+				}
+				else
+				{
+					System.out.println("Unexpected Trace: " + s);
+					passed = false;
+				}
+			}
+		} catch (IOException e) {
+	        System.out.println("ioerror");
+		}
+
+		if (numResults == 0)
+		{
+	        System.out.println("No results.  Is trace output enabled?");
+			passed = false;
+		}
+		else if (!scriptComplete)
+		{
+	        System.out.println("Script did not complete");
+			passed = false;
+		}
+
+        return passed;
+    }
+}

Propchange: incubator/flex/trunk/mustella/MustellaResultsParser.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/flex/trunk/mustella/as3/src/mustella/AIR/CompareBitmap.as
URL: http://svn.apache.org/viewvc/incubator/flex/trunk/mustella/as3/src/mustella/AIR/CompareBitmap.as?rev=1333232&view=auto
==============================================================================
--- incubator/flex/trunk/mustella/as3/src/mustella/AIR/CompareBitmap.as (added)
+++ incubator/flex/trunk/mustella/as3/src/mustella/AIR/CompareBitmap.as Wed May  2 22:44:38 2012
@@ -0,0 +1,996 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.*;
+import flash.events.*;
+import flash.filesystem.*;
+import flash.net.*;
+import flash.text.*;
+import flash.utils.*;
+import flash.filesystem.*;
+import flash.geom.*;
+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);
+ *  stageText (optional)
+ *  maxColorVariance
+ *  numColorVariances
+ *  waitTarget Do Not Use
+ *  waitEvent Do Not Use
+ *
+ *  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;
+	
+	public static var DEFAULT_MAX_COLOR_VARIANCE:int = 0;
+	public static var DEFAULT_NUM_COLOR_VARIANCES:int = 0;
+
+	// 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;
+
+
+	/**
+	 *  If the user tells us it's a stageText, we'll try to grab the bitmapdata 
+	 *  via mx_internal call 
+	 */
+	public var stageText:Boolean
+
+	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 &lt;= 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;
+	}
+
+	/**
+	 *  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 writer:URLLoader;
+
+	private static var connection:LocalConnection;
+	private static var commandconnection:LocalConnection;
+	
+	private function statusHandler(event:Event):void
+	{
+	}
+
+	/**
+	 *  Constructor
+	 */
+	public function CompareBitmap() 
+	{ 
+		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");
+			}
+		}
+
+	}
+
+	// We override execute here.  In other TestSteps, we override doStep().
+	override public function execute(root:DisplayObject, context:UnitTester, testCase:TestCase, testResult:TestResult):Boolean
+	{
+		var cv:ConditionalValue = null;
+		var configID:String = null;
+		
+		if( conditionalValues ){			
+			// Use MultiResult to determine the proper URL.
+			cv = new MultiResult().chooseCV(conditionalValues);
+			if(cv){
+				// Use thet cv's url if it is set; otherwise, stick with the CompareBitmap's url (directory).
+				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 ("Replacing $testID with " + UnitTester.currentTestID);
+			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;
+		}
+
+		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;
+				}
+			}
+
+			writePNG(actualTarget);
+			return false;
+		}
+		else
+		{
+			readPNG();
+			return false;
+		}
+
+	}
+
+	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;
+		}
+		return new Point(width, height);
+	}
+
+	// Given a displayObject, sets up the screenBits.
+	private function getScreenBits(target:DisplayObject):void{
+		try 
+		{
+			if (!stageText) {
+				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));
+			} else {
+
+				trace ("Using stagetext");
+				try { 
+					var tmpbm:BitmapData = target["textDisplay"]["captureBitmapData"]();
+					screenBits = new BitmapData(tmpbm.rect.width, tmpbm.rect.height, true, 0xFFFFFFFF);
+					screenBits.draw (tmpbm, new Matrix());
+
+				} catch (e:Error) {
+					trace ("Tried for StageText bitmap data, but it failed");
+					trace (e.getStackTrace());
+				}
+
+			}
+		}
+		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;
+	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;
+			}
+		}
+
+		if (!reader.content)
+		{
+			testResult.doFail ("baseline image not available");
+			return true;
+		}
+
+		getScreenBits(target);
+
+		try
+		{
+			baselineBits = new BitmapData(reader.content.width, reader.content.height);
+			baselineBits.draw(reader.content, new Matrix());
+
+			var compareVal:Object = baselineBits.compare (screenBits);
+
+			if (compareVal is BitmapData && numColorVariances) {
+				compareVal = compareWithVariances(compareVal as BitmapData)
+			}
+
+			if (compareVal != 0)
+			{
+				testResult.doFail ("compare returned" + compareVal, absolutePathResult(url) + ".bad.png");
+
+	
+				if (useRemoteDiffer)
+				{
+					sendImagesToDiffer();
+					return false;
+				} else if (fileSuffix != "") { 
+					writePNG (target);
+				}
+			}
+		} 
+		catch (e:Error) 
+		{ 
+			testResult.doFail (e.getStackTrace());	
+		}
+		return true;
+	}
+	
+	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))
+			stepComplete();
+	}
+
+	private function readErrorHandler(event:Event = null):void
+	{
+		var failString:String = "baseline image could not be read.";
+
+		failString += "  Creating image file as a .bad.png.";
+		var actualTarget:DisplayObject = DisplayObject(context.stringToObject(target));
+		getScreenBits(actualTarget);
+		writePNG(actualTarget);
+		testResult.doFail ( failString );
+		stepComplete();
+	}
+
+	/**
+	* Read a file and return a ByteArray that we can feed into reader (a Loader).
+	**/
+	public function loadFileBytes( file:File ):ByteArray{
+				
+		var fileStream:FileStream = new FileStream();
+		var file:File;
+		var ba:ByteArray = new ByteArray();
+		var bytesRead:int = 0;
+		var bytesAvail:int = 0;
+		
+		fileStream.open(file, FileMode.READ);
+		bytesAvail = fileStream.bytesAvailable;
+		
+		while( bytesAvail > 0 ){
+			fileStream.readBytes(ba, bytesRead, bytesAvail);
+			bytesAvail = fileStream.bytesAvailable;
+		}
+		
+		fileStream.close();
+
+		return ba;
+	}
+
+
+	public function readPNG():void
+	{
+		reader = new Loader();
+		reader.contentLoaderInfo.addEventListener(Event.COMPLETE, readCompleteHandler);
+		reader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, readErrorHandler);
+		reader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, readErrorHandler);
+		
+		var req:URLRequest = new URLRequest();
+		var ba:ByteArray = null;
+		var file:File;
+
+		// If iOS and AIR, let's try using file I/O instead of loader stuff. AIR on devices can be a pain with the url stuff.
+		if( UnitTester.isApollo && (UnitTester.cv.os.toLowerCase() == DeviceNames.IOS.toLowerCase()) ){
+			// Trim the leading ../ if we have it.
+			if ( url.indexOf ("../") == 0 ){
+				url = url.substring (3);
+			}
+		
+			file = File.documentsDirectory.resolvePath( url );
+			
+			if( !file.exists ){
+				readErrorHandler();
+				return;
+			}
+			
+			ba = loadFileBytes( file );
+			reader.loadBytes( ba );
+		}else{		
+			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);
+			// }
+		
+			trace ("readPNG:requesting url: " + req.url);			
+			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)
+		{
+			if (stageText == false) 
+			{
+				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));
+			} else {
+
+				trace ("stageText value: " + stageText);
+				try { 
+					bitmapData = target["textDisplay"]["captureBitmapData"]();
+					trace ("success asking StageText for bitmap data");
+				} catch (e:Error) {
+					trace ("Tried for StageText bitmap data, but it failed");
+					trace (e.getStackTrace());
+				}
+
+			}
+
+		} 
+		var png:MustellaPNGEncoder = new MustellaPNGEncoder();
+		var ba:ByteArray = png.encode (bitmapData);
+
+		return ba;
+	}
+
+
+	public function writePNG(target:DisplayObject):void 
+	{
+		var ba:ByteArray = getPngByteArray(target, screenBits);
+
+
+		if( UnitTester.createBitmapReferences ){
+			fileSuffix = "";
+		}
+
+		if( UnitTester.writeBaselinesToDisk ){
+			// context.testDir: mobile/components/Button/properties/
+			// url: ../properties/baselines/button_android_test1_CustomName.png
+			var writePath:String = createWritePath( context.testDir, url + fileSuffix );
+			var deviceWritePath:String = UnitTester.mustellaWriteLocation + "/" + writePath;
+//			trace("*******deviceWritePath = " + deviceWritePath); 
+			var hostWritePath:String = writePath;
+			var file:File = new File ( deviceWritePath );
+			var fileStream:FileStream = new FileStream();
+			var hostCommand:String;
+
+			// open() opens synchronously, so we don't have to (and can't) use listeners.
+			fileStream.open(file, FileMode.WRITE);
+			fileStream.writeBytes(ba);
+			fileStream.close();
+
+			// Tell the host machine to copy the baseline image.
+			// Also, give it a URL with test info. to use when sending it to flexqa01's baseline server.
+			if( UnitTester.cv.os.toLowerCase() == DeviceNames.ANDROID.toLowerCase() ||
+				UnitTester.cv.os.toLowerCase() == DeviceNames.IOS.toLowerCase() ||
+				UnitTester.cv.os.toLowerCase() == DeviceNames.QNX.toLowerCase() ){
+				hostCommand = "CopyDeviceFile: FROM=" + deviceWritePath + " TO=" + hostWritePath;
+				
+				// If this is about creating bitmaps, skip the upload, we're done
+				if ( !UnitTester.createBitmapReferences ){
+					hostCommand += " SCREENURL=" + (UnitTester.urlAssemble ("screen", context.testDir, context.scriptName, this.testResult.testID, UnitTester.run_id));
+					hostCommand += " BASELINEURL=" + (UnitTester.urlAssemble ("baseline", context.testDir, context.scriptName, this.testResult.testID, UnitTester.run_id));
+				}
+
+				// Trace statements are parsed by the host.
+				trace( hostCommand );
+			}
+
+			if (UnitTester.createBitmapReferences){
+				stepComplete();
+			}
+
+			return;
+		}else{
+			trace("AIR CompareBitmap is called, but we're not writing to disk.  This is wrong.");
+		}
+    }
+
+	private function adjustWriteURI(url:String):String
+	{
+		var base:String = null;
+		
+		// For iOS, do something different.
+		if( UnitTester.isApollo && (UnitTester.cv.os != null) && (UnitTester.cv.os.toLowerCase() == DeviceNames.IOS.toLowerCase()) ){
+			base = url;
+			
+			// Trim the leading ../ if we have it.
+			if ( base.indexOf ("../") == 0 ){
+				base = base.substring (3);
+			}
+			
+			base = File.documentsDirectory.resolvePath(base).nativePath;
+			
+			return base;
+		}else{
+			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);
+		}
+	}
+
+	/**
+	 * Called by writePNG when, for example, we're testing on Android.
+	 * firstPart:	mobile/components/Button/properties/
+	 * secondPart:	../properties/baselines/button_android_test1_CustomName.png
+	 **/
+	private function createWritePath( firstPart:String, secondPart:String ):String{
+		var ret:String = "tests/" + firstPart.substring( 0, firstPart.lastIndexOf( "/" ) );
+		
+		var removeMe:String = ret.substring( ret.lastIndexOf( "/" ), ret.length ); // "properties"
+		ret += secondPart.substring( secondPart.indexOf( removeMe ) + removeMe.length, secondPart.length );
+
+		trace("createWritePath returning " + ret);
+		return ret;
+	}
+
+	private var screenDone:Boolean = false;
+	private var baselineDone:Boolean = false;
+
+	private function writeCompleteHandler(event:Event):void
+	{
+		trace("baseline write successful " + event);
+		if (UnitTester.createBitmapReferences)
+			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
+	{
+		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)
+			stepComplete();
+
+
+	}
+
+	/**
+	 *  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 && (UnitTester.cv.os != null) && (UnitTester.cv.os.toLowerCase() == DeviceNames.IOS.toLowerCase()) ){
+			base = url;
+			
+			// Trim the leading ../ if we have it.
+			if ( base.indexOf ("../") == 0 ){
+				base = base.substring (3);
+			}
+			
+			base = File.documentsDirectory.resolvePath(base).nativePath;
+			
+		} else if( UnitTester.isApollo && (UnitTester.cv.os != null) && (UnitTester.cv.os.toLowerCase() == DeviceNames.ANDROID.toLowerCase()) ){
+
+			/// code doing what it does now: 
+				
+			var fPath:String = createWritePath( context.testDir, url + fileSuffix );
+
+			/// clean up 
+			if (fPath.indexOf ("tests/") == 0)
+				fPath = fPath.substring (5);
+
+			/// clean up 
+			/// it probably has the .bad.png suffix
+			if (fPath.indexOf (".bad.png") > 0)
+				fPath = fPath.substring (0, fPath.length-".bad.png".length);
+				
+			base = fPath;
+
+		}else{
+			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);
+				}
+
+				base += "/" + tmp;
+			}
+		}
+		
+		return base;
+	}
+
+	
+	private function absolutePath(url:String):String
+	{
+		var swf:String = normalizeURL(root.loaderInfo.url);
+
+		var pos:int = swf.indexOf("file:///");
+		if (pos != 0)
+		{
+			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"));
+		stepComplete();
+	}
+
+	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 allowed:int = numColorVariances * UnitTester.pixelToleranceMultiplier;
+		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)
+						{
+							return bm;
+						}
+					}
+					allowed--;
+					if (allowed < 0)
+					{
+						return bm;
+					}
+				}
+			}
+		}
+		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;
+	}
+
+	override protected function stepComplete():void 
+	{ 
+
+                if (baselineBits != null)
+                        baselineBits.dispose();
+                if (screenBits != null)
+                        screenBits.dispose();
+
+
+		reader=null;
+		writer=null;
+		
+		super.stepComplete();
+
+
+	}
+}
+
+}

Propchange: incubator/flex/trunk/mustella/as3/src/mustella/AIR/CompareBitmap.as
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/flex/trunk/mustella/as3/src/mustella/ApolloFilePath.as
URL: http://svn.apache.org/viewvc/incubator/flex/trunk/mustella/as3/src/mustella/ApolloFilePath.as?rev=1333232&view=auto
==============================================================================
--- incubator/flex/trunk/mustella/as3/src/mustella/ApolloFilePath.as (added)
+++ incubator/flex/trunk/mustella/as3/src/mustella/ApolloFilePath.as Wed May  2 22:44:38 2012
@@ -0,0 +1,129 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.utils.*;
+import flash.net.*;
+import flash.events.*;
+import flash.display.*;
+import flash.desktop.NativeApplication;
+import flash.geom.Matrix;
+import flash.geom.Point;
+import flash.filesystem.File;
+
+[Mixin]
+/**
+ * Apollo doesn't return anything useable from the loaderInfo.url: 
+ * it looks like this: app-context://my.swf
+ * The received url in a test, which is looks like "../Properties/baselines/my.png"
+ * won't load. Apparently, the "../" is offensive. To get the fully qualified path, 
+ * we need the Apollo File class.  That's what this Mixin supplies.
+ * Also, Apollo like soft exits, and won't re-launch after a kill (java's destroy process). 
+ * so exit by calling the window's close method. 
+ */
+public class ApolloFilePath 
+{ 
+
+	public static var _root:DisplayObject;
+
+	public static function init(root:DisplayObject):void
+	{
+		UnitTester.isApollo = true;
+		CompareBitmap.adjustPath = apolloAdjust;
+		
+		/// the exit method has to be gentler for apollo, too
+		UnitTester.exitWhenDone = true;
+		UnitTester.exit = apolloExit;
+		_root=root;
+
+	}
+
+	
+	/**
+	 * gets the url from CompareBitmap; 
+	 * creates fully qualified path using flash File class. 
+	 */
+	public static function apolloAdjust(url:String):String
+	{
+
+		var swf:String = _root.loaderInfo.url;
+		var f:File = new File (swf);
+		// clean it up: 
+		var myPattern:RegExp = /\\/g;
+		var path:String;
+		
+		if( UnitTester.cv.os == DeviceNames.ANDROID ){
+			// AIR for Android returns empty string for nativePath (on purpose).  Use url instead.
+			// See https://zerowing.corp.adobe.com/display/airlinux/Resource+Mapping.
+			path = f.url;
+		}else{
+			path = f.nativePath;
+			path = path.replace (":", "|");
+		}
+
+		path = path.replace (myPattern, "/");			
+
+		// yank off the swfs directory, which we're in
+		path = path.substr (0, path.lastIndexOf ("/")-1);
+		path = path.substr (0, path.lastIndexOf ("/"));
+
+		if (url.indexOf ("../")==0)
+			url = url.substring (2);
+
+		if (url.indexOf ("/..")==0)
+		{
+			url = url.substring (3);
+			path = path.substr (0, path.lastIndexOf ("/"));
+		}
+
+		/// create the final url
+		path = path + url;
+
+		if( UnitTester.cv.os == DeviceNames.ANDROID ){
+			// AIR for Android needs it to start with app:/, so just return at this point.
+			return path;
+		}else{
+			return "file:///" + path;		
+		}
+	}
+
+	/**
+	 * call the native window close method
+	 */
+	public static function apolloExit(): void 
+	{ 
+		/// hack around an issue that apollo seems to hang when it exits
+		/// with a socket still open. Arbitrary sleep isn't attractive
+		/// but we never received a response from Runner after sending 
+		/// ScriptDone
+		setTimeout (real_apolloExit, 1500);
+	}
+
+
+	public static function real_apolloExit(): void 
+	{ 
+
+		// Call the more general exit
+		trace ("Doing an apollo exit");
+		NativeApplication.nativeApplication.exit(1);
+	}
+}
+
+}

Propchange: incubator/flex/trunk/mustella/as3/src/mustella/ApolloFilePath.as
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/flex/trunk/mustella/as3/src/mustella/Assert.as
URL: http://svn.apache.org/viewvc/incubator/flex/trunk/mustella/as3/src/mustella/Assert.as?rev=1333232&view=auto
==============================================================================
--- incubator/flex/trunk/mustella/as3/src/mustella/Assert.as (added)
+++ incubator/flex/trunk/mustella/as3/src/mustella/Assert.as Wed May  2 22:44:38 2012
@@ -0,0 +1,170 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.events.Event;
+import flash.events.EventDispatcher;
+import flash.events.IEventDispatcher;
+import flash.utils.getTimer;
+
+import mx.utils.ObjectUtil;
+
+/**
+ *  The base class for all Asserts that the test
+ *  has succeeded or not.
+ *  All asserts should be derived from this class because
+ *  the timing of the wait events is different than that for
+ *  other TestSteps.  See AssertPropertyValue for an example.
+ *
+ *  Asserts don't execute their steps until after the
+ *  waitEvent has been received (if there is one) whereas
+ *  non-Asserts execute their steps and then wait for the
+ *  waitEvent.
+ */
+public class Assert extends TestStep
+{
+	// list of properties we don't examine in determining equivalence
+	private static var excludeList:Array = [
+						"stage", 
+						"systemManager", 
+						"parent", 
+						"owner", 
+						"target", 
+						"currentTarget"
+			];
+	 
+	/**
+	 *  Called by the test case in case you need to set up before execute()
+	 */
+	public function preview(root:DisplayObject, context:UnitTester, testCase:TestCase, testResult:TestResult):void
+	{
+		this.root = root;
+		this.context = context;
+		this.testCase = testCase;
+		this.testResult = testResult;
+
+		if (waitEvent)
+		{
+			if (waitTarget == null)
+				waitTarget = target;
+			var actualTarget:Object = context.stringToObject(waitTarget);
+			// it is ok for us to not have an actualTarget during preview
+			// someone may be waiting for the object to be created.
+			if (actualTarget)
+				actualTarget.addEventListener(waitEvent, eventListener);
+		}
+	}
+
+	/**
+	 *  All subclasses should override this method
+	 */
+	override public function execute(root:DisplayObject, context:UnitTester, testCase:TestCase, testResult:TestResult):Boolean
+	{
+		this.root = root;
+		this.context = context;
+		this.testCase = testCase;
+		this.testResult = testResult;
+
+		if (waitEvent)
+		{
+			if (waitTarget == null)
+				waitTarget = target;
+
+			var actualTarget:IEventDispatcher = context.stringToObject(waitTarget) as IEventDispatcher;
+			if (!actualTarget)
+			{
+				testResult.doFail("waitTarget " + waitTarget + " not found");
+				return true;
+			}
+			actualTarget.removeEventListener(waitEvent, eventListener);
+			if (numEvents == 0)
+			{
+				actualTarget.addEventListener(waitEvent, waitEventHandler);
+				testCase.setExpirationTime(getTimer() + timeout);
+				return false;
+			}
+		}
+
+		doStep();
+		return true;
+	}
+
+	/**
+	 *  Storage for numEvents
+	 */
+	private var numEvents:int = 0;
+
+	/**
+	 *  The name of the object to test.
+	 */
+	public var target:String;
+
+	/**
+	 *  The method that gets called back when the event we're waiting on fires
+	 */
+	override protected function waitEventHandler(event:Event):void
+	{
+		doStep();
+		super.waitEventHandler(event);
+	}
+
+	/**
+	 *	The event listener
+	 */
+	private function eventListener(event:Event):void
+	{
+		testCase.setExpirationTime(0);
+
+		numEvents++;
+	}
+
+	/**
+	 *  Called by the test case in case you need to clean up after execute()
+	 */
+	public function cleanup():void
+	{
+	}
+
+	/**
+	 *  convert everything to strings (like null)
+	 */
+	protected function valueToString(value:*):String
+	{
+		if (value == null)
+			return "null";
+		var s:String;
+		
+		if (value is Number)
+		{
+			if ((value is int) || (value is uint))
+				s = value.toString();
+			else
+				s = value.toFixed(6);
+		}
+		else
+			s = value.toString();
+
+		if (s == "[object Object]")
+			s = ObjectUtil.toString(value, null, excludeList);
+		return s;
+	}
+}
+
+}

Propchange: incubator/flex/trunk/mustella/as3/src/mustella/Assert.as
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/flex/trunk/mustella/as3/src/mustella/AssertError.as
URL: http://svn.apache.org/viewvc/incubator/flex/trunk/mustella/as3/src/mustella/AssertError.as?rev=1333232&view=auto
==============================================================================
--- incubator/flex/trunk/mustella/as3/src/mustella/AssertError.as (added)
+++ incubator/flex/trunk/mustella/as3/src/mustella/AssertError.as Wed May  2 22:44:38 2012
@@ -0,0 +1,86 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 mx.core.mx_internal;
+use namespace mx_internal;
+
+/**
+ *  Instead of a property, we use an event so the MXML
+ *  compiler will wrap the code in a function for us
+ */
+[Event(name="valueExpression", type="flash.events.Event")]
+
+/**
+ *  Tests that the value of a property is as expected
+ *  MXML attributes:
+ *  value
+ *  waitTarget (optional)
+ *  waitEvent (optional)
+ *  timeout (optional)
+ */
+public class AssertError extends Assert
+{
+	/**
+	 *  See if the property has the correct value
+	 */
+	override protected function doStep():void
+	{
+		if (hasEventListener("valueExpression"))
+		{
+			context.resetValue();
+			try
+			{
+				dispatchEvent(new RunCodeEvent("valueExpression", root["document"], context, testCase, testResult));
+			}
+			catch (e1:Error)
+			{
+				TestOutput.logResult("Exception thrown evaluating value expression.");
+				testResult.doFail (e1.getStackTrace());	
+				return;
+			}
+			value = context.value;
+			if (!context.valueChanged)
+				TestOutput.logResult("WARNING: value was not set by valueExpression.  'value=' missing from expression?");
+		}
+
+		if (valueToString(testCase.lastError) != valueToString(value))
+		{
+			testResult.doFail ( "Expected Error " + valueToString(value) + ", got " + valueToString(testCase.lastError));
+		} 
+	}
+
+	/**
+	 *  The value the property should have
+	 */
+	public var value:Object;
+
+	/**
+	 *  customize string representation
+	 */
+	override public function toString():String
+	{
+		var s:String = "AssertError";
+		return s;
+	}
+}
+
+}

Propchange: incubator/flex/trunk/mustella/as3/src/mustella/AssertError.as
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/flex/trunk/mustella/as3/src/mustella/AssertEvent.as
URL: http://svn.apache.org/viewvc/incubator/flex/trunk/mustella/as3/src/mustella/AssertEvent.as?rev=1333232&view=auto
==============================================================================
--- incubator/flex/trunk/mustella/as3/src/mustella/AssertEvent.as (added)
+++ incubator/flex/trunk/mustella/as3/src/mustella/AssertEvent.as Wed May  2 22:44:38 2012
@@ -0,0 +1,219 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.display.IBitmapDrawable;
+import flash.utils.*;
+import flash.net.*;
+import flash.events.*;
+import flash.display.*;
+import flash.geom.Matrix;
+
+/**
+ *  Tests that the value of a property is as expected
+ *  MXML attributes:
+ *  target
+ *  eventName
+ *  eventType
+ *  waitTarget (optional)
+ *  waitEvent (optional)
+ *  timeout (optional)
+ */
+public class AssertEvent extends Assert
+{
+
+	private var eventListenerListening:Boolean = false;
+
+	/**
+	 *  Test the value of a property, log result if failure.
+	 */
+	override public function preview(root:DisplayObject, context:UnitTester, testCase:TestCase, testResult:TestResult):void
+	{
+		this.root = root;
+		this.context = context;
+		this.testCase = testCase;
+		this.testResult = testResult;
+
+		var actualTarget:Object = context.stringToObject(target);
+		if (actualTarget)
+		{
+			actualTarget.addEventListener(eventName, eventListener);
+			eventListenerListening = true;
+			testCase.cleanupAsserts.push(this);
+		}
+		// we don't fail during preview, we will fail later anyway
+	}
+
+	/**
+	 *  Test the value of a property, log result if failure.
+	 */
+	override public function execute(root:DisplayObject, context:UnitTester, testCase:TestCase, testResult:TestResult):Boolean
+	{
+		this.root = root;
+		this.context = context;
+		this.testCase = testCase;
+		this.testResult = testResult;
+
+		if (numEvents == 1 && (numExpectedEvents == 1 || numExpectedEvents == -1))
+		{
+			doStep();
+			return true;
+		}
+
+		if ((numEvents < numExpectedEvents) || (numEvents == 0 && numExpectedEvents == -1))
+		{
+			var actualTarget:IEventDispatcher = context.stringToObject(target) as IEventDispatcher;
+			if (!actualTarget)
+			{
+				testResult.doFail("target " + target + " not found");
+				return true;
+			}
+			// if eventListener is not hooked up, make sure it is
+			if (!eventListenerListening)
+			{
+				actualTarget.addEventListener(eventName, eventListener);
+				eventListenerListening = true;
+				testCase.cleanupAsserts.push(this);
+			}
+			// don't remove eventListener because we still want to check for extra events
+			// but add this in so we can wait until we get the required number of events
+			actualTarget.addEventListener(eventName, waitEventHandler);
+			testCase.setExpirationTime(getTimer() + timeout);
+			waitEvent = eventName;
+			waitTarget = target;
+			return false;
+		}
+
+		return super.execute(root, context, testCase, testResult);
+	}
+
+	/**
+	 *  Test the value of a property, log result if failure.
+	 */
+	override protected function doStep():void
+	{
+		var actualTarget:Object = context.stringToObject(target);
+		if (!actualTarget)
+		{
+			testResult.doFail("Target " + target + " not found");
+			return;
+		}
+
+		context.lastEvent = lastEvent;
+
+		if (numExpectedEvents != -1 && numEvents != numExpectedEvents)
+		{
+			testResult.doFail("Event " + eventName + " received " + numEvents + " times");
+			return;
+		}
+
+		if (getQualifiedClassName(lastEvent).indexOf(eventClass) == -1)
+			testResult.doFail("Event " + eventName + " of class " + getQualifiedClassName(lastEvent));
+	}
+
+	/**
+	 *  The name of the event to watch for
+	 */
+	public var eventName:String;
+
+	/**
+	 *  The class of the event, e.g. mx.events.DataGridEvent
+	 */
+	public var eventClass:String;
+
+	/**
+	 *  Storage for numEvents
+	 */
+	protected var numEvents:int = 0;
+
+	/**
+	 *  Number of expected events (must be > 0), use AssertNoEvent for 0.
+	 *  Set to -1 if you want to see at least one event and don't care if there's more.
+	 */
+	public var numExpectedEvents:int = 1;
+
+	/**
+	 *  The event object
+	 */
+	private var lastEvent:Event;
+
+	/**
+	 *	The event listener
+	 */
+	protected function eventListener(event:Event):void
+	{
+		testCase.setExpirationTime(0);
+
+		lastEvent = event;
+		numEvents++;
+
+		if (numExpectedEvents != -1 && numEvents > numExpectedEvents)
+		{
+			testResult.doFail ("Event " + eventName + " received " + numEvents + " times");	
+			return;
+		}
+	}
+
+	/**
+	 *  Test the value of a property, log result if failure.
+	 */
+	override public function cleanup():void
+	{
+		var actualTarget:Object = context.stringToObject(target);
+		if (actualTarget)	// might be null if object was killed
+			actualTarget.removeEventListener(eventName, eventListener);
+	}
+
+	/**
+	 *  customize string representation
+	 */
+	override public function toString():String
+	{
+		var s:String = "AssertEvent";
+		if (target)
+			s += ": target = " + target;
+		if (eventName)
+			s += ", eventName = " + eventName;
+		return s;
+	}
+
+	/**
+	 *  The method that gets called back when the event we're waiting on fires
+	 */
+	override protected function waitEventHandler(event:Event):void
+	{
+		// we can rely on eventListener to update lastEvent and numEvents
+
+		// keep waiting if there aren't enough events
+		if (numExpectedEvents != -1 && numEvents < numExpectedEvents)
+		{
+			testCase.setExpirationTime(getTimer() + timeout);
+			return;
+		}
+
+		// finish up
+		waitEvent = eventName;
+		waitTarget = target;
+		super.waitEventHandler(event);
+
+	}
+}
+
+}

Propchange: incubator/flex/trunk/mustella/as3/src/mustella/AssertEvent.as
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/flex/trunk/mustella/as3/src/mustella/AssertEventPropertyValue.as
URL: http://svn.apache.org/viewvc/incubator/flex/trunk/mustella/as3/src/mustella/AssertEventPropertyValue.as?rev=1333232&view=auto
==============================================================================
--- incubator/flex/trunk/mustella/as3/src/mustella/AssertEventPropertyValue.as (added)
+++ incubator/flex/trunk/mustella/as3/src/mustella/AssertEventPropertyValue.as Wed May  2 22:44:38 2012
@@ -0,0 +1,112 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.utils.*;
+
+import mx.core.mx_internal;
+use namespace mx_internal;
+
+/**
+ *  Instead of a property, we use an event so the MXML
+ *  compiler will wrap the code in a function for us
+ */
+[Event(name="valueExpression", type="flash.events.Event")]
+
+
+/**
+ *  Tests that the value of a property is as expected
+ *  MXML attributes:
+ *  target (ignored)
+ *  propertyName
+ *  value
+ *  waitTarget (optional)
+ *  waitEvent (optional)
+ *  timeout (optional)
+ */
+public class AssertEventPropertyValue extends Assert
+{
+	/**
+	 *  See if the property has the correct value
+	 */
+	override protected function doStep():void
+	{
+		if (hasEventListener("valueExpression"))
+		{
+			context.resetValue();
+			try
+			{
+				dispatchEvent(new RunCodeEvent("valueExpression", root["document"], context, testCase, testResult));
+			}
+			catch (e1:Error)
+			{
+				TestOutput.logResult("Exception thrown evaluating value expression.");
+				testResult.doFail (e1.getStackTrace());	
+				return;
+			}
+			value = context.value;
+			if (!context.valueChanged)
+				TestOutput.logResult("WARNING: value was not set by valueExpression.  'value=' missing from expression?");
+		}
+
+		var val:Object;
+		if (!context.lastEvent)
+		{
+			testResult.doFail ("No event fired prior to this step");
+			return;
+		}
+		if (!(propertyName in context.lastEvent))
+		{
+			testResult.doFail ("Event does not have property " + propertyName);
+			return;
+		}
+		val = context.lastEvent[propertyName];
+
+		if (valueToString(val) != valueToString(value))
+		{
+			testResult.doFail ( getQualifiedClassName(context.lastEvent) + "." + propertyName + " " + valueToString(val)  + " != " + valueToString(value));
+		} 
+	}
+
+	/**
+	 *  The name of the property to test
+	 */
+	public var propertyName:String;
+
+	/**
+	 *  The value the property should have
+	 */
+	public var value:Object;
+
+	/**
+	 *  customize string representation
+	 */
+	override public function toString():String
+	{
+		var s:String = "AssertEventPropertyValue";
+		if (target)
+			s += ": target = " + target;
+		if (propertyName)
+			s += ", propertyName = " + propertyName;
+		return s;
+	}
+}
+
+}

Propchange: incubator/flex/trunk/mustella/as3/src/mustella/AssertEventPropertyValue.as
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/flex/trunk/mustella/as3/src/mustella/AssertMethodValue.as
URL: http://svn.apache.org/viewvc/incubator/flex/trunk/mustella/as3/src/mustella/AssertMethodValue.as?rev=1333232&view=auto
==============================================================================
--- incubator/flex/trunk/mustella/as3/src/mustella/AssertMethodValue.as (added)
+++ incubator/flex/trunk/mustella/as3/src/mustella/AssertMethodValue.as Wed May  2 22:44:38 2012
@@ -0,0 +1,139 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.display.IBitmapDrawable;
+import flash.events.EventDispatcher;
+import flash.utils.*;
+import flash.net.*;
+import flash.events.*;
+import flash.display.*;
+import flash.geom.Matrix;
+
+import mx.core.mx_internal;
+use namespace mx_internal;
+
+/**
+ *  Instead of a property, we use an event so the MXML
+ *  compiler will wrap the code in a function for us
+ */
+[Event(name="method", type="flash.events.Event")]
+
+/**
+ *  Instead of a property, we use an event so the MXML
+ *  compiler will wrap the code in a function for us
+ */
+[Event(name="valueExpression", type="flash.events.Event")]
+
+/**
+*  Vector of conditionalValue objects.
+**/
+[DefaultProperty("conditionalValues")]
+
+/**
+ *  Tests that the value of a property is as expected
+ *  MXML attributes:
+ *  target (not used)
+ *  method
+ *  value
+ *  waitTarget (optional)
+ *  waitEvent (optional)
+ *  timeout (optional)
+ */
+public class AssertMethodValue extends Assert
+{
+	public var conditionalValues:Vector.<ConditionalValue> = null;
+	
+	/**
+	 *  Test the value of a property, log result if failure.
+	 */
+	override protected function doStep():void
+	{
+		var cv:ConditionalValue = null;
+		var dispatcher:EventDispatcher = this;
+		
+		context.resetValue();
+		
+		// Use MultiResult to determine the proper value (or valueExpression, below).
+		if(conditionalValues){
+			cv = new MultiResult().chooseCV(conditionalValues);
+			if(cv){
+				value = cv.value;
+				dispatcher = cv;
+			}
+		}
+
+		// Execute the method.
+		try 
+		{
+			dispatchEvent(new RunCodeEvent("method", root["document"], context, testCase, testResult));				
+		}
+		catch (e:Error)
+		{
+			TestOutput.logResult("Exception thrown executing method.");
+			testResult.doFail (e.getStackTrace());
+			return;
+		}
+		if (!context.valueChanged)
+			TestOutput.logResult("WARNING: value was not set by method.  'value=' missing from expression?");
+		var methodValue:Object = context.value;
+
+		// Execute the valueExpression.
+		if (dispatcher.hasEventListener("valueExpression"))
+		{
+			context.resetValue();
+			try
+			{
+				dispatcher.dispatchEvent(new RunCodeEvent("valueExpression", root["document"], context, testCase, testResult));
+			}
+			catch (e1:Error)
+			{
+				TestOutput.logResult("Exception thrown evaluating value expression.");
+				testResult.doFail (e1.getStackTrace());	
+				return;
+			}
+			value = context.value;
+			if (!context.valueChanged)
+				TestOutput.logResult("WARNING: value was not set by valueExpression.  'value=' missing from expression?");
+		}
+
+		if (valueToString(methodValue) != valueToString(value))
+		{
+			testResult.doFail ( "method returned " + valueToString(methodValue) + ", expected " + valueToString(value));
+		} 
+	}
+
+	/**
+	 *  The value the method should return
+	 */
+	public var value:Object;
+
+	/**
+	 *  customize string representation
+	 */
+	override public function toString():String
+	{
+		var s:String = "AssertMethodValue (method cannot be shown) ";
+		return s;
+	}
+
+}
+
+}

Propchange: incubator/flex/trunk/mustella/as3/src/mustella/AssertMethodValue.as
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/flex/trunk/mustella/as3/src/mustella/AssertNoEvent.as
URL: http://svn.apache.org/viewvc/incubator/flex/trunk/mustella/as3/src/mustella/AssertNoEvent.as?rev=1333232&view=auto
==============================================================================
--- incubator/flex/trunk/mustella/as3/src/mustella/AssertNoEvent.as (added)
+++ incubator/flex/trunk/mustella/as3/src/mustella/AssertNoEvent.as Wed May  2 22:44:38 2012
@@ -0,0 +1,80 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.display.IBitmapDrawable;
+import flash.utils.*;
+import flash.net.*;
+import flash.events.*;
+import flash.display.*;
+import flash.geom.Matrix;
+
+/**
+ *  Tests that the value of a property is as expected
+ *  MXML attributes:
+ *  target
+ *  eventName
+ *  eventType
+ *  waitTarget (optional)
+ *  waitEvent (optional)
+ *  timeout (optional)
+ */
+public class AssertNoEvent extends AssertEvent
+{
+	/**
+	 *  Test the value of a property, log result if failure.
+	 */
+	override public function execute(root:DisplayObject, context:UnitTester, testCase:TestCase, testResult:TestResult):Boolean
+	{
+		return true;
+	}
+
+	/**
+	 *	The event listener
+	 */
+	override protected function eventListener(event:Event):void
+	{
+		testCase.setExpirationTime(0);
+
+		numEvents++;
+
+		if (numEvents)
+		{
+			testResult.doFail ("Event " + eventName + " unexpectedly received " + numEvents + " times");	
+			return;
+		}
+	}
+
+	/**
+	 *  customize string representation
+	 */
+	override public function toString():String
+	{
+		var s:String = "AssertNoEvent";
+		if (target)
+			s += ": target = " + target;
+		if (eventName)
+			s += ", eventName = " + eventName;
+		return s;
+	}
+
+}
+
+}

Propchange: incubator/flex/trunk/mustella/as3/src/mustella/AssertNoEvent.as
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/flex/trunk/mustella/as3/src/mustella/AssertPixelValue.as
URL: http://svn.apache.org/viewvc/incubator/flex/trunk/mustella/as3/src/mustella/AssertPixelValue.as?rev=1333232&view=auto
==============================================================================
--- incubator/flex/trunk/mustella/as3/src/mustella/AssertPixelValue.as (added)
+++ incubator/flex/trunk/mustella/as3/src/mustella/AssertPixelValue.as Wed May  2 22:44:38 2012
@@ -0,0 +1,150 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.display.IBitmapDrawable;
+import flash.events.EventDispatcher;
+import flash.utils.*;
+import flash.net.*;
+import flash.events.*;
+import flash.display.*;
+import flash.geom.Matrix;
+import flash.geom.Point;
+
+import mx.core.mx_internal;
+use namespace mx_internal;
+
+/**
+*  Vector of conditionalValue objects.
+**/
+[DefaultProperty("conditionalValues")]
+
+/**
+ *  Instead of a property, we use an event so the MXML
+ *  compiler will wrap the code in a function for us
+ */
+[Event(name="valueExpression", type="flash.events.Event")]
+
+/**
+ *  Tests that the value of a property is as expected
+ *  MXML attributes:
+ *  target
+ *  value
+ *  waitTarget (optional)
+ *  waitEvent (optional)
+ *  timeout (optional)
+ */
+public class AssertPixelValue extends Assert
+{
+	public var conditionalValues:Vector.<ConditionalValue> = null;
+
+    /**
+     *  Test the value of a pixel, log result if failure.
+     */
+    override protected function doStep():void
+    {
+		var cv:ConditionalValue = null;
+		var dispatcher:EventDispatcher = this;
+        var pt:Point = new Point(x, y);
+        var actualTarget:Object = context.stringToObject(target);
+        if (!actualTarget)
+        {
+            testResult.doFail("Target " + target + " not found");
+            return;
+        }
+
+		// Use MultiResult to determine the proper value (or valueExpression, below).
+		if(conditionalValues){
+			cv = new MultiResult().chooseCV(conditionalValues);
+			if(cv){
+				value = uint(cv.value);
+				dispatcher = cv;
+			}
+		}
+
+        var stagePt:Point = actualTarget.localToGlobal(new Point(0, 0));
+        var altPt:Point = actualTarget.localToGlobal(new Point(actualTarget.width, actualTarget.height));
+        stagePt.x = Math.min(stagePt.x, altPt.x);
+        stagePt.y = Math.min(stagePt.y, altPt.y);
+        var screenBits:BitmapData = new BitmapData(actualTarget.width, actualTarget.height);
+        try
+        {
+            screenBits.draw(root.stage, new Matrix(1, 0, 0, 1, -stagePt.x, -stagePt.y));
+        }
+        catch(se2:SecurityError)
+        {
+            screenBits.draw(root, new Matrix(1, 0, 0, 1, -stagePt.x, -stagePt.y));
+        }
+        
+		if (dispatcher.hasEventListener("valueExpression"))
+        {
+            context.resetValue();
+            try
+            {
+	           	dispatcher.dispatchEvent(new RunCodeEvent("valueExpression", root["document"], context, testCase, testResult));
+            }
+            catch (e1:Error)
+            {
+                TestOutput.logResult("Exception thrown evaluating value expression.");
+                testResult.doFail (e1.getStackTrace()); 
+                return;
+            }
+            value = uint(context.value);
+            if (!context.valueChanged)
+                TestOutput.logResult("WARNING: value was not set by valueExpression.  'value=' missing from expression?");
+        }
+
+        if (screenBits.getPixel(pt.x, pt.y) != value)
+        {
+            testResult.doFail ( target + " pixel at (" + x + "," + y + ") " + 
+                screenBits.getPixel(pt.x, pt.y).toString(16).toUpperCase() + " != 0x" + value.toString(16).toUpperCase());
+        } 
+    }
+
+    /**
+     *  The color value the property should have
+     */
+    public var value:uint;
+
+    /**
+     *  The x offset into the component
+     */
+    public var x:Number;
+
+    /**
+     *  The y offset into the component
+     */
+    public var y:Number;
+
+    /**
+     *  customize string representation
+     */
+    override public function toString():String
+    {
+        var s:String = "AssertPixelValue";
+        if (target)
+            s += ": target = " + target;
+        s += ", x = " + x;
+        s += ", y = " + y;
+        return s;
+    }
+}
+
+}

Propchange: incubator/flex/trunk/mustella/as3/src/mustella/AssertPixelValue.as
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/flex/trunk/mustella/as3/src/mustella/AssertPropertyValue.as
URL: http://svn.apache.org/viewvc/incubator/flex/trunk/mustella/as3/src/mustella/AssertPropertyValue.as?rev=1333232&view=auto
==============================================================================
--- incubator/flex/trunk/mustella/as3/src/mustella/AssertPropertyValue.as (added)
+++ incubator/flex/trunk/mustella/as3/src/mustella/AssertPropertyValue.as Wed May  2 22:44:38 2012
@@ -0,0 +1,134 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.events.EventDispatcher;
+
+import mx.core.mx_internal;
+use namespace mx_internal;
+
+/**
+*  Vector of conditionalValue objects.
+**/
+[DefaultProperty("conditionalValues")]
+
+/**
+ *  Instead of a property, we use an event so the MXML
+ *  compiler will wrap the code in a function for us
+ */
+[Event(name="valueExpression", type="flash.events.Event")]
+
+/**
+ *  Tests that the value of a property is as expected
+ *  MXML attributes:
+ *  target
+ *  propertyName
+ *  value
+ *  waitTarget (optional)
+ *  waitEvent (optional)
+ *  timeout (optional)
+ */
+public class AssertPropertyValue extends Assert
+{
+	public var conditionalValues:Vector.<ConditionalValue> = null;
+	
+	/**
+	 *  See if the property has the correct value
+	 */
+	override protected function doStep():void
+	{
+		var actualTarget:Object = context.stringToObject(target);
+		var multiResultResult:String = "";
+		var cv:ConditionalValue = null;
+		var dispatcher:EventDispatcher = this;
+		
+		if (!actualTarget)
+		{
+			testResult.doFail("Target " + target + " not found");
+			return;
+		}
+
+		if (!(propertyName in actualTarget))
+		{
+			testResult.doFail ( target + "." + propertyName + " does not exist");
+			return;
+		}
+
+		// Use MultiResult to determine the proper value (or valueExpression, below).
+		if(conditionalValues){
+			cv = new MultiResult().chooseCV(conditionalValues);
+			if(cv){
+				value = cv.value;
+				dispatcher = cv;
+			}
+		}
+
+		if (dispatcher.hasEventListener("valueExpression"))
+		{
+			context.resetValue();
+			try
+			{
+				dispatcher.dispatchEvent(new RunCodeEvent("valueExpression", root["document"], context, testCase, testResult));
+			}
+			catch (e1:Error)
+			{
+				TestOutput.logResult("Exception thrown evaluating value expression.");
+				testResult.doFail (e1.getStackTrace());	
+				return;
+			}
+			
+			value = context.value;
+			
+			if (!context.valueChanged)
+				TestOutput.logResult("WARNING: value was not set by valueExpression.  'value=' missing from expression?");
+
+		}
+
+		if (valueToString(actualTarget[propertyName]) != valueToString(value))
+		{
+			testResult.doFail ( target + "." + propertyName + " " + valueToString(actualTarget[propertyName]) + " != " + valueToString(value));
+		}
+	}
+
+	/**
+	 *  The name of the property to test
+	 */
+	public var propertyName:String;
+
+	/**
+	 *  The value the property should have
+	 */
+	public var value:Object;
+
+	/**
+	 *  customize string representation
+	 */
+	override public function toString():String
+	{
+		var s:String = "AssertPropertyValue";
+		if (target)
+			s += ": target = " + target;
+		if (propertyName)
+			s += ", propertyName = " + propertyName;
+		return s;
+	}
+}
+
+}

Propchange: incubator/flex/trunk/mustella/as3/src/mustella/AssertPropertyValue.as
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/flex/trunk/mustella/as3/src/mustella/AssertStyleValue.as
URL: http://svn.apache.org/viewvc/incubator/flex/trunk/mustella/as3/src/mustella/AssertStyleValue.as?rev=1333232&view=auto
==============================================================================
--- incubator/flex/trunk/mustella/as3/src/mustella/AssertStyleValue.as (added)
+++ incubator/flex/trunk/mustella/as3/src/mustella/AssertStyleValue.as Wed May  2 22:44:38 2012
@@ -0,0 +1,124 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.events.EventDispatcher;
+
+import mx.core.mx_internal;
+use namespace mx_internal;
+
+/**
+ *  Instead of a property, we use an event so the MXML
+ *  compiler will wrap the code in a function for us
+ */
+[Event(name="valueExpression", type="flash.events.Event")]
+
+/**
+*  Vector of conditionalValue objects.
+**/
+[DefaultProperty("conditionalValues")]
+
+/**
+ *  Tests that the value of a property is as expected
+ *  MXML attributes:
+ *  target
+ *  styleName
+ *  value
+ *  waitTarget (optional)
+ *  waitEvent (optional)
+ *  timeout (optional)
+ */
+public class AssertStyleValue extends Assert
+{
+	public var conditionalValues:Vector.<ConditionalValue> = null;
+
+	/**
+	 *  Test the value of a property, log result if failure.
+	 */
+	override protected function doStep():void
+	{
+		var cv:ConditionalValue = null;
+		var dispatcher:EventDispatcher = this;
+		var actualTarget:Object = context.stringToObject(target);
+		
+		if (!actualTarget)
+		{
+			testResult.doFail("Target " + target + " not found");
+			return;
+		}
+
+		// Use MultiResult to determine the proper value (or valueExpression, below).
+		if(conditionalValues){
+			cv = new MultiResult().chooseCV(conditionalValues);
+			if(cv){
+				value = cv.value;
+				dispatcher = cv;
+			}
+		}
+
+		if (dispatcher.hasEventListener("valueExpression"))
+		{
+			context.resetValue();
+			try
+			{
+				dispatcher.dispatchEvent(new RunCodeEvent("valueExpression", root["document"], context, testCase, testResult));
+			}
+			catch (e1:Error)
+			{
+				TestOutput.logResult("Exception thrown evaluating value expression.");
+				testResult.doFail (e1.getStackTrace());	
+				return;
+			}
+			value = context.value;
+			if (!context.valueChanged)
+				TestOutput.logResult("WARNING: value was not set by valueExpression.  'value=' missing from expression?");
+		}
+
+		if (valueToString(actualTarget.getStyle(styleName)) != valueToString(value))
+		{
+			testResult.doFail( target + "." + styleName + " " + valueToString(actualTarget.getStyle(styleName)) + " != " + valueToString(value));
+		} 
+	}
+
+	/**
+	 *  The name of the property to test
+	 */
+	public var styleName:String;
+
+	/**
+	 *  The value the property should have
+	 */
+	public var value:Object;
+
+	/**
+	 *  customize string representation
+	 */
+	override public function toString():String
+	{
+		var s:String = "AssertStyleValue";
+		if (target)
+			s += ": target = " + target;
+		if (styleName)
+			s += ", styleName = " + styleName;
+		return s;
+	}
+}
+
+}

Propchange: incubator/flex/trunk/mustella/as3/src/mustella/AssertStyleValue.as
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/flex/trunk/mustella/as3/src/mustella/AssertTitle.as
URL: http://svn.apache.org/viewvc/incubator/flex/trunk/mustella/as3/src/mustella/AssertTitle.as?rev=1333232&view=auto
==============================================================================
--- incubator/flex/trunk/mustella/as3/src/mustella/AssertTitle.as (added)
+++ incubator/flex/trunk/mustella/as3/src/mustella/AssertTitle.as Wed May  2 22:44:38 2012
@@ -0,0 +1,70 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.external.ExternalInterface;
+
+import mx.core.mx_internal;
+use namespace mx_internal;
+
+/**
+ *  Instead of a property, we use an event so the MXML
+ *  compiler will wrap the code in a function for us
+ */
+[Event(name="valueExpression", type="flash.events.Event")]
+
+/**
+ *  Tests that the value of a property is as expected
+ *  MXML attributes:
+ *  title
+ *  waitTarget (optional)
+ *  waitEvent (optional)
+ *  timeout (optional)
+ */
+public class AssertTitle extends Assert
+{
+	/**
+	 *  See if the property has the correct value
+	 */
+	override protected function doStep():void
+	{
+		var actualTitle:String = ExternalInterface.call("BrowserHistory.getTitle");
+		if (valueToString(actualTitle) != valueToString(title))
+		{
+			testResult.doFail ( "Expected " + valueToString(title) + ", got " + valueToString(actualTitle));
+		} 
+	}
+
+	/**
+	 *  The value the url should have
+	 */
+	public var title:String;
+
+	/**
+	 *  customize string representation
+	 */
+	override public function toString():String
+	{
+		var s:String = "AssertTitle";
+		return s;
+	}
+}
+
+}

Propchange: incubator/flex/trunk/mustella/as3/src/mustella/AssertTitle.as
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/flex/trunk/mustella/as3/src/mustella/AssertType.as
URL: http://svn.apache.org/viewvc/incubator/flex/trunk/mustella/as3/src/mustella/AssertType.as?rev=1333232&view=auto
==============================================================================
--- incubator/flex/trunk/mustella/as3/src/mustella/AssertType.as (added)
+++ incubator/flex/trunk/mustella/as3/src/mustella/AssertType.as Wed May  2 22:44:38 2012
@@ -0,0 +1,111 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.utils.getQualifiedClassName;
+
+import mx.core.mx_internal;
+use namespace mx_internal;
+
+/**
+ *  Instead of a property, we use an event so the MXML
+ *  compiler will wrap the code in a function for us
+ */
+[Event(name="valueExpression", type="flash.events.Event")]
+
+/**
+ *  Tests that the value of a property is as expected
+ *  MXML attributes:
+ *  target
+ *  propertyName
+ *  value
+ *  waitTarget (optional)
+ *  waitEvent (optional)
+ *  timeout (optional)
+ */
+public class AssertType extends Assert
+{
+	/**
+	 *  See if the property has the correct value
+	 */
+	override protected function doStep():void
+	{
+		var actualTarget:Object = context.stringToObject(target);
+		if (!actualTarget)
+		{
+			testResult.doFail("Target " + target + " not found");
+			return;
+		}
+
+		if (hasEventListener("valueExpression"))
+		{
+			context.resetValue();
+			try
+			{
+				dispatchEvent(new RunCodeEvent("valueExpression", root["document"], context, testCase, testResult));
+			}
+			catch (e1:Error)
+			{
+				TestOutput.logResult("Exception thrown evaluating value expression.");
+				testResult.doFail (e1.getStackTrace());	
+				return;
+			}
+			value = context.value;
+			if (!context.valueChanged)
+				TestOutput.logResult("WARNING: value was not set by valueExpression.  'value=' missing from expression?");
+		}
+
+		if (!(propertyName in actualTarget))
+		{
+			testResult.doFail ( target + "." + propertyName + " does not exist");
+			return;
+		}
+
+		if (getQualifiedClassName(actualTarget[propertyName]) != valueToString(value))
+		{
+			testResult.doFail ( target + "." + propertyName + " " + getQualifiedClassName(actualTarget[propertyName]) + " != " + valueToString(value));
+		} 
+	}
+
+	/**
+	 *  The name of the property to test
+	 */
+	public var propertyName:String;
+
+	/**
+	 *  The value the property should have
+	 */
+	public var value:Object;
+
+	/**
+	 *  customize string representation
+	 */
+	override public function toString():String
+	{
+		var s:String = "AssertPropertyValue";
+		if (target)
+			s += ": target = " + target;
+		if (propertyName)
+			s += ", propertyName = " + propertyName;
+		return s;
+	}
+}
+
+}

Propchange: incubator/flex/trunk/mustella/as3/src/mustella/AssertType.as
------------------------------------------------------------------------------
    svn:eol-style = native

Added: incubator/flex/trunk/mustella/as3/src/mustella/AssertURL.as
URL: http://svn.apache.org/viewvc/incubator/flex/trunk/mustella/as3/src/mustella/AssertURL.as?rev=1333232&view=auto
==============================================================================
--- incubator/flex/trunk/mustella/as3/src/mustella/AssertURL.as (added)
+++ incubator/flex/trunk/mustella/as3/src/mustella/AssertURL.as Wed May  2 22:44:38 2012
@@ -0,0 +1,79 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.external.ExternalInterface;
+
+import mx.core.mx_internal;
+use namespace mx_internal;
+
+/**
+ *  Instead of a property, we use an event so the MXML
+ *  compiler will wrap the code in a function for us
+ */
+[Event(name="valueExpression", type="flash.events.Event")]
+
+/**
+ *  Tests that the value of a property is as expected
+ *  MXML attributes:
+ *  url
+ *  waitTarget (optional)
+ *  waitEvent (optional)
+ *  timeout (optional)
+ */
+public class AssertURL extends Assert
+{
+	/**
+	 *  See if the property has the correct value
+	 */
+	override protected function doStep():void
+	{
+		var actualURL:String = ExternalInterface.call("BrowserHistory.getURL");
+		var pos:int = actualURL.indexOf("#");
+		var actualHash:String = "";
+		if (pos > -1)
+			actualHash = actualURL.substring(pos + 1);
+		var hash:String = "";
+		pos = url.indexOf("#");
+		if (pos > -1)
+			hash = url.substring(pos + 1);
+
+		if (valueToString(actualHash) != valueToString(hash))
+		{
+			testResult.doFail ( "Expected " + valueToString(hash) + ", got " + valueToString(actualHash));
+		} 
+	}
+
+	/**
+	 *  The value the url should have
+	 */
+	public var url:String;
+
+	/**
+	 *  customize string representation
+	 */
+	override public function toString():String
+	{
+		var s:String = "AssertURL";
+		return s;
+	}
+}
+
+}

Propchange: incubator/flex/trunk/mustella/as3/src/mustella/AssertURL.as
------------------------------------------------------------------------------
    svn:eol-style = native