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 javafx.scene.control.test.textinput;
  26 
  27 import client.test.ScreenshotCheck;
  28 import com.sun.javafx.scene.control.skin.TextInputControlSkin;
  29 import java.lang.reflect.Field;
  30 import java.util.HashMap;
  31 import java.util.HashSet;
  32 import java.util.List;
  33 import java.util.Map;
  34 import java.util.logging.Level;
  35 import java.util.logging.Logger;
  36 import javafx.beans.property.BooleanProperty;
  37 import javafx.scene.Node;
  38 import javafx.scene.Scene;
  39 import javafx.scene.control.Button;
  40 import javafx.scene.control.Control;
  41 import javafx.scene.control.MenuItem;
  42 import javafx.scene.control.PasswordField;
  43 import javafx.scene.control.TextInputControl;
  44 import javafx.scene.control.test.Change;
  45 import javafx.scene.control.test.mix.PopupMenuTest;
  46 import javafx.scene.control.test.textinput.TextInputBaseApp.Pages;
  47 import javafx.scene.control.test.textinput.TextInputChanger.TextInputControlWrapInterface;
  48 import javafx.scene.control.test.textinput.TextInputChanger.TextInputPages;
  49 import javafx.scene.input.Clipboard;
  50 import javafx.scene.input.DataFormat;
  51 import javafx.scene.layout.Pane;
  52 import org.jemmy.Point;
  53 import org.jemmy.action.GetAction;
  54 import org.jemmy.control.Wrap;
  55 import org.jemmy.fx.ByID;
  56 import org.jemmy.fx.Root;
  57 import org.jemmy.interfaces.Keyboard;
  58 import org.jemmy.interfaces.Keyboard.KeyboardButtons;
  59 import org.jemmy.interfaces.Keyboard.KeyboardModifiers;
  60 import org.jemmy.interfaces.Mouse.MouseButtons;
  61 import org.jemmy.interfaces.Parent;
  62 import org.jemmy.interfaces.Text;
  63 import org.jemmy.lookup.LookupCriteria;
  64 import org.jemmy.timing.State;
  65 import org.junit.Assert;
  66 import static org.junit.Assert.*;
  67 import org.junit.Test;
  68 import org.junit.runner.RunWith;
  69 import test.javaclient.shared.FilteredTestRunner;
  70 import test.javaclient.shared.TestBase;
  71 import test.javaclient.shared.Utils;
  72 import test.javaclient.shared.screenshots.ScreenshotUtils;
  73 
  74 /**
  75  * @author Oleg Barbashov
  76  */
  77 @RunWith(FilteredTestRunner.class)
  78 public class TextInputBase extends TestBase {
  79 
  80     {
  81         ScreenshotUtils.setComparatorDistance(0.003f);
  82     }
  83     private Wrap<? extends TextInputControl> taTesting = null;
  84 
  85     static final KeyboardModifiers CTRL = Utils.isMacOS() ? KeyboardModifiers.META_DOWN_MASK : KeyboardModifiers.CTRL_DOWN_MASK;
  86 //    /**
  87 //     * Test for TextInput setMaximumLength API
  88 //     */
  89 //    @ScreenshotCheck
  90 //    @Test(timeout=300000)
  91 //    public void maximumLengthTest() throws InterruptedException, Throwable {
  92 //        openPage(Pages.MaximumLength.name());
  93 //
  94 //        verifyFailures();
  95 //
  96 //        Parent<Node> parent = scene.as(Parent.class, Node.class);
  97 //        Lookup lookup = parent.lookup(TextInput.class);
  98 //        for (int i = 0; i < lookup.size(); i++) {
  99 //            final Wrap<? extends TextInput> wrap = lookup.wrap(i);
 100 //            final Integer maximumLength = new GetAction<Integer>() {
 101 //                @Override
 102 //                public void run(Object... parameters) {
 103 //                    setResult(wrap.getControl().getMaximumLength());
 104 //                }
 105 //            }.dispatch(Root.ROOT.getEnvironment());
 106 //            Text text = wrap.as(Text.class);
 107 //            long timeout = Wrap.WAIT_STATE_TIMEOUT.getValue();
 108 //            String str = createLongString(maximumLength + 2);
 109 //            try {
 110 //                text.type(str);
 111 //            } catch (Exception ex) {
 112 //                // expected as text length is limited but Jemmy does not expect limitation and wait for all sequence
 113 //            }
 114 //            Wrap.WAIT_STATE_TIMEOUT.setValue(timeout);
 115 //            wrap.waitProperty(Wrap.TEXT_PROP_NAME, str.subSequence(0, maximumLength));
 116 //        }
 117 //        checkScreenshot(getClass().getSimpleName() + "-" + Pages.MaximumLength.name());
 118 //        throwScreenshotError();
 119 //    }
 120     /**
 121      * Test for backward API
 122      */
 123     @ScreenshotCheck
 124     @Test(timeout = 300000)
 125     public void backwardInternalTest() throws InterruptedException {
 126         textInputControlInput(TextInputPages.backward.name(), true);
 127     }
 128 
 129     /**
 130      * Test for copy API
 131      */
 132     @ScreenshotCheck
 133     @Test(timeout = 300000)
 134     public void copyInternalTest() throws InterruptedException {
 135         textInputControlInput(TextInputPages.copy.name(), true);
 136     }
 137 
 138     /**
 139      * Test for cut API
 140      */
 141     @ScreenshotCheck
 142     @Test(timeout = 300000)
 143     public void cutInternalTest() throws InterruptedException {
 144         textInputControlInput(TextInputPages.cut.name(), true);
 145     }
 146 
 147     /**
 148      * Test for deleteNextChar API
 149      */
 150     @ScreenshotCheck
 151     @Test(timeout = 300000)
 152     public void deleteNextCharInternalTest() throws InterruptedException {
 153         textInputControlInput(TextInputPages.deleteNextChar.name(), true);
 154     }
 155 
 156     /**
 157      * Test for deletePreviousChar API
 158      */
 159     @ScreenshotCheck
 160     @Test(timeout = 300000)
 161     public void deletePreviousCharInternalTest() throws InterruptedException {
 162         textInputControlInput(TextInputPages.deletePreviousChar.name(), true);
 163     }
 164 
 165     /**
 166      * Test for end API
 167      */
 168     @ScreenshotCheck
 169     @Test(timeout = 300000)
 170     public void endInternalTest() throws InterruptedException {
 171         textInputControlInput(TextInputPages.end.name(), true);
 172     }
 173 
 174     /**
 175      * Test for forward API
 176      */
 177     @ScreenshotCheck
 178     @Test(timeout = 300000)
 179     public void forwardInternalTest() throws InterruptedException {
 180         textInputControlInput(TextInputPages.forward.name(), true);
 181     }
 182 
 183     /**
 184      * Test for home API
 185      */
 186     @ScreenshotCheck
 187     @Test(timeout = 300000)
 188     public void homeInternalTest() throws InterruptedException {
 189         textInputControlInput(TextInputPages.home.name(), true);
 190     }
 191 
 192     /**
 193      * Test for isEditableTextBoxWrap API
 194      */
 195     @ScreenshotCheck
 196     @Test(timeout = 300000)
 197     public void isEditableTextBoxWrapInternalTest() throws InterruptedException {
 198         textInputControlInput(TextInputPages.isEditable.name(), true);
 199     }
 200 
 201     /**
 202      * Test for nextWord API
 203      */
 204     @ScreenshotCheck
 205     @Test(timeout = 300000)
 206     public void nextWordInternalTest() throws InterruptedException {
 207         textInputControlInput(TextInputPages.nextWord.name(), true);
 208     }
 209 
 210     /**
 211      * Test for paste API
 212      */
 213     @ScreenshotCheck
 214     @Test(timeout = 300000)
 215     public void pasteInternalTest() throws InterruptedException {
 216         textInputControlInput(TextInputPages.paste.name(), true);
 217     }
 218 
 219     /**
 220      * Test for positionCaret API
 221      */
 222     @ScreenshotCheck
 223     @Test(timeout = 300000)
 224     public void positionCaretInternalTest() throws InterruptedException {
 225         textInputControlInput(TextInputPages.positionCaret.name(), true);
 226     }
 227 
 228     /**
 229      * Test for previousWord API
 230      */
 231     @ScreenshotCheck
 232     @Test(timeout = 300000)
 233     public void previousWordInternalTest() throws InterruptedException {
 234         textInputControlInput(TextInputPages.previousWord.name(), true);
 235     }
 236 
 237     /**
 238      * Test for selectAll API
 239      */
 240     @ScreenshotCheck
 241     @Test(timeout = 300000)
 242     public void selectAllInternalTest() throws InterruptedException {
 243         textInputControlInput(TextInputPages.selectAll.name(), true);
 244     }
 245 
 246     /**
 247      * Test for selectBackward API
 248      */
 249     @ScreenshotCheck
 250     @Test(timeout = 300000)
 251     public void selectBackwardInternalTest() throws InterruptedException {
 252         textInputControlInput(TextInputPages.selectBackward.name(), true);
 253     }
 254 
 255     /**
 256      * Test for selectEnd API
 257      */
 258     @ScreenshotCheck
 259     @Test(timeout = 300000)
 260     public void selectEndInternalTest() throws InterruptedException {
 261         textInputControlInput(TextInputPages.selectEnd.name(), true);
 262     }
 263 
 264     /**
 265      * Test for selectForward API
 266      */
 267     @ScreenshotCheck
 268     @Test(timeout = 300000)
 269     public void selectForwardInternalTest() throws InterruptedException {
 270         textInputControlInput(TextInputPages.selectForward.name(), true);
 271     }
 272 
 273     /**
 274      * Test for selectHome API
 275      */
 276     @ScreenshotCheck
 277     @Test(timeout = 300000)
 278     public void selectHomeInternalTest() throws InterruptedException {
 279         textInputControlInput(TextInputPages.selectHome.name(), true);
 280     }
 281 
 282     /**
 283      * Test for selectNext API
 284      */
 285     @ScreenshotCheck
 286     @Test(timeout = 300000)
 287     public void selectNextWordInternalTest() throws InterruptedException {
 288         textInputControlInput(TextInputPages.selectNextWord.name(), true);
 289     }
 290 
 291     /**
 292      * Test for selectPreviousWord API
 293      */
 294     @ScreenshotCheck
 295     @Test(timeout = 300000)
 296     public void selectPreviousWordInternalTest() throws InterruptedException {
 297         textInputControlInput(TextInputPages.selectPreviousWord.name(), true);
 298     }
 299 
 300     /**
 301      * Test for setText API
 302      */
 303     @ScreenshotCheck
 304     @Test(timeout = 300000)
 305     public void setTextInternalTest() throws InterruptedException {
 306         textInputControlInput(TextInputPages.setText.name(), true);
 307     }
 308 
 309     /**
 310      * Test for backward API by simulating user input
 311      */
 312     @ScreenshotCheck
 313     @Test(timeout = 300000)
 314     public void backwardExternalTest() throws InterruptedException {
 315         textInputControlInput(TextInputPages.backward.name(), false);
 316     }
 317 
 318     /**
 319      * Test for copy API by simulating user input
 320      */
 321     @ScreenshotCheck
 322     @Test(timeout = 300000)
 323     public void copyExternalTest() throws InterruptedException {
 324         textInputControlInput(TextInputPages.copy.name(), false);
 325     }
 326 
 327     /**
 328      * Test for cut API by simulating user input
 329      */
 330     @ScreenshotCheck
 331     @Test(timeout = 300000)
 332     public void cutExternalTest() throws InterruptedException {
 333         textInputControlInput(TextInputPages.cut.name(), false);
 334     }
 335 
 336     /**
 337      * Test for deleteNextChar API by simulating user input
 338      */
 339     @ScreenshotCheck
 340     @Test(timeout = 300000)
 341     public void deleteNextCharExternalTest() throws InterruptedException {
 342         textInputControlInput(TextInputPages.deleteNextChar.name(), false);
 343     }
 344 
 345     /**
 346      * Test for deletePreviousChar API by simulating user input
 347      */
 348     @ScreenshotCheck
 349     @Test(timeout = 300000)
 350     public void deletePreviousCharExternalTest() throws InterruptedException {
 351         textInputControlInput(TextInputPages.deletePreviousChar.name(), false);
 352     }
 353 
 354     /**
 355      * Test for end API by simulating user input
 356      */
 357     @ScreenshotCheck
 358     @Test(timeout = 300000)
 359     public void endExternalTest() throws InterruptedException {
 360         textInputControlInput(TextInputPages.end.name(), false);
 361     }
 362 
 363     /**
 364      * Test for forward API by simulating user input
 365      */
 366     @ScreenshotCheck
 367     @Test(timeout = 300000)
 368     public void forwardExternalTest() throws InterruptedException {
 369         textInputControlInput(TextInputPages.forward.name(), false);
 370     }
 371 
 372     /**
 373      * Test for home API by simulating user input
 374      */
 375     @ScreenshotCheck
 376     @Test(timeout = 300000)
 377     public void homeExternalTest() throws InterruptedException {
 378         textInputControlInput(TextInputPages.home.name(), false);
 379     }
 380 
 381     /**
 382      * Test for isEditableTextBoxWrap API by simulating user input
 383      */
 384     @ScreenshotCheck
 385     @Test(timeout = 300000)
 386     public void isEditableTextBoxWrapExternalTest() throws InterruptedException {
 387         textInputControlInput(TextInputPages.isEditable.name(), false);
 388     }
 389 
 390     /**
 391      * Test for nextWord API by simulating user input
 392      */
 393     @ScreenshotCheck
 394     @Test(timeout = 300000)
 395     public void nextWordExternalTest() throws InterruptedException {
 396         if (Utils.isMacOS()) {
 397             textInputControlInput(TextInputPages.macNextWordExternal.name(), false);
 398         } else {
 399             textInputControlInput(TextInputPages.nextWord.name(), false);
 400         }
 401     }
 402 
 403     /**
 404      * Test for paste API by simulating user input
 405      */
 406     @ScreenshotCheck
 407     @Test(timeout = 300000)
 408     public void pasteExternalTest() throws InterruptedException {
 409         textInputControlInput(TextInputPages.paste.name(), false);
 410     }
 411 
 412     /**
 413      * Test for positionCaret API by simulating user input
 414      */
 415     @ScreenshotCheck
 416     @Test(timeout = 300000)
 417     public void positionCaretExternalTest() throws InterruptedException {
 418         textInputControlInput(TextInputPages.positionCaret.name(), false);
 419     }
 420 
 421     /**
 422      * Test for previousWord API by simulating user input
 423      */
 424     @ScreenshotCheck
 425     @Test(timeout = 300000)
 426     public void previousWordExternalTest() throws InterruptedException {
 427         textInputControlInput(TextInputPages.previousWord.name(), false);
 428     }
 429 
 430     /**
 431      * Test for selectAll API by simulating user input
 432      */
 433     @ScreenshotCheck
 434     @Test(timeout = 300000)
 435     public void selectAllExternalTest() throws InterruptedException {
 436         textInputControlInput(TextInputPages.selectAll.name(), false);
 437     }
 438 
 439     /**
 440      * Test for selectBackward API by simulating user input
 441      */
 442     @ScreenshotCheck
 443     @Test(timeout = 300000)
 444     public void selectBackwardExternalTest() throws InterruptedException {
 445         textInputControlInput(TextInputPages.selectBackward.name(), false);
 446     }
 447 
 448     /**
 449      * Test for selectEnd API by simulating user input
 450      */
 451     @ScreenshotCheck
 452     @Test(timeout = 300000)
 453     public void selectEndExternalTest() throws InterruptedException {
 454         textInputControlInput(TextInputPages.selectEnd.name(), false);
 455     }
 456 
 457     /**
 458      * Test for selectForward API by simulating user input
 459      */
 460     @ScreenshotCheck
 461     @Test(timeout = 300000)
 462     public void selectForwardExternalTest() throws InterruptedException {
 463         textInputControlInput(TextInputPages.selectForward.name(), false);
 464     }
 465 
 466     /**
 467      * Test for selectHome API by simulating user input
 468      */
 469     @ScreenshotCheck
 470     @Test(timeout = 300000)
 471     public void selectHomeExternalTest() throws InterruptedException {
 472         textInputControlInput(TextInputPages.selectHome.name(), false);
 473     }
 474 
 475     /**
 476      * Test for selectNext API by simulating user input
 477      */
 478     @ScreenshotCheck
 479     @Test(timeout = 300000)
 480     public void selectNextWordExternalTest() throws InterruptedException {
 481         textInputControlInput(TextInputPages.selectNextWord.name(), false);
 482     }
 483 
 484     /**
 485      * Test for selectPreviousWord API by simulating user input
 486      */
 487     @ScreenshotCheck
 488     @Test(timeout = 300000)
 489     public void selectPreviousWordExternalTest() throws InterruptedException {
 490         textInputControlInput(TextInputPages.selectPreviousWord.name(), false);
 491     }
 492 
 493     /**
 494      * Test for setText API by simulating user input
 495      */
 496     @ScreenshotCheck
 497     @Test(timeout = 300000)
 498     public void setTextExternalTest() throws InterruptedException {
 499         textInputControlInput(TextInputPages.setText.name(), false);
 500     }
 501 
 502     /**
 503      * Test for Context Menu
 504      */
 505     @ScreenshotCheck
 506     @Test(timeout = 300000)
 507     public void contextMenuTest() throws InterruptedException {
 508         openPage(Pages.InputTest.name());
 509 
 510         final Wrap<? extends TextInputControl> wrap = getScene().as(Parent.class, Node.class).lookup(TextInputControl.class).wrap();
 511         final Text text = wrap.as(Text.class);
 512 
 513         initContext();
 514         boolean password = PasswordField.class.isAssignableFrom(wrap.getControl().getClass());
 515         if (!password) {
 516             getMenuItem("Select All").mouse().move();
 517             getMenuItem("Copy").mouse().click();
 518             checkClipboard(SAMPLE_STRING);
 519 
 520             getMenuItem("Cut").mouse().click();
 521             checkClipboard(SAMPLE_STRING);
 522             checkText(text, "");
 523         } else {
 524             checkState("Copy", true);
 525             checkState("Cut", true);
 526         }
 527 
 528         initContext();
 529         getMenuItem("Delete").mouse().click();
 530         checkText(text, "");
 531 
 532         initContext();
 533         getMenuItem("Select All").mouse().click();
 534         getScene().waitState(new State() {
 535             public Object reached() {
 536                 return wrap.getControl().getSelection().getLength() == SAMPLE_STRING.length() ? true : null;
 537             }
 538         });
 539 
 540         initContext();
 541         final Map<DataFormat, Object> data_map = new HashMap<DataFormat, Object>();
 542         data_map.put(DataFormat.PLAIN_TEXT, SAMPLE_STRING);
 543 
 544         new GetAction() {
 545             @Override
 546             public void run(Object... os) throws Exception {
 547                 Clipboard.getSystemClipboard().setContent(data_map);
 548             }
 549         }.dispatch(Root.ROOT.getEnvironment());
 550 
 551         getMenuItem("Paste").mouse().click();
 552         checkText(text, SAMPLE_STRING);
 553 
 554         wrap.keyboard().pushKey(KeyboardButtons.HOME);
 555         checkState("Copy", true);
 556         checkState("Cut", true);
 557         checkState("Paste", false);
 558 
 559         new GetAction() {
 560             @Override
 561             public void run(Object... os) throws Exception {
 562                 Clipboard.getSystemClipboard().clear();
 563             }
 564         }.dispatch(Root.ROOT.getEnvironment());
 565 
 566         checkState("Paste", true);
 567         checkState("Delete", true);
 568         checkState("Select All", false);
 569     }
 570 
 571     @ScreenshotCheck
 572     @Test
 573     public void ctrlBackspaceMultilineTest() {
 574         openPage(Pages.CtrlBackspaceTest.name());
 575         Wrap<? extends Button> btn = getScene().as(org.jemmy.interfaces.Parent.class, Node.class).lookup(new ByID<Button>(TextAreaApp.MULTILINE_BTN_ID + Pages.CtrlBackspaceTest.name())).wrap();
 576         click(btn);
 577         ctrlBackspaceTest();
 578     }
 579 
 580     @ScreenshotCheck
 581     @Test
 582     public void ctrlBackspaceRandomSymbolsTest() {
 583         openPage(Pages.CtrlBackspaceTest.name());
 584         Wrap<? extends Button> btn = getScene().as(org.jemmy.interfaces.Parent.class, Node.class).lookup(new ByID<Button>(TextAreaApp.RANDOM_TEXT_BTN_ID + Pages.CtrlBackspaceTest.name())).wrap();
 585         click(btn);
 586         ctrlBackspaceTest();
 587     }
 588 
 589     @ScreenshotCheck
 590     @Test
 591     public void ctrlDeleteMultilineTest() {
 592         openPage(Pages.CtrlDeleteTest.name());
 593         Wrap<? extends Button> btn = getScene().as(org.jemmy.interfaces.Parent.class, Node.class).lookup(new ByID<Button>(TextAreaApp.MULTILINE_BTN_ID + Pages.CtrlDeleteTest.name())).wrap();
 594         click(btn);
 595         ctrlDeleteTest();
 596     }
 597 
 598     @ScreenshotCheck
 599     @Test
 600     public void ctrlDeleteRandomSymbolsTest() {
 601         openPage(Pages.CtrlDeleteTest.name());
 602         Wrap<? extends Button> btn = getScene().as(org.jemmy.interfaces.Parent.class, Node.class).lookup(new ByID<Button>(TextAreaApp.RANDOM_TEXT_BTN_ID + Pages.CtrlDeleteTest.name())).wrap();
 603         click(btn);
 604         ctrlDeleteTest();
 605     }
 606 
 607     private void ctrlBackspaceTest() {
 608         taTesting = getScene().as(org.jemmy.interfaces.Parent.class, Node.class).lookup(new ByID<TextInputControl>(TextAreaApp.INPUT_AREA_ID + Pages.CtrlBackspaceTest.name())).wrap();
 609         click(taTesting);
 610         end();
 611 
 612         String text = getTextFromControl();
 613         final String initialText = text;
 614         while (!"".equals(text)) {
 615             text = deleteLastWord(text);
 616             taTesting.keyboard().pushKey(Keyboard.KeyboardButtons.BACK_SPACE, CTRL);
 617             if (isPasswordField()) {
 618                 Assert.assertEquals(initialText, getTextFromControl());
 619             } else {
 620                 if (!text.equals(getTextFromControl())) {
 621                     out(initialText, text);
 622                 }
 623                 Assert.assertEquals(text, getTextFromControl());
 624             }
 625         }
 626     }
 627 
 628     private void ctrlDeleteTest() {
 629         taTesting = getScene().as(org.jemmy.interfaces.Parent.class, Node.class).lookup(new ByID<TextInputControl>(TextAreaApp.INPUT_AREA_ID + Pages.CtrlDeleteTest.name())).wrap();
 630 
 631         click(taTesting);
 632         home();
 633         String text = getTextFromControl();
 634         final String initialText = text;
 635         while (!"".equals(text)) {
 636             text = deleteFirstWord(text, true);
 637             taTesting.keyboard().pushKey(Keyboard.KeyboardButtons.DELETE, CTRL);
 638             if (isPasswordField()) {
 639                 Assert.assertEquals(initialText, getTextFromControl());
 640             } else {
 641                 if (!text.equals(getTextFromControl())) {
 642                     out(initialText, text);
 643                 }
 644                 Assert.assertEquals(text, getTextFromControl());
 645             }
 646         }
 647     }
 648 
 649     private void out(String initial, String text) {
 650         System.out.println("Initial text : ");
 651         System.out.println(initial);
 652         System.out.println("Control's text : ");
 653         System.out.println(getTextFromControl());
 654         System.out.println("Text : ");
 655         System.out.println(text);
 656         System.out.println("END");
 657     }
 658 
 659     private String deleteLastWord(String text) {
 660         String reverce = new StringBuffer(text).reverse().toString();
 661         reverce = deleteFirstWord(reverce, false);
 662         return new StringBuffer(reverce).reverse().toString();
 663     }
 664 
 665     /*
 666      * Deletes first word according to specific rules.
 667      * Behavior depend on whether deleting is made
 668      * using Ctrl + Delete in the beginning of the string or
 669      * using Ctrl + Backspace in the end of the string.
 670      * <code>deleteFromBeginning</code> flag separates these cases.
 671      *
 672      * @param text initial string
 673      * @param deleteFromBeginning flag which shows how deletion is performed.
 674      * @return string without first word.
 675      */
 676     private String deleteFirstWord(String text, boolean deleteFromBeginning) {
 677         final String[] punctuation = new String[]{" ", "\n", "\t", "/", ",", ";", "!", "@", "#", "$", "%", "^", "*", "(", ")", "&", "."};
 678         if (!deleteFromBeginning) {
 679             while (startsWithAnyOf(text, punctuation)) {
 680                 text = text.substring(1);
 681             }
 682             text = removeLeadingChars(text, punctuation);
 683         } else {
 684             if (!Utils.isWindows()) {
 685                 if (' ' == text.charAt(0)) {
 686                     int pos = 0;
 687                     while(' ' == text.charAt(pos)) ++pos;
 688                     text = text.substring(pos);
 689                 } else if (startsWithAnyOf(text, punctuation)) {
 690                     text = text.substring(1);
 691                 }
 692             }
 693 
 694             text = removeLeadingChars(text, punctuation);
 695 
 696             while (startsWithAnyOf(text, punctuation)) {
 697                 if (!Utils.isWindows()) {
 698                     break;
 699                 }
 700                 text = text.substring(1);
 701             }
 702         }
 703         return text;
 704     }
 705 
 706     /*
 707     For each charachter from <code>toRemove</code> finds which occurs first and deletes it.
 708     If none is found then returns empty string.
 709     */
 710     String removeLeadingChars(String str, String[] toRemove) {
 711         int idx = Integer.MAX_VALUE;
 712         for (String ch : toRemove) {
 713             if (str.indexOf(ch) >= 0) {
 714                 idx = Math.min(str.indexOf(ch), idx);
 715             }
 716         }
 717         idx = idx == Integer.MAX_VALUE ? -1 : idx;
 718         return (idx < 0) ? "" : str.substring(idx);
 719     }
 720 
 721     protected boolean startsWithAnyOf(String str, String[] symbols) {
 722         for (String sym : symbols) {
 723             if (str.startsWith(sym)) {
 724                 return true;
 725             }
 726         }
 727         return false;
 728     }
 729 
 730     protected void click(Wrap<? extends Control> control) {
 731         Point p = control.getClickPoint();
 732         control.mouse().move(p);
 733         control.mouse().click();
 734     }
 735 
 736     protected void initContext() {
 737         final Wrap<? extends TextInputControl> wrap = getScene().as(Parent.class, Node.class).lookup(TextInputControl.class).wrap();
 738         wrap.as(Text.class).clear();
 739         wrap.as(Text.class).type(SAMPLE_STRING);
 740         wrap.keyboard().pushKey(KeyboardButtons.A, Utils.isMacOS() ? KeyboardModifiers.META_DOWN_MASK : CTRL);
 741         new GetAction() {
 742             @Override
 743             public void run(Object... os) throws Exception {
 744                 Clipboard.getSystemClipboard().clear();
 745             }
 746         }.dispatch(Root.ROOT.getEnvironment());
 747     }
 748 
 749     protected void checkState(final String menu, boolean disabled) {
 750         Wrap<? extends Node> wrap = getMenuItem(menu);
 751         MenuItem menu_item = ((MenuItem) wrap.getControl().getProperties().get(MenuItem.class));
 752         assertEquals(menu_item.isDisable(), disabled);
 753     }
 754 
 755     protected void checkText(final Text text, final String str) {
 756         getScene().waitState(new State() {
 757             public Object reached() {
 758                 return text.text().contentEquals(str) ? true : null;
 759             }
 760         });
 761     }
 762 
 763     protected void checkClipboard(final String str) {
 764         getScene().waitState(new State() {
 765             public Object reached() {
 766                 return new GetAction<String>() {
 767                     @Override
 768                     public void run(Object... os) throws Exception {
 769                         setResult(Clipboard.getSystemClipboard().getString());
 770                     }
 771                 }.dispatch(Root.ROOT.getEnvironment()).contentEquals(str) ? true : null;
 772             }
 773         });
 774     }
 775 
 776     protected Wrap<? extends Node> getMenuItem(final String menu) {
 777         getScene().mouse().click();
 778         Parent<Node> parent = getScene().as(Parent.class, Node.class);
 779         final Wrap<? extends TextInputControl> wrap = parent.lookup(TextInputControl.class).wrap();
 780         wrap.mouse().click(1, wrap.getClickPoint(), MouseButtons.BUTTON3);
 781         Wrap<? extends Scene> scene_wrap = PopupMenuTest.getPopupSceneWrap();
 782         Wrap<? extends Node> menu_item = scene_wrap.as(Parent.class, Node.class).lookup(Node.class, new LookupCriteria<Node>() {
 783             public boolean check(Node node) {
 784                 if (node.getProperties().containsKey(MenuItem.class)) {
 785                     String text = ((MenuItem) node.getProperties().get(MenuItem.class)).getText();
 786                     if (text != null && text.contentEquals(menu)) {
 787                         return true;
 788                     }
 789                 }
 790                 return false;
 791             }
 792         }).wrap();
 793         return menu_item;
 794     }
 795     final protected String SAMPLE_STRING = "Sample string";
 796     protected Boolean focused;
 797 
 798     /**
 799      * Test for textInputControl API by simulating user input
 800      */
 801     public void textInputControlInput(final String changeName, boolean internal) throws InterruptedException {
 802         openPage(Pages.InputTest.name());
 803         Thread.sleep(500);
 804         Parent<Node> parent = getScene().as(Parent.class, Node.class);
 805 
 806         //Take focus on scene.
 807         getScene().mouse().click(1, new Point(1, 1));
 808 
 809         final Wrap<? extends TextInputControl> wrap = parent.lookup(TextInputControl.class).wrap();
 810 
 811         //Request focus on control.
 812         new GetAction() {
 813             @Override
 814             public void run(Object... os) throws Exception {
 815                 wrap.getControl().requestFocus();
 816             }
 817         }.dispatch(Root.ROOT.getEnvironment());
 818 
 819 
 820         final ReporterImpl reporter = new ReporterImpl();
 821         List<Change<TextInputControlWrapInterface>> text_wrap_input_changers = TextInputChanger.getTextInputWrapChangers(reporter);
 822 
 823         for (final Change<TextInputControlWrapInterface> change : text_wrap_input_changers) {
 824             if (change.getMarker().startsWith(changeName)) {
 825                 if (internal) {
 826                     applyChange(new TextInputInternalWrap(wrap.getControl()), change, reporter, wrap, true);
 827                 } else {
 828                     applyChange(new TextInputExternalWrap(wrap), change, reporter, wrap, false);
 829                 }
 830             }
 831         }
 832 
 833         if (reporter.isFailed()) {
 834             Assert.fail(reporter.getReason());
 835         }
 836     }
 837 
 838     void applyChange(final TextInputControlWrapInterface control, final Change<TextInputControlWrapInterface> change,
 839             ReporterImpl reporter, final Wrap<? extends TextInputControl> wrap, final boolean internal) {
 840         final String text = new GetAction<String>() {
 841             @Override
 842             public void run(Object... os) throws Exception {
 843                 setResult(control.getControl().getText());
 844             }
 845         }.dispatch(Root.ROOT.getEnvironment());
 846         control.getControl().setEditable(true);
 847 
 848         final TextInputControl controlInstance = (TextInputControl) wrap.getControl();
 849         new GetAction() {
 850             @Override
 851             public void run(Object... parameters) {
 852                 ((TextInputControlSkin) controlInstance.getSkin()).setCaretAnimating(false);
 853                 try {
 854                     Field blink_field;
 855                     blink_field = TextInputControlSkin.class.getDeclaredField("blink");
 856                     blink_field.setAccessible(true);
 857                     BooleanProperty blink = (BooleanProperty) blink_field.get((TextInputControlSkin) controlInstance.getSkin());
 858                     blink.set(false);
 859                 } catch (Exception ex) {
 860                     Logger.getLogger(TextInputBase.class.getName()).log(Level.SEVERE, null, ex);
 861                 }
 862             }
 863         }.dispatch(Root.ROOT.getEnvironment());
 864 
 865         if (internal) {
 866             new GetAction() {
 867                 @Override
 868                 public void run(Object... parameters) {
 869                     change.apply(control, internal);
 870                 }
 871             }.dispatch(Root.ROOT.getEnvironment());
 872         } else {
 873             change.apply(control, internal);
 874         }
 875 
 876         try {
 877             Wrap<? extends Pane> paneWrap = (Wrap<? extends Pane>) ScreenshotUtils.getPageContent();
 878             ScreenshotUtils.checkScreenshot(new StringBuilder(getName()).append("-").append(change.getMarker().replace(' ', '_')).append(internal ? "-internal" : "-external").toString(), paneWrap);
 879         } catch (Throwable e) {
 880             reporter.report("For change <" + change.getMarker() + "> message : " + e.getMessage());
 881         } finally {
 882             new GetAction() {
 883                 @Override
 884                 public void run(Object... parameters) {
 885                     ((TextInputControlSkin) controlInstance.getSkin()).setCaretAnimating(true);
 886                 }
 887             }.dispatch(Root.ROOT.getEnvironment());
 888         }
 889         new GetAction() {
 890             @Override
 891             public void run(Object... os) throws Exception {
 892                 control.setText(text);
 893             }
 894         }.dispatch(Root.ROOT.getEnvironment());
 895         System.err.println(">>got text: " + getTextFromControl(wrap.getControl()));
 896         wrap.waitState(new State() {
 897             public Object reached() {
 898                 String currentText = getTextFromControl(wrap.getControl());
 899                 return text.equalsIgnoreCase(currentText) ? 42 : null;
 900             }
 901         });
 902 
 903         wrap.waitState(new State() {
 904             String s1;
 905             String s2;
 906 
 907             public Object reached() {
 908                 s1 = text.toUpperCase();
 909                 s2 = getTextFromControl(wrap.getControl()).toUpperCase();
 910                 return s1.equals(s2) ? true : null;
 911             }
 912 
 913             public String toString() {
 914                 return "s1 = <" + s1 + ">, s2 = <" + s2 + ">.";
 915             }
 916         });
 917     }
 918 
 919     String getTextFromControl(final TextInputControl cntrl) {
 920         return new GetAction<String>() {
 921             @Override
 922             public void run(Object... os) throws Exception {
 923                 setResult(cntrl.getText());
 924             }
 925         }.dispatch(Root.ROOT.getEnvironment());
 926     }
 927 
 928     String getTextFromControl() {
 929         return new GetAction<String>() {
 930             @Override
 931             public void run(Object... os) throws Exception {
 932                 setResult(taTesting.getControl().getText());
 933             }
 934         }.dispatch(Root.ROOT.getEnvironment());
 935     }
 936 
 937     void forward() {
 938         new GetAction<Void>() {
 939             @Override
 940             public void run(Object... os) throws Exception {
 941                 taTesting.getControl().forward();
 942             }
 943         }.dispatch(Root.ROOT.getEnvironment());
 944     }
 945 
 946     void home() {
 947         new GetAction<Void>() {
 948             @Override
 949             public void run(Object... os) throws Exception {
 950                 taTesting.getControl().home();
 951             }
 952         }.dispatch(Root.ROOT.getEnvironment());
 953     }
 954 
 955     private boolean isPasswordField() {
 956         return new GetAction<Boolean>() {
 957             @Override
 958             public void run(Object... os) throws Exception {
 959                 setResult(PasswordField.class.isAssignableFrom(taTesting.getControl().getClass()));
 960             }
 961         }.dispatch(Root.ROOT.getEnvironment());
 962     }
 963 
 964     void end() {
 965         new GetAction<Void>() {
 966             @Override
 967             public void run(Object... os) throws Exception {
 968                 taTesting.getControl().end();
 969             }
 970         }.dispatch(Root.ROOT.getEnvironment());
 971     }
 972 
 973     public class ReporterImpl extends Reporter {
 974 
 975         protected boolean failed = false;
 976         protected HashSet<String> reasons = new HashSet<String>();
 977 
 978         public boolean isFailed() {
 979             return failed;
 980         }
 981 
 982         public String getReason() {
 983             String reason = "Fault reasons:\n";
 984             for (String str : reasons) {
 985                 reason += "   <" + str + ">\n";
 986             }
 987             return reason;
 988         }
 989 
 990         @Override
 991         public void report(String string) {
 992             failed = true;
 993             reasons.add(string + "\n" + getStackTrace());
 994         }
 995 
 996         protected String getStackTrace() {
 997             String trace = "Stack trace:\n";
 998             for (StackTraceElement ste : new Throwable().getStackTrace()) {
 999                 trace += "\t" + ste + "\n";
1000             }
1001             return trace;
1002         }
1003     }
1004 
1005     protected static String createLongString(int length) {
1006         StringBuilder builder = new StringBuilder("L");
1007         for (int j = 0; j < length - 3; j++) {
1008             builder.append("o");
1009         }
1010         builder.append("ng");
1011         return builder.substring(0, length).toString();
1012     }
1013 }