3434import java .io .File ;
3535import java .io .IOException ;
3636import java .net .URL ;
37+ import java .util .AbstractMap ;
38+ import java .util .Map ;
3739
3840import org .scijava .util .ClassUtils ;
3941import org .scijava .util .FileUtils ;
@@ -58,7 +60,8 @@ public class TestUtils {
5860 * @throws IOException
5961 */
6062 public static File createTemporaryDirectory (final String prefix ) throws IOException {
61- return createTemporaryDirectory (prefix , getCallingClass (null ));
63+ final Map .Entry <Class <?>, String > calling = getCallingCodeLocation (null );
64+ return createTemporaryDirectory (prefix , calling .getKey (), calling .getValue ());
6265 }
6366
6467 /**
@@ -77,18 +80,51 @@ public static File createTemporaryDirectory(final String prefix) throws IOExcept
7780 */
7881 public static File createTemporaryDirectory (final String prefix ,
7982 final Class <?> forClass ) throws IOException
83+ {
84+ return createTemporaryDirectory (prefix , forClass , "" );
85+ }
86+
87+ /**
88+ * Makes a temporary directory for use with unit tests.
89+ * <p>
90+ * When the unit test runs in a Maven context, the temporary directory will be
91+ * created in the corresponding <i>target/</i> directory instead of
92+ * <i>/tmp/</i>.
93+ * </p>
94+ *
95+ * @param prefix the prefix for the directory's name
96+ * @param forClass the class for context (to determine whether there's a
97+ * <i>target/<i> directory)
98+ * @param suffix the suffix for the directory's name
99+ * @return the reference to the newly-created temporary directory
100+ * @throws IOException
101+ */
102+ public static File createTemporaryDirectory (final String prefix ,
103+ final Class <?> forClass , final String suffix ) throws IOException
80104 {
81105 final URL directory = ClassUtils .getLocation (forClass );
82- if (directory != null && "file" .equals (directory .getProtocol ())) {
83- final String path = directory .getPath ();
84- if (path != null && path .endsWith ("/target/test-classes/" )) {
85- final File baseDirectory =
86- new File (path .substring (0 , path .length () - 13 ));
87- final File file = File .createTempFile (prefix , "" , baseDirectory );
88- if (file .delete () && file .mkdir ()) return file ;
89- }
106+ if (directory == null ) {
107+ throw new IllegalArgumentException ("No location for class " + forClass );
108+ }
109+ if (!"file" .equals (directory .getProtocol ())) {
110+ throw new IllegalArgumentException ("Invalid directory: " + directory );
111+ }
112+ final String path = directory .getPath ();
113+ if (path == null ) throw new IllegalArgumentException ("Directory has null path" );
114+ final File baseDirectory ;
115+ if (path .endsWith ("/target/test-classes/" )) {
116+ baseDirectory = new File (path ).getParentFile ();
117+ } else {
118+ baseDirectory = new File (path );
119+ }
120+
121+ final File file = new File (baseDirectory , prefix + suffix );
122+ if (file .isDirectory ()) FileUtils .deleteRecursively (file );
123+ else if (file .exists () && !file .delete ()) {
124+ throw new IOException ("Could not remove " + file );
90125 }
91- return FileUtils .createTemporaryDirectory (prefix , "" );
126+ if (!file .mkdir ()) throw new IOException ("Could not make directory " + file );
127+ return file ;
92128 }
93129
94130 /**
@@ -104,6 +140,22 @@ public static File createTemporaryDirectory(final String prefix,
104140 * @return the class of the caller
105141 */
106142 public static Class <?> getCallingClass (final Class <?> excluding ) {
143+ return getCallingCodeLocation (excluding ).getKey ();
144+ }
145+
146+ /**
147+ * Returns the class and the method/line number of the caller (excluding the specified class).
148+ * <p>
149+ * Sometimes it is convenient to determine the caller's context, e.g. to
150+ * determine whether running in a maven-surefire-plugin context (in which case
151+ * the location of the caller's class would end in
152+ * <i>target/test-classes/</i>).
153+ * </p>
154+ *
155+ * @param excluding the class to exclude (or null)
156+ * @return the class of the caller and the method and line number
157+ */
158+ public static Map .Entry <Class <?>, String > getCallingCodeLocation (final Class <?> excluding ) {
107159 final String thisClassName = TestUtils .class .getName ();
108160 final String thisClassName2 = excluding == null ? null : excluding .getName ();
109161 final Thread currentThread = Thread .currentThread ();
@@ -115,14 +167,17 @@ public static Class<?> getCallingClass(final Class<?> excluding) {
115167 continue ;
116168 }
117169 final ClassLoader loader = currentThread .getContextClassLoader ();
170+ final Class <?> clazz ;
118171 try {
119- return loader .loadClass (element .getClassName ());
172+ clazz = loader .loadClass (element .getClassName ());
120173 }
121174 catch (ClassNotFoundException e ) {
122175 throw new UnsupportedOperationException ("Could not load " +
123176 element .getClassName () + " with the current context class loader (" +
124177 loader + ")!" );
125178 }
179+ final String suffix = element .getMethodName () + "-L" + element .getLineNumber ();
180+ return new AbstractMap .SimpleEntry <Class <?>, String >(clazz , suffix );
126181 }
127182 throw new UnsupportedOperationException ("No calling class outside " + thisClassName + " found!" );
128183 }
0 commit comments