our own copy of mustella.  Only some have been fully ported to FlexJS.  See 
list in compile-js-config.xml


Project: http://git-wip-us.apache.org/repos/asf/flex-asjs/repo
Commit: http://git-wip-us.apache.org/repos/asf/flex-asjs/commit/27eb06f5
Tree: http://git-wip-us.apache.org/repos/asf/flex-asjs/tree/27eb06f5
Diff: http://git-wip-us.apache.org/repos/asf/flex-asjs/diff/27eb06f5

Branch: refs/heads/packaging
Commit: 27eb06f5a01cd0e796bb067a7950ac83c6e134eb
Parents: d9e8503
Author: Alex Harui <aha...@apache.org>
Authored: Thu Sep 21 11:46:09 2017 -0700
Committer: Alex Harui <aha...@apache.org>
Committed: Thu Sep 21 11:46:09 2017 -0700

----------------------------------------------------------------------
 mustella/build.xml                              |  114 +
 mustella/src/main/config/compile-js-config.xml  |  163 ++
 mustella/src/main/config/compile-swf-config.xml |  145 +
 mustella/src/main/flex/AIR/CompareBitmap.as     | 1260 +++++++++
 mustella/src/main/flex/ApolloFilePath.as        |  129 +
 mustella/src/main/flex/Assert.as                |  185 ++
 mustella/src/main/flex/AssertError.as           |   90 +
 mustella/src/main/flex/AssertEvent.as           |  219 ++
 .../src/main/flex/AssertEventPropertyValue.as   |  112 +
 mustella/src/main/flex/AssertMethodValue.as     |  143 +
 mustella/src/main/flex/AssertNoEvent.as         |   80 +
 mustella/src/main/flex/AssertPixelValue.as      |  150 +
 mustella/src/main/flex/AssertPropertyValue.as   |  142 +
 mustella/src/main/flex/AssertStyleValue.as      |  124 +
 mustella/src/main/flex/AssertTitle.as           |   70 +
 mustella/src/main/flex/AssertType.as            |  111 +
 mustella/src/main/flex/AssertURL.as             |   79 +
 mustella/src/main/flex/Bug.as                   |   29 +
 mustella/src/main/flex/CBTester.mxml            |  305 ++
 mustella/src/main/flex/ChangeState.as           |   96 +
 mustella/src/main/flex/CheckEmbeddedFonts.as    |   44 +
 mustella/src/main/flex/CompareBitmap.as         | 1603 +++++++++++
 mustella/src/main/flex/ConditionalValue.as      |  356 +++
 .../ContinueAfterRuntimeException.ICO           |  Bin 0 -> 1078 bytes
 .../ContinueAfterRuntimeException.cpp           |  362 +++
 .../ContinueAfterRuntimeException.dsp           |  140 +
 .../ContinueAfterRuntimeException.dsw           |   29 +
 .../ContinueAfterRuntimeException.h             |   30 +
 .../ContinueAfterRuntimeException.rc            |  140 +
 .../ContinueAfterRuntimeException/SMALL.ICO     |  Bin 0 -> 318 bytes
 .../ContinueAfterRuntimeException/StdAfx.cpp    |   26 +
 .../flex/ContinueAfterRuntimeException/StdAfx.h |   52 +
 .../ContinueAfterRuntimeException/resource.h    |   45 +
 mustella/src/main/flex/CoverageTimeout.as       |   43 +
 .../src/main/flex/CreateBitmapReferences.as     |   46 +
 mustella/src/main/flex/DesktopMacSettings.as    |   40 +
 mustella/src/main/flex/DesktopWinSettings.as    |   40 +
 mustella/src/main/flex/DeviceNames.as           |   66 +
 mustella/src/main/flex/DispatchEvent.as         |  141 +
 mustella/src/main/flex/DispatchKeyEvent.as      |  673 +++++
 .../src/main/flex/DispatchMouseClickEvent.as    |  298 ++
 mustella/src/main/flex/DispatchMouseEvent.as    |  306 ++
 mustella/src/main/flex/DragAndDropMain.mxml     |   41 +
 mustella/src/main/flex/DragAndDropScript.mxml   |   66 +
 mustella/src/main/flex/EffectTesting.as         |  645 +++++
 mustella/src/main/flex/EnableRemoteImageDiff.as |   46 +
 mustella/src/main/flex/ErrorArray.as            |   41 +
 mustella/src/main/flex/EventSnifferRemote.as    |  154 ++
 mustella/src/main/flex/ExcludeFileLocation.as   |  226 ++
 .../src/main/flex/ExcludeFileLocationApollo.as  |  300 ++
 mustella/src/main/flex/ExcludeList.as           |   44 +
 mustella/src/main/flex/ExcludeList.txt          |    1 +
 mustella/src/main/flex/ExcludeListTextFile.as   |   71 +
 mustella/src/main/flex/ExitWhenDone.as          |   49 +
 mustella/src/main/flex/FakeSoftKeyboard.as      |  129 +
 mustella/src/main/flex/IncludeFileLocation.as   |  100 +
 mustella/src/main/flex/IncludeList.as           |   45 +
 mustella/src/main/flex/IncludeList.txt          |    1 +
 mustella/src/main/flex/IncludeListTextFile.as   |   71 +
 mustella/src/main/flex/Localhost8080.as         |   46 +
 mustella/src/main/flex/MobileConfig.as          |   30 +
 mustella/src/main/flex/MouseSnifferRemote.as    |  282 ++
 mustella/src/main/flex/MultiResult.as           |  193 ++
 mustella/src/main/flex/MustellaLogEvent.as      |   44 +
 mustella/src/main/flex/MustellaPNGEncoder.as    |  183 ++
 .../src/main/flex/MustellaRealTimeLogger.as     |   68 +
 mustella/src/main/flex/MustellaSandboxEvent.as  |   53 +
 mustella/src/main/flex/NoFail.as                |   41 +
 mustella/src/main/flex/ObjectSnifferRemote.as   |  333 +++
 mustella/src/main/flex/Pause.as                 |   66 +
 mustella/src/main/flex/PixelSnifferRemote.as    |  205 ++
 mustella/src/main/flex/PlaybackControl.as       |   91 +
 mustella/src/main/flex/README                   |  271 ++
 mustella/src/main/flex/ResetComponent.as        |  476 ++++
 mustella/src/main/flex/RunCode.as               |   77 +
 mustella/src/main/flex/RunCodeEvent.as          |   68 +
 mustella/src/main/flex/RunnerPortAlt.as         |   46 +
 mustella/src/main/flex/SaveBitmapFailures.as    |   62 +
 .../main/flex/SaveBitmapFailuresDistServer.as   |   62 +
 mustella/src/main/flex/ScriptRunner.as          |   53 +
 .../src/main/flex/SendFormattedResultsToLog.as  |  121 +
 mustella/src/main/flex/SendResultsToRunner.as   |  192 ++
 .../src/main/flex/SendResultsToSnifferClient.as |   83 +
 mustella/src/main/flex/SetProperty.as           |  144 +
 mustella/src/main/flex/SetShowRTE.as            |   43 +
 mustella/src/main/flex/SetStyle.as              |  118 +
 mustella/src/main/flex/SetURL.as                |   95 +
 mustella/src/main/flex/SetVettingRun.as         |   44 +
 mustella/src/main/flex/SnifferCellRenderer.mxml |   75 +
 mustella/src/main/flex/SnifferRemoteClient.mxml |  514 ++++
 mustella/src/main/flex/SocketAddress.as         |   52 +
 mustella/src/main/flex/TargetConfigurations.as  |  114 +
 mustella/src/main/flex/TestCase.as              |  525 ++++
 mustella/src/main/flex/TestOutput.as            |   76 +
 mustella/src/main/flex/TestResult.as            |  164 ++
 mustella/src/main/flex/TestStep.as              |  191 ++
 mustella/src/main/flex/TypeInfo.as              |  100 +
 mustella/src/main/flex/UnitTester.as            | 2617 ++++++++++++++++++
 mustella/src/main/flex/Util.as                  |   43 +
 mustella/src/main/flex/VerboseMode.as           |   46 +
 mustella/src/main/flex/WaitForCondition.as      |  150 +
 mustella/src/main/flex/WaitForEffectsToEnd.as   |  125 +
 mustella/src/main/flex/WaitForEvent.as          |  211 ++
 mustella/src/main/flex/WaitForLayoutManager.as  |  205 ++
 mustella/src/main/flex/WaitForSandboxApp.as     |  106 +
 mustella/src/main/flex/WaitForWindow.as         |   46 +
 mustella/src/main/flex/imageDiff.mxml           |  444 +++
 mustella/src/main/flex/main.mxml                |   35 +
 mustella/src/main/flex/myBitmap.png             |  Bin 0 -> 622 bytes
 mustella/src/main/flex/myTest4.png              |  Bin 0 -> 622 bytes
 .../src/main/flex/skins/pauseButtonSkin.mxml    |  176 ++
 mustella/src/main/flex/skins/pauseIcon.png      |  Bin 0 -> 369 bytes
 .../src/main/flex/skins/playButtonSkin.mxml     |  177 ++
 mustella/src/main/flex/skins/playIcon.png       |  Bin 0 -> 605 bytes
 .../src/main/flex/skins/stepButtonSkin.mxml     |  177 ++
 mustella/src/main/flex/skins/stepIcon.png       |  Bin 0 -> 413 bytes
 116 files changed, 20215 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/build.xml
