All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.assertj.swing.driver.JComboBoxDriver Maven / Gradle / Ivy

There is a newer version: 3.17.1
Show newest version
/**
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with
 * the License. You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on
 * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the
 * specific language governing permissions and limitations under the License.
 *
 * Copyright 2012-2015 the original author or authors.
 */
package org.assertj.swing.driver;

import static javax.swing.text.DefaultEditorKit.selectAllAction;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Fail.fail;
import static org.assertj.core.util.Preconditions.checkNotNull;
import static org.assertj.core.util.Strings.quote;
import static org.assertj.swing.driver.ComponentPreconditions.checkEnabledAndShowing;
import static org.assertj.swing.driver.JComboBoxContentQuery.contents;
import static org.assertj.swing.driver.JComboBoxEditableQuery.isEditable;
import static org.assertj.swing.driver.JComboBoxItemCountQuery.itemCountIn;
import static org.assertj.swing.driver.JComboBoxItemIndexPreconditions.checkItemIndexInBounds;
import static org.assertj.swing.driver.JComboBoxMatchingItemQuery.matchingItemIndex;
import static org.assertj.swing.driver.JComboBoxSelectedIndexQuery.selectedIndexOf;
import static org.assertj.swing.driver.JComboBoxSelectionValueQuery.selection;
import static org.assertj.swing.driver.JComboBoxSetSelectedIndexTask.setSelectedIndex;
import static org.assertj.swing.driver.TextAssert.verifyThat;
import static org.assertj.swing.edt.GuiActionRunner.execute;
import static org.assertj.swing.exception.ActionFailedException.actionFailure;
import static org.assertj.swing.format.Formatting.format;
import static org.assertj.swing.util.Arrays.format;

import java.awt.Component;
import java.util.regex.Pattern;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.swing.ComboBoxEditor;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JList;

import org.assertj.core.description.Description;
import org.assertj.core.util.VisibleForTesting;
import org.assertj.swing.annotation.RunsInCurrentThread;
import org.assertj.swing.annotation.RunsInEDT;
import org.assertj.swing.cell.JComboBoxCellReader;
import org.assertj.swing.core.Robot;
import org.assertj.swing.edt.GuiQuery;
import org.assertj.swing.edt.GuiTask;
import org.assertj.swing.exception.ComponentLookupException;
import org.assertj.swing.exception.LocationUnavailableException;
import org.assertj.swing.internal.annotation.InternalApi;
import org.assertj.swing.util.Pair;
import org.assertj.swing.util.PatternTextMatcher;
import org.assertj.swing.util.StringTextMatcher;
import org.assertj.swing.util.TextMatcher;

