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.cell;
  26 
  27 import client.test.Smoke;
  28 import com.sun.glass.ui.Application;
  29 import com.sun.javafx.scene.control.skin.LabeledText;
  30 import java.util.ArrayList;
  31 import java.util.List;
  32 import java.util.logging.Level;
  33 import java.util.logging.Logger;
  34 import javafx.collections.ObservableList;
  35 import javafx.scene.Node;
  36 import javafx.scene.Scene;
  37 import javafx.scene.control.*;
  38 import javafx.scene.control.test.ControlsTestBase;
  39 import javafx.scene.control.test.cellapps.CellCustomStringConverter;
  40 import javafx.scene.control.test.cellapps.CellsApp;
  41 import static javafx.scene.control.test.cellapps.CellsApp.*;
  42 import javafx.scene.control.test.cellapps.CellsApp.CellType;
  43 import javafx.scene.control.test.cellapps.CellsApp.DataItem;
  44 import org.jemmy.action.GetAction;
  45 import org.jemmy.control.Wrap;
  46 import org.jemmy.fx.ByID;
  47 import org.jemmy.fx.ByText;
  48 import org.jemmy.fx.Root;
  49 import org.jemmy.interfaces.Keyboard.KeyboardButtons;
  50 import org.jemmy.interfaces.Keyboard.KeyboardModifiers;
  51 import org.jemmy.interfaces.Parent;
  52 import org.jemmy.interfaces.Selectable;
  53 import org.jemmy.interfaces.Text;
  54 import org.jemmy.lookup.Lookup;
  55 import org.jemmy.lookup.LookupCriteria;
  56 import org.jemmy.timing.State;
  57 import org.junit.After;
  58 import static org.junit.Assert.assertEquals;
  59 import org.junit.Test;
  60 import org.junit.runner.RunWith;
  61 import test.javaclient.shared.FilteredTestRunner;
  62 import test.javaclient.shared.Utils;
  63 
  64 @RunWith(FilteredTestRunner.class)
  65 public abstract class CellsTestBase extends ControlsTestBase {
  66 
  67     protected static Wrap<? extends Scene> scene = null;
  68     protected static Parent<Node> parent = null;
  69     protected static String cellID = null;
  70     protected static String choiceID = null;
  71     protected static Wrap<? extends Control> testedControl = null;
  72 
  73     protected static void updateWraps() {
  74         scene = Root.ROOT.lookup().wrap();
  75         parent = scene.as(Parent.class, Node.class);
  76     }
  77 
  78     protected abstract Wrap select(String data);
  79 
  80     protected abstract ObservableList<DataItem> getCurrentProgramValues();
  81 
  82     @After
  83     public void tearDown() throws InterruptedException {
  84         Wrap error = parent.lookup(Label.class, new ByID<Label>(ERROR_LABEL_ID)).wrap();
  85         assertEquals("", error.getProperty(Wrap.TEXT_PROP_NAME));
  86         new GetAction() {
  87             @Override
  88             public void run(Object... os) throws Exception {
  89                 ((Button) os[0]).getOnAction().handle(null);
  90             }
  91         }.dispatch(Root.ROOT.getEnvironment(), parent.lookup(Button.class, new ByID(RESET_SCENE_BTN_ID)).wrap().getControl());
  92     }
  93 
  94     @Smoke
  95     @Test(timeout = 300000)
  96     public void enterTextTest() throws InterruptedException {
  97         doFactoryChange(CellType.CustomCell);
  98         startEditingByMouse("Data item 0");
  99 
 100         String newData = "New data";
 101         Wrap<? extends TextField> edit_wrap = parent.lookup(TextField.class, new ByID<TextField>(cellID)).wrap();
 102         edit_wrap.keyboard().pushKey(KeyboardButtons.A, Utils.isMacOS() ? KeyboardModifiers.META_DOWN_MASK : KeyboardModifiers.CTRL_DOWN_MASK);
 103         edit_wrap.as(Text.class).type(newData);
 104         commitEditing(newData);
 105         select(newData);
 106     }
 107 
 108     @Smoke
 109     @Test(timeout = 300000)
 110     public void escapeEditingTest() throws Exception {
 111         doFactoryChange(CellType.CustomCell);
 112         startEditingByMouse("Data item 3");
 113 
 114         String newData = "New data";
 115         Wrap<? extends TextField> edit_wrap = parent.lookup(TextField.class, new ByID<TextField>(cellID)).wrap();
 116         edit_wrap.mouse().click();
 117         edit_wrap.keyboard().pushKey(KeyboardButtons.A, Utils.isMacOS() ? KeyboardModifiers.META_DOWN_MASK : KeyboardModifiers.CTRL_DOWN_MASK);
 118         edit_wrap.as(Text.class).type(newData);
 119         escapeEditing(newData);
 120 
 121         try {
 122             select(newData);
 123         } catch (Exception ex) {
 124             ex.printStackTrace();
 125             return;
 126         }
 127 
 128         throw new Exception("Test fails, because we've found item, which should be, because editing was escaped");
 129     }
 130 
 131     @Smoke
 132     @Test(timeout = 300000)
 133     public void editInnerSelectionTest() throws InterruptedException {
 134         doFactoryChange(CellType.CustomCell);
 135         Wrap<String> item_wrap = startEditingByMouse("Data item 3");
 136         item_wrap.mouse().click();
 137         testedControl.as(Parent.class, Node.class).lookup(TextField.class, new ByID<TextField>(cellID)).wait(1);
 138     }
 139 
 140     @Smoke
 141     @Test(timeout = 300000)
 142     public void editFocusTest() throws InterruptedException {
 143         doFactoryChange(CellType.CustomCell);
 144         startEditingByMouse("Data item 3");
 145         scene.keyboard().pushKey(KeyboardButtons.TAB);
 146         testedControl.as(Parent.class, Node.class).lookup(TextField.class, new ByID<TextField>(cellID)).wait(1);
 147     }
 148 
 149     @Smoke
 150     @Test(timeout = 300000)
 151     public void clickOtherItemTest() throws InterruptedException {
 152         doFactoryChange(CellType.CustomCell);
 153         startEditingByMouse("Data item 3");
 154         select("Data item 2");
 155         scene.waitState(new State<Integer>() {
 156             public Integer reached() {
 157                 return parent.lookup(TextField.class, new ByID<TextField>(cellID)).size();
 158             }
 159         }, 0);
 160     }
 161 
 162     @Smoke
 163     @Test(timeout = 300000)
 164     public void editOtherItemTest() throws InterruptedException {
 165         doFactoryChange(CellType.CustomCell);
 166         select("Data item 5");
 167         startEditingByMouse("Data item 3");
 168         startEditingByMouse("Data item 2");
 169         parent.lookup(TextField.class, new ByID<TextField>(cellID)).wait(1);
 170     }
 171 
 172     @Smoke
 173     @Test(timeout = 300000)
 174     public void commonCheckBoxFactoryWithMouseTest() {
 175         doCommonCheckOfChanger(CellType.CheckBox, Boolean.FALSE, Boolean.TRUE, Boolean.TRUE, null, WayOfEditing.ByMouse);
 176     }
 177 
 178     @Smoke
 179     @Test(timeout = 300000)
 180     public void commonCheckBoxFactoryWithKeyboardTest() {
 181         doCommonCheckOfChanger(CellType.CheckBox, Boolean.FALSE, Boolean.TRUE, Boolean.TRUE, null, WayOfEditing.ByKeyboard);
 182     }
 183 
 184     @Smoke
 185     @Test(timeout = 300000)
 186     public void commonChoiceBoxFacoryWithMouseTest() {
 187         doCommonCheckOfChanger(CellType.ChoiceBox, data.get(5), someValues.get(1), someValues.get(1), new CellCustomStringConverter().toString(someValues.get(1).toString()), WayOfEditing.ByMouse);
 188     }
 189 
 190     @Smoke
 191     @Test(timeout = 300000)
 192     public void commonChoiceBoxFacoryWithKeyboardTest() {
 193         doCommonCheckOfChanger(CellType.ChoiceBox, data.get(3), someValues.get(2), someValues.get(2), new CellCustomStringConverter().toString(someValues.get(2).toString()), WayOfEditing.ByKeyboard);
 194     }
 195 
 196     @Smoke
 197     @Test(timeout = 300000)
 198     public void commonComboBoxFacoryWithMouseTest() {
 199         doCommonCheckOfChanger(CellType.ComboBox, data.get(8), someValues.get(2), someValues.get(2), new CellCustomStringConverter().toString(someValues.get(2).toString()), WayOfEditing.ByMouse);
 200     }
 201 
 202     @Smoke
 203     @Test(timeout = 300000)
 204     public void commonComboBoxFacoryWithKeyboardTest() {
 205         doCommonCheckOfChanger(CellType.ComboBox, data.get(4), someValues.get(0), someValues.get(0), new CellCustomStringConverter().toString(someValues.get(0).toString()), WayOfEditing.ByKeyboard);
 206     }
 207 
 208     @Smoke
 209     @Test(timeout = 300000)
 210     public void commonTextFieldFacoryWithMouseTest() {
 211         doCommonCheckOfChanger(CellType.TextField, data.get(7), someValues.get(0), new CellCustomStringConverter().fromString(someValues.get(0).toString()),
 212                 new CellCustomStringConverter().toString(new CellCustomStringConverter().fromString(someValues.get(0).toString())), WayOfEditing.ByMouse);
 213     }
 214 
 215     @Smoke
 216     @Test(timeout = 300000)
 217     public void commonTextFieldFacoryWithKeyboardTest() {
 218         doCommonCheckOfChanger(CellType.TextField, data.get(2), someValues.get(1), new CellCustomStringConverter().fromString(someValues.get(1).toString()),
 219                 new CellCustomStringConverter().toString(new CellCustomStringConverter().fromString(someValues.get(1).toString())), WayOfEditing.ByKeyboard);
 220     }
 221 
 222     @Smoke
 223     @Test(timeout = 300000)
 224     public void commonCustomTextFieldFacoryWithMouseTest() {
 225         doCommonCheckOfChanger(CellType.CustomCell, data.get(7), someValues.get(0), new CellCustomStringConverter().fromString(someValues.get(0).toString()),
 226                 new CellCustomStringConverter().toString(new CellCustomStringConverter().fromString(someValues.get(0).toString())), WayOfEditing.ByMouse);
 227     }
 228 
 229     @Smoke
 230     @Test(timeout = 300000)
 231     public void commonCustomTextFieldFacoryWithKeyboardTest() {
 232         doCommonCheckOfChanger(CellType.CustomCell, data.get(2), someValues.get(1), new CellCustomStringConverter().fromString(someValues.get(1).toString()),
 233                 new CellCustomStringConverter().toString(new CellCustomStringConverter().fromString(someValues.get(1).toString())), WayOfEditing.ByKeyboard);
 234     }
 235 
 236     protected Wrap startEditingByMouse(String data) {
 237         Wrap<? extends DataItem> wrap = select(data);
 238         wrap.mouse().click();
 239         return wrap;
 240     }
 241 
 242     protected Wrap startEditingByKeyboard(String data) {
 243         Wrap<? extends DataItem> wrap = select(data);
 244         wrap.keyboard().pushKey(KeyboardButtons.F2);
 245         return wrap;
 246     }
 247 
 248     protected void escapeEditing(String data) {
 249         parent.lookup(TextField.class, new ByText<TextField>(data)).wrap().keyboard().pushKey(KeyboardButtons.ESCAPE);
 250     }
 251 
 252     protected void commitEditing(String data) {
 253         parent.lookup(TextField.class, new ByText<TextField>(data)).wrap().keyboard().pushKey(KeyboardButtons.ENTER);
 254     }
 255 
 256     protected void doCommonCheckOfChanger(CellsApp.CellType cellType, Object editableValue, Object newValue, Object expectedValue, String expectedValueRepresentation, WayOfEditing way) {
 257         doFactoryChange(cellType);
 258         checkShowingChangeAfterTypeOfFactoryChanging(cellType);
 259         changeValue(cellType, way, editableValue, newValue);
 260         checkValueChangingProgrammly(expectedValue, cellType.equals(CellType.CheckBox) ? ValueType.Bool : ValueType.Str);
 261         checkValueChangingByShowing(expectedValueRepresentation, cellType);
 262     }
 263 
 264     protected void doFactoryChange(final CellsApp.CellType cellType) {
 265         final Wrap<? extends ComboBox<CellType>> comboBox = parent.lookup(ComboBox.class, new ByID(choiceID)).wrap();
 266         Application.invokeAndWait(new Runnable() {
 267 
 268             @Override
 269             public void run() {
 270                 try {
 271                     comboBox.getControl().getSelectionModel().select(cellType);
 272                 } catch (Throwable ex) {
 273                     ex.printStackTrace();
 274                 }
 275             }
 276         });
 277     }
 278 
 279     protected void changeValue(CellsApp.CellType cellType, WayOfEditing way, Object editableValue, final Object newValue) {
 280         if (!cellType.equals(CellType.CheckBox)) {
 281             switch (way) {
 282                 case ByKeyboard:
 283                     startEditingByKeyboard(editableValue.toString());
 284                     break;
 285                 case ByMouse:
 286                     startEditingByMouse(editableValue.toString());
 287             }
 288         }
 289 
 290         switch (cellType) {
 291             case CheckBox:
 292                 Lookup lookup = testedControl.as(Parent.class, Node.class).lookup(CheckBox.class);
 293                 int size = lookup.size();
 294                 assertEquals(size, dataItemsSize + (testedControl.getControl() instanceof TreeView ? 1 : 0), 0);
 295                 for (int i = 0; i < size; i++) {
 296                     if (way == WayOfEditing.ByMouse) {
 297                         lookup.wrap(i).mouse().click();
 298                     } else {
 299                         new GetAction() {
 300                             @Override
 301                             public void run(Object... os) throws Exception {
 302                                 ((Control) os[0]).requestFocus();
 303                             }
 304                         }.dispatch(Root.ROOT.getEnvironment(), (Control) lookup.wrap(i).getControl());//Otherwise it use mouse click to get focus and make "selected" value changed.
 305                         lookup.wrap(i).keyboard().pushKey(KeyboardButtons.SPACE);
 306                     }
 307                 }
 308                 break;
 309             case ChoiceBox:
 310                 Lookup lookupChoiceBox = testedControl.as(Parent.class, Node.class).lookup(ChoiceBox.class);
 311                 final Wrap<? extends ChoiceBox> choiceBox = lookupChoiceBox.wrap();
 312                 choiceBox.waitState(new State<Boolean>() {
 313                     public Boolean reached() {
 314                         return choiceBox.getControl().isVisible();
 315                     }
 316                 }, true);
 317                 assertEquals(lookupChoiceBox.size(), 1, 0);
 318                 if (way == WayOfEditing.ByMouse) {
 319                     choiceBox.as(Selectable.class).selector().select(converter.toString(newValue));
 320                     choiceBox.waitState(new State<Boolean>() {
 321                         public Boolean reached() {
 322                             return choiceBox.getControl().getSelectionModel().getSelectedItem().equals(newValue);
 323                         }
 324                     }, true);
 325                 } else { //by keyboard
 326                     //choiceBox.keyboard().pushKey(KeyboardButtons.SPACE);
 327                     for (int i = 0; i < getIndexOfValueInChoiceBox(choiceBox, newValue) + 1; i++) {
 328                         choiceBox.keyboard().pushKey(KeyboardButtons.DOWN);
 329                     }
 330                     choiceBox.keyboard().pushKey(KeyboardButtons.ENTER);
 331                 }
 332                 break;
 333             case ComboBox:
 334                 Lookup lookupComboBox = testedControl.as(Parent.class, Node.class).lookup(ComboBox.class);
 335                 assertEquals(lookupComboBox.size(), 1, 0);
 336                 Wrap<? extends ComboBox> comboBox = lookupComboBox.wrap();
 337                 if (way == WayOfEditing.ByMouse) {
 338                     comboBox.as(Selectable.class).selector().select(newValue);
 339                 } else { //by keyboard
 340                     comboBox.keyboard().pushKey(KeyboardButtons.SPACE);
 341                     for (int i = 0; i < getIndexOfValueInComboBox(comboBox, newValue) + 1; i++) {
 342                         comboBox.keyboard().pushKey(KeyboardButtons.DOWN);
 343                     }
 344                     comboBox.keyboard().pushKey(KeyboardButtons.ENTER);
 345                 }
 346                 break;
 347             case TextField:
 348             case CustomCell:
 349                 Lookup lookupTextField = testedControl.as(Parent.class, Node.class).lookup(TextField.class);
 350                 assertEquals(lookupTextField.size(), 1, 0);
 351                 final Wrap<? extends TextField> textField = lookupTextField.wrap();
 352                 new GetAction() {
 353                     @Override
 354                     public void run(Object... os) throws Exception {
 355                         textField.getControl().requestFocus();
 356                     }
 357                 }.dispatch(Root.ROOT.getEnvironment());
 358                 textField.keyboard().pushKey(KeyboardButtons.HOME);
 359                 textField.keyboard().pushKey(KeyboardButtons.END, KeyboardModifiers.SHIFT_DOWN_MASK);
 360                 textField.keyboard().pushKey(KeyboardButtons.DELETE);
 361                 textField.as(Text.class).type(newValue.toString());
 362                 textField.keyboard().pushKey(KeyboardButtons.ENTER);
 363                 break;
 364             default:
 365                 throw new IllegalStateException("Unknown version");
 366         }
 367     }
 368 
 369     protected int getIndexOfValueInChoiceBox(final Wrap< ? extends ChoiceBox> choiceBox, final Object newValue) {
 370         return new GetAction<Integer>() {
 371             @Override
 372             public void run(Object... os) throws Exception {
 373                 setResult(choiceBox.getControl().getItems().indexOf(newValue));
 374             }
 375         }.dispatch(Root.ROOT.getEnvironment());
 376     }
 377 
 378     protected int getIndexOfValueInComboBox(final Wrap< ? extends ComboBox> comboBox, final Object newValue) {
 379         return new GetAction<Integer>() {
 380             @Override
 381             public void run(Object... os) throws Exception {
 382                 setResult(comboBox.getControl().getItems().indexOf(newValue));
 383             }
 384         }.dispatch(Root.ROOT.getEnvironment());
 385     }
 386 
 387     protected void checkValueChangingByShowing(final String expectedValue, CellType cellType) {
 388         if (!cellType.equals(CellType.CheckBox)) {
 389             final int size = testedControl.as(Parent.class, Node.class).lookup(new LookupCriteria<Node>() {
 390                 public boolean check(Node cntrl) {
 391                     return (cntrl instanceof LabeledText)
 392                             && ((LabeledText) cntrl).getText().equals(expectedValue)
 393                             && cntrl.isVisible();
 394                 }
 395             }).lookup().size();
 396             assertEquals("Failed to lookup visible labeled with text [" + expectedValue + "]", size, 1, 0);
 397         }
 398     }
 399 
 400     protected void checkShowingChangeAfterTypeOfFactoryChanging(CellType cellType) {
 401         testedControl.waitState(() -> {
 402             List<String> shownValues = new ArrayList<>();
 403             Lookup lookup = testedControl.as(Parent.class, Node.class).lookup(new LookupCriteria<Node>() {
 404                 @Override
 405                 public boolean check(final Node cntrl) {
 406                     if (cntrl instanceof LabeledText) {
 407                         boolean isVisible = new GetAction<Boolean>() {
 408 
 409                             @Override
 410                             public void run(Object... os) throws Exception {
 411                                 setResult(cntrl.isVisible());
 412                             }
 413                         }.dispatch(Root.ROOT.getEnvironment());
 414                         if (isVisible) {
 415                             return true;
 416                         }
 417                     }
 418                     return false;
 419                 }
 420             }).lookup();
 421             int size = lookup.size();
 422             for (int i = 0; i < size; i++) {
 423                 shownValues.add(new GetAction<String>() {
 424                     @Override
 425                     public void run(Object... os) throws Exception {
 426                         setResult(((LabeledText) os[0]).getText());
 427                     }
 428                 }.dispatch(Root.ROOT.getEnvironment(), (LabeledText) lookup.wrap(i).getControl()));
 429             }
 430 
 431             List<DataItem> failedAttemps = new ArrayList<>();
 432             for (DataItem item : data) {
 433                 int counter = 0;
 434                 for (String str : shownValues) {
 435                     if (str.contains(CellCustomStringConverter.TO_STRING_PREFIX) && str.contains(item.toString())) {
 436                         counter++;
 437                     }
 438                 }
 439                 if (counter != 1) {
 440                     System.out.println("For data item <" + item + "> cannot find proper representation.");
 441                     failedAttemps.add(item);
 442                 }
 443             }
 444             if (failedAttemps.isEmpty()) {
 445                 return true;
 446             } else {
 447                 return null;
 448             }
 449         });
 450     }
 451 
 452     protected void checkValueChangingProgrammly(Object expectedValue, ValueType type) {
 453         switch (type) {
 454             case Bool:
 455                 for (DataItem item : getCurrentProgramValues()) {
 456                     assertEquals((Boolean) expectedValue, item.choiceBoxChecker.getValue());
 457                 }
 458                 break;
 459             case Str:
 460                 int counter = 0;
 461                 for (DataItem item : getCurrentProgramValues()) {
 462                     if (item.toString().equals(expectedValue.toString())) {
 463                         counter++;
 464                     }
 465                 }
 466                 assertEquals(counter, 1, 0);
 467                 break;
 468             default:
 469                 throw new IllegalStateException("Unknown option");
 470         }
 471     }
 472 
 473     protected enum ValueType {
 474 
 475         Bool, Str
 476     };
 477 
 478     protected enum WayOfEditing {
 479 
 480         ByMouse, ByKeyboard
 481     };
 482 }