8315726: Open source several AWT applet tests

Reviewed-by: psadhukhan, aivanov
This commit is contained in:
Alexander Zvegintsev 2023-09-13 22:23:27 +00:00
parent 92ad4a2399
commit 1741d13b12
4 changed files with 849 additions and 0 deletions

View File

@ -0,0 +1,174 @@
/*
* Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.Choice;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Panel;
/*
* @test
* @bug 4115139 4128213
* @summary Tests that the (rather bizarre) rules for handling selection
* in Choice components are implemented as documented in
* "The Java Class Libraries 2nd Edition"
* @key headful
*/
public class ChoiceSelectTest extends Panel {
final Choice c;
public ChoiceSelectTest() {
setLayout(new FlowLayout());
c = new Choice();
add(c);
}
private void test() {
testAddition();
testInsertion();
testRemoval();
testIndices();
}
public void testAddition() {
c.removeAll();
// check that after first item added selection is zero
c.addItem("zero");
if (c.getSelectedIndex() != 0) {
throw new SelectionException("selection wrong after first add");
}
// check that selection doesn't change for subsequent adds
c.addItem("one");
c.select(1);
c.addItem("two");
if (c.getSelectedIndex() != 1) {
throw new SelectionException("selection wrong after subsequent add");
}
}
public void testInsertion() {
c.removeAll();
// check that after first item inserted selection is zero
c.insert("zero", 0);
if (c.getSelectedIndex() != 0) {
throw new SelectionException("selection wrong after first insert");
}
// check that if selected item shifted, selection goes to zero
c.insert("three", 1);
c.select(1);
c.insert("one", 1);
if (c.getSelectedIndex() != 0) {
throw new SelectionException("selection wrong after selected item shifted");
}
// check that if selected item not shifted, selection stays the same
c.select(1);
c.insert("two", 2);
if (c.getSelectedIndex() != 1) {
throw new SelectionException("selection wrong after item inserted after selection");
}
}
public void testRemoval() {
c.removeAll();
// check that if removing selected item, selection goes to 0
c.add("zero");
c.add("one");
c.add("two");
c.select(2);
c.remove(2);
if (c.getSelectedIndex() != 0) {
throw new SelectionException("selection wrong after removing selected item");
}
// check that if removing item before the selection
// the selected index is updated
c.add("two");
c.add("three");
c.select(3);
c.remove(1);
if (c.getSelectedIndex() != 2) {
throw new SelectionException("selection wrong after removing item before it");
}
}
public void testIndices() {
c.removeAll();
c.addItem("zero");
c.addItem("one");
c.addItem("two");
c.addItem("three");
c.addItem("four");
c.addItem("five");
// Test selection of negative index
try {
c.select(-1);
throw new SelectionException("Negative Index Test FAILED");
} catch (IllegalArgumentException expected) {}
// Test selection of zero index
try {
c.select(0);
} catch (IllegalArgumentException iae) {
throw new SelectionException("Zero Index Test FAILED", iae);
}
// Test selection of maximum index
try {
c.select(5);
} catch (IllegalArgumentException iae) {
throw new SelectionException("Maximum Index Test FAILED", iae);
}
// Test selection of index that is too large
try {
c.select(6);
throw new SelectionException("Greater than Maximum Index Test FAILED");
} catch (IllegalArgumentException expected) {}
}
public static void main(String[] args) throws Exception {
EventQueue.invokeAndWait(() -> new ChoiceSelectTest().test());
}
class SelectionException extends RuntimeException {
SelectionException(String msg, Throwable cause) {
super(msg, cause);
System.out.println(
"Selection item is '" + c.getSelectedItem() +
"' at index " + c.getSelectedIndex());
}
SelectionException(String msg) {
this(msg, null);
}
}
}

View File

