1 /* 2 * Copyright (c) 2014, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.javafx.application; 27 28 import java.util.concurrent.Callable; 29 import java.util.concurrent.CountDownLatch; 30 import java.util.concurrent.TimeUnit; 31 import java.util.concurrent.atomic.AtomicReference; 32 import javafx.application.Application; 33 import javafx.application.Platform; 34 import javafx.geometry.Pos; 35 import javafx.scene.Group; 36 import javafx.scene.Node; 37 import javafx.scene.Scene; 38 import javafx.scene.control.Button; 39 import javafx.scene.control.ContextMenu; 40 import javafx.scene.control.Label; 41 import javafx.scene.control.Tooltip; 42 import javafx.scene.layout.StackPane; 43 import javafx.scene.shape.Circle; 44 import javafx.scene.shape.Rectangle; 45 import javafx.stage.Stage; 46 import junit.framework.AssertionFailedError; 47 import org.junit.AfterClass; 48 import util.Util; 49 50 import static org.junit.Assert.*; 51 import static util.Util.TIMEOUT; 52 53 /** 54 * Unit tests for scene graph construction on a background thread 55 */ 56 public class SceneGraphThreadCommon { 57 58 // Sleep time showing/hiding window in milliseconds 59 private static final int SLEEP_TIME = 1000; 60 61 // Latch indicating that the start method has been called 62 private static final CountDownLatch launchLatch = new CountDownLatch(1); 63 64 // Completion latch indicating that the launch method has returned 65 private static final CountDownLatch doneLatch = new CountDownLatch(1); 66 67 // Callable to create the node in question on the init thread 68 static volatile Callable<Node> initCallable; 69 70 // Singleton Application instance 71 static MyApp myApp; 72 73 // Application class. An instance is created and initialized before running 74 // the first test, and it lives through the execution of all tests. 75 public static class MyApp extends Application { 76 77 Node content; 78 Stage primaryStage; 79 80 public MyApp() { 81 Platform.setImplicitExit(false); 82 assertTrue(Platform.isFxApplicationThread()); 83 } 84 85 @Override public void init() throws Exception { 86 assertFalse(Platform.isFxApplicationThread()); 87 SceneGraphThreadCommon.myApp = this; 88 content = initCallable.call(); 89 assertNotNull(content); 90 } 91 92 @Override public void start(Stage primaryStage) throws Exception { 93 assertTrue(Platform.isFxApplicationThread()); 94 primaryStage.setTitle("Primary stage"); 95 StackPane root = new StackPane(content); 96 Scene scene = new Scene(root, 300, 200); 97 assertFalse(primaryStage.isShowing()); 98 primaryStage.setScene(scene); 99 primaryStage.show(); 100 assertTrue(primaryStage.isShowing()); 101 102 this.primaryStage = primaryStage; 103 launchLatch.countDown(); 104 } 105 } 106 107 108 private void doTest(Callable<Node> callable) { 109 // Start the Application using the specified Callable 110 initCallable = callable; 111 final Thread testThread = Thread.currentThread(); 112 final AtomicReference<Throwable> launchErr = new AtomicReference<>(null); 113 new Thread(() -> { 114 try { 115 Application.launch(MyApp.class, (String[])null); 116 doneLatch.countDown(); 117 } catch (Throwable t) { 118 launchErr.set(t); 119 testThread.interrupt(); 120 } 121 }).start(); 122 123 try { 124 if (!launchLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)) { 125 throw new AssertionFailedError("Timeout waiting for Application to launch"); 126 } 127 } catch (InterruptedException ex) { 128 Throwable t = launchErr.get(); 129 if (t instanceof RuntimeException) { 130 throw (RuntimeException)t; 131 } 132 else if (t instanceof Error) { 133 throw (Error)t; 134 } else { 135 throw new RuntimeException(t); 136 } 137 } 138 assertNotNull(myApp); 139 assertNotNull(myApp.content); 140 assertNotNull(myApp.primaryStage); 141 Util.sleep(SLEEP_TIME); 142 Util.runAndWait(() -> myApp.primaryStage.hide()); 143 Util.sleep(SLEEP_TIME); 144 Platform.exit(); 145 try { 146 if (!doneLatch.await(TIMEOUT, TimeUnit.MILLISECONDS)) { 147 throw new AssertionFailedError("Timeout waiting for Application to finish"); 148 } 149 } catch (InterruptedException ex) { 150 Throwable t = launchErr.get(); 151 if (t instanceof RuntimeException) { 152 throw (RuntimeException)t; 153 } 154 else if (t instanceof Error) { 155 throw (Error)t; 156 } else { 157 throw new RuntimeException(t); 158 } 159 } 160 } 161 162 // ========================== TEST CASES ========================== 163 164 protected void doTestShape() { 165 doTest(() -> new Circle(75, 75, 50)); 166 } 167 168 protected void doTestContextMenu() { 169 doTest(() -> { 170 Label label = new Label("My Label"); 171 172 ContextMenu contextMenu = new ContextMenu(); 173 label.setContextMenu(contextMenu); 174 return label; 175 }); 176 } 177 178 protected void doTestTooltip() { 179 doTest(() -> { 180 Button button = new Button("My Button"); 181 182 Tooltip tooltip = new Tooltip("My Tooltip"); 183 button.setTooltip(tooltip); 184 return button; 185 }); 186 } 187 188 protected void doTestScene() { 189 doTest(() -> { 190 // Test creating a Scene and modifying the nodes in that scene 191 Group root1 = new Group(); 192 Group root2 = new Group(); 193 Scene theScene = new Scene(root1); 194 Rectangle theNode = new Rectangle(75, 50); 195 root1.getChildren().add(theNode); 196 root1.getChildren().clear(); 197 root2.getChildren().add(theNode); 198 theScene.setRoot(root2); 199 root2.getChildren().clear(); 200 return theNode; 201 }); 202 } 203 204 }