diff options
Diffstat (limited to 'org.eclipse.jgit.junit/src')
12 files changed, 479 insertions, 111 deletions
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/Assert.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/Assert.java index 96713788f8..6e0a8c79ab 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/Assert.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/Assert.java @@ -9,8 +9,6 @@ */ package org.eclipse.jgit.junit; -import static java.lang.Boolean.valueOf; - /** * Assertion class */ @@ -25,7 +23,8 @@ public class Assert { * actual value */ public static void assertEquals(boolean expect, boolean actual) { - org.junit.Assert.assertEquals(valueOf(expect), valueOf(actual)); + org.junit.Assert.assertEquals(Boolean.valueOf(expect), + Boolean.valueOf(actual)); } /** @@ -41,6 +40,7 @@ public class Assert { public static void assertEquals(String message, boolean expect, boolean actual) { org.junit.Assert - .assertEquals(message, valueOf(expect), valueOf(actual)); + .assertEquals(message, Boolean.valueOf(expect), + Boolean.valueOf(actual)); } } diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/FakeIndexFactory.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/FakeIndexFactory.java new file mode 100644 index 0000000000..eb23bec584 --- /dev/null +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/FakeIndexFactory.java @@ -0,0 +1,243 @@ +/* + * Copyright (C) 2025, Google Inc. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.junit; + +import static java.util.function.Function.identity; +import static java.util.stream.Collectors.toMap; +import static java.util.stream.Collectors.toUnmodifiableList; + +import java.io.IOException; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.eclipse.jgit.errors.CorruptObjectException; +import org.eclipse.jgit.errors.MissingObjectException; +import org.eclipse.jgit.internal.storage.file.PackIndex; +import org.eclipse.jgit.internal.storage.file.PackIndex.EntriesIterator; +import org.eclipse.jgit.internal.storage.file.PackReverseIndex; +import org.eclipse.jgit.lib.AbbreviatedObjectId; +import org.eclipse.jgit.lib.AnyObjectId; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.ObjectId; + +/** + * Create indexes with predefined data + * + * @since 7.2 + */ +public class FakeIndexFactory { + + /** + * An object for the fake index + * + * @param name + * a sha1 + * @param offset + * the (fake) position of the object in the pack + */ + public record IndexObject(String name, long offset) { + /** + * Name (sha1) as an objectId + * + * @return name (a sha1) as an objectId. + */ + public ObjectId getObjectId() { + return ObjectId.fromString(name); + } + } + + /** + * Return an index populated with these objects + * + * @param objs + * objects to be indexed + * @return a PackIndex implementation + */ + public static PackIndex indexOf(List<IndexObject> objs) { + return new FakePackIndex(objs); + } + + /** + * Return a reverse pack index with these objects + * + * @param objs + * objects to be indexed + * @return a PackReverseIndex implementation + */ + public static PackReverseIndex reverseIndexOf(List<IndexObject> objs) { + return new FakeReverseIndex(objs); + } + + private FakeIndexFactory() { + } + + private static class FakePackIndex implements PackIndex { + private static final Comparator<IndexObject> SHA1_COMPARATOR = (o1, + o2) -> String.CASE_INSENSITIVE_ORDER.compare(o1.name(), + o2.name()); + + private final Map<String, IndexObject> idx; + + private final List<IndexObject> sha1Ordered; + + private final long offset64count; + + FakePackIndex(List<IndexObject> objs) { + sha1Ordered = objs.stream().sorted(SHA1_COMPARATOR) + .collect(toUnmodifiableList()); + idx = objs.stream().collect(toMap(IndexObject::name, identity())); + offset64count = objs.stream() + .filter(o -> o.offset > Integer.MAX_VALUE).count(); + } + + @Override + public Iterator<MutableEntry> iterator() { + return new FakeEntriesIterator(sha1Ordered); + } + + @Override + public long getObjectCount() { + return sha1Ordered.size(); + } + + @Override + public long getOffset64Count() { + return offset64count; + } + + @Override + public ObjectId getObjectId(long nthPosition) { + return ObjectId + .fromString(sha1Ordered.get((int) nthPosition).name()); + } + + @Override + public long getOffset(long nthPosition) { + return sha1Ordered.get((int) nthPosition).offset(); + } + + @Override + public long findOffset(AnyObjectId objId) { + IndexObject o = idx.get(objId.name()); + if (o == null) { + return -1; + } + return o.offset(); + } + + @Override + public int findPosition(AnyObjectId objId) { + IndexObject o = idx.get(objId.name()); + if (o == null) { + return -1; + } + return sha1Ordered.indexOf(o); + } + + @Override + public long findCRC32(AnyObjectId objId) throws MissingObjectException { + throw new UnsupportedOperationException(); + } + + @Override + public boolean hasCRC32Support() { + return false; + } + + @Override + public void resolve(Set<ObjectId> matches, AbbreviatedObjectId id, + int matchLimit) throws IOException { + throw new UnsupportedOperationException(); + } + + @Override + public byte[] getChecksum() { + return new byte[0]; + } + } + + private static class FakeReverseIndex implements PackReverseIndex { + private static final Comparator<IndexObject> OFFSET_COMPARATOR = Comparator + .comparingLong(IndexObject::offset); + + private final List<IndexObject> byOffset; + + private final Map<Long, IndexObject> ridx; + + FakeReverseIndex(List<IndexObject> objs) { + byOffset = objs.stream().sorted(OFFSET_COMPARATOR) + .collect(toUnmodifiableList()); + ridx = byOffset.stream() + .collect(toMap(IndexObject::offset, identity())); + } + + @Override + public void verifyPackChecksum(String packFilePath) { + // Do nothing + } + + @Override + public ObjectId findObject(long offset) { + IndexObject indexObject = ridx.get(offset); + if (indexObject == null) { + return null; + } + return ObjectId.fromString(indexObject.name()); + } + + @Override + public long findNextOffset(long offset, long maxOffset) + throws CorruptObjectException { + IndexObject o = ridx.get(offset); + if (o == null) { + throw new CorruptObjectException("Invalid offset"); //$NON-NLS-1$ + } + int pos = byOffset.indexOf(o); + if (pos == byOffset.size() - 1) { + return maxOffset; + } + return byOffset.get(pos + 1).offset(); + } + + @Override + public int findPosition(long offset) { + IndexObject indexObject = ridx.get(offset); + return byOffset.indexOf(indexObject); + } + + @Override + public ObjectId findObjectByPosition(int nthPosition) { + return byOffset.get(nthPosition).getObjectId(); + } + } + + private static class FakeEntriesIterator extends EntriesIterator { + + private static final byte[] buffer = new byte[Constants.OBJECT_ID_LENGTH]; + + private final Iterator<IndexObject> it; + + FakeEntriesIterator(List<IndexObject> objs) { + super(objs.size()); + it = objs.iterator(); + } + + @Override + protected void readNext() { + IndexObject next = it.next(); + next.getObjectId().copyRawTo(buffer, 0); + setIdBuffer(buffer, 0); + setOffset(next.offset()); + } + } +} diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java index 61d3b860e9..177d8737cb 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/JGitTestUtil.java @@ -107,6 +107,7 @@ public abstract class JGitTestUtil { * Get test resource file. * * @param fileName + * file name * @return the test resource file */ public static File getTestResourceFile(String fileName) { @@ -141,8 +142,11 @@ public abstract class JGitTestUtil { * Copy test resource. * * @param name + * resource name * @param dest + * destination file * @throws IOException + * if an IO error occurred */ public static void copyTestResource(String name, File dest) throws IOException { @@ -165,10 +169,14 @@ public abstract class JGitTestUtil { * Write a trash file. * * @param db + * the repository * @param name + * file name * @param data + * file content * @return the trash file * @throws IOException + * if an IO error occurred */ public static File writeTrashFile(final Repository db, final String name, final String data) throws IOException { @@ -181,11 +189,16 @@ public abstract class JGitTestUtil { * Write a trash file. * * @param db + * the repository * @param subdir + * under working tree * @param name + * file name * @param data + * file content * @return the trash file * @throws IOException + * if an IO error occurred */ public static File writeTrashFile(final Repository db, final String subdir, @@ -237,9 +250,12 @@ public abstract class JGitTestUtil { * Read a file's content * * @param db + * the repository * @param name + * file name * @return the content of the file * @throws IOException + * if an IO error occurred */ public static String read(Repository db, String name) throws IOException { @@ -251,6 +267,7 @@ public abstract class JGitTestUtil { * Check if file exists * * @param db + * the repository * @param name * name of the file * @return {@code true} if the file exists @@ -264,8 +281,11 @@ public abstract class JGitTestUtil { * Delete a trash file. * * @param db + * the repository * @param name + * file name * @throws IOException + * if an IO error occurred */ public static void deleteTrashFile(final Repository db, final String name) throws IOException { @@ -284,6 +304,7 @@ public abstract class JGitTestUtil { * the target of the symbolic link * @return the path to the symbolic link * @throws Exception + * if an error occurred * @since 4.2 */ public static Path writeLink(Repository db, String link, diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java index 59662cec95..0d20f6488a 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java @@ -20,12 +20,13 @@ import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.time.Instant; -import java.util.ArrayList; +import java.time.ZoneId; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Random; import java.util.Set; import java.util.TreeSet; @@ -46,6 +47,7 @@ import org.eclipse.jgit.util.SystemReader; import org.junit.After; import org.junit.Before; import org.junit.Rule; +import org.junit.rules.TemporaryFolder; import org.junit.rules.TestName; /** @@ -83,8 +85,20 @@ public abstract class LocalDiskRepositoryTestCase { protected MockSystemReader mockSystemReader; private final Set<Repository> toClose = new HashSet<>(); + + /** + * Temporary test root directory for files created by tests. + * @since 7.2 + */ + @Rule + public TemporaryFolder testRoot = new TemporaryFolder(); + + Random rand = new Random(); + private File tmp; + private File homeDir; + /** * The current test name. * @@ -107,17 +121,23 @@ public abstract class LocalDiskRepositoryTestCase { * Setup test * * @throws Exception + * if an error occurred */ @Before public void setUp() throws Exception { - tmp = File.createTempFile("jgit_" + getTestName() + '_', "_tmp"); - CleanupThread.deleteOnShutdown(tmp); - if (!tmp.delete() || !tmp.mkdir()) { - throw new IOException("Cannot create " + tmp); - } + tmp = testRoot.newFolder(getTestName() + rand.nextInt()); + mockSystemReader = new MockSystemReader(); SystemReader.setInstance(mockSystemReader); + // Mock the home directory. We don't want to pick up the real user's git + // config, or global git ignore. + // XDG_CONFIG_HOME isn't set in the MockSystemReader. + mockSystemReader.setProperty("user.home", tmp.getAbsolutePath()); + mockSystemReader.setProperty("HOME", tmp.getAbsolutePath()); + homeDir = FS.DETECTED.userHome(); + FS.DETECTED.setUserHome(tmp.getAbsoluteFile()); + // Measure timer resolution before the test to avoid time critical tests // are affected by time needed for measurement. // The MockSystemReader must be configured first since we need to use @@ -189,25 +209,24 @@ public abstract class LocalDiskRepositoryTestCase { * Tear down the test * * @throws Exception + * if an error occurred */ @After public void tearDown() throws Exception { RepositoryCache.clear(); - for (Repository r : toClose) + for (Repository r : toClose) { r.close(); + } toClose.clear(); // Since memory mapping is controlled by the GC we need to // tell it this is a good time to clean up and unlock // memory mapped files. // - if (useMMAP) + if (useMMAP) { System.gc(); - if (tmp != null) - recursiveDelete(tmp, false, true); - if (tmp != null && !tmp.exists()) - CleanupThread.removed(tmp); - + } + FS.DETECTED.setUserHome(homeDir); SystemReader.setInstance(null); } @@ -216,8 +235,8 @@ public abstract class LocalDiskRepositoryTestCase { */ protected void tick() { mockSystemReader.tick(5 * 60); - final long now = mockSystemReader.getCurrentTime(); - final int tz = mockSystemReader.getTimezone(now); + Instant now = mockSystemReader.now(); + ZoneId tz = mockSystemReader.getTimeZoneId(); author = new PersonIdent(author, now, tz); committer = new PersonIdent(committer, now, tz); @@ -314,11 +333,11 @@ public abstract class LocalDiskRepositoryTestCase { * {@link #CONTENT} controlling which info is present in the * resulting string. * @return a string encoding the index state - * @throws IllegalStateException * @throws IOException + * if an IO error occurred */ public static String indexState(Repository repo, int includedOptions) - throws IllegalStateException, IOException { + throws IOException { DirCache dc = repo.readDirCache(); StringBuilder sb = new StringBuilder(); TreeSet<Instant> timeStamps = new TreeSet<>(); @@ -452,6 +471,7 @@ public abstract class LocalDiskRepositoryTestCase { * a subdirectory * @return a unique directory for a test * @throws IOException + * if an IO error occurred */ protected File createTempDirectory(String name) throws IOException { File directory = new File(createTempFile(), name); @@ -467,6 +487,7 @@ public abstract class LocalDiskRepositoryTestCase { * working directory * @return a unique directory for a test repository * @throws IOException + * if an IO error occurred */ protected File createUniqueTestGitDir(boolean bare) throws IOException { String gitdirName = createTempFile().getPath(); @@ -487,6 +508,7 @@ public abstract class LocalDiskRepositoryTestCase { * * @return a unique path that does not exist. * @throws IOException + * if an IO error occurred */ protected File createTempFile() throws IOException { File p = File.createTempFile("tmp_", "", tmp); @@ -586,6 +608,7 @@ public abstract class LocalDiskRepositoryTestCase { * the file * @return the content of the file * @throws IOException + * if an IO error occurred */ protected String read(File f) throws IOException { return JGitTestUtil.read(f); @@ -602,42 +625,4 @@ public abstract class LocalDiskRepositoryTestCase { private static HashMap<String, String> cloneEnv() { return new HashMap<>(System.getenv()); } - - private static final class CleanupThread extends Thread { - private static final CleanupThread me; - static { - me = new CleanupThread(); - Runtime.getRuntime().addShutdownHook(me); - } - - static void deleteOnShutdown(File tmp) { - synchronized (me) { - me.toDelete.add(tmp); - } - } - - static void removed(File tmp) { - synchronized (me) { - me.toDelete.remove(tmp); - } - } - - private final List<File> toDelete = new ArrayList<>(); - - @Override - public void run() { - // On windows accidentally open files or memory - // mapped regions may prevent files from being deleted. - // Suggesting a GC increases the likelihood that our - // test repositories actually get removed after the - // tests, even in the case of failure. - System.gc(); - synchronized (this) { - boolean silent = false; - boolean failOnError = false; - for (File tmp : toDelete) - recursiveDelete(tmp, silent, failOnError); - } - } - } } diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java index 6bfe70659b..38f0d0b2cb 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java @@ -18,6 +18,8 @@ import java.lang.reflect.Field; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.time.Duration; +import java.time.ZoneId; +import java.time.ZoneOffset; import java.util.HashMap; import java.util.Locale; import java.util.Map; @@ -144,32 +146,30 @@ public class MockSystemReader extends SystemReader { * Set a property * * @param key + * the key * @param value + * the value */ public void setProperty(String key, String value) { values.put(key, value); } - /** {@inheritDoc} */ @Override public String getenv(String variable) { return values.get(variable); } - /** {@inheritDoc} */ @Override public String getProperty(String key) { return values.get(key); } - /** {@inheritDoc} */ @Override public FileBasedConfig openUserConfig(Config parent, FS fs) { assert parent == null || parent == systemGitConfig; return userGitConfig; } - /** {@inheritDoc} */ @Override public FileBasedConfig openSystemConfig(Config parent, FS fs) { assert parent == null; @@ -193,19 +193,16 @@ public class MockSystemReader extends SystemReader { return systemGitConfig; } - /** {@inheritDoc} */ @Override public String getHostname() { return "fake.host.example.com"; } - /** {@inheritDoc} */ @Override public long getCurrentTime() { return now; } - /** {@inheritDoc} */ @Override public MonotonicClock getClock() { return () -> { @@ -236,31 +233,31 @@ public class MockSystemReader extends SystemReader { now += secDelta * 1000L; } - /** {@inheritDoc} */ @Override public int getTimezone(long when) { return getTimeZone().getOffset(when) / (60 * 1000); } - /** {@inheritDoc} */ @Override public TimeZone getTimeZone() { return TimeZone.getTimeZone("GMT-03:30"); } - /** {@inheritDoc} */ + @Override + public ZoneId getTimeZoneId() { + return ZoneOffset.ofHoursMinutes(-3, -30); + } + @Override public Locale getLocale() { return Locale.US; } - /** {@inheritDoc} */ @Override public SimpleDateFormat getSimpleDateFormat(String pattern) { return new SimpleDateFormat(pattern, getLocale()); } - /** {@inheritDoc} */ @Override public DateFormat getDateTimeInstance(int dateStyle, int timeStyle) { return DateFormat @@ -312,7 +309,7 @@ public class MockSystemReader extends SystemReader { field.setAccessible(true); field.set(null, null); } catch (Exception e) { - e.printStackTrace(); + throw new RuntimeException(e); } } diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/Repeat.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/Repeat.java index 343aa92f8a..4bf2eb59da 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/Repeat.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/Repeat.java @@ -21,6 +21,8 @@ import java.lang.annotation.Target; public @interface Repeat { /** * Number of repetitions + * + * @return number of repetitions */ public abstract int n(); diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepeatRule.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepeatRule.java index adcc10cad8..30fffe9d94 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepeatRule.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepeatRule.java @@ -125,7 +125,6 @@ public class RepeatRule implements TestRule { } } - /** {@inheritDoc} */ @Override public Statement apply(Statement statement, Description description) { Statement result = statement; diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java index 04988f6289..3a283ce10d 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java @@ -62,8 +62,11 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { * Copy a file * * @param src + * file to copy * @param dst + * destination of the copy * @throws IOException + * if an IO error occurred */ protected static void copyFile(File src, File dst) throws IOException { @@ -81,9 +84,12 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { * Write a trash file * * @param name + * file name * @param data + * file content * @return the trash file * @throws IOException + * if an IO error occurred */ protected File writeTrashFile(String name, String data) throws IOException { @@ -99,6 +105,7 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { * the target of the symbolic link * @return the path to the symbolic link * @throws Exception + * if an error occurred * @since 4.2 */ protected Path writeLink(String link, String target) @@ -110,10 +117,14 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { * Write a trash file * * @param subdir + * in working tree * @param name + * file name * @param data + * file content * @return the trash file * @throws IOException + * if an IO error occurred */ protected File writeTrashFile(final String subdir, final String name, final String data) @@ -125,8 +136,10 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { * Read content of a file * * @param name + * file name * @return the file's content * @throws IOException + * if an IO error occurred */ protected String read(String name) throws IOException { return JGitTestUtil.read(db, name); @@ -149,6 +162,7 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { * @param name * file name * @throws IOException + * if an IO error occurred */ protected void deleteTrashFile(String name) throws IOException { JGitTestUtil.deleteTrashFile(db, name); @@ -158,9 +172,11 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { * Check content of a file. * * @param f + * file * @param checkData * expected content * @throws IOException + * if an IO error occurred */ protected static void checkFile(File f, String checkData) throws IOException { @@ -181,7 +197,6 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { /** Working directory of {@link #db}. */ protected File trash; - /** {@inheritDoc} */ @Override @Before public void setUp() throws Exception { @@ -229,11 +244,11 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { * {@link #CONTENT} controlling which info is present in the * resulting string. * @return a string encoding the index state - * @throws IllegalStateException * @throws IOException + * if an IO error occurred */ public String indexState(int includedOptions) - throws IllegalStateException, IOException { + throws IOException { return indexState(db, includedOptions); } @@ -251,7 +266,9 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { * a {@link org.eclipse.jgit.treewalk.FileTreeIterator} which * determines which files should go into the new index * @throws FileNotFoundException + * file was not found * @throws IOException + * if an IO error occurred */ protected void resetIndex(FileTreeIterator treeItr) throws FileNotFoundException, IOException { @@ -339,7 +356,9 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { * @return return the last measured value of the filesystem timer which is * greater than then the lastmodification time of lastfile. * @throws InterruptedException + * if thread was interrupted * @throws IOException + * if an IO error occurred * @since 5.1.9 */ public static Instant fsTick(File lastFile) @@ -378,8 +397,11 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { * Create a branch * * @param objectId + * new value to create the branch on * @param branchName + * branch name * @throws IOException + * if an IO error occurred */ protected void createBranch(ObjectId objectId, String branchName) throws IOException { @@ -393,6 +415,7 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { * * @return list of refs * @throws IOException + * if an IO error occurred */ public List<Ref> getRefs() throws IOException { return db.getRefDatabase().getRefs(); @@ -402,11 +425,12 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { * Checkout a branch * * @param branchName - * @throws IllegalStateException + * branch name * @throws IOException + * if an IO error occurred */ protected void checkoutBranch(String branchName) - throws IllegalStateException, IOException { + throws IOException { try (RevWalk walk = new RevWalk(db)) { RevCommit head = walk.parseCommit(db.resolve(Constants.HEAD)); RevCommit branch = walk.parseCommit(db.resolve(branchName)); @@ -436,7 +460,9 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { * the contents which should be written into the files * @return the File object associated to the last written file. * @throws IOException + * if an IO error occurred * @throws InterruptedException + * if thread was interrupted */ protected File writeTrashFiles(boolean ensureDistinctTimestamps, String... contents) @@ -459,8 +485,11 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { * one. * * @param filename + * file name * @param contents + * file content * @param branch + * branch name * @return the created commit */ protected RevCommit commitFile(String filename, String contents, String branch) { @@ -494,7 +523,9 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { * Create <code>DirCacheEntry</code> * * @param path + * file path * @param mode + * file mode * @return the DirCacheEntry */ protected DirCacheEntry createEntry(String path, FileMode mode) { @@ -505,8 +536,11 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { * Create <code>DirCacheEntry</code> * * @param path + * file path * @param mode + * file mode * @param content + * file content * @return the DirCacheEntry */ protected DirCacheEntry createEntry(final String path, final FileMode mode, @@ -518,9 +552,13 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { * Create <code>DirCacheEntry</code> * * @param path + * file path * @param mode + * file mode * @param stage + * stage index of the new entry * @param content + * file content * @return the DirCacheEntry */ protected DirCacheEntry createEntry(final String path, final FileMode mode, @@ -538,7 +576,9 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { * Create <code>DirCacheEntry</code> * * @param path + * file path * @param objectId + * of the entry * @return the DirCacheEntry */ protected DirCacheEntry createGitLink(String path, AnyObjectId objectId) { @@ -553,8 +593,11 @@ public abstract class RepositoryTestCase extends LocalDiskRepositoryTestCase { * Assert files are equal * * @param expected + * expected file * @param actual + * actual file * @throws IOException + * if an IO error occurred */ public static void assertEqualsFile(File expected, File actual) throws IOException { diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/SeparateClassloaderTestRunner.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/SeparateClassloaderTestRunner.java index c8c56b21b8..2a482df04a 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/SeparateClassloaderTestRunner.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/SeparateClassloaderTestRunner.java @@ -44,7 +44,7 @@ public class SeparateClassloaderTestRunner extends BlockJUnit4ClassRunner { try { String pathSeparator = System.getProperty("path.separator"); String[] classPathEntries = System.getProperty("java.class.path") - .split(pathSeparator); + .split(pathSeparator, -1); URL[] urls = new URL[classPathEntries.length]; for (int i = 0; i < classPathEntries.length; i++) { urls[i] = Paths.get(classPathEntries[i]).toUri().toURL(); diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/StrictWorkMonitor.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/StrictWorkMonitor.java index c77bca9751..0168ecea30 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/StrictWorkMonitor.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/StrictWorkMonitor.java @@ -20,32 +20,27 @@ import org.eclipse.jgit.lib.ProgressMonitor; public final class StrictWorkMonitor implements ProgressMonitor { private int lastWork, totalWork; - /** {@inheritDoc} */ @Override public void start(int totalTasks) { // empty } - /** {@inheritDoc} */ @Override public void beginTask(String title, int total) { this.totalWork = total; lastWork = 0; } - /** {@inheritDoc} */ @Override public void update(int completed) { lastWork += completed; } - /** {@inheritDoc} */ @Override public void endTask() { assertEquals("Units of work recorded", totalWork, lastWork); } - /** {@inheritDoc} */ @Override public boolean isCancelled() { return false; diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java index 483b9a7c81..c546ae9082 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java @@ -20,6 +20,8 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; import java.security.MessageDigest; +import java.time.Instant; +import java.time.ZoneId; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -29,6 +31,7 @@ import java.util.List; import java.util.Set; import java.util.TimeZone; +import org.eclipse.jgit.annotations.Nullable; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.dircache.DirCache; import org.eclipse.jgit.dircache.DirCacheBuilder; @@ -70,6 +73,7 @@ import org.eclipse.jgit.revwalk.RevObject; import org.eclipse.jgit.revwalk.RevTag; import org.eclipse.jgit.revwalk.RevTree; import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.storage.pack.PackConfig; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.treewalk.filter.PathFilterGroup; import org.eclipse.jgit.util.ChangeIdUtil; @@ -115,6 +119,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * @param db * the test repository to write into. * @throws IOException + * if an IO error occurred */ public TestRepository(R db) throws IOException { this(db, new RevWalk(db), new MockSystemReader()); @@ -128,6 +133,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * @param rw * the RevObject pool to use for object lookup. * @throws IOException + * if an IO error occurred */ public TestRepository(R db, RevWalk rw) throws IOException { this(db, rw, new MockSystemReader()); @@ -144,6 +150,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * the MockSystemReader to use for clock and other system * operations. * @throws IOException + * if an IO error occurred * @since 4.2 */ public TestRepository(R db, RevWalk rw, MockSystemReader reader) @@ -153,8 +160,8 @@ public class TestRepository<R extends Repository> implements AutoCloseable { this.pool = rw; this.inserter = db.newObjectInserter(); this.mockSystemReader = reader; - long now = mockSystemReader.getCurrentTime(); - int tz = mockSystemReader.getTimezone(now); + Instant now = mockSystemReader.now(); + ZoneId tz = mockSystemReader.getTimeZoneAt(now); defaultAuthor = new PersonIdent(AUTHOR, AUTHOR_EMAIL, now, tz); defaultCommitter = new PersonIdent(COMMITTER, COMMITTER_EMAIL, now, tz); } @@ -193,20 +200,45 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * * @return current date. * @since 4.2 + * @deprecated Use {@link #getInstant()} instead. */ + @Deprecated(since = "7.2") public Date getDate() { return new Date(mockSystemReader.getCurrentTime()); } /** + * Get instant + * + * @return current instant. + * @since 6.8 + */ + public Instant getInstant() { + return mockSystemReader.now(); + } + + /** * Get timezone * * @return timezone used for default identities. + * @deprecated Use {@link #getTimeZoneId()} instead. */ + @Deprecated(since = "7.2") public TimeZone getTimeZone() { return mockSystemReader.getTimeZone(); } + + /** + * Get timezone + * + * @return timezone used for default identities. + * @since 7.2 + */ + public ZoneId getTimeZoneId() { + return mockSystemReader.getTimeZoneId(); + } + /** * Adjust the current time that will used by the next commit. * @@ -218,14 +250,14 @@ public class TestRepository<R extends Repository> implements AutoCloseable { } /** - * Set the author and committer using {@link #getDate()}. + * Set the author and committer using {@link #getInstant()}. * * @param c * the commit builder to store. */ public void setAuthorAndCommitter(org.eclipse.jgit.lib.CommitBuilder c) { - c.setAuthor(new PersonIdent(defaultAuthor, getDate())); - c.setCommitter(new PersonIdent(defaultCommitter, getDate())); + c.setAuthor(new PersonIdent(defaultAuthor, getInstant())); + c.setCommitter(new PersonIdent(defaultCommitter, getInstant())); } /** @@ -235,6 +267,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * file content, will be UTF-8 encoded. * @return reference to the blob. * @throws Exception + * if an error occurred */ public RevBlob blob(String content) throws Exception { return blob(content.getBytes(UTF_8)); @@ -247,6 +280,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * binary file content. * @return the new, fully parsed blob. * @throws Exception + * if an error occurred */ public RevBlob blob(byte[] content) throws Exception { ObjectId id; @@ -266,6 +300,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * a blob, previously constructed in the repository. * @return the entry. * @throws Exception + * if an error occurred */ public DirCacheEntry file(String path, RevBlob blob) throws Exception { @@ -284,6 +319,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * a blob, previously constructed in the repository. * @return the entry. * @throws Exception + * if an error occurred * @since 6.3 */ public DirCacheEntry link(String path, RevBlob blob) throws Exception { @@ -301,6 +337,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * to be sorted properly and may be empty. * @return the new, fully parsed tree specified by the entry list. * @throws Exception + * if an error occurred */ public RevTree tree(DirCacheEntry... entries) throws Exception { final DirCache dc = DirCache.newInCore(); @@ -326,6 +363,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * the path to find the entry of. * @return the parsed object entry at this path, never null. * @throws Exception + * if an error occurred */ public RevObject get(RevTree tree, String path) throws Exception { @@ -357,6 +395,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * zero or more IDs of the commit's parents. * @return the ID of the new commit. * @throws Exception + * if an error occurred * @since 5.5 */ public ObjectId unparsedCommit(ObjectId... parents) throws Exception { @@ -373,6 +412,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * zero or more parents of the commit. * @return the new commit. * @throws Exception + * if an error occurred */ public RevCommit commit(RevCommit... parents) throws Exception { return commit(1, tree(), parents); @@ -389,6 +429,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * zero or more parents of the commit. * @return the new commit. * @throws Exception + * if an error occurred */ public RevCommit commit(RevTree tree, RevCommit... parents) throws Exception { @@ -407,6 +448,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * zero or more parents of the commit. * @return the new commit. * @throws Exception + * if an error occurred */ public RevCommit commit(int secDelta, RevCommit... parents) throws Exception { @@ -428,6 +470,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * zero or more parents of the commit. * @return the new, fully parsed commit. * @throws Exception + * if an error occurred */ public RevCommit commit(final int secDelta, final RevTree tree, final RevCommit... parents) throws Exception { @@ -450,6 +493,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * zero or more IDs of the commit's parents. * @return the ID of the new commit. * @throws Exception + * if an error occurred * @since 5.5 */ public ObjectId unparsedCommit(final int secDelta, final RevTree tree, @@ -461,8 +505,8 @@ public class TestRepository<R extends Repository> implements AutoCloseable { c = new org.eclipse.jgit.lib.CommitBuilder(); c.setTreeId(tree); c.setParentIds(parents); - c.setAuthor(new PersonIdent(defaultAuthor, getDate())); - c.setCommitter(new PersonIdent(defaultCommitter, getDate())); + c.setAuthor(new PersonIdent(defaultAuthor, getInstant())); + c.setCommitter(new PersonIdent(defaultCommitter, getInstant())); c.setMessage(""); ObjectId id; try (ObjectInserter ins = inserter) { @@ -496,12 +540,13 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * object the tag should be pointed at. * @return the new, fully parsed annotated tag object. * @throws Exception + * if an error occurred */ public RevTag tag(String name, RevObject dst) throws Exception { final TagBuilder t = new TagBuilder(); t.setObjectId(dst); t.setTag(name); - t.setTagger(new PersonIdent(defaultCommitter, getDate())); + t.setTagger(new PersonIdent(defaultCommitter, getInstant())); t.setMessage(""); ObjectId id; try (ObjectInserter ins = inserter) { @@ -524,6 +569,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * the target object. * @return the target object. * @throws Exception + * if an error occurred */ public RevCommit update(String ref, CommitBuilder to) throws Exception { return update(ref, to.create()); @@ -534,12 +580,13 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * * @param ref * the name of the reference to amend, which must already exist. - * If {@code ref} does not start with {@code refs/} and is not the - * magic names {@code HEAD} {@code FETCH_HEAD} or {@code - * MERGE_HEAD}, then {@code refs/heads/} will be prefixed in front - * of the given name, thereby assuming it is a branch. + * If {@code ref} does not start with {@code refs/} and is not + * the magic names {@code HEAD} {@code FETCH_HEAD} or {@code + * MERGE_HEAD}, then {@code refs/heads/} will be prefixed in + * front of the given name, thereby assuming it is a branch. * @return commit builder that amends the branch on commit. * @throws Exception + * if an error occurred */ public CommitBuilder amendRef(String ref) throws Exception { String name = normalizeRef(ref); @@ -556,6 +603,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * the id of the commit to amend. * @return commit builder. * @throws Exception + * if an error occurred */ public CommitBuilder amend(AnyObjectId id) throws Exception { return amend(pool.parseCommit(id), commit()); @@ -610,6 +658,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * the target object. * @return the target object. * @throws Exception + * if an error occurred */ public <T extends AnyObjectId> T update(String ref, T obj) throws Exception { ref = normalizeRef(ref); @@ -632,9 +681,10 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * Delete a reference. * * @param ref - * the name of the reference to delete. This is normalized - * in the same way as {@link #update(String, AnyObjectId)}. + * the name of the reference to delete. This is normalized in the + * same way as {@link #update(String, AnyObjectId)}. * @throws Exception + * if an error occurred * @since 4.4 */ public void delete(String ref) throws Exception { @@ -674,6 +724,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * @param id * ID of detached head. * @throws Exception + * if an error occurred * @see #reset(String) */ public void reset(AnyObjectId id) throws Exception { @@ -695,13 +746,14 @@ public class TestRepository<R extends Repository> implements AutoCloseable { /** * Soft-reset HEAD to a different commit. * <p> - * This is equivalent to {@code git reset --soft} in that it modifies HEAD but - * not the index or the working tree of a non-bare repository. + * This is equivalent to {@code git reset --soft} in that it modifies HEAD + * but not the index or the working tree of a non-bare repository. * * @param name - * revision string; either an existing ref name, or something that - * can be parsed to an object ID. + * revision string; either an existing ref name, or something + * that can be parsed to an object ID. * @throws Exception + * if an error occurred */ public void reset(String name) throws Exception { RefUpdate.Result result; @@ -735,6 +787,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * @return the new, fully parsed commit, or null if no work was done due to * the resulting tree being identical. * @throws Exception + * if an error occurred */ public RevCommit cherryPick(AnyObjectId id) throws Exception { RevCommit commit = pool.parseCommit(id); @@ -762,7 +815,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { b.setParentId(head); b.setTreeId(merger.getResultTreeId()); b.setAuthor(commit.getAuthorIdent()); - b.setCommitter(new PersonIdent(defaultCommitter, getDate())); + b.setCommitter(new PersonIdent(defaultCommitter, getInstant())); b.setMessage(commit.getFullMessage()); ObjectId result; try (ObjectInserter ins = inserter) { @@ -779,6 +832,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * Update the dumb client server info files. * * @throws Exception + * if an error occurred */ public void updateServerInfo() throws Exception { if (db instanceof FileRepository) { @@ -816,6 +870,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * parsing of. * @return {@code object} * @throws Exception + * if an error occurred */ public <T extends RevObject> T parseBody(T object) throws Exception { pool.parseBody(object); @@ -851,6 +906,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * the object to tag * @return the tagged object * @throws Exception + * if an error occurred */ public ObjectId lightweightTag(String name, ObjectId obj) throws Exception { if (!name.startsWith(Constants.R_TAGS)) @@ -868,8 +924,11 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * the tips to start checking from; if not supplied the refs of * the repository are used instead. * @throws MissingObjectException + * if object is missing * @throws IncorrectObjectTypeException + * if object has unexpected type * @throws IOException + * if an IO error occurred */ public void fsck(RevObject... tips) throws MissingObjectException, IncorrectObjectTypeException, IOException { @@ -922,13 +981,14 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * not removed. * * @throws Exception + * if an error occurred */ public void packAndPrune() throws Exception { if (db.getObjectDatabase() instanceof ObjectDirectory) { ObjectDirectory odb = (ObjectDirectory) db.getObjectDatabase(); NullProgressMonitor m = NullProgressMonitor.INSTANCE; - final PackFile pack, idx; + PackFile pack; try (PackWriter pw = new PackWriter(db)) { Set<ObjectId> all = new HashSet<>(); for (Ref r : db.getRefDatabase().getRefs()) @@ -943,12 +1003,22 @@ public class TestRepository<R extends Repository> implements AutoCloseable { } pack.setReadOnly(); - idx = pack.create(PackExt.INDEX); + PackFile idx = pack.create(PackExt.INDEX); try (OutputStream out = new BufferedOutputStream(new FileOutputStream(idx))) { pw.writeIndex(out); } idx.setReadOnly(); + + PackConfig pc = new PackConfig(db); + if (pc.getMinBytesForObjSizeIndex() >= 0) { + PackFile oidx = pack.create(PackExt.OBJECT_SIZE_INDEX); + try (OutputStream out = new BufferedOutputStream( + new FileOutputStream(oidx))) { + pw.writeObjectSizeIndex(out); + } + oidx.setReadOnly(); + } } odb.openPack(pack); @@ -977,7 +1047,8 @@ public class TestRepository<R extends Repository> implements AutoCloseable { private static void prunePacked(ObjectDirectory odb) throws IOException { for (Pack p : odb.getPacks()) { for (MutableEntry e : p) - FileUtils.delete(odb.fileFor(e.toObjectId())); + FileUtils.delete(odb.fileFor(e.toObjectId()), + FileUtils.SKIP_MISSING); } } @@ -1004,6 +1075,8 @@ public class TestRepository<R extends Repository> implements AutoCloseable { } /** + * Create commit builder + * * @return construct a new commit builder that updates this branch. If * the branch already exists, the commit builder will have its * first parent as the current commit and its tree will be @@ -1022,6 +1095,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * the commit to update to. * @return {@code to}. * @throws Exception + * if an error occurred */ public RevCommit update(CommitBuilder to) throws Exception { return update(to.create()); @@ -1034,6 +1108,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * the commit to update to. * @return {@code to}. * @throws Exception + * if an error occurred */ public RevCommit update(RevCommit to) throws Exception { return TestRepository.this.update(ref, to); @@ -1041,7 +1116,9 @@ public class TestRepository<R extends Repository> implements AutoCloseable { /** * Delete this branch. + * * @throws Exception + * if an error occurred * @since 4.4 */ public void delete() throws Exception { @@ -1096,14 +1173,18 @@ public class TestRepository<R extends Repository> implements AutoCloseable { } /** - * set parent commit + * Set parent commit * * @param p - * parent commit + * parent commit, can be {@code null} * @return this commit builder * @throws Exception + * if an error occurred */ - public CommitBuilder parent(RevCommit p) throws Exception { + public CommitBuilder parent(@Nullable RevCommit p) throws Exception { + if (p == null) { + return this; + } if (parents.isEmpty()) { DirCacheBuilder b = tree.builder(); parseBody(p); @@ -1165,6 +1246,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * the file content * @return this commit builder * @throws Exception + * if an error occurred */ public CommitBuilder add(String path, String content) throws Exception { return add(path, blob(content)); @@ -1179,6 +1261,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * blob for this file * @return this commit builder * @throws Exception + * if an error occurred */ public CommitBuilder add(String path, RevBlob id) throws Exception { @@ -1352,7 +1435,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { c.setAuthor(author); if (committer != null) { if (updateCommitterTime) - committer = new PersonIdent(committer, getDate()); + committer = new PersonIdent(committer, getInstant()); c.setCommitter(committer); } @@ -1404,6 +1487,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable { * * @return child commit builder * @throws Exception + * if an error occurred */ public CommitBuilder child() throws Exception { return new CommitBuilder(this); diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/time/MonotonicFakeClock.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/time/MonotonicFakeClock.java index e5338d36cd..31db6a2c7b 100644 --- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/time/MonotonicFakeClock.java +++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/time/MonotonicFakeClock.java @@ -40,7 +40,6 @@ public class MonotonicFakeClock implements MonotonicClock { now += unit.toMillis(add); } - /** {@inheritDoc} */ @Override public ProposedTimestamp propose() { long t = now++; |