/* * * 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 as; import org.apache.flex.compiler.clients.MXMLC; import org.apache.flex.compiler.problems.ICompilerProblem; import org.apache.flex.utils.*; import utils.FlashplayerSecurityHandler; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.concurrent.*; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; /** * Base class for AS feature tests which compile AS code with MXMLC and run it in the standalone Flash Player. * Copied and modified from MXMLFeatureTestsBase.java */ public class ASFeatureTestsBase { private static final String NAMESPACE_2009 = "http://ns.adobe.com/mxml/2009"; protected File generateTempFile(String source) { // Write the MXML into a temp file. ITestAdapter testAdapter = TestAdapterFactory.getTestAdapter(); String tempDir = testAdapter.getTempDir(); File tempASFile = null; try { tempASFile = File.createTempFile(getClass().getSimpleName(), ".as", new File(tempDir)); tempASFile.deleteOnExit(); BufferedWriter out = new BufferedWriter(new FileWriter(tempASFile)); String className = tempASFile.getName(); // chop off .as className = className.substring(0, className.length() - 3); source = source.replaceAll("%0", className); out.write(source); out.close(); } catch (IOException e1) { e1.printStackTrace(); fail("Error generating test code"); } return tempASFile; } protected String compile(File tempASFile, String source, boolean withFramework, boolean withRPC, boolean withSpark, String[] otherOptions, boolean checkExitCode) { System.out.println("Generating test:"); ITestAdapter testAdapter = TestAdapterFactory.getTestAdapter(); // Build the list of SWCs to compile against on the library path. List<String> swcs = new ArrayList<String>(); if (withFramework) { swcs.add(testAdapter.getFlexArtifact("framework").getPath()); swcs.add(testAdapter.getFlexArtifactResourceBundle("framework").getPath()); } if (withRPC) { swcs.add(testAdapter.getFlexArtifact("rpc").getPath()); swcs.add(testAdapter.getFlexArtifactResourceBundle("rpc").getPath()); } if (withSpark) { swcs.add(testAdapter.getFlexArtifact("spark").getPath()); swcs.add(testAdapter.getFlexArtifactResourceBundle("spark").getPath()); } List<String> args = new ArrayList<String>(); args.add("-external-library-path=" + testAdapter.getPlayerglobal().getPath()); if(swcs.size() > 0) { String libraryPath = "-library-path=" + StringUtils.join(swcs.toArray(new String[swcs.size()]), ","); args.add(libraryPath); } if (withFramework || withRPC || withSpark) args.add("-namespace=" + NAMESPACE_2009 + "," + testAdapter.getFlexManifestPath("mxml-2009")); if (otherOptions != null) { Collections.addAll(args, otherOptions); } args.add(tempASFile.getAbsolutePath()); // Use MXMLC to compile the MXML file against playerglobal.swc and possibly other SWCs. MXMLC mxmlc = new MXMLC(); StringBuffer cmdLine = new StringBuffer(); for(String arg : args) { cmdLine.append(arg).append(" "); } System.out.println("Compiling test:\n" + cmdLine.toString()); int exitCode = mxmlc.mainNoExit(args.toArray(new String[args.size()])); // Check that there were no compilation problems. List<ICompilerProblem> problems = mxmlc.getProblems().getProblems(); StringBuilder sb = new StringBuilder(checkExitCode ? "Unexpected compilation problems:\n" : ""); for (ICompilerProblem problem : problems) { sb.append(problem.toString()); sb.append('\n'); } System.out.println("After compile:\n" + sb.toString()); if (checkExitCode) assertThat(sb.toString(), exitCode, is(0)); return sb.toString(); } protected void compileAndExpectErrors(String source, boolean withFramework, boolean withRPC, boolean withSpark, String[] otherOptions, String errors) { File tempASFile = generateTempFile(source); String results = compile(tempASFile, source, withFramework, withRPC, withSpark, otherOptions, false); assertThat(results, is(errors)); } protected void compileAndRun(String source, boolean withFramework, boolean withRPC, boolean withSpark, String[] otherOptions) { int exitCode = 0; File tempASFile = generateTempFile(source); compile(tempASFile, source, withFramework, withRPC, withSpark, otherOptions, true); ITestAdapter testAdapter = TestAdapterFactory.getTestAdapter(); // Check the existence of the flashplayer executable File playerExecutable = testAdapter.getFlashplayerDebugger(); if(!playerExecutable.isFile() || !playerExecutable.exists()) { fail("The flashplayer executable " + testAdapter.getFlashplayerDebugger().getPath() + " doesn't exist."); } // Run the SWF in the standalone player amd wait until the SWF calls System.exit(). String swf = FilenameNormalization.normalize(tempASFile.getAbsolutePath()); swf = swf.replace(".as", ".swf"); String[] runArgs = new String[] { testAdapter.getFlashplayerDebugger().getPath(), swf }; try { System.out.println("Executing test:\n" + Arrays.toString(runArgs)); // TODO: Hack to add the directory containing the temp swf to the flashplayer trust. new FlashplayerSecurityHandler().trustFile(tempASFile.getParentFile()); exitCode = executeCommandWithTimeout(runArgs, 20); } catch (Exception e) { e.printStackTrace(); // If we just print the stacktrace the exitCode is still 0 and the test will pass. fail("Got exception"); } // Check that the runtime exit code was 0, meaning that no asserts failed. assertThat(exitCode, is(0)); } protected void compileAndRun(String source) { compileAndRun(source, false, false, false, null); } public static int executeCommandWithTimeout(String[] args, long timeoutInSeconds) throws Exception { ExecutorService service = Executors.newSingleThreadExecutor(); Process process = Runtime.getRuntime().exec(args); try { Callable<Integer> call = new CallableProcess(process); Future<Integer> future = service.submit(call); return future.get(timeoutInSeconds, TimeUnit.SECONDS); } catch (ExecutionException e) { throw new Exception("Process failed to execute", e); } catch (TimeoutException e) { process.destroy(); throw new Exception("Process timed out", e); } finally { service.shutdown(); } } private static class CallableProcess implements Callable<Integer> { private Process p; public CallableProcess(Process process) { p = process; } public Integer call() throws Exception { return p.waitFor(); } } /** * Combines various code snippets to make a complete one-file MXML Sprite-based application. */ protected String getAS(String[] imports, String[] declarations, String[] testCode, String[] extraCode) { String[] template = new String[] { "package {", "import flash.display.Sprite;", "import flash.events.Event;", "import flash.system.System;", "%1", "public class %0 extends flash.display.Sprite", "{", " public function %0()", " {", " loaderInfo.addEventListener(flash.events.Event.INIT, initHandler);", " }", " %2", " private function initHandler(e:flash.events.Event):void", " {", " %3", " System.exit(0);", " }", " private function assertEqual(message:String, actualValue:*, expectedValue:*):void", " {", " if (actualValue !== expectedValue)", " {", " trace(message, actualValue, expectedValue);", " System.exit(1);", " }", " }", "}", "}", "%4" }; String source = StringUtils.join(template, "\n"); source = source.replace("%1", StringUtils.join(imports, "\n")); source = source.replace("%2", StringUtils.join(declarations, "\n ")); source = source.replace("%3", StringUtils.join(testCode, "\n")); source = source.replace("%4", StringUtils.join(extraCode, "\n")); return source; } }