xref: /JGit/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java (revision 5c5f7c6b146b24f2bd4afae1902df85ad6e57ea3)
1 /*
2  * Copyright (C) 2008-2009, Google Inc.
3  * Copyright (C) 2008, Imran M Yousuf <imyousuf@smartitengineering.com>
4  * Copyright (C) 2008, Jonas Fonseca <fonseca@diku.dk> and others
5  *
6  * This program and the accompanying materials are made available under the
7  * terms of the Eclipse Distribution License v. 1.0 which is available at
8  * https://www.eclipse.org/org/documents/edl-v10.php.
9  *
10  * SPDX-License-Identifier: BSD-3-Clause
11  */
12 
13 package org.eclipse.jgit.junit;
14 
15 import static java.nio.charset.StandardCharsets.UTF_8;
16 
17 import java.io.File;
18 import java.io.FileNotFoundException;
19 import java.io.FileOutputStream;
20 import java.io.IOException;
21 import java.io.InputStream;
22 import java.io.OutputStreamWriter;
23 import java.io.Writer;
24 import java.lang.reflect.Method;
25 import java.net.URISyntaxException;
26 import java.net.URL;
27 import java.nio.file.Path;
28 
29 import org.eclipse.jgit.lib.Repository;
30 import org.eclipse.jgit.util.FileUtils;
31 import org.eclipse.jgit.util.IO;
32 import org.eclipse.jgit.util.RawParseUtils;
33 import org.junit.Assert;
34 import org.junit.Test;
35 
36 /**
37  * Abstract test util class
38  */
39 public abstract class JGitTestUtil {
40 	/** Constant <code>CLASSPATH_TO_RESOURCES="org/eclipse/jgit/test/resources/"</code> */
41 	public static final String CLASSPATH_TO_RESOURCES = "org/eclipse/jgit/test/resources/";
42 
JGitTestUtil()43 	private JGitTestUtil() {
44 		throw new UnsupportedOperationException();
45 	}
46 
47 	/**
48 	 * Get name of current test by inspecting stack trace
49 	 *
50 	 * @return the name
51 	 */
getName()52 	public static String getName() {
53 		GatherStackTrace stack;
54 		try {
55 			throw new GatherStackTrace();
56 		} catch (GatherStackTrace wanted) {
57 			stack = wanted;
58 		}
59 
60 		try {
61 			for (StackTraceElement stackTrace : stack.getStackTrace()) {
62 				String className = stackTrace.getClassName();
63 				String methodName = stackTrace.getMethodName();
64 				Method method;
65 				try {
66 					method = Class.forName(className) //
67 							.getMethod(methodName, (Class[]) null);
68 				} catch (NoSuchMethodException e) {
69 					// could be private, i.e. not a test method
70 					// could have arguments, not handled
71 					continue;
72 				}
73 
74 				Test annotation = method.getAnnotation(Test.class);
75 				if (annotation != null)
76 					return methodName;
77 			}
78 		} catch (ClassNotFoundException shouldNeverOccur) {
79 			// Fall through and crash.
80 		}
81 
82 		throw new AssertionError("Cannot determine name of current test");
83 	}
84 
85 	@SuppressWarnings("serial")
86 	private static class GatherStackTrace extends Exception {
87 		// Thrown above to collect the stack frame.
88 	}
89 
90 	/**
91 	 * Assert byte arrays are equal
92 	 *
93 	 * @param exp
94 	 *            expected value
95 	 * @param act
96 	 *            actual value
97 	 */
assertEquals(byte[] exp, byte[] act)98 	public static void assertEquals(byte[] exp, byte[] act) {
99 		Assert.assertEquals(s(exp), s(act));
100 	}
101 
s(byte[] raw)102 	private static String s(byte[] raw) {
103 		return RawParseUtils.decode(raw);
104 	}
105 
106 	/**
107 	 * Get test resource file.
108 	 *
109 	 * @param fileName
110 	 * @return the test resource file
111 	 */
getTestResourceFile(String fileName)112 	public static File getTestResourceFile(String fileName) {
113 		if (fileName == null || fileName.length() <= 0) {
114 			return null;
115 		}
116 		final URL url = cl().getResource(CLASSPATH_TO_RESOURCES + fileName);
117 		if (url == null) {
118 			// If URL is null then try to load it as it was being
119 			// loaded previously
120 			return new File("tst", fileName);
121 		}
122 		if ("jar".equals(url.getProtocol())) {
123 			try {
124 				File tmp = File.createTempFile("tmp_", "_" + fileName);
125 				copyTestResource(fileName, tmp);
126 				return tmp;
127 			} catch (IOException err) {
128 				throw new RuntimeException("Cannot create temporary file", err);
129 			}
130 		}
131 		try {
132 			return new File(url.toURI());
133 		} catch (IllegalArgumentException e) {
134 			throw new IllegalArgumentException(e.getMessage() + " " + url);
135 		} catch (URISyntaxException e) {
136 			return new File(url.getPath());
137 		}
138 	}
139 
140 	/**
141 	 * Copy test resource.
142 	 *
143 	 * @param name
144 	 * @param dest
145 	 * @throws IOException
146 	 */
copyTestResource(String name, File dest)147 	public static void copyTestResource(String name, File dest)
148 			throws IOException {
149 		URL url = cl().getResource(CLASSPATH_TO_RESOURCES + name);
150 		if (url == null)
151 			throw new FileNotFoundException(name);
152 		try (InputStream in = url.openStream();
153 				FileOutputStream out = new FileOutputStream(dest)) {
154 			byte[] buf = new byte[4096];
155 			for (int n; (n = in.read(buf)) > 0;)
156 				out.write(buf, 0, n);
157 		}
158 	}
159 
cl()160 	private static ClassLoader cl() {
161 		return JGitTestUtil.class.getClassLoader();
162 	}
163 
164 	/**
165 	 * Write a trash file.
166 	 *
167 	 * @param db
168 	 * @param name
169 	 * @param data
170 	 * @return the trash file
171 	 * @throws IOException
172 	 */
writeTrashFile(final Repository db, final String name, final String data)173 	public static File writeTrashFile(final Repository db,
174 			final String name, final String data) throws IOException {
175 		File path = new File(db.getWorkTree(), name);
176 		write(path, data);
177 		return path;
178 	}
179 
180 	/**
181 	 * Write a trash file.
182 	 *
183 	 * @param db
184 	 * @param subdir
185 	 * @param name
186 	 * @param data
187 	 * @return the trash file
188 	 * @throws IOException
189 	 */
writeTrashFile(final Repository db, final String subdir, final String name, final String data)190 	public static File writeTrashFile(final Repository db,
191 			final String subdir,
192 			final String name, final String data) throws IOException {
193 		File path = new File(db.getWorkTree() + "/" + subdir, name);
194 		write(path, data);
195 		return path;
196 	}
197 
198 	/**
199 	 * Write a string as a UTF-8 file.
200 	 *
201 	 * @param f
202 	 *            file to write the string to. Caller is responsible for making
203 	 *            sure it is in the trash directory or will otherwise be cleaned
204 	 *            up at the end of the test. If the parent directory does not
205 	 *            exist, the missing parent directories are automatically
206 	 *            created.
207 	 * @param body
208 	 *            content to write to the file.
209 	 * @throws IOException
210 	 *             the file could not be written.
211 	 */
write(File f, String body)212 	public static void write(File f, String body)
213 			throws IOException {
214 		FileUtils.mkdirs(f.getParentFile(), true);
215 		try (Writer w = new OutputStreamWriter(new FileOutputStream(f),
216 				UTF_8)) {
217 			w.write(body);
218 		}
219 	}
220 
221 	/**
222 	 * Fully read a UTF-8 file and return as a string.
223 	 *
224 	 * @param file
225 	 *            file to read the content of.
226 	 * @return UTF-8 decoded content of the file, empty string if the file
227 	 *         exists but has no content.
228 	 * @throws IOException
229 	 *             the file does not exist, or could not be read.
230 	 */
read(File file)231 	public static String read(File file) throws IOException {
232 		final byte[] body = IO.readFully(file);
233 		return new String(body, 0, body.length, UTF_8);
234 	}
235 
236 	/**
237 	 * Read a file's content
238 	 *
239 	 * @param db
240 	 * @param name
241 	 * @return the content of the file
242 	 * @throws IOException
243 	 */
read(Repository db, String name)244 	public static String read(Repository db, String name)
245 			throws IOException {
246 		File file = new File(db.getWorkTree(), name);
247 		return read(file);
248 	}
249 
250 	/**
251 	 * Check if file exists
252 	 *
253 	 * @param db
254 	 * @param name
255 	 *            name of the file
256 	 * @return {@code true} if the file exists
257 	 */
check(Repository db, String name)258 	public static boolean check(Repository db, String name) {
259 		File file = new File(db.getWorkTree(), name);
260 		return file.exists();
261 	}
262 
263 	/**
264 	 * Delete a trash file.
265 	 *
266 	 * @param db
267 	 * @param name
268 	 * @throws IOException
269 	 */
deleteTrashFile(final Repository db, final String name)270 	public static void deleteTrashFile(final Repository db,
271 			final String name) throws IOException {
272 		File path = new File(db.getWorkTree(), name);
273 		FileUtils.delete(path);
274 	}
275 
276 	/**
277 	 * Write a symbolic link
278 	 *
279 	 * @param db
280 	 *            the repository
281 	 * @param link
282 	 *            the path of the symbolic link to create
283 	 * @param target
284 	 *            the target of the symbolic link
285 	 * @return the path to the symbolic link
286 	 * @throws Exception
287 	 * @since 4.2
288 	 */
writeLink(Repository db, String link, String target)289 	public static Path writeLink(Repository db, String link,
290 			String target) throws Exception {
291 		return FileUtils.createSymLink(new File(db.getWorkTree(), link),
292 				target);
293 	}
294 
295 	/**
296 	 * Concatenate byte arrays.
297 	 *
298 	 * @param b
299 	 *            byte arrays to combine together.
300 	 * @return a single byte array that contains all bytes copied from input
301 	 *         byte arrays.
302 	 * @since 4.9
303 	 */
concat(byte[]... b)304 	public static byte[] concat(byte[]... b) {
305 		int n = 0;
306 		for (byte[] a : b) {
307 			n += a.length;
308 		}
309 
310 		byte[] data = new byte[n];
311 		n = 0;
312 		for (byte[] a : b) {
313 			System.arraycopy(a, 0, data, n, a.length);
314 			n += a.length;
315 		}
316 		return data;
317 	}
318 }
319