xref: /JGit/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java (revision 5c5f7c6b146b24f2bd4afae1902df85ad6e57ea3)
1d9e07a57SRobin Rosenberg /*
2d9e07a57SRobin Rosenberg  * Copyright (C) 2008-2009, Google Inc.
3d9e07a57SRobin Rosenberg  * Copyright (C) 2008, Imran M Yousuf <imyousuf@smartitengineering.com>
4*5c5f7c6bSMatthias Sohn  * Copyright (C) 2008, Jonas Fonseca <fonseca@diku.dk> and others
5d9e07a57SRobin Rosenberg  *
6*5c5f7c6bSMatthias Sohn  * This program and the accompanying materials are made available under the
7*5c5f7c6bSMatthias Sohn  * terms of the Eclipse Distribution License v. 1.0 which is available at
8*5c5f7c6bSMatthias Sohn  * https://www.eclipse.org/org/documents/edl-v10.php.
9d9e07a57SRobin Rosenberg  *
10*5c5f7c6bSMatthias Sohn  * SPDX-License-Identifier: BSD-3-Clause
11d9e07a57SRobin Rosenberg  */
12d9e07a57SRobin Rosenberg 
13d9e07a57SRobin Rosenberg package org.eclipse.jgit.junit;
14d9e07a57SRobin Rosenberg 
1530c6c754SDavid Pursehouse import static java.nio.charset.StandardCharsets.UTF_8;
160b4e781fSDavid Pursehouse 
17d9e07a57SRobin Rosenberg import java.io.File;
18573d36a4SShawn Pearce import java.io.FileNotFoundException;
19b649eaa9SDariusz Luksza import java.io.FileOutputStream;
20b649eaa9SDariusz Luksza import java.io.IOException;
21573d36a4SShawn Pearce import java.io.InputStream;
22b649eaa9SDariusz Luksza import java.io.OutputStreamWriter;
23b649eaa9SDariusz Luksza import java.io.Writer;
24d9e07a57SRobin Rosenberg import java.lang.reflect.Method;
25d9e07a57SRobin Rosenberg import java.net.URISyntaxException;
26d9e07a57SRobin Rosenberg import java.net.URL;
27a406ebf4SAndrey Loskutov import java.nio.file.Path;
28d9e07a57SRobin Rosenberg 
29d35586a4SMatthias Sohn import org.eclipse.jgit.lib.Repository;
30b649eaa9SDariusz Luksza import org.eclipse.jgit.util.FileUtils;
319ea38173SRobin Stocker import org.eclipse.jgit.util.IO;
32d9e07a57SRobin Rosenberg import org.eclipse.jgit.util.RawParseUtils;
33d9e07a57SRobin Rosenberg import org.junit.Assert;
34d9e07a57SRobin Rosenberg import org.junit.Test;
35d9e07a57SRobin Rosenberg 
36a90b75b4SMatthias Sohn /**
37a90b75b4SMatthias Sohn  * Abstract test util class
38a90b75b4SMatthias Sohn  */
39d9e07a57SRobin Rosenberg public abstract class JGitTestUtil {
40a90b75b4SMatthias Sohn 	/** Constant <code>CLASSPATH_TO_RESOURCES="org/eclipse/jgit/test/resources/"</code> */
41d9e07a57SRobin Rosenberg 	public static final String CLASSPATH_TO_RESOURCES = "org/eclipse/jgit/test/resources/";
42d9e07a57SRobin Rosenberg 
JGitTestUtil()43d9e07a57SRobin Rosenberg 	private JGitTestUtil() {
44d9e07a57SRobin Rosenberg 		throw new UnsupportedOperationException();
45d9e07a57SRobin Rosenberg 	}
46d9e07a57SRobin Rosenberg 
47a90b75b4SMatthias Sohn 	/**
48a90b75b4SMatthias Sohn 	 * Get name of current test by inspecting stack trace
49a90b75b4SMatthias Sohn 	 *
50a90b75b4SMatthias Sohn 	 * @return the name
51a90b75b4SMatthias Sohn 	 */
getName()52d9e07a57SRobin Rosenberg 	public static String getName() {
53d9e07a57SRobin Rosenberg 		GatherStackTrace stack;
54d9e07a57SRobin Rosenberg 		try {
55d9e07a57SRobin Rosenberg 			throw new GatherStackTrace();
56d9e07a57SRobin Rosenberg 		} catch (GatherStackTrace wanted) {
57d9e07a57SRobin Rosenberg 			stack = wanted;
58d9e07a57SRobin Rosenberg 		}
59d9e07a57SRobin Rosenberg 
60d9e07a57SRobin Rosenberg 		try {
61d9e07a57SRobin Rosenberg 			for (StackTraceElement stackTrace : stack.getStackTrace()) {
62d9e07a57SRobin Rosenberg 				String className = stackTrace.getClassName();
63d9e07a57SRobin Rosenberg 				String methodName = stackTrace.getMethodName();
64d9e07a57SRobin Rosenberg 				Method method;
65d9e07a57SRobin Rosenberg 				try {
66d9e07a57SRobin Rosenberg 					method = Class.forName(className) //
67d9e07a57SRobin Rosenberg 							.getMethod(methodName, (Class[]) null);
68d9e07a57SRobin Rosenberg 				} catch (NoSuchMethodException e) {
69d9e07a57SRobin Rosenberg 					// could be private, i.e. not a test method
70d9e07a57SRobin Rosenberg 					// could have arguments, not handled
71d9e07a57SRobin Rosenberg 					continue;
72d9e07a57SRobin Rosenberg 				}
73d9e07a57SRobin Rosenberg 
74d9e07a57SRobin Rosenberg 				Test annotation = method.getAnnotation(Test.class);
75d9e07a57SRobin Rosenberg 				if (annotation != null)
76d9e07a57SRobin Rosenberg 					return methodName;
77d9e07a57SRobin Rosenberg 			}
78d9e07a57SRobin Rosenberg 		} catch (ClassNotFoundException shouldNeverOccur) {
79d9e07a57SRobin Rosenberg 			// Fall through and crash.
80d9e07a57SRobin Rosenberg 		}
81d9e07a57SRobin Rosenberg 
82d9e07a57SRobin Rosenberg 		throw new AssertionError("Cannot determine name of current test");
83d9e07a57SRobin Rosenberg 	}
84d9e07a57SRobin Rosenberg 
85d9e07a57SRobin Rosenberg 	@SuppressWarnings("serial")
86d9e07a57SRobin Rosenberg 	private static class GatherStackTrace extends Exception {
87d9e07a57SRobin Rosenberg 		// Thrown above to collect the stack frame.
88d9e07a57SRobin Rosenberg 	}
89d9e07a57SRobin Rosenberg 
90a90b75b4SMatthias Sohn 	/**
91a90b75b4SMatthias Sohn 	 * Assert byte arrays are equal
92a90b75b4SMatthias Sohn 	 *
93a90b75b4SMatthias Sohn 	 * @param exp
94a90b75b4SMatthias Sohn 	 *            expected value
95a90b75b4SMatthias Sohn 	 * @param act
96a90b75b4SMatthias Sohn 	 *            actual value
97a90b75b4SMatthias Sohn 	 */
assertEquals(byte[] exp, byte[] act)98d9e07a57SRobin Rosenberg 	public static void assertEquals(byte[] exp, byte[] act) {
99d9e07a57SRobin Rosenberg 		Assert.assertEquals(s(exp), s(act));
100d9e07a57SRobin Rosenberg 	}
101d9e07a57SRobin Rosenberg 
s(byte[] raw)102d9e07a57SRobin Rosenberg 	private static String s(byte[] raw) {
103d9e07a57SRobin Rosenberg 		return RawParseUtils.decode(raw);
104d9e07a57SRobin Rosenberg 	}
105d9e07a57SRobin Rosenberg 
106a90b75b4SMatthias Sohn 	/**
107a90b75b4SMatthias Sohn 	 * Get test resource file.
108a90b75b4SMatthias Sohn 	 *
109a90b75b4SMatthias Sohn 	 * @param fileName
110a90b75b4SMatthias Sohn 	 * @return the test resource file
111a90b75b4SMatthias Sohn 	 */
getTestResourceFile(String fileName)1126d370d83SHan-Wen Nienhuys 	public static File getTestResourceFile(String fileName) {
113d9e07a57SRobin Rosenberg 		if (fileName == null || fileName.length() <= 0) {
114d9e07a57SRobin Rosenberg 			return null;
115d9e07a57SRobin Rosenberg 		}
116d9e07a57SRobin Rosenberg 		final URL url = cl().getResource(CLASSPATH_TO_RESOURCES + fileName);
117d9e07a57SRobin Rosenberg 		if (url == null) {
118d9e07a57SRobin Rosenberg 			// If URL is null then try to load it as it was being
119d9e07a57SRobin Rosenberg 			// loaded previously
120d9e07a57SRobin Rosenberg 			return new File("tst", fileName);
121d9e07a57SRobin Rosenberg 		}
122573d36a4SShawn Pearce 		if ("jar".equals(url.getProtocol())) {
123573d36a4SShawn Pearce 			try {
124573d36a4SShawn Pearce 				File tmp = File.createTempFile("tmp_", "_" + fileName);
125573d36a4SShawn Pearce 				copyTestResource(fileName, tmp);
126573d36a4SShawn Pearce 				return tmp;
127573d36a4SShawn Pearce 			} catch (IOException err) {
128573d36a4SShawn Pearce 				throw new RuntimeException("Cannot create temporary file", err);
129573d36a4SShawn Pearce 			}
130573d36a4SShawn Pearce 		}
131d9e07a57SRobin Rosenberg 		try {
132d9e07a57SRobin Rosenberg 			return new File(url.toURI());
133573d36a4SShawn Pearce 		} catch (IllegalArgumentException e) {
134573d36a4SShawn Pearce 			throw new IllegalArgumentException(e.getMessage() + " " + url);
135d9e07a57SRobin Rosenberg 		} catch (URISyntaxException e) {
136d9e07a57SRobin Rosenberg 			return new File(url.getPath());
137d9e07a57SRobin Rosenberg 		}
138d9e07a57SRobin Rosenberg 	}
139d9e07a57SRobin Rosenberg 
140a90b75b4SMatthias Sohn 	/**
141a90b75b4SMatthias Sohn 	 * Copy test resource.
142a90b75b4SMatthias Sohn 	 *
143a90b75b4SMatthias Sohn 	 * @param name
144a90b75b4SMatthias Sohn 	 * @param dest
145a90b75b4SMatthias Sohn 	 * @throws IOException
146a90b75b4SMatthias Sohn 	 */
copyTestResource(String name, File dest)147573d36a4SShawn Pearce 	public static void copyTestResource(String name, File dest)
148573d36a4SShawn Pearce 			throws IOException {
149573d36a4SShawn Pearce 		URL url = cl().getResource(CLASSPATH_TO_RESOURCES + name);
150573d36a4SShawn Pearce 		if (url == null)
151573d36a4SShawn Pearce 			throw new FileNotFoundException(name);
152f91ce7faSDavid Pursehouse 		try (InputStream in = url.openStream();
153f91ce7faSDavid Pursehouse 				FileOutputStream out = new FileOutputStream(dest)) {
154573d36a4SShawn Pearce 			byte[] buf = new byte[4096];
155573d36a4SShawn Pearce 			for (int n; (n = in.read(buf)) > 0;)
156573d36a4SShawn Pearce 				out.write(buf, 0, n);
157573d36a4SShawn Pearce 		}
158573d36a4SShawn Pearce 	}
159573d36a4SShawn Pearce 
cl()160d9e07a57SRobin Rosenberg 	private static ClassLoader cl() {
161d9e07a57SRobin Rosenberg 		return JGitTestUtil.class.getClassLoader();
162d9e07a57SRobin Rosenberg 	}
163b649eaa9SDariusz Luksza 
164a90b75b4SMatthias Sohn 	/**
165a90b75b4SMatthias Sohn 	 * Write a trash file.
166a90b75b4SMatthias Sohn 	 *
167a90b75b4SMatthias Sohn 	 * @param db
168a90b75b4SMatthias Sohn 	 * @param name
169a90b75b4SMatthias Sohn 	 * @param data
170a90b75b4SMatthias Sohn 	 * @return the trash file
171a90b75b4SMatthias Sohn 	 * @throws IOException
172a90b75b4SMatthias Sohn 	 */
writeTrashFile(final Repository db, final String name, final String data)173d35586a4SMatthias Sohn 	public static File writeTrashFile(final Repository db,
174b649eaa9SDariusz Luksza 			final String name, final String data) throws IOException {
175b649eaa9SDariusz Luksza 		File path = new File(db.getWorkTree(), name);
176b649eaa9SDariusz Luksza 		write(path, data);
177b649eaa9SDariusz Luksza 		return path;
178b649eaa9SDariusz Luksza 	}
179b649eaa9SDariusz Luksza 
180a90b75b4SMatthias Sohn 	/**
181a90b75b4SMatthias Sohn 	 * Write a trash file.
182a90b75b4SMatthias Sohn 	 *
183a90b75b4SMatthias Sohn 	 * @param db
184a90b75b4SMatthias Sohn 	 * @param subdir
185a90b75b4SMatthias Sohn 	 * @param name
186a90b75b4SMatthias Sohn 	 * @param data
187a90b75b4SMatthias Sohn 	 * @return the trash file
188a90b75b4SMatthias Sohn 	 * @throws IOException
189a90b75b4SMatthias Sohn 	 */
writeTrashFile(final Repository db, final String subdir, final String name, final String data)190d35586a4SMatthias Sohn 	public static File writeTrashFile(final Repository db,
191803debd7SJevgeni Zelenkov 			final String subdir,
192803debd7SJevgeni Zelenkov 			final String name, final String data) throws IOException {
193803debd7SJevgeni Zelenkov 		File path = new File(db.getWorkTree() + "/" + subdir, name);
194803debd7SJevgeni Zelenkov 		write(path, data);
195803debd7SJevgeni Zelenkov 		return path;
196803debd7SJevgeni Zelenkov 	}
197803debd7SJevgeni Zelenkov 
198b649eaa9SDariusz Luksza 	/**
199b649eaa9SDariusz Luksza 	 * Write a string as a UTF-8 file.
200b649eaa9SDariusz Luksza 	 *
201b649eaa9SDariusz Luksza 	 * @param f
202b649eaa9SDariusz Luksza 	 *            file to write the string to. Caller is responsible for making
203b649eaa9SDariusz Luksza 	 *            sure it is in the trash directory or will otherwise be cleaned
204b649eaa9SDariusz Luksza 	 *            up at the end of the test. If the parent directory does not
205b649eaa9SDariusz Luksza 	 *            exist, the missing parent directories are automatically
206b649eaa9SDariusz Luksza 	 *            created.
207b649eaa9SDariusz Luksza 	 * @param body
208b649eaa9SDariusz Luksza 	 *            content to write to the file.
209b649eaa9SDariusz Luksza 	 * @throws IOException
210b649eaa9SDariusz Luksza 	 *             the file could not be written.
211b649eaa9SDariusz Luksza 	 */
write(File f, String body)2126d370d83SHan-Wen Nienhuys 	public static void write(File f, String body)
213b649eaa9SDariusz Luksza 			throws IOException {
214b649eaa9SDariusz Luksza 		FileUtils.mkdirs(f.getParentFile(), true);
215f91ce7faSDavid Pursehouse 		try (Writer w = new OutputStreamWriter(new FileOutputStream(f),
21630c6c754SDavid Pursehouse 				UTF_8)) {
217b649eaa9SDariusz Luksza 			w.write(body);
218b649eaa9SDariusz Luksza 		}
219b649eaa9SDariusz Luksza 	}
220b649eaa9SDariusz Luksza 
2219ea38173SRobin Stocker 	/**
2229ea38173SRobin Stocker 	 * Fully read a UTF-8 file and return as a string.
2239ea38173SRobin Stocker 	 *
2249ea38173SRobin Stocker 	 * @param file
2259ea38173SRobin Stocker 	 *            file to read the content of.
2269ea38173SRobin Stocker 	 * @return UTF-8 decoded content of the file, empty string if the file
2279ea38173SRobin Stocker 	 *         exists but has no content.
2289ea38173SRobin Stocker 	 * @throws IOException
2299ea38173SRobin Stocker 	 *             the file does not exist, or could not be read.
2309ea38173SRobin Stocker 	 */
read(File file)2316d370d83SHan-Wen Nienhuys 	public static String read(File file) throws IOException {
2329ea38173SRobin Stocker 		final byte[] body = IO.readFully(file);
23330c6c754SDavid Pursehouse 		return new String(body, 0, body.length, UTF_8);
2349ea38173SRobin Stocker 	}
2359ea38173SRobin Stocker 
236a90b75b4SMatthias Sohn 	/**
237a90b75b4SMatthias Sohn 	 * Read a file's content
238a90b75b4SMatthias Sohn 	 *
239a90b75b4SMatthias Sohn 	 * @param db
240a90b75b4SMatthias Sohn 	 * @param name
241a90b75b4SMatthias Sohn 	 * @return the content of the file
242a90b75b4SMatthias Sohn 	 * @throws IOException
243a90b75b4SMatthias Sohn 	 */
read(Repository db, String name)2446d370d83SHan-Wen Nienhuys 	public static String read(Repository db, String name)
2459ea38173SRobin Stocker 			throws IOException {
2469ea38173SRobin Stocker 		File file = new File(db.getWorkTree(), name);
2479ea38173SRobin Stocker 		return read(file);
2489ea38173SRobin Stocker 	}
2499ea38173SRobin Stocker 
250a90b75b4SMatthias Sohn 	/**
251a90b75b4SMatthias Sohn 	 * Check if file exists
252a90b75b4SMatthias Sohn 	 *
253a90b75b4SMatthias Sohn 	 * @param db
254a90b75b4SMatthias Sohn 	 * @param name
255a90b75b4SMatthias Sohn 	 *            name of the file
256a90b75b4SMatthias Sohn 	 * @return {@code true} if the file exists
257a90b75b4SMatthias Sohn 	 */
check(Repository db, String name)2586d370d83SHan-Wen Nienhuys 	public static boolean check(Repository db, String name) {
2590c4553d2SChristian Halstrick 		File file = new File(db.getWorkTree(), name);
2600c4553d2SChristian Halstrick 		return file.exists();
2610c4553d2SChristian Halstrick 	}
2620c4553d2SChristian Halstrick 
263a90b75b4SMatthias Sohn 	/**
264a90b75b4SMatthias Sohn 	 * Delete a trash file.
265a90b75b4SMatthias Sohn 	 *
266a90b75b4SMatthias Sohn 	 * @param db
267a90b75b4SMatthias Sohn 	 * @param name
268a90b75b4SMatthias Sohn 	 * @throws IOException
269a90b75b4SMatthias Sohn 	 */
deleteTrashFile(final Repository db, final String name)270d35586a4SMatthias Sohn 	public static void deleteTrashFile(final Repository db,
271b649eaa9SDariusz Luksza 			final String name) throws IOException {
272b649eaa9SDariusz Luksza 		File path = new File(db.getWorkTree(), name);
273b649eaa9SDariusz Luksza 		FileUtils.delete(path);
274b649eaa9SDariusz Luksza 	}
275b649eaa9SDariusz Luksza 
2762cdc130dSMatthias Sohn 	/**
277a90b75b4SMatthias Sohn 	 * Write a symbolic link
278a90b75b4SMatthias Sohn 	 *
2792cdc130dSMatthias Sohn 	 * @param db
2802cdc130dSMatthias Sohn 	 *            the repository
2812cdc130dSMatthias Sohn 	 * @param link
2822cdc130dSMatthias Sohn 	 *            the path of the symbolic link to create
2832cdc130dSMatthias Sohn 	 * @param target
2842cdc130dSMatthias Sohn 	 *            the target of the symbolic link
2852cdc130dSMatthias Sohn 	 * @return the path to the symbolic link
2862cdc130dSMatthias Sohn 	 * @throws Exception
2872cdc130dSMatthias Sohn 	 * @since 4.2
2882cdc130dSMatthias Sohn 	 */
writeLink(Repository db, String link, String target)289a406ebf4SAndrey Loskutov 	public static Path writeLink(Repository db, String link,
290a406ebf4SAndrey Loskutov 			String target) throws Exception {
291a406ebf4SAndrey Loskutov 		return FileUtils.createSymLink(new File(db.getWorkTree(), link),
292a406ebf4SAndrey Loskutov 				target);
293a406ebf4SAndrey Loskutov 	}
294a406ebf4SAndrey Loskutov 
2952c299964SZhen Chen 	/**
2962c299964SZhen Chen 	 * Concatenate byte arrays.
2972c299964SZhen Chen 	 *
2982c299964SZhen Chen 	 * @param b
2992c299964SZhen Chen 	 *            byte arrays to combine together.
3002c299964SZhen Chen 	 * @return a single byte array that contains all bytes copied from input
3012c299964SZhen Chen 	 *         byte arrays.
3022c299964SZhen Chen 	 * @since 4.9
3032c299964SZhen Chen 	 */
concat(byte[]... b)3042c299964SZhen Chen 	public static byte[] concat(byte[]... b) {
3052c299964SZhen Chen 		int n = 0;
3062c299964SZhen Chen 		for (byte[] a : b) {
3072c299964SZhen Chen 			n += a.length;
3082c299964SZhen Chen 		}
3092c299964SZhen Chen 
3102c299964SZhen Chen 		byte[] data = new byte[n];
3112c299964SZhen Chen 		n = 0;
3122c299964SZhen Chen 		for (byte[] a : b) {
3132c299964SZhen Chen 			System.arraycopy(a, 0, data, n, a.length);
3142c299964SZhen Chen 			n += a.length;
3152c299964SZhen Chen 		}
3162c299964SZhen Chen 		return data;
3172c299964SZhen Chen 	}
318d9e07a57SRobin Rosenberg }
319