001    /*
002     * Created on Feb 27, 2008
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 @2008-2010 the original author or authors.
015     */
016    package org.fest.swing.driver;
017    
018    import static javax.swing.JOptionPane.*;
019    import static org.fest.assertions.Assertions.assertThat;
020    import static org.fest.swing.driver.JOptionPaneMessageQuery.messageOf;
021    import static org.fest.swing.driver.JOptionPaneMessageTypeQuery.messageTypeOf;
022    import static org.fest.swing.driver.JOptionPaneMessageTypes.messageTypeAsText;
023    import static org.fest.swing.driver.JOptionPaneOptionsQuery.optionsOf;
024    import static org.fest.swing.driver.JOptionPaneTitleQuery.titleOf;
025    import static org.fest.swing.driver.TextAssert.verifyThat;
026    
027    import java.util.regex.Pattern;
028    
029    import javax.swing.*;
030    import javax.swing.text.JTextComponent;
031    
032    import org.fest.assertions.Description;
033    import org.fest.swing.annotation.RunsInEDT;
034    import org.fest.swing.core.Robot;
035    import org.fest.swing.core.matcher.JButtonMatcher;
036    import org.fest.swing.exception.ComponentLookupException;
037    
038    /**
039     * Understands functional testing of <code>{@link JOptionPane}</code>s:
040     * <ul>
041     * <li>user input simulation</li>
042     * <li>state verification</li>
043     * <li>property value query</li>
044     * </ul>
045     * This class is intended for internal use only. Please use the classes in the package
046     * <code>{@link org.fest.swing.fixture}</code> in your tests.
047     *
048     * @author Alex Ruiz
049     */
050    public class JOptionPaneDriver extends JComponentDriver {
051    
052      private static final String MESSAGE_PROPERTY = "message";
053      private static final String MESSAGE_TYPE_PROPERTY = "messageType";
054      private static final String OPTIONS_PROPERTY = "options";
055      private static final String TITLE_PROPERTY = "title";
056    
057      /**
058       * Creates a new </code>{@link JOptionPaneDriver}</code>.
059       * @param robot the robot to use to simulate user input.
060       */
061      public JOptionPaneDriver(Robot robot) {
062        super(robot);
063      }
064    
065      /**
066       * Asserts that the title in the given <code>{@link JOptionPane}</code> matches the given value.
067       * @param optionPane the target {@code JOptionPane}.
068       * @param title the title to match. It can be a regular expression.
069       * @throws AssertionError if the {@code JOptionPane} does not have the given title.
070       */
071      @RunsInEDT
072      public void requireTitle(JOptionPane optionPane, String title) {
073        verifyThat(title(optionPane)).as(propertyName(optionPane, TITLE_PROPERTY)).isEqualOrMatches(title);
074      }
075    
076      /**
077       * Asserts that the title in the given <code>{@link JOptionPane}</code> matches the given regular expression pattern.
078       * @param optionPane the target {@code JOptionPane}.
079       * @param pattern the regular expression pattern to match.
080       * @throws NullPointerException if the given regular expression pattern is <code>null</code>.
081       * @throws AssertionError if the {@code JOptionPane} does not have the given title.
082       * @since 1.2
083       */
084      @RunsInEDT
085      public void requireTitle(JOptionPane optionPane, Pattern pattern) {
086        verifyThat(title(optionPane)).as(propertyName(optionPane, TITLE_PROPERTY)).matches(pattern);
087      }
088    
089    
090      /**
091       * Returns the title of the given <code>{@link JOptionPane}</code>.
092       * @param optionPane the target {@code JOptionPane}.
093       * @return the title of the given {@code JOptionPane}.
094       * @since 1.2
095       */
096      @RunsInEDT
097      public String title(JOptionPane optionPane) {
098        return titleOf(optionPane);
099      }
100    
101      /**
102       * Asserts that the title of the <code>{@link JOptionPane}</code> matches the given value. If the given value is a
103       * regular expression and the message in the {@code JOptionPane} is not a <code>String</code>, this method will use the
104       * <code>toString</code> representation of such message.
105       * message in the {@code JOptionPane} is not a <code>String</code>, this method will use the
106       * <code>toString</code> representation of such message.
107       * @param optionPane the target {@code JOptionPane}.
108       * @param message the message to verify. If it is a <code>String</code>, it can be specified as a regular expression.
109       * @throws AssertionError if the message in the {@code JOptionPane} is not equal to or does not match the given
110       * message.
111       */
112      @RunsInEDT
113      public void requireMessage(JOptionPane optionPane, Object message) {
114        Object actual = messageOf(optionPane);
115        if (message instanceof String) {
116          requireMessage(optionPane, (String)message, toStringOf(actual));
117          return;
118        }
119        assertThat(actual).as(messageProperty(optionPane)).isEqualTo(message);
120      }
121    
122      @RunsInEDT
123      private void requireMessage(JOptionPane optionPane, String expected, String actual) {
124        verifyThat(actual).as(messageProperty(optionPane)).isEqualOrMatches(expected);
125      }
126    
127      /**
128       * Asserts that the title of the <code>{@link JOptionPane}</code> matches the given regular expression pattern. If the
129       * message in the {@code JOptionPane} is not a <code>String</code>, this method will use the
130       * <code>toString</code> representation of such message.
131       * @param optionPane the target {@code JOptionPane}.
132       * @param pattern the regular expression to match.
133       * @throws NullPointerException if the given regular expression pattern is <code>null</code>.
134       * @throws AssertionError if the message in the </code>JOptionPaneFixture</code> does not match the given regular
135       * expression pattern.
136       * @since 1.2
137       */
138      @RunsInEDT
139      public void requireMessage(JOptionPane optionPane, Pattern pattern) {
140        Object actual = messageOf(optionPane);
141        verifyThat(toStringOf(actual)).as(messageProperty(optionPane)).matches(pattern);
142      }
143    
144      private String toStringOf(Object o) {
145        return (o == null) ? null : o.toString();
146      }
147    
148      private Description messageProperty(JOptionPane optionPane) {
149        return propertyName(optionPane, MESSAGE_PROPERTY);
150      }
151    
152      /**
153       * Asserts that the <code>{@link JOptionPane}</code> has the given options.
154       * @param optionPane the target {@code JOptionPane}.
155       * @param options the options to verify.
156       * @throws AssertionError if the {@code JOptionPane} does not have the given options.
157       */
158      @RunsInEDT
159      public void requireOptions(JOptionPane optionPane, Object[] options) {
160        assertThat(optionsOf(optionPane)).as(propertyName(optionPane, OPTIONS_PROPERTY)).isEqualTo(options);
161      }
162    
163      /**
164       * Finds the "OK" button in the <code>{@link JOptionPane}</code>. This method is independent of locale and platform.
165       * @param optionPane the target {@code JOptionPane}.
166       * @return the "OK" button.
167       * @throws ComponentLookupException if the a "OK" button cannot be found.
168       */
169      @RunsInEDT
170      public JButton okButton(JOptionPane optionPane) {
171        return buttonWithTextFromUIManager(optionPane, "OptionPane.okButtonText");
172      }
173    
174      /**
175       * Finds the "Cancel" button in the <code>{@link JOptionPane}</code>. This method is independent of locale and
176       * platform.
177       * @param optionPane the target {@code JOptionPane}.
178       * @return the "Cancel" button.
179       * @throws ComponentLookupException if the a "Cancel" button cannot be found.
180       */
181      @RunsInEDT
182      public JButton cancelButton(JOptionPane optionPane) {
183        return buttonWithTextFromUIManager(optionPane, "OptionPane.cancelButtonText");
184      }
185    
186      /**
187       * Finds the "Yes" button in the <code>{@link JOptionPane}</code>. This method is independent of locale and platform.
188       * @param optionPane the target {@code JOptionPane}.
189       * @return the "Yes" button.
190       * @throws ComponentLookupException if the a "Yes" button cannot be found.
191       */
192      @RunsInEDT
193      public JButton yesButton(JOptionPane optionPane) {
194        return buttonWithTextFromUIManager(optionPane, "OptionPane.yesButtonText");
195      }
196    
197      /**
198       * Finds the "No" button in the <code>{@link JOptionPane}</code>.  This method is independent of locale and platform.
199       * @param optionPane the target {@code JOptionPane}.
200       * @return the "No" button.
201       * @throws ComponentLookupException if the a "No" button cannot be found.
202       */
203      @RunsInEDT
204      public JButton noButton(JOptionPane optionPane) {
205        return buttonWithTextFromUIManager(optionPane, "OptionPane.noButtonText");
206      }
207    
208      @RunsInEDT
209      private JButton buttonWithTextFromUIManager(JOptionPane optionPane, String key) {
210        return buttonWithText(optionPane, UIManager.getString(key));
211      }
212    
213      /**
214       * Finds a button in the <code>{@link JOptionPane}</code> containing the given text.
215       * @param optionPane the target {@code JOptionPane}.
216       * @param text the text of the button to find and return. It can be a regular expression.
217       * @return a button containing the given text.
218       * @throws ComponentLookupException if the a button with the given text cannot be found.
219       */
220      @RunsInEDT
221      public JButton buttonWithText(JOptionPane optionPane, String text) {
222        return robot.finder().find(optionPane, JButtonMatcher.withText(text).andShowing());
223      }
224    
225      /**
226       * Finds a button in the <code>{@link JOptionPane}</code> whose text matches the given regular expression pattern.
227       * @param optionPane the target {@code JOptionPane}.
228       * @param pattern the regular expression pattern to match.
229       * @return a button containing the given text.
230       * @throws NullPointerException if the given regular expression pattern is <code>null</code>.
231       * @throws ComponentLookupException if the a button with the given text cannot be found.
232       * @since 1.2
233       */
234      @RunsInEDT
235      public JButton buttonWithText(JOptionPane optionPane, Pattern pattern) {
236        return robot.finder().find(optionPane, JButtonMatcher.withText(pattern).andShowing());
237      }
238    
239      /**
240       * Finds a <code>{@link JButton}</code> in the <code>{@link JOptionPane}</code> (assuming it has only one button.)
241       * @param optionPane the target {@code JOptionPane}.
242       * @return the only <code>JButton</code> contained in the {@code JOptionPane}.
243       * @throws ComponentLookupException if a matching component could not be found.
244       * @throws ComponentLookupException if more than one matching component is found.
245       * @deprecated in 1.2
246       */
247      @RunsInEDT
248      @Deprecated public JButton button(JOptionPane optionPane) {
249        return robot.finder().findByType(optionPane, JButton.class);
250      }
251    
252      /**
253       * Returns the <code>{@link JTextComponent}</code> in the given message only if the message is of type input.
254       * @param optionPane the target {@code JOptionPane}.
255       * @return the text component in the given message.
256       * @throws ComponentLookupException if the message type is not input and therefore it does not contain a text component.
257       * @deprecated in 1.2
258       */
259      @RunsInEDT
260      @Deprecated public JTextComponent textBox(JOptionPane optionPane) {
261        return robot.finder().findByType(optionPane, JTextComponent.class);
262      }
263    
264      /**
265       * Asserts that the <code>{@link JOptionPane}</code> is displaying an error message.
266       * @param optionPane the target {@code JOptionPane}.
267       */
268      @RunsInEDT
269      public void requireErrorMessage(JOptionPane optionPane) {
270        assertEqualMessageType(optionPane, ERROR_MESSAGE);
271      }
272    
273      /**
274       * Asserts that the <code>{@link JOptionPane}</code> is displaying an information message.
275       * @param optionPane the target {@code JOptionPane}.
276       */
277      @RunsInEDT
278      public void requireInformationMessage(JOptionPane optionPane) {
279        assertEqualMessageType(optionPane, INFORMATION_MESSAGE);
280      }
281    
282      /**
283       * Asserts that the <code>{@link JOptionPane}</code> is displaying a warning message.
284       * @param optionPane the target {@code JOptionPane}.
285       */
286      @RunsInEDT
287      public void requireWarningMessage(JOptionPane optionPane) {
288        assertEqualMessageType(optionPane, WARNING_MESSAGE);
289      }
290    
291      /**
292       * Asserts that the <code>{@link JOptionPane}</code> is displaying a question.
293       * @param optionPane the target {@code JOptionPane}.
294       */
295      @RunsInEDT
296      public void requireQuestionMessage(JOptionPane optionPane) {
297        assertEqualMessageType(optionPane, QUESTION_MESSAGE);
298      }
299    
300      /**
301       * Asserts that the <code>{@link JOptionPane}</code> is displaying a plain message.
302       * @param optionPane the target {@code JOptionPane}.
303       */
304      @RunsInEDT
305      public void requirePlainMessage(JOptionPane optionPane) {
306        assertEqualMessageType(optionPane, PLAIN_MESSAGE);
307      }
308    
309      @RunsInEDT
310      private void assertEqualMessageType(JOptionPane optionPane, int expected) {
311        String actualType = actualMessageTypeAsText(optionPane);
312        assertThat(actualType).as(propertyName(optionPane, MESSAGE_TYPE_PROPERTY)).isEqualTo(messageTypeAsText(expected));
313      }
314    
315      @RunsInEDT
316      private String actualMessageTypeAsText(final JOptionPane optionPane) {
317        return messageTypeAsText(messageTypeOf(optionPane));
318      }
319    }