diff --git a/build.gradle b/build.gradle index 42dba09631..45465a3aea 100644 --- a/build.gradle +++ b/build.gradle @@ -3572,6 +3572,7 @@ project(":systemTests") { testapp5 testapp6 testscriptapp1 + testscriptapp2 } def nonModSrcSets = [ @@ -3585,7 +3586,8 @@ project(":systemTests") { sourceSets.testapp4, sourceSets.testapp5, sourceSets.testapp6, - sourceSets.testscriptapp1 + sourceSets.testscriptapp1, + sourceSets.testscriptapp2 ] project.ext.buildModule = false @@ -3685,7 +3687,7 @@ project(":systemTests") { } test.dependsOn(createTestApps); - def modtestapps = [ "testapp2", "testapp3", "testapp4", "testapp5", "testapp6", "testscriptapp1" ] + def modtestapps = [ "testapp2", "testapp3", "testapp4", "testapp5", "testapp6", "testscriptapp1", "testscriptapp2" ] modtestapps.each { testapp -> def testappCapital = testapp.capitalize() def copyTestAppTask = task("copy${testappCapital}", type: Copy) { diff --git a/modules/javafx.fxml/src/main/docs/javafx/fxml/doc-files/introduction_to_fxml.html b/modules/javafx.fxml/src/main/docs/javafx/fxml/doc-files/introduction_to_fxml.html index b34806f2f7..dc738eaf8b 100644 --- a/modules/javafx.fxml/src/main/docs/javafx/fxml/doc-files/introduction_to_fxml.html +++ b/modules/javafx.fxml/src/main/docs/javafx/fxml/doc-files/introduction_to_fxml.html @@ -29,7 +29,7 @@ - + Introduction to FXML | JavaFX @FXVERSION@ @@ -597,13 +597,13 @@

Expression Binding

-
(unary operator)Unary minus operator, applied on a number !
(unary operator)Unary negation of a boolean + -
- * / - % Numerical binary operators + * / + % Numerical binary operators && ||Boolean binary operators > >=
- < <=
- == != - Binary operators of comparison.
Both arguments must be of type Comparable + < <=
+ == != + Binary operators of comparison.
Both arguments must be of type Comparable

Static Properties

@@ -641,6 +641,8 @@

Script Event Handlers

Note the use of the language processing instruction at the beginning of the code snippet. This PI tells the FXML loader which scripting language should be used to execute the event handler. A page language must be specified whenever inline script is used in an FXML document, and can only be specified once per document. However, this does not apply to external scripts, which may be implemented using any number of supported scripting languages. Scripting is discussed in more detail in the next section.

+

Note: to turn off automatic compilation of script code place the processing instruction <?compile false?> before the element that contains the script. To turn on compilation of script code again use the processing instruction <?compile true?> (or short: <?compile?>). The compile processing instruction can be used repeatedly to turn compilation of script code off and on.

+

Controller Method Event Handlers

A controller method event handler is a method defined by a document's "controller". A controller is an object that is associated with the deserialized contents of an FXML document and is responsible for coordinating the behaviors of the objects (often user interface elements) defined by the document.

@@ -700,15 +702,15 @@

Event handlers from expressions

With the controller that contains a field like this

- +
 public class MyController {
-    
+
     @FXML
     public EventHandler<ActionEvent> onActionHandler = new EventHandler<>() { ... }
 
     ...
-}  
+}
 

Note that other kinds of expressions, like binding expressions @@ -763,14 +765,18 @@

Special handlers for collections a <VBox fx:controller="com.foo.MyController" xmlns:fx="http://javafx.com/fxml" onParentChange="#handleParentChange"/> - +

Note that collections and properties do not currently support scripting handlers.

Scripting

The <fx:script> tag allows a caller to import scripting code into or embed script within a FXML file. Any JVM scripting language can be used, including JavaScript, Groovy, and Clojure, among others. Script code is often used to define event handlers directly in markup or in an associated source file, since event handlers can often be written more concisely in more loosely-typed scripting languages than they can in a statically-typed language such as Java.

-

For example, the following markup defines a function called handleButtonAction() that is called by the action handler attached to the Button element:

+

Scripts are compiled by default, when they are first loaded, if the ScriptEngine implements the javax.script.Compilable interface. If compilation fails, the FXMLLoader will fall back to interpreted mode.

+ +

Note: to turn off automatic compilation of script code place the processing instruction <?compile false?> before the script element. To turn on compilation of script code again use the processing instruction <?compile true?> (or short: <?compile?>). The compile processing instruction can be used repeatedly to turn compilation of script code off and on.

+ +

The following example markup defines a function called handleButtonAction() that is called by the action handler attached to the Button element:

 <?language javascript?>
@@ -798,6 +804,8 @@ 

Scripting

example.fxml
+<?language javascript?>
+
 <?import javafx.scene.control.*?>
 <?import javafx.scene.layout.*?>
 
@@ -833,8 +841,7 @@ 

Scripting

<Label text="$myText"/>
- -

Warning:As of JavaFX 8, importClass() javascript function is no longer supported. You have to use fully qualified names as in the example above or load a nashorn compatibility script.

+

Warning: As of JavaFX 8, importClass() javascript function is no longer supported. You have to use fully qualified names as in the example above or load a nashorn compatibility script.

 load("nashorn:mozilla_compat.js");
@@ -843,7 +850,7 @@ 

Scripting

function handleButtonAction(event) { System.out.println('You clicked me!'); } -
+

Controllers

While it can be convenient to write simple event handlers in script, either inline or defined in external files, it is often preferable to define more complex application logic in a compiled, strongly-typed language such as Java. As discussed earlier, the fx:controller attribute allows a caller to associate a "controller" class with an FXML document. A controller is a compiled class that implements the "code behind" the object hierarchy defined by the document.

diff --git a/modules/javafx.fxml/src/main/java/javafx/fxml/FXMLLoader.java b/modules/javafx.fxml/src/main/java/javafx/fxml/FXMLLoader.java index b4677b4482..7ab2a6e7fb 100644 --- a/modules/javafx.fxml/src/main/java/javafx/fxml/FXMLLoader.java +++ b/modules/javafx.fxml/src/main/java/javafx/fxml/FXMLLoader.java @@ -63,6 +63,8 @@ import javafx.util.Callback; import javax.script.Bindings; +import javax.script.Compilable; +import javax.script.CompiledScript; import javax.script.ScriptContext; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; @@ -1558,21 +1560,55 @@ public void processStartElement() throws IOException { location = new URL(FXMLLoader.this.location, source); } Bindings engineBindings = engine.getBindings(ScriptContext.ENGINE_SCOPE); - engineBindings.put(engine.FILENAME, location.getPath()); + String filename = location.getPath(); + engineBindings.put(engine.FILENAME, filename); InputStreamReader scriptReader = null; + String script = null; try { scriptReader = new InputStreamReader(location.openStream(), charset); - engine.eval(scriptReader); - } catch(ScriptException exception) { - exception.printStackTrace(); + StringBuilder sb = new StringBuilder(); + final int bufSize = 4096; + char[] charBuffer = new char[bufSize]; + int n; + do { + n = scriptReader.read(charBuffer,0,bufSize); + if (n > 0) { + sb.append(new String(charBuffer,0,n)); + } + } while (n > -1); + script = sb.toString(); + } catch (IOException exception) { + throw constructLoadException(exception); } finally { if (scriptReader != null) { scriptReader.close(); } } - } catch (IOException exception) { - throw constructLoadException(exception); + try { + if (engine instanceof Compilable && compileScript) { + CompiledScript compiledScript = null; + try { + compiledScript = ((Compilable) engine).compile(script); + } catch (ScriptException compileExc) { + Logging.getJavaFXLogger().warning(filename + ": compiling caused \"" + compileExc + + "\", falling back to evaluating script in uncompiled mode"); + } + if (compiledScript != null) { + compiledScript.eval(); + } else { // fallback to uncompiled mode + engine.eval(script); + } + } else { + engine.eval(script); + } + } catch (ScriptException exception) { + System.err.println(filename + ": caused ScriptException"); + exception.printStackTrace(); + } + } + catch (IOException exception) { + throw constructLoadException(exception); } } } @@ -1583,13 +1619,31 @@ public void processEndElement() throws IOException { if (value != null && !staticLoad) { // Evaluate the script + String filename = null; try { Bindings engineBindings = scriptEngine.getBindings(ScriptContext.ENGINE_SCOPE); - engineBindings.put(scriptEngine.FILENAME, location.getPath() + "-script_starting_at_line_" - + (getLineNumber() - (int) ((String) value).codePoints().filter(c -> c == '\n').count())); - scriptEngine.eval((String)value); + String script = (String) value; + filename = location.getPath() + "-script_starting_at_line_" + + (getLineNumber() - (int) script.codePoints().filter(c -> c == '\n').count()); + engineBindings.put(scriptEngine.FILENAME, filename); + if (scriptEngine instanceof Compilable && compileScript) { + CompiledScript compiledScript = null; + try { + compiledScript = ((Compilable) scriptEngine).compile(script); + } catch (ScriptException compileExc) { + Logging.getJavaFXLogger().warning(filename + ": compiling caused \"" + compileExc + + "\", falling back to evaluating script in uncompiled mode"); + } + if (compiledScript != null) { + compiledScript.eval(); + } else { // fallback to uncompiled mode + scriptEngine.eval(script); + } + } else { + scriptEngine.eval(script); + } } catch (ScriptException exception) { - System.err.println(exception.getMessage()); + System.err.println(filename + ": caused ScriptException\n" + exception.getMessage()); } } } @@ -1681,11 +1735,24 @@ public void handle(T event) { public final String script; public final ScriptEngine scriptEngine; public final String filename; + public CompiledScript compiledScript; + public boolean isCompiled = false; public ScriptEventHandler(String script, ScriptEngine scriptEngine, String filename) { this.script = script; this.scriptEngine = scriptEngine; this.filename = filename; + if (scriptEngine instanceof Compilable && compileScript) { + try { + // supply the filename to the scriptEngine engine scope Bindings in case it is needed for compilation + scriptEngine.getBindings(ScriptContext.ENGINE_SCOPE).put(scriptEngine.FILENAME, filename); + this.compiledScript = ((Compilable) scriptEngine).compile(script); + this.isCompiled = true; + } catch (ScriptException compileExc) { + Logging.getJavaFXLogger().warning(filename + ": compiling caused \"" + compileExc + + "\", falling back to evaluating script in uncompiled mode"); + } + } } @Override @@ -1699,9 +1766,13 @@ public void handle(Event event) { localBindings.put(scriptEngine.FILENAME, filename); // Execute the script try { - scriptEngine.eval(script, localBindings); - } catch (ScriptException exception){ - throw new RuntimeException(exception); + if (isCompiled) { + compiledScript.eval(localBindings); + } else { + scriptEngine.eval(script, localBindings); + } + } catch (ScriptException exception) { + throw new RuntimeException(filename + ": caused ScriptException", exception); } } } @@ -1819,6 +1890,7 @@ public void invoke(Object... params) { private Element current = null; private ScriptEngine scriptEngine = null; + private static boolean compileScript = true; private List packages = new LinkedList(); private Map> classes = new HashMap>(); @@ -1845,6 +1917,12 @@ public void invoke(Object... params) { */ public static final String IMPORT_PROCESSING_INSTRUCTION = "import"; + /** + * The tag name of the compile processing instruction. + * @since 15 + */ + public static final String COMPILE_PROCESSING_INSTRUCTION = "compile"; + /** * Prefix of 'fx' namespace. */ @@ -2678,6 +2756,10 @@ private void processProcessingInstruction() throws LoadException { processLanguage(); } else if (piTarget.equals(IMPORT_PROCESSING_INSTRUCTION)) { processImport(); + } else if (piTarget.equals(COMPILE_PROCESSING_INSTRUCTION)) { + String strCompile = xmlStreamReader.getPIData().trim(); + // if PIData() is empty string then default to true, otherwise use Boolean.parseBoolean(string) to determine the boolean value + compileScript = (strCompile.length() == 0 ? true : Boolean.parseBoolean(strCompile)); } } diff --git a/tests/system/src/test/java/test/launchertest/ModuleLauncherTest.java b/tests/system/src/test/java/test/launchertest/ModuleLauncherTest.java index 346bf78c4e..10c14eb6d4 100644 --- a/tests/system/src/test/java/test/launchertest/ModuleLauncherTest.java +++ b/tests/system/src/test/java/test/launchertest/ModuleLauncherTest.java @@ -44,6 +44,7 @@ private static final String modulePath5 = System.getProperty("launchertest.testapp5.module.path"); private static final String modulePath6 = System.getProperty("launchertest.testapp6.module.path"); private static final String modulePathScript1 = System.getProperty("launchertest.testscriptapp1.module.path"); + private static final String modulePathScript2 = System.getProperty("launchertest.testscriptapp2.module.path"); private static final String moduleName = "mymod"; @@ -281,4 +282,27 @@ public void testFXMLScriptDeployment() throws Exception { doTestLaunchModule(modulePathScript1, "myapp1.FXMLScriptDeployment"); } + @Test (timeout = 15000) + public void testFXMLScriptDeployment2Compile_On() throws Exception { + doTestLaunchModule(modulePathScript2, "myapp2.FXMLScriptDeployment2Compile_On"); + } + + @Test (timeout = 15000) + public void testFXMLScriptDeployment2Compile_Off() throws Exception { + doTestLaunchModule(modulePathScript2, "myapp2.FXMLScriptDeployment2Compile_Off"); + } + + @Test (timeout = 15000) + public void testFXMLScriptDeployment2Compile_On_Off() throws Exception { + doTestLaunchModule(modulePathScript2, "myapp2.FXMLScriptDeployment2Compile_On_Off"); + } + + @Test (timeout = 15000) + public void testFXMLScriptDeployment2Compile_Off_On() throws Exception { + doTestLaunchModule(modulePathScript2, "myapp2.FXMLScriptDeployment2Compile_Off_On"); + } + @Test (timeout = 15000) + public void testFXMLScriptDeployment2Compile_Fail_Compilation() throws Exception { + doTestLaunchModule(modulePathScript2, "myapp2.FXMLScriptDeployment2Compile_Fail_Compilation"); + } } diff --git a/tests/system/src/testscriptapp1/resources/mymod/META-INF/services/javax.script.ScriptEngineFactory b/tests/system/src/testscriptapp1/resources/mymod/META-INF/services/javax.script.ScriptEngineFactory index b2ef7c5bac..8baed7c6dd 100644 --- a/tests/system/src/testscriptapp1/resources/mymod/META-INF/services/javax.script.ScriptEngineFactory +++ b/tests/system/src/testscriptapp1/resources/mymod/META-INF/services/javax.script.ScriptEngineFactory @@ -1,2 +1 @@ pseudoScriptEngine.RgfPseudoScriptEngineFactory - diff --git a/tests/system/src/testscriptapp2/java/mymod/module-info.java b/tests/system/src/testscriptapp2/java/mymod/module-info.java new file mode 100644 index 0000000000..004112036c --- /dev/null +++ b/tests/system/src/testscriptapp2/java/mymod/module-info.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +module mymod { + requires javafx.controls; + requires javafx.fxml; + + requires java.scripting; + provides javax.script.ScriptEngineFactory with pseudoScriptEngineCompilable.RgfPseudoScriptEngineCompilableFactory; + exports pseudoScriptEngineCompilable; + exports myapp2; +} diff --git a/tests/system/src/testscriptapp2/java/mymod/myapp2/Constants.java b/tests/system/src/testscriptapp2/java/mymod/myapp2/Constants.java new file mode 100644 index 0000000000..b2aa4b2b61 --- /dev/null +++ b/tests/system/src/testscriptapp2/java/mymod/myapp2/Constants.java @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package myapp2; // verbatim from myapp6 + +public class Constants { + + public static final int SHOWTIME = 2500; + + // NOTE: these constants must match those in test.launchertest.Constants + public static final int ERROR_NONE = 2; + public static final int ERROR_UNEXPECTED_EXCEPTION = 4; + + public static final int ERROR_ASSERTION_FAILURE = 28; +} diff --git a/tests/system/src/testscriptapp2/java/mymod/myapp2/FXMLScriptDeployment2Compile_Fail_Compilation.java b/tests/system/src/testscriptapp2/java/mymod/myapp2/FXMLScriptDeployment2Compile_Fail_Compilation.java new file mode 100644 index 0000000000..a6856bb9db --- /dev/null +++ b/tests/system/src/testscriptapp2/java/mymod/myapp2/FXMLScriptDeployment2Compile_Fail_Compilation.java @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package myapp2; + +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.TreeMap; + +import javafx.application.Application; +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.fxml.FXMLLoader; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.AnchorPane; +import javafx.stage.Stage; + +import javax.script.Bindings; +import javax.script.ScriptContext; + +import static myapp2.Constants.*; +import pseudoScriptEngineCompilable.InvocationInfos; +import pseudoScriptEngineCompilable.RgfPseudoScriptEngineCompilable; + +/** + * Modular test application for testing FXML. + * This is launched by ModuleLauncherTest. + */ +public class FXMLScriptDeployment2Compile_Fail_Compilation extends Application { + + static boolean bDebug = false; // true; // display invocation list + + /** Runs the application and invokes the tests. + * @param args the command line arguments, if any given the RgfPseudoScriptEngine invocation logs get displayed + * which are used in the asserCorrectInvocations() method + */ + public static void main(String[] args) { + try { + // any argument will cause the bDebug flag to be set to true + if (args.length > 0) { + bDebug = true; + } + new FXMLScriptDeployment2Compile_Fail_Compilation().launch(); + // for debugging, allows to study invocation logs in detail + if (bDebug) { dumpEvalInformation(); } + assertCorrectInvocations(); + } catch (AssertionError ex) { + System.err.println("ASSERTION ERROR: caught unexpected exception: " + ex); + ex.printStackTrace(System.err); + System.exit(ERROR_ASSERTION_FAILURE); + } catch (Error | Exception ex) { + System.err.println("ERROR: caught unexpected exception: " + ex); + ex.printStackTrace(System.err); + System.exit(ERROR_UNEXPECTED_EXCEPTION); + } + System.exit(ERROR_NONE); // not in stop() method as we need to run the assertions first + } + + @Override + public void start(Stage mainStage) { + URL fxmlUrl = null; + Parent rootNode = null; + Scene scene = null; + Button btn = null; + try { + fxmlUrl = Util.getURL(FXMLScriptDeployment2Compile_Fail_Compilation.class, "demo_03_fail_compile"); + rootNode = FXMLLoader.load(fxmlUrl); + scene = new Scene(rootNode); + btn = (Button) scene.lookup("#idButton"); + } + catch (Exception ioe) { + ioe.printStackTrace(); + System.exit(ERROR_UNEXPECTED_EXCEPTION); + } + // fire three events on the button + btn.fire(); + btn.fireEvent(new ActionEvent()); + btn.fireEvent(new MouseEvent(MouseEvent.MOUSE_CLICKED, + 0, // double x, + 0, // double y, + 0, // double screenX, + 0, // double screenY, + MouseButton.PRIMARY, // MouseButton button, + 0, // int clickCount, + false, // boolean shiftDown, + false, // boolean controlDown, + false, // boolean altDown, + false, // boolean metaDown, + true, // boolean primaryButtonDown, + false, // boolean middleButtonDown, + false, // boolean secondaryButtonDown, + false, // boolean synthesized, + false, // boolean popupTrigger, + false, // boolean stillSincePress, + null // PickResult pickResult + ) + ); + + // mainStage.setScene(scene); + // mainStage.show(); + Platform.exit(); + } + + // show engine invocations with script text and their Bindings + static void dumpEvalInformation() { + System.err.println("\nListing eval() invocation information (invocationList):"); + + Iterator it = RgfPseudoScriptEngineCompilable.getEnginesUsed().iterator(); + while (it.hasNext()) { + RgfPseudoScriptEngineCompilable rpse = it.next(); + ArrayList invocationList = rpse.getInvocationList(); + System.err.println("ScriptEngine: [" + rpse + "]"); + + Iterator itEval = invocationList.iterator(); + int count = 1; + while (itEval.hasNext()) { + System.err.println("\teval() invocation # " + count + ": "); + InvocationInfos entry = itEval.next(); + System.err.println(entry.toDebugFormat("\t\t")); // indentation + count++; + System.err.println(); + } + } + } + + static void assertCorrectInvocations() { + // test only creates one engine for a script controller + Util.assertTrue("exactly one pseudo script engine instance", + RgfPseudoScriptEngineCompilable.getEnginesUsed().size() == 1); + RgfPseudoScriptEngineCompilable rpse = RgfPseudoScriptEngineCompilable.getEnginesUsed().get(0); + + ArrayList invocationList = rpse.getInvocationList(); + Util.assertTrue("exactly nine script engine invocations", invocationList.size() == 9); + + final String FILENAME = "javax.script.filename"; + final String ARGV = "javax.script.argv"; + final String EVENT = "event"; + final String IDBUTTON = "idButton"; + final String IDROOT = "idRoot"; + final String LOCATION = "location"; // always FXML File hosting script controller code + final String RESOURCES = "resources"; // always null in this test + + for (int invocation = 1; invocation <= invocationList.size(); invocation++) { + InvocationInfos entry = (InvocationInfos) invocationList.get(invocation - 1); + String script = entry.script; + TreeMap scopes = (TreeMap) entry.bindings; + + TreeMap engineBindings = scopes.get(100); + TreeMap globalBindings = scopes.get(200); + + Object obj = null; + Button btn = null; + + // global Bindings + Util.assertExists(IDROOT + " in global scope Bindings", globalBindings.containsKey(IDROOT)); + obj = globalBindings.get(IDROOT); + Util.assertType(IDROOT, AnchorPane.class, obj); + + Util.assertExists(LOCATION + " in global scope Bindings", globalBindings.containsKey(LOCATION)); + obj = globalBindings.get(LOCATION); + Util.assertType(LOCATION, URL.class, obj); + + Util.assertExists(RESOURCES + " in global scope Bindings", globalBindings.containsKey(RESOURCES)); + obj = globalBindings.get(RESOURCES); + Util.assertNull(RESOURCES,obj); + + if (invocation == 1) { + Util.assertNotExists(IDBUTTON + " in global scope Bindings", globalBindings.containsKey(IDBUTTON)); + } + else { + Util.assertExists(IDBUTTON + " in global scope Bindings", globalBindings.containsKey(IDBUTTON)); + obj = globalBindings.get(IDBUTTON); + Util.assertType(IDBUTTON, Button.class, obj); + btn = (Button) obj; + } + + // engine Bindings + Util.assertExists(FILENAME + " in engine scope Bindings", engineBindings.containsKey(FILENAME)); + if (invocation < 7) { // no event objects, no arguments + Util.assertNotExists(ARGV + " in engine scope Bindings", engineBindings.containsKey(ARGV)); + Util.assertNotExists(EVENT + " in engine scope Bindings", engineBindings.containsKey(EVENT)); + } + else { // this has events on the Button + Util.assertExists(ARGV + " in engine scope Bindings", engineBindings.containsKey(ARGV)); + Object[] argv = (Object[]) engineBindings.get(ARGV); + + Util.assertExists(EVENT + " in engine scope Bindings", engineBindings.containsKey(EVENT)); + obj = engineBindings.get(EVENT); + + Util.assertSame("argv[0] == event", argv[0], obj); + + if (invocation == 9) { + Util.assertType(EVENT, MouseEvent.class, obj); + MouseEvent ev = (MouseEvent) obj; + Util.assertSame("MouseEvent.getSource() == btn", ev.getSource(), btn); + Util.assertSame("MouseEvent.MOUSE_CLICKED", MouseEvent.MOUSE_CLICKED, ev.getEventType()); + } else { + Util.assertType(EVENT, ActionEvent.class, obj); + ActionEvent ev = (ActionEvent) obj; + Util.assertSame("ActionEvent.getSource() == btn", ev.getSource(), btn); + } + } + + // check filename and script + String filename = (String) engineBindings.get(FILENAME); + boolean ok = false; + switch (invocation) { + case 1: + Util.assertEndsWith ("demo_03_topscript.sqtmc", filename); + Util.assertStartsWith("demo_03_topscript.sqtmc file - pseudo script in external file, starts with the filename", script); + break; + + case 2: + Util.assertEndsWith ("demo_03_middlescript.sqtmc", filename); + Util.assertStartsWith("demo_03_middlescript.sqtmc file - pseudo script in external file, starts with the filename", script); + break; + + case 3: + Util.assertEndsWith("demo_03_fail_compile.fxml-script_starting_at_line_52", filename); + Util.assertStartsWith("demo_03_fail_compile.fxml embedded script sqtmc - line # 52", script); + break; + + case 4: + Util.assertEndsWith ("demo_03_bottomscript.sqtmc", filename); + Util.assertStartsWith("demo_03_bottomscript.sqtmc file - pseudo script in external file, starts with the filename", script); + break; + + case 5: + Util.assertEndsWith("demo_03_fail_compile.fxml-script_starting_at_line_56", filename); + Util.assertStartsWith("something (line # 56)(PCDATA)", script); + break; + + case 6: + Util.assertEndsWith("demo_03_fail_compile.fxml-script_starting_at_line_59", filename); + Util.assertStartsWith("demo_03_fail_compile.fxml (line # 59):", script); + break; + + case 7: // same as case 8 (same button clicked) + Util.assertEndsWith("demo_03_fail_compile.fxml-onAction_attribute_in_element_ending_at_line_46", filename); + Util.assertStartsWith("demo_03_fail_compile.fxml embedded event - ActionEvent - line # 45 - LF entity ( ) " + + "forces linebreak in attribute value:", script); + break; + + case 8: // same as case 7 (same button clicked) + Util.assertEndsWith("demo_03_fail_compile.fxml-onAction_attribute_in_element_ending_at_line_46", filename); + Util.assertStartsWith("demo_03_fail_compile.fxml embedded event - ActionEvent - line # 45 - LF entity ( ) " + + "forces linebreak in attribute value:", script); + break; + + case 9: + Util.assertEndsWith("demo_03_fail_compile.fxml-onMouseClicked_attribute_in_element_ending_at_line_46", filename); + Util.assertStartsWith("demo_03_fail_compile.fxml embedded event - MouseClicked - line # 44 (PCDATA)", script); + break; + } + } + } +} diff --git a/tests/system/src/testscriptapp2/java/mymod/myapp2/FXMLScriptDeployment2Compile_Off.java b/tests/system/src/testscriptapp2/java/mymod/myapp2/FXMLScriptDeployment2Compile_Off.java new file mode 100644 index 0000000000..cc56d3bbe0 --- /dev/null +++ b/tests/system/src/testscriptapp2/java/mymod/myapp2/FXMLScriptDeployment2Compile_Off.java @@ -0,0 +1,288 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package myapp2; + +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.TreeMap; + +import javafx.application.Application; +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.fxml.FXMLLoader; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.AnchorPane; +import javafx.stage.Stage; + +import javax.script.Bindings; +import javax.script.ScriptContext; + +import static myapp2.Constants.*; +import pseudoScriptEngineCompilable.InvocationInfos; +import pseudoScriptEngineCompilable.RgfPseudoScriptEngineCompilable; + +/** + * Modular test application for testing FXML. + * This is launched by ModuleLauncherTest. + */ +public class FXMLScriptDeployment2Compile_Off extends Application { + + static boolean bDebug = false; // true; // display invocation list + + /** Runs the application and invokes the tests. + * @param args the command line arguments, if any given the RgfPseudoScriptEngine invocation logs get displayed + * which are used in the asserCorrectInvocations() method + */ + public static void main(String[] args) { + try { + // any argument will cause the bDebug flag to be set to true + if (args.length > 0) { + bDebug = true; + } + new FXMLScriptDeployment2Compile_Off().launch(); + // for debugging, allows to study invocation logs in detail + if (bDebug) { dumpEvalInformation(); } + assertCorrectInvocations(); + } catch (AssertionError ex) { + System.err.println("ASSERTION ERROR: caught unexpected exception: " + ex); + ex.printStackTrace(System.err); + System.exit(ERROR_ASSERTION_FAILURE); + } catch (Error | Exception ex) { + System.err.println("ERROR: caught unexpected exception: " + ex); + ex.printStackTrace(System.err); + System.exit(ERROR_UNEXPECTED_EXCEPTION); + } + System.exit(ERROR_NONE); // not in stop() method as we need to run the assertions first + } + + @Override + public void start(Stage mainStage) { + URL fxmlUrl = null; + Parent rootNode = null; + Scene scene = null; + Button btn = null; + try { + fxmlUrl = Util.getURL(FXMLScriptDeployment2Compile_Off.class, "demo_02_off"); + rootNode = FXMLLoader.load(fxmlUrl); + scene = new Scene(rootNode); + btn = (Button) scene.lookup("#idButton"); + } + catch (Exception ioe) { + ioe.printStackTrace(); + System.exit(ERROR_UNEXPECTED_EXCEPTION); + } + // fire three events on the button + btn.fire(); + btn.fireEvent(new ActionEvent()); + btn.fireEvent(new MouseEvent(MouseEvent.MOUSE_CLICKED, + 0, // double x, + 0, // double y, + 0, // double screenX, + 0, // double screenY, + MouseButton.PRIMARY, // MouseButton button, + 0, // int clickCount, + false, // boolean shiftDown, + false, // boolean controlDown, + false, // boolean altDown, + false, // boolean metaDown, + true, // boolean primaryButtonDown, + false, // boolean middleButtonDown, + false, // boolean secondaryButtonDown, + false, // boolean synthesized, + false, // boolean popupTrigger, + false, // boolean stillSincePress, + null // PickResult pickResult + ) + ); + + // mainStage.setScene(scene); + // mainStage.show(); + Platform.exit(); + } + + // show engine invocations with script text and their Bindings + static void dumpEvalInformation() { + System.err.println("\nListing eval() invocation information (invocationList):"); + + Iterator it = RgfPseudoScriptEngineCompilable.getEnginesUsed().iterator(); + while (it.hasNext()) { + RgfPseudoScriptEngineCompilable rpse = it.next(); + ArrayList invocationList = rpse.getInvocationList(); + System.err.println("ScriptEngine: [" + rpse + "]"); + + Iterator itEval = invocationList.iterator(); + int count = 1; + while (itEval.hasNext()) { + System.err.println("\teval() invocation # " + count + ": "); + InvocationInfos entry = itEval.next(); + System.err.println(entry.toDebugFormat("\t\t")); // indentation + count++; + System.err.println(); + } + } + } + + static void assertCorrectInvocations() { + // test only creates one engine for a script controller + Util.assertTrue("exactly one pseudo script engine instance", + RgfPseudoScriptEngineCompilable.getEnginesUsed().size() == 1); + RgfPseudoScriptEngineCompilable rpse = RgfPseudoScriptEngineCompilable.getEnginesUsed().get(0); + + ArrayList invocationList = rpse.getInvocationList(); + Util.assertTrue("exactly nine script engine invocations", invocationList.size() == 9); + + final String FILENAME = "javax.script.filename"; + final String ARGV = "javax.script.argv"; + final String EVENT = "event"; + final String IDBUTTON = "idButton"; + final String IDROOT = "idRoot"; + final String LOCATION = "location"; // always FXML File hosting script controller code + final String RESOURCES = "resources"; // always null in this test + + for (int invocation = 1; invocation <= invocationList.size(); invocation++) { + InvocationInfos entry = (InvocationInfos) invocationList.get(invocation - 1); + String script = entry.script; + TreeMap scopes = (TreeMap) entry.bindings; + + TreeMap engineBindings = scopes.get(100); + TreeMap globalBindings = scopes.get(200); + + Object obj = null; + Button btn = null; + + // global Bindings + Util.assertExists(IDROOT + " in global scope Bindings", globalBindings.containsKey(IDROOT)); + obj = globalBindings.get(IDROOT); + Util.assertType(IDROOT, AnchorPane.class, obj); + + Util.assertExists(LOCATION + " in global scope Bindings", globalBindings.containsKey(LOCATION)); + obj = globalBindings.get(LOCATION); + Util.assertType(LOCATION, URL.class, obj); + + Util.assertExists(RESOURCES + " in global scope Bindings", globalBindings.containsKey(RESOURCES)); + obj = globalBindings.get(RESOURCES); + Util.assertNull(RESOURCES,obj); + + if (invocation == 1) { + Util.assertNotExists(IDBUTTON + " in global scope Bindings", globalBindings.containsKey(IDBUTTON)); + } + else { + Util.assertExists(IDBUTTON + " in global scope Bindings", globalBindings.containsKey(IDBUTTON)); + obj = globalBindings.get(IDBUTTON); + Util.assertType(IDBUTTON, Button.class, obj); + btn = (Button) obj; + } + + // engine Bindings + Util.assertExists(FILENAME + " in engine scope Bindings", engineBindings.containsKey(FILENAME)); + if (invocation < 7) { // no event objects, no arguments + Util.assertNotExists(ARGV + " in engine scope Bindings", engineBindings.containsKey(ARGV)); + Util.assertNotExists(EVENT + " in engine scope Bindings", engineBindings.containsKey(EVENT)); + } + else { // this has events on the Button + Util.assertExists(ARGV + " in engine scope Bindings", engineBindings.containsKey(ARGV)); + Object[] argv = (Object[]) engineBindings.get(ARGV); + + Util.assertExists(EVENT + " in engine scope Bindings", engineBindings.containsKey(EVENT)); + obj = engineBindings.get(EVENT); + + Util.assertSame("argv[0] == event", argv[0], obj); + + if (invocation == 9) { + Util.assertType(EVENT, MouseEvent.class, obj); + MouseEvent ev = (MouseEvent) obj; + Util.assertSame("MouseEvent.getSource() == btn", ev.getSource(), btn); + Util.assertSame("MouseEvent.MOUSE_CLICKED", MouseEvent.MOUSE_CLICKED, ev.getEventType()); + } else { + Util.assertType(EVENT, ActionEvent.class, obj); + ActionEvent ev = (ActionEvent) obj; + Util.assertSame("ActionEvent.getSource() == btn", ev.getSource(), btn); + } + } + + // check filename and script + String filename = (String) engineBindings.get(FILENAME); + boolean ok = false; + switch (invocation) { + case 1: + Util.assertEndsWith ("demo_02_topscript.sqtmc", filename); + Util.assertStartsWith("demo_02_topscript.sqtmc file - pseudo script in external file, starts with the filename", script); + break; + + case 2: + Util.assertEndsWith ("demo_02_middlescript.sqtmc", filename); + Util.assertStartsWith("demo_02_middlescript.sqtmc file - pseudo script in external file, starts with the filename", script); + break; + + case 3: + Util.assertEndsWith("demo_02_off.fxml-script_starting_at_line_52", filename); + Util.assertStartsWith("demo_02_off.fxml embedded script sqtmc - line # 52", script); + break; + + case 4: + Util.assertEndsWith ("demo_02_bottomscript.sqtmc", filename); + Util.assertStartsWith("demo_02_bottomscript.sqtmc file - pseudo script in external file, starts with the filename", script); + break; + + case 5: + Util.assertEndsWith("demo_02_off.fxml-script_starting_at_line_56", filename); + Util.assertStartsWith("something (line # 56)(PCDATA)", script); + break; + + case 6: + Util.assertEndsWith("demo_02_off.fxml-script_starting_at_line_59", filename); + Util.assertStartsWith("demo_02_off.fxml (line # 59):", script); + break; + + case 7: // same as case 8 (same button clicked) + Util.assertEndsWith("demo_02_off.fxml-onAction_attribute_in_element_ending_at_line_46", filename); + Util.assertStartsWith("demo_02_off.fxml embedded event - ActionEvent - line # 45 - LF entity ( ) " + + "forces linebreak in attribute value:", script); + break; + + case 8: // same as case 7 (same button clicked) + Util.assertEndsWith("demo_02_off.fxml-onAction_attribute_in_element_ending_at_line_46", filename); + Util.assertStartsWith("demo_02_off.fxml embedded event - ActionEvent - line # 45 - LF entity ( ) " + + "forces linebreak in attribute value:", script); + break; + + case 9: + Util.assertEndsWith("demo_02_off.fxml-onMouseClicked_attribute_in_element_ending_at_line_46", filename); + Util.assertStartsWith("demo_02_off.fxml embedded event - MouseClicked - line # 44 (PCDATA)", script); + break; + } + } + } +} diff --git a/tests/system/src/testscriptapp2/java/mymod/myapp2/FXMLScriptDeployment2Compile_Off_On.java b/tests/system/src/testscriptapp2/java/mymod/myapp2/FXMLScriptDeployment2Compile_Off_On.java new file mode 100644 index 0000000000..6091f8a1da --- /dev/null +++ b/tests/system/src/testscriptapp2/java/mymod/myapp2/FXMLScriptDeployment2Compile_Off_On.java @@ -0,0 +1,290 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package myapp2; + +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.TreeMap; + +import javafx.application.Application; +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.fxml.FXMLLoader; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.AnchorPane; +import javafx.stage.Stage; + +import javax.script.Bindings; +import javax.script.ScriptContext; + +import static myapp2.Constants.*; +import pseudoScriptEngineCompilable.InvocationInfos; +import pseudoScriptEngineCompilable.RgfPseudoScriptEngineCompilable; + +/** + * Modular test application for testing FXML. + * This is launched by ModuleLauncherTest. + */ +public class FXMLScriptDeployment2Compile_Off_On extends Application { + + static boolean bDebug = false; // true; // display invocation list + + /** Runs the application and invokes the tests. + * @param args the command line arguments, if any given the RgfPseudoScriptEngine invocation logs get displayed + * which are used in the asserCorrectInvocations() method + */ + public static void main(String[] args) { + try { + // any argument will cause the bDebug flag to be set to true + if (args.length > 0) { + bDebug = true; + } + new FXMLScriptDeployment2Compile_Off_On().launch(); + // for debugging, allows to study invocation logs in detail + if (bDebug) { dumpEvalInformation(); } + assertCorrectInvocations(); + } catch (AssertionError ex) { + System.err.println("ASSERTION ERROR: caught unexpected exception: " + ex); + ex.printStackTrace(System.err); + System.exit(ERROR_ASSERTION_FAILURE); + } catch (Error | Exception ex) { + System.err.println("ERROR: caught unexpected exception: " + ex); + ex.printStackTrace(System.err); + System.exit(ERROR_UNEXPECTED_EXCEPTION); + } + System.exit(ERROR_NONE); // not in stop() method as we need to run the assertions first + } + + @Override + public void start(Stage mainStage) { + URL fxmlUrl = null; + Parent rootNode = null; + Scene scene = null; + Button btn = null; + try { + fxmlUrl = Util.getURL(FXMLScriptDeployment2Compile_Off_On.class, "demo_02_off_on"); + rootNode = FXMLLoader.load(fxmlUrl); + scene = new Scene(rootNode); + btn = (Button) scene.lookup("#idButton"); + } + catch (Exception ioe) { + ioe.printStackTrace(); + System.exit(ERROR_UNEXPECTED_EXCEPTION); + } + // fire three events on the button + btn.fire(); + btn.fireEvent(new ActionEvent()); + btn.fireEvent(new MouseEvent(MouseEvent.MOUSE_CLICKED, + 0, // double x, + 0, // double y, + 0, // double screenX, + 0, // double screenY, + MouseButton.PRIMARY, // MouseButton button, + 0, // int clickCount, + false, // boolean shiftDown, + false, // boolean controlDown, + false, // boolean altDown, + false, // boolean metaDown, + true, // boolean primaryButtonDown, + false, // boolean middleButtonDown, + false, // boolean secondaryButtonDown, + false, // boolean synthesized, + false, // boolean popupTrigger, + false, // boolean stillSincePress, + null // PickResult pickResult + ) + ); + + // mainStage.setScene(scene); + // mainStage.show(); + Platform.exit(); + } + + // show engine invocations with script text and their Bindings + static void dumpEvalInformation() { + System.err.println("\nListing eval() invocation information (invocationList):"); + + Iterator it = RgfPseudoScriptEngineCompilable.getEnginesUsed().iterator(); + while (it.hasNext()) { + RgfPseudoScriptEngineCompilable rpse = it.next(); + ArrayList invocationList = rpse.getInvocationList(); + System.err.println("ScriptEngine: [" + rpse + "]"); + + Iterator itEval = invocationList.iterator(); + int count = 1; + while (itEval.hasNext()) { + System.err.println("\teval() invocation # " + count + ": "); + InvocationInfos entry = itEval.next(); + System.err.println(entry.toDebugFormat("\t\t")); // indentation + count++; + System.err.println(); + } + } + } + + static void assertCorrectInvocations() { + // test only creates one engine for a script controller + Util.assertTrue("exactly one pseudo script engine instance", + RgfPseudoScriptEngineCompilable.getEnginesUsed().size() == 1); + RgfPseudoScriptEngineCompilable rpse = RgfPseudoScriptEngineCompilable.getEnginesUsed().get(0); + + ArrayList invocationList = rpse.getInvocationList(); + Util.assertTrue("exactly nine script engine invocations", invocationList.size() == 9); + + final String FILENAME = "javax.script.filename"; + final String ARGV = "javax.script.argv"; + final String EVENT = "event"; + final String IDBUTTON = "idButton"; + final String IDROOT = "idRoot"; + final String LOCATION = "location"; // always FXML File hosting script controller code + final String RESOURCES = "resources"; // always null in this test + + for (int invocation = 1; invocation <= invocationList.size(); invocation++) { + InvocationInfos entry = (InvocationInfos) invocationList.get(invocation - 1); + String script = entry.script; + TreeMap scopes = (TreeMap) entry.bindings; + + TreeMap engineBindings = scopes.get(100); + TreeMap globalBindings = scopes.get(200); + + Object obj = null; + Button btn = null; + + // global Bindings + Util.assertExists(IDROOT + " in global scope Bindings", globalBindings.containsKey(IDROOT)); + obj = globalBindings.get(IDROOT); + Util.assertType(IDROOT, AnchorPane.class, obj); + + Util.assertExists(LOCATION + " in global scope Bindings", globalBindings.containsKey(LOCATION)); + obj = globalBindings.get(LOCATION); + Util.assertType(LOCATION, URL.class, obj); + + Util.assertExists(RESOURCES + " in global scope Bindings", globalBindings.containsKey(RESOURCES)); + obj = globalBindings.get(RESOURCES); + Util.assertNull(RESOURCES,obj); + + if (invocation == 1) { + Util.assertNotExists(IDBUTTON + " in global scope Bindings", globalBindings.containsKey(IDBUTTON)); + } + else { + Util.assertExists(IDBUTTON + " in global scope Bindings", globalBindings.containsKey(IDBUTTON)); + obj = globalBindings.get(IDBUTTON); + Util.assertType(IDBUTTON, Button.class, obj); + btn = (Button) obj; + } + + // engine Bindings + Util.assertExists(FILENAME + " in engine scope Bindings", engineBindings.containsKey(FILENAME)); + if (invocation < 7) { // no event objects, no arguments + Util.assertNotExists(ARGV + " in engine scope Bindings", engineBindings.containsKey(ARGV)); + Util.assertNotExists(EVENT + " in engine scope Bindings", engineBindings.containsKey(EVENT)); + } + else { // this has events on the Button + Util.assertExists(ARGV + " in engine scope Bindings", engineBindings.containsKey(ARGV)); + Object[] argv = (Object[]) engineBindings.get(ARGV); + + Util.assertExists(EVENT + " in engine scope Bindings", engineBindings.containsKey(EVENT)); + obj = engineBindings.get(EVENT); + + Util.assertSame("argv[0] == event", argv[0], obj); + + if (invocation == 9) { + Util.assertType(EVENT, MouseEvent.class, obj); + MouseEvent ev = (MouseEvent) obj; + Util.assertSame("MouseEvent.getSource() == btn", ev.getSource(), btn); + Util.assertSame("MouseEvent.MOUSE_CLICKED", MouseEvent.MOUSE_CLICKED, ev.getEventType()); + } else { + Util.assertType(EVENT, ActionEvent.class, obj); + ActionEvent ev = (ActionEvent) obj; + Util.assertSame("ActionEvent.getSource() == btn", ev.getSource(), btn); + } + } + + // check filename and script + String filename = (String) engineBindings.get(FILENAME); + boolean ok = false; + switch (invocation) { + case 1: + Util.assertEndsWith ("demo_02_topscript.sqtmc", filename); + Util.assertStartsWith("demo_02_topscript.sqtmc file - pseudo script in external file, starts with the filename", script); + break; + + case 2: + Util.assertEndsWith ("demo_02_middlescript.sqtmc", filename); + Util.assertStartsWith("demo_02_middlescript.sqtmc file - pseudo script in external file, starts with the filename", script); + break; + + case 3: + Util.assertEndsWith("demo_02_off_on.fxml-script_starting_at_line_52", filename); + Util.assertStartsWith("demo_02_off_on.fxml embedded script sqtmc - line # 52", script); + break; + + case 4: + Util.assertEndsWith ("demo_02_bottomscript.sqtmc", filename); + Util.assertStartsWith("RgfPseudoCompiledScript.eval(): RgfPseudoCompiledScript=[demo_02_bottomscript.sqtmc file - " + + "pseudo script", script); + break; + + case 5: + Util.assertEndsWith("demo_02_off_on.fxml-script_starting_at_line_56", filename); + Util.assertStartsWith("something (line # 56)(PCDATA)", script); + break; + + case 6: + Util.assertEndsWith("demo_02_off_on.fxml-script_starting_at_line_59", filename); + Util.assertStartsWith("RgfPseudoCompiledScript.eval(): RgfPseudoCompiledScript=[demo_02_off_on.fxml (line # 59):", script); + break; + + case 7: // same as case 8 (same button clicked) + Util.assertEndsWith("demo_02_off_on.fxml-onAction_attribute_in_element_ending_at_line_46", filename); + Util.assertStartsWith("RgfPseudoCompiledScript.eval(Bindings bindings): RgfPseudoCompiledScript=[demo_02_off_on.fxml " + + "embedded event - ActionEvent - line # 45 -", script); + break; + + case 8: // same as case 7 (same button clicked) + Util.assertEndsWith("demo_02_off_on.fxml-onAction_attribute_in_element_ending_at_line_46", filename); + Util.assertStartsWith("RgfPseudoCompiledScript.eval(Bindings bindings): RgfPseudoCompiledScript=[demo_02_off_on.fxml " + + "embedded event - ActionEvent - line # 45 -", script); + break; + + case 9: + Util.assertEndsWith("demo_02_off_on.fxml-onMouseClicked_attribute_in_element_ending_at_line_46", filename); + Util.assertStartsWith("RgfPseudoCompiledScript.eval(Bindings bindings): RgfPseudoCompiledScript=[demo_02_off_on.fxml " + + "embedded event - MouseClicked - line # 44", script); + break; + } + } + } +} diff --git a/tests/system/src/testscriptapp2/java/mymod/myapp2/FXMLScriptDeployment2Compile_On.java b/tests/system/src/testscriptapp2/java/mymod/myapp2/FXMLScriptDeployment2Compile_On.java new file mode 100644 index 0000000000..c965330f66 --- /dev/null +++ b/tests/system/src/testscriptapp2/java/mymod/myapp2/FXMLScriptDeployment2Compile_On.java @@ -0,0 +1,293 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package myapp2; + +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.TreeMap; + +import javafx.application.Application; +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.fxml.FXMLLoader; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.AnchorPane; +import javafx.stage.Stage; + +import javax.script.Bindings; +import javax.script.ScriptContext; + +import static myapp2.Constants.*; +import pseudoScriptEngineCompilable.InvocationInfos; +import pseudoScriptEngineCompilable.RgfPseudoScriptEngineCompilable; + +/** + * Modular test application for testing FXML. + * This is launched by ModuleLauncherTest. + */ +public class FXMLScriptDeployment2Compile_On extends Application { + + static boolean bDebug = false; // true; // display invocation list + + /** Runs the application and invokes the tests. + * @param args the command line arguments, if any given the RgfPseudoScriptEngine invocation logs get displayed + * which are used in the asserCorrectInvocations() method + */ + public static void main(String[] args) { + try { + // any argument will cause the bDebug flag to be set to true + if (args.length > 0) { + bDebug = true; + } + new FXMLScriptDeployment2Compile_On().launch(); + // for debugging, allows to study invocation logs in detail + if (bDebug) { dumpEvalInformation(); } + assertCorrectInvocations(); + } catch (AssertionError ex) { + System.err.println("ASSERTION ERROR: caught unexpected exception: " + ex); + ex.printStackTrace(System.err); + System.exit(ERROR_ASSERTION_FAILURE); + } catch (Error | Exception ex) { + System.err.println("ERROR: caught unexpected exception: " + ex); + ex.printStackTrace(System.err); + System.exit(ERROR_UNEXPECTED_EXCEPTION); + } + System.exit(ERROR_NONE); // not in stop() method as we need to run the assertions first + } + + @Override + public void start(Stage mainStage) { + URL fxmlUrl = null; + Parent rootNode = null; + Scene scene = null; + Button btn = null; + try { + fxmlUrl = Util.getURL(FXMLScriptDeployment2Compile_On.class, "demo_02_on"); + rootNode = FXMLLoader.load(fxmlUrl); + scene = new Scene(rootNode); + btn = (Button) scene.lookup("#idButton"); + } + catch (Exception ioe) { + ioe.printStackTrace(); + System.exit(ERROR_UNEXPECTED_EXCEPTION); + } + // fire three events on the button + btn.fire(); + btn.fireEvent(new ActionEvent()); + btn.fireEvent(new MouseEvent(MouseEvent.MOUSE_CLICKED, + 0, // double x, + 0, // double y, + 0, // double screenX, + 0, // double screenY, + MouseButton.PRIMARY, // MouseButton button, + 0, // int clickCount, + false, // boolean shiftDown, + false, // boolean controlDown, + false, // boolean altDown, + false, // boolean metaDown, + true, // boolean primaryButtonDown, + false, // boolean middleButtonDown, + false, // boolean secondaryButtonDown, + false, // boolean synthesized, + false, // boolean popupTrigger, + false, // boolean stillSincePress, + null // PickResult pickResult + ) + ); + + // mainStage.setScene(scene); + // mainStage.show(); + Platform.exit(); + } + + // show engine invocations with script text and their Bindings + static void dumpEvalInformation() { + System.err.println("\nListing eval() invocation information (invocationList):"); + + Iterator it = RgfPseudoScriptEngineCompilable.getEnginesUsed().iterator(); + while (it.hasNext()) { + RgfPseudoScriptEngineCompilable rpse = it.next(); + ArrayList invocationList = rpse.getInvocationList(); + System.err.println("ScriptEngine: [" + rpse + "]"); + + Iterator itEval = invocationList.iterator(); + int count = 1; + while (itEval.hasNext()) { + System.err.println("\teval() invocation # " + count + ": "); + InvocationInfos entry = itEval.next(); + System.err.println(entry.toDebugFormat("\t\t")); // indentation + count++; + System.err.println(); + } + } + } + + static void assertCorrectInvocations() { + // test only creates one engine for a script controller + Util.assertTrue("exactly one pseudo script engine instance", + RgfPseudoScriptEngineCompilable.getEnginesUsed().size() == 1); + RgfPseudoScriptEngineCompilable rpse = RgfPseudoScriptEngineCompilable.getEnginesUsed().get(0); + + ArrayList invocationList = rpse.getInvocationList(); + Util.assertTrue("exactly nine script engine invocations", invocationList.size() == 9); + + final String FILENAME = "javax.script.filename"; + final String ARGV = "javax.script.argv"; + final String EVENT = "event"; + final String IDBUTTON = "idButton"; + final String IDROOT = "idRoot"; + final String LOCATION = "location"; // always FXML File hosting script controller code + final String RESOURCES = "resources"; // always null in this test + + for (int invocation = 1; invocation <= invocationList.size(); invocation++) { + InvocationInfos entry = (InvocationInfos) invocationList.get(invocation - 1); + String script = entry.script; + TreeMap scopes = (TreeMap) entry.bindings; + + TreeMap engineBindings = scopes.get(100); + TreeMap globalBindings = scopes.get(200); + + Object obj = null; + Button btn = null; + + // global Bindings + Util.assertExists(IDROOT + " in global scope Bindings", globalBindings.containsKey(IDROOT)); + obj = globalBindings.get(IDROOT); + Util.assertType(IDROOT, AnchorPane.class, obj); + + Util.assertExists(LOCATION + " in global scope Bindings", globalBindings.containsKey(LOCATION)); + obj = globalBindings.get(LOCATION); + Util.assertType(LOCATION, URL.class, obj); + + Util.assertExists(RESOURCES + " in global scope Bindings", globalBindings.containsKey(RESOURCES)); + obj = globalBindings.get(RESOURCES); + Util.assertNull(RESOURCES,obj); + + if (invocation == 1) { + Util.assertNotExists(IDBUTTON + " in global scope Bindings", globalBindings.containsKey(IDBUTTON)); + } + else { + Util.assertExists(IDBUTTON + " in global scope Bindings", globalBindings.containsKey(IDBUTTON)); + obj = globalBindings.get(IDBUTTON); + Util.assertType(IDBUTTON, Button.class, obj); + btn = (Button) obj; + } + + // engine Bindings + Util.assertExists(FILENAME + " in engine scope Bindings", engineBindings.containsKey(FILENAME)); + if (invocation < 7) { // no event objects, no arguments + Util.assertNotExists(ARGV + " in engine scope Bindings", engineBindings.containsKey(ARGV)); + Util.assertNotExists(EVENT + " in engine scope Bindings", engineBindings.containsKey(EVENT)); + } + else { // this has events on the Button + Util.assertExists(ARGV + " in engine scope Bindings", engineBindings.containsKey(ARGV)); + Object[] argv = (Object[]) engineBindings.get(ARGV); + + Util.assertExists(EVENT + " in engine scope Bindings", engineBindings.containsKey(EVENT)); + obj = engineBindings.get(EVENT); + + Util.assertSame("argv[0] == event", argv[0], obj); + + if (invocation == 9) { + Util.assertType(EVENT, MouseEvent.class, obj); + MouseEvent ev = (MouseEvent) obj; + Util.assertSame("MouseEvent.getSource() == btn", ev.getSource(), btn); + Util.assertSame("MouseEvent.MOUSE_CLICKED", MouseEvent.MOUSE_CLICKED, ev.getEventType()); + } else { + Util.assertType(EVENT, ActionEvent.class, obj); + ActionEvent ev = (ActionEvent) obj; + Util.assertSame("ActionEvent.getSource() == btn", ev.getSource(), btn); + } + } + + // check filename and script + String filename = (String) engineBindings.get(FILENAME); + boolean ok = false; + switch (invocation) { + case 1: + Util.assertEndsWith ("demo_02_topscript.sqtmc", filename); + Util.assertStartsWith("RgfPseudoCompiledScript.eval(): RgfPseudoCompiledScript=[demo_02_topscript.sqtmc " + + "file - pseudo script", script); + break; + + case 2: + Util.assertEndsWith ("demo_02_middlescript.sqtmc", filename); + Util.assertStartsWith("RgfPseudoCompiledScript.eval(): RgfPseudoCompiledScript=[demo_02_middlescript.sqtmc " + + "file - pseudo script", script); + break; + + case 3: + Util.assertEndsWith("demo_02_on.fxml-script_starting_at_line_52", filename); + Util.assertStartsWith("RgfPseudoCompiledScript.eval(): RgfPseudoCompiledScript=[demo_02_on.fxml embedded " + + "script sqtmc - line # 52", script); + break; + + case 4: + Util.assertEndsWith ("demo_02_bottomscript.sqtmc", filename); + Util.assertStartsWith("RgfPseudoCompiledScript.eval(): RgfPseudoCompiledScript=[demo_02_bottomscript.sqtmc " + + "file - pseudo script", script); + break; + + case 5: + Util.assertEndsWith("demo_02_on.fxml-script_starting_at_line_56", filename); + Util.assertStartsWith("RgfPseudoCompiledScript.eval(): RgfPseudoCompiledScript=[something (line # 56)", script); + break; + + case 6: + Util.assertEndsWith("demo_02_on.fxml-script_starting_at_line_59", filename); + Util.assertStartsWith("RgfPseudoCompiledScript.eval(): RgfPseudoCompiledScript=[demo_02_on.fxml (line # 59):", script); + break; + + case 7: // same as case 8 (same button clicked) + Util.assertEndsWith("demo_02_on.fxml-onAction_attribute_in_element_ending_at_line_46", filename); + Util.assertStartsWith("RgfPseudoCompiledScript.eval(Bindings bindings): RgfPseudoCompiledScript=[demo_02_on.fxml " + + "embedded event - ActionEvent - line # 45 -", script); + break; + + case 8: // same as case 7 (same button clicked) + Util.assertEndsWith("demo_02_on.fxml-onAction_attribute_in_element_ending_at_line_46", filename); + Util.assertStartsWith("RgfPseudoCompiledScript.eval(Bindings bindings): RgfPseudoCompiledScript=[demo_02_on.fxml " + + "embedded event - ActionEvent - line # 45 -", script); + break; + + case 9: + Util.assertEndsWith("demo_02_on.fxml-onMouseClicked_attribute_in_element_ending_at_line_46", filename); + Util.assertStartsWith("RgfPseudoCompiledScript.eval(Bindings bindings): RgfPseudoCompiledScript=[demo_02_on.fxml " + + "embedded event - MouseClicked - line # 44", script); + break; + } + } + } +} diff --git a/tests/system/src/testscriptapp2/java/mymod/myapp2/FXMLScriptDeployment2Compile_On_Off.java b/tests/system/src/testscriptapp2/java/mymod/myapp2/FXMLScriptDeployment2Compile_On_Off.java new file mode 100644 index 0000000000..07f51a838d --- /dev/null +++ b/tests/system/src/testscriptapp2/java/mymod/myapp2/FXMLScriptDeployment2Compile_On_Off.java @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package myapp2; + +import java.io.IOException; +import java.net.URL; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.TreeMap; + +import javafx.application.Application; +import javafx.application.Platform; +import javafx.event.ActionEvent; +import javafx.fxml.FXMLLoader; +import javafx.scene.Node; +import javafx.scene.Parent; +import javafx.scene.Scene; +import javafx.scene.control.Button; +import javafx.scene.input.MouseButton; +import javafx.scene.input.MouseEvent; +import javafx.scene.layout.AnchorPane; +import javafx.stage.Stage; + +import javax.script.Bindings; +import javax.script.ScriptContext; + +import static myapp2.Constants.*; +import pseudoScriptEngineCompilable.InvocationInfos; +import pseudoScriptEngineCompilable.RgfPseudoScriptEngineCompilable; + +/** + * Modular test application for testing FXML. + * This is launched by ModuleLauncherTest. + */ +public class FXMLScriptDeployment2Compile_On_Off extends Application { + + static boolean bDebug = false; // true; // display invocation list + + /** Runs the application and invokes the tests. + * @param args the command line arguments, if any given the RgfPseudoScriptEngine invocation logs get displayed + * which are used in the asserCorrectInvocations() method + */ + public static void main(String[] args) { + try { + // any argument will cause the bDebug flag to be set to true + if (args.length > 0) { + bDebug = true; + } + new FXMLScriptDeployment2Compile_On_Off().launch(); + // for debugging, allows to study invocation logs in detail + if (bDebug) { dumpEvalInformation(); } + assertCorrectInvocations(); + } catch (AssertionError ex) { + System.err.println("ASSERTION ERROR: caught unexpected exception: " + ex); + ex.printStackTrace(System.err); + System.exit(ERROR_ASSERTION_FAILURE); + } catch (Error | Exception ex) { + System.err.println("ERROR: caught unexpected exception: " + ex); + ex.printStackTrace(System.err); + System.exit(ERROR_UNEXPECTED_EXCEPTION); + } + System.exit(ERROR_NONE); // not in stop() method as we need to run the assertions first + } + + @Override + public void start(Stage mainStage) { + URL fxmlUrl = null; + Parent rootNode = null; + Scene scene = null; + Button btn = null; + try { + fxmlUrl = Util.getURL(FXMLScriptDeployment2Compile_On_Off.class, "demo_02_on_off"); + rootNode = FXMLLoader.load(fxmlUrl); + scene = new Scene(rootNode); + btn = (Button) scene.lookup("#idButton"); + } + catch (Exception ioe) { + ioe.printStackTrace(); + System.exit(ERROR_UNEXPECTED_EXCEPTION); + } + // fire three events on the button + btn.fire(); + btn.fireEvent(new ActionEvent()); + btn.fireEvent(new MouseEvent(MouseEvent.MOUSE_CLICKED, + 0, // double x, + 0, // double y, + 0, // double screenX, + 0, // double screenY, + MouseButton.PRIMARY, // MouseButton button, + 0, // int clickCount, + false, // boolean shiftDown, + false, // boolean controlDown, + false, // boolean altDown, + false, // boolean metaDown, + true, // boolean primaryButtonDown, + false, // boolean middleButtonDown, + false, // boolean secondaryButtonDown, + false, // boolean synthesized, + false, // boolean popupTrigger, + false, // boolean stillSincePress, + null // PickResult pickResult + ) + ); + + // mainStage.setScene(scene); + // mainStage.show(); + Platform.exit(); + } + + // show engine invocations with script text and their Bindings + static void dumpEvalInformation() { + System.err.println("\nListing eval() invocation information (invocationList):"); + + Iterator it = RgfPseudoScriptEngineCompilable.getEnginesUsed().iterator(); + while (it.hasNext()) { + RgfPseudoScriptEngineCompilable rpse = it.next(); + ArrayList invocationList = rpse.getInvocationList(); + System.err.println("ScriptEngine: [" + rpse + "]"); + + Iterator itEval = invocationList.iterator(); + int count = 1; + while (itEval.hasNext()) { + System.err.println("\teval() invocation # " + count + ": "); + InvocationInfos entry = itEval.next(); + System.err.println(entry.toDebugFormat("\t\t")); // indentation + count++; + System.err.println(); + } + } + } + + static void assertCorrectInvocations() { + // test only creates one engine for a script controller + Util.assertTrue("exactly one pseudo script engine instance", + RgfPseudoScriptEngineCompilable.getEnginesUsed().size() == 1); + RgfPseudoScriptEngineCompilable rpse = RgfPseudoScriptEngineCompilable.getEnginesUsed().get(0); + + ArrayList invocationList = rpse.getInvocationList(); + Util.assertTrue("exactly nine script engine invocations", invocationList.size() == 9); + + final String FILENAME = "javax.script.filename"; + final String ARGV = "javax.script.argv"; + final String EVENT = "event"; + final String IDBUTTON = "idButton"; + final String IDROOT = "idRoot"; + final String LOCATION = "location"; // always FXML File hosting script controller code + final String RESOURCES = "resources"; // always null in this test + + for (int invocation = 1; invocation <= invocationList.size(); invocation++) { + InvocationInfos entry = (InvocationInfos) invocationList.get(invocation - 1); + String script = entry.script; + TreeMap scopes = (TreeMap) entry.bindings; + + TreeMap engineBindings = scopes.get(100); + TreeMap globalBindings = scopes.get(200); + + Object obj = null; + Button btn = null; + + // global Bindings + Util.assertExists(IDROOT + " in global scope Bindings", globalBindings.containsKey(IDROOT)); + obj = globalBindings.get(IDROOT); + Util.assertType(IDROOT, AnchorPane.class, obj); + + Util.assertExists(LOCATION + " in global scope Bindings", globalBindings.containsKey(LOCATION)); + obj = globalBindings.get(LOCATION); + Util.assertType(LOCATION, URL.class, obj); + + Util.assertExists(RESOURCES + " in global scope Bindings", globalBindings.containsKey(RESOURCES)); + obj = globalBindings.get(RESOURCES); + Util.assertNull(RESOURCES,obj); + + if (invocation == 1) { + Util.assertNotExists(IDBUTTON + " in global scope Bindings", globalBindings.containsKey(IDBUTTON)); + } + else { + Util.assertExists(IDBUTTON + " in global scope Bindings", globalBindings.containsKey(IDBUTTON)); + obj = globalBindings.get(IDBUTTON); + Util.assertType(IDBUTTON, Button.class, obj); + btn = (Button) obj; + } + + // engine Bindings + Util.assertExists(FILENAME + " in engine scope Bindings", engineBindings.containsKey(FILENAME)); + if (invocation < 7) { // no event objects, no arguments + Util.assertNotExists(ARGV + " in engine scope Bindings", engineBindings.containsKey(ARGV)); + Util.assertNotExists(EVENT + " in engine scope Bindings", engineBindings.containsKey(EVENT)); + } + else { // this has events on the Button + Util.assertExists(ARGV + " in engine scope Bindings", engineBindings.containsKey(ARGV)); + Object[] argv = (Object[]) engineBindings.get(ARGV); + + Util.assertExists(EVENT + " in engine scope Bindings", engineBindings.containsKey(EVENT)); + obj = engineBindings.get(EVENT); + + Util.assertSame("argv[0] == event", argv[0], obj); + + if (invocation == 9) { + Util.assertType(EVENT, MouseEvent.class, obj); + MouseEvent ev = (MouseEvent) obj; + Util.assertSame("MouseEvent.getSource() == btn", ev.getSource(), btn); + Util.assertSame("MouseEvent.MOUSE_CLICKED", MouseEvent.MOUSE_CLICKED, ev.getEventType()); + } else { + Util.assertType(EVENT, ActionEvent.class, obj); + ActionEvent ev = (ActionEvent) obj; + Util.assertSame("ActionEvent.getSource() == btn", ev.getSource(), btn); + } + } + + // check filename and script + String filename = (String) engineBindings.get(FILENAME); + boolean ok = false; + switch (invocation) { + case 1: + Util.assertEndsWith ("demo_02_topscript.sqtmc", filename); + Util.assertStartsWith("RgfPseudoCompiledScript.eval(): RgfPseudoCompiledScript=[demo_02_topscript.sqtmc file - " + + "pseudo script", script); + break; + + case 2: + Util.assertEndsWith ("demo_02_middlescript.sqtmc", filename); + Util.assertStartsWith("RgfPseudoCompiledScript.eval(): RgfPseudoCompiledScript=[demo_02_middlescript.sqtmc file - " + + "pseudo script", script); + break; + + case 3: + Util.assertEndsWith("demo_02_on_off.fxml-script_starting_at_line_52", filename); + Util.assertStartsWith("demo_02_on_off.fxml embedded script sqtmc - line # 52", script); + break; + + case 4: + Util.assertEndsWith ("demo_02_bottomscript.sqtmc", filename); + Util.assertStartsWith("RgfPseudoCompiledScript.eval(): RgfPseudoCompiledScript=[demo_02_bottomscript.sqtmc file - " + + "pseudo script", script); + break; + + case 5: + Util.assertEndsWith("demo_02_on_off.fxml-script_starting_at_line_56", filename); + Util.assertStartsWith("something (line # 56)(PCDATA)", script); + break; + + case 6: + Util.assertEndsWith("demo_02_on_off.fxml-script_starting_at_line_59", filename); + Util.assertStartsWith("RgfPseudoCompiledScript.eval(): RgfPseudoCompiledScript=[demo_02_on_off.fxml (line # 59):", script); + break; + + case 7: // same as case 8 (same button clicked) + Util.assertEndsWith("demo_02_on_off.fxml-onAction_attribute_in_element_ending_at_line_46", filename); + Util.assertStartsWith("demo_02_on_off.fxml embedded event - ActionEvent - line # 45 - LF entity ( ) forces " + + "linebreak", script); + break; + + case 8: // same as case 7 (same button clicked) + Util.assertEndsWith("demo_02_on_off.fxml-onAction_attribute_in_element_ending_at_line_46", filename); + Util.assertStartsWith("demo_02_on_off.fxml embedded event - ActionEvent - line # 45 - LF entity ( ) forces " + + "linebreak", script); + break; + + case 9: + Util.assertEndsWith("demo_02_on_off.fxml-onMouseClicked_attribute_in_element_ending_at_line_46", filename); + Util.assertStartsWith("demo_02_on_off.fxml embedded event - MouseClicked - line # 44 (PCDATA)", script); + break; + } + } + } +} diff --git a/tests/system/src/testscriptapp2/java/mymod/myapp2/Util.java b/tests/system/src/testscriptapp2/java/mymod/myapp2/Util.java new file mode 100644 index 0000000000..a1c6cfd646 --- /dev/null +++ b/tests/system/src/testscriptapp2/java/mymod/myapp2/Util.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2017, 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package myapp2; + +import java.net.URL; + +public class Util { + + public static final URL getURL(Class clazz, String name) { + final String theName = name + ".fxml"; + final URL fxmlFile = clazz.getResource(theName); + if (fxmlFile == null) { + throw new AssertionError("(getURL()) unable to open: " + theName); + } + return fxmlFile; + } + + public static void assertNull(String message, Object o) { + if (o != null) { + throw new AssertionError("(assertNull) " + message + ", expected null object, but was non-null"); + } + } + + public static void assertNotNull(Object o) { + if (o == null) { + throw new AssertionError("(assertNotNull) expected non-null object, but was null"); + } + } + + public static void assertEndsWith(String expected, String observed) { + if ((expected == null && observed != null) || !observed.endsWith(expected)) { + throw new AssertionError("(assertEndsWith) " + "expected: <" + expected + "> but was: <" + observed + ">"); + } + } + + public static void assertStartsWith(String expected, String observed) { + if ((expected == null && observed != null) || !observed.startsWith(expected)) { + throw new AssertionError("(assertStartsWith) " + "expected: <" + expected + "> but was: <" + observed + ">"); + } + } + + + public static void assertSame(String message, Object expected, Object observed) { + if (expected != observed) { + throw new AssertionError("(assertSame) "+ message + ", expected: <" + expected + "> but was: <" + observed + ">"); + } + } + + public static void assertTrue(String message, boolean cond) { + if (!cond) { + throw new AssertionError("(assertTrue): " + message); + } + } + + public static void assertFalse(String message, boolean cond) { + if (cond) { + throw new AssertionError("(assertFalse): " + message); + } + } + + public static void assertExists(String message, boolean cond) { + if (!cond) { + throw new AssertionError("(assertExists): " + message); + } + } + + public static void assertNotExists(String message, boolean cond) { + if (cond) { + throw new AssertionError("(assertNotExists): " + message); + } + } + + public static void assertType(String message, Class clz, Object obj) { + if (obj == null) { + throw new AssertionError("(assertType): " + message+": \"obj\" is null"); + } + else if (clz == null) { + throw new AssertionError("(assertType): " + message+": \"clz\" is null"); + } + + if (! clz.isInstance(obj)) { + throw new AssertionError("(assertType): " + message + + ", object " + obj + + " is not an instance of class " + + clz + " -> " + clz.getName() + "]"); + } + } + + private Util() { + } +} diff --git a/tests/system/src/testscriptapp2/java/mymod/pseudoScriptEngineCompilable/InvocationInfos.java b/tests/system/src/testscriptapp2/java/mymod/pseudoScriptEngineCompilable/InvocationInfos.java new file mode 100644 index 0000000000..5e9391641e --- /dev/null +++ b/tests/system/src/testscriptapp2/java/mymod/pseudoScriptEngineCompilable/InvocationInfos.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pseudoScriptEngineCompilable; + +import javax.script.Bindings; +import javax.script.ScriptContext; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Set; +import java.util.TreeMap; + + +/** Stores PseudoScriptEngine related invocation information for asserting and debugging. */ +public class InvocationInfos { + public String script; + public TreeMap> bindings; + public Instant dateTime; + + InvocationInfos(String script, ScriptContext context) { + this.dateTime = Instant.now(); + this.script = script; + this.bindings = new TreeMap(); + // get and save each Bindings + for (Integer scope : context.getScopes()) { + Bindings binding = context.getBindings(scope); + bindings.put(scope, binding == null ? new TreeMap() : new TreeMap(binding)); + } + } + + /** + * Creates and returns a string having all information formatted to ease debugging. + * @return string formatted to ease debugging + */ + public String toDebugFormat(String indentation) { + StringBuilder sb = new StringBuilder(); + String indent = (indentation == null ? "\t\t" : indentation); + sb.append(indent).append("at: [").append(dateTime.toString()).append("]\n"); + sb.append(indent).append("script: [").append(script) .append("]\n"); + + for (Integer scope : (Set) bindings.keySet()) { + sb.append(indent).append("Bindings for scope # ").append(scope); + if (scope == 100) sb.append(" (ENGINE_SCOPE):"); + else if (scope == 200) sb.append(" (GLOBAL_SCOPE):"); + else sb.append(':'); + sb.append('\n'); + + TreeMap treeMap = bindings.get(scope); + for (String k : (Set) treeMap.keySet()) { + sb.append(indent).append("\t[").append(k).append("]:\t[").append(treeMap.get(k)).append("]\n"); + } + } + return sb.toString(); + } +} diff --git a/tests/system/src/testscriptapp2/java/mymod/pseudoScriptEngineCompilable/RgfPseudoCompiledScript.java b/tests/system/src/testscriptapp2/java/mymod/pseudoScriptEngineCompilable/RgfPseudoCompiledScript.java new file mode 100644 index 0000000000..dbdb0e7243 --- /dev/null +++ b/tests/system/src/testscriptapp2/java/mymod/pseudoScriptEngineCompilable/RgfPseudoCompiledScript.java @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pseudoScriptEngineCompilable; + +import javax.script.Bindings; +import javax.script.CompiledScript; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptException; + +public class RgfPseudoCompiledScript extends CompiledScript { + String code = null; + ScriptEngine scriptEngine = null; + + RgfPseudoCompiledScript(String code, ScriptEngine scriptEngine) { + this.code = code; + this.scriptEngine = scriptEngine; + } + + public Object eval(Bindings bindings) throws ScriptException { + return scriptEngine.eval("RgfPseudoCompiledScript.eval(Bindings bindings): " + code, bindings); + } + + public Object eval(ScriptContext context) throws ScriptException { + return scriptEngine.eval("RgfPseudoCompiledScript.eval(ScriptContext context): " + code, context); + } + + public Object eval() throws ScriptException { + return scriptEngine.eval("RgfPseudoCompiledScript.eval(): " + code ); + } + + public ScriptEngine getEngine() { + return scriptEngine; + } +} diff --git a/tests/system/src/testscriptapp2/java/mymod/pseudoScriptEngineCompilable/RgfPseudoScriptEngineCompilable.java b/tests/system/src/testscriptapp2/java/mymod/pseudoScriptEngineCompilable/RgfPseudoScriptEngineCompilable.java new file mode 100644 index 0000000000..69b8675f7b --- /dev/null +++ b/tests/system/src/testscriptapp2/java/mymod/pseudoScriptEngineCompilable/RgfPseudoScriptEngineCompilable.java @@ -0,0 +1,141 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pseudoScriptEngineCompilable; + +import javax.script.Bindings; +import javax.script.ScriptContext; +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; +import javax.script.ScriptException; + +import javax.script.Compilable; +import javax.script.CompiledScript; + +import javax.script.AbstractScriptEngine; +import javax.script.SimpleScriptContext; +import javax.script.SimpleBindings; + +import java.util.ArrayList; +import java.util.Set; +import java.util.TreeMap; +import java.io.Reader; +import java.io.BufferedReader; +import java.io.IOException; + +import java.time.Instant; + +public class RgfPseudoScriptEngineCompilable extends AbstractScriptEngine implements Compilable { + static final boolean bDebug = false; // true; + + /** Allows to log and access the ScriptEngine instances with their evalDataList. */ + static final ArrayList enginesUsed = new ArrayList(); + public static ArrayList getEnginesUsed() { + return enginesUsed; + } + + public RgfPseudoScriptEngineCompilable() { + enginesUsed.add(this); + } + + public ScriptEngineFactory getFactory() { + return new RgfPseudoScriptEngineCompilableFactory(); + } + + /** ArrayList of eval() (invocation) information. */ + final ArrayList invocationList = new ArrayList(); + + /** + * Returns ArrayList of eval() (invocation) information. + * @return invocationList + */ + public ArrayList getInvocationList() { + return invocationList; + } + + public Bindings createBindings() { + return new SimpleBindings(); + } + + public Object eval(Reader reader, ScriptContext context) { + if (bDebug) System.err.println("[debug: " + this + ".eval(Reader,ScriptContext), ScriptContext=" + context + "]"); + + return eval(readReader(reader), context); + } + + public Object eval(String script, ScriptContext context) { + if (bDebug) System.err.print("[debug: " + this + ".eval(String,ScriptContext), ScriptContext=" + context + "]"); + + // create copies of the Bindings for later inspection as they may + // get reused and changed on each eval() invocation + TreeMap bindings = new TreeMap(); + for (Integer scope : context.getScopes()) { + Bindings binding = context.getBindings(scope); + bindings.put(scope, binding == null ? new TreeMap() : new TreeMap(binding)); + } + invocationList.add(new InvocationInfos(script,context)); + if (bDebug) System.err.println(" | invocationList.size()=" + invocationList.size()); + return invocationList; + } + + public CompiledScript compile(Reader script) throws ScriptException { + return compile (readReader(script)); + } + + public CompiledScript compile(String script) throws ScriptException { + if (script.indexOf("FAIL COMPILATION") != -1) { + throw new ScriptException("test script contains FAIL COMPILATION"); + } + + String code = "RgfPseudoCompiledScript=[" + script + "]"; + RgfPseudoCompiledScript rpcs = new RgfPseudoCompiledScript(code, this); + return rpcs; + } + + String readReader(Reader reader) { + if (reader == null) { + return ""; + } + + BufferedReader bufferedReader = new BufferedReader(reader); + StringBuilder sb = new StringBuilder(); + // caters for possible IOException in read() and close() + try { + try { + char[] charBuffer = new char[1024]; + int r = 0; + + while ((r = bufferedReader.read(charBuffer)) != -1) { + sb.append(charBuffer, 0, r); + } + } finally { + bufferedReader.close(); + } + } catch (IOException ioe) { + throw new RuntimeException(ioe.getMessage(), ioe); + } + return sb.toString(); + } +} diff --git a/tests/system/src/testscriptapp2/java/mymod/pseudoScriptEngineCompilable/RgfPseudoScriptEngineCompilableFactory.java b/tests/system/src/testscriptapp2/java/mymod/pseudoScriptEngineCompilable/RgfPseudoScriptEngineCompilableFactory.java new file mode 100644 index 0000000000..acf09f54ff --- /dev/null +++ b/tests/system/src/testscriptapp2/java/mymod/pseudoScriptEngineCompilable/RgfPseudoScriptEngineCompilableFactory.java @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package pseudoScriptEngineCompilable; + +import javax.script.ScriptEngine; +import javax.script.ScriptEngineFactory; + +import java.lang.StringBuilder; +import java.util.Arrays; +import java.util.List; + + +public class RgfPseudoScriptEngineCompilableFactory implements ScriptEngineFactory { + static final String ENGINE_NAME = "RgfPseudoScriptLanguageCompilable (SQTMC) 1.0.0"; + static final String SHORT_ENGINE_NAME = "sqtmc"; + static final String ENGINE_VERSION = "100.20200228"; + static final List EXTENSIONS = Arrays.asList("sqtmc", "SQTMC"); + static final String LANGUAGE_NAME = "RgfPseudoScriptLanguageCompilable"; + static final String LANGUAGE_VERSION = "1.0.0.100.20200228"; + static final List MIME_TYPES = Arrays.asList("text/sqtmc", "application/x-sqtmc"); + static final String THREADING = "MULTITHREADED"; + static final List ENGINE_NAMES = Arrays.asList(SHORT_ENGINE_NAME, "RgfPseudoSLCompilable"); + + public String getEngineName() { + return ENGINE_NAME; + } + + public String getEngineVersion() { + return ENGINE_VERSION; + } + + public List getExtensions() { + return EXTENSIONS; + } + + public String getLanguageName() { + return LANGUAGE_NAME; + } + + public String getLanguageVersion() { + return LANGUAGE_VERSION; + } + + public String getName() { + return ENGINE_NAME; + } + + public String getMethodCallSyntax(String obj, String m, String... args) { + return "obj~(m, ...) /* ooRexx style */ "; + } + + public List getMimeTypes() { + return MIME_TYPES; + } + + public List getNames() { + return ENGINE_NAMES; + } + + public String getOutputStatement(String toDisplay) { + String tmpDisplay = toStringLiteral(toDisplay); + return "say " + tmpDisplay + " /* Rexx style (duplicate quotes within string) */ "; + } + + String toStringLiteral(String toDisplay) { + if (toDisplay == null) { + return "\"\""; + } + return '"' + toDisplay.replace("\"","\"\"") + '"'; + } + + public Object getParameter(final String key) { + switch (key) { + case "THREADING": + return THREADING; + + case ScriptEngine.NAME: + return SHORT_ENGINE_NAME; + + case ScriptEngine.ENGINE: + return ENGINE_NAME; + + case ScriptEngine.ENGINE_VERSION: + return ENGINE_VERSION; + + case ScriptEngine.LANGUAGE: + return LANGUAGE_NAME; + + case ScriptEngine.LANGUAGE_VERSION: + return LANGUAGE_VERSION; + + default: + return null; + } + } + + public String getProgram(String... statements) { + if (statements == null) { + return ""; + } + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < statements.length; i++) { + if (statements[i] == null) { + sb.append("\tsay 'null'; /* Rexx style */ \n"); + } + else { + sb.append("\t" + statements[i] + ";\n"); + } + } + return sb.toString(); + } + + public ScriptEngine getScriptEngine() { + return new RgfPseudoScriptEngineCompilable(); + } +} diff --git a/tests/system/src/testscriptapp2/resources/mymod/META-INF/services/javax.script.ScriptEngineFactory b/tests/system/src/testscriptapp2/resources/mymod/META-INF/services/javax.script.ScriptEngineFactory new file mode 100644 index 0000000000..018b592990 --- /dev/null +++ b/tests/system/src/testscriptapp2/resources/mymod/META-INF/services/javax.script.ScriptEngineFactory @@ -0,0 +1 @@ +pseudoScriptEngineCompilable.RgfPseudoScriptEngineCompilableFactory diff --git a/tests/system/src/testscriptapp2/resources/mymod/myapp2/demo_02_bottomscript.sqtmc b/tests/system/src/testscriptapp2/resources/mymod/myapp2/demo_02_bottomscript.sqtmc new file mode 100644 index 0000000000..978f4447ee --- /dev/null +++ b/tests/system/src/testscriptapp2/resources/mymod/myapp2/demo_02_bottomscript.sqtmc @@ -0,0 +1 @@ +demo_02_bottomscript.sqtmc file - pseudo script in external file, starts with the filename diff --git a/tests/system/src/testscriptapp2/resources/mymod/myapp2/demo_02_middlescript.sqtmc b/tests/system/src/testscriptapp2/resources/mymod/myapp2/demo_02_middlescript.sqtmc new file mode 100644 index 0000000000..1db61d511c --- /dev/null +++ b/tests/system/src/testscriptapp2/resources/mymod/myapp2/demo_02_middlescript.sqtmc @@ -0,0 +1 @@ +demo_02_middlescript.sqtmc file - pseudo script in external file, starts with the filename diff --git a/tests/system/src/testscriptapp2/resources/mymod/myapp2/demo_02_off.fxml b/tests/system/src/testscriptapp2/resources/mymod/myapp2/demo_02_off.fxml new file mode 100644 index 0000000000..ade608a318 --- /dev/null +++ b/tests/system/src/testscriptapp2/resources/mymod/myapp2/demo_02_off.fxml @@ -0,0 +1,70 @@ + + + + + + + + + + + + + + + +