001    /*
002     * Created on Apr 9, 2007
003     *
004     * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
005     * in compliance with the License. You may obtain a copy of the License at
006     *
007     * http://www.apache.org/licenses/LICENSE-2.0
008     *
009     * Unless required by applicable law or agreed to in writing, software distributed under the License
010     * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
011     * or implied. See the License for the specific language governing permissions and limitations under
012     * the License.
013     *
014     * Copyright @2007-2010 the original author or authors.
015     */
016    package org.fest.swing.fixture;
017    
018    import java.awt.Point;
019    import java.util.regex.Pattern;
020    
021    import javax.swing.JComboBox;
022    import javax.swing.JList;
023    
024    import org.fest.swing.cell.JComboBoxCellReader;
025    import org.fest.swing.core.*;
026    import org.fest.swing.driver.BasicJComboBoxCellReader;
027    import org.fest.swing.driver.JComboBoxDriver;
028    import org.fest.swing.exception.*;
029    import org.fest.swing.timing.Timeout;
030    
031    /**
032     * Understands functional testing of <code>{@link JComboBox}</code>es:
033     * <ul>
034     * <li>user input simulation</li>
035     * <li>state verification</li>
036     * <li>property value query</li>
037     * </ul>
038     * <p>
039     * The conversion between the values given in tests and the values being displayed by a <code>{@link JComboBox}</code>
040     * renderer is performed by a <code>{@link JComboBoxCellReader}</code>. This fixture uses a
041     * <code>{@link JComboBoxCellReader}</code> by default.
042     * </p>
043     *
044     * @author Alex Ruiz
045     * @author Yvonne Wang
046     */
047    public class JComboBoxFixture extends ComponentFixture<JComboBox> implements CommonComponentFixture,
048        EditableComponentFixture, ItemGroupFixture, JComponentFixture, JPopupMenuInvokerFixture {
049    
050      private JComboBoxDriver driver;
051    
052      /**
053       * Creates a new <code>{@link JComboBoxFixture}</code>.
054       * @param robot performs simulation of user events on the given <code>JComboBox</code>.
055       * @param target the <code>JComboBox</code> to be managed by this fixture.
056       * @throws NullPointerException if <code>robot</code> is <code>null</code>.
057       * @throws NullPointerException if <code>target</code> is <code>null</code>.
058       */
059      public JComboBoxFixture(Robot robot, JComboBox target) {
060        super(robot, target);
061        createDriver();
062      }
063    
064      /**
065       * Creates a new <code>{@link JComboBoxFixture}</code>.
066       * @param robot performs simulation of user events on a <code>JComboBox</code>.
067       * @param comboBoxName the name of the <code>JComboBox</code> to find using the given <code>Robot</code>.
068       * @throws NullPointerException if <code>robot</code> is <code>null</code>.
069       * @throws ComponentLookupException if a matching <code>JComboBox</code> could not be found.
070       * @throws ComponentLookupException if more than one matching <code>JComboBox</code> is found.
071       */
072      public JComboBoxFixture(Robot robot, String comboBoxName) {
073        super(robot, comboBoxName, JComboBox.class);
074        createDriver();
075      }
076    
077      private void createDriver() {
078        driver(new JComboBoxDriver(robot));
079      }
080    
081      /**
082       * Sets the <code>{@link JComboBoxDriver}</code> to be used by this fixture.
083       * @param newDriver the new <code>JComboBoxDriver</code>.
084       * @throws NullPointerException if the given driver is <code>null</code>.
085       */
086      protected final void driver(JComboBoxDriver newDriver) {
087        validateNotNull(newDriver);
088        driver = newDriver;
089      }
090    
091      /**
092       * Simulates a user clicking this fixture's <code>{@link JComboBox}</code>.
093       * @return this fixture.
094       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is disabled.
095       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is not showing on the screen.
096       */
097      public JComboBoxFixture click() {
098        driver.click(target);
099        return this;
100      }
101    
102      /**
103       * Simulates a user clicking this fixture's <code>{@link JComboBox}</code>.
104       * @param button the button to click.
105       * @return this fixture.
106       * @throws NullPointerException if the given <code>MouseButton</code> is <code>null</code>.
107       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is disabled.
108       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is not showing on the screen.
109       */
110      public JComboBoxFixture click(MouseButton button) {
111        driver.click(target, button);
112        return this;
113      }
114    
115      /**
116       * Simulates a user clicking this fixture's <code>{@link JComboBox}</code>.
117       * @param mouseClickInfo specifies the button to click and the times the button should be clicked.
118       * @return this fixture.
119       * @throws NullPointerException if the given <code>MouseClickInfo</code> is <code>null</code>.
120       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is disabled.
121       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is not showing on the screen.
122       */
123      public JComboBoxFixture click(MouseClickInfo mouseClickInfo) {
124        driver.click(target, mouseClickInfo);
125        return this;
126      }
127    
128      /**
129       * Simulates a user double-clicking this fixture's <code>{@link JComboBox}</code>.
130       * @return this fixture.
131       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is disabled.
132       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is not showing on the screen.
133       */
134      public JComboBoxFixture doubleClick() {
135        driver.doubleClick(target);
136        return this;
137      }
138    
139      /**
140       * Simulates a user right-clicking this fixture's <code>{@link JComboBox}</code>.
141       * @return this fixture.
142       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is disabled.
143       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is not showing on the screen.
144       */
145      public JComboBoxFixture rightClick() {
146        driver.rightClick(target);
147        return this;
148      }
149    
150      /**
151       * Returns the <code>String</code> representation of the elements in this fixture's <code>{@link JComboBox}</code>,
152       * using this fixture's <code>{@link JComboBoxCellReader}</code>.
153       * @return the <code>String</code> representation of the elements in this fixture's <code>JComboBox</code>.
154       * @see #cellReader(JComboBoxCellReader)
155       */
156      public String[] contents() {
157        return driver.contentsOf(target);
158      }
159    
160      /**
161       * Simulates a user entering the specified text in the <code>{@link JComboBox}</code>, replacing any text. This action
162       * is executed only if the <code>{@link JComboBox}</code> is editable.
163       * @param text the text to enter.
164       * @return this fixture.
165       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is disabled.
166       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is not showing on the screen.
167       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is not editable.
168       */
169      public JComboBoxFixture replaceText(String text) {
170        driver.replaceText(target, text);
171        return this;
172      }
173    
174      /**
175       * Simulates a user selecting the text in the <code>{@link JComboBox}</code>. This action is executed only if the
176       * <code>{@link JComboBox}</code> is editable.
177       * @return this fixture.
178       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is disabled.
179       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is not showing on the screen.
180       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is not editable.
181       */
182      public JComboBoxFixture selectAllText() {
183        driver.selectAllText(target);
184        return this;
185      }
186    
187      /**
188       * Simulates a user entering the specified text in this fixture's <code>{@link JComboBox}</code>. This action is
189       * executed only if the <code>{@link JComboBox}</code> is editable.
190       * @param text the text to enter.
191       * @return this fixture.
192       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is disabled.
193       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is not showing on the screen.
194       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is not editable.
195       * @throws ActionFailedException if this fixture's <code>JComboBox</code> does not have an editor.
196       */
197      public JComboBoxFixture enterText(String text) {
198        driver.enterText(target, text);
199        return this;
200      }
201    
202      /**
203       * Gives input focus to this fixture's <code>{@link JComboBox}</code>.
204       * @return this fixture.
205       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is disabled.
206       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is not showing on the screen.
207       */
208      public JComboBoxFixture focus() {
209        driver.focus(target);
210        return this;
211      }
212    
213      /**
214       * Finds and returns the {@link JList} in the pop-up raised by this fixture's <code>{@link JComboBox}</code>.
215       * @return the <code>JList</code> in the pop-up raised by this fixture's <code>JComboBox</code>.
216       * @throws ComponentLookupException if the <code>JList</code> in the pop-up could not be found.
217       */
218      public JList list() {
219        return driver.dropDownList();
220      }
221    
222      /**
223       * Simulates a user pressing given key with the given modifiers on this fixture's <code>{@link JComboBox}</code>.
224       * Modifiers is a mask from the available <code>{@link java.awt.event.InputEvent}</code> masks.
225       * @param keyPressInfo specifies the key and modifiers to press.
226       * @return this fixture.
227       * @throws NullPointerException if the given <code>KeyPressInfo</code> is <code>null</code>.
228       * @throws IllegalArgumentException if the given code is not a valid key code.
229       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is disabled.
230       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is not showing on the screen.
231       * @see KeyPressInfo
232       */
233      public JComboBoxFixture pressAndReleaseKey(KeyPressInfo keyPressInfo) {
234        driver.pressAndReleaseKey(target, keyPressInfo);
235        return this;
236      }
237    
238      /**
239       * Simulates a user pressing and releasing the given keys on this fixture's <code>{@link JComboBox}</code>.
240       * @param keyCodes one or more codes of the keys to press.
241       * @return this fixture.
242       * @throws NullPointerException if the given array of codes is <code>null</code>.
243       * @throws IllegalArgumentException if any of the given code is not a valid key code.
244       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is disabled.
245       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is not showing on the screen.
246       * @see java.awt.event.KeyEvent
247       */
248      public JComboBoxFixture pressAndReleaseKeys(int... keyCodes) {
249        driver.pressAndReleaseKeys(target, keyCodes);
250        return this;
251      }
252    
253      /**
254       * Simulates a user pressing the given key on this fixture's <code>{@link JComboBox}</code>.
255       * @param keyCode the code of the key to press.
256       * @return this fixture.
257       * @throws IllegalArgumentException if any of the given code is not a valid key code.
258       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is disabled.
259       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is not showing on the screen.
260       * @see java.awt.event.KeyEvent
261       */
262      public JComboBoxFixture pressKey(int keyCode) {
263        driver.pressKey(target, keyCode);
264        return this;
265      }
266    
267      /**
268       * Simulates a user releasing the given key on this fixture's <code>{@link JComboBox}</code>.
269       * @param keyCode the code of the key to release.
270       * @return this fixture.
271       * @throws IllegalArgumentException if any of the given code is not a valid key code.
272       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is disabled.
273       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is not showing on the screen.
274       * @see java.awt.event.KeyEvent
275       */
276      public JComboBoxFixture releaseKey(int keyCode) {
277        driver.releaseKey(target, keyCode);
278        return this;
279      }
280    
281      /**
282       * Clears the selection in this fixture's <code>{@link JComboBox}</code>. Since this method does not simulate user
283       * input, it does not verifies that this fixture's <code>JComboBox</code> is enabled and showing.
284       * @return this fixture.
285       * @since 1.2
286       */
287      public JComboBoxFixture clearSelection() {
288        driver.clearSelection(target);
289        return this;
290      }
291    
292      /**
293       * Simulates a user selecting an item in this fixture's <code>{@link JComboBox}</code>.
294       * @param index the index of the item to select.
295       * @return this fixture.
296       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is disabled.
297       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is not showing on the screen.
298       * @throws IndexOutOfBoundsException if the given index is negative or greater than the index of the last item in the
299       * <code>JComboBox</code>.
300       */
301      public JComboBoxFixture selectItem(int index) {
302        driver.selectItem(target, index);
303        return this;
304      }
305    
306      /**
307       * Simulates a user selecting an item in this fixture's <code>{@link JComboBox}</code>. The text of the item to
308       * select must match the given <code>String</code>. Such text is retrieved by this fixture's
309       * <code>{@link JComboBoxCellReader}</code>.
310       * @param text the text of the item to select. It can be a regular expression.
311       * @return this fixture.
312       * @throws LocationUnavailableException if an element matching the given text cannot be found.
313       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is disabled.
314       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is not showing on the screen.
315       * @see #cellReader(JComboBoxCellReader)
316       */
317      public JComboBoxFixture selectItem(String text) {
318        driver.selectItem(target, text);
319        return this;
320      }
321    
322      /**
323       * Simulates a user selecting an item in this fixture's <code>{@link JComboBox}</code>. The text of the item to
324       * select must match the given regular expression pattern. Such text is retrieved by this fixture's
325       * <code>{@link JComboBoxCellReader}</code>.
326       * @param pattern the regular expression pattern to match.
327       * @return this fixture.
328       * @throws LocationUnavailableException if an element matching the given pattern cannot be found.
329       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is disabled.
330       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is not showing on the screen.
331       * @throws NullPointerException if the given regular expression pattern is <code>null</code>.
332       * @see #cellReader(JComboBoxCellReader)
333       * @since 1.2
334       */
335      public JComboBoxFixture selectItem(Pattern pattern) {
336        driver.selectItem(target, pattern);
337        return this;
338      }
339    
340      /**
341       * Returns the <code>String</code> representation of the value of an item in this fixture's
342       * <code>{@link JComboBox}</code>, using this fixture's <code>{@link JComboBoxCellReader}</code>.
343       * @param index the index of the item to return.
344       * @return the <code>String</code> representation of the value of an item in this fixture's <code>JComboBox</code>.
345       * @throws IndexOutOfBoundsException if the given index is negative or greater than the index of the last item in the
346       * <code>JComboBox</code>.
347       * @see #cellReader(JComboBoxCellReader)
348       */
349      public String valueAt(int index) {
350        return driver.value(target, index);
351      }
352    
353      /**
354       * Asserts that this fixture's <code>{@link JComboBox}</code> is enabled.
355       * @return this fixture.
356       * @throws AssertionError if this fixture's <code>JComboBox</code> is disabled.
357       */
358      public JComboBoxFixture requireEnabled() {
359        driver.requireEnabled(target);
360        return this;
361      }
362      /**
363       * Asserts that this fixture's <code>{@link JComboBox}</code> has input focus.
364       * @return this fixture.
365       * @throws AssertionError if this fixture's <code>JComboBox</code> does not have input focus.
366       */
367      public JComboBoxFixture requireFocused() {
368        driver.requireFocused(target);
369        return this;
370      }
371    
372    
373      /**
374       * Asserts that this fixture's <code>{@link JComboBox}</code> is enabled.
375       * @param timeout the time this fixture will wait for the component to be enabled.
376       * @return this fixture.
377       * @throws org.fest.swing.exception.WaitTimedOutError if this fixture's <code>JComboBox</code> is never enabled.
378       */
379      public JComboBoxFixture requireEnabled(Timeout timeout) {
380        driver.requireEnabled(target, timeout);
381        return this;
382      }
383    
384      /**
385       * Asserts that this fixture's <code>{@link JComboBox}</code> is disabled.
386       * @return this fixture.
387       * @throws AssertionError if this fixture's <code>JComboBox</code> is enabled.
388       */
389      public JComboBoxFixture requireDisabled() {
390        driver.requireDisabled(target);
391        return this;
392      }
393    
394      /**
395       * Asserts that this fixture's <code>{@link JComboBox}</code> is visible.
396       * @return this fixture.
397       * @throws AssertionError if this fixture's <code>JComboBox</code> is not visible.
398       */
399      public JComboBoxFixture requireVisible() {
400        driver.requireVisible(target);
401        return this;
402      }
403    
404      /**
405       * Asserts that this fixture's <code>{@link JComboBox}</code> is not visible.
406       * @return this fixture.
407       * @throws AssertionError if this fixture's <code>JComboBox</code> is visible.
408       */
409      public JComboBoxFixture requireNotVisible() {
410        driver.requireNotVisible(target);
411        return this;
412      }
413    
414      /**
415       * Asserts that this fixture's <code>{@link JComboBox}</code> is editable.
416       * @throws AssertionError if this fixture's <code>JComboBox</code> is not editable.
417       * @return this fixture.
418       */
419      public JComboBoxFixture requireEditable() {
420        driver.requireEditable(target);
421        return this;
422      }
423    
424      /**
425       * Asserts that this fixture's <code>{@link JComboBox}</code> is not editable.
426       * @throws AssertionError if this fixture's <code>JComboBox</code> is editable.
427       * @return this fixture.
428       */
429      public JComboBoxFixture requireNotEditable() {
430        driver.requireNotEditable(target);
431        return this;
432      }
433    
434      /**
435       * Verifies that the <code>String</code> representation of the selected item in this fixture's
436       * <code>{@link JComboBox}</code> matches the given text.
437       * @param value the text to match. It can be a regular expression.
438       * @return this fixture.
439       * @throws AssertionError if the selected item does not match the given text.
440       * @see #cellReader(JComboBoxCellReader)
441       */
442      public JComboBoxFixture requireSelection(String value) {
443        driver.requireSelection(target, value);
444        return this;
445      }
446    
447      /**
448       * Verifies that this fixture's <code>{@link JComboBox}</code> has the expected number of items
449       * @param expected the expected number of items.
450       * @return this fixture.
451       * @throws AssertionError if the number of items in this fixture's <code>JComboBox</code> is not equal to the expected
452       * one.
453       * @since 1.2
454       */
455      public JComboBoxFixture requireItemCount(int expected) {
456        driver.requireItemCount(target, expected);
457        return this;
458      }
459    
460      /**
461       * Verifies that the <code>String</code> representation of the selected item in this fixture's
462       * <code>{@link JComboBox}</code> matches the given regular expression pattern.
463       * @param pattern the regular expression pattern to match.
464       * @return this fixture.
465       * @throws NullPointerException if the given regular expression pattern is <code>null</code>.
466       * @throws AssertionError if the selected item does not match the given regular expression pattern.
467       * @see #cellReader(JComboBoxCellReader)
468       * @since 1.2
469       */
470      public JComboBoxFixture requireSelection(Pattern pattern) {
471        driver.requireSelection(target, pattern);
472        return this;
473      }
474    
475      /**
476       * Verifies that the index of the selected item in this fixture's <code>{@link JComboBox}</code> is equal to the given
477       * value.
478       * @param index the expected selection index.
479       * @return this fixture.
480       * @throws AssertionError if the selected index is not equal to the given one.
481       * @since 1.2
482       */
483      public JComboBoxFixture requireSelection(int index) {
484        driver.requireSelection(target, index);
485        return this;
486      }
487    
488      /**
489       * Verifies that this fixture's <code>{@link JComboBox}</code> does not have any selection.
490       * @return this fixture.
491       * @throws AssertionError if this fixture's <code>JComboBox</code> has a selection.
492       */
493      public JComboBoxFixture requireNoSelection() {
494        driver.requireNoSelection(target);
495        return this;
496      }
497    
498      /**
499       * Asserts that the toolTip in this fixture's <code>{@link JComboBox}</code> matches the given value.
500       * @param expected the given value. It can be a regular expression.
501       * @return this fixture.
502       * @throws AssertionError if the toolTip in this fixture's <code>JComboBox</code> does not match the given value.
503       * @since 1.2
504       */
505      public JComboBoxFixture requireToolTip(String expected) {
506        driver.requireToolTip(target, expected);
507        return this;
508      }
509    
510      /**
511       * Asserts that the toolTip in this fixture's <code>{@link JComboBox}</code> matches the given regular expression
512       * pattern.
513       * @param pattern the regular expression pattern to match.
514       * @return this fixture.
515       * @throws NullPointerException if the given regular expression pattern is <code>null</code>.
516       * @throws AssertionError if the toolTip in this fixture's <code>JComboBox</code> does not match the given regular
517       * expression pattern.
518       * @since 1.2
519       */
520      public JComboBoxFixture requireToolTip(Pattern pattern) {
521        driver.requireToolTip(target, pattern);
522        return this;
523      }
524    
525      /**
526       * Returns the client property stored in this fixture's <code>{@link JComboBox}</code>, under the given key.
527       * @param key the key to use to retrieve the client property.
528       * @return the value of the client property stored under the given key, or <code>null</code> if the property was
529       * not found.
530       * @throws NullPointerException if the given key is <code>null</code>.
531       * @since 1.2
532       */
533      public Object clientProperty(Object key) {
534        return driver.clientProperty(target, key);
535      }
536    
537      /**
538       * Shows a pop-up menu using this fixture's <code>{@link JComboBox}</code> as the invoker of the pop-up menu.
539       * @return a fixture that manages the displayed pop-up menu.
540       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is disabled.
541       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is not showing on the screen.
542       * @throws ComponentLookupException if a pop-up menu cannot be found.
543       */
544      public JPopupMenuFixture showPopupMenu() {
545        return new JPopupMenuFixture(robot, driver.invokePopupMenu(target));
546      }
547    
548      /**
549       * Shows a pop-up menu at the given point using this fixture's <code>{@link JComboBox}</code> as the invoker of the
550       * pop-up menu.
551       * @param p the given point where to show the pop-up menu.
552       * @return a fixture that manages the displayed pop-up menu.
553       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is disabled.
554       * @throws IllegalStateException if this fixture's <code>JComboBox</code> is not showing on the screen.
555       * @throws ComponentLookupException if a pop-up menu cannot be found.
556       */
557      public JPopupMenuFixture showPopupMenuAt(Point p) {
558        return new JPopupMenuFixture(robot, driver.invokePopupMenu(target, p));
559      }
560    
561      /**
562       * Updates the implementation of <code>{@link JComboBoxCellReader}</code> to use when comparing internal values
563       * of this fixture's <code>{@link JComboBox}</code> and the values expected in a test. The default implementation to
564       * use is <code>{@link BasicJComboBoxCellReader}</code>.
565       * @param cellReader the new <code>JComboBoxCellValueReader</code> to use.
566       * @return this fixture.
567       * @throws NullPointerException if <code>cellReader</code> is <code>null</code>.
568       */
569      public JComboBoxFixture cellReader(JComboBoxCellReader cellReader) {
570        driver.cellReader(cellReader);
571        return this;
572      }
573    }