----------------------------------------------------------------------
diff --git a/mustella/build.xml b/mustella/build.xml
new file mode 100644
index 0000000..891d4c6
--- /dev/null
+++ b/mustella/build.xml
@@ -0,0 +1,114 @@
+<?xml version="1.0"?>
+<!--
+
+  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.
+
+-->
+
+
+<project name="mustella" default="main" basedir=".">
+    <property name="FLEXJS_HOME" location=".."/>
+    
+    <property file="${FLEXJS_HOME}/env.properties"/>
+    <property environment="env"/>
+    <property file="${FLEXJS_HOME}/build.properties"/>
+    <property name="FLEX_HOME" value="${FLEXJS_HOME}"/>
+    
+    <property name="target.name" value="${ant.project.name}.swc" />
+    
+    <target name="main" depends="clean,check-compiler,compile,compile-js" 
description="Full build of ${ant.project.name}.swc">
+    </target>
+    
+    <target name="compile-js" unless="env.AIR_HOME">
+        <echo message="Compiling ${ant.project.name}.swc"/>
+        <echo message="FLEX_HOME: ${FLEX_HOME}"/>
+        <echo message="FALCON_HOME: ${FALCON_HOME}"/>
+        <echo message="FALCONJX_HOME: ${FALCONJX_HOME}"/>
+        
+        <java jar="${FALCONJX_HOME}/lib/compc.jar" fork="true" >
+            <jvmarg value="-Xmx384m" />
+            <jvmarg value="-Dsun.io.useCanonCaches=false" />
+            <jvmarg value="-Dflexlib=${FLEX_HOME}/frameworks" />
+            <arg value="+flexlib=${FLEX_HOME}/frameworks" />
+            <arg value="+playerglobal.version=${playerglobal.version}" />
+            <arg value="-compiler.strict-xml=true" />
+            <arg value="-compiler.targets=SWF,JSFlex" />
+            <arg value="-output=${basedir}/${target.name}" />
+            <arg value="-load-config=${FLEX_HOME}/frameworks/js-config.xml" />
+            <arg 
value="-load-config+=${basedir}/src/main/config/compile-js-config.xml" />
+            <arg value="-js-load-config=${FLEX_HOME}/frameworks/js-config.xml" 
/>
+            <arg 
value="-js-load-config+=${basedir}/src/main/config/compile-js-config.xml" />
+        </java>
+    </target>
+    
+    <target name="clean">
+        <delete file="${target.name}" failonerror="false" />
+    </target>
+    
+    <target name="compile" description="Compiles .as files into .swc" 
if="env.AIR_HOME">
+        <echo message="Compiling ${ant.project.name}.swc"/>
+        <echo message="FLEX_HOME: ${FLEX_HOME}"/>
+        <echo message="FALCON_HOME: ${FALCON_HOME}"/>
+        <echo message="FALCONJX_HOME: ${FALCONJX_HOME}"/>
+        
+        <java jar="${FALCONJX_HOME}/lib/compc.jar" fork="true" >
+            <jvmarg value="-Xmx384m" />
+            <jvmarg value="-Dsun.io.useCanonCaches=false" />
+            <jvmarg value="-Dflexlib=${FLEX_HOME}/frameworks" />
+            <arg value="+flexlib=${FLEX_HOME}/frameworks" />
+            <arg value="+playerglobal.version=${playerglobal.version}" />
+            <arg value="+env.AIR_HOME=${env.AIR_HOME}" />
+            <arg value="-compiler.strict-xml=true" />
+            <arg value="-compiler.targets=SWF,JSFlex" />
+            <arg value="-output=${basedir}/${target.name}" />
+            <arg 
value="-load-config=${basedir}/src/main/config/compile-swf-config.xml" />
+            <arg value="-js-load-config=${FLEX_HOME}/frameworks/js-config.xml" 
/>
+            <arg 
value="-js-load-config+=${basedir}/src/main/config/compile-js-config.xml" />
+        </java>
+    </target>
+    
+    <target name="check-compiler" 
depends="check-falcon-home,check-falconjx-home">
+        <path id="lib.path">
+            <fileset dir="${FALCONJX_HOME}/lib" 
includes="falcon-flexTasks.jar"/>
+        </path>
+        <taskdef resource="flexTasks.tasks" classpathref="lib.path"/>
+    </target>
+    
+    <target name="check-falcon-home"
+        description="Set FALCON_HOME to point at the compiler.">
+        
+        <available file="${FLEXJS_HOME}/lib/falcon-mxmlc.jar"
+        type="file"
+        property="FALCON_HOME"
+        value="${FLEXJS_HOME}"/>
+        
+        <fail message="FALCON_HOME must be set to a folder with a lib 
sub-folder containing falcon-mxmlc.jar such as the compiler folder in 
flex-falcon repo or the root of a FlexJS SDK"
+        unless="FALCON_HOME"/>
+    </target>
+    
+    <target name="check-falconjx-home"
+        description="Set FALCONJX_HOME to point at the cross-compiler.">
+        
+        <available file="${FLEXJS_HOME}/js/lib/jsc.jar"
+        type="file"
+        property="FALCONJX_HOME"
+        value="${FLEXJS_HOME}/js"/>
+        
+        <fail message="FALCONJX_HOME must be set to a folder with a lib 
sub-folder containing jsc.jar such as the compiler-jx folder in flex-falcon 
repo or the js folder of a FlexJS SDK"
+        unless="FALCONJX_HOME"/>
+    </target>
+    
+</project>

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/config/compile-js-config.xml
----------------------------------------------------------------------
diff --git a/mustella/src/main/config/compile-js-config.xml 
b/mustella/src/main/config/compile-js-config.xml
new file mode 100644
index 0000000..21b61f8
--- /dev/null
+++ b/mustella/src/main/config/compile-js-config.xml
@@ -0,0 +1,163 @@
+<!--
+
+  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.
+
+-->
+<flex-config>
+
+    <compiler>
+        <accessible>false</accessible>
+
+        <!-- build both SWF and JS. -->
+        <targets>
+            <target>SWF</target>
+            <target>JSFlex</target>
+        </targets>
+        <strict-xml>true</strict-xml>
+
+               <mxml>
+                       <children-as-data>true</children-as-data>
+               </mxml>
+               
<binding-value-change-event>org.apache.flex.events.ValueChangeEvent</binding-value-change-event>
+               
<binding-value-change-event-kind>org.apache.flex.events.ValueChangeEvent</binding-value-change-event-kind>
+               
<binding-value-change-event-type>valueChange</binding-value-change-event-type>
+
+        <define>
+            <name>COMPILE::SWF</name>
+            <value>false</value>
+        </define>
+        <define>
+            <name>COMPILE::JS</name>
+            <value>true</value>
+        </define>
+
+        <keep-as3-metadata>
+          <name>Bindable</name>
+          <name>Managed</name>
+          <name>ChangeEvent</name>
+          <name>NonCommittingChangeEvent</name>
+          <name>Transient</name>
+        </keep-as3-metadata>
+         
+        <locale/>
+        
+        <namespaces>
+            <!--
+            <namespace>
+                <uri>library://ns.apache.org/flexjs/basic</uri>
+                
<manifest>../../../../../../../projects/Core/src/main/resources/basic-manifest.xml</manifest>
+            </namespace>
+             -->
+        </namespaces>
+
+        <!-- overwrite the default library-path setting -->
+        <library-path>
+          <path-element>../../../../js/libs/GCL.swc</path-element>
+          
<path-element>../../../../frameworks/js/FlexJS/libs/CoreJS.swc</path-element>
+        </library-path>
+        
+        <source-path>
+            <path-element>../flex</path-element>
+        </source-path>
+        
+        <warn-no-constructor>false</warn-no-constructor>
+        
+        <!-- Use of the instanceof operator. -->
+        <warn-instance-of-changes>false</warn-instance-of-changes>
+    </compiler>
+    
+    <include-file>
+    </include-file>
+
+    <include-sources>
+    </include-sources>
+    
+    <include-classes>
+        <!--
+        <class>ApolloFilePath</class>
+         -->
+        <class>Assert</class>
+        <!--
+        <class>AssertError</class>
+        <class>AssertEvent</class>
+        <class>AssertEventPropertyValue</class>
+        <class>AssertMethodValue</class>
+        <class>AssertNoEvent</class>
+        <class>AssertPixelValue</class>
+         -->
+        <class>AssertPropertyValue</class>
+        <!--
+        <class>AssertStyleValue</class>
+        <class>AssertTitle</class>
+        <class>AssertType</class>
+        <class>AssertURL</class>
+        <class>CheckEmbeddedFonts</class>
+        <class>ChangeState</class>
+        <class>CompareBitmap</class>
+        <class>CreateBitmapReferences</class>
+         -->
+        <class>DispatchEvent</class>
+        <class>DispatchKeyEvent</class>
+        <class>DispatchMouseClickEvent</class>
+        <class>DispatchMouseEvent</class>
+        <!--
+        <class>ExcludeFileLocation</class>
+        <class>ExcludeFileLocationApollo</class>
+         -->
+        <class>ExitWhenDone</class>
+        <!--
+        <class>IncludeListTextFile</class>
+        <class>IncludeFileLocation</class>
+        <class>Localhost8080</class>
+        <class>MustellaPNGEncoder</class>
+        <class>Pause</class>
+        <class>ResetComponent</class>
+         -->
+        <class>RunCode</class>
+        <!--
+        <class>RunCodeEvent</class>
+        <class>SaveBitmapFailures</class>
+        <class>ScriptRunner</class>
+         -->
+        <class>SendFormattedResultsToLog</class>
+        <class>SendResultsToRunner</class>
+        <class>SetProperty</class>
+        <!--
+        <class>SetStyle</class>
+        <class>SetShowRTE</class>
+        <class>SetURL</class>
+        <class>SocketAddress</class>
+        -->
+        <class>TestCase</class>
+        <class>TestOutput</class>
+        <class>TestResult</class>
+        <class>TestStep</class>
+        <!--
+        <class>TypeInfo</class>
+         -->
+        <class>UnitTester</class>
+        <!--
+        <class>VerboseMode</class>
+        <class>WaitForCondition</class>
+        <class>WaitForEffectsToEnd</class>
+        <class>WaitForEvent</class>
+        <class>WaitForLayoutManager</class>
+        <class>WaitForSandboxApp</class>
+        <class>WaitForWindow</class>
+         -->
+    </include-classes>
+    
+</flex-config>

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/config/compile-swf-config.xml
----------------------------------------------------------------------
diff --git a/mustella/src/main/config/compile-swf-config.xml 
b/mustella/src/main/config/compile-swf-config.xml
new file mode 100644
index 0000000..5c87682
--- /dev/null
+++ b/mustella/src/main/config/compile-swf-config.xml
@@ -0,0 +1,145 @@
+<!--
+
+  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.
+
+-->
+<flex-config>
+
+    <compiler>
+        <accessible>false</accessible>
+        
+        <!-- build both SWF and JS. -->
+        <targets>
+            <target>SWF</target>
+            <target>JSFlex</target>
+        </targets>
+        <strict-xml>true</strict-xml>
+
+        <external-library-path>
+            
<path-element>${env.AIR_HOME}/frameworks/libs/air/airglobal.swc</path-element>
+        </external-library-path>
+        
+        <allow-subclass-overrides>true</allow-subclass-overrides>
+        
+               <mxml>
+                       <children-as-data>true</children-as-data>
+               </mxml>
+               
<binding-value-change-event>org.apache.flex.events.ValueChangeEvent</binding-value-change-event>
+               
<binding-value-change-event-kind>org.apache.flex.events.ValueChangeEvent</binding-value-change-event-kind>
+               
<binding-value-change-event-type>valueChange</binding-value-change-event-type>
+        
+        <define>
+            <name>COMPILE::SWF</name>
+            <value>true</value>
+        </define>
+        <define>
+            <name>COMPILE::JS</name>
+            <value>false</value>
+        </define>
+
+        <keep-as3-metadata>
+          <name>Bindable</name>
+          <name>Managed</name>
+          <name>ChangeEvent</name>
+          <name>NonCommittingChangeEvent</name>
+          <name>Transient</name>
+          <name>SWFOverride</name>
+        </keep-as3-metadata>
+         
+        <locale/>
+        
+        <library-path/>
+
+        <namespaces>
+            <!--
+            <namespace>
+                <uri>library://ns.apache.org/flexjs/basic</uri>
+                <manifest>../resources/basic-manifest.xml</manifest>
+            </namespace>
+             -->
+        </namespaces>
+        
+        <source-path>
+            <path-element>../flex</path-element>
+        </source-path>
+        
+        <warn-no-constructor>false</warn-no-constructor>
+        
+        <!-- Use of the instanceof operator. -->
+        <warn-instance-of-changes>false</warn-instance-of-changes>
+    </compiler>
+    
+    <include-classes>
+        <class>ApolloFilePath</class>
+        <class>Assert</class>
+        <class>AssertError</class>
+        <class>AssertEvent</class>
+        <class>AssertEventPropertyValue</class>
+        <class>AssertMethodValue</class>
+        <class>AssertNoEvent</class>
+        <class>AssertPixelValue</class>
+        <class>AssertPropertyValue</class>
+        <class>AssertStyleValue</class>
+        <class>AssertTitle</class>
+        <class>AssertType</class>
+        <class>AssertURL</class>
+        <class>CheckEmbeddedFonts</class>
+        <class>ChangeState</class>
+        <class>CompareBitmap</class>
+        <class>CreateBitmapReferences</class>
+        <class>DispatchEvent</class>
+        <class>DispatchKeyEvent</class>
+        <class>DispatchMouseClickEvent</class>
+        <class>DispatchMouseEvent</class>
+        <class>ExcludeFileLocation</class>
+        <class>ExcludeFileLocationApollo</class>
+        <class>ExitWhenDone</class>
+        <class>IncludeListTextFile</class>
+        <class>IncludeFileLocation</class>
+        <class>Localhost8080</class>
+        <class>MustellaPNGEncoder</class>
+        <class>Pause</class>
+        <class>ResetComponent</class>
+        <class>RunCode</class>
+        <class>RunCodeEvent</class>
+        <class>SaveBitmapFailures</class>
+        <class>ScriptRunner</class>
+        <class>SendFormattedResultsToLog</class>
+        <class>SendResultsToRunner</class>
+        <class>SetProperty</class>
+        <class>SetStyle</class>
+        <class>SetShowRTE</class>
+        <class>SetURL</class>
+        <class>SocketAddress</class>
+        <class>TestCase</class>
+        <class>TestOutput</class>
+        <class>TestResult</class>
+        <class>TestStep</class>
+        <class>TypeInfo</class>
+        <class>UnitTester</class>
+        <class>VerboseMode</class>
+        <class>WaitForCondition</class>
+        <class>WaitForEffectsToEnd</class>
+        <class>WaitForEvent</class>
+        <class>WaitForLayoutManager</class>
+        <class>WaitForSandboxApp</class>
+        <class>WaitForWindow</class>
+    </include-classes>
+    
+    <target-player>20.0</target-player>
+       
+
+</flex-config>

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/flex/AIR/CompareBitmap.as
----------------------------------------------------------------------
diff --git a/mustella/src/main/flex/AIR/CompareBitmap.as 
b/mustella/src/main/flex/AIR/CompareBitmap.as
new file mode 100644
index 0000000..e96da6f
--- /dev/null
+++ b/mustella/src/main/flex/AIR/CompareBitmap.as
@@ -0,0 +1,1260 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 AIR { 
+
+import flash.display.*;
+import flash.events.*;
+import flash.filesystem.*;
+import flash.net.*;
+import flash.text.*;
+import flash.text.engine.*;
+import flash.geom.ColorTransform;
+import flash.utils.*;
+import flash.filesystem.*;
+import flash.geom.*;
+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);
+ *  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;
+
+       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;
+
+       // 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 xmlreader:URLLoader;
+       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;
+                               }
+                       }
+
+                       writeBaselines(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;
+       
+       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;
+                       }
+               }
+
+               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());
+
+                       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();
+               if (s !== xmlreader.data)
+               {
+                       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))
+                       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
+       {
+               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);
+                       }
+               }
+               
+               reader = new Loader();
+               reader.contentLoaderInfo.addEventListener(Event.COMPLETE, 
readCompleteHandler);
+               
reader.contentLoaderInfo.addEventListener(SecurityErrorEvent.SECURITY_ERROR, 
readErrorHandler);
+               
reader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, 
readErrorHandler);
+               //      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 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);
+
+               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);
+               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();
+
+
+       }
+       
+       /****** 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 && !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";
+               if (d.filters && d.filters.length > 0)
+               {
+                       s = d.filters.toString();
+                       xml.@filters = s;
+               }
+               if (d.opaqueBackground)
+                       xml.@opaqueBackground = "true";
+               if (d.scale9Grid)
+               {
+                       s = d.scale9Grid.toString();
+                       xml.@scale9Grid = s;
+               }
+               if (d is TextField)
+               {
+                       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++)
+                       {
+                               childXML = 
getDisplayListProperties(doc.getChildAt(i));
+                               xml.appendChild(childXML);                      
        
+                       }
+               }
+               return xml;
+       }
+       
+       // scan entire display list, but only dump objects intersecting target
+       protected function getDisplayListXML(target:DisplayObject):XML
+       {
+               var n:int;
+               var i: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;
+       }
+}
+
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/flex/ApolloFilePath.as
----------------------------------------------------------------------
diff --git a/mustella/src/main/flex/ApolloFilePath.as 
b/mustella/src/main/flex/ApolloFilePath.as
new file mode 100644
index 0000000..47a66c0
--- /dev/null
+++ b/mustella/src/main/flex/ApolloFilePath.as
@@ -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);
+       }
+}
+
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/flex/Assert.as
----------------------------------------------------------------------
diff --git a/mustella/src/main/flex/Assert.as b/mustella/src/main/flex/Assert.as
new file mode 100644
index 0000000..b5b5ead
--- /dev/null
+++ b/mustella/src/main/flex/Assert.as
@@ -0,0 +1,185 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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.display.DisplayObject;
+import flash.events.Event;
+import flash.events.EventDispatcher;
+import flash.events.IEventDispatcher;
+import flash.utils.getTimer;
+}
+
+import org.apache.flex.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:Object, 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
+        */
+    COMPILE::SWF
+       override public function execute(root:Object, 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
+        */
+    COMPILE::SWF
+       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);
+               return s;
+       }
+
+    protected function contains(value:*, expectedError:ErrorArray):Boolean {
+        if (expectedError && expectedError.parts && expectedError.parts.length)
+            for (var i:uint = 0; i < expectedError.parts.length; i++) {
+                if 
(valueToString(value).indexOf(valueToString(expectedError.parts[i])) == -1)
+                    return false;
+            }
+
+        return true;
+    }
+}
+
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/flex/AssertError.as
----------------------------------------------------------------------
diff --git a/mustella/src/main/flex/AssertError.as 
b/mustella/src/main/flex/AssertError.as
new file mode 100644
index 0000000..59fd925
--- /dev/null
+++ b/mustella/src/main/flex/AssertError.as
@@ -0,0 +1,90 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 (errorArray) {
+            var errors:ErrorArray = new ErrorArray(errorArray);
+                       if (!contains(testCase.lastError, errors))
+                               testResult.doFail("Expected Error contains " + 
valueToString(errors) + ", got " + valueToString(testCase.lastError));
+        } else 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:*;
+
+    public var errorArray:Array;
+
+       /**
+        *  customize string representation
+        */
+       override public function toString():String
+       {
+               var s:String = "AssertError";
+               return s;
+       }
+}
+
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/flex/AssertEvent.as
----------------------------------------------------------------------
diff --git a/mustella/src/main/flex/AssertEvent.as 
b/mustella/src/main/flex/AssertEvent.as
new file mode 100644
index 0000000..0abb8ce
--- /dev/null
+++ b/mustella/src/main/flex/AssertEvent.as
@@ -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);
+
+       }
+}
+
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/flex/AssertEventPropertyValue.as
----------------------------------------------------------------------
diff --git a/mustella/src/main/flex/AssertEventPropertyValue.as 
b/mustella/src/main/flex/AssertEventPropertyValue.as
new file mode 100644
index 0000000..fa732fd
--- /dev/null
+++ b/mustella/src/main/flex/AssertEventPropertyValue.as
@@ -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;
+       }
+}
+
+}

http://git-wip-us.apache.org/repos/asf/flex-asjs/blob/27eb06f5/mustella/src/main/flex/AssertMethodValue.as
----------------------------------------------------------------------
diff --git a/mustella/src/main/flex/AssertMethodValue.as 
b/mustella/src/main/flex/AssertMethodValue.as
new file mode 100644
index 0000000..96b7cfb
--- /dev/null
+++ b/mustella/src/main/flex/AssertMethodValue.as
@@ -0,0 +1,143 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+//  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 (errorArray) {
+            var errors:ErrorArray = new ErrorArray(errorArray);
+            if (!contains(methodValue, errors))
+                testResult.doFail("method returned " + 
valueToString(methodValue) + ", expected it contains " + valueToString(errors));
+        } else if (valueToString(methodValue) != valueToString(value))
+            testResult.doFail("method returned " + valueToString(methodValue) 
+ ", expected " + valueToString(value));
+       }
+
+       /**
+        *  The value the method should return
+        */
+       public var value:*;
+
+    public var errorArray:Array;
+
+       /**
+        *  customize string representation
+        */
+       override public function toString():String
+       {
+               var s:String = "AssertMethodValue (method cannot be shown) ";
+               return s;
+       }
+
+}
+
+}

Reply via email to