1/* 2 * Copyright (c) 2015, 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 8167636 8167639 8168972 27 * @summary Testing built-in editor. 28 * @modules java.desktop/java.awt 29 * jdk.internal.ed/jdk.internal.editor.spi 30 * jdk.editpad/jdk.editpad 31 * @run testng EditPadTest 32 */ 33 34import java.awt.AWTException; 35import java.awt.Component; 36import java.awt.Container; 37import java.awt.Dimension; 38import java.awt.Frame; 39import java.awt.GraphicsEnvironment; 40import java.awt.Point; 41import java.awt.Robot; 42import java.awt.event.InputEvent; 43import java.awt.event.WindowEvent; 44import java.lang.reflect.InvocationTargetException; 45import java.util.ServiceLoader; 46import java.util.concurrent.ExecutionException; 47import java.util.concurrent.ExecutorService; 48import java.util.concurrent.Executors; 49import java.util.concurrent.Future; 50import java.util.function.Consumer; 51 52import javax.swing.JButton; 53import javax.swing.JFrame; 54import javax.swing.JPanel; 55import javax.swing.JScrollPane; 56import javax.swing.JTextArea; 57import javax.swing.JViewport; 58import javax.swing.SwingUtilities; 59 60import org.testng.annotations.AfterClass; 61import org.testng.annotations.BeforeClass; 62import org.testng.annotations.Test; 63import jdk.internal.editor.spi.BuildInEditorProvider; 64import static org.testng.Assert.assertEquals; 65import static org.testng.Assert.assertTrue; 66 67@Test 68public class EditPadTest { 69 70 private static final int DELAY = 500; 71 private static final String WINDOW_LABEL = "Test Edit Pad"; 72 73 private static ExecutorService executor; 74 private static Robot robot; 75 private static JFrame frame = null; 76 private static JTextArea area = null; 77 private static JButton cancel = null; 78 private static JButton accept = null; 79 private static JButton exit = null; 80 81 @BeforeClass 82 public static void setUpEditorPadTest() { 83 if (!GraphicsEnvironment.isHeadless()) { 84 try { 85 robot = new Robot(); 86 robot.setAutoWaitForIdle(true); 87 robot.setAutoDelay(DELAY); 88 } catch (AWTException e) { 89 throw new ExceptionInInitializerError(e); 90 } 91 } 92 } 93 94 @AfterClass 95 public static void shutdown() { 96 executorShutdown(); 97 } 98 99 public void testSimple() { 100 testEdit("abcdef", 1, "xyz", 101 () -> assertSource("abcdef"), 102 () -> writeSource("xyz"), 103 () -> accept(), 104 () -> assertSource("xyz"), 105 () -> shutdownEditor()); 106 } 107 108 public void testCancel() { 109 testEdit("abcdef", 0, "abcdef", 110 () -> assertSource("abcdef"), 111 () -> writeSource("xyz"), 112 () -> cancel()); 113 } 114 115 public void testAbort() { 116 testEdit("abcdef", 0, "abcdef", 117 () -> assertSource("abcdef"), 118 () -> writeSource("xyz"), 119 () -> shutdownEditor()); 120 } 121 122 public void testAcceptCancel() { 123 testEdit("abcdef", 1, "xyz", 124 () -> assertSource("abcdef"), 125 () -> writeSource("xyz"), 126 () -> accept(), 127 () -> assertSource("xyz"), 128 () -> writeSource("!!!!!!!!!"), 129 () -> cancel()); 130 } 131 132 public void testAcceptEdit() { 133 testEdit("abcdef", 2, "xyz", 134 () -> assertSource("abcdef"), 135 () -> writeSource("NoNo"), 136 () -> accept(), 137 () -> assertSource("NoNo"), 138 () -> writeSource("xyz"), 139 () -> exit()); 140 } 141 142 private void testEdit(String initialText, 143 int savedCount, String savedText, Runnable... actions) { 144 class Handler { 145 146 String text = null; 147 int count = 0; 148 149 void handle(String s) { 150 ++count; 151 text = s; 152 } 153 } 154 Handler save = new Handler(); 155 Handler error = new Handler(); 156 157 if (GraphicsEnvironment.isHeadless()) { 158 // Do not actually run if we are headless 159 return; 160 } 161 Future<?> task = doActions(actions); 162 builtInEdit(initialText, save::handle, error::handle); 163 complete(task); 164 assertEquals(error.count, 0, "Error: " + error.text); 165 assertTrue(save.count != savedCount 166 || save.text == null 167 ? savedText != null 168 : savedText.equals(save.text), 169 "Expected " + savedCount + " saves, got " + save.count 170 + ", expected \"" + savedText + "\" got \"" + save.text + "\""); 171 } 172 173 private static ExecutorService getExecutor() { 174 if (executor == null) { 175 executor = Executors.newSingleThreadExecutor(); 176 } 177 return executor; 178 } 179 180 private static void executorShutdown() { 181 if (executor != null) { 182 executor.shutdown(); 183 executor = null; 184 } 185 } 186 187 private void builtInEdit(String initialText, 188 Consumer<String> saveHandler, Consumer<String> errorHandler) { 189 ServiceLoader<BuildInEditorProvider> sl 190 = ServiceLoader.load(BuildInEditorProvider.class); 191 // Find the highest ranking provider 192 BuildInEditorProvider provider = null; 193 for (BuildInEditorProvider p : sl) { 194 if (provider == null || p.rank() > provider.rank()) { 195 provider = p; 196 } 197 } 198 if (provider != null) { 199 provider.edit(WINDOW_LABEL, 200 initialText, saveHandler, errorHandler); 201 } else { 202 throw new InternalError("Cannot find provider"); 203 } 204 } 205 206 private Future<?> doActions(Runnable... actions) { 207 return getExecutor().submit(() -> { 208 try { 209 waitForIdle(); 210 SwingUtilities.invokeLater(this::seekElements); 211 waitForIdle(); 212 for (Runnable act : actions) { 213 act.run(); 214 } 215 } catch (Throwable e) { 216 shutdownEditor(); 217 if (e instanceof AssertionError) { 218 throw (AssertionError) e; 219 } 220 throw new RuntimeException(e); 221 } 222 }); 223 } 224 225 private void complete(Future<?> task) { 226 try { 227 task.get(); 228 waitForIdle(); 229 } catch (ExecutionException e) { 230 if (e.getCause() instanceof AssertionError) { 231 throw (AssertionError) e.getCause(); 232 } 233 throw new RuntimeException(e); 234 } catch (Exception e) { 235 throw new RuntimeException(e); 236 } finally { 237 shutdownEditor(); 238 } 239 } 240 241 private void writeSource(String s) { 242 SwingUtilities.invokeLater(() -> area.setText(s)); 243 } 244 245 private void assertSource(String expected) { 246 String[] s = new String[1]; 247 try { 248 SwingUtilities.invokeAndWait(() -> s[0] = area.getText()); 249 } catch (InvocationTargetException | InterruptedException e) { 250 throw new RuntimeException(e); 251 } 252 assertEquals(s[0], expected); 253 } 254 255 private void accept() { 256 clickOn(accept); 257 } 258 259 private void exit() { 260 clickOn(exit); 261 } 262 263 private void cancel() { 264 clickOn(cancel); 265 } 266 267 private void shutdownEditor() { 268 SwingUtilities.invokeLater(this::clearElements); 269 waitForIdle(); 270 } 271 272 private void waitForIdle() { 273 robot.waitForIdle(); 274 robot.delay(DELAY); 275 } 276 277 private void seekElements() { 278 for (Frame f : Frame.getFrames()) { 279 if (f.getTitle().equals(WINDOW_LABEL)) { 280 frame = (JFrame) f; 281 // workaround 282 frame.setLocation(0, 0); 283 Container root = frame.getContentPane(); 284 for (Component c : root.getComponents()) { 285 if (c instanceof JScrollPane) { 286 JScrollPane scrollPane = (JScrollPane) c; 287 for (Component comp : scrollPane.getComponents()) { 288 if (comp instanceof JViewport) { 289 JViewport view = (JViewport) comp; 290 area = (JTextArea) view.getComponent(0); 291 } 292 } 293 } 294 if (c instanceof JPanel) { 295 JPanel p = (JPanel) c; 296 for (Component comp : p.getComponents()) { 297 if (comp instanceof JButton) { 298 JButton b = (JButton) comp; 299 switch (b.getText()) { 300 case "Cancel": 301 cancel = b; 302 break; 303 case "Exit": 304 exit = b; 305 break; 306 case "Accept": 307 accept = b; 308 break; 309 } 310 } 311 } 312 } 313 } 314 } 315 } 316 } 317 318 private void clearElements() { 319 if (frame != null) { 320 frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING)); 321 frame = null; 322 } 323 area = null; 324 accept = null; 325 cancel = null; 326 exit = null; 327 } 328 329 private void clickOn(JButton button) { 330 waitForIdle(); 331 waitForIdle(); 332 waitForIdle(); 333 waitForIdle(); 334 waitForIdle(); 335 waitForIdle(); 336 Point p = button.getLocationOnScreen(); 337 Dimension d = button.getSize(); 338 robot.mouseMove(p.x + d.width / 2, p.y + d.height / 2); 339 robot.mousePress(InputEvent.BUTTON1_DOWN_MASK); 340 robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK); 341 } 342} 343