@ -0,0 +1,156 @@
/*
* Copyright (c) 1998, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Label;
import java.awt.Panel;
/*
* @test
* @key headful
* @summary automated test for "displayable" property on Component
*/
public class Displayable extends Panel {
Label status = new Label("Displayable Test started...");
public void init() {
setLayout(new BorderLayout());
add("South", status);
LightDisplayable light = new LightDisplayable();
shouldNotBeDisplayable(light, "before added to container ");
HeavyDisplayable heavy = new HeavyDisplayable();
shouldNotBeDisplayable(heavy, "before added to container ");
add("West", light);
add("East", heavy);
statusMessage("Displayable test completed successfully.");
}
protected void addImpl(Component child, Object constraints, int index) {
super.addImpl(child, constraints, index);
if (isDisplayable()) {
shouldBeDisplayable(child, "after added to displayable container ");
} else {
shouldNotBeDisplayable(child, "after added to undisplayable container ");
}
}
public void remove(Component child) {
super.remove(child);
shouldNotBeDisplayable(child, "after removed from displayable container ");
}
public void statusMessage(String msg) {
status.setText(msg);
status.invalidate();
validate();
}
public static void shouldNotBeDisplayable(Component c, String why) {
if (c.isDisplayable()) {
throw new RuntimeException("Component is displayable "+why+c.getName());
}
}
public static void shouldBeDisplayable(Component c, String why) {
if (!c.isDisplayable()) {
throw new RuntimeException("Component is NOT displayable "+why+c.getName());
}
}
public static void main(String[] args) throws Exception {
EventQueue.invokeAndWait(() -> {
Frame f = new Frame();
try {
Displayable test = new Displayable();
test.init();
f.add("North", test);
f.pack();
} finally {
f.dispose();
}
});
}
}
class LightDisplayable extends Component {
public Dimension getPreferredSize() {
return new Dimension(50,50);
}
public void paint(Graphics g) {
Dimension size = getSize();
g.setColor(Color.blue);
g.fillRect(0, 0, size.width, size.height);
super.paint(g);
}
public void addNotify() {
Displayable.shouldNotBeDisplayable(this, "before addNotify ");
super.addNotify();
Displayable.shouldBeDisplayable(this, "after addNotify ");
}
public void removeNotify() {
Displayable.shouldBeDisplayable(this, "before removeNotify ");
super.removeNotify();
Displayable.shouldNotBeDisplayable(this, "after removeNotify ");
}
}
class HeavyDisplayable extends Panel {
public Dimension getPreferredSize() {
return new Dimension(50, 50);
}
public void paint(Graphics g) {
Dimension size = getSize();
g.setColor(Color.black);
g.fillRect(0, 0, size.width, size.height);
super.paint(g);
}
public void addNotify() {
Displayable.shouldNotBeDisplayable(this, "before addNotify ");
super.addNotify();
Displayable.shouldBeDisplayable(this, "after addNotify ");
}
public void removeNotify() {
Displayable.shouldBeDisplayable(this, "before removeNotify ");
super.removeNotify();
Displayable.shouldNotBeDisplayable(this, "after removeNotify ");
}
}

View File

@ -0,0 +1,127 @@
/*
* Copyright (c) 2002, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Robot;
import java.awt.event.InputEvent;
/*
* @test
* @bug 4749659
* @summary Tests that popup menu doesn't steal focus from top-level
* @key headful
*/
public class TestWindowsLFFocus {
static volatile boolean actionFired;
static JFrame frame;
static JMenuBar bar;
static JMenuItem item;
static volatile Point frameLoc;
public static void main(String[] args) throws Exception {
for (UIManager.LookAndFeelInfo lookAndFeel : UIManager.getInstalledLookAndFeels()) {
UIManager.setLookAndFeel(lookAndFeel.getClassName());
test();
}
System.err.println("PASSED");
}
private static void test() throws Exception {
try {
SwingUtilities.invokeAndWait(() -> {
actionFired = false;
frame = new JFrame();
bar = new JMenuBar();
frame.setJMenuBar(bar);
JMenu menu = new JMenu("menu");
bar.add(menu);
item = new JMenuItem("item");
menu.add(item);
item.addActionListener(e -> actionFired = true);
frame.getContentPane().add(new JButton("none"));
frame.setBounds(100, 100, 100, 100);
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.setVisible(true);
});
Robot robot = new Robot();
robot.setAutoWaitForIdle(true);
robot.setAutoDelay(50);
robot.waitForIdle();
robot.delay(1000);
SwingUtilities.invokeAndWait(() -> {
Point location = frame.getLocationOnScreen();
Insets insets = frame.getInsets();
location.translate(insets.left + 15, insets.top + bar.getHeight() / 2);
frameLoc = location;
});
robot.mouseMove(frameLoc.x, frameLoc.y);
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
robot.delay(1000);
SwingUtilities.invokeAndWait(() -> {
Point location = new Point(frameLoc);
location.y += bar.getHeight() / 2 + item.getHeight() / 2;
frameLoc = location;
});
robot.mouseMove(frameLoc.x, frameLoc.y);
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
robot.waitForIdle();
robot.delay(500);
if (!actionFired) {
throw new RuntimeException("Menu closed without action");
}
} finally {
SwingUtilities.invokeAndWait(() -> {
if (frame != null) {
frame.dispose();
}
});
}
}
}

