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         assertTrue(pseudoClassStates.contains(PseudoClass.getPseudoClass("editable")));
 658 
 659         comboBox.setEditable(false);
 660         assertFalse(pseudoClassStates.contains(PseudoClass.getPseudoClass("editable")));
 661 
 662         comboBox.show();
 663         assertTrue(pseudoClassStates.contains(PseudoClass.getPseudoClass("showing")));
 664 
 665         comboBox.hide();
 666         assertFalse(pseudoClassStates.contains(PseudoClass.getPseudoClass("showing")));
 667 
 668         comboBox.arm();
 669         assertTrue(pseudoClassStates.contains(PseudoClass.getPseudoClass("armed")));
 670 
 671     }
 672 
 673     /*********************************************************************
 674      * Tests for properties                                              *
 675      ********************************************************************/
 676 
 677     @Test public void ensureAllowsNullConverter() {
 678         comboBox.setConverter(null);
 679         assertNull(comboBox.getConverter());
 680     }
 681 
 682     @Test public void ensureCanSetNonNullCellFactory() {
 683         Callback<ListView<String>, ListCell<String>> cf = p -> null;
 684         comboBox.setCellFactory(cf);
 685         assertEquals(cf, comboBox.getCellFactory());
 686     }
 687 
 688     @Test public void ensureEditorIsNonNullWhenComboBoxIsNotEditable() {
 689         assertNotNull(comboBox.getEditor());
 690     }
 691 
 692     @Test public void ensureEditorIsNonNullWhenComboBoxIsEditable() {
 693         comboBox.setEditable(true);
 694         assertNotNull(comboBox.getEditor());
 695     }
 696 
 697     @Test public void ensureEditorDoesNotChangeWhenEditableToggles() {
 698         comboBox.setEditable(true);
 699         assertNotNull(comboBox.getEditor());
 700         comboBox.setEditable(false);
 701         assertNotNull(comboBox.getEditor());
 702         comboBox.setEditable(true);
 703         assertNotNull(comboBox.getEditor());
 704     }
 705 
 706     @Test public void ensureCanSetValueToNonNullStringAndBackAgain() {
 707         comboBox.setValue("Test 123");
 708         assertEquals("Test 123", comboBox.getValue());
 709         comboBox.setValue(null);
 710         assertNull(comboBox.getValue());
 711     }
 712 
 713     @Test public void ensureCanToggleEditable() {
 714         comboBox.setEditable(true);
 715         assertTrue(comboBox.isEditable());
 716         comboBox.setEditable(false);
 717         assertFalse(comboBox.isEditable());
 718     }
 719 
 720     @Test public void ensureCanToggleShowing() {
 721         Stage stage = new Stage();
 722         Scene scene = new Scene(comboBox);
 723         stage.setScene(scene);
 724 
 725         comboBox.show();
 726         assertTrue(comboBox.isShowing());
 727         comboBox.hide();
 728         assertFalse(comboBox.isShowing());
 729     }
 730 
 731     @Test public void ensureCanNotToggleShowingWhenDisabled() {
 732         Stage stage = new Stage();
 733         Scene scene = new Scene(comboBox);
 734         stage.setScene(scene);
 735 
 736         comboBox.setDisable(true);
 737         comboBox.show();
 738         assertFalse(comboBox.isShowing());
 739         comboBox.setDisable(false);
 740         comboBox.show();
 741         assertTrue(comboBox.isShowing());
 742     }
 743 
 744     @Test public void ensureCanSetPromptText() {
 745         comboBox.setPromptText("Test 1 2 3");
 746         assertEquals("Test 1 2 3", comboBox.getPromptText());
 747     }
 748 
 749     @Test public void ensureCanSetPromptTextToNull() {
 750         comboBox.setPromptText("");
 751         assertEquals("", comboBox.getPromptText());
 752         comboBox.setPromptText(null);
 753         assertEquals(null, comboBox.getPromptText());
 754     }
 755 
 756     @Test public void ensurePromptTextStripsNewlines() {
 757         comboBox.setPromptText("Test\n1\n2\n3");
 758         assertEquals("Test123", comboBox.getPromptText());
 759     }
 760 
 761     @Test public void ensureCanSetPlaceholder() {
 762         Label label = new javafx.scene.control.Label("Test 1 2 3");
 763         comboBox.setPlaceholder(label);
 764         assertEquals(label, comboBox.getPlaceholder());
 765     }
 766 
 767     @Test public void ensureCanToggleArmed() {
 768         assertFalse(comboBox.isArmed());
 769         comboBox.arm();
 770         assertTrue(comboBox.isArmed());
 771         comboBox.disarm();
 772         assertFalse(comboBox.isArmed());
 773     }
 774 
 775     @Test public void ensureCanSetVisibleRowCount() {
 776         comboBox.setVisibleRowCount(13);
 777         assertEquals(13, comboBox.getVisibleRowCount());
 778     }
 779 
 780     @Test public void ensureCanSetVisibleRowCountToNegativeValues() {
 781         comboBox.setVisibleRowCount(-10);
 782         assertEquals(-10, comboBox.getVisibleRowCount());
 783     }
 784 
 785     @Test public void ensureCanSetOnAction() {
 786         EventHandler<ActionEvent> onAction = t -> { };
 787         comboBox.setOnAction(onAction);
 788         assertEquals(onAction, comboBox.getOnAction());
 789     }
 790 
 791     @Test public void ensureOnActionPropertyReferencesBean() {
 792         assertEquals(comboBox, comboBox.onActionProperty().getBean());
 793     }
 794 
 795     /*********************************************************************
 796      * Tests for property binding                                        *
 797      ********************************************************************/
 798     @Test public void checkPromptTextPropertyBind() {
 799         StringProperty strPr = new SimpleStringProperty("value");
 800         comboBox.promptTextProperty().bind(strPr);
 801         assertTrue("PromptText cannot be bound", comboBox.getPromptText().equals("value"));
 802         strPr.setValue("newvalue");
 803         assertTrue("PromptText cannot be bound", comboBox.getPromptText().equals("newvalue"));
 804     }
 805 
 806     @Test public void checkValuePropertyBind() {
 807         StringProperty strPr = new SimpleStringProperty("value");
 808         comboBox.valueProperty().bind(strPr);
 809         assertTrue("value cannot be bound", comboBox.getValue().equals("value"));
 810         strPr.setValue("newvalue");
 811         assertTrue("value cannot be bound", comboBox.getValue().equals("newvalue"));
 812     }
 813 
 814 
 815 
 816     /*********************************************************************
 817      * Tests for bug reports                                             *
 818      ********************************************************************/
 819 
 820     @Test public void test_rt18972() {
 821         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 822         sm.select(1);
 823         assertTrue(sm.isSelected(1));
 824 
 825         comboBox.setEditable(true);
 826         comboBox.setValue("New Value");
 827 
 828         // there should be no selection in the selection model, as "New Value"
 829         // isn't an item in the list, however, it is a totally valid value for
 830         // the value property
 831         assertFalse(sm.isSelected(1));
 832         assertEquals("New Value", sm.getSelectedItem());
 833         assertEquals("New Value", comboBox.getValue());
 834 
 835         comboBox.setEditable(false);
 836         assertEquals(-1, sm.getSelectedIndex());
 837         assertEquals("New Value", sm.getSelectedItem());
 838         assertEquals("New Value", comboBox.getValue());
 839     }
 840 
 841     @Test public void test_rt18941() {
 842         comboBox.getItems().addAll("Apple", "Orange", "Banana");
 843         comboBox.setValue("Orange");
 844         assertEquals("Orange", comboBox.getValue());
 845         assertEquals("Orange", comboBox.getSelectionModel().getSelectedItem());
 846         assertTrue("Selected Index: " + sm.getSelectedIndex(), sm.isSelected(1));
 847     }
 848 
 849     @Test public void test_rt19227() {
 850         comboBox.getItems().addAll("0","0","0","0","0");
 851         comboBox.getSelectionModel().select(2);
 852         assertEquals("0", comboBox.getValue());
 853         assertEquals("0", comboBox.getSelectionModel().getSelectedItem());
 854         assertTrue(sm.isSelected(2));
 855     }
 856 
 857     @Ignore("JDK-8091127 Test not working as the heights being returned are not accurate")
 858     @Test public void test_rt20106() {
 859         comboBox.getItems().addAll("0","1","2","3","4","5","6","7","8","9");
 860 
 861         Stage stage = new Stage();
 862         Scene scene = new Scene(comboBox);
 863         stage.setScene(scene);
 864         comboBox.applyCss();
 865         comboBox.show();
 866 
 867         comboBox.setVisibleRowCount(5);
 868         double initialHeight = getListView().getHeight();
 869         assertFalse("initialHeight: " + initialHeight, Double.compare(0.0, initialHeight) == 0);
 870 
 871         comboBox.setVisibleRowCount(0);
 872         double smallHeight =    getListView().getHeight();
 873         assertTrue("smallHeight: " + smallHeight + ", initialHeight: " + initialHeight,
 874                 smallHeight != initialHeight && smallHeight < initialHeight);
 875 
 876         comboBox.setVisibleRowCount(7);
 877         double biggerHeight = getListView().getHeight();
 878         assertTrue(biggerHeight != smallHeight && smallHeight < biggerHeight);
 879     }
 880 
 881     private int count = 0;
 882     @Test public void test_rt20103() {
 883         final TextField tf = new TextField();
 884 
 885         comboBox.setOnAction(t -> {
 886             count++;
 887         });
 888 
 889         assertTrue(count == 0);
 890 
 891         comboBox.valueProperty().bind(tf.textProperty());   // count++ here
 892         assertTrue("count: " + count, count == 1);
 893 
 894         tf.setText("Text1");                                // count++ here
 895         assertTrue("count: " + count, count == 2);
 896 
 897         comboBox.valueProperty().unbind();                  // no count++ here
 898         assertTrue("count: " + count, count == 2);
 899 
 900         comboBox.valueProperty().bindBidirectional(tf.textProperty());  // count++ here
 901         tf.setText("Text2");
 902         assertTrue("count: " + count, count == 3);
 903     }
 904 
 905     @Ignore("Test not working as the skin is not being properly instantiated")
 906     @Test public void test_rt20100() {
 907         comboBox.getItems().addAll("0","1","2","3","4","5","6","7","8","9");
 908 
 909         Stage stage = new Stage();
 910         Scene scene = new Scene(comboBox);
 911         stage.setScene(scene);
 912         comboBox.applyCss();
 913         comboBox.show();
 914 
 915         comboBox.setConverter(new StringConverter() {
 916             int toStringCounter = 0;
 917             int fromStringCounter = 0;
 918 
 919             @Override public String toString(Object t) {
 920                 return "TO_STRING";
 921             }
 922 
 923             @Override public Object fromString(String string) {
 924                 return "FROM_STRING";
 925             }
 926         });
 927 
 928         comboBox.getSelectionModel().select(2);
 929         assertEquals("2", comboBox.getValue());
 930 
 931         ListView listView = getListView();
 932 //        listView.applyCss();
 933 
 934         assertEquals("2", listView.getSelectionModel().getSelectedItem());
 935 
 936         System.out.println(listView.getSkin());
 937 
 938         VirtualFlow flow = (VirtualFlow)listView.lookup("#virtual-flow");
 939         assertNotNull(flow);
 940 
 941         IndexedCell cell = flow.getVisibleCell(2);
 942         System.out.println("cell: " + cell);
 943         assertEquals("TO_STRING", cell.getText());
 944     }
 945 
 946     @Test public void test_rt20189() {
 947         comboBox.getItems().addAll("0","1","2","3","4","5","6","7","8","9");
 948 
 949         Stage stage = new Stage();
 950         Scene scene = new Scene(comboBox);
 951         stage.setScene(scene);
 952         comboBox.applyCss();
 953         comboBox.show();
 954 
 955         comboBox.getSelectionModel().select(2);
 956         Object item = sm.getSelectedItem();
 957         assertEquals("2", item);
 958         assertEquals(2, sm.getSelectedIndex());
 959 
 960         comboBox.setValue("test");
 961         item = sm.getSelectedItem();
 962         assertEquals("test",item);
 963         assertEquals(-1, sm.getSelectedIndex());
 964 
 965         comboBox.getSelectionModel().select(2);
 966         item = sm.getSelectedItem();
 967         assertEquals("2", item);
 968         assertEquals(2, sm.getSelectedIndex());
 969     }
 970 
 971     @Test public void test_rt27654() {
 972         comboBox.getItems().addAll("0","1","2","3","4","5","6","7","8","9");
 973 
 974         SingleSelectionModel sm = comboBox.getSelectionModel();
 975 
 976         Stage stage = new Stage();
 977         Scene scene = new Scene(comboBox);
 978         stage.setScene(scene);
 979         comboBox.applyCss();
 980         comboBox.show();
 981         ListCell<String> buttonCell = (ListCell<String>) getDisplayNode();
 982 
 983         sm.select(2);
 984         assertEquals("2", sm.getSelectedItem());
 985         assertEquals("2", comboBox.getValue());
 986         assertEquals("2", buttonCell.getText());
 987         assertEquals(2, sm.getSelectedIndex());
 988 
 989         sm.clearSelection();
 990         assertNull(sm.getSelectedItem());
 991         assertNull(comboBox.getValue());
 992         assertNull(buttonCell.getText());
 993         assertEquals(-1, sm.getSelectedIndex());
 994 
 995         sm.select(2);
 996         assertEquals("2", sm.getSelectedItem());
 997         assertEquals("2", comboBox.getValue());
 998         assertEquals("2", buttonCell.getText());
 999         assertEquals(2, sm.getSelectedIndex());
1000     }
1001 
1002     @Test public void test_rt24412() {
1003         SingleSelectionModel sm = comboBox.getSelectionModel();
1004 
1005         Stage stage = new Stage();
1006         Scene scene = new Scene(comboBox);
1007         stage.setScene(scene);
1008         comboBox.applyCss();
1009         comboBox.show();
1010         ListCell<String> buttonCell = (ListCell<String>) getDisplayNode();
1011 
1012         comboBox.getItems().setAll("0","1","2","3","4","5","6","7","8","9");
1013 
1014         sm.select("2");
1015         assertEquals("2", sm.getSelectedItem());
1016         assertEquals("2", comboBox.getValue());
1017         assertEquals("2", buttonCell.getText());
1018         assertEquals(2, sm.getSelectedIndex());
1019 
1020         sm.clearSelection();
1021         assertNull(sm.getSelectedItem());
1022         assertNull(comboBox.getValue());
1023         assertNull(buttonCell.getText());
1024         assertEquals(-1, sm.getSelectedIndex());
1025 
1026         sm.select("2");
1027         assertEquals("2", sm.getSelectedItem());
1028         assertEquals("2", comboBox.getValue());
1029         assertEquals("2", buttonCell.getText());
1030         assertEquals(2, sm.getSelectedIndex());
1031     }
1032 
1033     @Test public void test_rt28245() {
1034         final ObservableList<String> strings = FXCollections.observableArrayList(
1035             "Option 1", "Option 2", "Option 3"
1036         );
1037 
1038         ComboBox<String> comboBox = new ComboBox<String>();
1039         comboBox.setItems(strings);
1040         comboBox.setEditable(true);
1041         comboBox.valueProperty().addListener((ov, t, t1) -> {
1042             if (t == null && t1.isEmpty()) {
1043                 fail("Old value is '" + t + "' and new value is '" + t1 + "'.");
1044             }
1045         });
1046 
1047         StageLoader sl = new StageLoader(comboBox);
1048 
1049         assertNull(comboBox.getValue());
1050         assertTrue(comboBox.getEditor().getText().isEmpty());
1051 
1052         comboBox.requestFocus();
1053 
1054         new KeyEventFirer(comboBox).doKeyPress(KeyCode.ENTER);
1055 
1056         sl.dispose();
1057     }
1058 
1059     @Test public void test_rt31479() {
1060         ComboBox<String> comboBox = new ComboBox<String>();
1061 
1062         StageLoader sl = new StageLoader(comboBox);
1063 
1064         final double widthBefore = comboBox.getWidth();
1065 
1066         // add item
1067         comboBox.getItems().add("Option 1");
1068 
1069         // open and close combobox
1070         comboBox.show();
1071         comboBox.hide();
1072 
1073         // set a placeholder
1074         comboBox.setPlaceholder(new Circle(12, Color.RED));
1075 
1076         // remove item
1077         comboBox.getItems().clear();
1078 
1079         // fire pulse (this allows layout to cause the size to grow)
1080         Toolkit.getToolkit().firePulse();
1081 
1082         // test size
1083         assertEquals(widthBefore, comboBox.getWidth(), 0.00);
1084 
1085         sl.dispose();
1086     }
1087 
1088     @Test public void test_rt32139() {
1089         final ObservableList<String> items =
1090                 FXCollections.observableArrayList("Good value", "Bad value");
1091 
1092         final ComboBox<String> comboBox = new ComboBox<>(items);
1093         comboBox.getSelectionModel().select(0);
1094 
1095         comboBox.getSelectionModel().selectedIndexProperty().addListener((ov, oldIdx, newIdx) -> {
1096             if (newIdx.intValue() != 0) {
1097                 comboBox.getSelectionModel().select(0);
1098             }
1099         });
1100 
1101         StageLoader sl = new StageLoader(comboBox);
1102 
1103         try {
1104             comboBox.getSelectionModel().select(1);
1105         } catch (StackOverflowError e) {
1106             fail("Stack overflow should not happen here");
1107         }
1108 
1109         sl.dispose();
1110     }
1111 
1112     @Test public void test_rt21186() {
1113         final ComboBox<String> comboBox = new ComboBox<>();
1114         comboBox.setEditable(true);
1115 
1116         StageLoader sl = new StageLoader(comboBox);
1117 
1118         assertNull(comboBox.getTooltip());
1119         assertNull(comboBox.getEditor().getTooltip());
1120 
1121         Tooltip tooltip = new Tooltip("Tooltip");
1122         comboBox.setTooltip(tooltip);
1123         assertEquals(tooltip, comboBox.getTooltip());
1124         assertEquals(tooltip, comboBox.getEditor().getTooltip());
1125 
1126         comboBox.setTooltip(null);
1127         assertNull(comboBox.getTooltip());
1128         assertNull(comboBox.getEditor().getTooltip());
1129 
1130         sl.dispose();
1131     }
1132 
1133     @Test public void test_rt34573() {
1134         final ComboBox<String> comboBox = new ComboBox<>();
1135 
1136         final ListCell<String> customCell = new ListCellShim<String>() {
1137             @Override public void updateItem(String item, boolean empty) {
1138                 super.updateItem(item, empty);
1139                 setText(item);
1140             }
1141         };
1142         comboBox.setButtonCell(customCell);
1143 
1144         StageLoader sl = new StageLoader(comboBox);
1145 
1146         comboBox.setItems(FXCollections.observableArrayList("A","B","C","D"));
1147         comboBox.setValue("B");
1148         assertEquals("B", comboBox.getButtonCell().getText());
1149         assertEquals(1, comboBox.getButtonCell().getIndex());
1150 
1151         comboBox.setItems(FXCollections.observableArrayList("1","2","3","4"));
1152         assertNull(comboBox.getButtonCell().getText());
1153         assertEquals(-1, comboBox.getButtonCell().getIndex());
1154 
1155         sl.dispose();
1156     }
1157 
1158     @Test public void test_rt34566() {
1159         final ComboBox<String> comboBox = new ComboBox<>();
1160 
1161         final ListCell<String> customCell = new ListCellShim<String>() {
1162             @Override public void updateItem(String item, boolean empty) {
1163                 super.updateItem(item, empty);
1164                 setText(item);
1165             }
1166         };
1167         comboBox.setButtonCell(customCell);
1168 
1169         StageLoader sl = new StageLoader(comboBox);
1170 
1171         comboBox.setItems(FXCollections.observableArrayList("A","B","C","D"));
1172 
1173         PseudoClass empty = PseudoClass.getPseudoClass("empty");
1174 
1175         comboBox.setValue("B");
1176         assertEquals("B", comboBox.getButtonCell().getText());
1177         assertEquals(1, comboBox.getButtonCell().getIndex());
1178         assertFalse(customCell.getPseudoClassStates().contains(empty));
1179 
1180         comboBox.setValue(null);
1181         Toolkit.getToolkit().firePulse();
1182         assertNull(comboBox.getButtonCell().getText());
1183         assertEquals(-1, comboBox.getButtonCell().getIndex());
1184         assertTrue(customCell.getPseudoClassStates().contains(empty));
1185 
1186         comboBox.setValue("A");
1187         assertEquals("A", comboBox.getButtonCell().getText());
1188         assertEquals(0, comboBox.getButtonCell().getIndex());
1189         assertFalse(customCell.getPseudoClassStates().contains(empty));
1190 
1191         sl.dispose();
1192     }
1193 
1194     private int test_rt34603_count = 0;
1195     @Test public void test_rt34603() {
1196         assertEquals(0, test_rt34603_count);
1197 
1198         VBox hbox = new VBox(10);
1199 
1200         ComboBox<String> box = new ComboBox<>();
1201         box.getItems().add("test");
1202         box.setEditable(true);
1203         box.getSelectionModel().selectFirst();
1204 
1205         Button defaultButton = new Button("press");
1206         defaultButton.setOnAction(arg0 -> {
1207             test_rt34603_count++;
1208         });
1209         defaultButton.setDefaultButton(true);
1210 
1211         hbox.getChildren().addAll(box, defaultButton);
1212 
1213         StageLoader sl = new StageLoader(hbox);
1214 
1215         box.getEditor().requestFocus();
1216         KeyEventFirer keyboard = new KeyEventFirer(box);
1217         keyboard.doKeyPress(KeyCode.ENTER);
1218 
1219         assertEquals(1, test_rt34603_count);
1220 
1221         sl.dispose();
1222     }
1223 
1224     private int test_rt35586_count = 0;
1225     @Test public void test_rt35586() {
1226         assertEquals(0, test_rt35586_count);
1227 
1228         final ComboBox<String> cb = new ComboBox<String>();
1229         cb.setEditable(true);
1230         cb.setOnAction(event -> {
1231             test_rt35586_count++;
1232             assertEquals("Test", cb.getEditor().getText());
1233         });
1234 
1235         StageLoader sl = new StageLoader(cb);
1236 
1237         cb.requestFocus();
1238         cb.getEditor().setText("Test");
1239         KeyEventFirer keyboard = new KeyEventFirer(cb);
1240         keyboard.doKeyPress(KeyCode.ENTER);
1241 
1242         assertEquals(1, test_rt35586_count);
1243 
1244         sl.dispose();
1245     }
1246 
1247     @Test public void test_rt35039() {
1248         final List<String> data = new ArrayList<>();
1249         data.add("aabbaa");
1250         data.add("bbc");
1251 
1252         final ComboBox<String> combo = new ComboBox<>();
1253         combo.setEditable(true);
1254         combo.setItems(FXCollections.observableArrayList(data));
1255 
1256         StageLoader sl = new StageLoader(combo);
1257 
1258         // everything should be null to start with
1259         assertNull(combo.getValue());
1260         assertTrue(combo.getEditor().getText().isEmpty());
1261         assertNull(combo.getSelectionModel().getSelectedItem());
1262 
1263         // select "bbc" and ensure everything is set to that
1264         combo.getSelectionModel().select(1);
1265         assertEquals("bbc", combo.getValue());
1266         assertEquals("bbc", combo.getEditor().getText());
1267         assertEquals("bbc", combo.getSelectionModel().getSelectedItem());
1268 
1269         // change the items list - but retain the same content. We expect
1270         // that "bbc" remains selected as it is still in the list
1271         combo.setItems(FXCollections.observableArrayList(data));
1272         assertEquals("bbc", combo.getValue());
1273         assertEquals("bbc", combo.getEditor().getText());
1274         assertEquals("bbc", combo.getSelectionModel().getSelectedItem());
1275 
1276         sl.dispose();
1277     }
1278 
1279     @Test public void test_rt35840() {
1280         final ComboBox<String> cb = new ComboBox<String>();
1281         cb.setEditable(true);
1282         StageLoader sl = new StageLoader(cb);
1283         cb.requestFocus();
1284 
1285         KeyEventFirer keyboard = new KeyEventFirer(cb);
1286         keyboard.doKeyTyped(KeyCode.T);
1287         keyboard.doKeyTyped(KeyCode.E);
1288         keyboard.doKeyTyped(KeyCode.S);
1289         keyboard.doKeyTyped(KeyCode.T);
1290         assertEquals("TEST", cb.getEditor().getText());
1291 
1292         assertNull(cb.getValue());
1293         keyboard.doKeyPress(KeyCode.ENTER);
1294         assertEquals("TEST", cb.getValue());
1295 
1296         sl.dispose();
1297     }
1298 
1299     @Test public void test_rt36280_nonEditable_F4ShowsPopup() {
1300         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1301         StageLoader sl = new StageLoader(cb);
1302         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1303 
1304         assertFalse(cb.isShowing());
1305         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1306         assertTrue(cb.isShowing());
1307 
1308         sl.dispose();
1309     }
1310 
1311     @Test public void test_rt36280_nonEditable_altUpShowsPopup() {
1312         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1313         StageLoader sl = new StageLoader(cb);
1314         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1315 
1316         assertFalse(cb.isShowing());
1317         cbKeyboard.doKeyPress(KeyCode.UP, KeyModifier.ALT);  // show the popup
1318         assertTrue(cb.isShowing());
1319 
1320         sl.dispose();
1321     }
1322 
1323     @Test public void test_rt36280_nonEditable_altDownShowsPopup() {
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         new StageLoader(cb);
1329 
1330         assertFalse(cb.isShowing());
1331         cbKeyboard.doKeyPress(KeyCode.DOWN, KeyModifier.ALT);  // show the popup
1332         assertTrue(cb.isShowing());
1333 
1334         sl.dispose();
1335     }
1336 
1337     @Test public void test_rt36280_nonEditable_enterHidesShowingPopup() {
1338         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1339         StageLoader sl = new StageLoader(cb);
1340         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1341 
1342         ListView listView = (ListView) ((ComboBoxListViewSkin)cb.getSkin()).getPopupContent();
1343         assertNotNull(listView);
1344 
1345         KeyEventFirer lvKeyboard = new KeyEventFirer(listView);
1346 
1347         assertFalse(cb.isShowing());
1348         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1349         assertTrue(cb.isShowing());
1350         lvKeyboard.doKeyPress(KeyCode.ENTER);  // hide the popup
1351         assertFalse(cb.isShowing());
1352 
1353         sl.dispose();
1354     }
1355 
1356     @Test public void test_rt36280_nonEditable_spaceHidesShowingPopup() {
1357         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1358         StageLoader sl = new StageLoader(cb);
1359         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1360 
1361         ListView listView = (ListView) ((ComboBoxListViewSkin)cb.getSkin()).getPopupContent();
1362         assertNotNull(listView);
1363 
1364         KeyEventFirer lvKeyboard = new KeyEventFirer(listView);
1365 
1366         assertFalse(cb.isShowing());
1367         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1368         assertTrue(cb.isShowing());
1369         lvKeyboard.doKeyPress(KeyCode.SPACE);  // hide the popup
1370         assertFalse(cb.isShowing());
1371 
1372         sl.dispose();
1373     }
1374 
1375     @Test public void test_rt36280_nonEditable_escapeHidesShowingPopup() {
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         ListView listView = (ListView) ((ComboBoxListViewSkin)cb.getSkin()).getPopupContent();
1381         assertNotNull(listView);
1382 
1383         KeyEventFirer lvKeyboard = new KeyEventFirer(listView);
1384 
1385         assertFalse(cb.isShowing());
1386         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1387         assertTrue(cb.isShowing());
1388         lvKeyboard.doKeyPress(KeyCode.ESCAPE);  // hide the popup
1389         assertFalse(cb.isShowing());
1390 
1391         sl.dispose();
1392     }
1393 
1394     @Test public void test_rt36280_nonEditable_F4HidesShowingPopup() {
1395         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1396         StageLoader sl = new StageLoader(cb);
1397         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1398 
1399         assertFalse(cb.isShowing());
1400         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1401         assertTrue(cb.isShowing());
1402         cbKeyboard.doKeyPress(KeyCode.F4);  // hide the popup
1403         assertFalse(cb.isShowing());
1404 
1405         sl.dispose();
1406     }
1407 
1408     @Test public void test_rt36280_nonEditable_arrowKeysChangeSelection() {
1409         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1410         StageLoader sl = new StageLoader(cb);
1411         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1412 
1413         assertFalse(cb.isShowing());
1414         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1415         assertTrue(cb.isShowing());
1416 
1417         assertNull(cb.getSelectionModel().getSelectedItem());
1418 
1419         cbKeyboard.doDownArrowPress();
1420         assertEquals("a", cb.getSelectionModel().getSelectedItem());
1421 
1422         cbKeyboard.doDownArrowPress();
1423         assertEquals("b", cb.getSelectionModel().getSelectedItem());
1424 
1425         cbKeyboard.doUpArrowPress();
1426         assertEquals("a", cb.getSelectionModel().getSelectedItem());
1427 
1428         sl.dispose();
1429     }
1430 
1431     @Test public void test_rt36280_editable_F4ShowsPopup() {
1432         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1433         cb.setEditable(true);
1434         StageLoader sl = new StageLoader(cb);
1435         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1436 
1437         assertFalse(cb.isShowing());
1438         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1439         assertTrue(cb.isShowing());
1440 
1441         sl.dispose();
1442     }
1443 
1444     @Test public void test_rt36280_editable_altUpShowsPopup() {
1445         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1446         cb.setEditable(true);
1447         StageLoader sl = new StageLoader(cb);
1448         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1449 
1450         assertFalse(cb.isShowing());
1451         cbKeyboard.doKeyPress(KeyCode.UP, KeyModifier.ALT);  // show the popup
1452         assertTrue(cb.isShowing());
1453 
1454         sl.dispose();
1455     }
1456 
1457     @Test public void test_rt36280_editable_altDownShowsPopup_onComboBox() {
1458         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1459         cb.setEditable(true);
1460         StageLoader sl = new StageLoader(cb);
1461         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1462 
1463         assertFalse(cb.isShowing());
1464         assertTrue(cb.getEditor().getText().isEmpty());
1465         cbKeyboard.doKeyPress(KeyCode.DOWN, KeyModifier.ALT);  // show the popup
1466         assertTrue(cb.isShowing());
1467         assertTrue(cb.getEditor().getText().isEmpty());
1468 
1469         sl.dispose();
1470     }
1471 
1472     @Test public void test_rt36280_editable_altDownShowsPopup_onTextField() {
1473         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1474         cb.setEditable(true);
1475         StageLoader sl = new StageLoader(cb);
1476 
1477         KeyEventFirer tfKeyboard = new KeyEventFirer(cb.getEditor());
1478         assertFalse(cb.isShowing());
1479         assertTrue(cb.getEditor().getText().isEmpty());
1480         tfKeyboard.doKeyPress(KeyCode.DOWN, KeyModifier.ALT);  // show the popup
1481         assertTrue(cb.isShowing());
1482         assertTrue(cb.getEditor().getText().isEmpty());
1483 
1484         sl.dispose();
1485     }
1486 
1487     @Test public void test_rt36280_editable_enterHidesShowingPopup() {
1488         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1489         cb.setEditable(true);
1490         StageLoader sl = new StageLoader(cb);
1491         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1492 
1493         ListView listView = (ListView) ((ComboBoxListViewSkin)cb.getSkin()).getPopupContent();
1494         assertNotNull(listView);
1495 
1496         KeyEventFirer lvKeyboard = new KeyEventFirer(listView);
1497 
1498         assertFalse(cb.isShowing());
1499         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1500         assertTrue(cb.isShowing());
1501         lvKeyboard.doKeyPress(KeyCode.ENTER);  // hide the popup
1502         assertFalse(cb.isShowing());
1503 
1504         sl.dispose();
1505     }
1506 
1507     @Test public void test_rt36280_editable_spaceHidesShowingPopup() {
1508         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1509         cb.setEditable(true);
1510         StageLoader sl = new StageLoader(cb);
1511         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1512 
1513         ListView listView = (ListView) ((ComboBoxListViewSkin)cb.getSkin()).getPopupContent();
1514         assertNotNull(listView);
1515 
1516         KeyEventFirer lvKeyboard = new KeyEventFirer(listView);
1517 
1518         assertFalse(cb.isShowing());
1519         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1520         assertTrue(cb.isShowing());
1521         lvKeyboard.doKeyPress(KeyCode.SPACE);  // hide the popup
1522         assertFalse(cb.isShowing());
1523 
1524         sl.dispose();
1525     }
1526 
1527     @Test public void test_rt36280_editable_escapeHidesShowingPopup() {
1528         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1529         cb.setEditable(true);
1530         StageLoader sl = new StageLoader(cb);
1531         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1532 
1533         ListView listView = (ListView) ((ComboBoxListViewSkin)cb.getSkin()).getPopupContent();
1534         assertNotNull(listView);
1535 
1536         KeyEventFirer lvKeyboard = new KeyEventFirer(listView);
1537 
1538         assertFalse(cb.isShowing());
1539         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1540         assertTrue(cb.isShowing());
1541         lvKeyboard.doKeyPress(KeyCode.ESCAPE);  // hide the popup
1542         assertFalse(cb.isShowing());
1543 
1544         sl.dispose();
1545     }
1546 
1547     @Test public void test_rt36280_editable_F4HidesShowingPopup() {
1548         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1549         cb.setEditable(true);
1550         StageLoader sl = new StageLoader(cb);
1551         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1552 
1553         assertFalse(cb.isShowing());
1554         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1555         assertTrue(cb.isShowing());
1556         cbKeyboard.doKeyPress(KeyCode.F4);  // hide the popup
1557         assertFalse(cb.isShowing());
1558 
1559         sl.dispose();
1560     }
1561 
1562     @Test public void test_rt36280_editable_arrowKeysChangeSelection() {
1563         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1564         cb.setEditable(true);
1565         StageLoader sl = new StageLoader(cb);
1566         KeyEventFirer cbKeyboard = new KeyEventFirer(cb);
1567 
1568         assertFalse(cb.isShowing());
1569         cbKeyboard.doKeyPress(KeyCode.F4);  // show the popup
1570         assertTrue(cb.isShowing());
1571 
1572         assertNull(cb.getSelectionModel().getSelectedItem());
1573 
1574         cbKeyboard.doDownArrowPress();
1575         assertEquals("a", cb.getSelectionModel().getSelectedItem());
1576 
1577         cbKeyboard.doDownArrowPress();
1578         assertEquals("b", cb.getSelectionModel().getSelectedItem());
1579 
1580         cbKeyboard.doUpArrowPress();
1581         assertEquals("a", cb.getSelectionModel().getSelectedItem());
1582 
1583         sl.dispose();
1584     }
1585 
1586     @Test public void test_rt36651() {
1587         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1588         cb.setEditable(true);
1589         StageLoader sl = new StageLoader(cb);
1590 
1591         assertNull(cb.getValue());
1592         assertEquals(-1, cb.getSelectionModel().getSelectedIndex());
1593         assertNull(cb.getSelectionModel().getSelectedItem());
1594 
1595         sl.getStage().requestFocus();
1596         cb.show();
1597         Toolkit.getToolkit().firePulse();
1598 
1599         // selection should not change just by showing the popup
1600         assertNull(cb.getValue());
1601         assertEquals(-1, cb.getSelectionModel().getSelectedIndex());
1602         assertNull(cb.getSelectionModel().getSelectedItem());
1603 
1604         sl.dispose();
1605     }
1606 
1607     @Test public void test_rt36717() {
1608         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1609         StageLoader sl = new StageLoader(cb);
1610 
1611         // the stack overflow only occurs when a ComboBox changes from non-editable to editable
1612         cb.setEditable(false);
1613         cb.setEditable(true);
1614         assertNotNull(cb.getEditor());
1615         KeyEventFirer tfKeyboard = new KeyEventFirer(cb.getEditor());
1616         tfKeyboard.doKeyPress(KeyCode.ENTER);   // Stack overflow here
1617 
1618         sl.dispose();
1619     }
1620 
1621     @Test public void test_rt36827() {
1622         final Button btn = new Button("focus owner");
1623         final ComboBox<String> cb = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1624         VBox vbox = new VBox(btn, cb);
1625 
1626         StageLoader sl = new StageLoader(vbox);
1627         sl.getStage().requestFocus();
1628         btn.requestFocus();
1629         Toolkit.getToolkit().firePulse();
1630         Scene scene = sl.getStage().getScene();
1631 
1632         assertTrue(btn.isFocused());
1633         assertEquals(btn, scene.getFocusOwner());
1634 
1635         MouseEventFirer mouse = new MouseEventFirer(cb);
1636         mouse.fireMousePressAndRelease();
1637 
1638         assertTrue(cb.isShowing());
1639         assertTrue(cb.isFocused());
1640         assertEquals(cb, scene.getFocusOwner());
1641 
1642         sl.dispose();
1643     }
1644 
1645     @Test public void test_rt36902() {
1646         final ComboBox<String> cb1 = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1647         final ComboBox<String> cb2 = new ComboBox<>(FXCollections.observableArrayList("a", "b", "c"));
1648         cb2.setEditable(true);
1649         VBox vbox = new VBox(cb1, cb2);
1650 
1651         // lame - I would rather have one keyboard here but I couldn't get it to
1652         // work, so watch out for which keyboard is used below
1653         KeyEventFirer cb1Keyboard = new KeyEventFirer(cb1);
1654         KeyEventFirer cb2Keyboard = new KeyEventFirer(cb2);
1655 
1656         StageLoader sl = new StageLoader(vbox);
1657         sl.getStage().requestFocus();
1658         cb1.requestFocus();
1659         Toolkit.getToolkit().firePulse();
1660         Scene scene = sl.getStage().getScene();
1661 
1662         assertTrue(cb1.isFocused());
1663         assertEquals(cb1, scene.getFocusOwner());
1664 
1665         // move focus forward to cb2
1666         cb1Keyboard.doKeyPress(KeyCode.TAB);
1667         assertTrue(cb2.isFocused());
1668         assertEquals(cb2, scene.getFocusOwner());
1669 
1670         // move focus forward again to cb1
1671         cb2Keyboard.doKeyPress(KeyCode.TAB);
1672         assertTrue(cb1.isFocused());
1673         assertEquals(cb1, scene.getFocusOwner());
1674 
1675         // now start going backwards with shift-tab.
1676         // The first half of the bug is here - when we shift-tab into cb2, we
1677         // actually go into the FakeFocusTextField subcomponent, so whilst the
1678         // cb2.isFocused() returns true as expected, the scene focus owner is
1679         // not the ComboBox, but the FakeFocusTextField inside it
1680         cb1Keyboard.doKeyPress(KeyCode.TAB, KeyModifier.SHIFT);
1681         assertTrue("Expect cb2 to be focused, but actual focus owner is: " + scene.getFocusOwner(),
1682                 cb2.isFocused());
1683         // Updated with fix for RT-34602: The TextField now never gets
1684         // focus (it's just faking it).
1685         // assertEquals("Expect cb2 TextField to be focused, but actual focus owner is: " + scene.getFocusOwner(),
1686         //         cb2.getEditor(), scene.getFocusOwner());
1687         assertEquals("Expect cb2 to be focused, but actual focus owner is: " + scene.getFocusOwner(),
1688                      cb2, scene.getFocusOwner());
1689 
1690         // This is where the second half of the bug appears, as we are stuck in
1691         // the FakeFocusTextField of cb2, we never make it to cb1
1692         cb2Keyboard.doKeyPress(KeyCode.TAB, KeyModifier.SHIFT);
1693         assertTrue(cb1.isFocused());
1694         assertEquals(cb1, scene.getFocusOwner());
1695 
1696         sl.dispose();
1697     }
1698 
1699     private int rt_38901_counter;
1700     @Test public void test_rt_38901_selectNull() {
1701         test_rt_38901(true);
1702     }
1703 
1704     @Test public void test_rt_38901_selectNegativeOne() {
1705         test_rt_38901(false);
1706     }
1707 
1708     private void test_rt_38901(boolean selectNull) {
1709         rt_38901_counter = 0;
1710 
1711         final ComboBox<String> cb = new ComboBox<>();
1712         cb.setOnShowing((e) -> {
1713             cb.getItems().setAll("DUMMY " + (rt_38901_counter++));
1714         });
1715 
1716         assertEquals(-1, cb.getSelectionModel().getSelectedIndex());
1717         assertNull(cb.getSelectionModel().getSelectedItem());
1718         assertNull(cb.getValue());
1719         assertEquals(0, cb.getItems().size());
1720 
1721         // round one
1722         cb.show();
1723         assertEquals(1, cb.getItems().size());
1724         assertEquals("DUMMY 0", cb.getItems().get(0));
1725         cb.hide();
1726 
1727         cb.getSelectionModel().select(0);
1728         assertEquals(0, cb.getSelectionModel().getSelectedIndex());
1729         assertEquals("DUMMY 0", cb.getSelectionModel().getSelectedItem());
1730         assertEquals("DUMMY 0", cb.getValue());
1731 
1732         if (selectNull) cb.getSelectionModel().select(null);
1733         else cb.getSelectionModel().select(-1);
1734 
1735         assertEquals(-1, cb.getSelectionModel().getSelectedIndex());
1736         assertNull(cb.getSelectionModel().getSelectedItem());
1737         assertNull(cb.getValue());
1738 
1739 
1740         // round two
1741         cb.show();
1742         assertEquals(1, cb.getItems().size());
1743         assertEquals("DUMMY 1", cb.getItems().get(0));
1744         cb.hide();
1745 
1746         cb.getSelectionModel().select(0);
1747         assertEquals(0, cb.getSelectionModel().getSelectedIndex());
1748         assertEquals("DUMMY 1", cb.getSelectionModel().getSelectedItem());
1749         assertEquals("DUMMY 1", cb.getValue());
1750 
1751         if (selectNull) cb.getSelectionModel().select(null);
1752         else cb.getSelectionModel().select(-1);
1753 
1754         assertEquals(-1, cb.getSelectionModel().getSelectedIndex());
1755         assertNull(cb.getSelectionModel().getSelectedItem());
1756         assertNull(cb.getValue());
1757     }
1758 
1759     private int rt_22572_counter;
1760     @Test public void test_rt_22572() {
1761         rt_22572_counter = 0;
1762 
1763         final ComboBox<String> cb = new ComboBox<>();
1764         cb.setOnShowing((e) -> {
1765             cb.getItems().setAll("DUMMY " + (rt_22572_counter++));
1766         });
1767 
1768         StageLoader sl = new StageLoader(cb);
1769 
1770         assertEquals(-1, cb.getSelectionModel().getSelectedIndex());
1771         assertNull(cb.getSelectionModel().getSelectedItem());
1772         assertNull(cb.getValue());
1773         assertEquals(0, cb.getItems().size());
1774 
1775         // round one
1776         cb.show();
1777         assertEquals(1, cb.getItems().size());
1778         assertEquals("DUMMY 0", cb.getItems().get(0));
1779         cb.hide();
1780 
1781         cb.getSelectionModel().select(0);
1782         assertEquals(0, cb.getSelectionModel().getSelectedIndex());
1783         assertEquals("DUMMY 0", cb.getSelectionModel().getSelectedItem());
1784         assertEquals("DUMMY 0", cb.getValue());
1785 
1786 
1787         // round two - even though the items change, the value should still be
1788         // the old value (even though it doesn't exist in the items list any longer).
1789         // The selectedIndex and selectedItem do get reset however.
1790         cb.show();
1791         assertEquals(1, cb.getItems().size());
1792         assertEquals("DUMMY 1", cb.getItems().get(0));
1793         cb.hide();
1794 
1795         assertEquals(-1, cb.getSelectionModel().getSelectedIndex());
1796         assertNull(cb.getSelectionModel().getSelectedItem());
1797         assertEquals("DUMMY 0", cb.getValue());
1798 
1799         sl.dispose();
1800     }
1801 
1802     private int rt_22937_counter;
1803     @Test public void test_rt_22937() {
1804         rt_22937_counter = 0;
1805 
1806         final ComboBox<String> cb = new ComboBox<>();
1807         cb.setOnShowing((e) -> {
1808             cb.getItems().setAll("DUMMY " + (rt_22937_counter++));
1809         });
1810 
1811         cb.getItems().add("Toto");
1812         cb.setEditable(true);
1813         cb.setValue("Tata");
1814 
1815         StageLoader sl = new StageLoader(cb);
1816 
1817         assertEquals(-1, cb.getSelectionModel().getSelectedIndex());
1818         assertEquals("Tata", cb.getSelectionModel().getSelectedItem());
1819         assertEquals("Tata", cb.getValue());
1820         assertEquals(1, cb.getItems().size());
1821 
1822         cb.show();
1823         assertEquals(1, cb.getItems().size());
1824         assertEquals("DUMMY 0", cb.getItems().get(0));
1825         cb.hide();
1826 
1827         cb.getSelectionModel().select(0);
1828         assertEquals(0, cb.getSelectionModel().getSelectedIndex());
1829         assertEquals("DUMMY 0", cb.getSelectionModel().getSelectedItem());
1830         assertEquals("DUMMY 0", cb.getValue());
1831 
1832         sl.dispose();
1833     }
1834 
1835     @Test public void test_rt_39809() {
1836         ComboBox<String> comboBox = new ComboBox<>();
1837         comboBox.getItems().setAll(null, "1", "2", "3");
1838 
1839         StageLoader sl = new StageLoader(comboBox);
1840 
1841         comboBox.getSelectionModel().clearAndSelect(1);
1842         assertEquals("1", comboBox.getSelectionModel().getSelectedItem());
1843         assertEquals(1, comboBox.getSelectionModel().getSelectedIndex());
1844 
1845         comboBox.getSelectionModel().clearAndSelect(0);
1846         assertEquals(null, comboBox.getSelectionModel().getSelectedItem());
1847         assertEquals(0, comboBox.getSelectionModel().getSelectedIndex());
1848 
1849         sl.dispose();
1850     }
1851 
1852     @Test public void test_rt_39908() {
1853         ObservableList<String> model = FXCollections.observableArrayList("0", "1", "2", "3");
1854         ComboBox<String> comboBox = new ComboBox<>(model);
1855 
1856         StageLoader sl = new StageLoader(comboBox);
1857 
1858         comboBox.getSelectionModel().clearAndSelect(1);
1859         assertEquals("1", comboBox.getSelectionModel().getSelectedItem());
1860         assertEquals(1, comboBox.getSelectionModel().getSelectedIndex());
1861 
1862         model.set(0, "a");
1863         assertEquals("1", comboBox.getSelectionModel().getSelectedItem());
1864         assertEquals(1, comboBox.getSelectionModel().getSelectedIndex());
1865 
1866         sl.dispose();
1867     }
1868 
1869     /**
1870      * Bullet 1: selected index must be updated
1871      * Corner case: last selected. Fails for core
1872      */
1873     @Test public void test_rt_40012_selectedAtLastOnDisjointRemoveItemsAbove() {
1874         ObservableList<String> items = FXCollections.observableArrayList("0", "1", "2", "3", "4", "5");
1875         ComboBox<String> comboBox = new ComboBox<>(items);
1876         SelectionModel sm = comboBox.getSelectionModel();
1877 
1878         int last = items.size() - 1;
1879 
1880         // selecting item "5"
1881         sm.select(last);
1882 
1883         // disjoint remove of 2 elements above the last selected
1884         // Removing "1" and "3"
1885         items.removeAll(items.get(1), items.get(3));
1886 
1887         // selection should move up two places such that it remains on item "5",
1888         // but in index (last - 2).
1889         int expected = last - 2;
1890         assertEquals("5", sm.getSelectedItem());
1891         assertEquals("selected index after disjoint removes above", expected, sm.getSelectedIndex());
1892     }
1893 
1894     /**
1895      * Variant of 1: if selectedIndex is not updated,
1896      * the old index is no longer valid
1897      * for accessing the items.
1898      */
1899     @Test public void test_rt_40012_accessSelectedAtLastOnDisjointRemoveItemsAbove() {
1900         ObservableList<String> items = FXCollections.observableArrayList("0", "1", "2", "3", "4", "5");
1901         ComboBox<String> comboBox = new ComboBox<>(items);
1902         SelectionModel sm = comboBox.getSelectionModel();
1903 
1904         int last = items.size() - 1;
1905 
1906         // selecting item "5"
1907         sm.select(last);
1908 
1909         // disjoint remove of 2 elements above the last selected
1910         items.removeAll(items.get(1), items.get(3));
1911         int selected = sm.getSelectedIndex();
1912         if (selected > -1) {
1913             items.get(selected);
1914         }
1915     }
1916 
1917     /**
1918      * Bullet 2: selectedIndex notification count
1919      *
1920      * Note that we don't use the corner case of having the last index selected
1921      * (which fails already on updating the index)
1922      */
1923     private int rt_40012_count = 0;
1924     @Test public void test_rt_40012_selectedIndexNotificationOnDisjointRemovesAbove() {
1925         ObservableList<String> items = FXCollections.observableArrayList("0", "1", "2", "3", "4", "5");
1926         ComboBox<String> comboBox = new ComboBox<>(items);
1927         SelectionModel sm = comboBox.getSelectionModel();
1928 
1929         int last = items.size() - 2;
1930         sm.select(last);
1931         assertEquals(last, sm.getSelectedIndex());
1932 
1933         rt_40012_count = 0;
1934         sm.selectedIndexProperty().addListener(o -> rt_40012_count++);
1935 
1936         // disjoint remove of 2 elements above the last selected
1937         items.removeAll(items.get(1), items.get(3));
1938         assertEquals("sanity: selectedIndex must be shifted by -2", last - 2, sm.getSelectedIndex());
1939         assertEquals("must fire single event on removes above", 1, rt_40012_count);
1940     }
1941 
1942     /**
1943      * Bullet 3: unchanged selectedItem must not fire change
1944      */
1945     @Test
1946     public void test_rt_40012_selectedItemNotificationOnDisjointRemovesAbove() {
1947         ObservableList<String> items = FXCollections.observableArrayList("0", "1", "2", "3", "4", "5");
1948         ComboBox<String> comboBox = new ComboBox<>(items);
1949         SelectionModel sm = comboBox.getSelectionModel();
1950 
1951         int last = items.size() - 2;
1952         Object lastItem = items.get(last);
1953         sm.select(last);
1954         assertEquals(lastItem, sm.getSelectedItem());
1955 
1956         rt_40012_count = 0;
1957         sm.selectedItemProperty().addListener(o -> rt_40012_count++);
1958 
1959         // disjoint remove of 2 elements above the last selected
1960         items.removeAll(items.get(1), items.get(3));
1961         assertEquals("sanity: selectedItem unchanged", lastItem, sm.getSelectedItem());
1962         assertEquals("must not fire on unchanged selected item", 0, rt_40012_count);
1963     }
1964 
1965     @Test public void test_jdk_8150946_testCommit_valid() {
1966         ComboBox<String> comboBox = new ComboBox<>();
1967         comboBox.setEditable(true);
1968         assertEquals(null, comboBox.getValue());
1969         comboBox.getEditor().setText("ABC");
1970         comboBox.commitValue();
1971         assertEquals("ABC", comboBox.getValue());
1972     }
1973 
1974     @Test public void test_jdk_8150946_testCancel_toNull() {
1975         ComboBox<String> comboBox = new ComboBox<>();
1976         comboBox.setEditable(true);
1977         assertNull(comboBox.getValue());
1978         assertEquals("", comboBox.getEditor().getText());
1979         comboBox.getEditor().setText("ABC");
1980         assertNull(comboBox.getValue());
1981         comboBox.cancelEdit();
1982         assertNull(comboBox.getValue());
1983         assertNull(comboBox.getEditor().getText());
1984     }
1985 
1986     @Test public void test_jdk_8150946_testCancel_toNonNull() {
1987         ComboBox<String> comboBox = new ComboBox<>();
1988         comboBox.setEditable(true);
1989         comboBox.getEditor().setText("ABC");
1990         comboBox.commitValue();
1991         assertEquals("ABC", comboBox.getValue());
1992         assertEquals("ABC", comboBox.getEditor().getText());
1993         comboBox.getEditor().setText("DEF");
1994         assertEquals("DEF", comboBox.getEditor().getText());
1995         assertEquals("ABC", comboBox.getValue());
1996         comboBox.cancelEdit();
1997         assertEquals("ABC", comboBox.getValue());
1998         assertEquals("ABC", comboBox.getEditor().getText());
1999     }
2000 
2001     @Test public void test_jdk_8160493() {
2002         AtomicInteger count = new AtomicInteger();
2003         comboBox.valueProperty().addListener(o -> count.incrementAndGet());
2004         assertEquals(0, count.get());
2005 
2006         comboBox.getItems().addAll("Apple", "Orange", "Banana");
2007         sm.select(1);
2008         assertTrue(sm.isSelected(1));
2009         assertEquals(1, count.get());
2010         assertEquals("Orange", comboBox.getValue());
2011 
2012         comboBox.setValue("New Value");
2013         assertEquals(2, count.get());
2014         assertEquals("New Value", comboBox.getValue());
2015     }
2016 
2017     private int skinChangedCount = 0;
2018     @Test public void test_JDK_8185854() {
2019         final FlowPane comboPane = new FlowPane(10, 10);
2020         ComboBox combo = new ComboBox<String>();
2021 
2022         combo.skinProperty().addListener((o, oldSkin, newSkin) -> {
2023             skinChangedCount++;
2024         });
2025 
2026         combo.setDisable(false);
2027         combo.setEditable(false);
2028 
2029         comboPane.getChildren().add(combo);
2030 
2031         TabPane tabPane = new TabPane();
2032         Tab tab = new Tab();
2033         tab.setText("ComboBox");
2034         tab.setContent(comboPane);
2035         tabPane.getTabs().add(tab);
2036 
2037         BorderPane p = new BorderPane();
2038         p.setCenter(tabPane);
2039 
2040         Scene scene = new Scene(p);
2041         scene.getStylesheets().add(ComboBoxTest.class.getResource("JDK_8185854.css").toExternalForm());
2042 
2043         Toolkit tk = Toolkit.getToolkit();
2044 
2045         Stage stage = new Stage();
2046         stage.setScene(scene);
2047         stage.setWidth(500);
2048         stage.setHeight(400);
2049 
2050         stage.show();
2051 
2052         tk.firePulse();
2053 
2054         assertEquals("ComboBox skinProperty changed more than once, which is not expected.", 1, skinChangedCount);
2055     }
2056 }