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 package test.javafx.scene.control; 26 27 import javafx.application.Platform; 28 import javafx.scene.control.Alert; 29 import javafx.scene.control.ButtonType; 30 import javafx.scene.control.Dialog; 31 import javafx.scene.control.DialogShim; 32 import javafx.scene.control.HeavyweightDialogShim; 33 import javafx.stage.Stage; 34 import javafx.stage.WindowEvent; 35 import org.junit.After; 36 import org.junit.Test; 37 38 import static org.junit.Assert.*; 39 40 /** 41 * Note that this class tests non-blocking alerts only. For blocking alerts, 42 * there exists an exact copy of this code in 43 * rt\tests\system\src\test\java\javafx\scene\control 44 * 45 * Whenever this file changes, the contents of the class should be copied over 46 * to the system test class __with no changes__. 47 */ 48 public class AlertTest { 49 50 private static final String DUMMY_RESULT = "dummy"; 51 static boolean blocking = false; 52 53 private Dialog<ButtonType> dialog; 54 55 private boolean closeWasForcedButStageWasShowing = false; 56 private boolean closeVetoed = false; 57 private Object result = DUMMY_RESULT; 58 59 @After public void cleanup() { 60 getStage(dialog).close(); 61 dialog = null; 62 result = DUMMY_RESULT; 63 closeVetoed = false; 64 closeWasForcedButStageWasShowing = false; 65 } 66 67 private static Stage getStage(Dialog<?> dialog) { 68 return HeavyweightDialogShim.get_stage(DialogShim.get_dialog(dialog)); 69 } 70 71 private void showAndHideDialog(Dialog<?> dialog, boolean normalClose) { 72 if (dialog.isShowing()) return; 73 74 if (blocking) { 75 new Thread(() -> { 76 try { 77 // wait a short while after showing the dialog and try to 78 // close it. 79 Thread.sleep(750); 80 Platform.runLater(() -> hideDialog(dialog, normalClose)); 81 82 // wait again 83 Thread.sleep(750); 84 if (closeVetoed) { 85 // now we get serious and clobber the stage so that we 86 // can carry on with the next test. 87 result = dialog.getResult(); 88 closeWasForcedButStageWasShowing = true; 89 Platform.runLater(() -> getStage(dialog).close()); 90 } 91 } catch (InterruptedException e) { 92 e.printStackTrace(); 93 } 94 }).start(); 95 96 dialog.showAndWait(); 97 } else { 98 dialog.show(); 99 hideDialog(dialog, normalClose); 100 } 101 } 102 103 private void hideDialog(Dialog<?> dialog, boolean normalClose) { 104 Stage stage = getStage(dialog); 105 WindowEvent event = new WindowEvent(stage, WindowEvent.WINDOW_CLOSE_REQUEST); 106 107 if (normalClose) { 108 // we can't just click 'dialog.close()' here 109 dialog.close(); 110 } else { 111 // this is hacky, but effectively we're depending on the implementation 112 // detail of heavyweight dialogs to call into the onCloseRequest 113 // handler of the heavyweight stage. 114 stage.getOnCloseRequest().handle(event); 115 } 116 117 // if at this point the dialog is still showing, then the close was obviously vetoed 118 closeVetoed = dialog.isShowing(); 119 } 120 121 private void assertResultValue(Object expected, Dialog<?> dialog, boolean normalClose) { 122 showAndHideDialog(dialog, normalClose); 123 124 if (result != DUMMY_RESULT) { 125 assertEquals(expected, result); 126 } else { 127 assertEquals(expected, dialog.getResult()); 128 } 129 } 130 131 private void assertCloseRequestVetoed(Dialog<?> dialog, boolean normalClose) { 132 Stage stage = getStage(dialog); 133 showAndHideDialog(dialog, normalClose); 134 135 assertTrue(closeWasForcedButStageWasShowing || stage.isShowing()); 136 assertTrue(closeWasForcedButStageWasShowing || dialog.isShowing()); 137 } 138 139 private void assertCloseRequestAccepted(Dialog<?> dialog, boolean normalClose) { 140 Stage stage = getStage(dialog); 141 showAndHideDialog(dialog, normalClose); 142 143 assertFalse(!closeWasForcedButStageWasShowing && stage.isShowing()); 144 assertFalse(!closeWasForcedButStageWasShowing && dialog.isShowing()); 145 } 146 147 148 // --- Information alert tests 149 // Information has one 'OK' button. 150 // Because there is no cancel button, but only one button is present, we 151 // can close the dialog without veto, and the result will be null. 152 // 153 // TODO review the above statement - should we return null, ButtonType.CANCEL 154 // (even though it doesn't exist in the dialog) or, in cases where there is 155 // only one button, do we return that button as the result? 156 @Test public void alert_information_abnormalClose() { 157 dialog = new Alert(Alert.AlertType.INFORMATION, "Hello World!"); 158 assertResultValue(null, dialog, false); 159 assertCloseRequestAccepted(dialog, false); 160 } 161 162 @Test public void alert_information_normalClose() { 163 dialog = new Alert(Alert.AlertType.INFORMATION, "Hello World!"); 164 assertResultValue(null, dialog, true); 165 assertCloseRequestAccepted(dialog, true); 166 } 167 168 169 // --- Error alert tests 170 // Error has one 'OK' button. 171 // Because there is no cancel button, but only one button is present, we 172 // can close the dialog without veto, and the result will be null. 173 // 174 // TODO review the above statement - should we return null, ButtonType.CANCEL 175 // (even though it doesn't exist in the dialog) or, in cases where there is 176 // only one button, do we return that button as the result? 177 @Test public void alert_error_abnormalClose() { 178 dialog = new Alert(Alert.AlertType.ERROR, "Hello World!"); 179 assertResultValue(null, dialog, false); 180 assertCloseRequestAccepted(dialog, false); 181 } 182 183 @Test public void alert_error_normalClose() { 184 dialog = new Alert(Alert.AlertType.ERROR, "Hello World!"); 185 assertResultValue(null, dialog, true); 186 assertCloseRequestAccepted(dialog, true); 187 } 188 189 190 // --- Warning alert tests 191 // Warning has one 'OK' button. 192 // Because there is no cancel button, but only one button is present, we 193 // can close the dialog without veto, and the result will be null. 194 // 195 // TODO review the above statement - should we return null, ButtonType.CANCEL 196 // (even though it doesn't exist in the dialog) or, in cases where there is 197 // only one button, do we return that button as the result? 198 @Test public void alert_warning_abnormalClose() { 199 dialog = new Alert(Alert.AlertType.WARNING, "Hello World!"); 200 assertResultValue(null, dialog, false); 201 assertCloseRequestAccepted(dialog, false); 202 } 203 204 @Test public void alert_warning_normalClose() { 205 dialog = new Alert(Alert.AlertType.WARNING, "Hello World!"); 206 assertResultValue(null, dialog, true); 207 assertCloseRequestAccepted(dialog, true); 208 } 209 210 211 // --- Confirmation alert tests 212 // Confirmation has two buttons: 'OK' and 'Cancel' 213 // Because there is a cancel button, close requests are accepted, and the 214 // result type is ButtonType.CANCEL 215 @Test public void alert_confirmation_abnormalClose() { 216 dialog = new Alert(Alert.AlertType.CONFIRMATION, "Hello World!"); 217 assertResultValue(ButtonType.CANCEL, dialog, false); 218 assertCloseRequestAccepted(dialog, false); 219 } 220 221 @Test public void alert_confirmation_normalClose() { 222 dialog = new Alert(Alert.AlertType.CONFIRMATION, "Hello World!"); 223 assertResultValue(ButtonType.CANCEL, dialog, true); 224 assertCloseRequestAccepted(dialog, true); 225 } 226 227 228 // --- AlertType.NONE alert tests 229 // None has no buttons 230 // Because there is no cancel button, and zero other buttons, this dialog by 231 // default should not be closable 232 @Test public void alert_none_abnormalClose() { 233 dialog = new Alert(Alert.AlertType.NONE, "Hello World!"); 234 assertResultValue(null, dialog, false); 235 assertCloseRequestVetoed(dialog, false); 236 } 237 238 @Test public void alert_none_normalClose() { 239 dialog = new Alert(Alert.AlertType.NONE, "Hello World!"); 240 assertResultValue(null, dialog, true); 241 assertCloseRequestVetoed(dialog, true); 242 } 243 244 245 // --- Testing what happens with custom buttons and closing 246 @Test public void alert_zeroButtons_abnormalClose() { 247 dialog = new Alert(Alert.AlertType.NONE, "Hello World!"); 248 assertResultValue(null, dialog, false); 249 assertCloseRequestVetoed(dialog, false); 250 } 251 252 @Test public void alert_zeroButtons_normalClose() { 253 dialog = new Alert(Alert.AlertType.NONE, "Hello World!"); 254 assertResultValue(null, dialog, true); 255 assertCloseRequestVetoed(dialog, true); 256 } 257 258 @Test public void alert_oneButton_noCancel_abnormalClose() { 259 dialog = new Alert(Alert.AlertType.NONE, "Hello World!"); 260 dialog.getDialogPane().getButtonTypes().add(ButtonType.YES); 261 assertResultValue(null, dialog, false); 262 assertCloseRequestAccepted(dialog, false); 263 } 264 265 @Test public void alert_oneButton_noCancel_normalClose() { 266 dialog = new Alert(Alert.AlertType.NONE, "Hello World!"); 267 dialog.getDialogPane().getButtonTypes().add(ButtonType.YES); 268 assertResultValue(null, dialog, true); 269 assertCloseRequestAccepted(dialog, true); 270 } 271 272 @Test public void alert_oneButton_withCancel_abnormalClose() { 273 dialog = new Alert(Alert.AlertType.NONE, "Hello World!"); 274 dialog.getDialogPane().getButtonTypes().add(ButtonType.CANCEL); 275 assertResultValue(ButtonType.CANCEL, dialog, false); 276 assertCloseRequestAccepted(dialog, false); 277 } 278 279 @Test public void alert_oneButton_withCancel_normalClose() { 280 dialog = new Alert(Alert.AlertType.NONE, "Hello World!"); 281 dialog.getDialogPane().getButtonTypes().add(ButtonType.CANCEL); 282 assertResultValue(ButtonType.CANCEL, dialog, true); 283 assertCloseRequestAccepted(dialog, true); 284 } 285 286 @Test public void alert_twoButtons_noCancel_abnormalClose() { 287 dialog = new Alert(Alert.AlertType.NONE, "Hello World!"); 288 dialog.getDialogPane().getButtonTypes().addAll(ButtonType.APPLY, ButtonType.YES); 289 assertResultValue(null, dialog, false); 290 assertCloseRequestVetoed(dialog, false); 291 } 292 293 @Test public void alert_twoButtons_noCancel_normalClose() { 294 dialog = new Alert(Alert.AlertType.NONE, "Hello World!"); 295 dialog.getDialogPane().getButtonTypes().addAll(ButtonType.APPLY, ButtonType.YES); 296 assertResultValue(null, dialog, true); 297 assertCloseRequestVetoed(dialog, true); 298 } 299 300 @Test public void alert_twoButtons_withCancel_abnormalClose() { 301 dialog = new Alert(Alert.AlertType.NONE, "Hello World!"); 302 dialog.getDialogPane().getButtonTypes().addAll(ButtonType.APPLY, ButtonType.CANCEL); 303 assertResultValue(ButtonType.CANCEL, dialog, false); 304 assertCloseRequestAccepted(dialog, false); 305 } 306 307 @Test public void alert_twoButtons_withCancel_normalClose() { 308 dialog = new Alert(Alert.AlertType.NONE, "Hello World!"); 309 dialog.getDialogPane().getButtonTypes().addAll(ButtonType.APPLY, ButtonType.CANCEL); 310 assertResultValue(ButtonType.CANCEL, dialog, true); 311 assertCloseRequestAccepted(dialog, true); 312 } 313 }