1
1
package io .github .slimefun .e2etester .framework ;
2
2
3
+ import java .lang .annotation .Annotation ;
4
+ import java .lang .reflect .InvocationTargetException ;
3
5
import java .lang .reflect .Method ;
4
6
import java .util .ArrayList ;
5
7
import java .util .HashMap ;
6
8
import java .util .LinkedHashMap ;
7
9
import java .util .List ;
8
10
import java .util .Map ;
9
11
import java .util .Set ;
12
+ import java .util .concurrent .CountDownLatch ;
13
+ import java .util .concurrent .ExecutorService ;
14
+ import java .util .concurrent .Executors ;
15
+ import java .util .concurrent .atomic .AtomicBoolean ;
10
16
import java .util .function .Consumer ;
11
17
import java .util .stream .Collectors ;
12
18
13
19
import javax .annotation .Nonnull ;
14
20
21
+ import io .github .slimefun .e2etester .E2ETester ;
15
22
import org .bukkit .Bukkit ;
16
23
import org .reflections .Reflections ;
17
24
import org .reflections .scanners .Scanners ;
24
31
public class TestFramework {
25
32
26
33
private final Map <String , ArrayList <Consumer <Void >>> eventListeners = new HashMap <>();
34
+ private final ExecutorService service = Executors .newSingleThreadExecutor ();
27
35
28
36
private int testsRan ;
29
37
private int testsPassed ;
@@ -41,63 +49,89 @@ public void runTests(@Nonnull String packageName) {
41
49
// TODO: Remove
42
50
new Startup ();
43
51
44
- // Reflection go through all classes
45
- Reflections reflections = new Reflections (ConfigurationBuilder
46
- .build ()
47
- .addScanners (Scanners .values ())
48
- .forPackage (packageName , getClass ().getClassLoader ())
49
- );
50
-
51
- logMessage ("Running tests..." );
52
- logMessage ("" );
53
-
54
- final Set <Method > testMethods = reflections .get (Scanners .MethodsAnnotated .with (E2ETest .class ).as (Method .class ));
55
- final Map <Class <?>, List <Method >> tests = orderTests (testMethods );
56
- for (Map .Entry <Class <?>, List <Method >> entry : tests .entrySet ()) {
57
- logMessage ("%s:" , entry .getKey ().getName ());
58
-
59
- for (Method method : entry .getValue ()) {
60
- String description = method .getAnnotation (E2ETest .class ).description ();
61
-
62
- // Invoke
63
- try {
64
- testsRan ++;
65
-
66
- method .setAccessible (true );
67
- Object instance = method .getDeclaringClass ().getDeclaredConstructor ().newInstance ();
68
- method .invoke (instance );
69
-
70
- testsPassed ++;
71
- logMessage (" ✔ %s" , description );
72
- } catch (TestFailException e ) {
73
- testsFailed ++;
74
- logMessage (" x %s" , description );
75
- e .printStackTrace ();
76
- } catch (Exception e ) {
77
- testsFailed ++;
78
- logMessage (" x %s" , description );
79
- e .printStackTrace ();
52
+ service .submit (() -> {
53
+ // Reflection go through all classes
54
+ Reflections reflections = new Reflections (ConfigurationBuilder
55
+ .build ()
56
+ .addScanners (Scanners .values ())
57
+ .forPackage (packageName , getClass ().getClassLoader ())
58
+ );
59
+
60
+ logMessage ("Running tests..." );
61
+ logMessage ("" );
62
+
63
+ final Set <Method > testMethods = reflections .get (Scanners .MethodsAnnotated .with (E2ETest .class ).as (Method .class ));
64
+ final Map <Class <?>, List <Method >> tests = orderTests (testMethods );
65
+ for (Map .Entry <Class <?>, List <Method >> entry : tests .entrySet ()) {
66
+ logMessage ("%s:" , entry .getKey ().getName ());
67
+
68
+ for (Method method : entry .getValue ()) {
69
+ E2ETest annotation = method .getAnnotation (E2ETest .class );
70
+ String description = annotation .description ();
71
+ boolean threadSafe = annotation .threadSafe ();
72
+
73
+ CountDownLatch latch = new CountDownLatch (1 );
74
+ AtomicBoolean failed = new AtomicBoolean (false );
75
+
76
+ // Invoke
77
+ try {
78
+ testsRan ++;
79
+ method .setAccessible (true );
80
+ Object instance = method .getDeclaringClass ().getDeclaredConstructor ().newInstance ();
81
+ if (threadSafe ) {
82
+ method .invoke (instance );
83
+ } else {
84
+ Bukkit .getScheduler ().runTask (E2ETester .getInstance (), () -> {
85
+ try {
86
+ method .invoke (instance );
87
+ latch .countDown ();
88
+ } catch (IllegalAccessException | InvocationTargetException e ) {
89
+ latch .countDown ();
90
+ if (e .getCause () instanceof TestFailException ) {
91
+ failed .set (true );
92
+ e .printStackTrace ();
93
+ }
94
+ }
95
+ });
96
+ latch .await ();
97
+ }
98
+ if (failed .get ()) {
99
+ testsFailed ++;
100
+ logMessage (" x %s" , description );
101
+ } else {
102
+ testsPassed ++;
103
+ logMessage (" ✔ %s" , description );
104
+ }
105
+ } catch (TestFailException e ) {
106
+ testsFailed ++;
107
+ logMessage (" x %s" , description );
108
+ e .printStackTrace ();
109
+ } catch (Exception e ) {
110
+ testsFailed ++;
111
+ logMessage (" x %s" , description );
112
+ e .printStackTrace ();
113
+ }
80
114
}
81
115
}
82
- }
83
-
84
- logMessage ("" );
85
- logMessage ("Test results:" );
86
- logMessage (" Tests ran: %d" , this .testsRan );
87
- logMessage (" Tests passed: %d" , this .testsPassed );
88
- logMessage (" Tests failed: %d" , this .testsFailed );
89
- logMessage (" Tests skipped: %d" , this .testsSkipped );
90
116
91
- if (this .testsFailed > 0 ) {
92
- logMessage ("Test failure, exiting with code 1" );
93
- System .exit (1 );
94
- } else {
95
- Bukkit .shutdown ();
96
- }
117
+ logMessage ("" );
118
+ logMessage ("Test results:" );
119
+ logMessage (" Tests ran: %d" , this .testsRan );
120
+ logMessage (" Tests passed: %d" , this .testsPassed );
121
+ logMessage (" Tests failed: %d" , this .testsFailed );
122
+ logMessage (" Tests skipped: %d" , this .testsSkipped );
123
+
124
+ if (this .testsFailed > 0 ) {
125
+ logMessage ("Test failure, exiting with code 1" );
126
+ System .exit (1 );
127
+ } else {
128
+ Bukkit .getScheduler ().runTask (E2ETester .getInstance (), Bukkit ::shutdown );
129
+ }
130
+ });
97
131
}
98
132
99
133
public void on (@ Nonnull String event , Consumer <Void > consumer ) {
100
- eventListeners .putIfAbsent (event , new ArrayList <Consumer < Void > >());
134
+ eventListeners .putIfAbsent (event , new ArrayList <>());
101
135
102
136
ArrayList <Consumer <Void >> value = eventListeners .get (event );
103
137
if (value != null ) {
@@ -146,7 +180,7 @@ private Map<Class<?>, List<Method>> orderTests(Set<Method> methods) {
146
180
return tests .entrySet ().stream ()
147
181
.sorted ((entry1 , entry2 ) -> entry1 .getKey ().getName ().compareTo (entry2 .getKey ().getName ()))
148
182
.collect (Collectors .toMap (
149
- entry -> entry . getKey () ,
183
+ Map . Entry :: getKey ,
150
184
value -> value .getValue ().stream ()
151
185
.sorted ((method1 , method2 ) -> method1 .getName ().compareTo (method2 .getName ()))
152
186
.toList ()
0 commit comments