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 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.ALT_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             getScene().keyboard().pushKey(KeyboardButtons.ESCAPE);
 527         }
 528 
 529         initContext();
 530         getMenuItem("Delete").mouse().click();
 531         checkText(text, "");
 532 
 533         initContext();
 534         getMenuItem("Select All").mouse().click();
 535         getScene().waitState(new State() {
 536             public Object reached() {
 537                 return wrap.getControl().getSelection().getLength() == SAMPLE_STRING.length() ? true : null;
 538             }
 539         });
 540 
 541         initContext();
 542         final Map<DataFormat, Object> data_map = new HashMap<DataFormat, Object>();
 543         data_map.put(DataFormat.PLAIN_TEXT, SAMPLE_STRING);
 544 
 545         new GetAction() {
 546             @Override
 547             public void run(Object... os) throws Exception {
 548                 Clipboard.getSystemClipboard().setContent(data_map);
 549             }
 550         }.dispatch(Root.ROOT.getEnvironment());
 551 
 552         getMenuItem("Paste").mouse().click();
 553         checkText(text, SAMPLE_STRING);
 554 
 555         wrap.keyboard().pushKey(KeyboardButtons.HOME);
 556         checkState("Copy", true);
 557         checkState("Cut", true);
 558         checkState("Paste", false);
 559 
 560         new GetAction() {
 561             @Override
 562             public void run(Object... os) throws Exception {
 563                 Clipboard.getSystemClipboard().clear();
 564             }
 565         }.dispatch(Root.ROOT.getEnvironment());
 566 
 567         checkState("Paste", true);
 568         checkState("Delete", true);
 569         checkState("Select All", false);
 570     }
 571 
 572     @ScreenshotCheck
 573     @Test
 574     public void ctrlBackspaceMultilineTest() {
 575         openPage(Pages.CtrlBackspaceTest.name());
 576         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();
 577         click(btn);
 578         ctrlBackspaceTest();
 579     }
 580 
 581     @ScreenshotCheck
 582     @Test
 583     public void ctrlBackspaceRandomSymbolsTest() {
 584         openPage(Pages.CtrlBackspaceTest.name());
 585         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();
 586         click(btn);
 587         ctrlBackspaceTest();
 588     }
 589 
 590     @ScreenshotCheck
 591     @Test
 592     public void ctrlDeleteMultilineTest() {
 593         openPage(Pages.CtrlDeleteTest.name());
 594         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();
 595         click(btn);
 596         ctrlDeleteTest();
 597     }
 598 
 599     @ScreenshotCheck
 600     @Test
 601     public void ctrlDeleteRandomSymbolsTest() {
 602         openPage(Pages.CtrlDeleteTest.name());
 603         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();
 604         click(btn);
 605         ctrlDeleteTest();
 606     }
 607 
 608     private void ctrlBackspaceTest() {
 609         taTesting = getScene().as(org.jemmy.interfaces.Parent.class, Node.class).lookup(new ByID<TextInputControl>(TextAreaApp.INPUT_AREA_ID + Pages.CtrlBackspaceTest.name())).wrap();
 610         click(taTesting);
 611         end();
 612 
 613         String text = getTextFromControl();
 614         final String initialText = text;
 615         if (isPasswordField()) {
 616             taTesting.keyboard().pushKey(Keyboard.KeyboardButtons.BACK_SPACE, CTRL);
 617             if (Utils.isMacOS()) {
 618                 Assert.assertEquals("", getTextFromControl());
 619             } else {
 620                 Assert.assertEquals(initialText, getTextFromControl());
 621             }
 622         } else {
 623             while (!text.isEmpty()) {
 624                 text = deleteLastWord(text);
 625                 taTesting.keyboard().pushKey(Keyboard.KeyboardButtons.BACK_SPACE, CTRL);
 626                 if (!text.equals(getTextFromControl())) {
 627                     out(initialText, text);
 628                 }
 629                 Assert.assertEquals(text, getTextFromControl());
 630             }
 631         }
 632     }
 633 
 634     private void ctrlDeleteTest() {
 635         taTesting = getScene().as(org.jemmy.interfaces.Parent.class, Node.class).lookup(new ByID<TextInputControl>(TextAreaApp.INPUT_AREA_ID + Pages.CtrlDeleteTest.name())).wrap();
 636 
 637         click(taTesting);
 638         home();
 639         String text = getTextFromControl();
 640         final String initialText = text;
 641         while (!"".equals(text)) {
 642             text = deleteFirstWord(text, Utils.isMacOS() ? false : true);
 643             taTesting.keyboard().pushKey(Keyboard.KeyboardButtons.DELETE, CTRL);
 644             if (isPasswordField()) {
 645                 Assert.assertEquals(initialText, getTextFromControl());
 646             } else {
 647                 if (!text.equals(getTextFromControl())) {
 648                     out(initialText, text);
 649                 }
 650                 Assert.assertEquals(text, getTextFromControl());
 651             }
 652         }
 653     }
 654 
 655     private void out(String initial, String text) {
 656         System.out.println("Initial text : ");
 657         System.out.println(initial);
 658         System.out.println("Control's text : ");
 659         System.out.println(getTextFromControl());
 660         System.out.println("Text : ");
 661         System.out.println(text);
 662         System.out.println("END");
 663     }
 664 
 665     private String deleteLastWord(String text) {
 666         String reverce = new StringBuffer(text).reverse().toString();
 667         reverce = deleteFirstWord(reverce, false);
 668         return new StringBuffer(reverce).reverse().toString();
 669     }
 670 
 671     /*
 672      * Deletes first word according to specific rules.
 673      * Behavior depend on whether deleting is made
 674      * using Ctrl + Delete in the beginning of the string or
 675      * using Ctrl + Backspace in the end of the string.
 676      * <code>deleteFromBeginning</code> flag separates these cases.
 677      *
 678      * @param text initial string
 679      * @param deleteFromBeginning flag which shows how deletion is performed.
 680      * @return string without first word.
 681      */
 682     private String deleteFirstWord(String text, boolean deleteFromBeginning) {
 683         final String[] punctuation = new String[] {" ", "\n", "\t", "/", ",", ";", "!", "@", "#", "$", "%", "^", "*", "(", ")", "&", "."};
 684 
 685         if (!deleteFromBeginning) {
 686             while (startsWithAnyOf(text, punctuation)) {
 687                 text = text.substring(1);
 688             }
 689             text = removeLeadingChars(text, punctuation);
 690         } else {
 691             if (Utils.isLinux()) {
 692                 if (' ' == text.charAt(0)) {
 693                     int pos = 0;
 694                     while(' ' == text.charAt(pos)) ++pos;
 695                     text = text.substring(pos);
 696                 } else if (startsWithAnyOf(text, punctuation)) {
 697                     text = text.substring(1);
 698                 }
 699             }
 700 
 701             if ('\n' == text.charAt(0)) {
 702                 text = text.substring(1);
 703                 return text;
 704             }
 705 
 706             text = removeLeadingChars(text, punctuation);
 707 
 708             if ('\n' == text.charAt(0)) {
 709                 return text;
 710             }
 711             if (Utils.isLinux()) {
 712                 return text;
 713             }
 714             while (startsWithAnyOf(text, punctuation)) {
 715                 text = text.substring(1);
 716             }
 717         }
 718         return text;
 719     }
 720 
 721     /*
 722     For each charachter from <code>toRemove</code> finds which occurs first and deletes it.
 723     If none is found then returns empty string.
 724     */
 725     String removeLeadingChars(String str, String[] toRemove) {
 726         int idx = Integer.MAX_VALUE;
 727         for (String ch : toRemove) {
 728             if (str.indexOf(ch) >= 0) {
 729                 idx = Math.min(str.indexOf(ch), idx);
 730             }
 731         }
 732         idx = idx == Integer.MAX_VALUE ? -1 : idx;
 733         return (idx < 0) ? "" : str.substring(idx);
 734     }
 735 
 736     protected boolean startsWithAnyOf(String str, String[] symbols) {
 737         for (String sym : symbols) {
 738             if (str.startsWith(sym)) {
 739                 return true;
 740             }
 741         }
 742         return false;
 743     }
 744 
 745     protected void click(Wrap<? extends Control> control) {
 746         Point p = control.getClickPoint();
 747         control.mouse().move(p);
 748         control.mouse().click();
 749     }
 750 
 751     protected void initContext() {
 752         final Wrap<? extends TextInputControl> wrap = getScene().as(Parent.class, Node.class).lookup(TextInputControl.class).wrap();
 753         wrap.as(Text.class).clear();
 754         wrap.as(Text.class).type(SAMPLE_STRING);
 755         wrap.keyboard().pushKey(KeyboardButtons.A, Utils.isMacOS() ? KeyboardModifiers.META_DOWN_MASK : KeyboardModifiers.CTRL_DOWN_MASK);
 756         new GetAction() {
 757             @Override
 758             public void run(Object... os) throws Exception {
 759                 Clipboard.getSystemClipboard().clear();
 760             }
 761         }.dispatch(Root.ROOT.getEnvironment());
 762     }
 763 
 764     protected void checkState(final String menu, boolean disabled) {
 765         Wrap<? extends Node> wrap = getMenuItem(menu);
 766         MenuItem menu_item = ((MenuItem) wrap.getControl().getProperties().get(MenuItem.class));
 767         assertEquals(menu_item.isDisable(), disabled);
 768     }
 769 
 770     protected void checkText(final Text text, final String str) {
 771         getScene().waitState(new State() {
 772             public Object reached() {
 773                 return text.text().contentEquals(str) ? true : null;
 774             }
 775         });
 776     }
 777 
 778     protected void checkClipboard(final String str) {
 779         getScene().waitState(new State() {
 780             public Object reached() {
 781                 return new GetAction<String>() {
 782                     @Override
 783                     public void run(Object... os) throws Exception {
 784                         setResult(Clipboard.getSystemClipboard().getString());
 785                     }
 786                 }.dispatch(Root.ROOT.getEnvironment()).contentEquals(str) ? true : null;
 787             }
 788         });
 789     }
 790 
 791     protected Wrap<? extends Node> getMenuItem(final String menu) {
 792         getScene().mouse().click();
 793         Parent<Node> parent = getScene().as(Parent.class, Node.class);
 794         final Wrap<? extends TextInputControl> wrap = parent.lookup(TextInputControl.class).wrap();
 795         wrap.mouse().click(1, wrap.getClickPoint(), MouseButtons.BUTTON3);
 796         Wrap<? extends Scene> scene_wrap = PopupMenuTest.getPopupSceneWrap();
 797         Wrap<? extends Node> menu_item = scene_wrap.as(Parent.class, Node.class).lookup(Node.class, new LookupCriteria<Node>() {
 798             public boolean check(Node node) {
 799                 if (node.getProperties().containsKey(MenuItem.class)) {
 800                     String text = ((MenuItem) node.getProperties().get(MenuItem.class)).getText();
 801                     if (text != null && text.contentEquals(menu)) {
 802                         return true;
 803                     }
 804                 }
 805                 return false;
 806             }
 807         }).wrap();
 808         return menu_item;
 809     }
 810     final protected String SAMPLE_STRING = "Sample string";
 811     protected Boolean focused;
 812 
 813     /**
 814      * Test for textInputControl API by simulating user input
 815      */
 816     public void textInputControlInput(final String changeName, boolean internal) throws InterruptedException {
 817         openPage(Pages.InputTest.name());
 818         Thread.sleep(500);
 819         Parent<Node> parent = getScene().as(Parent.class, Node.class);
 820 
 821         //Take focus on scene.
 822         getScene().mouse().click(1, new Point(1, 1));
 823 
 824         final Wrap<? extends TextInputControl> wrap = parent.lookup(TextInputControl.class).wrap();
 825 
 826         //Request focus on control.
 827         new GetAction() {
 828             @Override
 829             public void run(Object... os) throws Exception {
 830                 wrap.getControl().requestFocus();
 831             }
 832         }.dispatch(Root.ROOT.getEnvironment());
 833 
 834 
 835         final ReporterImpl reporter = new ReporterImpl();
 836         List<Change<TextInputControlWrapInterface>> text_wrap_input_changers = TextInputChanger.getTextInputWrapChangers(reporter);
 837 
 838         for (final Change<TextInputControlWrapInterface> change : text_wrap_input_changers) {
 839             if (change.getMarker().startsWith(changeName)) {
 840                 if (internal) {
 841                     applyChange(new TextInputInternalWrap(wrap.getControl()), change, reporter, wrap, true);
 842                 } else {
 843                     applyChange(new TextInputExternalWrap(wrap), change, reporter, wrap, false);
 844                 }
 845             }
 846         }
 847 
 848         if (reporter.isFailed()) {
 849             Assert.fail(reporter.getReason());
 850         }
 851     }
 852 
 853     void applyChange(final TextInputControlWrapInterface control, final Change<TextInputControlWrapInterface> change,
 854             ReporterImpl reporter, final Wrap<? extends TextInputControl> wrap, final boolean internal) {
 855         final String text = new GetAction<String>() {
 856             @Override
 857             public void run(Object... os) throws Exception {
 858                 setResult(control.getControl().getText());
 859             }
 860         }.dispatch(Root.ROOT.getEnvironment());
 861         control.getControl().setEditable(true);
 862 
 863         final TextInputControl controlInstance = (TextInputControl) wrap.getControl();
 864         new GetAction() {
 865             @Override
 866             public void run(Object... parameters) {
 867                 ((TextInputControlSkin) controlInstance.getSkin()).setCaretAnimating(false);
 868                 try {
 869                     Field blink_field;
 870                     blink_field = TextInputControlSkin.class.getDeclaredField("blink");
 871                     blink_field.setAccessible(true);
 872                     BooleanProperty blink = (BooleanProperty) blink_field.get((TextInputControlSkin) controlInstance.getSkin());
 873                     blink.set(false);
 874                 } catch (Exception ex) {
 875                     Logger.getLogger(TextInputBase.class.getName()).log(Level.SEVERE, null, ex);
 876                 }
 877             }
 878         }.dispatch(Root.ROOT.getEnvironment());
 879 
 880         if (internal) {
 881             new GetAction() {
 882                 @Override
 883                 public void run(Object... parameters) {
 884                     change.apply(control, internal);
 885                 }
 886             }.dispatch(Root.ROOT.getEnvironment());
 887         } else {
 888             change.apply(control, internal);
 889         }
 890 
 891         try {
 892             Wrap<? extends Pane> paneWrap = (Wrap<? extends Pane>) ScreenshotUtils.getPageContent();
 893             ScreenshotUtils.checkScreenshot(new StringBuilder(getName()).append("-").append(change.getMarker().replace(' ', '_')).append(internal ? "-internal" : "-external").toString(), paneWrap);
 894         } catch (Throwable e) {
 895             reporter.report("For change <" + change.getMarker() + "> message : " + e.getMessage());
 896         } finally {
 897             new GetAction() {
 898                 @Override
 899                 public void run(Object... parameters) {
 900                     ((TextInputControlSkin) controlInstance.getSkin()).setCaretAnimating(true);
 901                 }
 902             }.dispatch(Root.ROOT.getEnvironment());
 903         }
 904         new GetAction() {
 905             @Override
 906             public void run(Object... os) throws Exception {
 907                 control.setText(text);
 908             }
 909         }.dispatch(Root.ROOT.getEnvironment());
 910         System.err.println(">>got text: " + getTextFromControl(wrap.getControl()));
 911         wrap.waitState(new State() {
 912             public Object reached() {
 913                 String currentText = getTextFromControl(wrap.getControl());
 914                 return text.equalsIgnoreCase(currentText) ? 42 : null;
 915             }
 916         });
 917 
 918         wrap.waitState(new State() {
 919             String s1;
 920             String s2;
 921 
 922             public Object reached() {
 923                 s1 = text.toUpperCase();
 924                 s2 = getTextFromControl(wrap.getControl()).toUpperCase();
 925                 return s1.equals(s2) ? true : null;
 926             }
 927 
 928             public String toString() {
 929                 return "s1 = <" + s1 + ">, s2 = <" + s2 + ">.";
 930             }
 931         });
 932     }
 933 
 934     String getTextFromControl(final TextInputControl cntrl) {
 935         return new GetAction<String>() {
 936             @Override
 937             public void run(Object... os) throws Exception {
 938                 setResult(cntrl.getText());
 939             }
 940         }.dispatch(Root.ROOT.getEnvironment());
 941     }
 942 
 943     String getTextFromControl() {
 944         return new GetAction<String>() {
 945             @Override
 946             public void run(Object... os) throws Exception {
 947                 setResult(taTesting.getControl().getText());
 948             }
 949         }.dispatch(Root.ROOT.getEnvironment());
 950     }
 951 
 952     void forward() {
 953         new GetAction<Void>() {
 954             @Override
 955             public void run(Object... os) throws Exception {
 956                 taTesting.getControl().forward();
 957             }
 958         }.dispatch(Root.ROOT.getEnvironment());
 959     }
 960 
 961     void home() {
 962         new GetAction<Void>() {
 963             @Override
 964             public void run(Object... os) throws Exception {
 965                 taTesting.getControl().home();
 966             }
 967         }.dispatch(Root.ROOT.getEnvironment());
 968     }
 969 
 970     private boolean isPasswordField() {
 971         return new GetAction<Boolean>() {
 972             @Override
 973             public void run(Object... os) throws Exception {
 974                 setResult(PasswordField.class.isAssignableFrom(taTesting.getControl().getClass()));
 975             }
 976         }.dispatch(Root.ROOT.getEnvironment());
 977     }
 978 
 979     void end() {
 980         new GetAction<Void>() {
 981             @Override
 982             public void run(Object... os) throws Exception {
 983                 taTesting.getControl().end();
 984             }
 985         }.dispatch(Root.ROOT.getEnvironment());
 986     }
 987 
 988     public class ReporterImpl extends Reporter {
 989 
 990         protected boolean failed = false;
 991         protected HashSet<String> reasons = new HashSet<String>();
 992 
 993         public boolean isFailed() {
 994             return failed;
 995         }
 996 
 997         public String getReason() {
 998             String reason = "Fault reasons:\n";
 999             for (String str : reasons) {
1000                 reason += "   <" + str + ">\n";
1001             }
1002             return reason;
1003         }
1004 
1005         @Override
1006         public void report(String string) {
1007             failed = true;
1008             reasons.add(string + "\n" + getStackTrace());
1009         }
1010 
1011         protected String getStackTrace() {
1012             String trace = "Stack trace:\n";
1013             for (StackTraceElement ste : new Throwable().getStackTrace()) {
1014                 trace += "\t" + ste + "\n";
1015             }
1016             return trace;
1017         }
1018     }
1019 
1020     protected static String createLongString(int length) {
1021         StringBuilder builder = new StringBuilder("L");
1022         for (int j = 0; j < length - 3; j++) {
1023             builder.append("o");
1024         }
1025         builder.append("ng");
1026         return builder.substring(0, length).toString();
1027     }
1028 }