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