1
+ /*
2
+ * Copyright 2024 the original author or authors.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ * https://www.apache.org/licenses/LICENSE-2.0
8
+ * Unless required by applicable law or agreed to in writing, software
9
+ * distributed under the License is distributed on an "AS IS" BASIS,
10
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ * See the License for the specific language governing permissions and
12
+ * limitations under the License.
13
+ *
14
+ */
15
+
1
16
package org .spockframework .runtime .extension .builtin ;
2
17
3
18
import org .codehaus .groovy .runtime .ResourceGroovyMethods ;
8
23
import org .spockframework .runtime .model .FieldInfo ;
9
24
import org .spockframework .runtime .model .ParameterInfo ;
10
25
import org .spockframework .util .*;
26
+ import spock .lang .TempDir ;
11
27
12
28
import java .io .File ;
13
29
import java .io .IOException ;
17
33
import java .nio .file .Path ;
18
34
import java .nio .file .SimpleFileVisitor ;
19
35
import java .nio .file .attribute .BasicFileAttributes ;
36
+ import java .util .Objects ;
20
37
import java .util .regex .Pattern ;
21
38
22
39
import static java .nio .file .FileVisitResult .CONTINUE ;
23
- import static org .spockframework .runtime .model .MethodInfo .MISSING_ARGUMENT ;
24
40
25
41
/**
26
42
* @author dqyuan
@@ -36,18 +52,21 @@ public class TempDirInterceptor implements IMethodInterceptor {
36
52
private final IThrowableBiConsumer <IMethodInvocation , Path , Exception > valueSetter ;
37
53
private final String name ;
38
54
private final Path parentDir ;
39
- private final boolean keep ;
55
+ private final TempDir annotation ;
56
+ private final TempDir .CleanupMode cleanupMode ;
40
57
41
58
private TempDirInterceptor (
42
59
IThrowableBiConsumer <IMethodInvocation , Path , Exception > valueSetter ,
43
60
String name ,
44
61
Path parentDir ,
45
- boolean keep ) {
62
+ TempDir annotation ,
63
+ TempDir .CleanupMode cleanupMode ) {
46
64
47
65
this .valueSetter = valueSetter ;
48
66
this .name = name ;
49
67
this .parentDir = parentDir ;
50
- this .keep = keep ;
68
+ this .annotation = annotation ;
69
+ this .cleanupMode = cleanupMode ;
51
70
}
52
71
53
72
private String dirPrefix (IMethodInvocation invocation ) {
@@ -88,7 +107,9 @@ protected Path setUp(IMethodInvocation invocation) throws Exception {
88
107
@ Override
89
108
public void intercept (IMethodInvocation invocation ) throws Throwable {
90
109
Path path = setUp (invocation );
91
- invocation .getStore (NAMESPACE ).put (path , new TempDirContainer (path , keep ));
110
+ // not super thrilled about identityHashCode, but apparently annotations use field equality and not identity
111
+ TempDirContainer old = invocation .getStore (NAMESPACE ).put (System .identityHashCode (annotation ), new TempDirContainer (path , cleanupMode ));
112
+ Checks .checkState (old == null , () -> "Replaced other value: " + old .path );
92
113
invocation .proceed ();
93
114
}
94
115
@@ -149,44 +170,87 @@ public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
149
170
}
150
171
}
151
172
152
- static TempDirInterceptor forField (FieldInfo fieldInfo , Path parentDir , boolean keep ) {
173
+ static TempDirInterceptor forField (FieldInfo fieldInfo , Path parentDir , TempDir annotation , TempDir . CleanupMode cleanupMode ) {
153
174
IThrowableFunction <Path , ?, Exception > typeMapper = createPathToTypeMapper (fieldInfo .getType ());
154
175
return new TempDirInterceptor (
155
176
(invocation , path ) -> fieldInfo .writeValue (invocation .getInstance (), typeMapper .apply (path )),
156
177
fieldInfo .getName (),
157
178
parentDir ,
158
- keep );
179
+ annotation ,
180
+ cleanupMode );
159
181
}
160
182
161
- static TempDirInterceptor forParameter (ParameterInfo parameterInfo , Path parentDir , boolean keep ) {
183
+ static TempDirInterceptor forParameter (ParameterInfo parameterInfo , Path parentDir , TempDir annotation , TempDir . CleanupMode cleanupMode ) {
162
184
IThrowableFunction <Path , ?, Exception > typeMapper = createPathToTypeMapper (parameterInfo .getReflection ().getType ());
163
185
return new TempDirInterceptor (
164
186
(IMethodInvocation invocation , Path path ) -> {
165
187
invocation .resolveArgument (parameterInfo .getIndex (), typeMapper .apply (path ));
166
188
},
167
189
parameterInfo .getName (),
168
190
parentDir ,
169
- keep );
191
+ annotation ,
192
+ cleanupMode );
193
+ }
194
+
195
+ static class FailureTracker implements IMethodInterceptor {
196
+ private final TempDir annotation ;
197
+
198
+ FailureTracker (TempDir annotation ) {
199
+ this .annotation = annotation ;
200
+ }
201
+
202
+ @ Override
203
+ public void intercept (IMethodInvocation invocation ) throws Throwable {
204
+ TempDirContainer tempDirContainer = invocation .getStore (NAMESPACE ).get (System .identityHashCode (annotation ), TempDirContainer .class );
205
+ try {
206
+ invocation .proceed ();
207
+ } catch (Throwable t ) {
208
+ tempDirContainer .markFailed ();
209
+ throw t ;
210
+ }
211
+ }
170
212
}
171
213
172
214
static class TempDirContainer implements AutoCloseable {
173
215
private final Path path ;
174
- private final boolean keep ;
216
+ private final TempDir .CleanupMode cleanupMode ;
217
+ private volatile boolean failed = false ;
175
218
176
- TempDirContainer (Path path , boolean keep ) {
219
+ TempDirContainer (Path path , TempDir . CleanupMode cleanupMode ) {
177
220
this .path = path ;
178
- this .keep = keep ;
221
+ this .cleanupMode = cleanupMode ;
222
+ }
223
+
224
+ void markFailed () {
225
+ failed = true ;
226
+ }
227
+
228
+ private void destroy (Path path ) throws IOException {
229
+ switch (cleanupMode ) {
230
+ case ON_SUCCESS :
231
+ if (failed ) {
232
+ System .err .printf ("TempDir '%s' not deleted because the test failed, please delete it manually after investigation.%n" ,
233
+ path .toAbsolutePath ());
234
+ return ;
235
+ }
236
+ case ALWAYS :
237
+ case DEFAULT :
238
+ deleteTempDir (path );
239
+ break ;
240
+ case NEVER :
241
+ break ;
242
+ default :
243
+ throw new IllegalStateException ("Unknown cleanup mode: " + cleanupMode );
244
+ }
179
245
}
180
246
181
247
@ Override
182
248
public void close () {
183
- if (!keep ) {
184
249
try {
185
- deleteTempDir (path );
250
+ destroy (path );
186
251
} catch (IOException e ) {
187
252
ExceptionUtil .sneakyThrow (e );
188
253
}
189
- }
190
254
}
191
255
}
192
256
}
0 commit comments