16
16
import static org .junit .jupiter .api .Assertions .assertEquals ;
17
17
import static org .junit .jupiter .api .Assertions .assertFalse ;
18
18
import static org .junit .jupiter .api .Assertions .assertTrue ;
19
+ import static org .junit .jupiter .api .Assertions .fail ;
19
20
20
21
import java .lang .invoke .MethodHandle ;
21
22
import java .lang .invoke .MethodHandles ;
32
33
import org .eclipse .swt .widgets .Shell ;
33
34
34
35
import org .eclipse .core .runtime .Assert ;
36
+ import org .eclipse .swtbot .swt .finder .SWTBot ;
37
+ import org .eclipse .swtbot .swt .finder .finders .UIThreadRunnable ;
35
38
import org .eclipse .zest .core .widgets .Graph ;
36
39
import org .eclipse .zest .core .widgets .GraphConnection ;
37
40
import org .eclipse .zest .core .widgets .GraphNode ;
38
- import org .eclipse .zest .core .widgets .IContainer ;
39
41
import org .eclipse .zest .core .widgets .internal .GraphLabel ;
40
42
import org .eclipse .zest .layouts .algorithms .SpringLayoutAlgorithm ;
41
43
import org .eclipse .zest .tests .examples .AbstractGraphTest .SWTBotExtension ;
42
- import org .eclipse .zest .tests .utils .GraphicalRobot ;
44
+ import org .eclipse .zest .tests .utils .ISWTBotGraphContainer ;
45
+ import org .eclipse .zest .tests .utils .SWTBotGraph ;
46
+ import org .eclipse .zest .tests .utils .SWTBotGraphConnection ;
47
+ import org .eclipse .zest .tests .utils .SWTBotGraphNode ;
43
48
import org .eclipse .zest .tests .utils .Snippet ;
44
49
45
50
import org .eclipse .draw2d .EventDispatcher ;
53
58
import org .eclipse .draw2d .geometry .Point ;
54
59
import org .eclipse .draw2d .geometry .Rectangle ;
55
60
61
+ import org .junit .jupiter .api .AfterEach ;
56
62
import org .junit .jupiter .api .extension .ExtendWith ;
57
63
import org .junit .jupiter .api .extension .ExtensionContext ;
58
64
import org .junit .jupiter .api .extension .InvocationInterceptor ;
64
70
*/
65
71
@ ExtendWith (SWTBotExtension .class )
66
72
public abstract class AbstractGraphTest {
67
- protected Graph graph ;
68
- protected GraphicalRobot robot ;
73
+ private Graph graph ;
74
+ private Shell shell ;
75
+ protected SWTBot robot ;
76
+ protected SWTBotGraph graphRobot ;
69
77
70
78
public static class SWTBotExtension implements InvocationInterceptor {
71
79
@ Override
@@ -81,6 +89,13 @@ public void interceptTestMethod(Invocation<Void> invocation,
81
89
}
82
90
}
83
91
92
+ @ AfterEach
93
+ public void tearDown () {
94
+ if (shell != null ) {
95
+ UIThreadRunnable .syncExec (shell ::dispose );
96
+ }
97
+ }
98
+
84
99
/**
85
100
* Wrapper method to handle the instantiation of the example class and the
86
101
* execution of the unit test. Each example must satisfy the following
@@ -95,6 +110,13 @@ public void interceptTestMethod(Invocation<Void> invocation,
95
110
* @throws Throwable If the example could not be instantiated.
96
111
*/
97
112
private void doTest (Snippet annotation , Invocation <Void > statement ) throws Throwable {
113
+ if (Display .getCurrent () != null ) {
114
+ fail ("""
115
+ SWTBot test needs to run in a non-UI thread.
116
+ Make sure that "Run in UI thread" is unchecked in your launch configuration or that useUIThread is set to false in the pom.xml
117
+ """ ); //$NON-NLS-1$
118
+ }
119
+
98
120
Class <?> clazz = annotation .type ();
99
121
100
122
Semaphore lock = new Semaphore (0 );
@@ -107,43 +129,48 @@ private void doTest(Snippet annotation, Invocation<Void> statement) throws Throw
107
129
// Fail early, otherwise the example might block indefinitely
108
130
Assert .isTrue (hasGraph (lookup , annotation ), "Graph object not found for " + clazz ); //$NON-NLS-1$
109
131
110
- // The actual test has to be executed asynchronously, so that it is run as part
111
- // of the readAndDispatch() call. Otherwise we end up in a deadlock, as both
112
- // snippet and test run in the UI thread.
113
- Display .getCurrent ().asyncExec (() -> {
114
- Shell shell = null ;
115
- try {
116
- graph = getGraph (lookup , annotation );
117
-
118
- // Make sure the layout is reproducible
119
- if (graph .getLayoutAlgorithm () instanceof SpringLayoutAlgorithm springLayout ) {
120
- springLayout .setRandom (annotation .random ());
132
+ // Create snippet
133
+ Display .getDefault ().asyncExec (() -> {
134
+ // Non-Blocking! Executed after the widget has been created
135
+ Display .getCurrent ().asyncExec (() -> {
136
+ try {
137
+ graph = getGraph (lookup , annotation );
138
+
139
+ // Make sure the layout is reproducible
140
+ if (graph .getLayoutAlgorithm () instanceof SpringLayoutAlgorithm springLayout ) {
141
+ springLayout .setRandom (annotation .random ());
142
+ }
143
+
144
+ graphRobot = new SWTBotGraph (graph );
145
+ shell = graph .getShell ();
146
+ robot = new SWTBot (shell );
147
+ // Wait for layout to be applied
148
+ waitEventLoop (10 );
149
+ } catch (Throwable e ) {
150
+ throwable .set (e );
151
+ } finally {
152
+ lock .release ();
121
153
}
122
-
123
- robot = new GraphicalRobot (graph );
124
- shell = graph .getShell ();
125
- // Wait for layout to be applied
126
- waitEventLoop (10 );
127
- // Run the actual test
128
- statement .proceed ();
154
+ });
155
+ // Blocking! Creates the snippet
156
+ try {
157
+ methodHandle .invoke (null );
129
158
} catch (Throwable e ) {
130
159
throwable .set (e );
131
160
} finally {
132
- // Close the snippet
133
- if (shell != null ) {
134
- shell .dispose ();
135
- }
136
161
lock .release ();
137
162
}
138
163
});
139
164
140
- methodHandle .invoke (null );
141
- // Wait for asynchronous test execution
165
+ // Wait for shell to be created
142
166
lock .acquire ();
143
167
// Propagate any errors
144
168
if (throwable .get () != null ) {
145
169
throw throwable .get ();
146
170
}
171
+
172
+ // Run the actual test
173
+ statement .proceed ();
147
174
}
148
175
149
176
/**
@@ -174,7 +201,7 @@ private void doTest(Snippet annotation, Invocation<Void> statement) throws Throw
174
201
*
175
202
* @return The Euclidean length of the given {@code connection}.
176
203
*/
177
- protected static double getLength (GraphConnection connection ) {
204
+ protected static double getLength (SWTBotGraphConnection connection ) {
178
205
Point c1 = getCenter (connection .getSource ());
179
206
Point c2 = getCenter (connection .getDestination ());
180
207
int x = c1 .x - c2 .x ;
@@ -197,7 +224,7 @@ protected static double getLength(Point vec) {
197
224
*
198
225
* @return The center of the given {@code node}.
199
226
*/
200
- protected static Point getCenter (GraphNode node ) {
227
+ protected static Point getCenter (SWTBotGraphNode node ) {
201
228
Point location = node .getLocation ();
202
229
Dimension size = node .getSize ();
203
230
return new Rectangle (location , size ).getCenter ();
@@ -264,28 +291,29 @@ protected static void assertConnection(GraphConnection connection, String source
264
291
* Asserts that the given {@code connection} uses a {@link PolylineConnection}
265
292
* with given {@code curveDepth}.
266
293
*
267
- * @param connection The graph connection to validate.
294
+ * @param bot The graph connection to validate.
268
295
* @param curveDepth The expected curveDepth of the connection
269
296
*/
270
- protected static void assertCurve (GraphConnection connection , int curveDepth ) throws ReflectiveOperationException {
297
+ protected static void assertCurve (SWTBotGraphConnection bot , int curveDepth ) throws ReflectiveOperationException {
298
+ GraphConnection connection = bot .widget ;
271
299
MethodHandles .Lookup lookup = MethodHandles .privateLookupIn (connection .getClass (), MethodHandles .lookup ());
272
300
VarHandle field = lookup .findVarHandle (connection .getClass (), "curveDepth" , int .class ); //$NON-NLS-1$
273
301
assertEquals (curveDepth , field .get (connection ), "Unexpected connection curve" ); //$NON-NLS-1$
274
302
}
275
303
276
304
/**
277
- * Asserts that no graph nodes in the given {@link IContainer} intersect with
278
- * one another. This method doesn't check nested containers.
305
+ * Asserts that no graph nodes in the given {@link ISWTBotGraphContainer}
306
+ * intersect with one another. This method doesn't check nested containers.
279
307
*
280
- * @param container The {@link IContainer } to validate.
308
+ * @param container The {@link ISWTBotGraphContainer } to validate.
281
309
*/
282
- protected static void assertNoOverlap (IContainer container ) {
283
- List <? extends GraphNode > nodes = container .getNodes ();
310
+ protected static void assertNoOverlap (ISWTBotGraphContainer container ) {
311
+ List <SWTBotGraphNode > nodes = container .getNodes ();
284
312
for (int i = 0 ; i < nodes .size (); ++i ) {
285
313
for (int j = i + 1 ; j < nodes .size (); ++j ) {
286
- GraphNode node1 = nodes .get (i );
314
+ SWTBotGraphNode node1 = nodes .get (i );
287
315
Rectangle bounds1 = new Rectangle (node1 .getLocation (), node1 .getSize ());
288
- GraphNode node2 = nodes .get (j );
316
+ SWTBotGraphNode node2 = nodes .get (j );
289
317
Rectangle bounds2 = new Rectangle (node2 .getLocation (), node2 .getSize ());
290
318
assertFalse (bounds1 .intersects (bounds2 ));
291
319
}
@@ -307,7 +335,7 @@ protected static void assertInstanceOf(Object object, Class<?> clazz) {
307
335
* Pumps the event loop for the given number of milliseconds. At least one
308
336
* events loop will be executed.
309
337
*/
310
- protected static void waitEventLoop (int time ) {
338
+ private static void waitEventLoop (int time ) {
311
339
long start = System .currentTimeMillis ();
312
340
do {
313
341
while (Display .getCurrent ().readAndDispatch ()) {
0 commit comments