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