1 /*
   2  * Copyright (c) 2011, 2016, 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 
  26 package test.javafx.scene.control;
  27 
  28 import test.com.sun.javafx.scene.control.infrastructure.KeyModifier;
  29 import test.com.sun.javafx.scene.control.infrastructure.MouseEventFirer;
  30 import com.sun.javafx.tk.Toolkit;
  31 import javafx.css.PseudoClass;
  32 
  33 import test.com.sun.javafx.scene.control.infrastructure.KeyEventFirer;
  34 import test.com.sun.javafx.scene.control.infrastructure.StageLoader;
  35 import javafx.scene.control.skin.ComboBoxListViewSkin;
  36 
  37 import static test.com.sun.javafx.scene.control.infrastructure.ControlTestUtils.assertStyleClassContains;
  38 import static org.junit.Assert.*;
  39 import static org.junit.Assert.assertEquals;
  40 
  41 import java.util.*;
  42 import java.util.concurrent.atomic.AtomicInteger;
  43 
  44 import javafx.beans.property.ObjectProperty;
  45 import javafx.beans.property.SimpleObjectProperty;
  46 import javafx.beans.property.SimpleStringProperty;
  47 import javafx.beans.property.StringProperty;
  48 import javafx.collections.FXCollections;
  49 import javafx.collections.ObservableList;
  50 import javafx.event.ActionEvent;
  51 import javafx.event.EventHandler;
  52 import javafx.scene.Node;
  53 import javafx.scene.Scene;
  54 import javafx.scene.control.Button;
  55 import javafx.scene.control.ComboBox;
  56 import javafx.scene.control.ComboBoxShim;
  57 import javafx.scene.control.IndexedCell;
  58 import javafx.scene.control.Label;
  59 import javafx.scene.control.ListCell;
  60 import javafx.scene.control.ListCellShim;
  61 import javafx.scene.control.ListView;
  62 import javafx.scene.control.SelectionModel;
  63 import javafx.scene.control.SelectionModelShim;
  64 import javafx.scene.control.SingleSelectionModel;
  65 import javafx.scene.control.TextField;
  66 import javafx.scene.control.Tooltip;
  67 import javafx.scene.control.skin.VirtualFlow;
  68 import javafx.scene.input.KeyCode;
  69 import javafx.scene.layout.VBox;
  70 import javafx.scene.paint.Color;
  71 import javafx.scene.shape.Circle;
  72 import javafx.stage.Stage;
  73 import javafx.util.Callback;
  74 import javafx.util.StringConverter;
  75 
  76 import org.junit.Before;
  77 import org.junit.Ignore;
  78 import org.junit.Test;
  79 
  80 public class ComboBoxTest {
  81     private ComboBox<String> comboBox;
  82     private SingleSelectionModel<String> sm;
  83 
  84     /*********************************************************************
  85      *                                                                   *
  86      * Utility methods                                                   *
  87      *                                                                   *
  88      ********************************************************************/
  89 
  90     public ListView getListView() {
  91         return (ListView) ((ComboBoxListViewSkin)comboBox.getSkin()).getPopupContent();
  92     }
  93 
  94     public Node getDisplayNode() {
  95         return ((ComboBoxListViewSkin)comboBox.getSkin()).getDisplayNode();
  96     }
  97 
  98 
  99 
 100     /*********************************************************************
 101      *                                                                   *
 102      * Setup                                                             *
 103      *                                                                   *
 104      ********************************************************************/
 105 
 106     @Before public void setup() {
 107         comboBox = new ComboBox<String>();
 108         comboBox.setSkin(new ComboBoxListViewSkin<>(comboBox));
 109         sm = comboBox.getSelectionModel();
 110     }
 111 
 112 
 113 
 114     /*********************************************************************
 115      *                                                                   *
 116      * Tests for the constructors                                        *
 117      *                                                                   *
 118      ********************************************************************/
 119 
 120     @Test public void noArgConstructorSetsTheStyleClass() {
 121         assertStyleClassContains(comboBox, "combo-box");
 122     }
 123 
 124     @Test public void noArgConstructorSetsNonNullSelectionModel() {
 125         assertNotNull(sm);
 126     }
 127 
 128     @Test public void noArgConstructorSetsNonNullItems() {
 129         assertNotNull(comboBox.getItems());
 130     }
 131 
 132     @Test public void noArgConstructor_selectedItemIsNull() {
 133         assertNull(sm.getSelectedItem());
 134     }
 135 
 136     @Test public void noArgConstructor_selectedIndexIsNegativeOne() {
 137         assertEquals(-1, sm.getSelectedIndex());
 138     }
 139 
 140     @Test public void noArgConstructor_valueIsNull() {
 141         assertNull(comboBox.getValue());
 142     }
 143 
 144     @Test public void noArgConstructor_editableIsFalse() {
 145         assertFalse(comboBox.isEditable());
 146     }
 147 
 148     @Test public void noArgConstructor_showingIsFalse() {
 149         assertFalse(comboBox.isShowing());
 150     }
 151 
 152     @Test public void noArgConstructor_promptTextIsEmptyString() {
 153         assertNull(comboBox.getPromptText());
 154     }
 155 
 156     @Test public void noArgConstructor_placeholderIsNull() {
 157         assertNull(comboBox.getPlaceholder());
 158     }
 159 
 160     @Test public void noArgConstructor_armedIsFalse() {
 161         assertFalse(comboBox.isArmed());
 162     }
 163 
 164     @Test public void noArgConstructor_converterIsNotNull() {
 165         assertNotNull(comboBox.getConverter());
 166     }
 167 
 168     @Test public void noArgConstructor_cellFactoryIsNull() {
 169         assertNull(comboBox.getCellFactory());
 170     }
 171 
 172     @Test public void noArgConstructor_visibleRowFactoryIs10() {
 173         assertEquals(10, comboBox.getVisibleRowCount());
 174     }
 175 
 176     @Test public void singleArgConstructorSetsTheStyleClass() {
 177         final ComboBox<String> b2 = new ComboBox<String>(FXCollections.observableArrayList("Hi"));
 178         assertStyleClassContains(b2, "combo-box");
 179     }
 180 
 181     @Test public void singleArgConstructorSetsNonNullSelectionModel() {
 182         final ComboBox<String> b2 = new ComboBox<String>(FXCollections.observableArrayList("Hi"));
 183         assertNotNull(b2.getSelectionModel());
 184     }
 185 
 186     @Test public void singleArgConstructorAllowsNullItems() {
 187         final ComboBox<String> b2 = new ComboBox<String>(null);
 188         assertNull(b2.getItems());
 189     }
 190 
 191     @Test public void singleArgConstructorTakesItems() {
 192         ObservableList<String> items = FXCollections.observableArrayList("Hi");
 193         final ComboBox<String> b2 = new ComboBox<String>(items);
 194         assertSame(items, b2.getItems());
 195     }
 196 
 197     @Test public void singleArgConstructor_selectedItemIsNull() {
 198         final ComboBox<String> b2 = new ComboBox<String>(FXCollections.observableArrayList("Hi"));
 199         assertNull(b2.getSelectionModel().getSelectedItem());
 200     }
 201 
 202     @Test public void singleArgConstructor_selectedIndexIsNegativeOne() {
 203         final ComboBox<String> b2 = new ComboBox<String>(FXCollections.observableArrayList("Hi"));
 204         assertEquals(-1, b2.getSelectionModel().getSelectedIndex());
 205     }
 206 
 207     @Test public void singleArgConstructor_valueIsNull() {
 208         final ComboBox<String> b2 = new ComboBox<String>(FXCollections.observableArrayList("Hi"));
 209         assertNull(b2.getValue());
 210     }
 211 
 212     @Test public void singleArgConstructor_editableIsFalse() {
 213         final ComboBox<String> b2 = new ComboBox<String>(FXCollections.observableArrayList("Hi"));
 214         assertFalse(b2.isEditable());
 215     }
 216 
 217     @Test public void singleArgConstructor_showingIsFalse() {
 218         final ComboBox<String> b2 = new ComboBox<String>(FXCollections.observableArrayList("Hi"));
 219         assertFalse(b2.isShowing());
 220     }
 221 
 222     @Test public void singleArgConstructor_promptTextIsEmptyString() {
 223         final ComboBox<String> b2 = new ComboBox<String>(FXCollections.observableArrayList("Hi"));
 224         assertNull(b2.getPromptText());
 225     }
 226 
 227     @Test public void singleArgConstructor_placeholderIsNull() {
 228         final ComboBox<String> b2 = new ComboBox<String>(FXCollections.observableArrayList("Hi"));
 229         assertNull(b2.getPlaceholder());
 230     }
 231 
 232     @Test public void singleArgConstructor_armedIsFalse() {
 233         final ComboBox<String> b2 = new ComboBox<String>(FXCollections.observableArrayList("Hi"));
 234         assertEquals(false, b2.isArmed());
 235     }
 236 
 237     @Test public void singleArgConstructor_converterIsNotNull() {
 238         final ComboBox<String> b2 = new ComboBox<String>(FXCollections.observableArrayList("Hi"));
 239         assertNotNull(b2.getConverter());
 240     }
 241 
 242     @Test public void singleArgConstructor_cellFactoryIsNull() {
 243         final ComboBox<String> b2 = new ComboBox<String>(FXCollections.observableArrayList("Hi"));
 244         assertNull(b2.getCellFactory());
 245     }
 246 
 247     @Test public void singleArgConstructor_visibleRowFactoryIs10() {
 248         final ComboBox<String> b2 = new ComboBox<String>(FXCollections.observableArrayList("Hi"));
 249         assertEquals(10, b2.getVisibleRowCount());
 250     }
 251 
 252     /*********************************************************************
 253      * Tests for selection model                                         *
 254      ********************************************************************/
 255 
 256     @Test public void selectionModelCanBeNull() {
 257         comboBox.setSelectionModel(null);
 258         assertNull(comboBox.getSelectionModel());
 259     }
 260 
 261     @Test public void selectionModelCanBeBound() {
 262         SingleSelectionModel<String> sm = ComboBoxShim.<String>get_ComboBoxSelectionModel(comboBox);
 263         ObjectProperty<SingleSelectionModel<String>> other = new SimpleObjectProperty<SingleSelectionModel<String>>(sm);
 264         comboBox.selectionModelProperty().bind(other);
 265         assertSame(sm, sm);
 266     }
 267 
 268     @Test public void selectionModelCanBeChanged() {
 269         SingleSelectionModel<String> sm = ComboBoxShim.<String>get_ComboBoxSelectionModel(comboBox);
 270         comboBox.setSelectionModel(sm);
 271         assertSame(sm, sm);
 272     }
 273 
 274     @Test public void canSetSelectedItemToAnItemEvenWhenThereAreNoItems() {
 275         final String randomString = new String("I AM A CRAZY RANDOM STRING");
 276         sm.select(randomString);
 277         assertEquals(-1, sm.getSelectedIndex());
 278         assertSame(randomString, sm.getSelectedItem());
 279     }
 280 
 281     @Test public void canSetSelectedItemToAnItemNotInTheDataModel() {
 282         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 283         final String randomString = new String("I AM A CRAZY RANDOM STRING");
 284         sm.select(randomString);
 285         assertEquals(-1, sm.getSelectedIndex());
 286         assertSame(randomString, sm.getSelectedItem());
 287     }
 288 
 289     @Test public void settingTheSelectedItemToAnItemInItemsResultsInTheCorrectSelectedIndex() {
 290         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 291         sm.select("Orange");
 292         assertEquals(1, sm.getSelectedIndex());
 293         assertSame("Orange", sm.getSelectedItem());
 294     }
 295 
 296     @Test public void settingTheSelectedItemToANonexistantItemAndThenSettingItemsWhichContainsItResultsInCorrectSelectedIndex() {
 297         sm.select("Orange");
 298         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 299         assertEquals(1, sm.getSelectedIndex());
 300         assertSame("Orange", sm.getSelectedItem());
 301     }
 302 
 303     @Test public void ensureSelectionClearsWhenAllItemsAreRemoved_selectIndex0() {
 304         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 305         sm.select(0);
 306         comboBox.getItems().clear();
 307         assertEquals(-1, sm.getSelectedIndex());
 308         assertEquals(null, sm.getSelectedItem());
 309     }
 310 
 311     @Test public void ensureSelectionClearsWhenAllItemsAreRemoved_selectIndex2() {
 312         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 313         sm.select(2);
 314         comboBox.getItems().clear();
 315         assertEquals(-1, sm.getSelectedIndex());
 316         assertEquals(null, sm.getSelectedItem());
 317     }
 318 
 319     @Test public void ensureSelectedItemRemainsAccurateWhenItemsAreCleared() {
 320         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 321         sm.select(2);
 322         comboBox.getItems().clear();
 323         assertNull(sm.getSelectedItem());
 324         assertEquals(-1, sm.getSelectedIndex());
 325 
 326         comboBox.getItems().addAll("Kiwifruit", "Mandarin", "Pineapple");
 327         sm.select(2);
 328         assertEquals("Pineapple", sm.getSelectedItem());
 329     }
 330 
 331     @Test public void ensureSelectionShiftsDownWhenOneNewItemIsAdded() {
 332         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 333         sm.select(1);
 334         assertEquals(1, sm.getSelectedIndex());
 335         assertEquals("Orange", sm.getSelectedItem());
 336 
 337         comboBox.getItems().add(0, "Kiwifruit");
 338         assertEquals(2, sm.getSelectedIndex());
 339         assertEquals("Orange", sm.getSelectedItem());
 340     }
 341 
 342     @Test public void ensureSelectionShiftsDownWhenMultipleNewItemAreAdded() {
 343         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 344         sm.select(1);
 345         assertEquals(1, sm.getSelectedIndex());
 346         assertEquals("Orange", sm.getSelectedItem());
 347 
 348         comboBox.getItems().addAll(0, Arrays.asList("Kiwifruit", "Pineapple", "Mandarin"));
 349         assertEquals("Orange", sm.getSelectedItem());
 350         assertEquals(4, sm.getSelectedIndex());
 351     }
 352 
 353     @Test public void ensureSelectionShiftsUpWhenOneItemIsRemoved() {
 354         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 355         sm.select(1);
 356         assertEquals(1, sm.getSelectedIndex());
 357         assertEquals("Orange", sm.getSelectedItem());
 358 
 359         comboBox.getItems().remove("Apple");
 360         assertEquals(0, sm.getSelectedIndex());
 361         assertEquals("Orange", sm.getSelectedItem());
 362     }
 363 
 364     @Test public void ensureSelectionShiftsUpWheMultipleItemsAreRemoved() {
 365         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 366         sm.select(2);
 367         assertEquals(2, sm.getSelectedIndex());
 368         assertEquals("Banana", sm.getSelectedItem());
 369 
 370         comboBox.getItems().removeAll(Arrays.asList("Apple", "Orange"));
 371         assertEquals(0, sm.getSelectedIndex());
 372         assertEquals("Banana", sm.getSelectedItem());
 373     }
 374 
 375     @Test public void ensureSelectionIsCorrectWhenItemsChange() {
 376         comboBox.setItems(FXCollections.observableArrayList("Item 1"));
 377         sm.select(0);
 378         assertEquals("Item 1", sm.getSelectedItem());
 379 
 380         comboBox.setItems(FXCollections.observableArrayList("Item 2"));
 381         assertEquals(-1, sm.getSelectedIndex());
 382         assertEquals(null, sm.getSelectedItem());
 383     }
 384 
 385     @Test(expected=NullPointerException.class)
 386     public void selectionModelComboBoxReferenceCanNotBeNull() {
 387         ComboBoxShim.<String>get_ComboBoxSelectionModel(null);
 388     }
 389 
 390     @Test public void ensureGetModelItemOutOfBoundsWorks_1() {
 391         ComboBox cb = new ComboBox(null);
 392         cb.getSelectionModel().select(-1);
 393         assertEquals(-1, cb.getSelectionModel().getSelectedIndex());
 394     }
 395 
 396     @Test public void ensureGetModelItemOutOfBoundsWorks_2() {
 397         ComboBox cb = new ComboBox(null);
 398         cb.getSelectionModel().select(0);
 399         assertEquals(-1, cb.getSelectionModel().getSelectedIndex());
 400     }
 401 
 402     @Test public void test_rt15793() {
 403         // ComboBox selectedIndex is 0 although the items list is empty
 404         final ComboBox lv = new ComboBox();
 405         final ObservableList list = FXCollections.observableArrayList();
 406         lv.setItems(list);
 407         list.add("toto");
 408         lv.getSelectionModel().select(0);
 409         assertEquals(0, lv.getSelectionModel().getSelectedIndex());
 410         list.remove(0);
 411         assertEquals(-1, lv.getSelectionModel().getSelectedIndex());
 412     }
 413 
 414     @Test public void ensureSelectionModelUpdatesValueProperty_withSelectIndex() {
 415         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 416         assertNull(comboBox.getValue());
 417         sm.select(0);
 418         assertEquals("Apple", comboBox.getValue());
 419     }
 420 
 421     @Test public void ensureSelectionModelUpdatesValueProperty_withSelectItem() {
 422         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 423         assertNull(comboBox.getValue());
 424         sm.select("Apple");
 425         assertEquals("Apple", comboBox.getValue());
 426     }
 427 
 428     @Test public void ensureSelectionModelUpdatesValueProperty_withSelectPrevious() {
 429         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 430         assertNull(comboBox.getValue());
 431         sm.select(2);
 432         sm.selectPrevious();
 433         assertEquals("Orange", comboBox.getValue());
 434     }
 435 
 436     @Test public void ensureSelectionModelUpdatesValueProperty_withSelectNext() {
 437         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 438         assertNull(comboBox.getValue());
 439         sm.select("Apple");
 440         sm.selectNext();
 441         assertEquals("Orange", comboBox.getValue());
 442     }
 443 
 444     @Test public void ensureSelectionModelUpdatesValueProperty_withSelectFirst() {
 445         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 446         assertNull(comboBox.getValue());
 447         sm.selectFirst();
 448         assertEquals("Apple", comboBox.getValue());
 449     }
 450 
 451     @Test public void ensureSelectionModelUpdatesValueProperty_withSelectLast() {
 452         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 453         assertNull(comboBox.getValue());
 454         sm.selectLast();
 455         assertEquals("Banana", comboBox.getValue());
 456     }
 457 
 458     @Test public void ensureSelectionModelClearsValueProperty() {
 459         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 460         assertNull(comboBox.getValue());
 461         sm.select(0);
 462         assertEquals("Apple", comboBox.getValue());
 463 
 464         sm.clearSelection();
 465         assertNull(comboBox.getValue());
 466     }
 467 
 468     @Test public void ensureSelectionModelClearsValuePropertyWhenNegativeOneSelected() {
 469         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 470         assertNull(comboBox.getValue());
 471         sm.select(0);
 472         assertEquals("Apple", comboBox.getValue());
 473 
 474         sm.select(-1);
 475         assertNull("Expected null, actual value: " + comboBox.getValue(), comboBox.getValue());
 476     }
 477 
 478     @Test public void ensureValueIsCorrectWhenItemsIsAddedToWithExistingSelection() {
 479         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 480         sm.select(1);
 481 
 482         comboBox.getItems().add(0, "Kiwifruit");
 483 
 484         assertEquals(2, sm.getSelectedIndex());
 485         assertEquals("Orange", sm.getSelectedItem());
 486         assertEquals("Orange", comboBox.getValue());
 487     }
 488 
 489     @Test public void ensureValueIsCorrectWhenItemsAreRemovedWithExistingSelection() {
 490         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 491         sm.select(1);
 492 
 493         comboBox.getItems().remove("Apple");
 494 
 495         assertEquals(0, sm.getSelectedIndex());
 496         assertEquals("Orange", sm.getSelectedItem());
 497         assertEquals("Orange", comboBox.getValue());
 498     }
 499 
 500     @Test public void ensureValueIsUpdatedByCorrectSelectionModelWhenSelectionModelIsChanged() {
 501         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 502         SingleSelectionModel sm1 = sm;
 503         sm1.select(1);
 504         assertEquals("Orange", comboBox.getValue());
 505 
 506         SingleSelectionModel sm2 = ComboBoxShim.<String>get_ComboBoxSelectionModel(comboBox);
 507         comboBox.setSelectionModel(sm2);
 508 
 509         sm1.select(2);  // value should not change as we are using old SM
 510         assertEquals("Orange", comboBox.getValue());
 511 
 512         sm2.select(0);  // value should change, as we are using new SM
 513         assertEquals("Apple", comboBox.getValue());
 514     }
 515 
 516     @Test public void ensureValueDoesNotChangeWhenBoundAndNoExceptions() {
 517         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 518 
 519         StringProperty sp = new SimpleStringProperty("empty");
 520         comboBox.valueProperty().bind(sp);
 521 
 522         sm.select(1);
 523         assertEquals("empty", comboBox.getValue());
 524     }
 525 
 526     @Test public void ensureSelectionModelUpdatesWhenValueChanges() {
 527         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 528         assertNull(sm.getSelectedItem());
 529         comboBox.setValue("Orange");
 530         assertEquals("Orange", sm.getSelectedItem());
 531     }
 532 
 533     @Test public void ensureSelectionModelUpdatesWhenValueChangesToNull() {
 534         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 535         comboBox.setValue("Kiwifruit");
 536         assertEquals("Kiwifruit", sm.getSelectedItem());
 537         assertEquals("Kiwifruit", comboBox.getValue());
 538         comboBox.setValue(null);
 539         assertEquals(null, sm.getSelectedItem());
 540         assertEquals(-1, sm.getSelectedIndex());
 541         assertEquals(null, comboBox.getValue());
 542     }
 543 
 544     @Test public void ensureValueEqualsSelectedItemWhenNotInItemsList() {
 545         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 546         SelectionModelShim.setSelectedItem(sm, "pineapple");
 547         assertEquals("pineapple", sm.getSelectedItem());
 548         assertEquals("pineapple", comboBox.getValue());
 549     }
 550 
 551     /*********************************************************************
 552      * Tests for default values                                         *
 553      ********************************************************************/
 554 
 555     @Test public void checkPromptTextPropertyName() {
 556         assertTrue(comboBox.promptTextProperty().getName().equals("promptText"));
 557     }
 558 
 559     @Test public void checkPlaceholderPropertyName() {
 560         assertTrue(comboBox.placeholderProperty().getName().equals("placeholder"));
 561     }
 562 
 563     @Test public void checkValuePropertyName() {
 564         assertTrue(comboBox.valueProperty().getName().equals("value"));
 565     }
 566 
 567     @Test public void checkItemsPropertyName() {
 568         assertTrue(comboBox.itemsProperty().getName().equals("items"));
 569     }
 570 
 571     @Test public void checkConverterPropertyName() {
 572         assertTrue(comboBox.converterProperty().getName().equals("converter"));
 573     }
 574 
 575     @Test public void checkSelectionModelPropertyName() {
 576         assertTrue(comboBox.selectionModelProperty().getName().equals("selectionModel"));
 577     }
 578 
 579     @Test public void checkVisibleRowCountPropertyName() {
 580         assertTrue(comboBox.visibleRowCountProperty().getName().equals("visibleRowCount"));
 581     }
 582 
 583     @Test public void checkOnActionPropertyName() {
 584         assertTrue(comboBox.onActionProperty().getName().equals("onAction"));
 585     }
 586 
 587     @Test public void checkArmedPropertyName() {
 588         assertTrue(comboBox.armedProperty().getName().equals("armed"));
 589     }
 590 
 591     @Test public void checkShowingPropertyName() {
 592         assertTrue(comboBox.showingProperty().getName().equals("showing"));
 593     }
 594 
 595     @Test public void checkEditablePropertyName() {
 596         assertTrue(comboBox.editableProperty().getName().equals("editable"));
 597     }
 598 
 599     @Test public void checkCellFactoryPropertyName() {
 600         assertTrue(comboBox.cellFactoryProperty().getName().equals("cellFactory"));
 601     }
 602 
 603     @Test public void defaultActionHandlerIsNotDefined() {
 604         assertNull(comboBox.getOnAction());
 605     }
 606 
 607     @Test public void defaultConverterCanHandleStringValues() {
 608         StringConverter<String> sc = comboBox.getConverter();
 609         assertEquals("input", sc.fromString("input"));
 610         assertEquals("input", sc.toString("input"));
 611     }
 612 
 613     @Test public void defaultConverterCanHandleIncorrectType_1() {
 614         ComboBox cb = new ComboBox();
 615         StringConverter sc = cb.getConverter();
 616         assertEquals("42", sc.toString(new Integer(42)));
 617     }
 618 
 619     @Test(expected=ClassCastException.class)
 620     public void defaultConverterCanHandleIncorrectType_2() {
 621         ComboBox<Integer> cb = new ComboBox<Integer>();
 622         StringConverter<Integer> sc = cb.getConverter();
 623         Integer value = sc.fromString("42");
 624     }
 625 
 626     @Test public void defaultConverterCanHandleNullValues() {
 627         StringConverter<String> sc = comboBox.getConverter();
 628         assertEquals(null, sc.fromString(null));
 629         assertEquals(null, sc.toString(null));
 630     }
 631 
 632     @Test public void ensureImpl_getPseudoClassStateReturnsValidValue() {
 633         Set<PseudoClass> pseudoClassStates = comboBox.getPseudoClassStates();
 634         assertFalse(comboBox.isEditable());
 635         assertTrue(pseudoClassStates.size() >= 0);
 636 
 637         comboBox.setEditable(true);
 638         pseudoClassStates = comboBox.getPseudoClassStates();
 639         assertTrue(pseudoClassStates.contains(PseudoClass.getPseudoClass("editable")));
 640 
 641         comboBox.setEditable(false);
 642         pseudoClassStates = comboBox.getPseudoClassStates();
 643         assertTrue(pseudoClassStates.contains(PseudoClass.getPseudoClass("editable")) == false);
 644 
 645         comboBox.show();
 646         pseudoClassStates = comboBox.getPseudoClassStates();
 647         assertTrue(pseudoClassStates.contains(PseudoClass.getPseudoClass("showing")));
 648 
 649         comboBox.hide();
 650         pseudoClassStates = comboBox.getPseudoClassStates();
 651         assertTrue(pseudoClassStates.contains(PseudoClass.getPseudoClass("showing")) == false);
 652 
 653         comboBox.arm();
 654         pseudoClassStates = comboBox.getPseudoClassStates();
 655         assertTrue(pseudoClassStates.contains(PseudoClass.getPseudoClass("armed")));
 656 
 657     }
 658 
 659     /*********************************************************************
 660      * Tests for properties                                              *
 661      ********************************************************************/
 662 
 663     @Test public void ensureAllowsNullConverter() {
 664         comboBox.setConverter(null);
 665         assertNull(comboBox.getConverter());
 666     }
 667 
 668     @Test public void ensureCanSetNonNullCellFactory() {
 669         Callback<ListView<String>, ListCell<String>> cf = p -> null;
 670         comboBox.setCellFactory(cf);
 671         assertEquals(cf, comboBox.getCellFactory());
 672     }
 673 
 674     @Test public void ensureEditorIsNonNullWhenComboBoxIsNotEditable() {
 675         assertNotNull(comboBox.getEditor());
 676     }
 677 
 678     @Test public void ensureEditorIsNonNullWhenComboBoxIsEditable() {
 679         comboBox.setEditable(true);
 680         assertNotNull(comboBox.getEditor());
 681     }
 682 
 683     @Test public void ensureEditorDoesNotChangeWhenEditableToggles() {
 684         comboBox.setEditable(true);
 685         assertNotNull(comboBox.getEditor());
 686         comboBox.setEditable(false);
 687         assertNotNull(comboBox.getEditor());
 688         comboBox.setEditable(true);
 689         assertNotNull(comboBox.getEditor());
 690     }
 691 
 692     @Test public void ensureCanSetValueToNonNullStringAndBackAgain() {
 693         comboBox.setValue("Test 123");
 694         assertEquals("Test 123", comboBox.getValue());
 695         comboBox.setValue(null);
 696         assertNull(comboBox.getValue());
 697     }
 698 
 699     @Test public void ensureCanToggleEditable() {
 700         comboBox.setEditable(true);
 701         assertTrue(comboBox.isEditable());
 702         comboBox.setEditable(false);
 703         assertFalse(comboBox.isEditable());
 704     }
 705 
 706     @Test public void ensureCanToggleShowing() {
 707         comboBox.show();
 708         assertTrue(comboBox.isShowing());
 709         comboBox.hide();
 710         assertFalse(comboBox.isShowing());
 711     }
 712 
 713     @Test public void ensureCanNotToggleShowingWhenDisabled() {
 714         comboBox.setDisable(true);
 715         comboBox.show();
 716         assertFalse(comboBox.isShowing());
 717         comboBox.setDisable(false);
 718         comboBox.show();
 719         assertTrue(comboBox.isShowing());
 720     }
 721 
 722     @Test public void ensureCanSetPromptText() {
 723         comboBox.setPromptText("Test 1 2 3");
 724         assertEquals("Test 1 2 3", comboBox.getPromptText());
 725     }
 726 
 727     @Test public void ensureCanSetPromptTextToNull() {
 728         comboBox.setPromptText("");
 729         assertEquals("", comboBox.getPromptText());
 730         comboBox.setPromptText(null);
 731         assertEquals(null, comboBox.getPromptText());
 732     }
 733 
 734     @Test public void ensurePromptTextStripsNewlines() {
 735         comboBox.setPromptText("Test\n1\n2\n3");
 736         assertEquals("Test123", comboBox.getPromptText());
 737     }
 738 
 739     @Test public void ensureCanSetPlaceholder() {
 740         Label label = new javafx.scene.control.Label("Test 1 2 3");
 741         comboBox.setPlaceholder(label);
 742         assertEquals(label, comboBox.getPlaceholder());
 743     }
 744 
 745     @Test public void ensureCanToggleArmed() {
 746         assertFalse(comboBox.isArmed());
 747         comboBox.arm();
 748         assertTrue(comboBox.isArmed());
 749         comboBox.disarm();
 750         assertFalse(comboBox.isArmed());
 751     }
 752 
 753     @Test public void ensureCanSetVisibleRowCount() {
 754         comboBox.setVisibleRowCount(13);
 755         assertEquals(13, comboBox.getVisibleRowCount());
 756     }
 757 
 758     @Test public void ensureCanSetVisibleRowCountToNegativeValues() {
 759         comboBox.setVisibleRowCount(-10);
 760         assertEquals(-10, comboBox.getVisibleRowCount());
 761     }
 762 
 763     @Test public void ensureCanSetOnAction() {
 764         EventHandler<ActionEvent> onAction = t -> { };
 765         comboBox.setOnAction(onAction);
 766         assertEquals(onAction, comboBox.getOnAction());
 767     }
 768 
 769     @Test public void ensureOnActionPropertyReferencesBean() {
 770         assertEquals(comboBox, comboBox.onActionProperty().getBean());
 771     }
 772 
 773     /*********************************************************************
 774      * Tests for property binding                                        *
 775      ********************************************************************/
 776     @Test public void checkPromptTextPropertyBind() {
 777         StringProperty strPr = new SimpleStringProperty("value");
 778         comboBox.promptTextProperty().bind(strPr);
 779         assertTrue("PromptText cannot be bound", comboBox.getPromptText().equals("value"));
 780         strPr.setValue("newvalue");
 781         assertTrue("PromptText cannot be bound", comboBox.getPromptText().equals("newvalue"));
 782     }
 783 
 784     @Test public void checkValuePropertyBind() {
 785         StringProperty strPr = new SimpleStringProperty("value");
 786         comboBox.valueProperty().bind(strPr);
 787         assertTrue("value cannot be bound", comboBox.getValue().equals("value"));
 788         strPr.setValue("newvalue");
 789         assertTrue("value cannot be bound", comboBox.getValue().equals("newvalue"));
 790     }
 791 
 792 
 793 
 794     /*********************************************************************
 795      * Tests for bug reports                                             *
 796      ********************************************************************/
 797 
 798     @Test public void test_rt18972() {
 799         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 800         sm.select(1);
 801         assertTrue(sm.isSelected(1));
 802 
 803         comboBox.setEditable(true);
 804         comboBox.setValue("New Value");
 805 
 806         // there should be no selection in the selection model, as "New Value"
 807         // isn't an item in the list, however, it is a totally valid value for
 808         // the value property
 809         assertFalse(sm.isSelected(1));
 810         assertEquals("New Value", sm.getSelectedItem());
 811         assertEquals("New Value", comboBox.getValue());
 812 
 813         comboBox.setEditable(false);
 814         assertEquals(-1, sm.getSelectedIndex());
 815         assertEquals("New Value", sm.getSelectedItem());
 816         assertEquals("New Value", comboBox.getValue());
 817     }
 818 
 819     @Test public void test_rt18941() {
 820         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 821         comboBox.setValue("Orange");
 822         assertEquals("Orange", comboBox.getValue());
 823         assertEquals("Orange", comboBox.getSelectionModel().getSelectedItem());
 824         assertTrue("Selected Index: " + sm.getSelectedIndex(), sm.isSelected(1));
 825     }
 826 
 827     @Test public void test_rt19227() {
 828         comboBox.getItems().addAll("0","0","0","0","0");
 829         comboBox.getSelectionModel().select(2);
 830         assertEquals("0", comboBox.getValue());
 831         assertEquals("0", comboBox.getSelectionModel().getSelectedItem());
 832         assertTrue(sm.isSelected(2));
 833     }
 834 
 835     @Ignore("Test not working as the heights being returned are not accurate")
 836     @Test public void test_rt20106() {
 837         comboBox.getItems().addAll("0","1","2","3","4","5","6","7","8","9");
 838 
 839         Stage stage = new Stage();
 840         Scene scene = new Scene(comboBox);
 841         stage.setScene(scene);
 842         comboBox.applyCss();
 843         comboBox.show();
 844 
 845         comboBox.setVisibleRowCount(5);
 846         double initialHeight = getListView().getHeight();
 847         assertFalse("initialHeight: " + initialHeight, Double.compare(0.0, initialHeight) == 0);
 848 
 849         comboBox.setVisibleRowCount(0);
 850         double smallHeight =    getListView().getHeight();
 851         assertTrue("smallHeight: " + smallHeight + ", initialHeight: " + initialHeight,
 852                 smallHeight != initialHeight && smallHeight < initialHeight);
 853 
 854         comboBox.setVisibleRowCount(7);
 855         double biggerHeight = getListView().getHeight();
 856         assertTrue(biggerHeight != smallHeight && smallHeight < biggerHeight);
 857     }
 858 
 859     private int count = 0;
 860     @Test public void test_rt20103() {
 861         final TextField tf = new TextField();
 862 
 863         comboBox.setOnAction(t -> {
 864             count++;
 865         });
 866 
 867         assertTrue(count == 0);
 868 
 869         comboBox.valueProperty().bind(tf.textProperty());   // count++ here
 870         assertTrue("count: " + count, count == 1);
 871 
 872         tf.setText("Text1");                                // count++ here
 873         assertTrue("count: " + count, count == 2);
 874 
 875         comboBox.valueProperty().unbind();                  // no count++ here
 876         assertTrue("count: " + count, count == 2);
 877 
 878         comboBox.valueProperty().bindBidirectional(tf.textProperty());  // count++ here
 879         tf.setText("Text2");
 880         assertTrue("count: " + count, count == 3);
 881     }
 882 
 883     @Ignore("Test not working as the skin is not being properly instantiated")
 884     @Test public void test_rt20100() {
 885         comboBox.getItems().addAll("0","1","2","3","4","5","6","7","8","9");
 886 
 887         Stage stage = new Stage();
 888         Scene scene = new Scene(comboBox);
 889         stage.setScene(scene);
 890         comboBox.applyCss();
 891         comboBox.show();
 892 
 893         comboBox.setConverter(new StringConverter() {
 894             int toStringCounter = 0;
 895             int fromStringCounter = 0;
 896 
 897             @Override public String toString(Object t) {
 898                 return "TO_STRING";
 899             }
 900 
 901             @Override public Object fromString(String string) {
 902                 return "FROM_STRING";
 903             }
 904         });
 905 
 906         comboBox.getSelectionModel().select(2);
 907         assertEquals("2", comboBox.getValue());
 908 
 909         ListView listView = getListView();
 910 //        listView.applyCss();
 911 
 912         assertEquals("2", listView.getSelectionModel().getSelectedItem());
 913 
 914         System.out.println(listView.getSkin());
 915 
 916         VirtualFlow flow = (VirtualFlow)listView.lookup("#virtual-flow");
 917         assertNotNull(flow);
 918 
 919         IndexedCell cell = flow.getVisibleCell(2);
 920         System.out.println("cell: " + cell);
 921         assertEquals("TO_STRING", cell.getText());
 922     }
 923 
 924     @Ignore
 925     @Test public void test_rt20189() {
 926         comboBox.getItems().addAll("0","1","2","3","4","5","6","7","8","9");
 927 
 928         Stage stage = new Stage();
 929         Scene scene = new Scene(comboBox);
 930         stage.setScene(scene);
 931         comboBox.applyCss();
 932         comboBox.show();
 933 
 934         SelectionModel sm = getListView().getSelectionModel();
 935 
 936         comboBox.getSelectionModel().select(2);
 937         Object item = sm.getSelectedItem();
 938         assertEquals("2", item);
 939         assertEquals(2, sm.getSelectedIndex());
 940 
 941         comboBox.setValue("test");
 942         item = sm.getSelectedItem();
 943         assertEquals("test",item);
 944         assertEquals(-1, sm.getSelectedIndex());
 945 
 946         comboBox.getSelectionModel().select(2);
 947         item = sm.getSelectedItem();
 948         assertEquals("2", item);
 949         assertEquals(2, sm.getSelectedIndex());
 950     }
 951 
 952     @Test public void test_rt27654() {
 953         comboBox.getItems().addAll("0","1","2","3","4","5","6","7","8","9");
 954 
 955         SingleSelectionModel sm = comboBox.getSelectionModel();
 956 
 957         Stage stage = new Stage();
 958         Scene scene = new Scene(comboBox);
 959         stage.setScene(scene);
 960         comboBox.applyCss();
 961         comboBox.show();
 962         ListCell<String> buttonCell = (ListCell<String>) getDisplayNode();
 963 
 964         sm.select(2);
 965         assertEquals("2", sm.getSelectedItem());
 966         assertEquals("2", comboBox.getValue());
 967         assertEquals("2", buttonCell.getText());
 968         assertEquals(2, sm.getSelectedIndex());
 969 
 970         sm.clearSelection();
 971         assertNull(sm.getSelectedItem());
 972         assertNull(comboBox.getValue());
 973         assertNull(buttonCell.getText());
 974         assertEquals(-1, sm.getSelectedIndex());
 975 
 976         sm.select(2);
 977         assertEquals("2", sm.getSelectedItem());
 978         assertEquals("2", comboBox.getValue());
 979         assertEquals("2", buttonCell.getText());
 980         assertEquals(2, sm.getSelectedIndex());
 981     }
 982 
 983     @Test public void test_rt24412() {
 984         SingleSelectionModel sm = comboBox.getSelectionModel();
 985 
 986         Stage stage = new Stage();
 987         Scene scene = new Scene(comboBox);
 988         stage.setScene(scene);
 989         comboBox.applyCss();
 990         comboBox.show();
 991         ListCell<String> buttonCell = (ListCell<String>) getDisplayNode();
 992 
 993         comboBox.getItems().setAll("0","1","2","3","4","5","6","7","8","9");
 994 
 995         sm.select("2");
 996         assertEquals("2", sm.getSelectedItem());
 997         assertEquals("2", comboBox.getValue());
 998         assertEquals("2", buttonCell.getText());
 999         assertEquals(2, sm.getSelectedIndex());
1000 
1001         sm.clearSelection();
1002         assertNull(sm.getSelectedItem());
1003         assertNull(comboBox.getValue());
1004         assertNull(buttonCell.getText());
1005         assertEquals(-1, sm.getSelectedIndex());
1006 
1007         sm.select("2");
1008         assertEquals("2", sm.getSelectedItem());
1009         assertEquals("2", comboBox.getValue());
1010         assertEquals("2", buttonCell.getText());
1011         assertEquals(2, sm.getSelectedIndex());
1012     }
1013 
1014     @Test public void test_rt28245() {
1015         final ObservableList<String> strings = FXCollections.observableArrayList(
1016             "Option 1", "Option 2", "Option 3"
1017         );
1018 
1019         ComboBox<String> comboBox = new ComboBox<String>();
1020         comboBox.setItems(strings);
1021         comboBox.setEditable(true);
1022         comboBox.valueProperty().addListener((ov, t, t1) -> {
1023             if (t == null && t1.isEmpty()) {
1024                 fail("Old value is '" + t + "' and new value is '" + t1 + "'.");
1025             }
1026         });
1027 
1028         StageLoader sl = new StageLoader(comboBox);
1029 
1030         assertNull(comboBox.getValue());
1031         assertTrue(comboBox.getEditor().getText().isEmpty());
1032 
1033         comboBox.requestFocus();
1034 
1035         new KeyEventFirer(comboBox).doKeyPress(KeyCode.ENTER);
1036 
1037         sl.dispose();
1038     }
1039 
1040     @Test public void test_rt31479() {
1041         ComboBox<String> comboBox = new ComboBox<String>();
1042 
1043         StageLoader sl = new StageLoader(comboBox);
1044 
1045         final double widthBefore = comboBox.getWidth();
1046 
1047         // add item
1048         comboBox.getItems().add("Option 1");
1049 
1050         // open and close combobox
1051         comboBox.show();
1052         comboBox.hide();
1053 
1054         // set a placeholder
1055         comboBox.setPlaceholder(new Circle(12, Color.RED));
1056 
1057         // remove item
1058         comboBox.getItems().clear();
1059 
1060         // fire pulse (this allows layout to cause the size to grow)
1061         Toolkit.getToolkit().firePulse();
1062 
1063         // test size
1064         assertEquals(widthBefore, comboBox.getWidth(), 0.00);
1065 
1066         sl.dispose();
1067     }
1068 
1069     @Test public void test_rt32139() {
1070         final ObservableList<String> items =
1071                 FXCollections.observableArrayList("Good value", "Bad value");
1072 
1073         final ComboBox<String> comboBox = new ComboBox<>(items);
1074         comboBox.getSelectionModel().select(0);
1075 
1076         comboBox.getSelectionModel().selectedIndexProperty().addListener((ov, oldIdx, newIdx) -> {
1077             if (newIdx.intValue() != 0) {
1078                 comboBox.getSelectionModel().select(0);
1079             }
1080         });
1081 
1082         StageLoader sl = new StageLoader(comboBox);
1083 
1084         try {
1085             comboBox.getSelectionModel().select(1);
1086         } catch (StackOverflowError e) {
1087             fail("Stack overflow should not happen here");
1088         }
1089 
1090         sl.dispose();
1091     }
1092 
1093     @Test public void test_rt21186() {
1094         final ComboBox<String> comboBox = new ComboBox<>();
1095         comboBox.setEditable(true);
1096 
1097         StageLoader sl = new StageLoader(comboBox);
1098 
1099         assertNull(comboBox.getTooltip());
1100         assertNull(comboBox.getEditor().getTooltip());
1101 
1102         Tooltip tooltip = new Tooltip("Tooltip");
1103         comboBox.setTooltip(tooltip);
1104         assertEquals(tooltip, comboBox.getTooltip());
1105         assertEquals(tooltip, comboBox.getEditor().getTooltip());
1106 
1107         comboBox.setTooltip(null);
1108         assertNull(comboBox.getTooltip());
1109         assertNull(comboBox.getEditor().getTooltip());
1110 
1111         sl.dispose();
1112     }
1113 
1114     @Test public void test_rt34573() {
1115         final ComboBox<String> comboBox = new ComboBox<>();
1116 
1117         final ListCell<String> customCell = new ListCellShim<String>() {
1118             @Override public void updateItem(String item, boolean empty) {
1119                 super.updateItem(item, empty);
1120                 setText(item);
1121             }
1122         };
1123         comboBox.setButtonCell(customCell);
1124 
1125         StageLoader sl = new StageLoader(comboBox);
1126 
1127         comboBox.setItems(FXCollections.observableArrayList("A","B","C","D"));
1128         comboBox.setValue("B");
1129         assertEquals("B", comboBox.getButtonCell().getText());
1130         assertEquals(1, comboBox.getButtonCell().getIndex());
1131 
1132         comboBox.setItems(FXCollections.observableArrayList("1","2","3","4"));
1133         assertNull(comboBox.getButtonCell().getText());
1134         assertEquals(-1, comboBox.getButtonCell().getIndex());
1135 
1136         sl.dispose();
1137     }
1138 
1139     @Test public void test_rt34566() {
1140         final ComboBox<String> comboBox = new ComboBox<>();
1141 
1142         final ListCell<String> customCell = new ListCellShim<String>() {
1143             @Override public void updateItem(String item, boolean empty) {
1144                 super.updateItem(item, empty);
1145                 setText(item);
1146             }
1147         };
1148         comboBox.setButtonCell(customCell);
1149 
1150         StageLoader sl = new StageLoader(comboBox);
1151 
1152         comboBox.setItems(FXCollections.observableArrayList("A","B","C","D"));
1153 
1154         PseudoClass empty = PseudoClass.getPseudoClass("empty");
1155 
1156         comboBox.setValue("B");
1157         assertEquals("B", comboBox.getButtonCell().getText());
1158         assertEquals(1, comboBox.getButtonCell().getIndex());
1159         assertFalse(customCell.getPseudoClassStates().contains(empty));
1160 
1161         comboBox.setValue(null);
1162         Toolkit.getToolkit().firePulse();
1163         assertNull(comboBox.getButtonCell().getText());
1164         assertEquals(-1, comboBox.getButtonCell().getIndex());
1165         assertTrue(customCell.getPseudoClassStates().contains(empty));
1166 
1167         comboBox.setValue("A");
1168         assertEquals("A", comboBox.getButtonCell().getText());
1169         assertEquals(0, comboBox.getButtonCell().getIndex());
1170         assertFalse(customCell.getPseudoClassStates().contains(empty));
1171 
1172         sl.dispose();
1173     }
1174 
1175     private int test_rt34603_count = 0;
1176     @Ignore("Bug has not yet been resolved")
1177     @Test public void test_rt34603() {
1178         assertEquals(0, test_rt34603_count);
1179 
1180         VBox hbox = new VBox(10);
1181 
1182         ComboBox<String> box = new ComboBox<>();
1183         box.getItems().add("test");
1184         box.setEditable(true);
1185         box.getSelectionModel().selectFirst();
1186 
1187         Button defaultButton = new Button("press");
1188         defaultButton.setOnAction(arg0 -> {
1189             test_rt34603_count++;
1190         });
1191         defaultButton.setDefaultButton(true);
1192 
1193         hbox.getChildren().addAll(box, defaultButton);
1194 
1195         StageLoader sl = new StageLoader(hbox);
1196 
1197         box.getEditor().requestFocus();
1198         KeyEventFirer keyboard = new KeyEventFirer(box);
1199         keyboard.doKeyPress(KeyCode.ENTER);
1200 
1201         assertEquals(1, test_rt34603_count);
1202 
1203         sl.dispose();
1204     }
1205 
1206     private int test_rt35586_count = 0;
1207     @Test public void test_rt35586() {
1208         assertEquals(0, test_rt35586_count);
1209 
1210         final ComboBox<String> cb = new ComboBox<String>();
1211         cb.setEditable(true);
1212         cb.setOnAction(event -> {
1213             test_rt35586_count++;
1214             assertEquals("Test", cb.getEditor().getText());
1215         });
1216 
1217         StageLoader sl = new StageLoader(cb);
1218 
1219         cb.requestFocus();
1220         cb.getEditor().setText("Test");
1221         KeyEventFirer keyboard = new KeyEventFirer(cb);
1222         keyboard.doKeyPress(KeyCode.ENTER);
1223 
1224         assertEquals(1, test_rt35586_count);
1225 
1226         sl.dispose();
1227     }
1228 
1229     @Test public void test_rt35039() {
1230         final List<String> data = new ArrayList<>();
1231         data.add("aabbaa");
1232         data.add("bbc");
1233 
1234         final ComboBox<String> combo = new ComboBox<>();
1235         combo.setEditable(true);
1236         combo.setItems(FXCollections.observableArrayList(data));
1237 
1238         StageLoader sl = new StageLoader(combo);
1239 
1240         // everything should be null to start with
1241         assertNull(combo.getValue());
1242         assertTrue(combo.getEditor().getText().isEmpty());
1243         assertNull(combo.getSelectionModel().getSelectedItem());
1244 
1245         // select "bbc" and ensure everything is set to that
1246         combo.getSelectionModel().select(1);
1247         assertEquals("bbc", combo.getValue());
1248         assertEquals("bbc", combo.getEditor().getText());
1249         assertEquals("bbc", combo.getSelectionModel().getSelectedItem());
1250 
1251         // change the items list - but retain the same content. We expect
1252         // that "bbc" remains selected as it is still in the list
1253         combo.setItems(FXCollections.observableArrayList(data));
1254         assertEquals("bbc", combo.getValue());
1255         assertEquals("bbc", combo.getEditor().getText());
1256         assertEquals("bbc", combo.getSelectionModel().getSelectedItem());
1257 
1258         sl.dispose();
1259     }
1260 
1261     @Test public void test_rt35840() {
1262         final ComboBox<String> cb = new ComboBox<String>();
1263         cb.setEditable(true);
1264         StageLoader sl = new StageLoader(cb);
1265         cb.requestFocus();
1266 
1267         KeyEventFirer keyboard = new KeyEventFirer(cb);
1268         keyboard.doKeyTyped(KeyCode.T);
1269         keyboard.doKeyTyped(KeyCode.E);
1270         keyboard.doKeyTyped(KeyCode.S);
1271         keyboard.doKeyTyped(KeyCode.T);
1272         assertEquals("TEST", cb.getEditor().getText());
1273 
1274         assertNull(cb.getValue());
1275         keyboard.doKeyPress(KeyCode.ENTER);
1276         assertEquals("TEST", cb.getValue());
1277 
1278         sl.dispose();
1279     }
1280 
1281     @Test public void test_rt36280_nonEditable_F4ShowsPopup() {
1282         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1283         StageLoader sl = new StageLoader(cb);
1284         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1285 
1286         assertFalse(cb.isShowing());
1287         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1288         assertTrue(cb.isShowing());
1289 
1290         sl.dispose();
1291     }
1292 
1293     @Test public void test_rt36280_nonEditable_altUpShowsPopup() {
1294         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1295         StageLoader sl = new StageLoader(cb);
1296         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1297 
1298         assertFalse(cb.isShowing());
1299         cbKeyboard.doKeyPress(KeyCode.UP, KeyModifier.ALT);  // show the popup
1300         assertTrue(cb.isShowing());
1301 
1302         sl.dispose();
1303     }
1304 
1305     @Test public void test_rt36280_nonEditable_altDownShowsPopup() {
1306         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1307         StageLoader sl = new StageLoader(cb);
1308         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1309 
1310         new StageLoader(cb);
1311 
1312         assertFalse(cb.isShowing());
1313         cbKeyboard.doKeyPress(KeyCode.DOWN, KeyModifier.ALT);  // show the popup
1314         assertTrue(cb.isShowing());
1315 
1316         sl.dispose();
1317     }
1318 
1319     @Test public void test_rt36280_nonEditable_enterHidesShowingPopup() {
1320         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1321         StageLoader sl = new StageLoader(cb);
1322         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1323 
1324         ListView listView = (ListView) ((ComboBoxListViewSkin)cb.getSkin()).getPopupContent();
1325         assertNotNull(listView);
1326 
1327         KeyEventFirer lvKeyboard = new KeyEventFirer(listView);
1328 
1329         assertFalse(cb.isShowing());
1330         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1331         assertTrue(cb.isShowing());
1332         lvKeyboard.doKeyPress(KeyCode.ENTER);  // hide the popup
1333         assertFalse(cb.isShowing());
1334 
1335         sl.dispose();
1336     }
1337 
1338     @Test public void test_rt36280_nonEditable_spaceHidesShowingPopup() {
1339         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1340         StageLoader sl = new StageLoader(cb);
1341         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1342 
1343         ListView listView = (ListView) ((ComboBoxListViewSkin)cb.getSkin()).getPopupContent();
1344         assertNotNull(listView);
1345 
1346         KeyEventFirer lvKeyboard = new KeyEventFirer(listView);
1347 
1348         assertFalse(cb.isShowing());
1349         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1350         assertTrue(cb.isShowing());
1351         lvKeyboard.doKeyPress(KeyCode.SPACE);  // hide the popup
1352         assertFalse(cb.isShowing());
1353 
1354         sl.dispose();
1355     }
1356 
1357     @Test public void test_rt36280_nonEditable_escapeHidesShowingPopup() {
1358         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1359         StageLoader sl = new StageLoader(cb);
1360         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1361 
1362         ListView listView = (ListView) ((ComboBoxListViewSkin)cb.getSkin()).getPopupContent();
1363         assertNotNull(listView);
1364 
1365         KeyEventFirer lvKeyboard = new KeyEventFirer(listView);
1366 
1367         assertFalse(cb.isShowing());
1368         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1369         assertTrue(cb.isShowing());
1370         lvKeyboard.doKeyPress(KeyCode.ESCAPE);  // hide the popup
1371         assertFalse(cb.isShowing());
1372 
1373         sl.dispose();
1374     }
1375 
1376     @Test public void test_rt36280_nonEditable_F4HidesShowingPopup() {
1377         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1378         StageLoader sl = new StageLoader(cb);
1379         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1380 
1381         assertFalse(cb.isShowing());
1382         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1383         assertTrue(cb.isShowing());
1384         cbKeyboard.doKeyPress(KeyCode.F4);  // hide the popup
1385         assertFalse(cb.isShowing());
1386 
1387         sl.dispose();
1388     }
1389 
1390     @Test public void test_rt36280_nonEditable_arrowKeysChangeSelection() {
1391         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1392         StageLoader sl = new StageLoader(cb);
1393         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1394 
1395         assertFalse(cb.isShowing());
1396         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1397         assertTrue(cb.isShowing());
1398 
1399         assertNull(cb.getSelectionModel().getSelectedItem());
1400 
1401         cbKeyboard.doDownArrowPress();
1402         assertEquals("a", cb.getSelectionModel().getSelectedItem());
1403 
1404         cbKeyboard.doDownArrowPress();
1405         assertEquals("b", cb.getSelectionModel().getSelectedItem());
1406 
1407         cbKeyboard.doUpArrowPress();
1408         assertEquals("a", cb.getSelectionModel().getSelectedItem());
1409 
1410         sl.dispose();
1411     }
1412 
1413     @Test public void test_rt36280_editable_F4ShowsPopup() {
1414         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1415         cb.setEditable(true);
1416         StageLoader sl = new StageLoader(cb);
1417         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1418 
1419         assertFalse(cb.isShowing());
1420         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1421         assertTrue(cb.isShowing());
1422 
1423         sl.dispose();
1424     }
1425 
1426     @Test public void test_rt36280_editable_altUpShowsPopup() {
1427         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1428         cb.setEditable(true);
1429         StageLoader sl = new StageLoader(cb);
1430         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1431 
1432         assertFalse(cb.isShowing());
1433         cbKeyboard.doKeyPress(KeyCode.UP, KeyModifier.ALT);  // show the popup
1434         assertTrue(cb.isShowing());
1435 
1436         sl.dispose();
1437     }
1438 
1439     @Test public void test_rt36280_editable_altDownShowsPopup_onComboBox() {
1440         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1441         cb.setEditable(true);
1442         StageLoader sl = new StageLoader(cb);
1443         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1444 
1445         assertFalse(cb.isShowing());
1446         assertTrue(cb.getEditor().getText().isEmpty());
1447         cbKeyboard.doKeyPress(KeyCode.DOWN, KeyModifier.ALT);  // show the popup
1448         assertTrue(cb.isShowing());
1449         assertTrue(cb.getEditor().getText().isEmpty());
1450 
1451         sl.dispose();
1452     }
1453 
1454     @Test public void test_rt36280_editable_altDownShowsPopup_onTextField() {
1455         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1456         cb.setEditable(true);
1457         StageLoader sl = new StageLoader(cb);
1458 
1459         KeyEventFirer tfKeyboard = new KeyEventFirer(cb.getEditor());
1460         assertFalse(cb.isShowing());
1461         assertTrue(cb.getEditor().getText().isEmpty());
1462         tfKeyboard.doKeyPress(KeyCode.DOWN, KeyModifier.ALT);  // show the popup
1463         assertTrue(cb.isShowing());
1464         assertTrue(cb.getEditor().getText().isEmpty());
1465 
1466         sl.dispose();
1467     }
1468 
1469     @Test public void test_rt36280_editable_enterHidesShowingPopup() {
1470         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1471         cb.setEditable(true);
1472         StageLoader sl = new StageLoader(cb);
1473         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1474 
1475         ListView listView = (ListView) ((ComboBoxListViewSkin)cb.getSkin()).getPopupContent();
1476         assertNotNull(listView);
1477 
1478         KeyEventFirer lvKeyboard = new KeyEventFirer(listView);
1479 
1480         assertFalse(cb.isShowing());
1481         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1482         assertTrue(cb.isShowing());
1483         lvKeyboard.doKeyPress(KeyCode.ENTER);  // hide the popup
1484         assertFalse(cb.isShowing());
1485 
1486         sl.dispose();
1487     }
1488 
1489     @Test public void test_rt36280_editable_spaceHidesShowingPopup() {
1490         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1491         cb.setEditable(true);
1492         StageLoader sl = new StageLoader(cb);
1493         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1494 
1495         ListView listView = (ListView) ((ComboBoxListViewSkin)cb.getSkin()).getPopupContent();
1496         assertNotNull(listView);
1497 
1498         KeyEventFirer lvKeyboard = new KeyEventFirer(listView);
1499 
1500         assertFalse(cb.isShowing());
1501         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1502         assertTrue(cb.isShowing());
1503         lvKeyboard.doKeyPress(KeyCode.SPACE);  // hide the popup
1504         assertFalse(cb.isShowing());
1505 
1506         sl.dispose();
1507     }
1508 
1509     @Test public void test_rt36280_editable_escapeHidesShowingPopup() {
1510         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1511         cb.setEditable(true);
1512         StageLoader sl = new StageLoader(cb);
1513         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1514 
1515         ListView listView = (ListView) ((ComboBoxListViewSkin)cb.getSkin()).getPopupContent();
1516         assertNotNull(listView);
1517 
1518         KeyEventFirer lvKeyboard = new KeyEventFirer(listView);
1519 
1520         assertFalse(cb.isShowing());
1521         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1522         assertTrue(cb.isShowing());
1523         lvKeyboard.doKeyPress(KeyCode.ESCAPE);  // hide the popup
1524         assertFalse(cb.isShowing());
1525 
1526         sl.dispose();
1527     }
1528 
1529     @Test public void test_rt36280_editable_F4HidesShowingPopup() {
1530         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1531         cb.setEditable(true);
1532         StageLoader sl = new StageLoader(cb);
1533         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1534 
1535         assertFalse(cb.isShowing());
1536         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1537         assertTrue(cb.isShowing());
1538         cbKeyboard.doKeyPress(KeyCode.F4);  // hide the popup
1539         assertFalse(cb.isShowing());
1540 
1541         sl.dispose();
1542     }
1543 
1544     @Test public void test_rt36280_editable_arrowKeysChangeSelection() {
1545         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1546         cb.setEditable(true);
1547         StageLoader sl = new StageLoader(cb);
1548         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1549 
1550         assertFalse(cb.isShowing());
1551         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1552         assertTrue(cb.isShowing());
1553 
1554         assertNull(cb.getSelectionModel().getSelectedItem());
1555 
1556         cbKeyboard.doDownArrowPress();
1557         assertEquals("a", cb.getSelectionModel().getSelectedItem());
1558 
1559         cbKeyboard.doDownArrowPress();
1560         assertEquals("b", cb.getSelectionModel().getSelectedItem());
1561 
1562         cbKeyboard.doUpArrowPress();
1563         assertEquals("a", cb.getSelectionModel().getSelectedItem());
1564 
1565         sl.dispose();
1566     }
1567 
1568     @Test public void test_rt36651() {
1569         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1570         cb.setEditable(true);
1571         StageLoader sl = new StageLoader(cb);
1572 
1573         assertNull(cb.getValue());
1574         assertEquals(-1, cb.getSelectionModel().getSelectedIndex());
1575         assertNull(cb.getSelectionModel().getSelectedItem());
1576 
1577         sl.getStage().requestFocus();
1578         cb.show();
1579         Toolkit.getToolkit().firePulse();
1580 
1581         // selection should not change just by showing the popup
1582         assertNull(cb.getValue());
1583         assertEquals(-1, cb.getSelectionModel().getSelectedIndex());
1584         assertNull(cb.getSelectionModel().getSelectedItem());
1585 
1586         sl.dispose();
1587     }
1588 
1589     @Test public void test_rt36717() {
1590         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1591         StageLoader sl = new StageLoader(cb);
1592 
1593         // the stack overflow only occurs when a ComboBox changes from non-editable to editable
1594         cb.setEditable(false);
1595         cb.setEditable(true);
1596         assertNotNull(cb.getEditor());
1597         KeyEventFirer tfKeyboard = new KeyEventFirer(cb.getEditor());
1598         tfKeyboard.doKeyPress(KeyCode.ENTER);   // Stack overflow here
1599 
1600         sl.dispose();
1601     }
1602 
1603     @Test public void test_rt36827() {
1604         final Button btn = new Button("focus owner");
1605         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1606         VBox vbox = new VBox(btn, cb);
1607 
1608         StageLoader sl = new StageLoader(vbox);
1609         sl.getStage().requestFocus();
1610         btn.requestFocus();
1611         Toolkit.getToolkit().firePulse();
1612         Scene scene = sl.getStage().getScene();
1613 
1614         assertTrue(btn.isFocused());
1615         assertEquals(btn, scene.getFocusOwner());
1616 
1617         MouseEventFirer mouse = new MouseEventFirer(cb);
1618         mouse.fireMousePressAndRelease();
1619 
1620         assertTrue(cb.isShowing());
1621         assertTrue(cb.isFocused());
1622         assertEquals(cb, scene.getFocusOwner());
1623 
1624         sl.dispose();
1625     }
1626 
1627     @Test public void test_rt36902() {
1628         final ComboBox<String> cb1 = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1629         final ComboBox<String> cb2 = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1630         cb2.setEditable(true);
1631         VBox vbox = new VBox(cb1, cb2);
1632 
1633         // lame - I would rather have one keyboard here but I couldn't get it to
1634         // work, so watch out for which keyboard is used below
1635         KeyEventFirer cb1Keyboard = new KeyEventFirer(cb1);
1636         KeyEventFirer cb2Keyboard = new KeyEventFirer(cb2);
1637 
1638         StageLoader sl = new StageLoader(vbox);
1639         sl.getStage().requestFocus();
1640         cb1.requestFocus();
1641         Toolkit.getToolkit().firePulse();
1642         Scene scene = sl.getStage().getScene();
1643 
1644         assertTrue(cb1.isFocused());
1645         assertEquals(cb1, scene.getFocusOwner());
1646 
1647         // move focus forward to cb2
1648         cb1Keyboard.doKeyPress(KeyCode.TAB);
1649         assertTrue(cb2.isFocused());
1650         assertEquals(cb2, scene.getFocusOwner());
1651 
1652         // move focus forward again to cb1
1653         cb2Keyboard.doKeyPress(KeyCode.TAB);
1654         assertTrue(cb1.isFocused());
1655         assertEquals(cb1, scene.getFocusOwner());
1656 
1657         // now start going backwards with shift-tab.
1658         // The first half of the bug is here - when we shift-tab into cb2, we
1659         // actually go into the FakeFocusTextField subcomponent, so whilst the
1660         // cb2.isFocused() returns true as expected, the scene focus owner is
1661         // not the ComboBox, but the FakeFocusTextField inside it
1662         cb1Keyboard.doKeyPress(KeyCode.TAB, KeyModifier.SHIFT);
1663         assertTrue("Expect cb2 to be focused, but actual focus owner is: " + scene.getFocusOwner(),
1664                 cb2.isFocused());
1665         // Updated with fix for RT-34602: The TextField now never gets
1666         // focus (it's just faking it).
1667         // assertEquals("Expect cb2 TextField to be focused, but actual focus owner is: " + scene.getFocusOwner(),
1668         //         cb2.getEditor(), scene.getFocusOwner());
1669         assertEquals("Expect cb2 to be focused, but actual focus owner is: " + scene.getFocusOwner(),
1670                      cb2, scene.getFocusOwner());
1671 
1672         // This is where the second half of the bug appears, as we are stuck in
1673         // the FakeFocusTextField of cb2, we never make it to cb1
1674         cb2Keyboard.doKeyPress(KeyCode.TAB, KeyModifier.SHIFT);
1675         assertTrue(cb1.isFocused());
1676         assertEquals(cb1, scene.getFocusOwner());
1677 
1678         sl.dispose();
1679     }
1680 
1681     private int rt_38901_counter;
1682     @Test public void test_rt_38901_selectNull() {
1683         test_rt_38901(true);
1684     }
1685 
1686     @Test public void test_rt_38901_selectNegativeOne() {
1687         test_rt_38901(false);
1688     }
1689 
1690     private void test_rt_38901(boolean selectNull) {
1691         rt_38901_counter = 0;
1692 
1693         final ComboBox<String> cb = new ComboBox<>();
1694         cb.setOnShowing((e) -> {
1695             cb.getItems().setAll("DUMMY " + (rt_38901_counter++));
1696         });
1697 
1698         assertEquals(-1, cb.getSelectionModel().getSelectedIndex());
1699         assertNull(cb.getSelectionModel().getSelectedItem());
1700         assertNull(cb.getValue());
1701         assertEquals(0, cb.getItems().size());
1702 
1703         // round one
1704         cb.show();
1705         assertEquals(1, cb.getItems().size());
1706         assertEquals("DUMMY 0", cb.getItems().get(0));
1707         cb.hide();
1708 
1709         cb.getSelectionModel().select(0);
1710         assertEquals(0, cb.getSelectionModel().getSelectedIndex());
1711         assertEquals("DUMMY 0", cb.getSelectionModel().getSelectedItem());
1712         assertEquals("DUMMY 0", cb.getValue());
1713 
1714         if (selectNull) cb.getSelectionModel().select(null);
1715         else cb.getSelectionModel().select(-1);
1716 
1717         assertEquals(-1, cb.getSelectionModel().getSelectedIndex());
1718         assertNull(cb.getSelectionModel().getSelectedItem());
1719         assertNull(cb.getValue());
1720 
1721 
1722         // round two
1723         cb.show();
1724         assertEquals(1, cb.getItems().size());
1725         assertEquals("DUMMY 1", cb.getItems().get(0));
1726         cb.hide();
1727 
1728         cb.getSelectionModel().select(0);
1729         assertEquals(0, cb.getSelectionModel().getSelectedIndex());
1730         assertEquals("DUMMY 1", cb.getSelectionModel().getSelectedItem());
1731         assertEquals("DUMMY 1", cb.getValue());
1732 
1733         if (selectNull) cb.getSelectionModel().select(null);
1734         else cb.getSelectionModel().select(-1);
1735 
1736         assertEquals(-1, cb.getSelectionModel().getSelectedIndex());
1737         assertNull(cb.getSelectionModel().getSelectedItem());
1738         assertNull(cb.getValue());
1739     }
1740 
1741     private int rt_22572_counter;
1742     @Test public void test_rt_22572() {
1743         rt_22572_counter = 0;
1744 
1745         final ComboBox<String> cb = new ComboBox<>();
1746         cb.setOnShowing((e) -> {
1747             cb.getItems().setAll("DUMMY " + (rt_22572_counter++));
1748         });
1749 
1750         StageLoader sl = new StageLoader(cb);
1751 
1752         assertEquals(-1, cb.getSelectionModel().getSelectedIndex());
1753         assertNull(cb.getSelectionModel().getSelectedItem());
1754         assertNull(cb.getValue());
1755         assertEquals(0, cb.getItems().size());
1756 
1757         // round one
1758         cb.show();
1759         assertEquals(1, cb.getItems().size());
1760         assertEquals("DUMMY 0", cb.getItems().get(0));
1761         cb.hide();
1762 
1763         cb.getSelectionModel().select(0);
1764         assertEquals(0, cb.getSelectionModel().getSelectedIndex());
1765         assertEquals("DUMMY 0", cb.getSelectionModel().getSelectedItem());
1766         assertEquals("DUMMY 0", cb.getValue());
1767 
1768 
1769         // round two - even though the items change, the value should still be
1770         // the old value (even though it doesn't exist in the items list any longer).
1771         // The selectedIndex and selectedItem do get reset however.
1772         cb.show();
1773         assertEquals(1, cb.getItems().size());
1774         assertEquals("DUMMY 1", cb.getItems().get(0));
1775         cb.hide();
1776 
1777         assertEquals(-1, cb.getSelectionModel().getSelectedIndex());
1778         assertNull(cb.getSelectionModel().getSelectedItem());
1779         assertEquals("DUMMY 0", cb.getValue());
1780 
1781         sl.dispose();
1782     }
1783 
1784     private int rt_22937_counter;
1785     @Test public void test_rt_22937() {
1786         rt_22937_counter = 0;
1787 
1788         final ComboBox<String> cb = new ComboBox<>();
1789         cb.setOnShowing((e) -> {
1790             cb.getItems().setAll("DUMMY " + (rt_22937_counter++));
1791         });
1792 
1793         cb.getItems().add("Toto");
1794         cb.setEditable(true);
1795         cb.setValue("Tata");
1796 
1797         StageLoader sl = new StageLoader(cb);
1798 
1799         assertEquals(-1, cb.getSelectionModel().getSelectedIndex());
1800         assertEquals("Tata", cb.getSelectionModel().getSelectedItem());
1801         assertEquals("Tata", cb.getValue());
1802         assertEquals(1, cb.getItems().size());
1803 
1804         cb.show();
1805         assertEquals(1, cb.getItems().size());
1806         assertEquals("DUMMY 0", cb.getItems().get(0));
1807         cb.hide();
1808 
1809         cb.getSelectionModel().select(0);
1810         assertEquals(0, cb.getSelectionModel().getSelectedIndex());
1811         assertEquals("DUMMY 0", cb.getSelectionModel().getSelectedItem());
1812         assertEquals("DUMMY 0", cb.getValue());
1813 
1814         sl.dispose();
1815     }
1816 
1817     @Test public void test_rt_39809() {
1818         ComboBox<String> comboBox = new ComboBox<>();
1819         comboBox.getItems().setAll(null, "1", "2", "3");
1820 
1821         StageLoader sl = new StageLoader(comboBox);
1822 
1823         comboBox.getSelectionModel().clearAndSelect(1);
1824         assertEquals("1", comboBox.getSelectionModel().getSelectedItem());
1825         assertEquals(1, comboBox.getSelectionModel().getSelectedIndex());
1826 
1827         comboBox.getSelectionModel().clearAndSelect(0);
1828         assertEquals(null, comboBox.getSelectionModel().getSelectedItem());
1829         assertEquals(0, comboBox.getSelectionModel().getSelectedIndex());
1830 
1831         sl.dispose();
1832     }
1833 
1834     @Test public void test_rt_39908() {
1835         ObservableList<String> model = FXCollections.observableArrayList("0", "1", "2", "3");
1836         ComboBox<String> comboBox = new ComboBox<>(model);
1837 
1838         StageLoader sl = new StageLoader(comboBox);
1839 
1840         comboBox.getSelectionModel().clearAndSelect(1);
1841         assertEquals("1", comboBox.getSelectionModel().getSelectedItem());
1842         assertEquals(1, comboBox.getSelectionModel().getSelectedIndex());
1843 
1844         model.set(0, "a");
1845         assertEquals("1", comboBox.getSelectionModel().getSelectedItem());
1846         assertEquals(1, comboBox.getSelectionModel().getSelectedIndex());
1847 
1848         sl.dispose();
1849     }
1850 
1851     /**
1852      * Bullet 1: selected index must be updated
1853      * Corner case: last selected. Fails for core
1854      */
1855     @Test public void test_rt_40012_selectedAtLastOnDisjointRemoveItemsAbove() {
1856         ObservableList<String> items = FXCollections.observableArrayList("0", "1", "2", "3", "4", "5");
1857         ComboBox<String> comboBox = new ComboBox<>(items);
1858         SelectionModel sm = comboBox.getSelectionModel();
1859 
1860         int last = items.size() - 1;
1861 
1862         // selecting item "5"
1863         sm.select(last);
1864 
1865         // disjoint remove of 2 elements above the last selected
1866         // Removing "1" and "3"
1867         items.removeAll(items.get(1), items.get(3));
1868 
1869         // selection should move up two places such that it remains on item "5",
1870         // but in index (last - 2).
1871         int expected = last - 2;
1872         assertEquals("5", sm.getSelectedItem());
1873         assertEquals("selected index after disjoint removes above", expected, sm.getSelectedIndex());
1874     }
1875 
1876     /**
1877      * Variant of 1: if selectedIndex is not updated,
1878      * the old index is no longer valid
1879      * for accessing the items.
1880      */
1881     @Test public void test_rt_40012_accessSelectedAtLastOnDisjointRemoveItemsAbove() {
1882         ObservableList<String> items = FXCollections.observableArrayList("0", "1", "2", "3", "4", "5");
1883         ComboBox<String> comboBox = new ComboBox<>(items);
1884         SelectionModel sm = comboBox.getSelectionModel();
1885 
1886         int last = items.size() - 1;
1887 
1888         // selecting item "5"
1889         sm.select(last);
1890 
1891         // disjoint remove of 2 elements above the last selected
1892         items.removeAll(items.get(1), items.get(3));
1893         int selected = sm.getSelectedIndex();
1894         if (selected > -1) {
1895             items.get(selected);
1896         }
1897     }
1898 
1899     /**
1900      * Bullet 2: selectedIndex notification count
1901      *
1902      * Note that we don't use the corner case of having the last index selected
1903      * (which fails already on updating the index)
1904      */
1905     private int rt_40012_count = 0;
1906     @Test public void test_rt_40012_selectedIndexNotificationOnDisjointRemovesAbove() {
1907         ObservableList<String> items = FXCollections.observableArrayList("0", "1", "2", "3", "4", "5");
1908         ComboBox<String> comboBox = new ComboBox<>(items);
1909         SelectionModel sm = comboBox.getSelectionModel();
1910 
1911         int last = items.size() - 2;
1912         sm.select(last);
1913         assertEquals(last, sm.getSelectedIndex());
1914 
1915         rt_40012_count = 0;
1916         sm.selectedIndexProperty().addListener(o -> rt_40012_count++);
1917 
1918         // disjoint remove of 2 elements above the last selected
1919         items.removeAll(items.get(1), items.get(3));
1920         assertEquals("sanity: selectedIndex must be shifted by -2", last - 2, sm.getSelectedIndex());
1921         assertEquals("must fire single event on removes above", 1, rt_40012_count);
1922     }
1923 
1924     /**
1925      * Bullet 3: unchanged selectedItem must not fire change
1926      */
1927     @Test
1928     public void test_rt_40012_selectedItemNotificationOnDisjointRemovesAbove() {
1929         ObservableList<String> items = FXCollections.observableArrayList("0", "1", "2", "3", "4", "5");
1930         ComboBox<String> comboBox = new ComboBox<>(items);
1931         SelectionModel sm = comboBox.getSelectionModel();
1932 
1933         int last = items.size() - 2;
1934         Object lastItem = items.get(last);
1935         sm.select(last);
1936         assertEquals(lastItem, sm.getSelectedItem());
1937 
1938         rt_40012_count = 0;
1939         sm.selectedItemProperty().addListener(o -> rt_40012_count++);
1940 
1941         // disjoint remove of 2 elements above the last selected
1942         items.removeAll(items.get(1), items.get(3));
1943         assertEquals("sanity: selectedItem unchanged", lastItem, sm.getSelectedItem());
1944         assertEquals("must not fire on unchanged selected item", 0, rt_40012_count);
1945     }
1946 
1947     @Test public void test_jdk_8150946_testCommit_valid() {
1948         ComboBox<String> comboBox = new ComboBox<>();
1949         comboBox.setEditable(true);
1950         assertEquals(null, comboBox.getValue());
1951         comboBox.getEditor().setText("ABC");
1952         comboBox.commitValue();
1953         assertEquals("ABC", comboBox.getValue());
1954     }
1955 
1956     @Test public void test_jdk_8150946_testCancel_toNull() {
1957         ComboBox<String> comboBox = new ComboBox<>();
1958         comboBox.setEditable(true);
1959         assertNull(comboBox.getValue());
1960         assertEquals("", comboBox.getEditor().getText());
1961         comboBox.getEditor().setText("ABC");
1962         assertNull(comboBox.getValue());
1963         comboBox.cancelEdit();
1964         assertNull(comboBox.getValue());
1965         assertNull(comboBox.getEditor().getText());
1966     }
1967 
1968     @Test public void test_jdk_8150946_testCancel_toNonNull() {
1969         ComboBox<String> comboBox = new ComboBox<>();
1970         comboBox.setEditable(true);
1971         comboBox.getEditor().setText("ABC");
1972         comboBox.commitValue();
1973         assertEquals("ABC", comboBox.getValue());
1974         assertEquals("ABC", comboBox.getEditor().getText());
1975         comboBox.getEditor().setText("DEF");
1976         assertEquals("DEF", comboBox.getEditor().getText());
1977         assertEquals("ABC", comboBox.getValue());
1978         comboBox.cancelEdit();
1979         assertEquals("ABC", comboBox.getValue());
1980         assertEquals("ABC", comboBox.getEditor().getText());
1981     }
1982 
1983     @Test public void test_jdk_8160493() {
1984         AtomicInteger count = new AtomicInteger();
1985         comboBox.valueProperty().addListener(o -> count.incrementAndGet());
1986         assertEquals(0, count.get());
1987 
1988         comboBox.getItems().addAll("Apple", "Orange", "Banana");
1989         sm.select(1);
1990         assertTrue(sm.isSelected(1));
1991         assertEquals(1, count.get());
1992         assertEquals("Orange", comboBox.getValue());
1993 
1994         comboBox.setValue("New Value");
1995         assertEquals(2, count.get());
1996         assertEquals("New Value", comboBox.getValue());
1997     }
1998 }