1 /* 2 * Copyright (c) 2017, 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 * @test 25 * @bug 8180370 26 * @summary Checks whether Special Chars are skipped while inputting Korean Text 27 * @requires (os.family == "mac") 28 * @run main/manual MissingSpecialCharsTest 29 */ 30 31 /** 32 * This test requires a manual intervention as the keyboard layout has to be 33 * changed to 2-set Korean. Once the keyboard layout has been selected, click on 34 * Start Test to start the automated tests. 35 */ 36 37 import java.awt.AWTException; 38 import java.awt.Font; 39 import java.awt.BorderLayout; 40 import java.awt.Dimension; 41 import java.awt.FlowLayout; 42 import java.awt.Robot; 43 import java.awt.event.WindowAdapter; 44 import java.awt.event.WindowEvent; 45 import javax.swing.JButton; 46 import javax.swing.JFrame; 47 import javax.swing.JPanel; 48 import javax.swing.JTextArea; 49 import javax.swing.SwingUtilities; 50 import javax.swing.WindowConstants; 51 import java.awt.event.KeyEvent; 52 import java.util.Timer; 53 import java.util.TimerTask; 54 import javax.swing.JLabel; 55 import javax.swing.JTextField; 56 57 public class MissingSpecialCharsTest { 58 private static Thread mainThread = null; 59 private static boolean testPassed = false; 60 private static boolean testGeneratedInterrupt = false; 61 private static JFrame frame = null; 62 private static int expectedResults[] = null; 63 private static int inKeyCodes[][] = null; 64 private static JLabel lblTestStatus = null; 65 private static String testResult; 66 67 public static void main(String[] args) throws Exception { 68 mainThread = Thread.currentThread(); 69 SwingUtilities.invokeAndWait(() -> { 70 setupUI(); 71 }); 72 try { 73 Thread.sleep(300000); 74 } catch (InterruptedException e) { 75 if (!testPassed && testGeneratedInterrupt) { 76 throw new RuntimeException("Korean text missing characters : " 77 + testResult); 78 } 79 } 80 81 if (testPassed) { 82 System.out.println(testResult); 83 } else if (!testGeneratedInterrupt) { 84 throw new RuntimeException("User has not executed the test"); 85 } 86 } 87 88 private static void setupUI() { 89 String description = " Select (2-Set) Korean Keyboard Layout \n" 90 + " And then click on Start Test \n\n" 91 + " Note : To check whether the keyboard layout" 92 + " has been changed properly\n" 93 + " you can try typing in the text field before" 94 + " clicking on start test\n"; 95 String title = "Marked Text Manual Test"; 96 97 frame = new JFrame(title); 98 99 JPanel mainPanel = new JPanel(new BorderLayout()); 100 101 JPanel textEditPanel = new JPanel(new FlowLayout()); 102 103 JTextField textFieldMain = new JTextField(20); 104 Font font = new Font("Source Han Serif K", Font.BOLD,12); 105 textFieldMain.setFont(font); 106 107 textEditPanel.add(textFieldMain); 108 109 mainPanel.add(textEditPanel, BorderLayout.CENTER); 110 111 JTextArea textArea = new JTextArea(description); 112 textArea.setEditable(false); 113 final JButton btnStartTest = new JButton("Start Test"); 114 final JButton btnCancelTest = new JButton("Cancel Test"); 115 116 btnStartTest.addActionListener((e) -> { 117 btnStartTest.setEnabled(false); 118 btnCancelTest.setEnabled(false); 119 glyphTest(textFieldMain); 120 }); 121 122 btnCancelTest.addActionListener((e) -> { 123 frame.dispose(); 124 testGeneratedInterrupt = false; 125 mainThread.interrupt(); 126 }); 127 mainPanel.add(textArea, BorderLayout.NORTH); 128 129 JPanel buttonPanel = new JPanel(new FlowLayout()); 130 buttonPanel.add(btnStartTest); 131 buttonPanel.add(btnCancelTest); 132 mainPanel.add(buttonPanel, BorderLayout.SOUTH); 133 134 lblTestStatus = new JLabel(""); 135 lblTestStatus.setMinimumSize(new Dimension(150, 20)); 136 lblTestStatus.setPreferredSize(new Dimension(150, 20)); 137 lblTestStatus.setVisible(true); 138 textEditPanel.add(lblTestStatus); 139 140 frame.add(mainPanel); 141 frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 142 frame.pack(); 143 frame.setLocationRelativeTo(null); 144 145 frame.addWindowListener(new WindowAdapter() { 146 @Override 147 public void windowClosing(WindowEvent e) { 148 testGeneratedInterrupt = false; 149 mainThread.interrupt(); 150 } 151 @Override 152 public void windowOpened( WindowEvent e ){ 153 textFieldMain.requestFocusInWindow(); 154 } 155 }); 156 157 frame.setVisible(true); 158 } 159 160 private static void glyphTest(JTextField textFieldToUse) { 161 try { 162 Robot robotKeySimulator = new Robot(); 163 164 scheduleKeyInputProcess(textFieldToUse, robotKeySimulator); 165 } 166 catch(AWTException e) { 167 System.err.print("Creation Of Robot Failed : " + e.getMessage()); 168 testResults(false); 169 } 170 } 171 172 private static void scheduleKeyInputProcess(JTextField textFieldToUse, 173 Robot robotKeyInput) { 174 textFieldToUse.setText(""); 175 lblTestStatus.setText("Running Tests.."); 176 textFieldToUse.requestFocusInWindow(); 177 178 Timer timer = new Timer(false); 179 long intervalWait = 2 * 1000; //2 Seconds 180 timer.schedule(new keyInputScheduler(timer, 181 textFieldToUse, robotKeyInput), 182 intervalWait, intervalWait); 183 } 184 185 private static boolean setKeyInput(int iCount) { 186 boolean inputSet = true; 187 188 final int iExclamation = KeyEvent.getExtendedKeyCodeForChar('!'); 189 190 if (iExclamation != KeyEvent.VK_UNDEFINED) { 191 switch(iCount) { 192 case 0: 193 // Input Korean q (#12610) /(#47) 194 expectedResults = new int[]{ 12610, 47 }; 195 inKeyCodes = new int[][] { {KeyEvent.VK_Q}, 196 {KeyEvent.VK_SLASH} 197 }; 198 break; 199 200 case 1: 201 // Input Korean q (#12610) /(#47) gh (#54840) \(#92) 202 expectedResults = new int[]{ 12610, 47, 54840, 92 }; 203 inKeyCodes = new int[][] { {KeyEvent.VK_Q}, 204 {KeyEvent.VK_SLASH}, 205 {KeyEvent.VK_G}, 206 {KeyEvent.VK_H}, 207 {KeyEvent.VK_BACK_SLASH} 208 }; 209 break; 210 211 case 2: 212 // Input Korean q (#12610) /(#47) ghq (#54857) \(#92) 213 expectedResults = new int[]{ 12610, 47, 54857, 92 }; 214 inKeyCodes = new int[][] { {KeyEvent.VK_Q}, 215 {KeyEvent.VK_SLASH}, 216 {KeyEvent.VK_G}, 217 {KeyEvent.VK_H}, 218 {KeyEvent.VK_Q}, 219 {KeyEvent.VK_BACK_SLASH} 220 }; 221 break; 222 223 case 3: 224 // Input Korean q (#12610) /(#47) gh (#54840) \(#92) 225 expectedResults = new int[]{ 12610, 47, 54840, 92 }; 226 inKeyCodes = new int[][] { {KeyEvent.VK_Q}, 227 {KeyEvent.VK_SLASH}, 228 {KeyEvent.VK_G}, 229 {KeyEvent.VK_H}, 230 {KeyEvent.VK_Q}, 231 {KeyEvent.VK_BACK_SPACE}, 232 {KeyEvent.VK_BACK_SLASH} 233 }; 234 break; 235 236 case 4: 237 // Input Korean q (#12610) /(#47) g (#12622) \(#92) 238 expectedResults = new int[]{ 12610, 47, 12622, 92 }; 239 inKeyCodes = new int[][] { {KeyEvent.VK_Q}, 240 {KeyEvent.VK_SLASH}, 241 {KeyEvent.VK_G}, 242 {KeyEvent.VK_H}, 243 {KeyEvent.VK_Q}, 244 {KeyEvent.VK_BACK_SPACE}, 245 {KeyEvent.VK_BACK_SPACE}, 246 {KeyEvent.VK_BACK_SLASH} 247 }; 248 break; 249 250 default: 251 inputSet = false; 252 break; 253 } 254 } 255 256 return inputSet; 257 } 258 259 private static void enterInput(Robot robotKeyInput, 260 int keyInputs[]) { 261 String strKeyInput = "KeyPress=>"; 262 final int noOfKeyInputs = keyInputs.length; 263 for (int i = 0; i < noOfKeyInputs; i++) { 264 robotKeyInput.keyPress(keyInputs[i]); 265 strKeyInput += (Integer.toHexString(keyInputs[i])) + ":" ; 266 } 267 268 strKeyInput += "KeyRelease=>"; 269 for (int i = noOfKeyInputs - 1; i >= 0; i--) { 270 robotKeyInput.keyRelease(keyInputs[i]); 271 strKeyInput += (Integer.toHexString(keyInputs[i])) + ":" ; 272 } 273 System.out.println(strKeyInput); 274 } 275 276 public static synchronized void testResults(boolean isPassed) { 277 frame.dispose(); 278 testPassed = isPassed; 279 testGeneratedInterrupt = true; 280 mainThread.interrupt(); 281 } 282 283 private static boolean validateInput(JTextField textFieldToUse) { 284 boolean validateRes = false; 285 286 if (expectedResults != null) { 287 String strCurr = textFieldToUse.getText(); 288 if (expectedResults.length == strCurr.length()) { 289 validateRes = true; 290 291 for (int i = 0; i < strCurr.length(); i++) { 292 final int charActual = strCurr.charAt(i); 293 if (charActual != expectedResults[i]) { 294 System.err.println("<" + i + "> Actual = " + charActual 295 + " Expected = " + expectedResults[i]); 296 validateRes = false; 297 break; 298 } 299 } 300 } 301 } 302 303 return validateRes; 304 } 305 306 static class keyInputScheduler extends TimerTask { 307 private final Timer timer; 308 private final JTextField textFieldToValidate; 309 private final Robot robotForKeyInput; 310 311 private int keyCount = 0; 312 private int taskCount = 0; 313 private boolean taskSet = false; 314 private boolean allTasksPerformed = false; 315 private boolean validationRes = false; 316 317 public keyInputScheduler(Timer timertoUse, 318 JTextField textFieldToUse, 319 Robot robotKeyInput) { 320 timer = timertoUse; 321 textFieldToValidate = textFieldToUse; 322 robotForKeyInput = robotKeyInput; 323 } 324 325 @Override 326 public void run() { 327 performTasks(); 328 } 329 330 public synchronized void performTasks() { 331 if (allTasksPerformed) { 332 stopTask(); 333 } 334 if (!taskSet) { 335 if (!setKeyInput(taskCount)) { 336 allTasksPerformed = true; 337 setTaskStatus(); 338 } else { 339 taskCount++; 340 taskSet = true; 341 keyCount = 0; 342 } 343 } 344 345 if (taskSet) { 346 final int iNoOfKeyInputs = inKeyCodes.length; 347 if (keyCount < iNoOfKeyInputs) { 348 enterInput(robotForKeyInput, inKeyCodes[keyCount]); 349 keyCount++; 350 } else { 351 validationRes = validateInput(textFieldToValidate); 352 if (!validationRes) { 353 allTasksPerformed = true; 354 } else { 355 taskSet = false; 356 textFieldToValidate.setText(""); 357 } 358 setTaskStatus(); 359 } 360 } 361 } 362 363 public void stopTask() { 364 timer.cancel(); 365 testResults(validationRes); 366 } 367 368 public void setTaskStatus() { 369 if (validationRes) { 370 if (allTasksPerformed) { 371 testResult = "All Tests Passed"; 372 } else { 373 testResult = "Test " + Integer.toString(taskCount) 374 + " Passed"; 375 } 376 } else { 377 testResult = "Test " + Integer.toString(taskCount) 378 + " Failed"; 379 } 380 lblTestStatus.setText(testResult); 381 } 382 } 383 }