1010
1111package org .junit .jupiter .engine .extension ;
1212
13+ import static com .google .common .jimfs .Configuration .unix ;
14+ import static java .lang .annotation .ElementType .METHOD ;
15+ import static java .lang .annotation .RetentionPolicy .RUNTIME ;
1316import static java .nio .file .Files .createDirectory ;
1417import static java .nio .file .Files .createFile ;
1518import static java .nio .file .Files .createSymbolicLink ;
1821import static java .nio .file .Files .deleteIfExists ;
1922import static org .assertj .core .api .Assertions .assertThat ;
2023import static org .assertj .core .api .Assertions .assertThatExceptionOfType ;
24+ import static org .junit .jupiter .api .condition .OS .WINDOWS ;
2125import static org .junit .jupiter .api .io .CleanupMode .ALWAYS ;
2226import static org .junit .jupiter .api .io .CleanupMode .DEFAULT ;
2327import static org .junit .jupiter .api .io .CleanupMode .NEVER ;
2428import static org .junit .jupiter .api .io .CleanupMode .ON_SUCCESS ;
2529import static org .mockito .ArgumentMatchers .any ;
2630import static org .mockito .Mockito .mock ;
31+ import static org .mockito .Mockito .reset ;
2732import static org .mockito .Mockito .spy ;
2833import static org .mockito .Mockito .verify ;
2934import static org .mockito .Mockito .when ;
3035
36+ import java .io .File ;
3137import java .io .IOException ;
38+ import java .lang .annotation .Retention ;
39+ import java .lang .annotation .Target ;
40+ import java .nio .file .FileSystem ;
3241import java .nio .file .Path ;
3342import java .util .Optional ;
3443
44+ import com .google .common .jimfs .Jimfs ;
45+
3546import org .assertj .core .api .ThrowableAssert .ThrowingCallable ;
3647import org .junit .jupiter .api .AfterEach ;
3748import org .junit .jupiter .api .BeforeEach ;
3849import org .junit .jupiter .api .DisplayName ;
3950import org .junit .jupiter .api .Nested ;
4051import org .junit .jupiter .api .Test ;
4152import org .junit .jupiter .api .condition .DisabledOnOs ;
42- import org .junit .jupiter .api .condition .OS ;
4353import org .junit .jupiter .api .extension .AnnotatedElementContext ;
4454import org .junit .jupiter .api .extension .ExtensionConfigurationException ;
4555import org .junit .jupiter .api .extension .ExtensionContext ;
4959import org .junit .jupiter .api .io .TempDirFactory ;
5060import org .junit .jupiter .engine .AbstractJupiterTestEngineTests ;
5161import org .junit .jupiter .engine .execution .NamespaceAwareStore ;
62+ import org .junit .jupiter .params .ParameterizedTest ;
63+ import org .junit .jupiter .params .provider .ValueSource ;
5264import org .junit .platform .commons .PreconditionViolationException ;
5365import org .junit .platform .engine .support .store .NamespacedHierarchicalStore ;
5466
@@ -65,6 +77,12 @@ class CloseablePathTests extends AbstractJupiterTestEngineTests {
6577
6678 private TempDirectory .CloseablePath closeablePath ;
6779
80+ @ Target (METHOD )
81+ @ Retention (RUNTIME )
82+ @ ValueSource (classes = { File .class , Path .class })
83+ private @interface ElementTypeSource {
84+ }
85+
6886 @ BeforeEach
6987 void setUpExtensionContext () {
7088 var store = new NamespaceAwareStore (new NamespacedHierarchicalStore <>(null ), Namespace .GLOBAL );
@@ -95,72 +113,107 @@ void cleanupRoot() throws IOException {
95113 delete (root );
96114 }
97115
98- @ Test
99116 @ DisplayName ("succeeds if the factory returns a directory" )
100- void factoryReturnsDirectory () throws Exception {
101- TempDirFactory factory = spy (new Factory (createDirectory (root .resolve ("directory" ))));
117+ @ ParameterizedTest
118+ @ ElementTypeSource
119+ void factoryReturnsDirectoryDynamic (Class <?> elementType ) throws IOException {
120+ TempDirFactory factory = (elementContext , extensionContext ) -> createDirectory (root .resolve ("directory" ));
102121
103- closeablePath = TempDirectory .createTempDir (factory , DEFAULT , elementContext , extensionContext );
122+ closeablePath = TempDirectory .createTempDir (factory , DEFAULT , elementType , elementContext ,
123+ extensionContext );
104124 assertThat (closeablePath .get ()).isDirectory ();
105125
106126 delete (closeablePath .get ());
107127 }
108128
109- @ Test
110129 @ DisplayName ("succeeds if the factory returns a symbolic link to a directory" )
111- @ DisabledOnOs (OS .WINDOWS )
112- void factoryReturnsSymbolicLinkToDirectory () throws Exception {
130+ @ ParameterizedTest
131+ @ ElementTypeSource
132+ @ DisabledOnOs (WINDOWS )
133+ void factoryReturnsSymbolicLinkToDirectory (Class <?> elementType ) throws IOException {
113134 Path directory = createDirectory (root .resolve ("directory" ));
114- TempDirFactory factory = spy (new Factory (createSymbolicLink (root .resolve ("symbolicLink" ), directory )));
135+ TempDirFactory factory = (elementContext ,
136+ extensionContext ) -> createSymbolicLink (root .resolve ("symbolicLink" ), directory );
115137
116- closeablePath = TempDirectory .createTempDir (factory , DEFAULT , elementContext , extensionContext );
138+ closeablePath = TempDirectory .createTempDir (factory , DEFAULT , elementType , elementContext ,
139+ extensionContext );
117140 assertThat (closeablePath .get ()).isDirectory ();
118141
119142 delete (closeablePath .get ());
120143 delete (directory );
121144 }
122145
146+ @ DisplayName ("succeeds if the factory returns a directory on a non-default file system for a Path annotated element" )
123147 @ Test
148+ void factoryReturnsDirectoryOnNonDefaultFileSystemWithPath () throws IOException {
149+ TempDirFactory factory = spy (new JimfsFactory ());
150+
151+ closeablePath = TempDirectory .createTempDir (factory , DEFAULT , Path .class , elementContext , extensionContext );
152+ assertThat (closeablePath .get ()).isDirectory ();
153+
154+ delete (closeablePath .get ());
155+ }
156+
124157 @ DisplayName ("fails if the factory returns null" )
125- void factoryReturnsNull () throws IOException {
158+ @ ParameterizedTest
159+ @ ElementTypeSource
160+ void factoryReturnsNull (Class <?> elementType ) throws IOException {
126161 TempDirFactory factory = spy (new Factory (null ));
127162
128163 assertThatExtensionConfigurationExceptionIsThrownBy (
129- () -> TempDirectory .createTempDir (factory , DEFAULT , elementContext , extensionContext ));
164+ () -> TempDirectory .createTempDir (factory , DEFAULT , elementType , elementContext , extensionContext ));
130165
131166 verify (factory ).close ();
132167 }
133168
134- @ Test
135169 @ DisplayName ("fails if the factory returns a file" )
136- void factoryReturnsFile () throws IOException {
170+ @ ParameterizedTest
171+ @ ElementTypeSource
172+ void factoryReturnsFile (Class <?> elementType ) throws IOException {
137173 Path file = createFile (root .resolve ("file" ));
138174 TempDirFactory factory = spy (new Factory (file ));
139175
140176 assertThatExtensionConfigurationExceptionIsThrownBy (
141- () -> TempDirectory .createTempDir (factory , DEFAULT , elementContext , extensionContext ));
177+ () -> TempDirectory .createTempDir (factory , DEFAULT , elementType , elementContext , extensionContext ));
142178
143179 verify (factory ).close ();
144180 assertThat (file ).doesNotExist ();
145181 }
146182
147- @ Test
148183 @ DisplayName ("fails if the factory returns a symbolic link to a file" )
149- @ DisabledOnOs (OS .WINDOWS )
150- void factoryReturnsSymbolicLinkToFile () throws IOException {
184+ @ ParameterizedTest
185+ @ ElementTypeSource
186+ @ DisabledOnOs (WINDOWS )
187+ void factoryReturnsSymbolicLinkToFile (Class <?> elementType ) throws IOException {
151188 Path file = createFile (root .resolve ("file" ));
152189 Path symbolicLink = createSymbolicLink (root .resolve ("symbolicLink" ), file );
153190 TempDirFactory factory = spy (new Factory (symbolicLink ));
154191
155192 assertThatExtensionConfigurationExceptionIsThrownBy (
156- () -> TempDirectory .createTempDir (factory , DEFAULT , elementContext , extensionContext ));
193+ () -> TempDirectory .createTempDir (factory , DEFAULT , elementType , elementContext , extensionContext ));
157194
158195 verify (factory ).close ();
159196 assertThat (symbolicLink ).doesNotExist ();
160197
161198 delete (file );
162199 }
163200
201+ @ DisplayName ("fails if the factory returns a directory on a non-default file system for a File annotated element" )
202+ @ Test
203+ void factoryReturnsDirectoryOnNonDefaultFileSystemWithFile () throws IOException {
204+ TempDirFactory factory = spy (new JimfsFactory ());
205+
206+ assertThatExceptionOfType (ExtensionConfigurationException .class )//
207+ .isThrownBy (() -> TempDirectory .createTempDir (factory , DEFAULT , File .class , elementContext ,
208+ extensionContext ))//
209+ .withMessage ("Failed to create default temp directory" )//
210+ .withCauseInstanceOf (PreconditionViolationException .class )//
211+ .havingCause ().withMessage ("temp directory with non-default file system cannot be injected into "
212+ + File .class .getName () + " target" );
213+
214+ verify (factory ).close ();
215+ }
216+
164217 // Mockito spying a lambda fails with: VM does not support modification of given type
165218 private record Factory (Path path ) implements TempDirFactory {
166219
@@ -171,6 +224,22 @@ public Path createTempDirectory(AnnotatedElementContext elementContext, Extensio
171224
172225 }
173226
227+ private static class JimfsFactory implements TempDirFactory {
228+
229+ private final FileSystem fileSystem = Jimfs .newFileSystem (unix ());
230+
231+ @ Override
232+ public Path createTempDirectory (AnnotatedElementContext elementContext , ExtensionContext extensionContext )
233+ throws Exception {
234+ return createDirectory (fileSystem .getPath ("/" ).resolve ("directory" ));
235+ }
236+
237+ @ Override
238+ public void close () throws IOException {
239+ TempDirFactory .super .close ();
240+ }
241+ }
242+
174243 private static void assertThatExtensionConfigurationExceptionIsThrownBy (ThrowingCallable callable ) {
175244 assertThatExceptionOfType (ExtensionConfigurationException .class )//
176245 .isThrownBy (callable )//
@@ -201,10 +270,13 @@ void cleanupTempDirectory() throws IOException {
201270 deleteIfExists (closeablePath .get ());
202271 }
203272
204- @ Test
205273 @ DisplayName ("is done for a cleanup mode of ALWAYS" )
206- void always () throws IOException {
207- closeablePath = TempDirectory .createTempDir (factory , ALWAYS , elementContext , extensionContext );
274+ @ ParameterizedTest
275+ @ ElementTypeSource
276+ void always (Class <?> elementType ) throws IOException {
277+ reset (factory );
278+
279+ closeablePath = TempDirectory .createTempDir (factory , ALWAYS , elementType , elementContext , extensionContext );
208280 assertThat (closeablePath .get ()).isDirectory ();
209281
210282 closeablePath .close ();
@@ -213,10 +285,13 @@ void always() throws IOException {
213285 assertThat (closeablePath .get ()).doesNotExist ();
214286 }
215287
216- @ Test
217288 @ DisplayName ("is not done for a cleanup mode of NEVER" )
218- void never () throws IOException {
219- closeablePath = TempDirectory .createTempDir (factory , NEVER , elementContext , extensionContext );
289+ @ ParameterizedTest
290+ @ ElementTypeSource
291+ void never (Class <?> elementType ) throws IOException {
292+ reset (factory );
293+
294+ closeablePath = TempDirectory .createTempDir (factory , NEVER , elementType , elementContext , extensionContext );
220295 assertThat (closeablePath .get ()).isDirectory ();
221296
222297 closeablePath .close ();
@@ -225,12 +300,16 @@ void never() throws IOException {
225300 assertThat (closeablePath .get ()).exists ();
226301 }
227302
228- @ Test
229303 @ DisplayName ("is not done for a cleanup mode of ON_SUCCESS, if there is an exception" )
230- void onSuccessWithException () throws IOException {
304+ @ ParameterizedTest
305+ @ ElementTypeSource
306+ void onSuccessWithException (Class <?> elementType ) throws IOException {
307+ reset (factory );
308+
231309 when (extensionContext .getExecutionException ()).thenReturn (Optional .of (new Exception ()));
232310
233- closeablePath = TempDirectory .createTempDir (factory , ON_SUCCESS , elementContext , extensionContext );
311+ closeablePath = TempDirectory .createTempDir (factory , ON_SUCCESS , elementType , elementContext ,
312+ extensionContext );
234313 assertThat (closeablePath .get ()).isDirectory ();
235314
236315 closeablePath .close ();
@@ -239,12 +318,16 @@ void onSuccessWithException() throws IOException {
239318 assertThat (closeablePath .get ()).exists ();
240319 }
241320
242- @ Test
243321 @ DisplayName ("is done for a cleanup mode of ON_SUCCESS, if there is no exception" )
244- void onSuccessWithNoException () throws IOException {
322+ @ ParameterizedTest
323+ @ ElementTypeSource
324+ void onSuccessWithNoException (Class <?> elementType ) throws IOException {
325+ reset (factory );
326+
245327 when (extensionContext .getExecutionException ()).thenReturn (Optional .empty ());
246328
247- closeablePath = TempDirectory .createTempDir (factory , ON_SUCCESS , elementContext , extensionContext );
329+ closeablePath = TempDirectory .createTempDir (factory , ON_SUCCESS , elementType , elementContext ,
330+ extensionContext );
248331 assertThat (closeablePath .get ()).isDirectory ();
249332
250333 closeablePath .close ();
0 commit comments