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