1 /* 2 * Copyright (c) 2012, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 /* 25 * @test 26 * @bug 8001533 8004547 27 * @summary Test launching FX application with java -jar 28 * Test uses main method and blank main method, a jfx app class and an incorrest 29 * jfx app class, a main-class for the manifest, a bogus one and none. 30 * All should execute except the incorrect fx app class entries. 31 * @run main FXLauncherTest 32 */ 33 import java.io.File; 34 import java.io.IOException; 35 import java.util.ArrayList; 36 import java.util.List; 37 38 public class FXLauncherTest extends TestHelper { 39 private static final String FX_MARKER_CLASS = "javafx.application.Application"; 40 private static void line() { 41 System.out.println("_____________________________________________"); 42 } 43 private static File MainJavaFile = null; 44 private static final File FXtestJar = new File("fxtest.jar"); 45 private static final File ManifestFile = new File("manifest.txt"); 46 private static final File ScratchDir = new File("."); 47 48 /* standard main class can be used as java main for fx app class */ 49 static final String StdMainClass = "helloworld.HelloWorld"; 50 static final String ExtMainClass = "helloworld.ExtHello"; 51 static final String NonFXMainClass = "helloworld.HelloJava"; 52 static int testcount = 0; 53 54 /* a main method and a blank. */ 55 static final String[] MAIN_METHODS = { 56 "public static void main(String[] args) { launch(args); }", 57 " " 58 }; 59 60 // Array of parameters to pass to fx application. 61 static final String[] APP_PARMS = { "one", "two" }; 62 63 // Create fx java file for test application 64 static void createJavaFile(String mainmethod) { 65 try { 66 String mainClass = "HelloWorld"; 67 List<String> contents = new ArrayList<>(); 68 contents.add("package helloworld;"); 69 contents.add("import javafx.application.Application;"); 70 contents.add("import javafx.event.ActionEvent;"); 71 contents.add("import javafx.event.EventHandler;"); 72 contents.add("import javafx.scene.Scene;"); 73 contents.add("import javafx.scene.control.Button;"); 74 contents.add("import javafx.scene.layout.StackPane;"); 75 contents.add("import javafx.stage.Stage;"); 76 contents.add("public class HelloWorld extends Application {"); 77 contents.add(mainmethod); 78 contents.add("@Override"); 79 contents.add("public void start(Stage primaryStage) {"); 80 contents.add(" primaryStage.setTitle(\"Hello World!\");"); 81 contents.add(" Button btn = new Button();"); 82 contents.add(" btn.setText(\"Say 'Hello World'\");"); 83 contents.add(" btn.setOnAction(new EventHandler<ActionEvent>() {"); 84 contents.add(" @Override"); 85 contents.add(" public void handle(ActionEvent event) {"); 86 contents.add(" System.out.println(\"Hello World!\");"); 87 contents.add(" }"); 88 contents.add(" });"); 89 contents.add(" StackPane root = new StackPane();"); 90 contents.add(" root.getChildren().add(btn);"); 91 contents.add(" primaryStage.setScene(new Scene(root, 300, 250));"); 92 contents.add("// primaryStage.show(); no GUI for auto tests. "); 93 contents.add(" System.out.println(\"HelloWorld.primaryStage.show();\");"); 94 contents.add(" System.out.println(\"Parameters:\");" ); 95 contents.add(" for(String p : getParameters().getUnnamed())"); 96 contents.add(" System.out.println(\"parameter: \" + p );" ); 97 contents.add(" System.exit(0);"); 98 contents.add("}"); 99 contents.add("}"); 100 101 // Create and compile java source. 102 MainJavaFile = new File(mainClass + JAVA_FILE_EXT); 103 createFile(MainJavaFile, contents); 104 compile("-d", ".", mainClass + JAVA_FILE_EXT); 105 } catch (java.io.IOException ioe) { 106 ioe.printStackTrace(); 107 throw new RuntimeException("Failed creating HelloWorld."); 108 } 109 } 110 111 /* 112 * Create class that extends HelloWorld instead of Application 113 */ 114 static void createExtJavaFile(String mainmethod) { 115 try { 116 String mainClass = "ExtHello"; 117 List<String> contents = new ArrayList<>(); 118 contents.add("package helloworld;"); 119 contents.add("public class ExtHello extends HelloWorld {"); 120 contents.add(mainmethod); 121 contents.add("}"); 122 // Create and compile java source. 123 MainJavaFile = new File(mainClass + JAVA_FILE_EXT); 124 createFile(MainJavaFile, contents); 125 compile("-cp", ".", "-d", ".", mainClass + JAVA_FILE_EXT); 126 } catch (java.io.IOException ioe) { 127 ioe.printStackTrace(); 128 throw new RuntimeException("Failed creating ExtHello."); 129 } 130 } 131 132 /* 133 * Create non-JavaFX class for testing if jfxrt.jar is being loaded 134 * when it shouldn't be 135 */ 136 static void createNonFXJavaFile() { 137 try { 138 String mainClass = "HelloJava"; 139 List<String> contents = new ArrayList<>(); 140 contents.add("package helloworld;"); 141 contents.add("public class HelloJava {"); 142 contents.add(" public static void main(String[] args) {"); 143 contents.add(" for(String aa : args)"); 144 contents.add(" System.out.println(\"arg: \" + aa);" ); 145 contents.add(" }"); 146 contents.add("}"); 147 // Create and compile java source. 148 MainJavaFile = new File(mainClass + JAVA_FILE_EXT); 149 createFile(MainJavaFile, contents); 150 compile("-cp", ".", "-d", ".", mainClass + JAVA_FILE_EXT); 151 } catch (java.io.IOException ioe) { 152 ioe.printStackTrace(); 153 throw new RuntimeException("Failed creating HelloJava."); 154 } 155 } 156 157 // Create manifest for test fx application 158 static List<String> createManifestContents(String mainClassEntry, String fxMainEntry) { 159 List<String> mcontents = new ArrayList<>(); 160 mcontents.add("Manifest-Version: 1.0"); 161 mcontents.add("Created-By: FXLauncherTest"); 162 if (mainClassEntry != null) { 163 mcontents.add("Main-Class: " + mainClassEntry); 164 System.out.println("Main-Class: " + mainClassEntry); 165 } 166 if (fxMainEntry != null) { 167 mcontents.add("JavaFX-Application-Class: " + fxMainEntry); 168 System.out.println("JavaFX-Application-Class: " + fxMainEntry); 169 } 170 return mcontents; 171 } 172 173 // Method to marshal createJar to TestHelper.createJar() 174 static void createJar(File theJar, File manifestFile) { 175 createJar("cvmf", manifestFile.getName(), 176 theJar.getAbsolutePath(), "helloworld"); 177 } 178 179 static void saveFile(String tname, int testcount, File srcFile) { 180 File newFile = new File(tname + "-" + testcount + "-" + srcFile.getName()); 181 System.out.println("renaming " + srcFile.getName() + 182 " to " + newFile.getName()); 183 srcFile.renameTo(newFile); 184 } 185 186 static void cleanupFiles() throws IOException { 187 for(File f : ScratchDir.listFiles()) { 188 recursiveDelete(f); 189 } 190 } 191 192 static void checkStatus(TestResult tr, String testName, int testCount, 193 String mainclass) throws Exception { 194 if (tr.testStatus) { 195 System.out.println("PASS: " + testName + ":" + testCount + 196 " : test with " + mainclass); 197 cleanupFiles(); 198 } else { 199 saveFile(testName, testcount, FXtestJar); 200 System.out.println("FAIL: " + testName + ":" + testCount + 201 " : test with " + mainclass); 202 cleanupFiles(); 203 System.err.println(tr); 204 throw new Exception("Failed: " + testName + ":" + testCount); 205 } 206 } 207 208 /* 209 * Set Main-Class and iterate main_methods. 210 * Try launching with both -jar and -cp methods, with and without FX main 211 * class manifest entry. 212 * All cases should run. 213 * 214 * See sun.launcher.LauncherHelper$FXHelper for more details on how JavaFX 215 * applications are launched. 216 */ 217 @Test 218 static void testBasicFXApp() throws Exception { 219 testBasicFXApp(true, false); // -cp, no JAC 220 testBasicFXApp(false, true); // -jar, with JAC 221 testBasicFXApp(false, false); // -jar, no JAC 222 } 223 224 static void testBasicFXApp(boolean useCP, boolean setFXMainClass) throws Exception { 225 String testname = "testBasicFXApp"; 226 if (useCP) { 227 testname = testname.concat("_useCP"); 228 } 229 String fxMC = StdMainClass; 230 if (!setFXMainClass) { 231 testname = testname.concat("_noJAC"); 232 fxMC = null; 233 } 234 for (String mm : MAIN_METHODS) { 235 testcount++; 236 line(); 237 System.out.println("test# " + testcount + "- Main method: " + mm); 238 createJavaFile(mm); 239 createFile(ManifestFile, createManifestContents(StdMainClass, fxMC)); 240 createJar(FXtestJar, ManifestFile); 241 String sTestJar = FXtestJar.getAbsolutePath(); 242 TestResult tr; 243 if (useCP) { 244 tr = doExec(javaCmd, "-cp", sTestJar, StdMainClass, APP_PARMS[0], APP_PARMS[1]); 245 } else { 246 tr = doExec(javaCmd, "-jar", sTestJar, APP_PARMS[0], APP_PARMS[1]); 247 } 248 tr.checkPositive(); 249 if (tr.testStatus && tr.contains("HelloWorld.primaryStage.show()")) { 250 for (String p : APP_PARMS) { 251 if (!tr.contains(p)) { 252 System.err.println("ERROR: Did not find " 253 + p + " in output!"); 254 } 255 } 256 } 257 checkStatus(tr, testname, testcount, StdMainClass); 258 } 259 } 260 261 /* 262 * Set Main-Class and iterate main methods. 263 * Main class extends another class that extends Application. 264 * Try launching with both -jar and -cp methods. 265 * All cases should run. 266 */ 267 @Test 268 static void testExtendFXApp() throws Exception { 269 testExtendFXApp(true, false); // -cp, no JAC 270 testExtendFXApp(false, true); // -jar, with JAC 271 testExtendFXApp(false, false); // -jar, no JAC 272 } 273 274 static void testExtendFXApp(boolean useCP, boolean setFXMainClass) throws Exception { 275 String testname = "testExtendFXApp"; 276 if (useCP) { 277 testname = testname.concat("_useCP"); 278 } 279 String fxMC = ExtMainClass; 280 if (!setFXMainClass) { 281 testname = testname.concat("_noJAC"); 282 fxMC = null; 283 } 284 for (String mm : MAIN_METHODS) { 285 testcount++; 286 line(); 287 System.out.println("test# " + testcount + "- Main method: " + mm); 288 createJavaFile(mm); 289 createExtJavaFile(mm); 290 createFile(ManifestFile, createManifestContents(ExtMainClass, fxMC)); 291 createJar(FXtestJar, ManifestFile); 292 String sTestJar = FXtestJar.getAbsolutePath(); 293 TestResult tr; 294 if (useCP) { 295 tr = doExec(javaCmd, "-cp", sTestJar, ExtMainClass, APP_PARMS[0], APP_PARMS[1]); 296 } else { 297 tr = doExec(javaCmd, "-jar", sTestJar, APP_PARMS[0], APP_PARMS[1]); 298 } 299 tr.checkPositive(); 300 if (tr.testStatus && tr.contains("HelloWorld.primaryStage.show()")) { 301 for (String p : APP_PARMS) { 302 if (!tr.contains(p)) { 303 System.err.println("ERROR: Did not find " 304 + p + " in output!"); 305 } 306 } 307 } 308 checkStatus(tr, testname, testcount, ExtMainClass); 309 } 310 } 311 312 /* 313 * Ensure we can NOT launch a FX app jar with no Main-Class manifest entry 314 */ 315 @Test 316 static void testMissingMC() throws Exception { 317 String testname = "testMissingMC"; 318 testcount++; 319 line(); 320 System.out.println("test# " + testcount + ": abort on missing Main-Class"); 321 createJavaFile(" "); // no main() needed 322 createFile(ManifestFile, createManifestContents(null, StdMainClass)); // No MC, but supply JAC 323 createJar(FXtestJar, ManifestFile); 324 String sTestJar = FXtestJar.getAbsolutePath(); 325 TestResult tr = doExec(javaCmd, "-jar", sTestJar, APP_PARMS[0], APP_PARMS[1]); 326 tr.checkNegative(); // should abort if no Main-Class 327 if (tr.testStatus) { 328 if (!tr.contains("no main manifest attribute")) { 329 System.err.println("ERROR: launcher did not abort properly"); 330 } 331 } else { 332 System.err.println("ERROR: jar executed with no Main-Class!"); 333 } 334 checkStatus(tr, testname, testcount, StdMainClass); 335 } 336 337 /* 338 * test to ensure that we don't load any extraneous fx jars when 339 * launching a standard java application 340 * Test both -cp and -jar methods since they use different code paths. 341 * Neither case should cause jfxrt.jar to be loaded. 342 */ 343 @Test 344 static void testExtraneousJars() throws Exception { 345 testExtraneousJars(true); 346 testExtraneousJars(false); 347 } 348 349 static void testExtraneousJars(boolean useCP) throws Exception { 350 String testname = "testExtraneousJars"; 351 if (useCP) { 352 testname = testname.concat("_useCP"); 353 } 354 testcount++; 355 line(); 356 System.out.println("test# " + testcount 357 + ": test for erroneous jfxrt.jar loading"); 358 createNonFXJavaFile(); 359 createFile(ManifestFile, createManifestContents(NonFXMainClass, null)); 360 createJar(FXtestJar, ManifestFile); 361 String sTestJar = FXtestJar.getAbsolutePath(); 362 TestResult tr; 363 364 if (useCP) { 365 tr = doExec(javaCmd, "-verbose:class", "-cp", sTestJar, NonFXMainClass, APP_PARMS[0], APP_PARMS[1]); 366 } else { 367 tr = doExec(javaCmd, "-verbose:class", "-jar", sTestJar, APP_PARMS[0], APP_PARMS[1]); 368 } 369 tr.checkPositive(); 370 if (tr.testStatus) { 371 if (!tr.notContains("jfxrt.jar")) { 372 System.out.println("testing for extraneous jfxrt jar"); 373 System.out.println(tr); 374 throw new Exception("jfxrt.jar is being loaded, it should not be!"); 375 } 376 for (String p : APP_PARMS) { 377 if (!tr.contains(p)) { 378 System.err.println("ERROR: Did not find " 379 + p + " in output!"); 380 } 381 } 382 } 383 checkStatus(tr, testname, testcount, NonFXMainClass); 384 } 385 386 public static void main(String... args) throws Exception { 387 //check if fx is part of jdk 388 Class<?> fxClass = null; 389 try { 390 fxClass = Class.forName(FX_MARKER_CLASS); 391 } catch (ClassNotFoundException ex) { 392 // do nothing 393 } 394 if (fxClass != null) { 395 FXLauncherTest fxt = new FXLauncherTest(); 396 fxt.run(args); 397 if (testExitValue > 0) { 398 System.out.println("Total of " + testExitValue 399 + " failed. Test cases covered: " 400 + FXLauncherTest.testcount); 401 System.exit(1); 402 } else { 403 System.out.println("All tests pass. Test cases covered: " 404 + FXLauncherTest.testcount); 405 } 406 } else { 407 System.err.println("Warning: JavaFX components missing or not supported"); 408 System.err.println(" test passes vacuosly."); 409 } 410 } 411 }