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 }