79
79
import static javax .swing .SwingUtilities .isEventDispatchThread ;
80
80
81
81
/**
82
- * Provides a framework for manual tests to display test instructions and
83
- * Pass/Fail buttons.
82
+ * A framework for manual tests to display test instructions and
83
+ * <i>Pass</i> / <i>Fail</i> buttons. The framework automatically
84
+ * creates a frame to display the instructions, provides buttons
85
+ * to select the test result, and handles test timeout.
86
+ *
87
+ * <p id="timeOutTimer">
88
+ * The instruction UI frame displays a timer at the top which indicates
89
+ * how much time is left. The timer can be paused using the <i>Pause</i>
90
+ * button to the right of the time; the title of the button changes to
91
+ * <i>Resume</i>. To resume the timer, use the <i>Resume</i> button.
92
+ *
93
+ * <p id="instructionText">
94
+ * In the center, the instruction UI frame displays instructions for the
95
+ * tester. The instructions can be either plain text or HTML. If the
96
+ * text of the instructions starts with {@code "<html>"}, the
97
+ * instructions are displayed as HTML, as supported by Swing, which
98
+ * provides richer formatting options.
99
+ * <p>
100
+ * The instructions are displayed in a text component with word-wrapping
101
+ * so that there's no horizontal scroll bar. If the text doesn't fit, a
102
+ * vertical scroll bar is shown. Use {@code rows} and {@code columns}
103
+ * parameters to change the size of this text component.
104
+ * If possible, choose the number of rows and columns so that
105
+ * the instructions fit and no scroll bars are shown.
106
+ *
107
+ * <p id="passFailButtons">
108
+ * At the bottom, the instruction UI frame displays the
109
+ * <i>Pass</i> and <i>Fail</i> buttons. The tester clicks either <i>Pass</i>
110
+ * or <i>Fail</i> button to finish the test. When the tester clicks the
111
+ * <i>Fail</i> button, the framework displays a dialog box prompting for
112
+ * a reason why the test fails. The tester enters the reason and clicks
113
+ * <i>OK</i> to close the dialog and fail the test,
114
+ * or simply closes the dialog to fail the test without providing any reason.
115
+ *
116
+ * <p id="screenCapture">
117
+ * If you enable the screenshot feature, a <i>Screenshot</i> button is
118
+ * added to the right of the <i>Fail</i> button. The tester can choose either
119
+ * <i>Capture Full Screen</i> (default) or <i>Capture Frames</i> and click the
120
+ * <i>Screenshot</i> button to take a screenshot.
121
+ * If there are multiple screens, screenshots of each screen are created.
122
+ * If the tester selects the <i>Capture Frames</i> mode, screenshots of all
123
+ * the windows or frames registered in the {@code PassFailJFrame} framework
124
+ * are created.
125
+ *
126
+ * <p id="logArea">
127
+ * If you enable a log area, the instruction UI frame adds a text component
128
+ * to display log messages below the buttons.
129
+ * Use {@link #log(String) log}, {@link #logSet(String) logSet}
130
+ * and {@link #logClear() logClear} static methods of {@code PassFailJFrame}
131
+ * to add or clear messages from the log area.
132
+ *
133
+ * <p id="awaitTestResult">
134
+ * After you create an instance of {@code PassFailJFrame}, call the
135
+ * {@link #awaitAndCheck() awaitAndCheck} method to stop the current thread
136
+ * (usually the main thread) and wait until the tester clicks
137
+ * either <i>Pass</i> or <i>Fail</i> button,
138
+ * or until the test times out.
84
139
* <p>
85
- * Instructions for the user can be either plain text or HTML as supported
86
- * by Swing. If the instructions start with {@code <html>}, the
87
- * instructions are displayed as HTML.
140
+ * The call to the {@code awaitAndCheck} method is usually the last
141
+ * statement in the {@code main} method of your test.
142
+ * If the test fails, an exception is thrown to signal the failure to jtreg.
143
+ * The test fails if the tester clicks the <i>Fail</i> button,
144
+ * if the timeout occurs,
145
+ * or if any window or frame is closed.
88
146
* <p>
147
+ * Before returning from {@code awaitAndCheck}, the framework disposes of
148
+ * all the windows and frames.
149
+ *
150
+ * <h2 id="sampleManualTest">Sample Manual Test</h2>
89
151
* A simple test would look like this:
90
- * <pre>{@code
152
+ * {@snippet id='sampleManualTestCode' lang='java':
91
153
* public class SampleManualTest {
92
154
* private static final String INSTRUCTIONS =
93
155
* "Click Pass, or click Fail if the test failed.";
94
156
*
95
157
* public static void main(String[] args) throws Exception {
96
158
* PassFailJFrame.builder()
97
159
* .instructions(INSTRUCTIONS)
98
- * .testUI(() -> createTestUI() )
160
+ * .testUI(SampleManualTest:: createTestUI)
99
161
* .build()
100
162
* .awaitAndCheck();
101
163
* }
106
168
* return testUI;
107
169
* }
108
170
* }
109
- * }</pre>
171
+ * }
110
172
* <p>
111
- * The above example uses the {@link Builder Builder} to set the parameters of
112
- * the instruction frame. It is the recommended way.
173
+ * The above example uses the {@link Builder Builder} class to set
174
+ * the parameters of the instruction frame.
175
+ * It is <em>the recommended way</em>.
176
+ *
113
177
* <p>
114
- * The framework will create instruction UI, it will call
115
- * the provided {@code createTestUI} on the Event Dispatch Thread (EDT),
116
- * and it will automatically position the test UI and make it visible.
178
+ * The framework will create an instruction UI frame, it will call
179
+ * the provided {@code createTestUI} on the Event Dispatch Thread (<dfn>EDT</dfn>),
180
+ * and it will automatically position the test UI frame and make it visible.
181
+ *
182
+ * <p id="jtregTagsForTest">
183
+ * Add the following jtreg tags before the test class declaration
184
+ * {@snippet :
185
+ * /*
186
+ * * @test
187
+ * * @summary Sample manual test
188
+ * * @library /java/awt/regtesthelpers
189
+ * * @build PassFailJFrame
190
+ * * @run main/manual SampleManualTest
191
+ * }
192
+ * and the closing comment tag <code>*/</code>.
117
193
* <p>
194
+ * The {@code @library} tag points to the location of the
195
+ * {@code PassFailJFrame} class in the source code;
196
+ * the {@code @build} tag makes jtreg compile the {@code PassFailJFrame} class,
197
+ * and finally the {@code @run} tag specifies it is a manual
198
+ * test and the class to run.
199
+ *
200
+ * <h2 id="usingBuilder">Using {@code Builder}</h2>
201
+ * Use methods of the {@link Builder Builder} class to set or change
202
+ * parameters of {@code PassFailJFrame} and its instruction UI:
203
+ * <ul>
204
+ * <li>{@link Builder#title(String) title} sets
205
+ * the title of the instruction UI
206
+ * (the default is {@value #TITLE});</li>
207
+ * <li>{@link Builder#testTimeOut(long) testTimeOut} sets
208
+ * the timeout of the test
209
+ * (the default is {@value #TEST_TIMEOUT});</li>
210
+ * <li>{@link Builder#rows(int) rows} and
211
+ * {@link Builder#columns(int) columns} control the size
212
+ * the text component which displays the instructions
213
+ * (the default number of rows is the number of lines in the text
214
+ * of the instructions,
215
+ * the default number of columns is {@value #COLUMNS});</li>
216
+ * <li>{@link Builder#logArea() logArea} adds a log area;</li>
217
+ * <li>{@link Builder#screenCapture() screenCapture}
218
+ * enables screenshots.</li>
219
+ * </ul>
220
+ *
221
+ * <h3 id="builderTestUI">Using {@code testUI} and {@code splitUI}</h3>
118
222
* The {@code Builder.testUI} methods accept interfaces which create one window
119
223
* or a list of windows if the test needs multiple windows,
120
224
* or directly a single window, an array of windows or a list of windows.
121
225
* <p>
122
- * For simple test UI, use {@code Builder.splitUI}, or explicitly
123
- * {@code Builder.splitUIRight} or {@code Builder.splitUIBottom} with
124
- * a {@code PanelCreator}. The framework will call the provided
125
- * {@code createUIPanel} to create the component with test UI and
226
+ * For simple test UI, use {@link Builder#splitUI(PanelCreator) splitUI},
227
+ * or explicitly
228
+ * {@link Builder#splitUIRight(PanelCreator) splitUIRight} or
229
+ * {@link Builder#splitUIBottom(PanelCreator) splitUIBottom} with
230
+ * a {@link PanelCreator PanelCreator}.
231
+ * The framework will call the provided
232
+ * {@code createUIPanel} method to create the component with test UI and
126
233
* will place it as the right or bottom component in a split pane
127
234
* along with instruction UI.
128
235
* <p>
236
+ * Note: <em>support for multiple windows is incomplete</em>.
237
+ *
238
+ * <h2 id="obsoleteSampleTest">Obsolete Sample Test</h2>
129
239
* Alternatively, use one of the {@code PassFailJFrame} constructors to
130
240
* create an object, then create secondary test UI, register it
131
241
* with {@code PassFailJFrame}, position it and make it visible.
132
242
* The following sample demonstrates it:
133
- * <pre>{@code
134
- * public class SampleOldManualTest {
243
+ * {@snippet id='obsoleteSampleTestCode' lang='java':
244
+ * public class ObsoleteManualTest {
135
245
* private static final String INSTRUCTIONS =
136
246
* "Click Pass, or click Fail if the test failed.";
137
247
*
138
248
* public static void main(String[] args) throws Exception {
139
249
* PassFailJFrame passFail = new PassFailJFrame(INSTRUCTIONS);
140
250
*
141
- * SwingUtilities.invokeAndWait(() -> createTestUI() );
251
+ * SwingUtilities.invokeAndWait(ObsoleteManualTest:: createTestUI);
142
252
*
143
253
* passFail.awaitAndCheck();
144
254
* }
151
261
* testUI.setVisible(true);
152
262
* }
153
263
* }
154
- * }</pre>
264
+ * }
155
265
* <p>
156
- * Use methods of the {@code Builder} class or constructors of the
157
- * {@code PassFailJFrame} class to control other parameters:
158
- * <ul>
159
- * <li>the title of the instruction UI,</li>
160
- * <li>the timeout of the test,</li>
161
- * <li>the size of the instruction UI via rows and columns, and</li>
162
- * <li>to add a log area,</li>
163
- * <li>to enable screenshots.</li>
164
- * </ul>
266
+ * This sample uses {@link #PassFailJFrame(String) a constructor} of
267
+ * {@code PassFailJFrame} to create its instance,
268
+ * there are several overloads provided which allow changing other parameters.
269
+ * <p>
270
+ * When you use the constructors, you have to explicitly create
271
+ * your test UI window on EDT. After you create the window,
272
+ * you need to register it with the framework using
273
+ * {@link #addTestWindow(Window) addTestWindow}
274
+ * to ensure the window is disposed of when the test completes.
275
+ * Before showing the window, you have to call
276
+ * {@link #positionTestWindow(Window, Position) positionTestWindow}
277
+ * to position the test window near the instruction UI frame provided
278
+ * by the framework. And finally you have to explicitly show the test UI
279
+ * window by calling {@code setVisible(true)}.
280
+ * <p>
281
+ * To avoid the complexity, use the {@link Builder Builder} class
282
+ * which provides a streamlined way to configure and create an
283
+ * instance of {@code PassFailJFrame}.
284
+ * <p>
285
+ * Consider updating tests which use {@code PassFailJFrame} constructors to
286
+ * use the builder pattern.
165
287
*/
166
288
public final class PassFailJFrame {
167
289
@@ -541,7 +663,11 @@ private static JComponent createInstructionUIPanel(String instructions,
541
663
: configurePlainText (instructions , rows , columns );
542
664
text .setEditable (false );
543
665
544
- main .add (new JScrollPane (text ), BorderLayout .CENTER );
666
+ JPanel textPanel = new JPanel (new BorderLayout ());
667
+ textPanel .setBorder (createEmptyBorder (4 , 0 , 0 , 0 ));
668
+ textPanel .add (new JScrollPane (text ), BorderLayout .CENTER );
669
+
670
+ main .add (textPanel , BorderLayout .CENTER );
545
671
546
672
JButton btnPass = new JButton ("Pass" );
547
673
btnPass .addActionListener ((e ) -> {
@@ -822,7 +948,7 @@ public void windowClosing(WindowEvent e) {
822
948
private static JComponent createCapturePanel () {
823
949
JComboBox <CaptureType > screenShortType = new JComboBox <>(CaptureType .values ());
824
950
825
- JButton capture = new JButton ("ScreenShot " );
951
+ JButton capture = new JButton ("Screenshot " );
826
952
capture .addActionListener ((e ) ->
827
953
captureScreen ((CaptureType ) screenShortType .getSelectedItem ()));
828
954
@@ -834,7 +960,7 @@ private static JComponent createCapturePanel() {
834
960
835
961
private enum CaptureType {
836
962
FULL_SCREEN ("Capture Full Screen" ),
837
- WINDOWS ("Capture Individual Frame " );
963
+ WINDOWS ("Capture Frames " );
838
964
839
965
private final String type ;
840
966
CaptureType (String type ) {
0 commit comments