22
22
*/
23
23
package org .jemmy2ext ;
24
24
25
+ import java .awt .AWTException ;
25
26
import java .awt .Component ;
26
27
import java .awt .EventQueue ;
27
28
import java .awt .Frame ;
28
29
import java .awt .Graphics ;
29
30
import java .awt .Rectangle ;
30
31
import java .awt .Robot ;
32
+ import java .awt .Toolkit ;
31
33
import java .awt .Window ;
32
34
import java .awt .image .BufferedImage ;
33
35
import java .io .BufferedOutputStream ;
36
38
import java .io .FileOutputStream ;
37
39
import java .io .IOException ;
38
40
import java .lang .reflect .InvocationTargetException ;
41
+ import java .text .DateFormat ;
42
+ import java .text .SimpleDateFormat ;
39
43
import java .util .ArrayList ;
40
44
import java .util .Collections ;
45
+ import java .util .Date ;
41
46
import java .util .List ;
42
47
import java .util .function .Function ;
43
48
import java .util .function .Supplier ;
83
88
*/
84
89
public class JemmyExt {
85
90
91
+ private static Robot robot = null ;
92
+
93
+ public static Robot getRobot () {
94
+ try {
95
+ if (robot == null ) {
96
+ robot = new Robot ();
97
+ }
98
+ return robot ;
99
+ } catch (AWTException e ) {
100
+ throw new RuntimeException (e );
101
+ }
102
+ }
103
+
86
104
/**
87
105
* Statically referencing all the classes that are needed by tests so that
88
106
* they're compiled by jtreg
@@ -151,78 +169,62 @@ public Boolean launch() throws Exception {
151
169
});
152
170
}
153
171
154
- public static void assertEquals (String string , StrictImageComparator comparator , BufferedImage expected , BufferedImage actual ) {
155
- try {
156
- assertTrue (string , comparator .compare (expected , actual ));
157
- } catch (Error err ) {
158
- save (expected , "expected.png" );
159
- save (actual , "actual.png" );
160
- throw err ;
161
- }
172
+ private static final DateFormat timestampFormat = new SimpleDateFormat ("yyyyMMddHHmmss" );
173
+ private static String timeStamp () {
174
+ return timestampFormat .format (new Date ());
162
175
}
163
176
164
- public static void assertNotEquals (String string , StrictImageComparator comparator , BufferedImage notExpected , BufferedImage actual ) {
165
- try {
166
- assertFalse (string , comparator .compare (notExpected , actual ));
167
- } catch (Error err ) {
168
- save (notExpected , "notExpected.png" );
169
- save (actual , "actual.png" );
170
- throw err ;
171
- }
177
+ /**
178
+ * Constructs filename with a timestamp.
179
+ * @param name File name or a path without the extension
180
+ * @param extension File extension (without the dot). Could be null,
181
+ * in which case timestamp is simply added to the filename (no trailing dot).
182
+ * @return file name
183
+ */
184
+ public static String timeStamp (String name , String extension ) {
185
+ return name + "-" + timeStamp () +
186
+ ((extension != null ) ? ("." + extension ) : "" );
187
+ }
188
+
189
+ /**
190
+ * Saves an image into a file. Filename will be constructed from the given fileID and
191
+ * a timestamp.
192
+ * @param image
193
+ * @param fileID
194
+ */
195
+ public static void save (BufferedImage image , String fileID ) {
196
+ doSave (image , timeStamp (fileID + "-" + lafShortName (), "png" ));
172
197
}
173
198
174
- public static void save ( BufferedImage image , String filename ) {
175
- String filepath = filename ;
199
+ //Saves an image into a file with the provided filename
200
+ private static void doSave ( BufferedImage image , String filename ) {
176
201
try {
177
- filepath = new File (filename ).getCanonicalPath ();
202
+ String filepath = new File (filename ).getCanonicalPath ();
178
203
System .out .println ("Saving screenshot to " + filepath );
179
204
BufferedOutputStream file = new BufferedOutputStream (new FileOutputStream (filepath ));
180
205
new PNGEncoder (file , PNGEncoder .COLOR_MODE ).encode (image );
181
206
} catch (IOException ioe ) {
182
- throw new RuntimeException ("Failed to save image to " + filepath , ioe );
207
+ throw new RuntimeException ("Failed to save image to " + filename , ioe );
183
208
}
184
209
}
185
210
186
- /**
187
- * Waits for a screen area taken by a component to not be completely black rectangle.
188
- * @return last (non-black) image
189
- * @throws TimeoutExpiredException if the waiting is unsuccessful
190
- */
191
- public static BufferedImage waitNotBlack (Robot rob , ComponentOperator operator , String imageName ) {
192
- class NonBlackImageChooser implements ComponentChooser {
193
- private BufferedImage image = null ;
194
- @ Override
195
- public boolean checkComponent (Component comp ) {
196
- image = capture (rob , operator );
197
- save (image , imageName );
198
- return !isBlack (image );
199
- }
200
-
201
- @ Override
202
- public String getDescription () {
203
- return "A non-black Image of " + operator ;
204
- }
205
- }
206
- NonBlackImageChooser chooser = new NonBlackImageChooser ();
207
- operator .waitState (chooser );
208
- return chooser .image ;
209
- }
210
-
211
211
/**
212
212
* Waits for the displayed image to be still.
213
+ * @param imageID an image ID with no extension. Timestamp and LAF information is added to the ID when saving.
213
214
* @return last still image
214
215
* @throws TimeoutExpiredException if the waiting is unsuccessful
215
216
*/
216
- public static BufferedImage waitStillImage (Robot rob , ComponentOperator operator , String imageName ) {
217
+ public static BufferedImage waitStillImage (ComponentOperator operator , String imageID ) {
217
218
operator .getTimeouts ().setTimeout ("Waiter.TimeDelta" , 1000 );
219
+ String timestampName = timeStamp (imageID + "-" + lafShortName (), "png" );
218
220
class StillImageChooser implements ComponentChooser {
219
221
private BufferedImage previousImage = null ;
220
222
private final StrictImageComparator sComparator = new StrictImageComparator ();
221
223
222
224
@ Override
223
225
public boolean checkComponent (Component comp ) {
224
- BufferedImage currentImage = capture (rob , operator );
225
- save (currentImage , imageName );
226
+ BufferedImage currentImage = capture (operator );
227
+ doSave (currentImage , timestampName );
226
228
boolean compareResult = previousImage == null ? false : sComparator .compare (currentImage , previousImage );
227
229
previousImage = currentImage ;
228
230
return compareResult ;
@@ -241,22 +243,23 @@ public String getDescription() {
241
243
/**
242
244
* Waits for the displayed image to change.
243
245
* @param reference image to compare to
246
+ * @param imageID an image ID with no extension. Timestamp and LAF information is added to the ID when saving.
244
247
* @return last (changed) image
245
248
* @throws TimeoutExpiredException if the waiting is unsuccessful
246
249
*/
247
- public static BufferedImage waitChangedImage (Robot rob ,
248
- Supplier <BufferedImage > supplier ,
250
+ public static BufferedImage waitChangedImage (Supplier <BufferedImage > supplier ,
249
251
BufferedImage reference ,
250
252
Timeouts timeouts ,
251
- String imageName ) throws InterruptedException {
253
+ String imageID ) throws InterruptedException {
252
254
ImageComparator comparator = new StrictImageComparator ();
255
+ String timestampName = timeStamp (imageID + "-" + lafShortName (), "png" );
253
256
class ImageWaitable implements Waitable {
254
257
BufferedImage image ;
255
258
256
259
@ Override
257
260
public Object actionProduced (Object obj ) {
258
261
image = supplier .get ();
259
- save (image , imageName );
262
+ doSave (image , timestampName );
260
263
return comparator .compare (reference , image ) ? null : image ;
261
264
}
262
265
@@ -316,10 +319,10 @@ public String getDescription() {
316
319
}
317
320
}
318
321
319
- public static BufferedImage capture (Robot rob , ComponentOperator operator ) {
322
+ public static BufferedImage capture (ComponentOperator operator ) {
320
323
Rectangle boundary = new Rectangle (operator .getLocationOnScreen (),
321
324
operator .getSize ());
322
- return rob .createScreenCapture (boundary );
325
+ return getRobot () .createScreenCapture (boundary );
323
326
}
324
327
325
328
/**
@@ -400,26 +403,26 @@ public void registerRoot(Throwable t) {
400
403
}
401
404
}
402
405
406
+ private static String lafShortName () { return UIManager .getLookAndFeel ().getClass ().getSimpleName (); }
407
+
403
408
/**
404
409
* Trying to capture as much information as possible. Currently it includes
405
410
* full dump and a screenshot of the whole screen.
406
411
*/
407
412
public static void captureAll () {
408
- String lookAndFeelClassName = UIManager .getLookAndFeel ().getClass ().getSimpleName ();
409
- PNGEncoder .captureScreen ("failure_" + lookAndFeelClassName + ".png" , PNGEncoder .COLOR_MODE );
413
+ save (getRobot ().createScreenCapture (new Rectangle (Toolkit .getDefaultToolkit ().getScreenSize ())), "failure" );
410
414
try {
411
- Dumper .dumpAll ("dumpAll_ " + lookAndFeelClassName + ". xml" );
415
+ Dumper .dumpAll (timeStamp ( "dumpAll- " + lafShortName (), " xml") );
412
416
} catch (FileNotFoundException ex ) {
413
417
Logger .getLogger (JemmyExt .class .getName ()).log (Level .SEVERE , null , ex );
414
418
}
415
- captureWindows (lookAndFeelClassName );
419
+ captureWindows ();
416
420
}
417
421
418
422
/**
419
423
* Captures each showing window image using Window.paint() method.
420
- * @param lookAndFeelClassName
421
424
*/
422
- private static void captureWindows (String lookAndFeelClassName ) {
425
+ private static void captureWindows () {
423
426
try {
424
427
EventQueue .invokeAndWait (() -> {
425
428
Window [] windows = Window .getWindows ();
@@ -434,10 +437,14 @@ private static void captureWindows(String lookAndFeelClassName) {
434
437
g .dispose ();
435
438
436
439
try {
437
- ImageIO .write (img , "png" , new File ("window_" + lookAndFeelClassName
438
- + "_" + index ++ + ".png" ));
439
- } catch (IOException e ) {
440
- e .printStackTrace ();
440
+ save (img , "window-" + index ++);
441
+ } catch (RuntimeException e ) {
442
+ if (e .getCause () instanceof IOException ) {
443
+ System .err .println ("Failed to save screen images" );
444
+ e .printStackTrace ();
445
+ } else {
446
+ throw e ;
447
+ }
441
448
}
442
449
}
443
450
});
0 commit comments