View File

@ -0,0 +1,392 @@
/*
* Copyright (c) 1999, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Choice;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Panel;
import java.awt.Polygon;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
/*
* @test
* @bug 4210936 4214524
* @summary Tests the results of the hit test methods on 3 different
* Shape objects - Polygon, Area, and GeneralPath. Both an
* automatic test for constraint compliance and a manual
* test for correctness are included in this one class.
* @library /java/awt/regtesthelpers
* @build PassFailJFrame
* @run main PathHitTest
*/
/*
* @test
* @bug 4210936 4214524
* @summary Tests the results of the hit test methods on 3 different
* Shape objects - Polygon, Area, and GeneralPath. Both an
* automatic test for constraint compliance and a manual
* test for correctness are included in this one class.
* @library /java/awt/regtesthelpers
* @build PassFailJFrame
* @run main/manual PathHitTest manual
*/
public class PathHitTest {
public static final int BOXSIZE = 5;
public static final int BOXCENTER = 2;
public static final int TESTSIZE = 400;
public static final int NUMTESTS = (TESTSIZE + BOXSIZE - 1) / BOXSIZE;
public static Shape[] testShapes = new Shape[5];
public static String[] testNames = {
"Polygon",
"EvenOdd GeneralPath",
"NonZero GeneralPath",
"Area from EO GeneralPath",
"Area from NZ GeneralPath",
};
static {
GeneralPath gpeo = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
Ellipse2D ell = new Ellipse2D.Float();
Point2D center = new Point2D.Float();
AffineTransform at = new AffineTransform();
for (int i = 0; i < 360; i += 30) {
center.setLocation(100, 0);
at.setToTranslation(200, 200);
at.rotate(i * Math.PI / 180);
at.transform(center, center);
ell.setFrame(center.getX() - 50, center.getY() - 50, 100, 100);
gpeo.append(ell, false);
}
GeneralPath side = new GeneralPath();
side.moveTo(0, 0);
side.lineTo(15, 10);
side.lineTo(30, 0);
side.lineTo(45, -10);
side.lineTo(60, 0);
append4sides(gpeo, side, 20, 20);
side.reset();
side.moveTo(0, 0);
side.quadTo(15, 10, 30, 0);
side.quadTo(45, -10, 60, 0);
append4sides(gpeo, side, 320, 20);
side.reset();
side.moveTo(0, 0);
side.curveTo(15, 10, 45, -10, 60, 0);
append4sides(gpeo, side, 20, 320);
GeneralPath gpnz = new GeneralPath(GeneralPath.WIND_NON_ZERO);
gpnz.append(gpeo, false);
Polygon p = new Polygon();
p.addPoint( 50, 50);
p.addPoint( 60, 350);
p.addPoint(250, 340);
p.addPoint(260, 150);
p.addPoint(140, 140);
p.addPoint(150, 260);
p.addPoint(340, 250);
p.addPoint(350, 60);
testShapes[0] = p;
testShapes[1] = gpeo;
testShapes[2] = gpnz;
testShapes[3] = new Area(gpeo);
testShapes[3].getPathIterator(null);
testShapes[4] = new Area(gpnz);
testShapes[4].getPathIterator(null);
}
private static void append4sides(GeneralPath path, GeneralPath side,
double xoff, double yoff) {
AffineTransform at = new AffineTransform();
at.setToTranslation(xoff, yoff);
for (int i = 0; i < 4; i++) {
path.append(side.getPathIterator(at), i != 0);
at.rotate(Math.toRadians(90), 30, 30);
}
}
public static void main(String[] argv) throws Exception {
if (argv.length > 0 && argv[0].equals("manual")) {
PathHitTestManual.doManual();
} else {
int totalerrs = 0;
for (int i = 0; i < testShapes.length; i++) {
totalerrs += testshape(testShapes[i], testNames[i]);
}
if (totalerrs != 0) {
throw new RuntimeException(totalerrs +
" constraint conditions violated!");
}
}
}
public static int testshape(Shape s, String name) {
int numerrs = 0;
long start = System.currentTimeMillis();
for (int y = 0; y < TESTSIZE; y += BOXSIZE) {
for (int x = 0; x < TESTSIZE; x += BOXSIZE) {
boolean rectintersects = s.intersects(x, y, BOXSIZE, BOXSIZE);
boolean rectcontains = s.contains(x, y, BOXSIZE, BOXSIZE);
boolean pointcontains = s.contains(x + BOXCENTER, y + BOXCENTER);
if (rectcontains && !rectintersects) {
System.err.println("rect is contained " +
"but does not intersect!");
numerrs++;
}
if (rectcontains && !pointcontains) {
System.err.println("rect is contained " +
"but center is not contained!");
numerrs++;
}
if (pointcontains && !rectintersects) {
System.err.println("center is contained " +
"but rect does not intersect!");
numerrs++;
}
}
}
long end = System.currentTimeMillis();
System.out.println(name + " completed in " +
(end - start) + "ms with " +
numerrs + " errors");
return numerrs;
}
static class PathHitTestManual extends Panel {
private static final String INSTRUCTIONS = """
This test displays the results of hit testing 5 different Shape
objects one at a time.
You can switch between shapes using the Choice component located
at the bottom of the window.
Each square in the test represents the
return values of the hit testing operators for that square region:
yellow - not yet tested
translucent blue overlay - the shape being tested
black - all outside
dark gray - rectangle intersects shape
light gray - rectangle intersects and center point is inside shape
white - rectangle is entirely contained in shape
red - some constraint was violated, including:
rectangle is contained, but center point is not
rectangle is contained, but rectangle.intersects is false
centerpoint is contained, but rectangle.intersects is false
Visually inspect the results to see if they match the above table.
Note that it is not a violation for rectangles that are entirely
inside the path to be light gray instead of white since sometimes
the path is complex enough to make an exact determination expensive.
You might see this on the GeneralPath NonZero example where the
circles that make up the path cross over the interior of the shape
and cause the hit testing methods to guess that the rectangle is
not guaranteed to be contained within the shape.
""";
PathHitTestCanvas phtc;
public void init() {
setLayout(new BorderLayout());
phtc = new PathHitTestCanvas();
add("Center", phtc);
final Choice ch = new Choice();
for (int i = 0; i < PathHitTest.testNames.length; i++) {
ch.add(PathHitTest.testNames[i]);
}
ch.addItemListener(e -> phtc.setShape(ch.getSelectedIndex()));
ch.select(0);
phtc.setShape(0);
add("South", ch);
}
public void start() {
phtc.start();
}
public void stop() {
phtc.stop();
}
public static class PathHitTestCanvas extends Canvas implements Runnable {
public static final Color[] colors = {
/* contains? point in? intersects? */
Color.black, /* NO NO NO */
Color.darkGray, /* NO NO YES */
Color.red, /* NO YES NO */
Color.lightGray, /* NO YES YES */
Color.red, /* YES NO NO */
Color.red, /* YES NO YES */
Color.red, /* YES YES NO */
Color.white, /* YES YES YES */
Color.yellow, /* used for untested points */
};
public Dimension getPreferredSize() {
return new Dimension(TESTSIZE, TESTSIZE);
}
public synchronized void start() {
if (!testdone) {
renderer = new Thread(this);
renderer.setPriority(Thread.MIN_PRIORITY);
renderer.start();
}
}
public synchronized void stop() {
renderer = null;
}
private Thread renderer;
private int shapeIndex = 0;
private byte[] indices = new byte[NUMTESTS * NUMTESTS];
boolean testdone = false;
private synchronized void setShape(int index) {
shapeIndex = index;
testdone = false;
start();
}
public void run() {
Thread me = Thread.currentThread();
Graphics2D g2d = (Graphics2D) getGraphics();
byte[] indices;
Shape s = testShapes[shapeIndex];
synchronized (this) {
if (renderer != me) {
return;
}
this.indices = new byte[NUMTESTS * NUMTESTS];
java.util.Arrays.fill(this.indices, (byte) 8);
indices = this.indices;
}
System.err.printf("%s %s\n", g2d, Color.yellow);
g2d.setColor(Color.yellow);
g2d.fillRect(0, 0, TESTSIZE, TESTSIZE);
int numtests = 0;
long start = System.currentTimeMillis();
for (int y = 0; renderer == me && y < TESTSIZE; y += BOXSIZE) {
for (int x = 0; renderer == me && x < TESTSIZE; x += BOXSIZE) {
byte index = 0;
if (s.intersects(x, y, BOXSIZE, BOXSIZE)) {
index += 1;
}
if (s.contains(x + BOXCENTER, y + BOXCENTER)) {
index += 2;
}
if (s.contains(x, y, BOXSIZE, BOXSIZE)) {
index += 4;
}
numtests++;
int i = (y / BOXSIZE) * NUMTESTS + (x / BOXSIZE);
indices[i] = index;
g2d.setColor(colors[index]);
g2d.fillRect(x, y, BOXSIZE, BOXSIZE);
}
}
synchronized (this) {
if (renderer != me) {
return;
}
g2d.setColor(new Color(0, 0, 1, .2f));
g2d.fill(s);
testdone = true;
long end = System.currentTimeMillis();
System.out.println(numtests + " tests took " + (end - start) + "ms");
}
}
public void paint(Graphics g) {
g.setColor(Color.yellow);
g.fillRect(0, 0, TESTSIZE, TESTSIZE);
byte[] indices = this.indices;
if (indices != null) {
for (int y = 0; y < TESTSIZE; y += BOXSIZE) {
for (int x = 0; x < TESTSIZE; x += BOXSIZE) {
int i = (y / BOXSIZE) * NUMTESTS + (x / BOXSIZE);
g.setColor(colors[indices[i]]);
g.fillRect(x, y, BOXSIZE, BOXSIZE);
}
}
}
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(new Color(0, 0, 1, .2f));
g2d.fill(testShapes[shapeIndex]);
}
}
static volatile PathHitTestManual pathHitTestManual;
private static void createAndShowGUI() {
pathHitTestManual = new PathHitTestManual();
Frame frame = new Frame("PathHitTestManual test window");
frame.add(pathHitTestManual);
frame.setSize(400, 450);
PassFailJFrame.addTestWindow(frame);
PassFailJFrame.positionTestWindow(frame, PassFailJFrame.Position.HORIZONTAL);
frame.setVisible(true);
pathHitTestManual.init();
pathHitTestManual.start();
}
public static void doManual() throws Exception {
PassFailJFrame passFailJFrame = new PassFailJFrame.Builder()
.title("PathHitTestManual Instructions")
.instructions(INSTRUCTIONS)
.testTimeOut(5)
.rows(30)
.columns(70)
.screenCapture()
.build();
EventQueue.invokeAndWait(PathHitTestManual::createAndShowGUI);
try {
passFailJFrame.awaitAndCheck();
} finally {
pathHitTestManual.stop();
}
}
}
}