aboutsummaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.junit/src/org
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit.junit/src/org')
-rw-r--r--org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/FakeIndexFactory.java243
-rw-r--r--org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java69
-rw-r--r--org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/MockSystemReader.java7
-rw-r--r--org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/SeparateClassloaderTestRunner.java2
-rw-r--r--org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java51
5 files changed, 304 insertions, 68 deletions
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/LocalDiskRepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/LocalDiskRepositoryTestCase.java
index 407290a399..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,19 +20,19 @@ import java.io.File;
import java.io.IOException;
import java.io.PrintStream;
import java.time.Instant;
+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;
-import java.util.concurrent.ConcurrentHashMap;
import org.eclipse.jgit.dircache.DirCache;
import org.eclipse.jgit.dircache.DirCacheEntry;
import org.eclipse.jgit.internal.storage.file.FileRepository;
-import org.eclipse.jgit.internal.util.ShutdownHook;
import org.eclipse.jgit.lib.ConfigConstants;
import org.eclipse.jgit.lib.Constants;
import org.eclipse.jgit.lib.ObjectId;
@@ -47,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;
/**
@@ -84,6 +85,16 @@ 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;
@@ -114,11 +125,8 @@ public abstract class LocalDiskRepositoryTestCase {
*/
@Before
public void setUp() throws Exception {
- tmp = File.createTempFile("jgit_" + getTestName() + '_', "_tmp");
- Cleanup.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);
@@ -219,12 +227,6 @@ public abstract class LocalDiskRepositoryTestCase {
System.gc();
}
FS.DETECTED.setUserHome(homeDir);
- if (tmp != null) {
- recursiveDelete(tmp, false, true);
- }
- if (tmp != null && !tmp.exists()) {
- Cleanup.removed(tmp);
- }
SystemReader.setInstance(null);
}
@@ -233,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);
@@ -623,41 +625,4 @@ public abstract class LocalDiskRepositoryTestCase {
private static HashMap<String, String> cloneEnv() {
return new HashMap<>(System.getenv());
}
-
- private static final class Cleanup {
- private static final Cleanup INSTANCE = new Cleanup();
-
- static {
- ShutdownHook.INSTANCE.register(() -> INSTANCE.onShutdown());
- }
-
- private final Set<File> toDelete = ConcurrentHashMap.newKeySet();
-
- private Cleanup() {
- // empty
- }
-
- static void deleteOnShutdown(File tmp) {
- INSTANCE.toDelete.add(tmp);
- }
-
- static void removed(File tmp) {
- INSTANCE.toDelete.remove(tmp);
- }
-
- private void onShutdown() {
- // 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 419fdb1966..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;
@@ -242,6 +244,11 @@ public class MockSystemReader extends SystemReader {
}
@Override
+ public ZoneId getTimeZoneId() {
+ return ZoneOffset.ofHoursMinutes(-3, -30);
+ }
+
+ @Override
public Locale getLocale() {
return Locale.US;
}
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/TestRepository.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
index a2e0a571eb..2d00a850e5 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
@@ -21,6 +21,7 @@ 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;
@@ -30,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;
@@ -157,8 +159,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);
}
@@ -197,7 +199,9 @@ 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());
}
@@ -209,18 +213,31 @@ public class TestRepository<R extends Repository> implements AutoCloseable {
* @since 6.8
*/
public Instant getInstant() {
- return Instant.ofEpochMilli(mockSystemReader.getCurrentTime());
+ 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.
*
@@ -232,14 +249,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()));
}
/**
@@ -487,8 +504,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) {
@@ -528,7 +545,7 @@ public class TestRepository<R extends Repository> implements AutoCloseable {
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) {
@@ -797,7 +814,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) {
@@ -1019,7 +1036,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);
}
}
@@ -1144,15 +1162,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);
@@ -1403,7 +1424,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);
}