/**
 * 

* Supports functional testing of {@code JComboBox}es. *

* *

* Note: This class is intended for internal use only. Please use the classes in the package * {@link org.assertj.swing.fixture} in your tests. *

* * @author Alex Ruiz * @author Yvonne Wang */ @InternalApi public class JComboBoxDriver extends JComponentDriver { private static final String EDITABLE_PROPERTY = "editable"; private static final String SELECTED_INDEX_PROPERTY = "selectedIndex"; private final JListDriver listDriver; private final JComboBoxDropDownListFinder dropDownListFinder; private JComboBoxCellReader cellReader; /** * Creates a new {@link JComboBoxDriver}. * * @param robot the robot to use to simulate user input. */ public JComboBoxDriver(@Nonnull Robot robot) { super(robot); listDriver = new JListDriver(robot); dropDownListFinder = new JComboBoxDropDownListFinder(robot); replaceCellReader(new BasicJComboBoxCellReader()); } /** * Returns an array of {@code String}s that represents the contents of the given {@code JComboBox} list. The * {@code String} representation of each element is performed using this driver's {@link JComboBoxCellReader}. * * @param comboBox the target {@code JComboBox}. * @return an array of {@code String}s that represent the contents of the given {@code JComboBox} list. * @see #value(JComboBox, int) * @see #replaceCellReader(JComboBoxCellReader) */ @RunsInEDT public @Nonnull String[] contentsOf(@Nonnull JComboBox comboBox) { return contents(comboBox, cellReader()); } /** * Selects the first item matching the given text in the {@code JComboBox}. The text of the {@code JComboBox} items is * obtained by this fixture's {@link JComboBoxCellReader}. * * @param comboBox the target {@code JComboBox}. * @param value the value to match. It can be a regular expression. * @throws LocationUnavailableException if an element matching the given value cannot be found. * @throws IllegalStateException if the {@code JComboBox} is disabled. * @throws IllegalStateException if the {@code JComboBox} is not showing on the screen. * @see #replaceCellReader(JComboBoxCellReader) */ @RunsInEDT public void selectItem(@Nonnull JComboBox comboBox, @Nullable String value) { selectItem(comboBox, new StringTextMatcher(value)); } /** * Selects the first item matching the given regular expression pattern in the {@code JComboBox}. The text of the * {@code JComboBox} items is obtained by this fixture's {@link JComboBoxCellReader}. * * @param comboBox the target {@code JComboBox}. * @param pattern the regular expression pattern to match. * @throws LocationUnavailableException if an element matching the given pattern cannot be found. * @throws IllegalStateException if the {@code JComboBox} is disabled. * @throws IllegalStateException if the {@code JComboBox} is not showing on the screen. * @throws NullPointerException if the given regular expression pattern is {@code null}. * @see #replaceCellReader(JComboBoxCellReader) */ @RunsInEDT public void selectItem(@Nonnull JComboBox comboBox, @Nonnull Pattern pattern) { selectItem(comboBox, new PatternTextMatcher(pattern)); } @RunsInEDT private void selectItem(@Nonnull JComboBox comboBox, @Nonnull TextMatcher matcher) { int index = matchingItemIndex(comboBox, matcher, cellReader()); if (index < 0) { String format = "Unable to find item matching %s among the JComboBox contents: "; String msg = String.format(format, matcher.description(), format(contentsOf(comboBox))); throw new LocationUnavailableException(msg); } selectItem(comboBox, index); } /** * Verifies that the {@code String} representation of the selected item in the {@code JComboBox} matches the given * text. * * @param comboBox the target {@code JComboBox}. * @param value the text to match. It can be a regular expression. * @throws AssertionError if the selected item does not match the given value. * @see #replaceCellReader(JComboBoxCellReader) */ @RunsInEDT public void requireSelection(@Nonnull JComboBox comboBox, @Nullable String value) { String selection = requiredSelectionOf(comboBox); verifyThat(selection).as(selectedIndexProperty(comboBox)).isEqualOrMatches(value); } /** * Verifies that the {@code String} representation of the selected item in the {@code JComboBox} matches the given * regular expression pattern. * * @param comboBox the target {@code JComboBox}. * @param pattern the regular expression pattern to match. * @throws AssertionError if the selected item does not match the given regular expression pattern. * @throws NullPointerException if the given regular expression pattern is {@code null}. * @see #replaceCellReader(JComboBoxCellReader) */ @RunsInEDT public void requireSelection(@Nonnull JComboBox comboBox, @Nonnull Pattern pattern) { String selection = requiredSelectionOf(comboBox); verifyThat(selection).as(selectedIndexProperty(comboBox)).matches(pattern); } @RunsInEDT private @Nullable String requiredSelectionOf(@Nonnull JComboBox comboBox) throws AssertionError { Pair selection = selection(comboBox, cellReader()); boolean hasSelection = selection.first; if (!hasSelection) { failNoSelection(comboBox); } return selection.second; } /** * Verifies that the index of the selected item in the {@code JComboBox} is equal to the given value. * * @param comboBox the target {@code JComboBox}. * @param index the expected selection index. * @throws AssertionError if the selection index is not equal to the given value. */ @RunsInEDT public void requireSelection(@Nonnull JComboBox comboBox, int index) { int selectedIndex = selectedIndexOf(comboBox); if (selectedIndex == -1) { failNoSelection(comboBox); } assertThat(selectedIndex).as(selectedIndexProperty(comboBox)).isEqualTo(index); } private void failNoSelection(@Nonnull JComboBox comboBox) { fail(String.format("[%s] No selection", selectedIndexProperty(comboBox).value())); } /** * Verifies that the {@code JComboBox} does not have any selection. * * @param comboBox the target {@code JComboBox}. * @throws AssertionError if the {@code JComboBox} has a selection. */ @RunsInEDT public void requireNoSelection(@Nonnull JComboBox comboBox) { Pair selection = selection(comboBox, cellReader()); boolean hasSelection = selection.first; if (!hasSelection) { return; } String format = "[%s] Expecting no selection, but found:<%s>"; fail(String.format(format, selectedIndexProperty(comboBox).value(), quote(selection.second))); } /** * Returns the {@code String} representation of the element under the given index, using this driver's * {@link JComboBoxCellReader}. * * @param comboBox the target {@code JComboBox}. * @param index the given index. * @return the value of the element under the given index. * @throws IndexOutOfBoundsException if the given index is negative or greater than the index of the last item in the * {@code JComboBox}. * @see #replaceCellReader(JComboBoxCellReader) */ public @Nullable String value(@Nonnull JComboBox comboBox, int index) { return valueAsText(comboBox, index, cellReader()); } @RunsInEDT private static @Nullable String valueAsText(final @Nonnull JComboBox comboBox, final int index, final @Nonnull JComboBoxCellReader cellReader) { return execute(new GuiQuery() { @Override protected @Nullable String executeInEDT() { checkItemIndexInBounds(comboBox, index); return cellReader.valueAt(comboBox, index); } }); } private @Nonnull Description selectedIndexProperty(@Nonnull JComboBox comboBox) { return propertyName(comboBox, SELECTED_INDEX_PROPERTY); } /** * Clears the selection in the given {@code JComboBox}. Since this method does not simulate user input, it does not * verifies that the {@code JComboBox} is enabled and showing. * * @param comboBox the target {@code JComboBox}. */ public void clearSelection(@Nonnull JComboBox comboBox) { setSelectedIndex(comboBox, -1); robot.waitForIdle(); } /** * Selects the item under the given index in the {@code JComboBox}. * * @param comboBox the target {@code JComboBox}. * @param index the given index. * @throws IllegalStateException if the {@code JComboBox} is disabled. * @throws IllegalStateException if the {@code JComboBox} is not showing on the screen. * @throws IndexOutOfBoundsException if the given index is negative or greater than the index of the last item in the * {@code JComboBox}. */ @RunsInEDT public void selectItem(final @Nonnull JComboBox comboBox, int index) { validateCanSelectItem(comboBox, index); showDropDownList(comboBox); selectItemAtIndex(comboBox, index); hideDropDownListIfVisible(comboBox); } @RunsInEDT private static void validateCanSelectItem(final @Nonnull JComboBox comboBox, final int index) { execute(new GuiTask() { @Override protected void executeInEDT() { checkEnabledAndShowing(comboBox); checkItemIndexInBounds(comboBox, index); } }); } @VisibleForTesting @RunsInEDT void showDropDownList(@Nonnull JComboBox comboBox) { // Location of pop-up button activator is LAF-dependent dropDownVisibleThroughUIDelegate(comboBox, true); } @RunsInEDT private void selectItemAtIndex(@Nonnull final JComboBox comboBox, final int index) { JList dropDownList = dropDownListFinder.findDropDownList(); if (dropDownList != null) { listDriver.selectItem(dropDownList, index); return; } setSelectedIndex(comboBox, index); robot.waitForIdle(); } @RunsInEDT private void hideDropDownListIfVisible(@Nonnull JComboBox comboBox) { dropDownVisibleThroughUIDelegate(comboBox, false); } @RunsInEDT private void dropDownVisibleThroughUIDelegate(@Nonnull final JComboBox comboBox, final boolean visible) { execute(new GuiTask() { @Override protected void executeInEDT() { comboBox.setPopupVisible(visible); } }); robot.waitForIdle(); } /** * Simulates a user entering the specified text in the {@code JComboBox}, replacing any text. This action is executed * only if the {@code JComboBox} is editable. * * @param comboBox the target {@code JComboBox}. * @param text the text to enter. * @throws IllegalStateException if the {@code JComboBox} is disabled. * @throws IllegalStateException if the {@code JComboBox} is not showing on the screen. * @throws IllegalStateException if the {@code JComboBox} is not editable. */ @RunsInEDT public void replaceText(@Nonnull JComboBox comboBox, @Nonnull String text) { selectAllText(comboBox); enterText(comboBox, text); } /** * Simulates a user selecting the text in the {@code JComboBox}. This action is executed only if the {@code JComboBox} * is editable. * * @param comboBox the target {@code JComboBox}. * @throws IllegalStateException if the {@code JComboBox} is disabled. * @throws IllegalStateException if the {@code JComboBox} is not showing on the screen. * @throws IllegalStateException if the {@code JComboBox} is not editable. */ @RunsInEDT public void selectAllText(@Nonnull JComboBox comboBox) { Component editor = accessibleEditorOf(comboBox); if (!(editor instanceof JComponent)) { return; } focus(editor); invokeAction((JComponent) editor, selectAllAction); } @RunsInEDT private static @Nullable Component accessibleEditorOf(final @Nonnull JComboBox comboBox) { return execute(new GuiQuery() { @Override protected @Nullable Component executeInEDT() { checkAccessibleEditor(comboBox); return editorComponentOf(comboBox); } }); } /** * Simulates a user entering the specified text in the {@code JComboBox}. This action is executed only if the * {@code JComboBox} is editable. * * @param comboBox the target {@code JComboBox}. * @param text the text to enter. * @throws IllegalStateException if the {@code JComboBox} is disabled. * @throws IllegalStateException if the {@code JComboBox} is not showing on the screen. * @throws IllegalStateException if the {@code JComboBox} is not editable. * @throws org.assertj.swing.exception.ActionFailedException if the {@code JComboBox} does not have an editor. */ @RunsInEDT public void enterText(final @Nonnull JComboBox comboBox, @Nonnull String text) { execute(new GuiTask() { @Override protected void executeInEDT() { checkAccessibleEditor(comboBox); } }); Component editor = editorComponentOf(comboBox); // this will never happen...at least in Sun's JVM if (editor == null) { throw actionFailure("JComboBox does not have an editor"); } focusAndWaitForFocusGain(editor); robot.enterText(text); } /** * Simulates a user pressing and releasing the given keys on the {@code JComboBox}. * * @param comboBox the target {@code JComboBox}. * @param keyCodes one or more codes of the keys to press. * @throws NullPointerException if the given array of codes is {@code null}. * @throws IllegalStateException if the {@code JComboBox} is disabled. * @throws IllegalStateException if the {@code JComboBox} is not showing on the screen. * @throws IllegalArgumentException if the given code is not a valid key code. * @see java.awt.event.KeyEvent */ @RunsInEDT public void pressAndReleaseKeys(@Nonnull JComboBox comboBox, @Nonnull int... keyCodes) { checkNotNull(keyCodes); checkInEdtEnabledAndShowing(comboBox); Component target = editorIfEditable(comboBox); if (target == null) { target = comboBox; } focusAndWaitForFocusGain(target); robot.pressAndReleaseKeys(keyCodes); } @RunsInEDT private static Component editorIfEditable(final JComboBox comboBox) { return execute(new GuiQuery() { @Override protected Component executeInEDT() { if (!comboBox.isEditable()) { return null; } return editorComponent(comboBox); } }); } @RunsInCurrentThread private static void checkAccessibleEditor(@Nonnull JComboBox comboBox) { checkEnabledAndShowing(comboBox); if (!comboBox.isEditable()) { String msg = String.format("Expecting component %s to be editable", format(comboBox)); throw new IllegalStateException(msg); } } @RunsInEDT private static @Nullable Component editorComponentOf(final @Nonnull JComboBox comboBox) { return execute(new GuiQuery() { @Override protected @Nullable Component executeInEDT() { return editorComponent(comboBox); } }); } @RunsInCurrentThread private static @Nullable Component editorComponent(@Nonnull JComboBox comboBox) { ComboBoxEditor editor = comboBox.getEditor(); if (editor == null) { return null; } return editor.getEditorComponent(); } /** * Find the {@code JList} in the pop-up raised by the {@code JComboBox}, if the LAF actually uses one. * * @return the found {@code JList}. * @throws ComponentLookupException if the {@code JList} in the pop-up could not be found. */ @RunsInEDT public @Nonnull JList dropDownList() { JList list = dropDownListFinder.findDropDownList(); if (list == null) { throw new ComponentLookupException("Unable to find the pop-up list for the JComboBox"); } return list; } /** * Asserts that the given {@code JComboBox} is editable. * * @param comboBox the target {@code JComboBox}. * @throws AssertionError if the {@code JComboBox} is not editable. */ @RunsInEDT public void requireEditable(final @Nonnull JComboBox comboBox) { checkEditable(comboBox, true); } /** * Asserts that the given {@code JComboBox} is not editable. * * @param comboBox the given {@code JComboBox}. * @throws AssertionError if the {@code JComboBox} is editable. */ @RunsInEDT public void requireNotEditable(@Nonnull JComboBox comboBox) { checkEditable(comboBox, false); } @RunsInEDT private void checkEditable(@Nonnull JComboBox comboBox, boolean expected) { assertThat(isEditable(comboBox)).as(editableProperty(comboBox)).isEqualTo(expected); } @RunsInEDT private static Description editableProperty(@Nonnull JComboBox comboBox) { return propertyName(comboBox, EDITABLE_PROPERTY); } /** * Updates the implementation of {@link JComboBoxCellReader} to use when comparing internal values of a * {@code JComboBox} and the values expected in a test. * * @param newCellReader the new {@code JComboBoxCellValueReader} to use. * @throws NullPointerException if {@code newCellReader} is {@code null}. */ public void replaceCellReader(@Nonnull JComboBoxCellReader newCellReader) { cellReader = checkNotNull(newCellReader); } /** * Verifies that number of items in the given {@code JComboBox} is equal to the expected one. * * @param comboBox the target {@code JComboBox}. * @param expected the expected number of items. * @throws AssertionError if the number of items in the given {@code JComboBox} is not equal to the expected one. */ @RunsInEDT public void requireItemCount(@Nonnull JComboBox comboBox, int expected) { int actual = itemCountIn(comboBox); assertThat(actual).as(propertyName(comboBox, "itemCount")).isEqualTo(expected); } /** * Returns the selected value of the given {@code JComboBox} as plain text. This method returns {@code null} if the * {code JComboBox} does not have any selection. * * @param comboBox the target {@code JComboBox}. * @return the selected value of the given {code JComboBox} as plain text, or {@code null} if the {code JComboBox} * does not have any selection. */ public @Nullable String selectedItemOf(@Nonnull JComboBox comboBox) { return selection(comboBox, cellReader()).second; } private @Nonnull JComboBoxCellReader cellReader() { return cellReader; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy