You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@flex.apache.org by ah...@apache.org on 2017/09/22 05:47:51 UTC
[20/24] git commit: [flex-asjs] [refs/heads/packaging] - our own copy
of mustella. Only some have been fully ported to FlexJS. See list in
compile-js-config.xml
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 <ah...@apache.org>
Authored: Thu Sep 21 11:46:09 2017 -0700
Committer: Alex Harui <ah...@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 <= 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;
+ }
+
+}
+
+}