summaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.test/tst
diff options
context:
space:
mode:
authorGit Development Community <git@vger.kernel.org>2009-09-29 16:47:03 -0700
committerShawn O. Pearce <spearce@spearce.org>2009-09-29 16:47:03 -0700
commit1a6964c8274c50f0253db75f010d78ef0e739343 (patch)
treeca833cc7cf6fc8c7b9850dee258f3a356c790ffc /org.eclipse.jgit.test/tst
downloadjgit-1a6964c8274c50f0253db75f010d78ef0e739343.tar.gz
jgit-1a6964c8274c50f0253db75f010d78ef0e739343.zip
Initial JGit contribution to eclipse.org
Per CQ 3448 this is the initial contribution of the JGit project to eclipse.org. It is derived from the historical JGit repository at commit 3a2dd9921c8a08740a9e02c421469e5b1a9e47cb. Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
Diffstat (limited to 'org.eclipse.jgit.test/tst')
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterReflowTest.java183
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditListTest.java127
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditTest.java146
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RawTextTest.java100
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBasicTest.java197
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderIteratorTest.java97
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java259
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java219
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheFindTest.java92
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheIteratorTest.java275
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheLargePathTest.java112
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheTreeTest.java189
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/fnmatch/FileNameMatcherTest.java764
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/AbbreviatedObjectIdTest.java351
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConcurrentRepackTest.java264
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConstantsEncodingTest.java95
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java191
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexTreeWalkerTest.java152
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/MockSystemReader.java97
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java1331
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PackIndexTestCase.java168
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PackIndexV1Test.java82
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PackIndexV2Test.java93
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PackReverseIndexTest.java121
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PackWriterTest.java533
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReadTreeTest.java581
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java166
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefUpdateTest.java768
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogReaderTest.java176
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryCacheTest.java132
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryConfigTest.java259
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryTestCase.java347
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_ObjectId.java111
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_PersonIdent.java111
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0002_Tree.java287
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0003_Basic.java581
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0004_PackReader.java114
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0007_Index.java455
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0008_testparserev.java142
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/TreeIteratorLeafOnlyTest.java129
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/TreeIteratorPostOrderTest.java147
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/TreeIteratorPreOrderTest.java147
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ValidRefNameTest.java177
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/WindowCacheGetTest.java149
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/WindowCacheReconfigureTest.java125
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/WorkDirCheckoutTest.java133
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/XInputStream.java88
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/empty.gitindex.datbin0 -> 32 bytes
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/sorttest.gitindex.datbin0 -> 288 bytes
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CherryPickTest.java156
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java391
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/EditListTest.java101
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/FileHeaderTest.java434
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/GetTextTest.java148
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcErrorTest.java103
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcTest.java206
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchErrorTest.java180
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchTest.java358
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/AlwaysEmptyRevQueueTest.java69
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/DateRevQueueTest.java124
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FIFORevQueueTest.java87
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FooterLineTest.java323
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/LIFORevQueueTest.java75
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java196
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java321
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevFlagSetTest.java137
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevObjectTest.java177
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevQueueTestCase.java91
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java356
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkCullTest.java100
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFilterTest.java297
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkMergeBaseTest.java139
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter1Test.java182
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter6012Test.java168
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkSortTest.java168
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java183
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java160
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/IndexPackTest.java123
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/LongMapTest.java138
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/OpenSshConfigTest.java228
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineInTest.java268
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineOutTest.java181
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushProcessTest.java418
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java275
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RemoteConfigTest.java432
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandOutputStreamTest.java152
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportTest.java197
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java247
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/AbstractTreeIteratorTest.java169
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/CanonicalTreeParserTest.java353
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/EmptyTreeIteratorTest.java112
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java173
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/NameConflictTreeWalkTest.java211
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/PostOrderTreeWalkTest.java195
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkBasicDiffTest.java122
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/AlwaysCloneTreeFilter.java63
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/NotTreeFilterTest.java91
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathSuffixFilterTestCase.java139
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/TreeFilterTest.java80
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/IntListTest.java162
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/JGitTestUtil.java79
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/NBTest.java334
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringBourneStyleTest.java117
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringBourneUserPathStyleTest.java136
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringGitPathStyleTest.java187
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_HexParseTest.java164
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_LineMapTest.java98
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_MatchTest.java75
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/StringUtilsTest.java84
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/TemporaryBufferTest.java380
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/TestRng.java67
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/TimeoutInputStreamTest.java189
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/TimeoutOutputStreamTest.java285
113 files changed, 23717 insertions, 0 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterReflowTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterReflowTest.java
new file mode 100644
index 0000000000..d9e50d20af
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterReflowTest.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * Copyright (C) 2009, Johannes E. Schindelin <johannes.schindelin@gmx.de>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.diff;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jgit.patch.FileHeader;
+import org.eclipse.jgit.patch.Patch;
+import org.eclipse.jgit.util.RawParseUtils;
+
+public class DiffFormatterReflowTest extends TestCase {
+ private RawText a;
+
+ private RawText b;
+
+ private FileHeader file;
+
+ private ByteArrayOutputStream out;
+
+ private DiffFormatter fmt;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ out = new ByteArrayOutputStream();
+ fmt = new DiffFormatter();
+ }
+
+ public void testNegativeContextFails() throws IOException {
+ init("X");
+ try {
+ fmt.setContext(-1);
+ fail("accepted negative context");
+ } catch (IllegalArgumentException e) {
+ // pass
+ }
+ }
+
+ public void testContext0() throws IOException {
+ init("X");
+ fmt.setContext(0);
+ assertFormatted();
+ }
+
+ public void testContext1() throws IOException {
+ init("X");
+ fmt.setContext(1);
+ assertFormatted();
+ }
+
+ public void testContext3() throws IOException {
+ init("X");
+ fmt.setContext(3);
+ assertFormatted();
+ }
+
+ public void testContext5() throws IOException {
+ init("X");
+ fmt.setContext(5);
+ assertFormatted();
+ }
+
+ public void testContext10() throws IOException {
+ init("X");
+ fmt.setContext(10);
+ assertFormatted();
+ }
+
+ public void testContext100() throws IOException {
+ init("X");
+ fmt.setContext(100);
+ assertFormatted();
+ }
+
+ public void testEmpty1() throws IOException {
+ init("E");
+ assertFormatted("E.patch");
+ }
+
+ public void testNoNewLine1() throws IOException {
+ init("Y");
+ assertFormatted("Y.patch");
+ }
+
+ public void testNoNewLine2() throws IOException {
+ init("Z");
+ assertFormatted("Z.patch");
+ }
+
+ private void init(final String name) throws IOException {
+ a = new RawText(readFile(name + "_PreImage"));
+ b = new RawText(readFile(name + "_PostImage"));
+ file = parseTestPatchFile(name + ".patch").getFiles().get(0);
+ }
+
+ private void assertFormatted() throws IOException {
+ assertFormatted(getName() + ".out");
+ }
+
+ private void assertFormatted(final String name) throws IOException {
+ fmt.format(out, file, a, b);
+ final String exp = RawParseUtils.decode(readFile(name));
+ assertEquals(exp, RawParseUtils.decode(out.toByteArray()));
+ }
+
+ private byte[] readFile(final String patchFile) throws IOException {
+ final InputStream in = getClass().getResourceAsStream(patchFile);
+ if (in == null) {
+ fail("No " + patchFile + " test vector");
+ return null; // Never happens
+ }
+ try {
+ final byte[] buf = new byte[1024];
+ final ByteArrayOutputStream temp = new ByteArrayOutputStream();
+ int n;
+ while ((n = in.read(buf)) > 0)
+ temp.write(buf, 0, n);
+ return temp.toByteArray();
+ } finally {
+ in.close();
+ }
+ }
+
+ private Patch parseTestPatchFile(final String patchFile) throws IOException {
+ final InputStream in = getClass().getResourceAsStream(patchFile);
+ if (in == null) {
+ fail("No " + patchFile + " test vector");
+ return null; // Never happens
+ }
+ try {
+ final Patch p = new Patch();
+ p.parse(in);
+ return p;
+ } finally {
+ in.close();
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditListTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditListTest.java
new file mode 100644
index 0000000000..5c2c3d0a22
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditListTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.diff;
+
+import java.util.Iterator;
+
+import junit.framework.TestCase;
+
+public class EditListTest extends TestCase {
+ public void testEmpty() {
+ final EditList l = new EditList();
+ assertEquals(0, l.size());
+ assertTrue(l.isEmpty());
+ assertEquals("EditList[]", l.toString());
+
+ assertTrue(l.equals(l));
+ assertTrue(l.equals(new EditList()));
+ assertFalse(l.equals(""));
+ assertEquals(l.hashCode(), new EditList().hashCode());
+ }
+
+ public void testAddOne() {
+ final Edit e = new Edit(1, 2, 1, 1);
+ final EditList l = new EditList();
+ l.add(e);
+ assertEquals(1, l.size());
+ assertFalse(l.isEmpty());
+ assertSame(e, l.get(0));
+ assertSame(e, l.iterator().next());
+
+ assertTrue(l.equals(l));
+ assertFalse(l.equals(new EditList()));
+
+ final EditList l2 = new EditList();
+ l2.add(e);
+ assertTrue(l.equals(l2));
+ assertTrue(l2.equals(l));
+ assertEquals(l.hashCode(), l2.hashCode());
+ }
+
+ public void testAddTwo() {
+ final Edit e1 = new Edit(1, 2, 1, 1);
+ final Edit e2 = new Edit(8, 8, 8, 12);
+ final EditList l = new EditList();
+ l.add(e1);
+ l.add(e2);
+ assertEquals(2, l.size());
+ assertSame(e1, l.get(0));
+ assertSame(e2, l.get(1));
+
+ final Iterator<Edit> i = l.iterator();
+ assertSame(e1, i.next());
+ assertSame(e2, i.next());
+
+ assertTrue(l.equals(l));
+ assertFalse(l.equals(new EditList()));
+
+ final EditList l2 = new EditList();
+ l2.add(e1);
+ l2.add(e2);
+ assertTrue(l.equals(l2));
+ assertTrue(l2.equals(l));
+ assertEquals(l.hashCode(), l2.hashCode());
+ }
+
+ public void testSet() {
+ final Edit e1 = new Edit(1, 2, 1, 1);
+ final Edit e2 = new Edit(3, 4, 3, 3);
+ final EditList l = new EditList();
+ l.add(e1);
+ assertSame(e1, l.get(0));
+ assertSame(e1, l.set(0, e2));
+ assertSame(e2, l.get(0));
+ }
+
+ public void testRemove() {
+ final Edit e1 = new Edit(1, 2, 1, 1);
+ final Edit e2 = new Edit(8, 8, 8, 12);
+ final EditList l = new EditList();
+ l.add(e1);
+ l.add(e2);
+ l.remove(e1);
+ assertEquals(1, l.size());
+ assertSame(e2, l.get(0));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditTest.java
new file mode 100644
index 0000000000..6f3d21e558
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/EditTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * Copyright (C) 2009, Johannes E. Schindelin <johannes.schindelin@gmx.de>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.diff;
+
+import junit.framework.TestCase;
+
+public class EditTest extends TestCase {
+ public void testCreate() {
+ final Edit e = new Edit(1, 2, 3, 4);
+ assertEquals(1, e.getBeginA());
+ assertEquals(2, e.getEndA());
+ assertEquals(3, e.getBeginB());
+ assertEquals(4, e.getEndB());
+ }
+
+ public void testCreateEmpty() {
+ final Edit e = new Edit(1, 3);
+ assertEquals(1, e.getBeginA());
+ assertEquals(1, e.getEndA());
+ assertEquals(3, e.getBeginB());
+ assertEquals(3, e.getEndB());
+ }
+
+ public void testSwap() {
+ final Edit e = new Edit(1, 2, 3, 4);
+ e.swap();
+ assertEquals(3, e.getBeginA());
+ assertEquals(4, e.getEndA());
+ assertEquals(1, e.getBeginB());
+ assertEquals(2, e.getEndB());
+ }
+
+ public void testType_Insert() {
+ final Edit e = new Edit(1, 1, 1, 2);
+ assertSame(Edit.Type.INSERT, e.getType());
+ }
+
+ public void testType_Delete() {
+ final Edit e = new Edit(1, 2, 1, 1);
+ assertSame(Edit.Type.DELETE, e.getType());
+ }
+
+ public void testType_Replace() {
+ final Edit e = new Edit(1, 2, 1, 4);
+ assertSame(Edit.Type.REPLACE, e.getType());
+ }
+
+ public void testType_Empty() {
+ assertSame(Edit.Type.EMPTY, new Edit(1, 1, 2, 2).getType());
+ assertSame(Edit.Type.EMPTY, new Edit(1, 2).getType());
+ }
+
+ public void testToString() {
+ final Edit e = new Edit(1, 2, 1, 4);
+ assertEquals("REPLACE(1-2,1-4)", e.toString());
+ }
+
+ public void testEquals1() {
+ final Edit e1 = new Edit(1, 2, 3, 4);
+ final Edit e2 = new Edit(1, 2, 3, 4);
+
+ assertTrue(e1.equals(e1));
+ assertTrue(e1.equals(e2));
+ assertTrue(e2.equals(e1));
+ assertEquals(e1.hashCode(), e2.hashCode());
+ assertFalse(e1.equals(""));
+ }
+
+ public void testNotEquals1() {
+ assertFalse(new Edit(1, 2, 3, 4).equals(new Edit(0, 2, 3, 4)));
+ }
+
+ public void testNotEquals2() {
+ assertFalse(new Edit(1, 2, 3, 4).equals(new Edit(1, 0, 3, 4)));
+ }
+
+ public void testNotEquals3() {
+ assertFalse(new Edit(1, 2, 3, 4).equals(new Edit(1, 2, 0, 4)));
+ }
+
+ public void testNotEquals4() {
+ assertFalse(new Edit(1, 2, 3, 4).equals(new Edit(1, 2, 3, 0)));
+ }
+
+ public void testExtendA() {
+ final Edit e = new Edit(1, 2, 1, 1);
+
+ e.extendA();
+ assertEquals(new Edit(1, 3, 1, 1), e);
+
+ e.extendA();
+ assertEquals(new Edit(1, 4, 1, 1), e);
+ }
+
+ public void testExtendB() {
+ final Edit e = new Edit(1, 2, 1, 1);
+
+ e.extendB();
+ assertEquals(new Edit(1, 2, 1, 2), e);
+
+ e.extendB();
+ assertEquals(new Edit(1, 2, 1, 3), e);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RawTextTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RawTextTest.java
new file mode 100644
index 0000000000..5cb8bc3945
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RawTextTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * Copyright (C) 2009, Johannes E. Schindelin <johannes.schindelin@gmx.de>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.diff;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.util.RawParseUtils;
+
+public class RawTextTest extends TestCase {
+ public void testEmpty() {
+ final RawText r = new RawText(new byte[0]);
+ assertEquals(0, r.size());
+ }
+
+ public void testEquals() {
+ final RawText a = new RawText(Constants.encodeASCII("foo-a\nfoo-b\n"));
+ final RawText b = new RawText(Constants.encodeASCII("foo-b\nfoo-c\n"));
+
+ assertEquals(2, a.size());
+ assertEquals(2, b.size());
+
+ // foo-a != foo-b
+ assertFalse(a.equals(0, b, 0));
+ assertFalse(b.equals(0, a, 0));
+
+ // foo-b == foo-b
+ assertTrue(a.equals(1, b, 0));
+ assertTrue(b.equals(0, a, 1));
+ }
+
+ public void testWriteLine1() throws IOException {
+ final RawText a = new RawText(Constants.encodeASCII("foo-a\nfoo-b\n"));
+ final ByteArrayOutputStream o = new ByteArrayOutputStream();
+ a.writeLine(o, 0);
+ final byte[] r = o.toByteArray();
+ assertEquals("foo-a", RawParseUtils.decode(r));
+ }
+
+ public void testWriteLine2() throws IOException {
+ final RawText a = new RawText(Constants.encodeASCII("foo-a\nfoo-b"));
+ final ByteArrayOutputStream o = new ByteArrayOutputStream();
+ a.writeLine(o, 1);
+ final byte[] r = o.toByteArray();
+ assertEquals("foo-b", RawParseUtils.decode(r));
+ }
+
+ public void testWriteLine3() throws IOException {
+ final RawText a = new RawText(Constants.encodeASCII("a\n\nb\n"));
+ final ByteArrayOutputStream o = new ByteArrayOutputStream();
+ a.writeLine(o, 1);
+ final byte[] r = o.toByteArray();
+ assertEquals("", RawParseUtils.decode(r));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBasicTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBasicTest.java
new file mode 100644
index 0000000000..cc37c2bf8b
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBasicTest.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2008-2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.dircache;
+
+import java.io.File;
+
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+
+public class DirCacheBasicTest extends RepositoryTestCase {
+ public void testReadMissing_RealIndex() throws Exception {
+ final File idx = new File(db.getDirectory(), "index");
+ assertFalse(idx.exists());
+
+ final DirCache dc = DirCache.read(db);
+ assertNotNull(dc);
+ assertEquals(0, dc.getEntryCount());
+ }
+
+ public void testReadMissing_TempIndex() throws Exception {
+ final File idx = new File(db.getDirectory(), "tmp_index");
+ assertFalse(idx.exists());
+
+ final DirCache dc = DirCache.read(idx);
+ assertNotNull(dc);
+ assertEquals(0, dc.getEntryCount());
+ }
+
+ public void testLockMissing_RealIndex() throws Exception {
+ final File idx = new File(db.getDirectory(), "index");
+ final File lck = new File(db.getDirectory(), "index.lock");
+ assertFalse(idx.exists());
+ assertFalse(lck.exists());
+
+ final DirCache dc = DirCache.lock(db);
+ assertNotNull(dc);
+ assertFalse(idx.exists());
+ assertTrue(lck.exists());
+ assertEquals(0, dc.getEntryCount());
+
+ dc.unlock();
+ assertFalse(idx.exists());
+ assertFalse(lck.exists());
+ }
+
+ public void testLockMissing_TempIndex() throws Exception {
+ final File idx = new File(db.getDirectory(), "tmp_index");
+ final File lck = new File(db.getDirectory(), "tmp_index.lock");
+ assertFalse(idx.exists());
+ assertFalse(lck.exists());
+
+ final DirCache dc = DirCache.lock(idx);
+ assertNotNull(dc);
+ assertFalse(idx.exists());
+ assertTrue(lck.exists());
+ assertEquals(0, dc.getEntryCount());
+
+ dc.unlock();
+ assertFalse(idx.exists());
+ assertFalse(lck.exists());
+ }
+
+ public void testWriteEmptyUnlock_RealIndex() throws Exception {
+ final File idx = new File(db.getDirectory(), "index");
+ final File lck = new File(db.getDirectory(), "index.lock");
+ assertFalse(idx.exists());
+ assertFalse(lck.exists());
+
+ final DirCache dc = DirCache.lock(db);
+ assertEquals(0, lck.length());
+ dc.write();
+ assertEquals(12 + 20, lck.length());
+
+ dc.unlock();
+ assertFalse(idx.exists());
+ assertFalse(lck.exists());
+ }
+
+ public void testWriteEmptyCommit_RealIndex() throws Exception {
+ final File idx = new File(db.getDirectory(), "index");
+ final File lck = new File(db.getDirectory(), "index.lock");
+ assertFalse(idx.exists());
+ assertFalse(lck.exists());
+
+ final DirCache dc = DirCache.lock(db);
+ assertEquals(0, lck.length());
+ dc.write();
+ assertEquals(12 + 20, lck.length());
+
+ assertTrue(dc.commit());
+ assertTrue(idx.exists());
+ assertFalse(lck.exists());
+ assertEquals(12 + 20, idx.length());
+ }
+
+ public void testWriteEmptyReadEmpty_RealIndex() throws Exception {
+ final File idx = new File(db.getDirectory(), "index");
+ final File lck = new File(db.getDirectory(), "index.lock");
+ assertFalse(idx.exists());
+ assertFalse(lck.exists());
+ {
+ final DirCache dc = DirCache.lock(db);
+ dc.write();
+ assertTrue(dc.commit());
+ assertTrue(idx.exists());
+ }
+ {
+ final DirCache dc = DirCache.read(db);
+ assertEquals(0, dc.getEntryCount());
+ }
+ }
+
+ public void testWriteEmptyLockEmpty_RealIndex() throws Exception {
+ final File idx = new File(db.getDirectory(), "index");
+ final File lck = new File(db.getDirectory(), "index.lock");
+ assertFalse(idx.exists());
+ assertFalse(lck.exists());
+ {
+ final DirCache dc = DirCache.lock(db);
+ dc.write();
+ assertTrue(dc.commit());
+ assertTrue(idx.exists());
+ }
+ {
+ final DirCache dc = DirCache.lock(db);
+ assertEquals(0, dc.getEntryCount());
+ assertTrue(idx.exists());
+ assertTrue(lck.exists());
+ dc.unlock();
+ }
+ }
+
+ public void testBuildThenClear() throws Exception {
+ final DirCache dc = DirCache.read(db);
+
+ final String[] paths = { "a.", "a.b", "a/b", "a0b" };
+ final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
+ for (int i = 0; i < paths.length; i++)
+ ents[i] = new DirCacheEntry(paths[i]);
+
+ final DirCacheBuilder b = dc.builder();
+ for (int i = 0; i < ents.length; i++)
+ b.add(ents[i]);
+ b.finish();
+
+ assertEquals(paths.length, dc.getEntryCount());
+ dc.clear();
+ assertEquals(0, dc.getEntryCount());
+ }
+
+ public void testFindOnEmpty() throws Exception {
+ final DirCache dc = DirCache.newInCore();
+ final byte[] path = Constants.encode("a");
+ assertEquals(-1, dc.findEntry(path, path.length));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderIteratorTest.java
new file mode 100644
index 0000000000..03bb7f5e83
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderIteratorTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.dircache;
+
+import java.util.Collections;
+
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
+
+public class DirCacheBuilderIteratorTest extends RepositoryTestCase {
+ public void testPathFilterGroup_DoesNotSkipTail() throws Exception {
+ final DirCache dc = DirCache.read(db);
+
+ final FileMode mode = FileMode.REGULAR_FILE;
+ final String[] paths = { "a.", "a/b", "a/c", "a/d", "a0b" };
+ final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
+ for (int i = 0; i < paths.length; i++) {
+ ents[i] = new DirCacheEntry(paths[i]);
+ ents[i].setFileMode(mode);
+ }
+ {
+ final DirCacheBuilder b = dc.builder();
+ for (int i = 0; i < ents.length; i++)
+ b.add(ents[i]);
+ b.finish();
+ }
+
+ final int expIdx = 2;
+ final DirCacheBuilder b = dc.builder();
+ final TreeWalk tw = new TreeWalk(db);
+ tw.reset();
+ tw.addTree(new DirCacheBuildIterator(b));
+ tw.setRecursive(true);
+ tw.setFilter(PathFilterGroup.createFromStrings(Collections
+ .singleton(paths[expIdx])));
+
+ assertTrue("found " + paths[expIdx], tw.next());
+ final DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
+ assertNotNull(c);
+ assertEquals(expIdx, c.ptr);
+ assertSame(ents[expIdx], c.getDirCacheEntry());
+ assertEquals(paths[expIdx], tw.getPathString());
+ assertEquals(mode.getBits(), tw.getRawMode(0));
+ assertSame(mode, tw.getFileMode(0));
+ b.add(c.getDirCacheEntry());
+
+ assertFalse("no more entries", tw.next());
+
+ b.finish();
+ assertEquals(ents.length, dc.getEntryCount());
+ for (int i = 0; i < ents.length; i++)
+ assertSame(ents[i], dc.getEntry(i));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java
new file mode 100644
index 0000000000..fe02a1b23e
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheBuilderTest.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.dircache;
+
+import java.io.File;
+
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+
+public class DirCacheBuilderTest extends RepositoryTestCase {
+ public void testBuildEmpty() throws Exception {
+ {
+ final DirCache dc = DirCache.lock(db);
+ final DirCacheBuilder b = dc.builder();
+ assertNotNull(b);
+ b.finish();
+ dc.write();
+ assertTrue(dc.commit());
+ }
+ {
+ final DirCache dc = DirCache.read(db);
+ assertEquals(0, dc.getEntryCount());
+ }
+ }
+
+ public void testBuildOneFile_FinishWriteCommit() throws Exception {
+ final String path = "a-file-path";
+ final FileMode mode = FileMode.REGULAR_FILE;
+ final long lastModified = 1218123387057L;
+ final int length = 1342;
+ final DirCacheEntry entOrig;
+ {
+ final DirCache dc = DirCache.lock(db);
+ final DirCacheBuilder b = dc.builder();
+ assertNotNull(b);
+
+ entOrig = new DirCacheEntry(path);
+ entOrig.setFileMode(mode);
+ entOrig.setLastModified(lastModified);
+ entOrig.setLength(length);
+
+ assertNotSame(path, entOrig.getPathString());
+ assertEquals(path, entOrig.getPathString());
+ assertEquals(ObjectId.zeroId(), entOrig.getObjectId());
+ assertEquals(mode.getBits(), entOrig.getRawMode());
+ assertEquals(0, entOrig.getStage());
+ assertEquals(lastModified, entOrig.getLastModified());
+ assertEquals(length, entOrig.getLength());
+ assertFalse(entOrig.isAssumeValid());
+ b.add(entOrig);
+
+ b.finish();
+ assertEquals(1, dc.getEntryCount());
+ assertSame(entOrig, dc.getEntry(0));
+
+ dc.write();
+ assertTrue(dc.commit());
+ }
+ {
+ final DirCache dc = DirCache.read(db);
+ assertEquals(1, dc.getEntryCount());
+
+ final DirCacheEntry entRead = dc.getEntry(0);
+ assertNotSame(entOrig, entRead);
+ assertEquals(path, entRead.getPathString());
+ assertEquals(ObjectId.zeroId(), entOrig.getObjectId());
+ assertEquals(mode.getBits(), entOrig.getRawMode());
+ assertEquals(0, entOrig.getStage());
+ assertEquals(lastModified, entOrig.getLastModified());
+ assertEquals(length, entOrig.getLength());
+ assertFalse(entOrig.isAssumeValid());
+ }
+ }
+
+ public void testBuildOneFile_Commit() throws Exception {
+ final String path = "a-file-path";
+ final FileMode mode = FileMode.REGULAR_FILE;
+ final long lastModified = 1218123387057L;
+ final int length = 1342;
+ final DirCacheEntry entOrig;
+ {
+ final DirCache dc = DirCache.lock(db);
+ final DirCacheBuilder b = dc.builder();
+ assertNotNull(b);
+
+ entOrig = new DirCacheEntry(path);
+ entOrig.setFileMode(mode);
+ entOrig.setLastModified(lastModified);
+ entOrig.setLength(length);
+
+ assertNotSame(path, entOrig.getPathString());
+ assertEquals(path, entOrig.getPathString());
+ assertEquals(ObjectId.zeroId(), entOrig.getObjectId());
+ assertEquals(mode.getBits(), entOrig.getRawMode());
+ assertEquals(0, entOrig.getStage());
+ assertEquals(lastModified, entOrig.getLastModified());
+ assertEquals(length, entOrig.getLength());
+ assertFalse(entOrig.isAssumeValid());
+ b.add(entOrig);
+
+ assertTrue(b.commit());
+ assertEquals(1, dc.getEntryCount());
+ assertSame(entOrig, dc.getEntry(0));
+ assertFalse(new File(db.getDirectory(), "index.lock").exists());
+ }
+ {
+ final DirCache dc = DirCache.read(db);
+ assertEquals(1, dc.getEntryCount());
+
+ final DirCacheEntry entRead = dc.getEntry(0);
+ assertNotSame(entOrig, entRead);
+ assertEquals(path, entRead.getPathString());
+ assertEquals(ObjectId.zeroId(), entOrig.getObjectId());
+ assertEquals(mode.getBits(), entOrig.getRawMode());
+ assertEquals(0, entOrig.getStage());
+ assertEquals(lastModified, entOrig.getLastModified());
+ assertEquals(length, entOrig.getLength());
+ assertFalse(entOrig.isAssumeValid());
+ }
+ }
+
+ public void testFindSingleFile() throws Exception {
+ final String path = "a-file-path";
+ final DirCache dc = DirCache.read(db);
+ final DirCacheBuilder b = dc.builder();
+ assertNotNull(b);
+
+ final DirCacheEntry entOrig = new DirCacheEntry(path);
+ assertNotSame(path, entOrig.getPathString());
+ assertEquals(path, entOrig.getPathString());
+ b.add(entOrig);
+ b.finish();
+
+ assertEquals(1, dc.getEntryCount());
+ assertSame(entOrig, dc.getEntry(0));
+ assertEquals(0, dc.findEntry(path));
+
+ assertEquals(-1, dc.findEntry("@@-before"));
+ assertEquals(0, real(dc.findEntry("@@-before")));
+
+ assertEquals(-2, dc.findEntry("a-zoo"));
+ assertEquals(1, real(dc.findEntry("a-zoo")));
+
+ assertSame(entOrig, dc.getEntry(path));
+ }
+
+ public void testAdd_InGitSortOrder() throws Exception {
+ final DirCache dc = DirCache.read(db);
+
+ final String[] paths = { "a.", "a.b", "a/b", "a0b" };
+ final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
+ for (int i = 0; i < paths.length; i++)
+ ents[i] = new DirCacheEntry(paths[i]);
+
+ final DirCacheBuilder b = dc.builder();
+ for (int i = 0; i < ents.length; i++)
+ b.add(ents[i]);
+ b.finish();
+
+ assertEquals(paths.length, dc.getEntryCount());
+ for (int i = 0; i < paths.length; i++) {
+ assertSame(ents[i], dc.getEntry(i));
+ assertEquals(paths[i], dc.getEntry(i).getPathString());
+ assertEquals(i, dc.findEntry(paths[i]));
+ assertSame(ents[i], dc.getEntry(paths[i]));
+ }
+ }
+
+ public void testAdd_ReverseGitSortOrder() throws Exception {
+ final DirCache dc = DirCache.read(db);
+
+ final String[] paths = { "a.", "a.b", "a/b", "a0b" };
+ final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
+ for (int i = 0; i < paths.length; i++)
+ ents[i] = new DirCacheEntry(paths[i]);
+
+ final DirCacheBuilder b = dc.builder();
+ for (int i = ents.length - 1; i >= 0; i--)
+ b.add(ents[i]);
+ b.finish();
+
+ assertEquals(paths.length, dc.getEntryCount());
+ for (int i = 0; i < paths.length; i++) {
+ assertSame(ents[i], dc.getEntry(i));
+ assertEquals(paths[i], dc.getEntry(i).getPathString());
+ assertEquals(i, dc.findEntry(paths[i]));
+ assertSame(ents[i], dc.getEntry(paths[i]));
+ }
+ }
+
+ public void testBuilderClear() throws Exception {
+ final DirCache dc = DirCache.read(db);
+
+ final String[] paths = { "a.", "a.b", "a/b", "a0b" };
+ final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
+ for (int i = 0; i < paths.length; i++)
+ ents[i] = new DirCacheEntry(paths[i]);
+ {
+ final DirCacheBuilder b = dc.builder();
+ for (int i = 0; i < ents.length; i++)
+ b.add(ents[i]);
+ b.finish();
+ }
+ assertEquals(paths.length, dc.getEntryCount());
+ {
+ final DirCacheBuilder b = dc.builder();
+ b.finish();
+ }
+ assertEquals(0, dc.getEntryCount());
+ }
+
+ private static int real(int eIdx) {
+ if (eIdx < 0)
+ eIdx = -(eIdx + 1);
+ return eIdx;
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java
new file mode 100644
index 0000000000..ab0c77110d
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheCGitCompatabilityTest.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.dircache;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.util.JGitTestUtil;
+
+public class DirCacheCGitCompatabilityTest extends RepositoryTestCase {
+ private final File index = pathOf("gitgit.index");
+
+ public void testReadIndex_LsFiles() throws Exception {
+ final Map<String, CGitIndexRecord> ls = readLsFiles();
+ final DirCache dc = new DirCache(index);
+ assertEquals(0, dc.getEntryCount());
+ dc.read();
+ assertEquals(ls.size(), dc.getEntryCount());
+ {
+ final Iterator<CGitIndexRecord> rItr = ls.values().iterator();
+ for (int i = 0; rItr.hasNext(); i++)
+ assertEqual(rItr.next(), dc.getEntry(i));
+ }
+ }
+
+ public void testTreeWalk_LsFiles() throws Exception {
+ final Map<String, CGitIndexRecord> ls = readLsFiles();
+ final DirCache dc = new DirCache(index);
+ assertEquals(0, dc.getEntryCount());
+ dc.read();
+ assertEquals(ls.size(), dc.getEntryCount());
+ {
+ final Iterator<CGitIndexRecord> rItr = ls.values().iterator();
+ final TreeWalk tw = new TreeWalk(db);
+ tw.reset();
+ tw.setRecursive(true);
+ tw.addTree(new DirCacheIterator(dc));
+ while (rItr.hasNext()) {
+ final DirCacheIterator dcItr;
+
+ assertTrue(tw.next());
+ dcItr = tw.getTree(0, DirCacheIterator.class);
+ assertNotNull(dcItr);
+
+ assertEqual(rItr.next(), dcItr.getDirCacheEntry());
+ }
+ }
+ }
+
+ private static void assertEqual(final CGitIndexRecord c,
+ final DirCacheEntry j) {
+ assertNotNull(c);
+ assertNotNull(j);
+
+ assertEquals(c.path, j.getPathString());
+ assertEquals(c.id, j.getObjectId());
+ assertEquals(c.mode, j.getRawMode());
+ assertEquals(c.stage, j.getStage());
+ }
+
+ public void testReadIndex_DirCacheTree() throws Exception {
+ final Map<String, CGitIndexRecord> cList = readLsFiles();
+ final Map<String, CGitLsTreeRecord> cTree = readLsTree();
+ final DirCache dc = new DirCache(index);
+ assertEquals(0, dc.getEntryCount());
+ dc.read();
+ assertEquals(cList.size(), dc.getEntryCount());
+
+ final DirCacheTree jTree = dc.getCacheTree(false);
+ assertNotNull(jTree);
+ assertEquals("", jTree.getNameString());
+ assertEquals("", jTree.getPathString());
+ assertTrue(jTree.isValid());
+ assertEquals(ObjectId
+ .fromString("698dd0b8d0c299f080559a1cffc7fe029479a408"), jTree
+ .getObjectId());
+ assertEquals(cList.size(), jTree.getEntrySpan());
+
+ final ArrayList<CGitLsTreeRecord> subtrees = new ArrayList<CGitLsTreeRecord>();
+ for (final CGitLsTreeRecord r : cTree.values()) {
+ if (FileMode.TREE.equals(r.mode))
+ subtrees.add(r);
+ }
+ assertEquals(subtrees.size(), jTree.getChildCount());
+
+ for (int i = 0; i < jTree.getChildCount(); i++) {
+ final DirCacheTree sj = jTree.getChild(i);
+ final CGitLsTreeRecord sc = subtrees.get(i);
+ assertEquals(sc.path, sj.getNameString());
+ assertEquals(sc.path + "/", sj.getPathString());
+ assertTrue(sj.isValid());
+ assertEquals(sc.id, sj.getObjectId());
+ }
+ }
+
+ private File pathOf(final String name) {
+ return JGitTestUtil.getTestResourceFile(name);
+ }
+
+ private Map<String, CGitIndexRecord> readLsFiles() throws Exception {
+ final LinkedHashMap<String, CGitIndexRecord> r = new LinkedHashMap<String, CGitIndexRecord>();
+ final BufferedReader br = new BufferedReader(new InputStreamReader(
+ new FileInputStream(pathOf("gitgit.lsfiles")), "UTF-8"));
+ try {
+ String line;
+ while ((line = br.readLine()) != null) {
+ final CGitIndexRecord cr = new CGitIndexRecord(line);
+ r.put(cr.path, cr);
+ }
+ } finally {
+ br.close();
+ }
+ return r;
+ }
+
+ private Map<String, CGitLsTreeRecord> readLsTree() throws Exception {
+ final LinkedHashMap<String, CGitLsTreeRecord> r = new LinkedHashMap<String, CGitLsTreeRecord>();
+ final BufferedReader br = new BufferedReader(new InputStreamReader(
+ new FileInputStream(pathOf("gitgit.lstree")), "UTF-8"));
+ try {
+ String line;
+ while ((line = br.readLine()) != null) {
+ final CGitLsTreeRecord cr = new CGitLsTreeRecord(line);
+ r.put(cr.path, cr);
+ }
+ } finally {
+ br.close();
+ }
+ return r;
+ }
+
+ private static class CGitIndexRecord {
+ final int mode;
+
+ final ObjectId id;
+
+ final int stage;
+
+ final String path;
+
+ CGitIndexRecord(final String line) {
+ final int tab = line.indexOf('\t');
+ final int sp1 = line.indexOf(' ');
+ final int sp2 = line.indexOf(' ', sp1 + 1);
+ mode = Integer.parseInt(line.substring(0, sp1), 8);
+ id = ObjectId.fromString(line.substring(sp1 + 1, sp2));
+ stage = Integer.parseInt(line.substring(sp2 + 1, tab));
+ path = line.substring(tab + 1);
+ }
+ }
+
+ private static class CGitLsTreeRecord {
+ final int mode;
+
+ final ObjectId id;
+
+ final String path;
+
+ CGitLsTreeRecord(final String line) {
+ final int tab = line.indexOf('\t');
+ final int sp1 = line.indexOf(' ');
+ final int sp2 = line.indexOf(' ', sp1 + 1);
+ mode = Integer.parseInt(line.substring(0, sp1), 8);
+ id = ObjectId.fromString(line.substring(sp2 + 1, tab));
+ path = line.substring(tab + 1);
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheFindTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheFindTest.java
new file mode 100644
index 0000000000..cdc659a21c
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheFindTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.dircache;
+
+import org.eclipse.jgit.lib.RepositoryTestCase;
+
+public class DirCacheFindTest extends RepositoryTestCase {
+ public void testEntriesWithin() throws Exception {
+ final DirCache dc = DirCache.read(db);
+
+ final String[] paths = { "a.", "a/b", "a/c", "a/d", "a0b" };
+ final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
+ for (int i = 0; i < paths.length; i++)
+ ents[i] = new DirCacheEntry(paths[i]);
+ final int aFirst = 1;
+ final int aLast = 3;
+
+ final DirCacheBuilder b = dc.builder();
+ for (int i = 0; i < ents.length; i++)
+ b.add(ents[i]);
+ b.finish();
+
+ assertEquals(paths.length, dc.getEntryCount());
+ for (int i = 0; i < ents.length; i++)
+ assertSame(ents[i], dc.getEntry(i));
+
+ {
+ final DirCacheEntry[] aContents = dc.getEntriesWithin("a");
+ assertNotNull(aContents);
+ assertEquals(aLast - aFirst + 1, aContents.length);
+ for (int i = aFirst, j = 0; i <= aLast; i++, j++)
+ assertSame(ents[i], aContents[j]);
+ }
+ {
+ final DirCacheEntry[] aContents = dc.getEntriesWithin("a/");
+ assertNotNull(aContents);
+ assertEquals(aLast - aFirst + 1, aContents.length);
+ for (int i = aFirst, j = 0; i <= aLast; i++, j++)
+ assertSame(ents[i], aContents[j]);
+ }
+
+ assertNotNull(dc.getEntriesWithin("a."));
+ assertEquals(0, dc.getEntriesWithin("a.").length);
+
+ assertNotNull(dc.getEntriesWithin("a0b"));
+ assertEquals(0, dc.getEntriesWithin("a0b.").length);
+
+ assertNotNull(dc.getEntriesWithin("zoo"));
+ assertEquals(0, dc.getEntriesWithin("zoo.").length);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheIteratorTest.java
new file mode 100644
index 0000000000..db9f684fed
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheIteratorTest.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.dircache;
+
+import java.util.Collections;
+
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
+
+public class DirCacheIteratorTest extends RepositoryTestCase {
+ public void testEmptyTree_NoTreeWalk() throws Exception {
+ final DirCache dc = DirCache.read(db);
+ assertEquals(0, dc.getEntryCount());
+
+ final DirCacheIterator i = new DirCacheIterator(dc);
+ assertTrue(i.eof());
+ }
+
+ public void testEmptyTree_WithTreeWalk() throws Exception {
+ final DirCache dc = DirCache.read(db);
+ assertEquals(0, dc.getEntryCount());
+
+ final TreeWalk tw = new TreeWalk(db);
+ tw.reset();
+ tw.addTree(new DirCacheIterator(dc));
+ assertFalse(tw.next());
+ }
+
+ public void testNoSubtree_NoTreeWalk() throws Exception {
+ final DirCache dc = DirCache.read(db);
+
+ final String[] paths = { "a.", "a0b" };
+ final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
+ for (int i = 0; i < paths.length; i++)
+ ents[i] = new DirCacheEntry(paths[i]);
+
+ final DirCacheBuilder b = dc.builder();
+ for (int i = 0; i < ents.length; i++)
+ b.add(ents[i]);
+ b.finish();
+
+ final DirCacheIterator i = new DirCacheIterator(dc);
+ int pathIdx = 0;
+ for (; !i.eof(); i.next(1)) {
+ assertEquals(pathIdx, i.ptr);
+ assertSame(ents[pathIdx], i.getDirCacheEntry());
+ pathIdx++;
+ }
+ assertEquals(paths.length, pathIdx);
+ }
+
+ public void testNoSubtree_WithTreeWalk() throws Exception {
+ final DirCache dc = DirCache.read(db);
+
+ final String[] paths = { "a.", "a0b" };
+ final FileMode[] modes = { FileMode.EXECUTABLE_FILE, FileMode.GITLINK };
+ final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
+ for (int i = 0; i < paths.length; i++) {
+ ents[i] = new DirCacheEntry(paths[i]);
+ ents[i].setFileMode(modes[i]);
+ }
+
+ final DirCacheBuilder b = dc.builder();
+ for (int i = 0; i < ents.length; i++)
+ b.add(ents[i]);
+ b.finish();
+
+ final DirCacheIterator i = new DirCacheIterator(dc);
+ final TreeWalk tw = new TreeWalk(db);
+ tw.reset();
+ tw.addTree(i);
+ int pathIdx = 0;
+ while (tw.next()) {
+ assertSame(i, tw.getTree(0, DirCacheIterator.class));
+ assertEquals(pathIdx, i.ptr);
+ assertSame(ents[pathIdx], i.getDirCacheEntry());
+ assertEquals(paths[pathIdx], tw.getPathString());
+ assertEquals(modes[pathIdx].getBits(), tw.getRawMode(0));
+ assertSame(modes[pathIdx], tw.getFileMode(0));
+ pathIdx++;
+ }
+ assertEquals(paths.length, pathIdx);
+ }
+
+ public void testSingleSubtree_NoRecursion() throws Exception {
+ final DirCache dc = DirCache.read(db);
+
+ final String[] paths = { "a.", "a/b", "a/c", "a/d", "a0b" };
+ final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
+ for (int i = 0; i < paths.length; i++) {
+ ents[i] = new DirCacheEntry(paths[i]);
+ ents[i].setFileMode(FileMode.REGULAR_FILE);
+ }
+
+ final DirCacheBuilder b = dc.builder();
+ for (int i = 0; i < ents.length; i++)
+ b.add(ents[i]);
+ b.finish();
+
+ final String[] expPaths = { "a.", "a", "a0b" };
+ final FileMode[] expModes = { FileMode.REGULAR_FILE, FileMode.TREE,
+ FileMode.REGULAR_FILE };
+ final int expPos[] = { 0, -1, 4 };
+
+ final DirCacheIterator i = new DirCacheIterator(dc);
+ final TreeWalk tw = new TreeWalk(db);
+ tw.reset();
+ tw.addTree(i);
+ tw.setRecursive(false);
+ int pathIdx = 0;
+ while (tw.next()) {
+ assertSame(i, tw.getTree(0, DirCacheIterator.class));
+ assertEquals(expModes[pathIdx].getBits(), tw.getRawMode(0));
+ assertSame(expModes[pathIdx], tw.getFileMode(0));
+ assertEquals(expPaths[pathIdx], tw.getPathString());
+
+ if (expPos[pathIdx] >= 0) {
+ assertEquals(expPos[pathIdx], i.ptr);
+ assertSame(ents[expPos[pathIdx]], i.getDirCacheEntry());
+ } else {
+ assertSame(FileMode.TREE, tw.getFileMode(0));
+ }
+
+ pathIdx++;
+ }
+ assertEquals(expPaths.length, pathIdx);
+ }
+
+ public void testSingleSubtree_Recursive() throws Exception {
+ final DirCache dc = DirCache.read(db);
+
+ final FileMode mode = FileMode.REGULAR_FILE;
+ final String[] paths = { "a.", "a/b", "a/c", "a/d", "a0b" };
+ final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
+ for (int i = 0; i < paths.length; i++) {
+ ents[i] = new DirCacheEntry(paths[i]);
+ ents[i].setFileMode(mode);
+ }
+
+ final DirCacheBuilder b = dc.builder();
+ for (int i = 0; i < ents.length; i++)
+ b.add(ents[i]);
+ b.finish();
+
+ final DirCacheIterator i = new DirCacheIterator(dc);
+ final TreeWalk tw = new TreeWalk(db);
+ tw.reset();
+ tw.addTree(i);
+ tw.setRecursive(true);
+ int pathIdx = 0;
+ while (tw.next()) {
+ final DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
+ assertNotNull(c);
+ assertEquals(pathIdx, c.ptr);
+ assertSame(ents[pathIdx], c.getDirCacheEntry());
+ assertEquals(paths[pathIdx], tw.getPathString());
+ assertEquals(mode.getBits(), tw.getRawMode(0));
+ assertSame(mode, tw.getFileMode(0));
+ pathIdx++;
+ }
+ assertEquals(paths.length, pathIdx);
+ }
+
+ public void testTwoLevelSubtree_Recursive() throws Exception {
+ final DirCache dc = DirCache.read(db);
+
+ final FileMode mode = FileMode.REGULAR_FILE;
+ final String[] paths = { "a.", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" };
+ final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
+ for (int i = 0; i < paths.length; i++) {
+ ents[i] = new DirCacheEntry(paths[i]);
+ ents[i].setFileMode(mode);
+ }
+
+ final DirCacheBuilder b = dc.builder();
+ for (int i = 0; i < ents.length; i++)
+ b.add(ents[i]);
+ b.finish();
+
+ final TreeWalk tw = new TreeWalk(db);
+ tw.reset();
+ tw.addTree(new DirCacheIterator(dc));
+ tw.setRecursive(true);
+ int pathIdx = 0;
+ while (tw.next()) {
+ final DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
+ assertNotNull(c);
+ assertEquals(pathIdx, c.ptr);
+ assertSame(ents[pathIdx], c.getDirCacheEntry());
+ assertEquals(paths[pathIdx], tw.getPathString());
+ assertEquals(mode.getBits(), tw.getRawMode(0));
+ assertSame(mode, tw.getFileMode(0));
+ pathIdx++;
+ }
+ assertEquals(paths.length, pathIdx);
+ }
+
+ public void testTwoLevelSubtree_FilterPath() throws Exception {
+ final DirCache dc = DirCache.read(db);
+
+ final FileMode mode = FileMode.REGULAR_FILE;
+ final String[] paths = { "a.", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" };
+ final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
+ for (int i = 0; i < paths.length; i++) {
+ ents[i] = new DirCacheEntry(paths[i]);
+ ents[i].setFileMode(mode);
+ }
+
+ final DirCacheBuilder b = dc.builder();
+ for (int i = 0; i < ents.length; i++)
+ b.add(ents[i]);
+ b.finish();
+
+ final TreeWalk tw = new TreeWalk(db);
+ for (int victimIdx = 0; victimIdx < paths.length; victimIdx++) {
+ tw.reset();
+ tw.addTree(new DirCacheIterator(dc));
+ tw.setFilter(PathFilterGroup.createFromStrings(Collections
+ .singleton(paths[victimIdx])));
+ tw.setRecursive(tw.getFilter().shouldBeRecursive());
+ assertTrue(tw.next());
+ final DirCacheIterator c = tw.getTree(0, DirCacheIterator.class);
+ assertNotNull(c);
+ assertEquals(victimIdx, c.ptr);
+ assertSame(ents[victimIdx], c.getDirCacheEntry());
+ assertEquals(paths[victimIdx], tw.getPathString());
+ assertEquals(mode.getBits(), tw.getRawMode(0));
+ assertSame(mode, tw.getFileMode(0));
+ assertFalse(tw.next());
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheLargePathTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheLargePathTest.java
new file mode 100644
index 0000000000..ceaadf97b6
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheLargePathTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.dircache;
+
+import java.io.IOException;
+
+import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+
+public class DirCacheLargePathTest extends RepositoryTestCase {
+ public void testPath_4090() throws Exception {
+ testLongPath(4090);
+ }
+
+ public void testPath_4094() throws Exception {
+ testLongPath(4094);
+ }
+
+ public void testPath_4095() throws Exception {
+ testLongPath(4095);
+ }
+
+ public void testPath_4096() throws Exception {
+ testLongPath(4096);
+ }
+
+ public void testPath_16384() throws Exception {
+ testLongPath(16384);
+ }
+
+ private void testLongPath(final int len) throws CorruptObjectException,
+ IOException {
+ final String longPath = makeLongPath(len);
+ final String shortPath = "~~~ shorter-path";
+
+ final DirCacheEntry longEnt = new DirCacheEntry(longPath);
+ final DirCacheEntry shortEnt = new DirCacheEntry(shortPath);
+ assertEquals(longPath, longEnt.getPathString());
+ assertEquals(shortPath, shortEnt.getPathString());
+
+ {
+ final DirCache dc1 = DirCache.lock(db);
+ {
+ final DirCacheBuilder b = dc1.builder();
+ b.add(longEnt);
+ b.add(shortEnt);
+ assertTrue(b.commit());
+ }
+ assertEquals(2, dc1.getEntryCount());
+ assertSame(longEnt, dc1.getEntry(0));
+ assertSame(shortEnt, dc1.getEntry(1));
+ }
+ {
+ final DirCache dc2 = DirCache.read(db);
+ assertEquals(2, dc2.getEntryCount());
+
+ assertNotSame(longEnt, dc2.getEntry(0));
+ assertEquals(longPath, dc2.getEntry(0).getPathString());
+
+ assertNotSame(shortEnt, dc2.getEntry(1));
+ assertEquals(shortPath, dc2.getEntry(1).getPathString());
+ }
+ }
+
+ private static String makeLongPath(final int len) {
+ final StringBuilder r = new StringBuilder(len);
+ for (int i = 0; i < len; i++)
+ r.append('a' + (i % 26));
+ return r.toString();
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheTreeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheTreeTest.java
new file mode 100644
index 0000000000..b84b240a74
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/dircache/DirCacheTreeTest.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.dircache;
+
+import java.io.IOException;
+
+import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+
+public class DirCacheTreeTest extends RepositoryTestCase {
+ public void testEmptyCache_NoCacheTree() throws Exception {
+ final DirCache dc = DirCache.read(db);
+ assertNull(dc.getCacheTree(false));
+ }
+
+ public void testEmptyCache_CreateEmptyCacheTree() throws Exception {
+ final DirCache dc = DirCache.read(db);
+ final DirCacheTree tree = dc.getCacheTree(true);
+ assertNotNull(tree);
+ assertSame(tree, dc.getCacheTree(false));
+ assertSame(tree, dc.getCacheTree(true));
+ assertEquals("", tree.getNameString());
+ assertEquals("", tree.getPathString());
+ assertEquals(0, tree.getChildCount());
+ assertEquals(0, tree.getEntrySpan());
+ assertFalse(tree.isValid());
+ }
+
+ public void testEmptyCache_Clear_NoCacheTree() throws Exception {
+ final DirCache dc = DirCache.read(db);
+ final DirCacheTree tree = dc.getCacheTree(true);
+ assertNotNull(tree);
+ dc.clear();
+ assertNull(dc.getCacheTree(false));
+ assertNotSame(tree, dc.getCacheTree(true));
+ }
+
+ public void testSingleSubtree() throws Exception {
+ final DirCache dc = DirCache.read(db);
+
+ final String[] paths = { "a.", "a/b", "a/c", "a/d", "a0b" };
+ final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
+ for (int i = 0; i < paths.length; i++)
+ ents[i] = new DirCacheEntry(paths[i]);
+ final int aFirst = 1;
+ final int aLast = 3;
+
+ final DirCacheBuilder b = dc.builder();
+ for (int i = 0; i < ents.length; i++)
+ b.add(ents[i]);
+ b.finish();
+
+ assertNull(dc.getCacheTree(false));
+ final DirCacheTree root = dc.getCacheTree(true);
+ assertNotNull(root);
+ assertSame(root, dc.getCacheTree(true));
+ assertEquals("", root.getNameString());
+ assertEquals("", root.getPathString());
+ assertEquals(1, root.getChildCount());
+ assertEquals(dc.getEntryCount(), root.getEntrySpan());
+ assertFalse(root.isValid());
+
+ final DirCacheTree aTree = root.getChild(0);
+ assertNotNull(aTree);
+ assertSame(aTree, root.getChild(0));
+ assertEquals("a", aTree.getNameString());
+ assertEquals("a/", aTree.getPathString());
+ assertEquals(0, aTree.getChildCount());
+ assertEquals(aLast - aFirst + 1, aTree.getEntrySpan());
+ assertFalse(aTree.isValid());
+ }
+
+ public void testTwoLevelSubtree() throws Exception {
+ final DirCache dc = DirCache.read(db);
+
+ final String[] paths = { "a.", "a/b", "a/c/e", "a/c/f", "a/d", "a0b" };
+ final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
+ for (int i = 0; i < paths.length; i++)
+ ents[i] = new DirCacheEntry(paths[i]);
+ final int aFirst = 1;
+ final int aLast = 4;
+ final int acFirst = 2;
+ final int acLast = 3;
+
+ final DirCacheBuilder b = dc.builder();
+ for (int i = 0; i < ents.length; i++)
+ b.add(ents[i]);
+ b.finish();
+
+ assertNull(dc.getCacheTree(false));
+ final DirCacheTree root = dc.getCacheTree(true);
+ assertNotNull(root);
+ assertSame(root, dc.getCacheTree(true));
+ assertEquals("", root.getNameString());
+ assertEquals("", root.getPathString());
+ assertEquals(1, root.getChildCount());
+ assertEquals(dc.getEntryCount(), root.getEntrySpan());
+ assertFalse(root.isValid());
+
+ final DirCacheTree aTree = root.getChild(0);
+ assertNotNull(aTree);
+ assertSame(aTree, root.getChild(0));
+ assertEquals("a", aTree.getNameString());
+ assertEquals("a/", aTree.getPathString());
+ assertEquals(1, aTree.getChildCount());
+ assertEquals(aLast - aFirst + 1, aTree.getEntrySpan());
+ assertFalse(aTree.isValid());
+
+ final DirCacheTree acTree = aTree.getChild(0);
+ assertNotNull(acTree);
+ assertSame(acTree, aTree.getChild(0));
+ assertEquals("c", acTree.getNameString());
+ assertEquals("a/c/", acTree.getPathString());
+ assertEquals(0, acTree.getChildCount());
+ assertEquals(acLast - acFirst + 1, acTree.getEntrySpan());
+ assertFalse(acTree.isValid());
+ }
+
+ /**
+ * We had bugs related to buffer size in the DirCache. This test creates an
+ * index larger than the default BufferedInputStream buffer size. This made
+ * the DirCache unable to read the extensions when index size exceeded the
+ * buffer size (in some cases at least).
+ *
+ * @throws CorruptObjectException
+ * @throws IOException
+ */
+ public void testWriteReadTree() throws CorruptObjectException, IOException {
+ final DirCache dc = DirCache.lock(db);
+
+ final String A = String.format("a%2000s", "a");
+ final String B = String.format("b%2000s", "b");
+ final String[] paths = { A + ".", A + "." + B, A + "/" + B, A + "0" + B };
+ final DirCacheEntry[] ents = new DirCacheEntry[paths.length];
+ for (int i = 0; i < paths.length; i++)
+ ents[i] = new DirCacheEntry(paths[i]);
+
+ final DirCacheBuilder b = dc.builder();
+ for (int i = 0; i < ents.length; i++)
+ b.add(ents[i]);
+
+ b.commit();
+ DirCache read = DirCache.read(db);
+
+ assertEquals(paths.length, read.getEntryCount());
+ assertEquals(1, read.getCacheTree(true).getChildCount());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/fnmatch/FileNameMatcherTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/fnmatch/FileNameMatcherTest.java
new file mode 100644
index 0000000000..752a1e2f68
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/fnmatch/FileNameMatcherTest.java
@@ -0,0 +1,764 @@
+/*
+ * Copyright (C) 2008, Florian Koeberle <florianskarten@web.de>
+ * Copyright (C) 2008, Florian Köberle <florianskarten@web.de>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.fnmatch;
+
+import org.eclipse.jgit.errors.InvalidPatternException;
+import org.eclipse.jgit.fnmatch.FileNameMatcher;
+
+import junit.framework.TestCase;
+
+public class FileNameMatcherTest extends TestCase {
+
+ private void assertMatch(final String pattern, final String input,
+ final boolean matchExpected, final boolean appendCanMatchExpected)
+ throws InvalidPatternException {
+ final FileNameMatcher matcher = new FileNameMatcher(pattern, null);
+ matcher.append(input);
+ assertEquals(matchExpected, matcher.isMatch());
+ assertEquals(appendCanMatchExpected, matcher.canAppendMatch());
+ }
+
+ private void assertFileNameMatch(final String pattern, final String input,
+ final char excludedCharacter, final boolean matchExpected,
+ final boolean appendCanMatchExpected)
+ throws InvalidPatternException {
+ final FileNameMatcher matcher = new FileNameMatcher(pattern,
+ new Character(excludedCharacter));
+ matcher.append(input);
+ assertEquals(matchExpected, matcher.isMatch());
+ assertEquals(appendCanMatchExpected, matcher.canAppendMatch());
+ }
+
+ public void testVerySimplePatternCase0() throws Exception {
+ assertMatch("", "", true, false);
+ }
+
+ public void testVerySimplePatternCase1() throws Exception {
+ assertMatch("ab", "a", false, true);
+ }
+
+ public void testVerySimplePatternCase2() throws Exception {
+ assertMatch("ab", "ab", true, false);
+ }
+
+ public void testVerySimplePatternCase3() throws Exception {
+ assertMatch("ab", "ac", false, false);
+ }
+
+ public void testVerySimplePatternCase4() throws Exception {
+ assertMatch("ab", "abc", false, false);
+ }
+
+ public void testVerySimpleWirdcardCase0() throws Exception {
+ assertMatch("?", "a", true, false);
+ }
+
+ public void testVerySimpleWildCardCase1() throws Exception {
+ assertMatch("??", "a", false, true);
+ }
+
+ public void testVerySimpleWildCardCase2() throws Exception {
+ assertMatch("??", "ab", true, false);
+ }
+
+ public void testVerySimpleWildCardCase3() throws Exception {
+ assertMatch("??", "abc", false, false);
+ }
+
+ public void testVerySimpleStarCase0() throws Exception {
+ assertMatch("*", "", true, true);
+ }
+
+ public void testVerySimpleStarCase1() throws Exception {
+ assertMatch("*", "a", true, true);
+ }
+
+ public void testVerySimpleStarCase2() throws Exception {
+ assertMatch("*", "ab", true, true);
+ }
+
+ public void testSimpleStarCase0() throws Exception {
+ assertMatch("a*b", "a", false, true);
+ }
+
+ public void testSimpleStarCase1() throws Exception {
+ assertMatch("a*c", "ac", true, true);
+ }
+
+ public void testSimpleStarCase2() throws Exception {
+ assertMatch("a*c", "ab", false, true);
+ }
+
+ public void testSimpleStarCase3() throws Exception {
+ assertMatch("a*c", "abc", true, true);
+ }
+
+ public void testManySolutionsCase0() throws Exception {
+ assertMatch("a*a*a", "aaa", true, true);
+ }
+
+ public void testManySolutionsCase1() throws Exception {
+ assertMatch("a*a*a", "aaaa", true, true);
+ }
+
+ public void testManySolutionsCase2() throws Exception {
+ assertMatch("a*a*a", "ababa", true, true);
+ }
+
+ public void testManySolutionsCase3() throws Exception {
+ assertMatch("a*a*a", "aaaaaaaa", true, true);
+ }
+
+ public void testManySolutionsCase4() throws Exception {
+ assertMatch("a*a*a", "aaaaaaab", false, true);
+ }
+
+ public void testVerySimpleGroupCase0() throws Exception {
+ assertMatch("[ab]", "a", true, false);
+ }
+
+ public void testVerySimpleGroupCase1() throws Exception {
+ assertMatch("[ab]", "b", true, false);
+ }
+
+ public void testVerySimpleGroupCase2() throws Exception {
+ assertMatch("[ab]", "ab", false, false);
+ }
+
+ public void testVerySimpleGroupRangeCase0() throws Exception {
+ assertMatch("[b-d]", "a", false, false);
+ }
+
+ public void testVerySimpleGroupRangeCase1() throws Exception {
+ assertMatch("[b-d]", "b", true, false);
+ }
+
+ public void testVerySimpleGroupRangeCase2() throws Exception {
+ assertMatch("[b-d]", "c", true, false);
+ }
+
+ public void testVerySimpleGroupRangeCase3() throws Exception {
+ assertMatch("[b-d]", "d", true, false);
+ }
+
+ public void testVerySimpleGroupRangeCase4() throws Exception {
+ assertMatch("[b-d]", "e", false, false);
+ }
+
+ public void testVerySimpleGroupRangeCase5() throws Exception {
+ assertMatch("[b-d]", "-", false, false);
+ }
+
+ public void testTwoGroupsCase0() throws Exception {
+ assertMatch("[b-d][ab]", "bb", true, false);
+ }
+
+ public void testTwoGroupsCase1() throws Exception {
+ assertMatch("[b-d][ab]", "ca", true, false);
+ }
+
+ public void testTwoGroupsCase2() throws Exception {
+ assertMatch("[b-d][ab]", "fa", false, false);
+ }
+
+ public void testTwoGroupsCase3() throws Exception {
+ assertMatch("[b-d][ab]", "bc", false, false);
+ }
+
+ public void testTwoRangesInOneGroupCase0() throws Exception {
+ assertMatch("[b-ce-e]", "a", false, false);
+ }
+
+ public void testTwoRangesInOneGroupCase1() throws Exception {
+ assertMatch("[b-ce-e]", "b", true, false);
+ }
+
+ public void testTwoRangesInOneGroupCase2() throws Exception {
+ assertMatch("[b-ce-e]", "c", true, false);
+ }
+
+ public void testTwoRangesInOneGroupCase3() throws Exception {
+ assertMatch("[b-ce-e]", "d", false, false);
+ }
+
+ public void testTwoRangesInOneGroupCase4() throws Exception {
+ assertMatch("[b-ce-e]", "e", true, false);
+ }
+
+ public void testTwoRangesInOneGroupCase5() throws Exception {
+ assertMatch("[b-ce-e]", "f", false, false);
+ }
+
+ public void testIncompleteRangesInOneGroupCase0() throws Exception {
+ assertMatch("a[b-]", "ab", true, false);
+ }
+
+ public void testIncompleteRangesInOneGroupCase1() throws Exception {
+ assertMatch("a[b-]", "ac", false, false);
+ }
+
+ public void testIncompleteRangesInOneGroupCase2() throws Exception {
+ assertMatch("a[b-]", "a-", true, false);
+ }
+
+ public void testCombinedRangesInOneGroupCase0() throws Exception {
+ assertMatch("[a-c-e]", "b", true, false);
+ }
+
+ /**
+ * The c belongs to the range a-c. "-e" is no valid range so d should not
+ * match.
+ *
+ * @throws Exception
+ * for some reasons
+ */
+ public void testCombinedRangesInOneGroupCase1() throws Exception {
+ assertMatch("[a-c-e]", "d", false, false);
+ }
+
+ public void testCombinedRangesInOneGroupCase2() throws Exception {
+ assertMatch("[a-c-e]", "e", true, false);
+ }
+
+ public void testInversedGroupCase0() throws Exception {
+ assertMatch("[!b-c]", "a", true, false);
+ }
+
+ public void testInversedGroupCase1() throws Exception {
+ assertMatch("[!b-c]", "b", false, false);
+ }
+
+ public void testInversedGroupCase2() throws Exception {
+ assertMatch("[!b-c]", "c", false, false);
+ }
+
+ public void testInversedGroupCase3() throws Exception {
+ assertMatch("[!b-c]", "d", true, false);
+ }
+
+ public void testAlphaGroupCase0() throws Exception {
+ assertMatch("[[:alpha:]]", "d", true, false);
+ }
+
+ public void testAlphaGroupCase1() throws Exception {
+ assertMatch("[[:alpha:]]", ":", false, false);
+ }
+
+ public void testAlphaGroupCase2() throws Exception {
+ // \u00f6 = 'o' with dots on it
+ assertMatch("[[:alpha:]]", "\u00f6", true, false);
+ }
+
+ public void test2AlphaGroupsCase0() throws Exception {
+ // \u00f6 = 'o' with dots on it
+ assertMatch("[[:alpha:]][[:alpha:]]", "a\u00f6", true, false);
+ assertMatch("[[:alpha:]][[:alpha:]]", "a1", false, false);
+ }
+
+ public void testAlnumGroupCase0() throws Exception {
+ assertMatch("[[:alnum:]]", "a", true, false);
+ }
+
+ public void testAlnumGroupCase1() throws Exception {
+ assertMatch("[[:alnum:]]", "1", true, false);
+ }
+
+ public void testAlnumGroupCase2() throws Exception {
+ assertMatch("[[:alnum:]]", ":", false, false);
+ }
+
+ public void testBlankGroupCase0() throws Exception {
+ assertMatch("[[:blank:]]", " ", true, false);
+ }
+
+ public void testBlankGroupCase1() throws Exception {
+ assertMatch("[[:blank:]]", "\t", true, false);
+ }
+
+ public void testBlankGroupCase2() throws Exception {
+ assertMatch("[[:blank:]]", "\r", false, false);
+ }
+
+ public void testBlankGroupCase3() throws Exception {
+ assertMatch("[[:blank:]]", "\n", false, false);
+ }
+
+ public void testBlankGroupCase4() throws Exception {
+ assertMatch("[[:blank:]]", "a", false, false);
+ }
+
+ public void testCntrlGroupCase0() throws Exception {
+ assertMatch("[[:cntrl:]]", "a", false, false);
+ }
+
+ public void testCntrlGroupCase1() throws Exception {
+ assertMatch("[[:cntrl:]]", String.valueOf((char) 7), true, false);
+ }
+
+ public void testDigitGroupCase0() throws Exception {
+ assertMatch("[[:digit:]]", "0", true, false);
+ }
+
+ public void testDigitGroupCase1() throws Exception {
+ assertMatch("[[:digit:]]", "5", true, false);
+ }
+
+ public void testDigitGroupCase2() throws Exception {
+ assertMatch("[[:digit:]]", "9", true, false);
+ }
+
+ public void testDigitGroupCase3() throws Exception {
+ // \u06f9 = EXTENDED ARABIC-INDIC DIGIT NINE
+ assertMatch("[[:digit:]]", "\u06f9", true, false);
+ }
+
+ public void testDigitGroupCase4() throws Exception {
+ assertMatch("[[:digit:]]", "a", false, false);
+ }
+
+ public void testDigitGroupCase5() throws Exception {
+ assertMatch("[[:digit:]]", "]", false, false);
+ }
+
+ public void testGraphGroupCase0() throws Exception {
+ assertMatch("[[:graph:]]", "]", true, false);
+ }
+
+ public void testGraphGroupCase1() throws Exception {
+ assertMatch("[[:graph:]]", "a", true, false);
+ }
+
+ public void testGraphGroupCase2() throws Exception {
+ assertMatch("[[:graph:]]", ".", true, false);
+ }
+
+ public void testGraphGroupCase3() throws Exception {
+ assertMatch("[[:graph:]]", "0", true, false);
+ }
+
+ public void testGraphGroupCase4() throws Exception {
+ assertMatch("[[:graph:]]", " ", false, false);
+ }
+
+ public void testGraphGroupCase5() throws Exception {
+ // \u00f6 = 'o' with dots on it
+ assertMatch("[[:graph:]]", "\u00f6", true, false);
+ }
+
+ public void testLowerGroupCase0() throws Exception {
+ assertMatch("[[:lower:]]", "a", true, false);
+ }
+
+ public void testLowerGroupCase1() throws Exception {
+ assertMatch("[[:lower:]]", "h", true, false);
+ }
+
+ public void testLowerGroupCase2() throws Exception {
+ assertMatch("[[:lower:]]", "A", false, false);
+ }
+
+ public void testLowerGroupCase3() throws Exception {
+ assertMatch("[[:lower:]]", "H", false, false);
+ }
+
+ public void testLowerGroupCase4() throws Exception {
+ // \u00e4 = small 'a' with dots on it
+ assertMatch("[[:lower:]]", "\u00e4", true, false);
+ }
+
+ public void testLowerGroupCase5() throws Exception {
+ assertMatch("[[:lower:]]", ".", false, false);
+ }
+
+ public void testPrintGroupCase0() throws Exception {
+ assertMatch("[[:print:]]", "]", true, false);
+ }
+
+ public void testPrintGroupCase1() throws Exception {
+ assertMatch("[[:print:]]", "a", true, false);
+ }
+
+ public void testPrintGroupCase2() throws Exception {
+ assertMatch("[[:print:]]", ".", true, false);
+ }
+
+ public void testPrintGroupCase3() throws Exception {
+ assertMatch("[[:print:]]", "0", true, false);
+ }
+
+ public void testPrintGroupCase4() throws Exception {
+ assertMatch("[[:print:]]", " ", true, false);
+ }
+
+ public void testPrintGroupCase5() throws Exception {
+ // \u00f6 = 'o' with dots on it
+ assertMatch("[[:print:]]", "\u00f6", true, false);
+ }
+
+ public void testPunctGroupCase0() throws Exception {
+ assertMatch("[[:punct:]]", ".", true, false);
+ }
+
+ public void testPunctGroupCase1() throws Exception {
+ assertMatch("[[:punct:]]", "@", true, false);
+ }
+
+ public void testPunctGroupCase2() throws Exception {
+ assertMatch("[[:punct:]]", " ", false, false);
+ }
+
+ public void testPunctGroupCase3() throws Exception {
+ assertMatch("[[:punct:]]", "a", false, false);
+ }
+
+ public void testSpaceGroupCase0() throws Exception {
+ assertMatch("[[:space:]]", " ", true, false);
+ }
+
+ public void testSpaceGroupCase1() throws Exception {
+ assertMatch("[[:space:]]", "\t", true, false);
+ }
+
+ public void testSpaceGroupCase2() throws Exception {
+ assertMatch("[[:space:]]", "\r", true, false);
+ }
+
+ public void testSpaceGroupCase3() throws Exception {
+ assertMatch("[[:space:]]", "\n", true, false);
+ }
+
+ public void testSpaceGroupCase4() throws Exception {
+ assertMatch("[[:space:]]", "a", false, false);
+ }
+
+ public void testUpperGroupCase0() throws Exception {
+ assertMatch("[[:upper:]]", "a", false, false);
+ }
+
+ public void testUpperGroupCase1() throws Exception {
+ assertMatch("[[:upper:]]", "h", false, false);
+ }
+
+ public void testUpperGroupCase2() throws Exception {
+ assertMatch("[[:upper:]]", "A", true, false);
+ }
+
+ public void testUpperGroupCase3() throws Exception {
+ assertMatch("[[:upper:]]", "H", true, false);
+ }
+
+ public void testUpperGroupCase4() throws Exception {
+ // \u00c4 = 'A' with dots on it
+ assertMatch("[[:upper:]]", "\u00c4", true, false);
+ }
+
+ public void testUpperGroupCase5() throws Exception {
+ assertMatch("[[:upper:]]", ".", false, false);
+ }
+
+ public void testXDigitGroupCase0() throws Exception {
+ assertMatch("[[:xdigit:]]", "a", true, false);
+ }
+
+ public void testXDigitGroupCase1() throws Exception {
+ assertMatch("[[:xdigit:]]", "d", true, false);
+ }
+
+ public void testXDigitGroupCase2() throws Exception {
+ assertMatch("[[:xdigit:]]", "f", true, false);
+ }
+
+ public void testXDigitGroupCase3() throws Exception {
+ assertMatch("[[:xdigit:]]", "0", true, false);
+ }
+
+ public void testXDigitGroupCase4() throws Exception {
+ assertMatch("[[:xdigit:]]", "5", true, false);
+ }
+
+ public void testXDigitGroupCase5() throws Exception {
+ assertMatch("[[:xdigit:]]", "9", true, false);
+ }
+
+ public void testXDigitGroupCase6() throws Exception {
+ assertMatch("[[:xdigit:]]", "۹", false, false);
+ }
+
+ public void testXDigitGroupCase7() throws Exception {
+ assertMatch("[[:xdigit:]]", ".", false, false);
+ }
+
+ public void testWordroupCase0() throws Exception {
+ assertMatch("[[:word:]]", "g", true, false);
+ }
+
+ public void testWordroupCase1() throws Exception {
+ // \u00f6 = 'o' with dots on it
+ assertMatch("[[:word:]]", "\u00f6", true, false);
+ }
+
+ public void testWordroupCase2() throws Exception {
+ assertMatch("[[:word:]]", "5", true, false);
+ }
+
+ public void testWordroupCase3() throws Exception {
+ assertMatch("[[:word:]]", "_", true, false);
+ }
+
+ public void testWordroupCase4() throws Exception {
+ assertMatch("[[:word:]]", " ", false, false);
+ }
+
+ public void testWordroupCase5() throws Exception {
+ assertMatch("[[:word:]]", ".", false, false);
+ }
+
+ public void testMixedGroupCase0() throws Exception {
+ assertMatch("[A[:lower:]C3-5]", "A", true, false);
+ }
+
+ public void testMixedGroupCase1() throws Exception {
+ assertMatch("[A[:lower:]C3-5]", "C", true, false);
+ }
+
+ public void testMixedGroupCase2() throws Exception {
+ assertMatch("[A[:lower:]C3-5]", "e", true, false);
+ }
+
+ public void testMixedGroupCase3() throws Exception {
+ assertMatch("[A[:lower:]C3-5]", "3", true, false);
+ }
+
+ public void testMixedGroupCase4() throws Exception {
+ assertMatch("[A[:lower:]C3-5]", "4", true, false);
+ }
+
+ public void testMixedGroupCase5() throws Exception {
+ assertMatch("[A[:lower:]C3-5]", "5", true, false);
+ }
+
+ public void testMixedGroupCase6() throws Exception {
+ assertMatch("[A[:lower:]C3-5]", "B", false, false);
+ }
+
+ public void testMixedGroupCase7() throws Exception {
+ assertMatch("[A[:lower:]C3-5]", "2", false, false);
+ }
+
+ public void testMixedGroupCase8() throws Exception {
+ assertMatch("[A[:lower:]C3-5]", "6", false, false);
+ }
+
+ public void testMixedGroupCase9() throws Exception {
+ assertMatch("[A[:lower:]C3-5]", ".", false, false);
+ }
+
+ public void testSpecialGroupCase0() throws Exception {
+ assertMatch("[[]", "[", true, false);
+ }
+
+ public void testSpecialGroupCase1() throws Exception {
+ assertMatch("[]]", "]", true, false);
+ }
+
+ public void testSpecialGroupCase2() throws Exception {
+ assertMatch("[]a]", "]", true, false);
+ }
+
+ public void testSpecialGroupCase3() throws Exception {
+ assertMatch("[a[]", "[", true, false);
+ }
+
+ public void testSpecialGroupCase4() throws Exception {
+ assertMatch("[a[]", "a", true, false);
+ }
+
+ public void testSpecialGroupCase5() throws Exception {
+ assertMatch("[!]]", "]", false, false);
+ }
+
+ public void testSpecialGroupCase6() throws Exception {
+ assertMatch("[!]]", "x", true, false);
+ }
+
+ public void testSpecialGroupCase7() throws Exception {
+ assertMatch("[:]]", ":]", true, false);
+ }
+
+ public void testSpecialGroupCase8() throws Exception {
+ assertMatch("[:]]", ":", false, true);
+ }
+
+ public void testSpecialGroupCase9() throws Exception {
+ try {
+ assertMatch("[[:]", ":", true, true);
+ fail("InvalidPatternException expected");
+ } catch (InvalidPatternException e) {
+ // expected
+ }
+ }
+
+ public void testUnsupportedGroupCase0() throws Exception {
+ try {
+ assertMatch("[[=a=]]", "b", false, false);
+ fail("InvalidPatternException expected");
+ } catch (InvalidPatternException e) {
+ assertTrue(e.getMessage().contains("[=a=]"));
+ }
+ }
+
+ public void testUnsupportedGroupCase1() throws Exception {
+ try {
+ assertMatch("[[.a.]]", "b", false, false);
+ fail("InvalidPatternException expected");
+ } catch (InvalidPatternException e) {
+ assertTrue(e.getMessage().contains("[.a.]"));
+ }
+ }
+
+ public void testFilePathSimpleCase() throws Exception {
+ assertFileNameMatch("a/b", "a/b", '/', true, false);
+ }
+
+ public void testFilePathCase0() throws Exception {
+ assertFileNameMatch("a*b", "a/b", '/', false, false);
+ }
+
+ public void testFilePathCase1() throws Exception {
+ assertFileNameMatch("a?b", "a/b", '/', false, false);
+ }
+
+ public void testFilePathCase2() throws Exception {
+ assertFileNameMatch("a*b", "a\\b", '\\', false, false);
+ }
+
+ public void testFilePathCase3() throws Exception {
+ assertFileNameMatch("a?b", "a\\b", '\\', false, false);
+ }
+
+ public void testReset() throws Exception {
+ final String pattern = "helloworld";
+ final FileNameMatcher matcher = new FileNameMatcher(pattern, null);
+ matcher.append("helloworld");
+ assertEquals(true, matcher.isMatch());
+ assertEquals(false, matcher.canAppendMatch());
+ matcher.reset();
+ matcher.append("hello");
+ assertEquals(false, matcher.isMatch());
+ assertEquals(true, matcher.canAppendMatch());
+ matcher.append("world");
+ assertEquals(true, matcher.isMatch());
+ assertEquals(false, matcher.canAppendMatch());
+ matcher.append("to much");
+ assertEquals(false, matcher.isMatch());
+ assertEquals(false, matcher.canAppendMatch());
+ matcher.reset();
+ matcher.append("helloworld");
+ assertEquals(true, matcher.isMatch());
+ assertEquals(false, matcher.canAppendMatch());
+ }
+
+ public void testCreateMatcherForSuffix() throws Exception {
+ final String pattern = "helloworld";
+ final FileNameMatcher matcher = new FileNameMatcher(pattern, null);
+ matcher.append("hello");
+ final FileNameMatcher childMatcher = matcher.createMatcherForSuffix();
+ assertEquals(false, matcher.isMatch());
+ assertEquals(true, matcher.canAppendMatch());
+ assertEquals(false, childMatcher.isMatch());
+ assertEquals(true, childMatcher.canAppendMatch());
+ matcher.append("world");
+ assertEquals(true, matcher.isMatch());
+ assertEquals(false, matcher.canAppendMatch());
+ assertEquals(false, childMatcher.isMatch());
+ assertEquals(true, childMatcher.canAppendMatch());
+ childMatcher.append("world");
+ assertEquals(true, matcher.isMatch());
+ assertEquals(false, matcher.canAppendMatch());
+ assertEquals(true, childMatcher.isMatch());
+ assertEquals(false, childMatcher.canAppendMatch());
+ childMatcher.reset();
+ assertEquals(true, matcher.isMatch());
+ assertEquals(false, matcher.canAppendMatch());
+ assertEquals(false, childMatcher.isMatch());
+ assertEquals(true, childMatcher.canAppendMatch());
+ childMatcher.append("world");
+ assertEquals(true, matcher.isMatch());
+ assertEquals(false, matcher.canAppendMatch());
+ assertEquals(true, childMatcher.isMatch());
+ assertEquals(false, childMatcher.canAppendMatch());
+ }
+
+ public void testCopyConstructor() throws Exception {
+ final String pattern = "helloworld";
+ final FileNameMatcher matcher = new FileNameMatcher(pattern, null);
+ matcher.append("hello");
+ final FileNameMatcher copy = new FileNameMatcher(matcher);
+ assertEquals(false, matcher.isMatch());
+ assertEquals(true, matcher.canAppendMatch());
+ assertEquals(false, copy.isMatch());
+ assertEquals(true, copy.canAppendMatch());
+ matcher.append("world");
+ assertEquals(true, matcher.isMatch());
+ assertEquals(false, matcher.canAppendMatch());
+ assertEquals(false, copy.isMatch());
+ assertEquals(true, copy.canAppendMatch());
+ copy.append("world");
+ assertEquals(true, matcher.isMatch());
+ assertEquals(false, matcher.canAppendMatch());
+ assertEquals(true, copy.isMatch());
+ assertEquals(false, copy.canAppendMatch());
+ copy.reset();
+ assertEquals(true, matcher.isMatch());
+ assertEquals(false, matcher.canAppendMatch());
+ assertEquals(false, copy.isMatch());
+ assertEquals(true, copy.canAppendMatch());
+ copy.append("helloworld");
+ assertEquals(true, matcher.isMatch());
+ assertEquals(false, matcher.canAppendMatch());
+ assertEquals(true, copy.isMatch());
+ assertEquals(false, copy.canAppendMatch());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/AbbreviatedObjectIdTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/AbbreviatedObjectIdTest.java
new file mode 100644
index 0000000000..45f8907da7
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/AbbreviatedObjectIdTest.java
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import junit.framework.TestCase;
+
+public class AbbreviatedObjectIdTest extends TestCase {
+ public void testEmpty_FromByteArray() {
+ final AbbreviatedObjectId i;
+ i = AbbreviatedObjectId.fromString(new byte[] {}, 0, 0);
+ assertNotNull(i);
+ assertEquals(0, i.length());
+ assertFalse(i.isComplete());
+ assertEquals("", i.name());
+ }
+
+ public void testEmpty_FromString() {
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString("");
+ assertNotNull(i);
+ assertEquals(0, i.length());
+ assertFalse(i.isComplete());
+ assertEquals("", i.name());
+ }
+
+ public void testFull_FromByteArray() {
+ final String s = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
+ final byte[] b = Constants.encodeASCII(s);
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(b, 0,
+ b.length);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertTrue(i.isComplete());
+ assertEquals(s, i.name());
+
+ final ObjectId f = i.toObjectId();
+ assertNotNull(f);
+ assertEquals(ObjectId.fromString(s), f);
+ assertEquals(f.hashCode(), i.hashCode());
+ }
+
+ public void testFull_FromString() {
+ final String s = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertTrue(i.isComplete());
+ assertEquals(s, i.name());
+
+ final ObjectId f = i.toObjectId();
+ assertNotNull(f);
+ assertEquals(ObjectId.fromString(s), f);
+ assertEquals(f.hashCode(), i.hashCode());
+ }
+
+ public void test1_FromString() {
+ final String s = "7";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertFalse(i.isComplete());
+ assertEquals(s, i.name());
+ assertNull(i.toObjectId());
+ }
+
+ public void test2_FromString() {
+ final String s = "7b";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertFalse(i.isComplete());
+ assertEquals(s, i.name());
+ assertNull(i.toObjectId());
+ }
+
+ public void test3_FromString() {
+ final String s = "7b6";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertFalse(i.isComplete());
+ assertEquals(s, i.name());
+ assertNull(i.toObjectId());
+ }
+
+ public void test4_FromString() {
+ final String s = "7b6e";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertFalse(i.isComplete());
+ assertEquals(s, i.name());
+ assertNull(i.toObjectId());
+ }
+
+ public void test5_FromString() {
+ final String s = "7b6e8";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertFalse(i.isComplete());
+ assertEquals(s, i.name());
+ assertNull(i.toObjectId());
+ }
+
+ public void test6_FromString() {
+ final String s = "7b6e80";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertFalse(i.isComplete());
+ assertEquals(s, i.name());
+ assertNull(i.toObjectId());
+ }
+
+ public void test7_FromString() {
+ final String s = "7b6e806";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertFalse(i.isComplete());
+ assertEquals(s, i.name());
+ assertNull(i.toObjectId());
+ }
+
+ public void test8_FromString() {
+ final String s = "7b6e8067";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertFalse(i.isComplete());
+ assertEquals(s, i.name());
+ assertNull(i.toObjectId());
+ }
+
+ public void test9_FromString() {
+ final String s = "7b6e8067e";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertFalse(i.isComplete());
+ assertEquals(s, i.name());
+ assertNull(i.toObjectId());
+ }
+
+ public void test17_FromString() {
+ final String s = "7b6e8067ec96acef9";
+ final AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);
+ assertNotNull(i);
+ assertEquals(s.length(), i.length());
+ assertFalse(i.isComplete());
+ assertEquals(s, i.name());
+ assertNull(i.toObjectId());
+ }
+
+ public void testEquals_Short() {
+ final String s = "7b6e8067";
+ final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(s);
+ final AbbreviatedObjectId b = AbbreviatedObjectId.fromString(s);
+ assertNotSame(a, b);
+ assertTrue(a.hashCode() == b.hashCode());
+ assertTrue(a.equals(b));
+ assertTrue(b.equals(a));
+ }
+
+ public void testEquals_Full() {
+ final String s = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
+ final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(s);
+ final AbbreviatedObjectId b = AbbreviatedObjectId.fromString(s);
+ assertNotSame(a, b);
+ assertTrue(a.hashCode() == b.hashCode());
+ assertTrue(a.equals(b));
+ assertTrue(b.equals(a));
+ }
+
+ public void testNotEquals_SameLength() {
+ final String sa = "7b6e8067";
+ final String sb = "7b6e806e";
+ final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa);
+ final AbbreviatedObjectId b = AbbreviatedObjectId.fromString(sb);
+ assertFalse(a.equals(b));
+ assertFalse(b.equals(a));
+ }
+
+ public void testNotEquals_DiffLength() {
+ final String sa = "7b6e8067abcd";
+ final String sb = "7b6e8067";
+ final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa);
+ final AbbreviatedObjectId b = AbbreviatedObjectId.fromString(sb);
+ assertFalse(a.equals(b));
+ assertFalse(b.equals(a));
+ }
+
+ public void testPrefixCompare_Full() {
+ final String s1 = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
+ final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(s1);
+ final ObjectId i1 = ObjectId.fromString(s1);
+ assertEquals(0, a.prefixCompare(i1));
+ assertTrue(i1.startsWith(a));
+
+ final String s2 = "7b6e8067ec96acef9a4184b43210d583b6d2f99b";
+ final ObjectId i2 = ObjectId.fromString(s2);
+ assertTrue(a.prefixCompare(i2) < 0);
+ assertFalse(i2.startsWith(a));
+
+ final String s3 = "7b6e8067ec96acef9a4184b43210d583b6d2f999";
+ final ObjectId i3 = ObjectId.fromString(s3);
+ assertTrue(a.prefixCompare(i3) > 0);
+ assertFalse(i3.startsWith(a));
+ }
+
+ public void testPrefixCompare_1() {
+ final String sa = "7";
+ final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa);
+
+ final String s1 = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
+ final ObjectId i1 = ObjectId.fromString(s1);
+ assertEquals(0, a.prefixCompare(i1));
+ assertTrue(i1.startsWith(a));
+
+ final String s2 = "8b6e8067ec96acef9a4184b43210d583b6d2f99a";
+ final ObjectId i2 = ObjectId.fromString(s2);
+ assertTrue(a.prefixCompare(i2) < 0);
+ assertFalse(i2.startsWith(a));
+
+ final String s3 = "6b6e8067ec96acef9a4184b43210d583b6d2f99a";
+ final ObjectId i3 = ObjectId.fromString(s3);
+ assertTrue(a.prefixCompare(i3) > 0);
+ assertFalse(i3.startsWith(a));
+ }
+
+ public void testPrefixCompare_7() {
+ final String sa = "7b6e806";
+ final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa);
+
+ final String s1 = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
+ final ObjectId i1 = ObjectId.fromString(s1);
+ assertEquals(0, a.prefixCompare(i1));
+ assertTrue(i1.startsWith(a));
+
+ final String s2 = "7b6e8167ec86acef9a4184b43210d583b6d2f99a";
+ final ObjectId i2 = ObjectId.fromString(s2);
+ assertTrue(a.prefixCompare(i2) < 0);
+ assertFalse(i2.startsWith(a));
+
+ final String s3 = "7b6e8057eca6acef9a4184b43210d583b6d2f99a";
+ final ObjectId i3 = ObjectId.fromString(s3);
+ assertTrue(a.prefixCompare(i3) > 0);
+ assertFalse(i3.startsWith(a));
+ }
+
+ public void testPrefixCompare_8() {
+ final String sa = "7b6e8067";
+ final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa);
+
+ final String s1 = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
+ final ObjectId i1 = ObjectId.fromString(s1);
+ assertEquals(0, a.prefixCompare(i1));
+ assertTrue(i1.startsWith(a));
+
+ final String s2 = "7b6e8167ec86acef9a4184b43210d583b6d2f99a";
+ final ObjectId i2 = ObjectId.fromString(s2);
+ assertTrue(a.prefixCompare(i2) < 0);
+ assertFalse(i2.startsWith(a));
+
+ final String s3 = "7b6e8057eca6acef9a4184b43210d583b6d2f99a";
+ final ObjectId i3 = ObjectId.fromString(s3);
+ assertTrue(a.prefixCompare(i3) > 0);
+ assertFalse(i3.startsWith(a));
+ }
+
+ public void testPrefixCompare_9() {
+ final String sa = "7b6e8067e";
+ final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa);
+
+ final String s1 = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
+ final ObjectId i1 = ObjectId.fromString(s1);
+ assertEquals(0, a.prefixCompare(i1));
+ assertTrue(i1.startsWith(a));
+
+ final String s2 = "7b6e8167ec86acef9a4184b43210d583b6d2f99a";
+ final ObjectId i2 = ObjectId.fromString(s2);
+ assertTrue(a.prefixCompare(i2) < 0);
+ assertFalse(i2.startsWith(a));
+
+ final String s3 = "7b6e8057eca6acef9a4184b43210d583b6d2f99a";
+ final ObjectId i3 = ObjectId.fromString(s3);
+ assertTrue(a.prefixCompare(i3) > 0);
+ assertFalse(i3.startsWith(a));
+ }
+
+ public void testPrefixCompare_17() {
+ final String sa = "7b6e8067ec96acef9";
+ final AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa);
+
+ final String s1 = "7b6e8067ec96acef9a4184b43210d583b6d2f99a";
+ final ObjectId i1 = ObjectId.fromString(s1);
+ assertEquals(0, a.prefixCompare(i1));
+ assertTrue(i1.startsWith(a));
+
+ final String s2 = "7b6e8067eca6acef9a4184b43210d583b6d2f99a";
+ final ObjectId i2 = ObjectId.fromString(s2);
+ assertTrue(a.prefixCompare(i2) < 0);
+ assertFalse(i2.startsWith(a));
+
+ final String s3 = "7b6e8067ec86acef9a4184b43210d583b6d2f99a";
+ final ObjectId i3 = ObjectId.fromString(s3);
+ assertTrue(a.prefixCompare(i3) > 0);
+ assertFalse(i3.startsWith(a));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConcurrentRepackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConcurrentRepackTest.java
new file mode 100644
index 0000000000..644c7b366c
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConcurrentRepackTest.java
@@ -0,0 +1,264 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * Copyright (C) 2009, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.revwalk.RevWalk;
+
+public class ConcurrentRepackTest extends RepositoryTestCase {
+ public void setUp() throws Exception {
+ WindowCacheConfig windowCacheConfig = new WindowCacheConfig();
+ windowCacheConfig.setPackedGitOpenFiles(1);
+ WindowCache.reconfigure(windowCacheConfig);
+ super.setUp();
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ WindowCacheConfig windowCacheConfig = new WindowCacheConfig();
+ WindowCache.reconfigure(windowCacheConfig);
+ }
+
+ public void testObjectInNewPack() throws IncorrectObjectTypeException,
+ IOException {
+ // Create a new object in a new pack, and test that it is present.
+ //
+ final Repository eden = createNewEmptyRepo();
+ final RevObject o1 = writeBlob(eden, "o1");
+ pack(eden, o1);
+ assertEquals(o1.name(), parse(o1).name());
+ }
+
+ public void testObjectMovedToNewPack1()
+ throws IncorrectObjectTypeException, IOException {
+ // Create an object and pack it. Then remove that pack and put the
+ // object into a different pack file, with some other object. We
+ // still should be able to access the objects.
+ //
+ final Repository eden = createNewEmptyRepo();
+ final RevObject o1 = writeBlob(eden, "o1");
+ final File[] out1 = pack(eden, o1);
+ assertEquals(o1.name(), parse(o1).name());
+
+ final RevObject o2 = writeBlob(eden, "o2");
+ pack(eden, o2, o1);
+
+ // Force close, and then delete, the old pack.
+ //
+ whackCache();
+ delete(out1);
+
+ // Now here is the interesting thing. Will git figure the new
+ // object exists in the new pack, and not the old one.
+ //
+ assertEquals(o2.name(), parse(o2).name());
+ assertEquals(o1.name(), parse(o1).name());
+ }
+
+ public void testObjectMovedWithinPack()
+ throws IncorrectObjectTypeException, IOException {
+ // Create an object and pack it.
+ //
+ final Repository eden = createNewEmptyRepo();
+ final RevObject o1 = writeBlob(eden, "o1");
+ final File[] out1 = pack(eden, o1);
+ assertEquals(o1.name(), parse(o1).name());
+
+ // Force close the old pack.
+ //
+ whackCache();
+
+ // Now overwrite the old pack in place. This method of creating a
+ // different pack under the same file name is partially broken. We
+ // should also have a different file name because the list of objects
+ // within the pack has been modified.
+ //
+ final RevObject o2 = writeBlob(eden, "o2");
+ final PackWriter pw = new PackWriter(eden, NullProgressMonitor.INSTANCE);
+ pw.addObject(o2);
+ pw.addObject(o1);
+ write(out1, pw);
+
+ // Try the old name, then the new name. The old name should cause the
+ // pack to reload when it opens and the index and pack mismatch.
+ //
+ assertEquals(o1.name(), parse(o1).name());
+ assertEquals(o2.name(), parse(o2).name());
+ }
+
+ public void testObjectMovedToNewPack2()
+ throws IncorrectObjectTypeException, IOException {
+ // Create an object and pack it. Then remove that pack and put the
+ // object into a different pack file, with some other object. We
+ // still should be able to access the objects.
+ //
+ final Repository eden = createNewEmptyRepo();
+ final RevObject o1 = writeBlob(eden, "o1");
+ final File[] out1 = pack(eden, o1);
+ assertEquals(o1.name(), parse(o1).name());
+
+ final ObjectLoader load1 = db.openBlob(o1);
+ assertNotNull(load1);
+
+ final RevObject o2 = writeBlob(eden, "o2");
+ pack(eden, o2, o1);
+
+ // Force close, and then delete, the old pack.
+ //
+ whackCache();
+ delete(out1);
+
+ // Now here is the interesting thing... can the loader we made
+ // earlier still resolve the object, even though its underlying
+ // pack is gone, but the object still exists.
+ //
+ final ObjectLoader load2 = db.openBlob(o1);
+ assertNotNull(load2);
+ assertNotSame(load1, load2);
+
+ final byte[] data2 = load2.getCachedBytes();
+ final byte[] data1 = load1.getCachedBytes();
+ assertNotNull(data2);
+ assertNotNull(data1);
+ assertNotSame(data1, data2); // cache should be per-pack, not per object
+ assertTrue(Arrays.equals(data1, data2));
+ assertEquals(load2.getType(), load1.getType());
+ }
+
+ private static void whackCache() {
+ final WindowCacheConfig config = new WindowCacheConfig();
+ config.setPackedGitOpenFiles(1);
+ WindowCache.reconfigure(config);
+ }
+
+ private RevObject parse(final AnyObjectId id)
+ throws MissingObjectException, IOException {
+ return new RevWalk(db).parseAny(id);
+ }
+
+ private File[] pack(final Repository src, final RevObject... list)
+ throws IOException {
+ final PackWriter pw = new PackWriter(src, NullProgressMonitor.INSTANCE);
+ for (final RevObject o : list) {
+ pw.addObject(o);
+ }
+
+ final ObjectId name = pw.computeName();
+ final File packFile = fullPackFileName(name, ".pack");
+ final File idxFile = fullPackFileName(name, ".idx");
+ final File[] files = new File[] { packFile, idxFile };
+ write(files, pw);
+ return files;
+ }
+
+ private static void write(final File[] files, final PackWriter pw)
+ throws IOException {
+ final long begin = files[0].getParentFile().lastModified();
+ FileOutputStream out;
+
+ out = new FileOutputStream(files[0]);
+ try {
+ pw.writePack(out);
+ } finally {
+ out.close();
+ }
+
+ out = new FileOutputStream(files[1]);
+ try {
+ pw.writeIndex(out);
+ } finally {
+ out.close();
+ }
+
+ touch(begin, files[0].getParentFile());
+ }
+
+ private static void delete(final File[] list) {
+ final long begin = list[0].getParentFile().lastModified();
+ for (final File f : list) {
+ f.delete();
+ assertFalse(f + " was removed", f.exists());
+ }
+ touch(begin, list[0].getParentFile());
+ }
+
+ private static void touch(final long begin, final File dir) {
+ while (begin >= dir.lastModified()) {
+ try {
+ Thread.sleep(25);
+ } catch (InterruptedException ie) {
+ //
+ }
+ dir.setLastModified(System.currentTimeMillis());
+ }
+ }
+
+ private File fullPackFileName(final ObjectId name, final String suffix) {
+ final File packdir = new File(db.getObjectsDirectory(), "pack");
+ return new File(packdir, "pack-" + name.name() + suffix);
+ }
+
+ private RevObject writeBlob(final Repository repo, final String data)
+ throws IOException {
+ final RevWalk revWalk = new RevWalk(repo);
+ final byte[] bytes = Constants.encode(data);
+ final ObjectWriter ow = new ObjectWriter(repo);
+ final ObjectId id = ow.writeBlob(bytes);
+ try {
+ parse(id);
+ fail("Object " + id.name() + " should not exist in test repository");
+ } catch (MissingObjectException e) {
+ // Ok
+ }
+ return revWalk.lookupBlob(id);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConstantsEncodingTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConstantsEncodingTest.java
new file mode 100644
index 0000000000..96568ff232
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ConstantsEncodingTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.UnsupportedEncodingException;
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+public class ConstantsEncodingTest extends TestCase {
+ public void testEncodeASCII_SimpleASCII()
+ throws UnsupportedEncodingException {
+ final String src = "abc";
+ final byte[] exp = { 'a', 'b', 'c' };
+ final byte[] res = Constants.encodeASCII(src);
+ assertTrue(Arrays.equals(exp, res));
+ assertEquals(src, new String(res, 0, res.length, "UTF-8"));
+ }
+
+ public void testEncodeASCII_FailOnNonASCII() {
+ final String src = "Ūnĭcōde̽";
+ try {
+ Constants.encodeASCII(src);
+ fail("Incorrectly accepted a Unicode character");
+ } catch (IllegalArgumentException err) {
+ assertEquals("Not ASCII string: " + src, err.getMessage());
+ }
+ }
+
+ public void testEncodeASCII_Number13() {
+ final long src = 13;
+ final byte[] exp = { '1', '3' };
+ final byte[] res = Constants.encodeASCII(src);
+ assertTrue(Arrays.equals(exp, res));
+ }
+
+ public void testEncode_SimpleASCII() throws UnsupportedEncodingException {
+ final String src = "abc";
+ final byte[] exp = { 'a', 'b', 'c' };
+ final byte[] res = Constants.encode(src);
+ assertTrue(Arrays.equals(exp, res));
+ assertEquals(src, new String(res, 0, res.length, "UTF-8"));
+ }
+
+ public void testEncode_Unicode() throws UnsupportedEncodingException {
+ final String src = "Ūnĭcōde̽";
+ final byte[] exp = { (byte) 0xC5, (byte) 0xAA, 0x6E, (byte) 0xC4,
+ (byte) 0xAD, 0x63, (byte) 0xC5, (byte) 0x8D, 0x64, 0x65,
+ (byte) 0xCC, (byte) 0xBD };
+ final byte[] res = Constants.encode(src);
+ assertTrue(Arrays.equals(exp, res));
+ assertEquals(src, new String(res, 0, res.length, "UTF-8"));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
new file mode 100644
index 0000000000..f871cc0524
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.File;
+import java.io.IOException;
+
+public class IndexDiffTest extends RepositoryTestCase {
+ public void testAdded() throws IOException {
+ GitIndex index = new GitIndex(db);
+ writeTrashFile("file1", "file1");
+ writeTrashFile("dir/subfile", "dir/subfile");
+ Tree tree = new Tree(db);
+
+ index.add(trash, new File(trash, "file1"));
+ index.add(trash, new File(trash, "dir/subfile"));
+ IndexDiff diff = new IndexDiff(tree, index);
+ diff.diff();
+ assertEquals(2, diff.getAdded().size());
+ assertTrue(diff.getAdded().contains("file1"));
+ assertTrue(diff.getAdded().contains("dir/subfile"));
+ assertEquals(0, diff.getChanged().size());
+ assertEquals(0, diff.getModified().size());
+ assertEquals(0, diff.getRemoved().size());
+ }
+
+ public void testRemoved() throws IOException {
+ GitIndex index = new GitIndex(db);
+ writeTrashFile("file2", "file2");
+ writeTrashFile("dir/file3", "dir/file3");
+
+ Tree tree = new Tree(db);
+ tree.addFile("file2");
+ tree.addFile("dir/file3");
+ assertEquals(2, tree.memberCount());
+ tree.findBlobMember("file2").setId(ObjectId.fromString("30d67d4672d5c05833b7192cc77a79eaafb5c7ad"));
+ Tree tree2 = (Tree) tree.findTreeMember("dir");
+ tree2.findBlobMember("file3").setId(ObjectId.fromString("873fb8d667d05436d728c52b1d7a09528e6eb59b"));
+ tree2.setId(new ObjectWriter(db).writeTree(tree2));
+ tree.setId(new ObjectWriter(db).writeTree(tree));
+
+ IndexDiff diff = new IndexDiff(tree, index);
+ diff.diff();
+ assertEquals(2, diff.getRemoved().size());
+ assertTrue(diff.getRemoved().contains("file2"));
+ assertTrue(diff.getRemoved().contains("dir/file3"));
+ assertEquals(0, diff.getChanged().size());
+ assertEquals(0, diff.getModified().size());
+ assertEquals(0, diff.getAdded().size());
+ }
+
+ public void testModified() throws IOException {
+ GitIndex index = new GitIndex(db);
+
+
+ index.add(trash, writeTrashFile("file2", "file2"));
+ index.add(trash, writeTrashFile("dir/file3", "dir/file3"));
+
+ writeTrashFile("dir/file3", "changed");
+
+ Tree tree = new Tree(db);
+ tree.addFile("file2").setId(ObjectId.fromString("0123456789012345678901234567890123456789"));
+ tree.addFile("dir/file3").setId(ObjectId.fromString("0123456789012345678901234567890123456789"));
+ assertEquals(2, tree.memberCount());
+
+ Tree tree2 = (Tree) tree.findTreeMember("dir");
+ tree2.setId(new ObjectWriter(db).writeTree(tree2));
+ tree.setId(new ObjectWriter(db).writeTree(tree));
+ IndexDiff diff = new IndexDiff(tree, index);
+ diff.diff();
+ assertEquals(2, diff.getChanged().size());
+ assertTrue(diff.getChanged().contains("file2"));
+ assertTrue(diff.getChanged().contains("dir/file3"));
+ assertEquals(1, diff.getModified().size());
+ assertTrue(diff.getModified().contains("dir/file3"));
+ assertEquals(0, diff.getAdded().size());
+ assertEquals(0, diff.getRemoved().size());
+ assertEquals(0, diff.getMissing().size());
+ }
+
+ public void testUnchangedSimple() throws IOException {
+ GitIndex index = new GitIndex(db);
+
+ index.add(trash, writeTrashFile("a.b", "a.b"));
+ index.add(trash, writeTrashFile("a.c", "a.c"));
+ index.add(trash, writeTrashFile("a=c", "a=c"));
+ index.add(trash, writeTrashFile("a=d", "a=d"));
+
+ Tree tree = new Tree(db);
+ // got the hash id'd from the data using echo -n a.b|git hash-object -t blob --stdin
+ tree.addFile("a.b").setId(ObjectId.fromString("f6f28df96c2b40c951164286e08be7c38ec74851"));
+ tree.addFile("a.c").setId(ObjectId.fromString("6bc0e647512d2a0bef4f26111e484dc87df7f5ca"));
+ tree.addFile("a=c").setId(ObjectId.fromString("06022365ddbd7fb126761319633bf73517770714"));
+ tree.addFile("a=d").setId(ObjectId.fromString("fa6414df3da87840700e9eeb7fc261dd77ccd5c2"));
+
+ tree.setId(new ObjectWriter(db).writeTree(tree));
+
+ IndexDiff diff = new IndexDiff(tree, index);
+ diff.diff();
+ assertEquals(0, diff.getChanged().size());
+ assertEquals(0, diff.getAdded().size());
+ assertEquals(0, diff.getRemoved().size());
+ assertEquals(0, diff.getMissing().size());
+ assertEquals(0, diff.getModified().size());
+ }
+
+ /**
+ * This test has both files and directories that involve
+ * the tricky ordering used by Git.
+ *
+ * @throws IOException
+ */
+ public void testUnchangedComplex() throws IOException {
+ GitIndex index = new GitIndex(db);
+
+ index.add(trash, writeTrashFile("a.b", "a.b"));
+ index.add(trash, writeTrashFile("a.c", "a.c"));
+ index.add(trash, writeTrashFile("a/b.b/b", "a/b.b/b"));
+ index.add(trash, writeTrashFile("a/b", "a/b"));
+ index.add(trash, writeTrashFile("a/c", "a/c"));
+ index.add(trash, writeTrashFile("a=c", "a=c"));
+ index.add(trash, writeTrashFile("a=d", "a=d"));
+
+ Tree tree = new Tree(db);
+ // got the hash id'd from the data using echo -n a.b|git hash-object -t blob --stdin
+ tree.addFile("a.b").setId(ObjectId.fromString("f6f28df96c2b40c951164286e08be7c38ec74851"));
+ tree.addFile("a.c").setId(ObjectId.fromString("6bc0e647512d2a0bef4f26111e484dc87df7f5ca"));
+ tree.addFile("a/b.b/b").setId(ObjectId.fromString("8d840bd4e2f3a48ff417c8e927d94996849933fd"));
+ tree.addFile("a/b").setId(ObjectId.fromString("db89c972fc57862eae378f45b74aca228037d415"));
+ tree.addFile("a/c").setId(ObjectId.fromString("52ad142a008aeb39694bafff8e8f1be75ed7f007"));
+ tree.addFile("a=c").setId(ObjectId.fromString("06022365ddbd7fb126761319633bf73517770714"));
+ tree.addFile("a=d").setId(ObjectId.fromString("fa6414df3da87840700e9eeb7fc261dd77ccd5c2"));
+
+ Tree tree3 = (Tree) tree.findTreeMember("a/b.b");
+ tree3.setId(new ObjectWriter(db).writeTree(tree3));
+ Tree tree2 = (Tree) tree.findTreeMember("a");
+ tree2.setId(new ObjectWriter(db).writeTree(tree2));
+ tree.setId(new ObjectWriter(db).writeTree(tree));
+
+ IndexDiff diff = new IndexDiff(tree, index);
+ diff.diff();
+ assertEquals(0, diff.getChanged().size());
+ assertEquals(0, diff.getAdded().size());
+ assertEquals(0, diff.getRemoved().size());
+ assertEquals(0, diff.getMissing().size());
+ assertEquals(0, diff.getModified().size());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexTreeWalkerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexTreeWalkerTest.java
new file mode 100644
index 0000000000..eb7b622d6c
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexTreeWalkerTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
+ * Copyright (C) 2006, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import org.eclipse.jgit.lib.GitIndex.Entry;
+
+public class IndexTreeWalkerTest extends RepositoryTestCase {
+ private ArrayList<String> treeOnlyEntriesVisited = new ArrayList<String>();
+ private ArrayList<String> bothVisited = new ArrayList<String>();
+ private ArrayList<String> indexOnlyEntriesVisited = new ArrayList<String>();
+
+ private class TestIndexTreeVisitor extends AbstractIndexTreeVisitor {
+ public void visitEntry(TreeEntry treeEntry, Entry indexEntry, File file) {
+ if (treeEntry == null)
+ indexOnlyEntriesVisited.add(indexEntry.getName());
+ else if (indexEntry == null)
+ treeOnlyEntriesVisited.add(treeEntry.getFullName());
+ else bothVisited.add(indexEntry.getName());
+ }
+ }
+
+ /*
+ * Need to think about what I really need to be able to do....
+ *
+ * 1) Visit all entries in index and tree
+ * 2) Get all directories that exist in the index, but not in the tree
+ * -- I'm pretty sure that I don't need to do the other way around
+ * because I already
+ */
+
+ public void testTreeOnlyOneLevel() throws IOException {
+ GitIndex index = new GitIndex(db);
+ Tree tree = new Tree(db);
+ tree.addFile("foo");
+ tree.addFile("bar");
+
+ new IndexTreeWalker(index, tree, trash, new TestIndexTreeVisitor()).walk();
+
+ assertTrue(treeOnlyEntriesVisited.get(0).equals("bar"));
+ assertTrue(treeOnlyEntriesVisited.get(1).equals("foo"));
+ }
+
+ public void testIndexOnlyOneLevel() throws IOException {
+ GitIndex index = new GitIndex(db);
+ Tree tree = new Tree(db);
+
+ index.add(trash, writeTrashFile("foo", "foo"));
+ index.add(trash, writeTrashFile("bar", "bar"));
+ new IndexTreeWalker(index, tree, trash, new TestIndexTreeVisitor()).walk();
+
+ assertTrue(indexOnlyEntriesVisited.get(0).equals("bar"));
+ assertTrue(indexOnlyEntriesVisited.get(1).equals("foo"));
+ }
+
+ public void testBoth() throws IOException {
+ GitIndex index = new GitIndex(db);
+ Tree tree = new Tree(db);
+
+ index.add(trash, writeTrashFile("a", "a"));
+ tree.addFile("b/b");
+ index.add(trash, writeTrashFile("c", "c"));
+ tree.addFile("c");
+
+ new IndexTreeWalker(index, tree, trash, new TestIndexTreeVisitor()).walk();
+ assertTrue(indexOnlyEntriesVisited.contains("a"));
+ assertTrue(treeOnlyEntriesVisited.contains("b/b"));
+ assertTrue(bothVisited.contains("c"));
+
+ }
+
+ public void testIndexOnlySubDirs() throws IOException {
+ GitIndex index = new GitIndex(db);
+ Tree tree = new Tree(db);
+
+ index.add(trash, writeTrashFile("foo/bar/baz", "foobar"));
+ index.add(trash, writeTrashFile("asdf", "asdf"));
+ new IndexTreeWalker(index, tree, trash, new TestIndexTreeVisitor()).walk();
+
+ assertEquals("asdf", indexOnlyEntriesVisited.get(0));
+ assertEquals("foo/bar/baz", indexOnlyEntriesVisited.get(1));
+ }
+
+ public void testLeavingTree() throws IOException {
+ GitIndex index = new GitIndex(db);
+ index.add(trash, writeTrashFile("foo/bar", "foo/bar"));
+ index.add(trash, writeTrashFile("foobar", "foobar"));
+
+ new IndexTreeWalker(index, db.mapTree(index.writeTree()), trash, new AbstractIndexTreeVisitor() {
+ @Override
+ public void visitEntry(TreeEntry entry, Entry indexEntry, File f) {
+ if (entry == null || indexEntry == null)
+ fail();
+ }
+
+ @Override
+ public void finishVisitTree(Tree tree, int i, String curDir)
+ throws IOException {
+ if (tree.memberCount() == 0)
+ fail();
+ if (i == 0)
+ fail();
+ }
+
+ }).walk();
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/MockSystemReader.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/MockSystemReader.java
new file mode 100644
index 0000000000..2e94632cee
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/MockSystemReader.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * Copyright (C) 2009, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2009, Yann Simon <yann.simon.fr@gmail.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TimeZone;
+
+import org.eclipse.jgit.util.SystemReader;
+
+class MockSystemReader extends SystemReader {
+ final Map<String, String> values = new HashMap<String, String>();
+
+ FileBasedConfig userGitConfig;
+
+ MockSystemReader() {
+ init(Constants.OS_USER_NAME_KEY);
+ init(Constants.GIT_AUTHOR_NAME_KEY);
+ init(Constants.GIT_AUTHOR_EMAIL_KEY);
+ init(Constants.GIT_COMMITTER_NAME_KEY);
+ init(Constants.GIT_COMMITTER_EMAIL_KEY);
+ userGitConfig = new FileBasedConfig(null);
+ }
+
+ private void init(final String n) {
+ values.put(n, n);
+ }
+
+ public String getenv(String variable) {
+ return values.get(variable);
+ }
+
+ public String getProperty(String key) {
+ return values.get(key);
+ }
+
+ public FileBasedConfig openUserConfig() {
+ return userGitConfig;
+ }
+
+ public String getHostname() {
+ return "fake.host.example.com";
+ }
+
+ @Override
+ public long getCurrentTime() {
+ return 1250379778668L; // Sat Aug 15 20:12:58 GMT-03:30 2009
+ }
+
+ @Override
+ public int getTimezone(long when) {
+ return TimeZone.getTimeZone("GMT-3:30").getOffset(when);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
new file mode 100644
index 0000000000..7c2676bc7d
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ObjectCheckerTest.java
@@ -0,0 +1,1331 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jgit.errors.CorruptObjectException;
+
+public class ObjectCheckerTest extends TestCase {
+ private ObjectChecker checker;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ checker = new ObjectChecker();
+ }
+
+ public void testInvalidType() {
+ try {
+ checker.check(Constants.OBJ_BAD, new byte[0]);
+ fail("Did not throw CorruptObjectException");
+ } catch (CorruptObjectException e) {
+ final String m = e.getMessage();
+ assertEquals("Invalid object type: " + Constants.OBJ_BAD, m);
+ }
+ }
+
+ public void testCheckBlob() throws CorruptObjectException {
+ // Any blob should pass...
+ checker.checkBlob(new byte[0]);
+ checker.checkBlob(new byte[1]);
+
+ checker.check(Constants.OBJ_BLOB, new byte[0]);
+ checker.check(Constants.OBJ_BLOB, new byte[1]);
+ }
+
+ public void testValidCommitNoParent() throws CorruptObjectException {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("author A. U. Thor <author@localhost> 1 +0000\n");
+ b.append("committer A. U. Thor <author@localhost> 1 +0000\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkCommit(data);
+ checker.check(Constants.OBJ_COMMIT, data);
+ }
+
+ public void testValidCommitBlankAuthor() throws CorruptObjectException {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("author <> 0 +0000\n");
+ b.append("committer <> 0 +0000\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkCommit(data);
+ checker.check(Constants.OBJ_COMMIT, data);
+ }
+
+ public void testValidCommit1Parent() throws CorruptObjectException {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("parent ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("author A. U. Thor <author@localhost> 1 +0000\n");
+ b.append("committer A. U. Thor <author@localhost> 1 +0000\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkCommit(data);
+ checker.check(Constants.OBJ_COMMIT, data);
+ }
+
+ public void testValidCommit2Parent() throws CorruptObjectException {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("parent ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("parent ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("author A. U. Thor <author@localhost> 1 +0000\n");
+ b.append("committer A. U. Thor <author@localhost> 1 +0000\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkCommit(data);
+ checker.check(Constants.OBJ_COMMIT, data);
+ }
+
+ public void testValidCommit128Parent() throws CorruptObjectException {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ for (int i = 0; i < 128; i++) {
+ b.append("parent ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+ }
+
+ b.append("author A. U. Thor <author@localhost> 1 +0000\n");
+ b.append("committer A. U. Thor <author@localhost> 1 +0000\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkCommit(data);
+ checker.check(Constants.OBJ_COMMIT, data);
+ }
+
+ public void testValidCommitNormalTime() throws CorruptObjectException {
+ final StringBuilder b = new StringBuilder();
+ final String when = "1222757360 -0730";
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("author A. U. Thor <author@localhost> " + when + "\n");
+ b.append("committer A. U. Thor <author@localhost> " + when + "\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkCommit(data);
+ checker.check(Constants.OBJ_COMMIT, data);
+ }
+
+ public void testInvalidCommitNoTree1() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("parent ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ assertEquals("no tree header", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitNoTree2() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("trie ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ assertEquals("no tree header", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitNoTree3() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ assertEquals("no tree header", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitNoTree4() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree\t");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ assertEquals("no tree header", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitInvalidTree1() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("zzzzfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ assertEquals("invalid tree", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitInvalidTree2() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append("z\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ assertEquals("invalid tree", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitInvalidTree3() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9b");
+ b.append("\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ assertEquals("invalid tree", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitInvalidTree4() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ assertEquals("invalid tree", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitInvalidParent1() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("parent ");
+ b.append("\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ assertEquals("invalid parent", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitInvalidParent2() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("parent ");
+ b.append("zzzzfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append("\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ assertEquals("invalid parent", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitInvalidParent3() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("parent ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append("\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ assertEquals("invalid parent", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitInvalidParent4() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("parent ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append("z\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ assertEquals("invalid parent", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitInvalidParent5() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("parent\t");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append("\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ // Yes, really, we complain about author not being
+ // found as the invalid parent line wasn't consumed.
+ assertEquals("no author", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitNoAuthor() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("committer A. U. Thor <author@localhost> 1 +0000\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ // Yes, really, we complain about author not being
+ // found as the invalid parent line wasn't consumed.
+ assertEquals("no author", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitNoCommitter1() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("author A. U. Thor <author@localhost> 1 +0000\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ // Yes, really, we complain about author not being
+ // found as the invalid parent line wasn't consumed.
+ assertEquals("no committer", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitNoCommitter2() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("author A. U. Thor <author@localhost> 1 +0000\n");
+ b.append("\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ // Yes, really, we complain about author not being
+ // found as the invalid parent line wasn't consumed.
+ assertEquals("no committer", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitInvalidAuthor1() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("author A. U. Thor <foo 1 +0000\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ // Yes, really, we complain about author not being
+ // found as the invalid parent line wasn't consumed.
+ assertEquals("invalid author", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitInvalidAuthor2() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("author A. U. Thor foo> 1 +0000\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ // Yes, really, we complain about author not being
+ // found as the invalid parent line wasn't consumed.
+ assertEquals("invalid author", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitInvalidAuthor3() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("author 1 +0000\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ // Yes, really, we complain about author not being
+ // found as the invalid parent line wasn't consumed.
+ assertEquals("invalid author", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitInvalidAuthor4() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("author a <b> +0000\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ // Yes, really, we complain about author not being
+ // found as the invalid parent line wasn't consumed.
+ assertEquals("invalid author", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitInvalidAuthor5() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("author a <b>\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ // Yes, really, we complain about author not being
+ // found as the invalid parent line wasn't consumed.
+ assertEquals("invalid author", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitInvalidAuthor6() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("author a <b> z");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ // Yes, really, we complain about author not being
+ // found as the invalid parent line wasn't consumed.
+ assertEquals("invalid author", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitInvalidAuthor7() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("author a <b> 1 z");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ // Yes, really, we complain about author not being
+ // found as the invalid parent line wasn't consumed.
+ assertEquals("invalid author", e.getMessage());
+ }
+ }
+
+ public void testInvalidCommitInvalidCommitter() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("tree ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("author a <b> 1 +0000\n");
+ b.append("committer a <");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkCommit(data);
+ fail("Did not catch corrupt object");
+ } catch (CorruptObjectException e) {
+ // Yes, really, we complain about author not being
+ // found as the invalid parent line wasn't consumed.
+ assertEquals("invalid committer", e.getMessage());
+ }
+ }
+
+ public void testValidTag() throws CorruptObjectException {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("object ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("type commit\n");
+ b.append("tag test-tag\n");
+ b.append("tagger A. U. Thor <author@localhost> 1 +0000\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkTag(data);
+ checker.check(Constants.OBJ_TAG, data);
+ }
+
+ public void testInvalidTagNoObject1() {
+ final StringBuilder b = new StringBuilder();
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTag(data);
+ fail("incorrectly accepted invalid tag");
+ } catch (CorruptObjectException e) {
+ assertEquals("no object header", e.getMessage());
+ }
+ }
+
+ public void testInvalidTagNoObject2() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("object\t");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTag(data);
+ fail("incorrectly accepted invalid tag");
+ } catch (CorruptObjectException e) {
+ assertEquals("no object header", e.getMessage());
+ }
+ }
+
+ public void testInvalidTagNoObject3() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("obejct ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTag(data);
+ fail("incorrectly accepted invalid tag");
+ } catch (CorruptObjectException e) {
+ assertEquals("no object header", e.getMessage());
+ }
+ }
+
+ public void testInvalidTagNoObject4() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("object ");
+ b.append("zz9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTag(data);
+ fail("incorrectly accepted invalid tag");
+ } catch (CorruptObjectException e) {
+ assertEquals("invalid object", e.getMessage());
+ }
+ }
+
+ public void testInvalidTagNoObject5() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("object ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append(" \n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTag(data);
+ fail("incorrectly accepted invalid tag");
+ } catch (CorruptObjectException e) {
+ assertEquals("invalid object", e.getMessage());
+ }
+ }
+
+ public void testInvalidTagNoObject6() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("object ");
+ b.append("be9");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTag(data);
+ fail("incorrectly accepted invalid tag");
+ } catch (CorruptObjectException e) {
+ assertEquals("invalid object", e.getMessage());
+ }
+ }
+
+ public void testInvalidTagNoType1() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("object ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTag(data);
+ fail("incorrectly accepted invalid tag");
+ } catch (CorruptObjectException e) {
+ assertEquals("no type header", e.getMessage());
+ }
+ }
+
+ public void testInvalidTagNoType2() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("object ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("type\tcommit\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTag(data);
+ fail("incorrectly accepted invalid tag");
+ } catch (CorruptObjectException e) {
+ assertEquals("no type header", e.getMessage());
+ }
+ }
+
+ public void testInvalidTagNoType3() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("object ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("tpye commit\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTag(data);
+ fail("incorrectly accepted invalid tag");
+ } catch (CorruptObjectException e) {
+ assertEquals("no type header", e.getMessage());
+ }
+ }
+
+ public void testInvalidTagNoType4() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("object ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("type commit");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTag(data);
+ fail("incorrectly accepted invalid tag");
+ } catch (CorruptObjectException e) {
+ assertEquals("no tag header", e.getMessage());
+ }
+ }
+
+ public void testInvalidTagNoTagHeader1() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("object ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("type commit\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTag(data);
+ fail("incorrectly accepted invalid tag");
+ } catch (CorruptObjectException e) {
+ assertEquals("no tag header", e.getMessage());
+ }
+ }
+
+ public void testInvalidTagNoTagHeader2() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("object ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("type commit\n");
+ b.append("tag\tfoo\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTag(data);
+ fail("incorrectly accepted invalid tag");
+ } catch (CorruptObjectException e) {
+ assertEquals("no tag header", e.getMessage());
+ }
+ }
+
+ public void testInvalidTagNoTagHeader3() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("object ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("type commit\n");
+ b.append("tga foo\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTag(data);
+ fail("incorrectly accepted invalid tag");
+ } catch (CorruptObjectException e) {
+ assertEquals("no tag header", e.getMessage());
+ }
+ }
+
+ public void testInvalidTagNoTagHeader4() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("object ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("type commit\n");
+ b.append("tag foo");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTag(data);
+ fail("incorrectly accepted invalid tag");
+ } catch (CorruptObjectException e) {
+ assertEquals("no tagger header", e.getMessage());
+ }
+ }
+
+ public void testInvalidTagNoTaggerHeader1() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("object ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("type commit\n");
+ b.append("tag foo\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTag(data);
+ fail("incorrectly accepted invalid tag");
+ } catch (CorruptObjectException e) {
+ assertEquals("no tagger header", e.getMessage());
+ }
+ }
+
+ public void testInvalidTagInvalidTaggerHeader1() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("object ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("type commit\n");
+ b.append("tag foo\n");
+ b.append("tagger \n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTag(data);
+ fail("incorrectly accepted invalid tag");
+ } catch (CorruptObjectException e) {
+ assertEquals("invalid tagger", e.getMessage());
+ }
+ }
+
+ public void testInvalidTagInvalidTaggerHeader3() {
+ final StringBuilder b = new StringBuilder();
+
+ b.append("object ");
+ b.append("be9bfa841874ccc9f2ef7c48d0c76226f89b7189");
+ b.append('\n');
+
+ b.append("type commit\n");
+ b.append("tag foo\n");
+ b.append("tagger a < 1 +000\n");
+
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTag(data);
+ fail("incorrectly accepted invalid tag");
+ } catch (CorruptObjectException e) {
+ assertEquals("invalid tagger", e.getMessage());
+ }
+ }
+
+ public void testValidEmptyTree() throws CorruptObjectException {
+ checker.checkTree(new byte[0]);
+ checker.check(Constants.OBJ_TREE, new byte[0]);
+ }
+
+ public void testValidTree1() throws CorruptObjectException {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "100644 regular-file");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkTree(data);
+ }
+
+ public void testValidTree2() throws CorruptObjectException {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "100755 executable");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkTree(data);
+ }
+
+ public void testValidTree3() throws CorruptObjectException {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "40000 tree");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkTree(data);
+ }
+
+ public void testValidTree4() throws CorruptObjectException {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "120000 symlink");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkTree(data);
+ }
+
+ public void testValidTree5() throws CorruptObjectException {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "160000 git link");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkTree(data);
+ }
+
+ public void testValidTree6() throws CorruptObjectException {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "100644 .a");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkTree(data);
+ }
+
+ public void testValidTreeSorting1() throws CorruptObjectException {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "100644 fooaaa");
+ entry(b, "100755 foobar");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkTree(data);
+ }
+
+ public void testValidTreeSorting2() throws CorruptObjectException {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "100755 fooaaa");
+ entry(b, "100644 foobar");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkTree(data);
+ }
+
+ public void testValidTreeSorting3() throws CorruptObjectException {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "40000 a");
+ entry(b, "100644 b");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkTree(data);
+ }
+
+ public void testValidTreeSorting4() throws CorruptObjectException {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "100644 a");
+ entry(b, "40000 b");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkTree(data);
+ }
+
+ public void testValidTreeSorting5() throws CorruptObjectException {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "100644 a.c");
+ entry(b, "40000 a");
+ entry(b, "100644 a0c");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkTree(data);
+ }
+
+ public void testValidTreeSorting6() throws CorruptObjectException {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "40000 a");
+ entry(b, "100644 apple");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkTree(data);
+ }
+
+ public void testValidTreeSorting7() throws CorruptObjectException {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "40000 an orang");
+ entry(b, "40000 an orange");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkTree(data);
+ }
+
+ public void testValidTreeSorting8() throws CorruptObjectException {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "100644 a");
+ entry(b, "100644 a0c");
+ entry(b, "100644 b");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ checker.checkTree(data);
+ }
+
+ public void testInvalidTreeModeStartsWithZero1() {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "0 a");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTree(data);
+ fail("incorrectly accepted an invalid tree");
+ } catch (CorruptObjectException e) {
+ assertEquals("mode starts with '0'", e.getMessage());
+ }
+ }
+
+ public void testInvalidTreeModeStartsWithZero2() {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "0100644 a");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTree(data);
+ fail("incorrectly accepted an invalid tree");
+ } catch (CorruptObjectException e) {
+ assertEquals("mode starts with '0'", e.getMessage());
+ }
+ }
+
+ public void testInvalidTreeModeStartsWithZero3() {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "040000 a");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTree(data);
+ fail("incorrectly accepted an invalid tree");
+ } catch (CorruptObjectException e) {
+ assertEquals("mode starts with '0'", e.getMessage());
+ }
+ }
+
+ public void testInvalidTreeModeNotOctal1() {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "8 a");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTree(data);
+ fail("incorrectly accepted an invalid tree");
+ } catch (CorruptObjectException e) {
+ assertEquals("invalid mode character", e.getMessage());
+ }
+ }
+
+ public void testInvalidTreeModeNotOctal2() {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "Z a");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTree(data);
+ fail("incorrectly accepted an invalid tree");
+ } catch (CorruptObjectException e) {
+ assertEquals("invalid mode character", e.getMessage());
+ }
+ }
+
+ public void testInvalidTreeModeNotSupportedMode1() {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "1 a");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTree(data);
+ fail("incorrectly accepted an invalid tree");
+ } catch (CorruptObjectException e) {
+ assertEquals("invalid mode 1", e.getMessage());
+ }
+ }
+
+ public void testInvalidTreeModeNotSupportedMode2() {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "170000 a");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTree(data);
+ fail("incorrectly accepted an invalid tree");
+ } catch (CorruptObjectException e) {
+ assertEquals("invalid mode " + 0170000, e.getMessage());
+ }
+ }
+
+ public void testInvalidTreeModeMissingName() {
+ final StringBuilder b = new StringBuilder();
+ b.append("100644");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTree(data);
+ fail("incorrectly accepted an invalid tree");
+ } catch (CorruptObjectException e) {
+ assertEquals("truncated in mode", e.getMessage());
+ }
+ }
+
+ public void testInvalidTreeNameContainsSlash() {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "100644 a/b");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTree(data);
+ fail("incorrectly accepted an invalid tree");
+ } catch (CorruptObjectException e) {
+ assertEquals("name contains '/'", e.getMessage());
+ }
+ }
+
+ public void testInvalidTreeNameIsEmpty() {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "100644 ");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTree(data);
+ fail("incorrectly accepted an invalid tree");
+ } catch (CorruptObjectException e) {
+ assertEquals("zero length name", e.getMessage());
+ }
+ }
+
+ public void testInvalidTreeNameIsDot() {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "100644 .");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTree(data);
+ fail("incorrectly accepted an invalid tree");
+ } catch (CorruptObjectException e) {
+ assertEquals("invalid name '.'", e.getMessage());
+ }
+ }
+
+ public void testInvalidTreeNameIsDotDot() {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "100644 ..");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTree(data);
+ fail("incorrectly accepted an invalid tree");
+ } catch (CorruptObjectException e) {
+ assertEquals("invalid name '..'", e.getMessage());
+ }
+ }
+
+ public void testInvalidTreeTruncatedInName() {
+ final StringBuilder b = new StringBuilder();
+ b.append("100644 b");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTree(data);
+ fail("incorrectly accepted an invalid tree");
+ } catch (CorruptObjectException e) {
+ assertEquals("truncated in name", e.getMessage());
+ }
+ }
+
+ public void testInvalidTreeTruncatedInObjectId() {
+ final StringBuilder b = new StringBuilder();
+ b.append("100644 b\0\1\2");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTree(data);
+ fail("incorrectly accepted an invalid tree");
+ } catch (CorruptObjectException e) {
+ assertEquals("truncated in object id", e.getMessage());
+ }
+ }
+
+ public void testInvalidTreeBadSorting1() {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "100644 foobar");
+ entry(b, "100644 fooaaa");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTree(data);
+ fail("incorrectly accepted an invalid tree");
+ } catch (CorruptObjectException e) {
+ assertEquals("incorrectly sorted", e.getMessage());
+ }
+ }
+
+ public void testInvalidTreeBadSorting2() {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "40000 a");
+ entry(b, "100644 a.c");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTree(data);
+ fail("incorrectly accepted an invalid tree");
+ } catch (CorruptObjectException e) {
+ assertEquals("incorrectly sorted", e.getMessage());
+ }
+ }
+
+ public void testInvalidTreeBadSorting3() {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "100644 a0c");
+ entry(b, "40000 a");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTree(data);
+ fail("incorrectly accepted an invalid tree");
+ } catch (CorruptObjectException e) {
+ assertEquals("incorrectly sorted", e.getMessage());
+ }
+ }
+
+ public void testInvalidTreeDuplicateNames1() {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "100644 a");
+ entry(b, "100644 a");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTree(data);
+ fail("incorrectly accepted an invalid tree");
+ } catch (CorruptObjectException e) {
+ assertEquals("duplicate entry names", e.getMessage());
+ }
+ }
+
+ public void testInvalidTreeDuplicateNames2() {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "100644 a");
+ entry(b, "100755 a");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTree(data);
+ fail("incorrectly accepted an invalid tree");
+ } catch (CorruptObjectException e) {
+ assertEquals("duplicate entry names", e.getMessage());
+ }
+ }
+
+ public void testInvalidTreeDuplicateNames3() {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "100644 a");
+ entry(b, "40000 a");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTree(data);
+ fail("incorrectly accepted an invalid tree");
+ } catch (CorruptObjectException e) {
+ assertEquals("duplicate entry names", e.getMessage());
+ }
+ }
+
+ public void testInvalidTreeDuplicateNames4() {
+ final StringBuilder b = new StringBuilder();
+ entry(b, "100644 a");
+ entry(b, "100644 a.c");
+ entry(b, "100644 a.d");
+ entry(b, "100644 a.e");
+ entry(b, "40000 a");
+ entry(b, "100644 zoo");
+ final byte[] data = Constants.encodeASCII(b.toString());
+ try {
+ checker.checkTree(data);
+ fail("incorrectly accepted an invalid tree");
+ } catch (CorruptObjectException e) {
+ assertEquals("duplicate entry names", e.getMessage());
+ }
+ }
+
+ private static void entry(final StringBuilder b, final String modeName) {
+ b.append(modeName);
+ b.append('\0');
+ for (int i = 0; i < Constants.OBJECT_ID_LENGTH; i++)
+ b.append((char) i);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PackIndexTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PackIndexTestCase.java
new file mode 100644
index 0000000000..31de3d98ad
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PackIndexTestCase.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.File;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.PackIndex.MutableEntry;
+
+public abstract class PackIndexTestCase extends RepositoryTestCase {
+
+ PackIndex smallIdx;
+
+ PackIndex denseIdx;
+
+ public void setUp() throws Exception {
+ super.setUp();
+ smallIdx = PackIndex.open(getFileForPack34be9032());
+ denseIdx = PackIndex.open(getFileForPackdf2982f28());
+ }
+
+ /**
+ * Return file with appropriate index version for prepared pack.
+ *
+ * @return file with index
+ */
+ public abstract File getFileForPack34be9032();
+
+ /**
+ * Return file with appropriate index version for prepared pack.
+ *
+ * @return file with index
+ */
+ public abstract File getFileForPackdf2982f28();
+
+ /**
+ * Verify CRC32 support.
+ *
+ * @throws MissingObjectException
+ * @throws UnsupportedOperationException
+ */
+ public abstract void testCRC32() throws MissingObjectException,
+ UnsupportedOperationException;
+
+ /**
+ * Test contracts of Iterator methods and this implementation remove()
+ * limitations.
+ */
+ public void testIteratorMethodsContract() {
+ Iterator<PackIndex.MutableEntry> iter = smallIdx.iterator();
+ while (iter.hasNext()) {
+ iter.next();
+ }
+
+ try {
+ iter.next();
+ fail("next() unexpectedly returned element");
+ } catch (NoSuchElementException x) {
+ // expected
+ }
+
+ try {
+ iter.remove();
+ fail("remove() shouldn't be implemented");
+ } catch (UnsupportedOperationException x) {
+ // expected
+ }
+ }
+
+ /**
+ * Test results of iterator comparing to content of well-known (prepared)
+ * small index.
+ */
+ public void testIteratorReturnedValues1() {
+ Iterator<PackIndex.MutableEntry> iter = smallIdx.iterator();
+ assertEquals("4b825dc642cb6eb9a060e54bf8d69288fbee4904", iter.next()
+ .name());
+ assertEquals("540a36d136cf413e4b064c2b0e0a4db60f77feab", iter.next()
+ .name());
+ assertEquals("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259", iter.next()
+ .name());
+ assertEquals("6ff87c4664981e4397625791c8ea3bbb5f2279a3", iter.next()
+ .name());
+ assertEquals("82c6b885ff600be425b4ea96dee75dca255b69e7", iter.next()
+ .name());
+ assertEquals("902d5476fa249b7abc9d84c611577a81381f0327", iter.next()
+ .name());
+ assertEquals("aabf2ffaec9b497f0950352b3e582d73035c2035", iter.next()
+ .name());
+ assertEquals("c59759f143fb1fe21c197981df75a7ee00290799", iter.next()
+ .name());
+ assertFalse(iter.hasNext());
+ }
+
+ /**
+ * Compare offset from iterator entries with output of findOffset() method.
+ */
+ public void testCompareEntriesOffsetsWithFindOffsets() {
+ for (MutableEntry me : smallIdx) {
+ assertEquals(smallIdx.findOffset(me.toObjectId()), me.getOffset());
+ }
+ for (MutableEntry me : denseIdx) {
+ assertEquals(denseIdx.findOffset(me.toObjectId()), me.getOffset());
+ }
+ }
+
+ /**
+ * Test partial results of iterator comparing to content of well-known
+ * (prepared) dense index, that may need multi-level indexing.
+ */
+ public void testIteratorReturnedValues2() {
+ Iterator<PackIndex.MutableEntry> iter = denseIdx.iterator();
+ while (!iter.next().name().equals(
+ "0a3d7772488b6b106fb62813c4d6d627918d9181")) {
+ // just iterating
+ }
+ assertEquals("1004d0d7ac26fbf63050a234c9b88a46075719d3", iter.next()
+ .name()); // same level-1
+ assertEquals("10da5895682013006950e7da534b705252b03be6", iter.next()
+ .name()); // same level-1
+ assertEquals("1203b03dc816ccbb67773f28b3c19318654b0bc8", iter.next()
+ .name());
+ }
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PackIndexV1Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PackIndexV1Test.java
new file mode 100644
index 0000000000..f3082fb294
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PackIndexV1Test.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2008, Imran M Yousuf <imyousuf@smartitengineering.com>
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
+ * Copyright (C) 2009, Matthias Sohn <matthias.sohn@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.File;
+
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.util.JGitTestUtil;
+
+public class PackIndexV1Test extends PackIndexTestCase {
+ @Override
+ public File getFileForPack34be9032() {
+ return JGitTestUtil.getTestResourceFile(
+ "pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.idx");
+ }
+
+ @Override
+ public File getFileForPackdf2982f28() {
+ return JGitTestUtil.getTestResourceFile(
+ "pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.idx");
+ }
+
+ /**
+ * Verify CRC32 - V1 should not index anything.
+ *
+ * @throws MissingObjectException
+ */
+ @Override
+ public void testCRC32() throws MissingObjectException {
+ assertFalse(smallIdx.hasCRC32Support());
+ try {
+ smallIdx.findCRC32(ObjectId
+ .fromString("4b825dc642cb6eb9a060e54bf8d69288fbee4904"));
+ fail("index V1 shouldn't support CRC");
+ } catch (UnsupportedOperationException x) {
+ // expected
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PackIndexV2Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PackIndexV2Test.java
new file mode 100644
index 0000000000..c5669f9d24
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PackIndexV2Test.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2008, Imran M Yousuf <imyousuf@smartitengineering.com>
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
+ * Copyright (C) 2009, Matthias Sohn <matthias.sohn@sap.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.File;
+
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.util.JGitTestUtil;
+
+public class PackIndexV2Test extends PackIndexTestCase {
+ @Override
+ public File getFileForPack34be9032() {
+ return JGitTestUtil.getTestResourceFile(
+ "pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.idxV2");
+ }
+
+ @Override
+ public File getFileForPackdf2982f28() {
+ return JGitTestUtil.getTestResourceFile(
+ "pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.idxV2");
+ }
+
+ /**
+ * Verify CRC32 indexing.
+ *
+ * @throws UnsupportedOperationException
+ * @throws MissingObjectException
+ */
+ @Override
+ public void testCRC32() throws MissingObjectException,
+ UnsupportedOperationException {
+ assertTrue(smallIdx.hasCRC32Support());
+ assertEquals(0x00000000C2B64258l, smallIdx.findCRC32(ObjectId
+ .fromString("4b825dc642cb6eb9a060e54bf8d69288fbee4904")));
+ assertEquals(0x0000000072AD57C2l, smallIdx.findCRC32(ObjectId
+ .fromString("540a36d136cf413e4b064c2b0e0a4db60f77feab")));
+ assertEquals(0x00000000FF10A479l, smallIdx.findCRC32(ObjectId
+ .fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259")));
+ assertEquals(0x0000000034B27DDCl, smallIdx.findCRC32(ObjectId
+ .fromString("6ff87c4664981e4397625791c8ea3bbb5f2279a3")));
+ assertEquals(0x000000004743F1E4l, smallIdx.findCRC32(ObjectId
+ .fromString("82c6b885ff600be425b4ea96dee75dca255b69e7")));
+ assertEquals(0x00000000640B358Bl, smallIdx.findCRC32(ObjectId
+ .fromString("902d5476fa249b7abc9d84c611577a81381f0327")));
+ assertEquals(0x000000002A17CB5El, smallIdx.findCRC32(ObjectId
+ .fromString("aabf2ffaec9b497f0950352b3e582d73035c2035")));
+ assertEquals(0x000000000B3B5BA6l, smallIdx.findCRC32(ObjectId
+ .fromString("c59759f143fb1fe21c197981df75a7ee00290799")));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PackReverseIndexTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PackReverseIndexTest.java
new file mode 100644
index 0000000000..19b705813f
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PackReverseIndexTest.java
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2008, Imran M Yousuf <imyousuf@smartitengineering.com>
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.lib.PackIndex.MutableEntry;
+import org.eclipse.jgit.util.JGitTestUtil;
+
+public class PackReverseIndexTest extends RepositoryTestCase {
+
+ private PackIndex idx;
+
+ private PackReverseIndex reverseIdx;
+
+ /**
+ * Set up tested class instance, test constructor by the way.
+ */
+ public void setUp() throws Exception {
+ super.setUp();
+ // index with both small (< 2^31) and big offsets
+ idx = PackIndex.open(JGitTestUtil.getTestResourceFile(
+ "pack-huge.idx"));
+ reverseIdx = new PackReverseIndex(idx);
+ }
+
+ /**
+ * Test findObject() for all index entries.
+ */
+ public void testFindObject() {
+ for (MutableEntry me : idx)
+ assertEquals(me.toObjectId(), reverseIdx.findObject(me.getOffset()));
+ }
+
+ /**
+ * Test findObject() with illegal argument.
+ */
+ public void testFindObjectWrongOffset() {
+ assertNull(reverseIdx.findObject(0));
+ }
+
+ /**
+ * Test findNextOffset() for all index entries.
+ *
+ * @throws CorruptObjectException
+ */
+ public void testFindNextOffset() throws CorruptObjectException {
+ long offset = findFirstOffset();
+ assertTrue(offset > 0);
+ for (int i = 0; i < idx.getObjectCount(); i++) {
+ long newOffset = reverseIdx.findNextOffset(offset, Long.MAX_VALUE);
+ assertTrue(newOffset > offset);
+ if (i == idx.getObjectCount() - 1)
+ assertEquals(newOffset, Long.MAX_VALUE);
+ else
+ assertEquals(newOffset, idx.findOffset(reverseIdx
+ .findObject(newOffset)));
+ offset = newOffset;
+ }
+ }
+
+ /**
+ * Test findNextOffset() with wrong illegal argument as offset.
+ */
+ public void testFindNextOffsetWrongOffset() {
+ try {
+ reverseIdx.findNextOffset(0, Long.MAX_VALUE);
+ fail("findNextOffset() should throw exception");
+ } catch (CorruptObjectException x) {
+ // expected
+ }
+ }
+
+ private long findFirstOffset() {
+ long min = Long.MAX_VALUE;
+ for (MutableEntry me : idx)
+ min = Math.min(min, me.getOffset());
+ return min;
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PackWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PackWriterTest.java
new file mode 100644
index 0000000000..7032907496
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/PackWriterTest.java
@@ -0,0 +1,533 @@
+/*
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.PackIndex.MutableEntry;
+import org.eclipse.jgit.revwalk.RevObject;
+import org.eclipse.jgit.revwalk.RevWalk;
+import org.eclipse.jgit.transport.IndexPack;
+import org.eclipse.jgit.util.JGitTestUtil;
+
+public class PackWriterTest extends RepositoryTestCase {
+
+ private static final List<ObjectId> EMPTY_LIST_OBJECT = Collections
+ .<ObjectId> emptyList();
+
+ private static final List<RevObject> EMPTY_LIST_REVS = Collections
+ .<RevObject> emptyList();
+
+ private PackWriter writer;
+
+ private ByteArrayOutputStream os;
+
+ private PackOutputStream cos;
+
+ private File packBase;
+
+ private File packFile;
+
+ private File indexFile;
+
+ private PackFile pack;
+
+ public void setUp() throws Exception {
+ super.setUp();
+ os = new ByteArrayOutputStream();
+ cos = new PackOutputStream(os);
+ packBase = new File(trash, "tmp_pack");
+ packFile = new File(trash, "tmp_pack.pack");
+ indexFile = new File(trash, "tmp_pack.idx");
+ writer = new PackWriter(db, new TextProgressMonitor());
+ }
+
+ /**
+ * Test constructor for exceptions, default settings, initialization.
+ */
+ public void testContructor() {
+ assertEquals(false, writer.isDeltaBaseAsOffset());
+ assertEquals(true, writer.isReuseDeltas());
+ assertEquals(true, writer.isReuseObjects());
+ assertEquals(0, writer.getObjectsNumber());
+ }
+
+ /**
+ * Change default settings and verify them.
+ */
+ public void testModifySettings() {
+ writer.setDeltaBaseAsOffset(true);
+ writer.setReuseDeltas(false);
+ writer.setReuseObjects(false);
+
+ assertEquals(true, writer.isDeltaBaseAsOffset());
+ assertEquals(false, writer.isReuseDeltas());
+ assertEquals(false, writer.isReuseObjects());
+ }
+
+ /**
+ * Write empty pack by providing empty sets of interesting/uninteresting
+ * objects and check for correct format.
+ *
+ * @throws IOException
+ */
+ public void testWriteEmptyPack1() throws IOException {
+ createVerifyOpenPack(EMPTY_LIST_OBJECT, EMPTY_LIST_OBJECT, false, false);
+
+ assertEquals(0, writer.getObjectsNumber());
+ assertEquals(0, pack.getObjectCount());
+ assertEquals("da39a3ee5e6b4b0d3255bfef95601890afd80709", writer
+ .computeName().name());
+ }
+
+ /**
+ * Write empty pack by providing empty iterator of objects to write and
+ * check for correct format.
+ *
+ * @throws IOException
+ */
+ public void testWriteEmptyPack2() throws IOException {
+ createVerifyOpenPack(EMPTY_LIST_REVS.iterator());
+
+ assertEquals(0, writer.getObjectsNumber());
+ assertEquals(0, pack.getObjectCount());
+ }
+
+ /**
+ * Try to pass non-existing object as uninteresting, with non-ignoring
+ * setting.
+ *
+ * @throws IOException
+ */
+ public void testNotIgnoreNonExistingObjects() throws IOException {
+ final ObjectId nonExisting = ObjectId
+ .fromString("0000000000000000000000000000000000000001");
+ try {
+ createVerifyOpenPack(EMPTY_LIST_OBJECT, Collections.nCopies(1,
+ nonExisting), false, false);
+ fail("Should have thrown MissingObjectException");
+ } catch (MissingObjectException x) {
+ // expected
+ }
+ }
+
+ /**
+ * Try to pass non-existing object as uninteresting, with ignoring setting.
+ *
+ * @throws IOException
+ */
+ public void testIgnoreNonExistingObjects() throws IOException {
+ final ObjectId nonExisting = ObjectId
+ .fromString("0000000000000000000000000000000000000001");
+ createVerifyOpenPack(EMPTY_LIST_OBJECT, Collections.nCopies(1,
+ nonExisting), false, true);
+ // shouldn't throw anything
+ }
+
+ /**
+ * Create pack basing on only interesting objects, then precisely verify
+ * content. No delta reuse here.
+ *
+ * @throws IOException
+ */
+ public void testWritePack1() throws IOException {
+ writer.setReuseDeltas(false);
+ writeVerifyPack1();
+ }
+
+ /**
+ * Test writing pack without object reuse. Pack content/preparation as in
+ * {@link #testWritePack1()}.
+ *
+ * @throws IOException
+ */
+ public void testWritePack1NoObjectReuse() throws IOException {
+ writer.setReuseDeltas(false);
+ writer.setReuseObjects(false);
+ writeVerifyPack1();
+ }
+
+ /**
+ * Create pack basing on both interesting and uninteresting objects, then
+ * precisely verify content. No delta reuse here.
+ *
+ * @throws IOException
+ */
+ public void testWritePack2() throws IOException {
+ writeVerifyPack2(false);
+ }
+
+ /**
+ * Test pack writing with deltas reuse, delta-base first rule. Pack
+ * content/preparation as in {@link #testWritePack2()}.
+ *
+ * @throws IOException
+ */
+ public void testWritePack2DeltasReuseRefs() throws IOException {
+ writeVerifyPack2(true);
+ }
+
+ /**
+ * Test pack writing with delta reuse. Delta bases referred as offsets. Pack
+ * configuration as in {@link #testWritePack2DeltasReuseRefs()}.
+ *
+ * @throws IOException
+ */
+ public void testWritePack2DeltasReuseOffsets() throws IOException {
+ writer.setDeltaBaseAsOffset(true);
+ writeVerifyPack2(true);
+ }
+
+ /**
+ * Test pack writing with delta reuse. Raw-data copy (reuse) is made on a
+ * pack with CRC32 index. Pack configuration as in
+ * {@link #testWritePack2DeltasReuseRefs()}.
+ *
+ * @throws IOException
+ */
+ public void testWritePack2DeltasCRC32Copy() throws IOException {
+ final File packDir = new File(db.getObjectsDirectory(), "pack");
+ final File crc32Pack = new File(packDir,
+ "pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.pack");
+ final File crc32Idx = new File(packDir,
+ "pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.idx");
+ copyFile(JGitTestUtil.getTestResourceFile(
+ "pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.idxV2"),
+ crc32Idx);
+ db.openPack(crc32Pack, crc32Idx);
+
+ writeVerifyPack2(true);
+ }
+
+ /**
+ * Create pack basing on fixed objects list, then precisely verify content.
+ * No delta reuse here.
+ *
+ * @throws IOException
+ * @throws MissingObjectException
+ *
+ */
+ public void testWritePack3() throws MissingObjectException, IOException {
+ writer.setReuseDeltas(false);
+ final ObjectId forcedOrder[] = new ObjectId[] {
+ ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"),
+ ObjectId.fromString("c59759f143fb1fe21c197981df75a7ee00290799"),
+ ObjectId.fromString("aabf2ffaec9b497f0950352b3e582d73035c2035"),
+ ObjectId.fromString("902d5476fa249b7abc9d84c611577a81381f0327"),
+ ObjectId.fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259"),
+ ObjectId.fromString("6ff87c4664981e4397625791c8ea3bbb5f2279a3") };
+ final RevWalk parser = new RevWalk(db);
+ final RevObject forcedOrderRevs[] = new RevObject[forcedOrder.length];
+ for (int i = 0; i < forcedOrder.length; i++)
+ forcedOrderRevs[i] = parser.parseAny(forcedOrder[i]);
+
+ createVerifyOpenPack(Arrays.asList(forcedOrderRevs).iterator());
+
+ assertEquals(forcedOrder.length, writer.getObjectsNumber());
+ verifyObjectsOrder(forcedOrder);
+ assertEquals("ed3f96b8327c7c66b0f8f70056129f0769323d86", writer
+ .computeName().name());
+ }
+
+ /**
+ * Another pack creation: basing on both interesting and uninteresting
+ * objects. No delta reuse possible here, as this is a specific case when we
+ * write only 1 commit, associated with 1 tree, 1 blob.
+ *
+ * @throws IOException
+ */
+ public void testWritePack4() throws IOException {
+ writeVerifyPack4(false);
+ }
+
+ /**
+ * Test thin pack writing: 1 blob delta base is on objects edge. Pack
+ * configuration as in {@link #testWritePack4()}.
+ *
+ * @throws IOException
+ */
+ public void testWritePack4ThinPack() throws IOException {
+ writeVerifyPack4(true);
+ }
+
+ /**
+ * Compare sizes of packs created using {@link #testWritePack2()} and
+ * {@link #testWritePack2DeltasReuseRefs()}. The pack using deltas should
+ * be smaller.
+ *
+ * @throws Exception
+ */
+ public void testWritePack2SizeDeltasVsNoDeltas() throws Exception {
+ testWritePack2();
+ final long sizePack2NoDeltas = cos.length();
+ tearDown();
+ setUp();
+ testWritePack2DeltasReuseRefs();
+ final long sizePack2DeltasRefs = cos.length();
+
+ assertTrue(sizePack2NoDeltas > sizePack2DeltasRefs);
+ }
+
+ /**
+ * Compare sizes of packs created using
+ * {@link #testWritePack2DeltasReuseRefs()} and
+ * {@link #testWritePack2DeltasReuseOffsets()}. The pack with delta bases
+ * written as offsets should be smaller.
+ *
+ * @throws Exception
+ */
+ public void testWritePack2SizeOffsetsVsRefs() throws Exception {
+ testWritePack2DeltasReuseRefs();
+ final long sizePack2DeltasRefs = cos.length();
+ tearDown();
+ setUp();
+ testWritePack2DeltasReuseOffsets();
+ final long sizePack2DeltasOffsets = cos.length();
+
+ assertTrue(sizePack2DeltasRefs > sizePack2DeltasOffsets);
+ }
+
+ /**
+ * Compare sizes of packs created using {@link #testWritePack4()} and
+ * {@link #testWritePack4ThinPack()}. Obviously, the thin pack should be
+ * smaller.
+ *
+ * @throws Exception
+ */
+ public void testWritePack4SizeThinVsNoThin() throws Exception {
+ testWritePack4();
+ final long sizePack4 = cos.length();
+ tearDown();
+ setUp();
+ testWritePack4ThinPack();
+ final long sizePack4Thin = cos.length();
+
+ assertTrue(sizePack4 > sizePack4Thin);
+ }
+
+ public void testWriteIndex() throws Exception {
+ writer.setIndexVersion(2);
+ writeVerifyPack4(false);
+
+ // Validate that IndexPack came up with the right CRC32 value.
+ final PackIndex idx1 = PackIndex.open(indexFile);
+ assertTrue(idx1 instanceof PackIndexV2);
+ assertEquals(0x4743F1E4L, idx1.findCRC32(ObjectId
+ .fromString("82c6b885ff600be425b4ea96dee75dca255b69e7")));
+
+ // Validate that an index written by PackWriter is the same.
+ final File idx2File = new File(indexFile.getAbsolutePath() + ".2");
+ final FileOutputStream is = new FileOutputStream(idx2File);
+ try {
+ writer.writeIndex(is);
+ } finally {
+ is.close();
+ }
+ final PackIndex idx2 = PackIndex.open(idx2File);
+ assertTrue(idx2 instanceof PackIndexV2);
+ assertEquals(idx1.getObjectCount(), idx2.getObjectCount());
+ assertEquals(idx1.getOffset64Count(), idx2.getOffset64Count());
+
+ for (int i = 0; i < idx1.getObjectCount(); i++) {
+ final ObjectId id = idx1.getObjectId(i);
+ assertEquals(id, idx2.getObjectId(i));
+ assertEquals(idx1.findOffset(id), idx2.findOffset(id));
+ assertEquals(idx1.findCRC32(id), idx2.findCRC32(id));
+ }
+ }
+
+ // TODO: testWritePackDeltasCycle()
+ // TODO: testWritePackDeltasDepth()
+
+ private void writeVerifyPack1() throws IOException {
+ final LinkedList<ObjectId> interestings = new LinkedList<ObjectId>();
+ interestings.add(ObjectId
+ .fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"));
+ createVerifyOpenPack(interestings, EMPTY_LIST_OBJECT, false, false);
+
+ final ObjectId expectedOrder[] = new ObjectId[] {
+ ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"),
+ ObjectId.fromString("c59759f143fb1fe21c197981df75a7ee00290799"),
+ ObjectId.fromString("540a36d136cf413e4b064c2b0e0a4db60f77feab"),
+ ObjectId.fromString("aabf2ffaec9b497f0950352b3e582d73035c2035"),
+ ObjectId.fromString("902d5476fa249b7abc9d84c611577a81381f0327"),
+ ObjectId.fromString("4b825dc642cb6eb9a060e54bf8d69288fbee4904"),
+ ObjectId.fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259"),
+ ObjectId.fromString("6ff87c4664981e4397625791c8ea3bbb5f2279a3") };
+
+ assertEquals(expectedOrder.length, writer.getObjectsNumber());
+ verifyObjectsOrder(expectedOrder);
+ assertEquals("34be9032ac282b11fa9babdc2b2a93ca996c9c2f", writer
+ .computeName().name());
+ }
+
+ private void writeVerifyPack2(boolean deltaReuse) throws IOException {
+ writer.setReuseDeltas(deltaReuse);
+ final LinkedList<ObjectId> interestings = new LinkedList<ObjectId>();
+ interestings.add(ObjectId
+ .fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"));
+ final LinkedList<ObjectId> uninterestings = new LinkedList<ObjectId>();
+ uninterestings.add(ObjectId
+ .fromString("540a36d136cf413e4b064c2b0e0a4db60f77feab"));
+ createVerifyOpenPack(interestings, uninterestings, false, false);
+
+ final ObjectId expectedOrder[] = new ObjectId[] {
+ ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"),
+ ObjectId.fromString("c59759f143fb1fe21c197981df75a7ee00290799"),
+ ObjectId.fromString("aabf2ffaec9b497f0950352b3e582d73035c2035"),
+ ObjectId.fromString("902d5476fa249b7abc9d84c611577a81381f0327"),
+ ObjectId.fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259"),
+ ObjectId.fromString("6ff87c4664981e4397625791c8ea3bbb5f2279a3") };
+ if (deltaReuse) {
+ // objects order influenced (swapped) by delta-base first rule
+ ObjectId temp = expectedOrder[4];
+ expectedOrder[4] = expectedOrder[5];
+ expectedOrder[5] = temp;
+ }
+ assertEquals(expectedOrder.length, writer.getObjectsNumber());
+ verifyObjectsOrder(expectedOrder);
+ assertEquals("ed3f96b8327c7c66b0f8f70056129f0769323d86", writer
+ .computeName().name());
+ }
+
+ private void writeVerifyPack4(final boolean thin) throws IOException {
+ final LinkedList<ObjectId> interestings = new LinkedList<ObjectId>();
+ interestings.add(ObjectId
+ .fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"));
+ final LinkedList<ObjectId> uninterestings = new LinkedList<ObjectId>();
+ uninterestings.add(ObjectId
+ .fromString("c59759f143fb1fe21c197981df75a7ee00290799"));
+ createVerifyOpenPack(interestings, uninterestings, thin, false);
+
+ final ObjectId writtenObjects[] = new ObjectId[] {
+ ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7"),
+ ObjectId.fromString("aabf2ffaec9b497f0950352b3e582d73035c2035"),
+ ObjectId.fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259") };
+ assertEquals(writtenObjects.length, writer.getObjectsNumber());
+ ObjectId expectedObjects[];
+ if (thin) {
+ expectedObjects = new ObjectId[4];
+ System.arraycopy(writtenObjects, 0, expectedObjects, 0,
+ writtenObjects.length);
+ expectedObjects[3] = ObjectId
+ .fromString("6ff87c4664981e4397625791c8ea3bbb5f2279a3");
+
+ } else {
+ expectedObjects = writtenObjects;
+ }
+ verifyObjectsOrder(expectedObjects);
+ assertEquals("cded4b74176b4456afa456768b2b5aafb41c44fc", writer
+ .computeName().name());
+ }
+
+ private void createVerifyOpenPack(final Collection<ObjectId> interestings,
+ final Collection<ObjectId> uninterestings, final boolean thin,
+ final boolean ignoreMissingUninteresting)
+ throws MissingObjectException, IOException {
+ writer.setThin(thin);
+ writer.setIgnoreMissingUninteresting(ignoreMissingUninteresting);
+ writer.preparePack(interestings, uninterestings);
+ writer.writePack(cos);
+ verifyOpenPack(thin);
+ }
+
+ private void createVerifyOpenPack(final Iterator<RevObject> objectSource)
+ throws MissingObjectException, IOException {
+ writer.preparePack(objectSource);
+ writer.writePack(cos);
+ verifyOpenPack(false);
+ }
+
+ private void verifyOpenPack(final boolean thin) throws IOException {
+ if (thin) {
+ final InputStream is = new ByteArrayInputStream(os.toByteArray());
+ final IndexPack indexer = new IndexPack(db, is, packBase);
+ try {
+ indexer.index(new TextProgressMonitor());
+ fail("indexer should grumble about missing object");
+ } catch (IOException x) {
+ // expected
+ }
+ }
+ final InputStream is = new ByteArrayInputStream(os.toByteArray());
+ final IndexPack indexer = new IndexPack(db, is, packBase);
+ indexer.setKeepEmpty(true);
+ indexer.setFixThin(thin);
+ indexer.setIndexVersion(2);
+ indexer.index(new TextProgressMonitor());
+ pack = new PackFile(indexFile, packFile);
+ }
+
+ private void verifyObjectsOrder(final ObjectId objectsOrder[]) {
+ final List<PackIndex.MutableEntry> entries = new ArrayList<PackIndex.MutableEntry>();
+
+ for (MutableEntry me : pack) {
+ entries.add(me.cloneEntry());
+ }
+ Collections.sort(entries, new Comparator<PackIndex.MutableEntry>() {
+ public int compare(MutableEntry o1, MutableEntry o2) {
+ return Long.signum(o1.getOffset() - o2.getOffset());
+ }
+ });
+
+ int i = 0;
+ for (MutableEntry me : entries) {
+ assertEquals(objectsOrder[i++].toObjectId(), me.toObjectId());
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReadTreeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReadTreeTest.java
new file mode 100644
index 0000000000..5ac75d8043
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReadTreeTest.java
@@ -0,0 +1,581 @@
+/*
+ * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
+ * Copyright (C) 2008-2009, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.HashMap;
+
+import org.eclipse.jgit.errors.CheckoutConflictException;
+
+public class ReadTreeTest extends RepositoryTestCase {
+
+ private Tree theHead;
+ private Tree theMerge;
+ private GitIndex theIndex;
+ private WorkDirCheckout theReadTree;
+ // Each of these rules are from the read-tree manpage
+ // go there to see what they mean.
+ // Rule 0 is left out for obvious reasons :)
+ public void testRules1thru3_NoIndexEntry() throws IOException {
+ GitIndex index = new GitIndex(db);
+
+ Tree head = new Tree(db);
+ FileTreeEntry headFile = head.addFile("foo");
+ ObjectId objectId = ObjectId.fromString("ba78e065e2c261d4f7b8f42107588051e87e18e9");
+ headFile.setId(objectId);
+ Tree merge = new Tree(db);
+
+ WorkDirCheckout readTree = new WorkDirCheckout(db, trash, head, index, merge);
+ readTree.prescanTwoTrees();
+
+ assertTrue(readTree.removed.contains("foo"));
+
+ readTree = new WorkDirCheckout(db, trash, merge, index, head);
+ readTree.prescanTwoTrees();
+
+ assertEquals(objectId, readTree.updated.get("foo"));
+
+ ObjectId anotherId = ObjectId.fromString("ba78e065e2c261d4f7b8f42107588051e87e18ee");
+ merge.addFile("foo").setId(anotherId);
+
+ readTree = new WorkDirCheckout(db, trash, head, index, merge);
+ readTree.prescanTwoTrees();
+
+ assertEquals(anotherId, readTree.updated.get("foo"));
+ }
+
+ void setupCase(HashMap<String, String> headEntries,
+ HashMap<String, String> mergeEntries,
+ HashMap<String, String> indexEntries) throws IOException {
+ theHead = buildTree(headEntries);
+ theMerge = buildTree(mergeEntries);
+ theIndex = buildIndex(indexEntries);
+ }
+
+ private GitIndex buildIndex(HashMap<String, String> indexEntries) throws IOException {
+ GitIndex index = new GitIndex(db);
+
+ if (indexEntries == null)
+ return index;
+ for (java.util.Map.Entry<String,String> e : indexEntries.entrySet()) {
+ index.add(trash, writeTrashFile(e.getKey(), e.getValue())).forceRecheck();
+ }
+
+ return index;
+ }
+
+ private Tree buildTree(HashMap<String, String> headEntries) throws IOException {
+ Tree tree = new Tree(db);
+
+ if (headEntries == null)
+ return tree;
+ for (java.util.Map.Entry<String,String> e : headEntries.entrySet()) {
+ tree.addFile(e.getKey()).setId(genSha1(e.getValue()));
+ }
+
+ return tree;
+ }
+
+ ObjectId genSha1(String data) {
+ InputStream is = new ByteArrayInputStream(data.getBytes());
+ ObjectWriter objectWriter = new ObjectWriter(db);
+ try {
+ return objectWriter.writeObject(Constants.OBJ_BLOB, data
+ .getBytes().length, is, true);
+ } catch (IOException e) {
+ fail(e.toString());
+ }
+ return null;
+ }
+
+ private WorkDirCheckout go() throws IOException {
+ theReadTree = new WorkDirCheckout(db, trash, theHead, theIndex, theMerge);
+ theReadTree.prescanTwoTrees();
+ return theReadTree;
+ }
+
+ // for these rules, they all have clean yes/no options
+ // but it doesn't matter if the entry is clean or not
+ // so we can just ignore the state in the filesystem entirely
+ public void testRules4thru13_IndexEntryNotInHead() throws IOException {
+ // rules 4 and 5
+ HashMap<String, String> idxMap;
+
+ idxMap = new HashMap<String, String>();
+ idxMap.put("foo", "foo");
+ setupCase(null, null, idxMap);
+ theReadTree = go();
+
+ assertTrue(theReadTree.updated.isEmpty());
+ assertTrue(theReadTree.removed.isEmpty());
+ assertTrue(theReadTree.conflicts.isEmpty());
+
+ // rules 6 and 7
+ idxMap = new HashMap<String, String>();
+ idxMap.put("foo", "foo");
+ setupCase(null, idxMap, idxMap);
+ theReadTree = go();
+
+ assertAllEmpty();
+
+ // rules 8 and 9
+ HashMap<String, String> mergeMap;
+ mergeMap = new HashMap<String, String>();
+
+ mergeMap.put("foo", "merge");
+ setupCase(null, mergeMap, idxMap);
+ go();
+
+ assertTrue(theReadTree.updated.isEmpty());
+ assertTrue(theReadTree.removed.isEmpty());
+ assertTrue(theReadTree.conflicts.contains("foo"));
+
+ // rule 10
+
+ HashMap<String, String> headMap = new HashMap<String, String>();
+ headMap.put("foo", "foo");
+ setupCase(headMap, null, idxMap);
+ go();
+
+ assertTrue(theReadTree.removed.contains("foo"));
+ assertTrue(theReadTree.updated.isEmpty());
+ assertTrue(theReadTree.conflicts.isEmpty());
+
+ // rule 11
+ setupCase(headMap, null, idxMap);
+ new File(trash, "foo").delete();
+ writeTrashFile("foo", "bar");
+ theIndex.getMembers()[0].forceRecheck();
+ go();
+
+ assertTrue(theReadTree.removed.isEmpty());
+ assertTrue(theReadTree.updated.isEmpty());
+ assertTrue(theReadTree.conflicts.contains("foo"));
+
+ // rule 12 & 13
+ headMap.put("foo", "head");
+ setupCase(headMap, null, idxMap);
+ go();
+
+ assertTrue(theReadTree.removed.isEmpty());
+ assertTrue(theReadTree.updated.isEmpty());
+ assertTrue(theReadTree.conflicts.contains("foo"));
+
+ // rules 14 & 15
+ setupCase(headMap, headMap, idxMap);
+ go();
+
+ assertAllEmpty();
+
+ // rules 16 & 17
+ setupCase(headMap, mergeMap, idxMap); go();
+ assertTrue(theReadTree.conflicts.contains("foo"));
+
+ // rules 18 & 19
+ setupCase(headMap, idxMap, idxMap); go();
+ assertAllEmpty();
+
+ // rule 20
+ setupCase(idxMap, mergeMap, idxMap); go();
+ assertTrue(theReadTree.updated.containsKey("foo"));
+
+ // rules 21
+ setupCase(idxMap, mergeMap, idxMap);
+ new File(trash, "foo").delete();
+ writeTrashFile("foo", "bar");
+ theIndex.getMembers()[0].forceRecheck();
+ go();
+ assertTrue(theReadTree.conflicts.contains("foo"));
+ }
+
+ private void assertAllEmpty() {
+ assertTrue(theReadTree.removed.isEmpty());
+ assertTrue(theReadTree.updated.isEmpty());
+ assertTrue(theReadTree.conflicts.isEmpty());
+ }
+
+ public void testDirectoryFileSimple() throws IOException {
+ theIndex = new GitIndex(db);
+ theIndex.add(trash, writeTrashFile("DF", "DF"));
+ Tree treeDF = db.mapTree(theIndex.writeTree());
+
+ recursiveDelete(new File(trash, "DF"));
+ theIndex = new GitIndex(db);
+ theIndex.add(trash, writeTrashFile("DF/DF", "DF/DF"));
+ Tree treeDFDF = db.mapTree(theIndex.writeTree());
+
+ theIndex = new GitIndex(db);
+ recursiveDelete(new File(trash, "DF"));
+
+ theIndex.add(trash, writeTrashFile("DF", "DF"));
+ theReadTree = new WorkDirCheckout(db, trash, treeDF, theIndex, treeDFDF);
+ theReadTree.prescanTwoTrees();
+
+ assertTrue(theReadTree.removed.contains("DF"));
+ assertTrue(theReadTree.updated.containsKey("DF/DF"));
+
+ recursiveDelete(new File(trash, "DF"));
+ theIndex = new GitIndex(db);
+ theIndex.add(trash, writeTrashFile("DF/DF", "DF/DF"));
+
+ theReadTree = new WorkDirCheckout(db, trash, treeDFDF, theIndex, treeDF);
+ theReadTree.prescanTwoTrees();
+ assertTrue(theReadTree.removed.contains("DF/DF"));
+ assertTrue(theReadTree.updated.containsKey("DF"));
+ }
+
+ /*
+ * Directory/File Conflict cases:
+ * It's entirely possible that in practice a number of these may be equivalent
+ * to the cases described in git-read-tree.txt. As long as it does the right thing,
+ * that's all I care about. These are basically reverse-engineered from
+ * what git currently does. If there are tests for these in git, it's kind of
+ * hard to track them all down...
+ *
+ * H I M Clean H==M H==I I==M Result
+ * ------------------------------------------------------------------
+ *1 D D F Y N Y N Update
+ *2 D D F N N Y N Conflict
+ *3 D F D Y N N Update
+ *4 D F D N N N Update
+ *5 D F F Y N N Y Keep
+ *6 D F F N N N Y Keep
+ *7 F D F Y Y N N Update
+ *8 F D F N Y N N Conflict
+ *9 F D F Y N N N Update
+ *10 F D D N N Y Keep
+ *11 F D D N N N Conflict
+ *12 F F D Y N Y N Update
+ *13 F F D N N Y N Conflict
+ *14 F F D N N N Conflict
+ *15 0 F D N N N Conflict
+ *16 0 D F Y N N N Update
+ *17 0 D F N N N Conflict
+ *18 F 0 D Update
+ *19 D 0 F Update
+ */
+
+ public void testDirectoryFileConflicts_1() throws Exception {
+ // 1
+ doit(mk("DF/DF"), mk("DF"), mk("DF/DF"));
+ assertNoConflicts();
+ assertUpdated("DF");
+ assertRemoved("DF/DF");
+ }
+
+ public void testDirectoryFileConflicts_2() throws Exception {
+ // 2
+ setupCase(mk("DF/DF"), mk("DF"), mk("DF/DF"));
+ writeTrashFile("DF/DF", "different");
+ go();
+ assertConflict("DF/DF");
+
+ }
+
+ public void testDirectoryFileConflicts_3() throws Exception {
+ // 3 - the first to break!
+ doit(mk("DF/DF"), mk("DF/DF"), mk("DF"));
+ assertUpdated("DF/DF");
+ assertRemoved("DF");
+ }
+
+ public void testDirectoryFileConflicts_4() throws Exception {
+ // 4 (basically same as 3, just with H and M different)
+ doit(mk("DF/DF"), mkmap("DF/DF", "foo"), mk("DF"));
+ assertUpdated("DF/DF");
+ assertRemoved("DF");
+
+ }
+
+ public void testDirectoryFileConflicts_5() throws Exception {
+ // 5
+ doit(mk("DF/DF"), mk("DF"), mk("DF"));
+ assertRemoved("DF/DF");
+
+ }
+
+ public void testDirectoryFileConflicts_6() throws Exception {
+ // 6
+ setupCase(mk("DF/DF"), mk("DF"), mk("DF"));
+ writeTrashFile("DF", "different");
+ go();
+ assertRemoved("DF/DF");
+ }
+
+ public void testDirectoryFileConflicts_7() throws Exception {
+ // 7
+ doit(mk("DF"), mk("DF"), mk("DF/DF"));
+ assertUpdated("DF");
+ assertRemoved("DF/DF");
+
+ cleanUpDF();
+ setupCase(mk("DF/DF"), mk("DF/DF"), mk("DF/DF/DF/DF/DF"));
+ go();
+ assertRemoved("DF/DF/DF/DF/DF");
+ assertUpdated("DF/DF");
+
+ cleanUpDF();
+ setupCase(mk("DF/DF"), mk("DF/DF"), mk("DF/DF/DF/DF/DF"));
+ writeTrashFile("DF/DF/DF/DF/DF", "diff");
+ go();
+ assertConflict("DF/DF/DF/DF/DF");
+ assertUpdated("DF/DF");
+
+ }
+
+ // 8 ?
+
+ public void testDirectoryFileConflicts_9() throws Exception {
+ // 9
+ doit(mk("DF"), mkmap("DF", "QP"), mk("DF/DF"));
+ assertRemoved("DF/DF");
+ assertUpdated("DF");
+ }
+
+ public void testDirectoryFileConflicts_10() throws Exception {
+ // 10
+ cleanUpDF();
+ doit(mk("DF"), mk("DF/DF"), mk("DF/DF"));
+ assertNoConflicts();
+
+ }
+
+ public void testDirectoryFileConflicts_11() throws Exception {
+ // 11
+ doit(mk("DF"), mk("DF/DF"), mkmap("DF/DF", "asdf"));
+ assertConflict("DF/DF");
+ }
+
+ public void testDirectoryFileConflicts_12() throws Exception {
+ // 12
+ cleanUpDF();
+ doit(mk("DF"), mk("DF/DF"), mk("DF"));
+ assertRemoved("DF");
+ assertUpdated("DF/DF");
+ }
+
+ public void testDirectoryFileConflicts_13() throws Exception {
+ // 13
+ cleanUpDF();
+ setupCase(mk("DF"), mk("DF/DF"), mk("DF"));
+ writeTrashFile("DF", "asdfsdf");
+ go();
+ assertConflict("DF");
+ assertUpdated("DF/DF");
+ }
+
+ public void testDirectoryFileConflicts_14() throws Exception {
+ // 14
+ cleanUpDF();
+ doit(mk("DF"), mk("DF/DF"), mkmap("DF", "Foo"));
+ assertConflict("DF");
+ assertUpdated("DF/DF");
+ }
+
+ public void testDirectoryFileConflicts_15() throws Exception {
+ // 15
+ doit(mkmap(), mk("DF/DF"), mk("DF"));
+ assertRemoved("DF");
+ assertUpdated("DF/DF");
+ }
+
+ public void testDirectoryFileConflicts_15b() throws Exception {
+ // 15, take 2, just to check multi-leveled
+ doit(mkmap(), mk("DF/DF/DF/DF"), mk("DF"));
+ assertRemoved("DF");
+ assertUpdated("DF/DF/DF/DF");
+ }
+
+ public void testDirectoryFileConflicts_16() throws Exception {
+ // 16
+ cleanUpDF();
+ doit(mkmap(), mk("DF"), mk("DF/DF/DF"));
+ assertRemoved("DF/DF/DF");
+ assertUpdated("DF");
+ }
+
+ public void testDirectoryFileConflicts_17() throws Exception {
+ // 17
+ cleanUpDF();
+ setupCase(mkmap(), mk("DF"), mk("DF/DF/DF"));
+ writeTrashFile("DF/DF/DF", "asdf");
+ go();
+ assertConflict("DF/DF/DF");
+ assertUpdated("DF");
+ }
+
+ public void testDirectoryFileConflicts_18() throws Exception {
+ // 18
+ cleanUpDF();
+ doit(mk("DF/DF"), mk("DF/DF/DF/DF"), null);
+ assertRemoved("DF/DF");
+ assertUpdated("DF/DF/DF/DF");
+ }
+
+ public void testDirectoryFileConflicts_19() throws Exception {
+ // 19
+ cleanUpDF();
+ doit(mk("DF/DF/DF/DF"), mk("DF/DF/DF"), null);
+ assertRemoved("DF/DF/DF/DF");
+ assertUpdated("DF/DF/DF");
+ }
+
+ private void cleanUpDF() throws Exception {
+ tearDown();
+ setUp();
+ recursiveDelete(new File(trash, "DF"));
+ }
+
+ private void assertConflict(String s) {
+ assertTrue(theReadTree.conflicts.contains(s));
+ }
+
+ private void assertUpdated(String s) {
+ assertTrue(theReadTree.updated.containsKey(s));
+ }
+
+ private void assertRemoved(String s) {
+ assertTrue(theReadTree.removed.contains(s));
+ }
+
+ private void assertNoConflicts() {
+ assertTrue(theReadTree.conflicts.isEmpty());
+ }
+
+ private void doit(HashMap<String, String> h, HashMap<String, String>m,
+ HashMap<String, String> i) throws IOException {
+ setupCase(h, m, i);
+ go();
+ }
+
+ private static HashMap<String, String> mk(String a) {
+ return mkmap(a, a);
+ }
+
+ private static HashMap<String, String> mkmap(String... args) {
+ if ((args.length % 2) > 0)
+ throw new IllegalArgumentException("needs to be pairs");
+
+ HashMap<String, String> map = new HashMap<String, String>();
+ for (int i = 0; i < args.length; i += 2) {
+ map.put(args[i], args[i+1]);
+ }
+
+ return map;
+ }
+
+ public void testUntrackedConflicts() throws IOException {
+ setupCase(null, mk("foo"), null);
+ writeTrashFile("foo", "foo");
+ go();
+
+ assertConflict("foo");
+
+ recursiveDelete(new File(trash, "foo"));
+ setupCase(null, mk("foo"), null);
+ writeTrashFile("foo/bar/baz", "");
+ writeTrashFile("foo/blahblah", "");
+ go();
+
+ assertConflict("foo/bar/baz");
+ assertConflict("foo/blahblah");
+
+ recursiveDelete(new File(trash, "foo"));
+
+ setupCase(mkmap("foo/bar", "", "foo/baz", ""),
+ mk("foo"), mkmap("foo/bar", "", "foo/baz", ""));
+ assertTrue(new File(trash, "foo/bar").exists());
+ go();
+
+ assertNoConflicts();
+ }
+
+ public void testCloseNameConflictsX0() throws IOException {
+ setupCase(mkmap("a/a", "a/a-c"), mkmap("a/a","a/a", "b.b/b.b","b.b/b.bs"), mkmap("a/a", "a/a-c") );
+ checkout();
+ go();
+ assertNoConflicts();
+ }
+
+ public void testCloseNameConflicts1() throws IOException {
+ setupCase(mkmap("a/a", "a/a-c"), mkmap("a/a","a/a", "a.a/a.a","a.a/a.a"), mkmap("a/a", "a/a-c") );
+ checkout();
+ go();
+ assertNoConflicts();
+ }
+
+ private void checkout() throws IOException {
+ theReadTree = new WorkDirCheckout(db, trash, theHead, theIndex, theMerge);
+ theReadTree.checkout();
+ }
+
+ public void testCheckoutOutChanges() throws IOException {
+ setupCase(mk("foo"), mk("foo/bar"), mk("foo"));
+ checkout();
+
+ assertFalse(new File(trash, "foo").isFile());
+ assertTrue(new File(trash, "foo/bar").isFile());
+ recursiveDelete(new File(trash, "foo"));
+
+ setupCase(mk("foo/bar"), mk("foo"), mk("foo/bar"));
+ checkout();
+
+ assertFalse(new File(trash, "foo/bar").isFile());
+ assertTrue(new File(trash, "foo").isFile());
+
+ setupCase(mk("foo"), mkmap("foo", "qux"), mkmap("foo", "bar"));
+
+ try {
+ checkout();
+ fail("did not throw exception");
+ } catch (CheckoutConflictException e) {
+ // should have thrown
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java
new file mode 100644
index 0000000000..d7b6193ce1
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefTest.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2009, Robin Rosenberg
+ * Copyright (C) 2009, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Map;
+
+import org.eclipse.jgit.lib.Ref.Storage;
+import org.eclipse.jgit.lib.RefUpdate.Result;
+
+/**
+ * Misc tests for refs. A lot of things are tested elsewhere so not having a
+ * test for a ref related method, does not mean it is untested.
+ */
+public class RefTest extends RepositoryTestCase {
+
+ public void testReadAllIncludingSymrefs() throws Exception {
+ ObjectId masterId = db.resolve("refs/heads/master");
+ RefUpdate updateRef = db.updateRef("refs/remotes/origin/master");
+ updateRef.setNewObjectId(masterId);
+ updateRef.setForceUpdate(true);
+ updateRef.update();
+ db
+ .writeSymref("refs/remotes/origin/HEAD",
+ "refs/remotes/origin/master");
+
+ ObjectId r = db.resolve("refs/remotes/origin/HEAD");
+ assertEquals(masterId, r);
+
+ Map<String, Ref> allRefs = db.getAllRefs();
+ Ref refHEAD = allRefs.get("refs/remotes/origin/HEAD");
+ assertNotNull(refHEAD);
+ assertEquals(masterId, refHEAD.getObjectId());
+ assertTrue(refHEAD.isPeeled());
+ assertNull(refHEAD.getPeeledObjectId());
+
+ Ref refmaster = allRefs.get("refs/remotes/origin/master");
+ assertEquals(masterId, refmaster.getObjectId());
+ assertFalse(refmaster.isPeeled());
+ assertNull(refmaster.getPeeledObjectId());
+ }
+
+ public void testReadSymRefToPacked() throws IOException {
+ db.writeSymref("HEAD", "refs/heads/b");
+ Ref ref = db.getRef("HEAD");
+ assertEquals(Ref.Storage.LOOSE_PACKED, ref.getStorage());
+ }
+
+ public void testReadSymRefToLoosePacked() throws IOException {
+ ObjectId pid = db.resolve("refs/heads/master^");
+ RefUpdate updateRef = db.updateRef("refs/heads/master");
+ updateRef.setNewObjectId(pid);
+ updateRef.setForceUpdate(true);
+ Result update = updateRef.update();
+ assertEquals(Result.FORCED, update); // internal
+
+ db.writeSymref("HEAD", "refs/heads/master");
+ Ref ref = db.getRef("HEAD");
+ assertEquals(Ref.Storage.LOOSE_PACKED, ref.getStorage());
+ }
+
+ public void testReadLooseRef() throws IOException {
+ RefUpdate updateRef = db.updateRef("ref/heads/new");
+ updateRef.setNewObjectId(db.resolve("refs/heads/master"));
+ Result update = updateRef.update();
+ assertEquals(Result.NEW, update);
+ Ref ref = db.getRef("ref/heads/new");
+ assertEquals(Storage.LOOSE, ref.getStorage());
+ }
+
+ /**
+ * Let an "outsider" create a loose ref with the same name as a packed one
+ *
+ * @throws IOException
+ * @throws InterruptedException
+ */
+ public void testReadLoosePackedRef() throws IOException,
+ InterruptedException {
+ Ref ref = db.getRef("refs/heads/master");
+ assertEquals(Storage.PACKED, ref.getStorage());
+ FileOutputStream os = new FileOutputStream(new File(db.getDirectory(),
+ "refs/heads/master"));
+ os.write(ref.getObjectId().name().getBytes());
+ os.write('\n');
+ os.close();
+
+ ref = db.getRef("refs/heads/master");
+ assertEquals(Storage.LOOSE_PACKED, ref.getStorage());
+ }
+
+ /**
+ * Modify a packed ref using the API. This creates a loose ref too, ie.
+ * LOOSE_PACKED
+ *
+ * @throws IOException
+ */
+ public void testReadSimplePackedRefSameRepo() throws IOException {
+ Ref ref = db.getRef("refs/heads/master");
+ ObjectId pid = db.resolve("refs/heads/master^");
+ assertEquals(Storage.PACKED, ref.getStorage());
+ RefUpdate updateRef = db.updateRef("refs/heads/master");
+ updateRef.setNewObjectId(pid);
+ updateRef.setForceUpdate(true);
+ Result update = updateRef.update();
+ assertEquals(Result.FORCED, update);
+
+ ref = db.getRef("refs/heads/master");
+ assertEquals(Storage.LOOSE_PACKED, ref.getStorage());
+ }
+
+ public void testOrigResolvedNamesBranch() throws IOException {
+ Ref ref = db.getRef("a");
+ assertEquals("refs/heads/a", ref.getName());
+ assertEquals("refs/heads/a", ref.getOrigName());
+ }
+
+ public void testOrigResolvedNamesSymRef() throws IOException {
+ Ref ref = db.getRef("HEAD");
+ assertEquals("refs/heads/master", ref.getName());
+ assertEquals("HEAD", ref.getOrigName());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefUpdateTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefUpdateTest.java
new file mode 100644
index 0000000000..3704c56173
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RefUpdateTest.java
@@ -0,0 +1,768 @@
+/*
+ * Copyright (C) 2008, Charles O'Farrell <charleso@charleso.org>
+ * Copyright (C) 2008-2009, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.eclipse.jgit.lib.RefUpdate.Result;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+
+public class RefUpdateTest extends RepositoryTestCase {
+
+ private RefUpdate updateRef(final String name) throws IOException {
+ final RefUpdate ref = db.updateRef(name);
+ ref.setNewObjectId(db.resolve(Constants.HEAD));
+ return ref;
+ }
+
+ private void delete(final RefUpdate ref, final Result expected)
+ throws IOException {
+ delete(ref, expected, true, true);
+ }
+
+ private void delete(final RefUpdate ref, final Result expected,
+ final boolean exists, final boolean removed) throws IOException {
+ assertEquals(exists, db.getAllRefs().containsKey(ref.getName()));
+ assertEquals(expected, ref.delete());
+ assertEquals(!removed, db.getAllRefs().containsKey(ref.getName()));
+ }
+
+ public void testNoCacheObjectIdSubclass() throws IOException {
+ final String newRef = "refs/heads/abc";
+ final RefUpdate ru = updateRef(newRef);
+ final RevCommit newid = new RevCommit(ru.getNewObjectId()) {
+ // empty
+ };
+ ru.setNewObjectId(newid);
+ Result update = ru.update();
+ assertEquals(Result.NEW, update);
+ final Ref r = db.getAllRefs().get(newRef);
+ assertNotNull(r);
+ assertEquals(newRef, r.getName());
+ assertNotNull(r.getObjectId());
+ assertNotSame(newid, r.getObjectId());
+ assertSame(ObjectId.class, r.getObjectId().getClass());
+ assertEquals(newid.copy(), r.getObjectId());
+ List<org.eclipse.jgit.lib.ReflogReader.Entry> reverseEntries1 = db.getReflogReader("refs/heads/abc").getReverseEntries();
+ org.eclipse.jgit.lib.ReflogReader.Entry entry1 = reverseEntries1.get(0);
+ assertEquals(1, reverseEntries1.size());
+ assertEquals(ObjectId.zeroId(), entry1.getOldId());
+ assertEquals(r.getObjectId(), entry1.getNewId());
+ assertEquals(new PersonIdent(db).toString(), entry1.getWho().toString());
+ assertEquals("", entry1.getComment());
+ List<org.eclipse.jgit.lib.ReflogReader.Entry> reverseEntries2 = db.getReflogReader("HEAD").getReverseEntries();
+ assertEquals(0, reverseEntries2.size());
+ }
+
+ public void testNewNamespaceConflictWithLoosePrefixNameExists()
+ throws IOException {
+ final String newRef = "refs/heads/z";
+ final RefUpdate ru = updateRef(newRef);
+ final RevCommit newid = new RevCommit(ru.getNewObjectId()) {
+ // empty
+ };
+ ru.setNewObjectId(newid);
+ Result update = ru.update();
+ assertEquals(Result.NEW, update);
+ // end setup
+ final String newRef2 = "refs/heads/z/a";
+ final RefUpdate ru2 = updateRef(newRef2);
+ final RevCommit newid2 = new RevCommit(ru2.getNewObjectId()) {
+ // empty
+ };
+ ru.setNewObjectId(newid2);
+ Result update2 = ru2.update();
+ assertEquals(Result.LOCK_FAILURE, update2);
+ assertEquals(1, db.getReflogReader("refs/heads/z").getReverseEntries().size());
+ assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
+ }
+
+ public void testNewNamespaceConflictWithPackedPrefixNameExists()
+ throws IOException {
+ final String newRef = "refs/heads/master/x";
+ final RefUpdate ru = updateRef(newRef);
+ final RevCommit newid = new RevCommit(ru.getNewObjectId()) {
+ // empty
+ };
+ ru.setNewObjectId(newid);
+ Result update = ru.update();
+ assertEquals(Result.LOCK_FAILURE, update);
+ assertNull(db.getReflogReader("refs/heads/master/x"));
+ assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
+ }
+
+ public void testNewNamespaceConflictWithLoosePrefixOfExisting()
+ throws IOException {
+ final String newRef = "refs/heads/z/a";
+ final RefUpdate ru = updateRef(newRef);
+ final RevCommit newid = new RevCommit(ru.getNewObjectId()) {
+ // empty
+ };
+ ru.setNewObjectId(newid);
+ Result update = ru.update();
+ assertEquals(Result.NEW, update);
+ // end setup
+ final String newRef2 = "refs/heads/z";
+ final RefUpdate ru2 = updateRef(newRef2);
+ final RevCommit newid2 = new RevCommit(ru2.getNewObjectId()) {
+ // empty
+ };
+ ru.setNewObjectId(newid2);
+ Result update2 = ru2.update();
+ assertEquals(Result.LOCK_FAILURE, update2);
+ assertEquals(1, db.getReflogReader("refs/heads/z/a").getReverseEntries().size());
+ assertNull(db.getReflogReader("refs/heads/z"));
+ assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
+ }
+
+ public void testNewNamespaceConflictWithPackedPrefixOfExisting()
+ throws IOException {
+ final String newRef = "refs/heads/prefix";
+ final RefUpdate ru = updateRef(newRef);
+ final RevCommit newid = new RevCommit(ru.getNewObjectId()) {
+ // empty
+ };
+ ru.setNewObjectId(newid);
+ Result update = ru.update();
+ assertEquals(Result.LOCK_FAILURE, update);
+ assertNull(db.getReflogReader("refs/heads/prefix"));
+ assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
+ }
+
+ /**
+ * Delete a ref that is pointed to by HEAD
+ *
+ * @throws IOException
+ */
+ public void testDeleteHEADreferencedRef() throws IOException {
+ ObjectId pid = db.resolve("refs/heads/master^");
+ RefUpdate updateRef = db.updateRef("refs/heads/master");
+ updateRef.setNewObjectId(pid);
+ updateRef.setForceUpdate(true);
+ Result update = updateRef.update();
+ assertEquals(Result.FORCED, update); // internal
+
+ RefUpdate updateRef2 = db.updateRef("refs/heads/master");
+ Result delete = updateRef2.delete();
+ assertEquals(Result.REJECTED_CURRENT_BRANCH, delete);
+ assertEquals(pid, db.resolve("refs/heads/master"));
+ assertEquals(1,db.getReflogReader("refs/heads/master").getReverseEntries().size());
+ assertEquals(0,db.getReflogReader("HEAD").getReverseEntries().size());
+ }
+
+ public void testLooseDelete() throws IOException {
+ final String newRef = "refs/heads/abc";
+ RefUpdate ref = updateRef(newRef);
+ ref.update(); // create loose ref
+ ref = updateRef(newRef); // refresh
+ delete(ref, Result.NO_CHANGE);
+ assertNull(db.getReflogReader("refs/heads/abc"));
+ }
+
+ public void testDeleteHead() throws IOException {
+ final RefUpdate ref = updateRef(Constants.HEAD);
+ delete(ref, Result.REJECTED_CURRENT_BRANCH, true, false);
+ assertEquals(0, db.getReflogReader("refs/heads/master").getReverseEntries().size());
+ assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
+ }
+
+ /**
+ * Delete a loose ref and make sure the directory in refs is deleted too,
+ * and the reflog dir too
+ *
+ * @throws IOException
+ */
+ public void testDeleteLooseAndItsDirectory() throws IOException {
+ ObjectId pid = db.resolve("refs/heads/c^");
+ RefUpdate updateRef = db.updateRef("refs/heads/z/c");
+ updateRef.setNewObjectId(pid);
+ updateRef.setForceUpdate(true);
+ updateRef.setRefLogMessage("new test ref", false);
+ Result update = updateRef.update();
+ assertEquals(Result.NEW, update); // internal
+ assertTrue(new File(db.getDirectory(), Constants.R_HEADS + "z")
+ .exists());
+ assertTrue(new File(db.getDirectory(), "logs/refs/heads/z").exists());
+
+ // The real test here
+ RefUpdate updateRef2 = db.updateRef("refs/heads/z/c");
+ updateRef2.setForceUpdate(true);
+ Result delete = updateRef2.delete();
+ assertEquals(Result.FORCED, delete);
+ assertNull(db.resolve("refs/heads/z/c"));
+ assertFalse(new File(db.getDirectory(), Constants.R_HEADS + "z")
+ .exists());
+ assertFalse(new File(db.getDirectory(), "logs/refs/heads/z").exists());
+ }
+
+ public void testDeleteNotFound() throws IOException {
+ final RefUpdate ref = updateRef("refs/heads/xyz");
+ delete(ref, Result.NEW, false, true);
+ }
+
+ public void testDeleteFastForward() throws IOException {
+ final RefUpdate ref = updateRef("refs/heads/a");
+ delete(ref, Result.FAST_FORWARD);
+ }
+
+ public void testDeleteForce() throws IOException {
+ final RefUpdate ref = db.updateRef("refs/heads/b");
+ ref.setNewObjectId(db.resolve("refs/heads/a"));
+ delete(ref, Result.REJECTED, true, false);
+ ref.setForceUpdate(true);
+ delete(ref, Result.FORCED);
+ }
+
+ public void testRefKeySameAsOrigName() {
+ Map<String, Ref> allRefs = db.getAllRefs();
+ for (Entry<String, Ref> e : allRefs.entrySet()) {
+ assertEquals(e.getKey(), e.getValue().getOrigName());
+
+ }
+ }
+
+ /**
+ * Try modify a ref forward, fast forward
+ *
+ * @throws IOException
+ */
+ public void testUpdateRefForward() throws IOException {
+ ObjectId ppid = db.resolve("refs/heads/master^");
+ ObjectId pid = db.resolve("refs/heads/master");
+
+ RefUpdate updateRef = db.updateRef("refs/heads/master");
+ updateRef.setNewObjectId(ppid);
+ updateRef.setForceUpdate(true);
+ Result update = updateRef.update();
+ assertEquals(Result.FORCED, update);
+ assertEquals(ppid, db.resolve("refs/heads/master"));
+
+ // real test
+ RefUpdate updateRef2 = db.updateRef("refs/heads/master");
+ updateRef2.setNewObjectId(pid);
+ Result update2 = updateRef2.update();
+ assertEquals(Result.FAST_FORWARD, update2);
+ assertEquals(pid, db.resolve("refs/heads/master"));
+ }
+
+ /**
+ * Delete a ref that exists both as packed and loose. Make sure the ref
+ * cannot be resolved after delete.
+ *
+ * @throws IOException
+ */
+ public void testDeleteLoosePacked() throws IOException {
+ ObjectId pid = db.resolve("refs/heads/c^");
+ RefUpdate updateRef = db.updateRef("refs/heads/c");
+ updateRef.setNewObjectId(pid);
+ updateRef.setForceUpdate(true);
+ Result update = updateRef.update();
+ assertEquals(Result.FORCED, update); // internal
+
+ // The real test here
+ RefUpdate updateRef2 = db.updateRef("refs/heads/c");
+ updateRef2.setForceUpdate(true);
+ Result delete = updateRef2.delete();
+ assertEquals(Result.FORCED, delete);
+ assertNull(db.resolve("refs/heads/c"));
+ }
+
+ /**
+ * Try modify a ref to same
+ *
+ * @throws IOException
+ */
+ public void testUpdateRefNoChange() throws IOException {
+ ObjectId pid = db.resolve("refs/heads/master");
+ RefUpdate updateRef = db.updateRef("refs/heads/master");
+ updateRef.setNewObjectId(pid);
+ Result update = updateRef.update();
+ assertEquals(Result.NO_CHANGE, update);
+ assertEquals(pid, db.resolve("refs/heads/master"));
+ }
+
+ /**
+ * Test case originating from
+ * <a href="http://bugs.eclipse.org/285991">bug 285991</a>
+ *
+ * Make sure the in memory cache is updated properly after
+ * update of symref. This one did not fail because the
+ * ref was packed due to implementation issues.
+ *
+ * @throws Exception
+ */
+ public void testRefsCacheAfterUpdate() throws Exception {
+ // Do not use the defalt repo for this case.
+ Map<String, Ref> allRefs = db.getAllRefs();
+ ObjectId oldValue = db.resolve("HEAD");
+ ObjectId newValue = db.resolve("HEAD^");
+ // first make HEAD refer to loose ref
+ RefUpdate updateRef = db.updateRef(Constants.HEAD);
+ updateRef.setForceUpdate(true);
+ updateRef.setNewObjectId(newValue);
+ Result update = updateRef.update();
+ assertEquals(Result.FORCED, update);
+
+ // now update that ref
+ updateRef = db.updateRef(Constants.HEAD);
+ updateRef.setForceUpdate(true);
+ updateRef.setNewObjectId(oldValue);
+ update = updateRef.update();
+ assertEquals(Result.FAST_FORWARD, update);
+ allRefs = db.getAllRefs();
+ assertEquals("refs/heads/master", allRefs.get("refs/heads/master").getName());
+ assertEquals("refs/heads/master", allRefs.get("refs/heads/master").getOrigName());
+ assertEquals("refs/heads/master", allRefs.get("HEAD").getName());
+ assertEquals("HEAD", allRefs.get("HEAD").getOrigName());
+ }
+
+ /**
+ * Test case originating from
+ * <a href="http://bugs.eclipse.org/285991">bug 285991</a>
+ *
+ * Make sure the in memory cache is updated properly after
+ * update of symref.
+ *
+ * @throws Exception
+ */
+ public void testRefsCacheAfterUpdateLoosOnly() throws Exception {
+ // Do not use the defalt repo for this case.
+ Map<String, Ref> allRefs = db.getAllRefs();
+ ObjectId oldValue = db.resolve("HEAD");
+ db.writeSymref(Constants.HEAD, "refs/heads/newref");
+ RefUpdate updateRef = db.updateRef(Constants.HEAD);
+ updateRef.setForceUpdate(true);
+ updateRef.setNewObjectId(oldValue);
+ Result update = updateRef.update();
+ assertEquals(Result.NEW, update);
+ allRefs = db.getAllRefs();
+ assertEquals("refs/heads/newref", allRefs.get("HEAD").getName());
+ assertEquals("HEAD", allRefs.get("HEAD").getOrigName());
+ assertEquals("refs/heads/newref", allRefs.get("refs/heads/newref").getName());
+ assertEquals("refs/heads/newref", allRefs.get("refs/heads/newref").getOrigName());
+ }
+
+ /**
+ * Try modify a ref, but get wrong expected old value
+ *
+ * @throws IOException
+ */
+ public void testUpdateRefLockFailureWrongOldValue() throws IOException {
+ ObjectId pid = db.resolve("refs/heads/master");
+ RefUpdate updateRef = db.updateRef("refs/heads/master");
+ updateRef.setNewObjectId(pid);
+ updateRef.setExpectedOldObjectId(db.resolve("refs/heads/master^"));
+ Result update = updateRef.update();
+ assertEquals(Result.LOCK_FAILURE, update);
+ assertEquals(pid, db.resolve("refs/heads/master"));
+ }
+
+ /**
+ * Try modify a ref forward, fast forward, checking old value first
+ *
+ * @throws IOException
+ */
+ public void testUpdateRefForwardWithCheck1() throws IOException {
+ ObjectId ppid = db.resolve("refs/heads/master^");
+ ObjectId pid = db.resolve("refs/heads/master");
+
+ RefUpdate updateRef = db.updateRef("refs/heads/master");
+ updateRef.setNewObjectId(ppid);
+ updateRef.setForceUpdate(true);
+ Result update = updateRef.update();
+ assertEquals(Result.FORCED, update);
+ assertEquals(ppid, db.resolve("refs/heads/master"));
+
+ // real test
+ RefUpdate updateRef2 = db.updateRef("refs/heads/master");
+ updateRef2.setExpectedOldObjectId(ppid);
+ updateRef2.setNewObjectId(pid);
+ Result update2 = updateRef2.update();
+ assertEquals(Result.FAST_FORWARD, update2);
+ assertEquals(pid, db.resolve("refs/heads/master"));
+ }
+
+ /**
+ * Try modify a ref forward, fast forward, checking old commit first
+ *
+ * @throws IOException
+ */
+ public void testUpdateRefForwardWithCheck2() throws IOException {
+ ObjectId ppid = db.resolve("refs/heads/master^");
+ ObjectId pid = db.resolve("refs/heads/master");
+
+ RefUpdate updateRef = db.updateRef("refs/heads/master");
+ updateRef.setNewObjectId(ppid);
+ updateRef.setForceUpdate(true);
+ Result update = updateRef.update();
+ assertEquals(Result.FORCED, update);
+ assertEquals(ppid, db.resolve("refs/heads/master"));
+
+ // real test
+ RevCommit old = new RevWalk(db).parseCommit(ppid);
+ RefUpdate updateRef2 = db.updateRef("refs/heads/master");
+ updateRef2.setExpectedOldObjectId(old);
+ updateRef2.setNewObjectId(pid);
+ Result update2 = updateRef2.update();
+ assertEquals(Result.FAST_FORWARD, update2);
+ assertEquals(pid, db.resolve("refs/heads/master"));
+ }
+
+ /**
+ * Try modify a ref that is locked
+ *
+ * @throws IOException
+ */
+ public void testUpdateRefLockFailureLocked() throws IOException {
+ ObjectId opid = db.resolve("refs/heads/master");
+ ObjectId pid = db.resolve("refs/heads/master^");
+ RefUpdate updateRef = db.updateRef("refs/heads/master");
+ updateRef.setNewObjectId(pid);
+ LockFile lockFile1 = new LockFile(new File(db.getDirectory(),"refs/heads/master"));
+ try {
+ assertTrue(lockFile1.lock()); // precondition to test
+ Result update = updateRef.update();
+ assertEquals(Result.LOCK_FAILURE, update);
+ assertEquals(opid, db.resolve("refs/heads/master"));
+ LockFile lockFile2 = new LockFile(new File(db.getDirectory(),"refs/heads/master"));
+ assertFalse(lockFile2.lock()); // was locked, still is
+ } finally {
+ lockFile1.unlock();
+ }
+ }
+
+ /**
+ * Try to delete a ref. Delete requires force.
+ *
+ * @throws IOException
+ */
+ public void testDeleteLoosePackedRejected() throws IOException {
+ ObjectId pid = db.resolve("refs/heads/c^");
+ ObjectId oldpid = db.resolve("refs/heads/c");
+ RefUpdate updateRef = db.updateRef("refs/heads/c");
+ updateRef.setNewObjectId(pid);
+ Result update = updateRef.update();
+ assertEquals(Result.REJECTED, update);
+ assertEquals(oldpid, db.resolve("refs/heads/c"));
+ }
+
+ public void testRenameBranchNoPreviousLog() throws IOException {
+ assertFalse("precondition, no log on old branchg", new File(db
+ .getDirectory(), "logs/refs/heads/b").exists());
+ ObjectId rb = db.resolve("refs/heads/b");
+ ObjectId oldHead = db.resolve(Constants.HEAD);
+ assertFalse(rb.equals(oldHead)); // assumption for this test
+ RefRename renameRef = db.renameRef("refs/heads/b",
+ "refs/heads/new/name");
+ Result result = renameRef.rename();
+ assertEquals(Result.RENAMED, result);
+ assertEquals(rb, db.resolve("refs/heads/new/name"));
+ assertNull(db.resolve("refs/heads/b"));
+ assertEquals(1, db.getReflogReader("new/name").getReverseEntries().size());
+ assertEquals("Branch: renamed b to new/name", db.getReflogReader("new/name")
+ .getLastEntry().getComment());
+ assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists());
+ assertEquals(oldHead, db.resolve(Constants.HEAD)); // unchanged
+ }
+
+ public void testRenameBranchHasPreviousLog() throws IOException {
+ ObjectId rb = db.resolve("refs/heads/b");
+ ObjectId oldHead = db.resolve(Constants.HEAD);
+ assertFalse("precondition for this test, branch b != HEAD", rb
+ .equals(oldHead));
+ RefLogWriter.writeReflog(db, rb, rb, "Just a message", "refs/heads/b");
+ assertTrue("no log on old branch", new File(db.getDirectory(),
+ "logs/refs/heads/b").exists());
+ RefRename renameRef = db.renameRef("refs/heads/b",
+ "refs/heads/new/name");
+ Result result = renameRef.rename();
+ assertEquals(Result.RENAMED, result);
+ assertEquals(rb, db.resolve("refs/heads/new/name"));
+ assertNull(db.resolve("refs/heads/b"));
+ assertEquals(2, db.getReflogReader("new/name").getReverseEntries().size());
+ assertEquals("Branch: renamed b to new/name", db.getReflogReader("new/name")
+ .getLastEntry().getComment());
+ assertEquals("Just a message", db.getReflogReader("new/name")
+ .getReverseEntries().get(1).getComment());
+ assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists());
+ assertEquals(oldHead, db.resolve(Constants.HEAD)); // unchanged
+ }
+
+ public void testRenameCurrentBranch() throws IOException {
+ ObjectId rb = db.resolve("refs/heads/b");
+ db.writeSymref(Constants.HEAD, "refs/heads/b");
+ ObjectId oldHead = db.resolve(Constants.HEAD);
+ assertTrue("internal test condition, b == HEAD", rb.equals(oldHead));
+ RefLogWriter.writeReflog(db, rb, rb, "Just a message", "refs/heads/b");
+ assertTrue("no log on old branch", new File(db.getDirectory(),
+ "logs/refs/heads/b").exists());
+ RefRename renameRef = db.renameRef("refs/heads/b",
+ "refs/heads/new/name");
+ Result result = renameRef.rename();
+ assertEquals(Result.RENAMED, result);
+ assertEquals(rb, db.resolve("refs/heads/new/name"));
+ assertNull(db.resolve("refs/heads/b"));
+ assertEquals("Branch: renamed b to new/name", db.getReflogReader(
+ "new/name").getLastEntry().getComment());
+ assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists());
+ assertEquals(rb, db.resolve(Constants.HEAD));
+ assertEquals(2, db.getReflogReader("new/name").getReverseEntries().size());
+ assertEquals("Branch: renamed b to new/name", db.getReflogReader("new/name").getReverseEntries().get(0).getComment());
+ assertEquals("Just a message", db.getReflogReader("new/name").getReverseEntries().get(1).getComment());
+ }
+
+ public void testRenameBranchAlsoInPack() throws IOException {
+ ObjectId rb = db.resolve("refs/heads/b");
+ ObjectId rb2 = db.resolve("refs/heads/b~1");
+ assertEquals(Ref.Storage.PACKED, db.getRef("refs/heads/b").getStorage());
+ RefUpdate updateRef = db.updateRef("refs/heads/b");
+ updateRef.setNewObjectId(rb2);
+ updateRef.setForceUpdate(true);
+ Result update = updateRef.update();
+ assertEquals("internal check new ref is loose", Result.FORCED, update);
+ assertEquals(Ref.Storage.LOOSE_PACKED, db.getRef("refs/heads/b")
+ .getStorage());
+ RefLogWriter.writeReflog(db, rb, rb, "Just a message", "refs/heads/b");
+ assertTrue("no log on old branch", new File(db.getDirectory(),
+ "logs/refs/heads/b").exists());
+ RefRename renameRef = db.renameRef("refs/heads/b",
+ "refs/heads/new/name");
+ Result result = renameRef.rename();
+ assertEquals(Result.RENAMED, result);
+ assertEquals(rb2, db.resolve("refs/heads/new/name"));
+ assertNull(db.resolve("refs/heads/b"));
+ assertEquals("Branch: renamed b to new/name", db.getReflogReader(
+ "new/name").getLastEntry().getComment());
+ assertEquals(3, db.getReflogReader("refs/heads/new/name").getReverseEntries().size());
+ assertEquals("Branch: renamed b to new/name", db.getReflogReader("refs/heads/new/name").getReverseEntries().get(0).getComment());
+ assertEquals(0, db.getReflogReader("HEAD").getReverseEntries().size());
+ // make sure b's log file is gone too.
+ assertFalse(new File(db.getDirectory(), "logs/refs/heads/b").exists());
+
+ // Create new Repository instance, to reread caches and make sure our
+ // assumptions are persistent.
+ Repository ndb = new Repository(db.getDirectory());
+ assertEquals(rb2, ndb.resolve("refs/heads/new/name"));
+ assertNull(ndb.resolve("refs/heads/b"));
+ }
+
+ public void tryRenameWhenLocked(String toLock, String fromName,
+ String toName, String headPointsTo) throws IOException {
+ // setup
+ db.writeSymref(Constants.HEAD, headPointsTo);
+ ObjectId oldfromId = db.resolve(fromName);
+ ObjectId oldHeadId = db.resolve(Constants.HEAD);
+ RefLogWriter.writeReflog(db, oldfromId, oldfromId, "Just a message",
+ fromName);
+ List<org.eclipse.jgit.lib.ReflogReader.Entry> oldFromLog = db
+ .getReflogReader(fromName).getReverseEntries();
+ List<org.eclipse.jgit.lib.ReflogReader.Entry> oldHeadLog = oldHeadId != null ? db
+ .getReflogReader(Constants.HEAD).getReverseEntries() : null;
+
+ assertTrue("internal check, we have a log", new File(db.getDirectory(),
+ "logs/" + fromName).exists());
+
+ // "someone" has branch X locked
+ LockFile lockFile = new LockFile(new File(db.getDirectory(), toLock));
+ try {
+ assertTrue(lockFile.lock());
+
+ // Now this is our test
+ RefRename renameRef = db.renameRef(fromName, toName);
+ Result result = renameRef.rename();
+ assertEquals(Result.LOCK_FAILURE, result);
+
+ // Check that the involved refs are the same despite the failure
+ assertExists(false, toName);
+ if (!toLock.equals(toName))
+ assertExists(false, toName + ".lock");
+ assertExists(true, toLock + ".lock");
+ if (!toLock.equals(fromName))
+ assertExists(false, "logs/" + fromName + ".lock");
+ assertExists(false, "logs/" + toName + ".lock");
+ assertEquals(oldHeadId, db.resolve(Constants.HEAD));
+ assertEquals(oldfromId, db.resolve(fromName));
+ assertNull(db.resolve(toName));
+ assertEquals(oldFromLog.toString(), db.getReflogReader(fromName)
+ .getReverseEntries().toString());
+ if (oldHeadId != null)
+ assertEquals(oldHeadLog, db.getReflogReader(Constants.HEAD)
+ .getReverseEntries());
+ } finally {
+ lockFile.unlock();
+ }
+ }
+
+ private void assertExists(boolean positive, String toName) {
+ assertEquals(toName + (positive ? " " : " does not ") + "exist",
+ positive, new File(db.getDirectory(), toName).exists());
+ }
+
+ public void testRenameBranchCannotLockAFileHEADisFromLockHEAD()
+ throws IOException {
+ tryRenameWhenLocked("HEAD", "refs/heads/b", "refs/heads/new/name",
+ "refs/heads/b");
+ }
+
+ public void testRenameBranchCannotLockAFileHEADisFromLockFrom()
+ throws IOException {
+ tryRenameWhenLocked("refs/heads/b", "refs/heads/b",
+ "refs/heads/new/name", "refs/heads/b");
+ }
+
+ public void testRenameBranchCannotLockAFileHEADisFromLockTo()
+ throws IOException {
+ tryRenameWhenLocked("refs/heads/new/name", "refs/heads/b",
+ "refs/heads/new/name", "refs/heads/b");
+ }
+
+ public void testRenameBranchCannotLockAFileHEADisToLockFrom()
+ throws IOException {
+ tryRenameWhenLocked("refs/heads/b", "refs/heads/b",
+ "refs/heads/new/name", "refs/heads/new/name");
+ }
+
+ public void testRenameBranchCannotLockAFileHEADisToLockTo()
+ throws IOException {
+ tryRenameWhenLocked("refs/heads/new/name", "refs/heads/b",
+ "refs/heads/new/name", "refs/heads/new/name");
+ }
+
+ public void testRenameBranchCannotLockAFileHEADisToLockTmp()
+ throws IOException {
+ tryRenameWhenLocked("RENAMED-REF.." + Thread.currentThread().getId(),
+ "refs/heads/b", "refs/heads/new/name", "refs/heads/new/name");
+ }
+
+ public void testRenameBranchCannotLockAFileHEADisOtherLockFrom()
+ throws IOException {
+ tryRenameWhenLocked("refs/heads/b", "refs/heads/b",
+ "refs/heads/new/name", "refs/heads/a");
+ }
+
+ public void testRenameBranchCannotLockAFileHEADisOtherLockTo()
+ throws IOException {
+ tryRenameWhenLocked("refs/heads/new/name", "refs/heads/b",
+ "refs/heads/new/name", "refs/heads/a");
+ }
+
+ public void testRenameBranchCannotLockAFileHEADisOtherLockTmp()
+ throws IOException {
+ tryRenameWhenLocked("RENAMED-REF.." + Thread.currentThread().getId(),
+ "refs/heads/b", "refs/heads/new/name", "refs/heads/a");
+ }
+
+ public void testRenameRefNameColission1avoided() throws IOException {
+ // setup
+ ObjectId rb = db.resolve("refs/heads/b");
+ db.writeSymref(Constants.HEAD, "refs/heads/a");
+ RefUpdate updateRef = db.updateRef("refs/heads/a");
+ updateRef.setNewObjectId(rb);
+ updateRef.setRefLogMessage("Setup", false);
+ assertEquals(Result.FAST_FORWARD, updateRef.update());
+ ObjectId oldHead = db.resolve(Constants.HEAD);
+ assertTrue(rb.equals(oldHead)); // assumption for this test
+ RefLogWriter.writeReflog(db, rb, rb, "Just a message", "refs/heads/a");
+ assertTrue("internal check, we have a log", new File(db.getDirectory(),
+ "logs/refs/heads/a").exists());
+
+ // Now this is our test
+ RefRename renameRef = db.renameRef("refs/heads/a", "refs/heads/a/b");
+ Result result = renameRef.rename();
+ assertEquals(Result.RENAMED, result);
+ assertNull(db.resolve("refs/heads/a"));
+ assertEquals(rb, db.resolve("refs/heads/a/b"));
+ assertEquals(3, db.getReflogReader("a/b").getReverseEntries().size());
+ assertEquals("Branch: renamed a to a/b", db.getReflogReader("a/b")
+ .getReverseEntries().get(0).getComment());
+ assertEquals("Just a message", db.getReflogReader("a/b")
+ .getReverseEntries().get(1).getComment());
+ assertEquals("Setup", db.getReflogReader("a/b").getReverseEntries()
+ .get(2).getComment());
+ // same thing was logged to HEAD
+ assertEquals("Branch: renamed a to a/b", db.getReflogReader("HEAD")
+ .getReverseEntries().get(0).getComment());
+ }
+
+ public void testRenameRefNameColission2avoided() throws IOException {
+ // setup
+ ObjectId rb = db.resolve("refs/heads/b");
+ db.writeSymref(Constants.HEAD, "refs/heads/prefix/a");
+ RefUpdate updateRef = db.updateRef("refs/heads/prefix/a");
+ updateRef.setNewObjectId(rb);
+ updateRef.setRefLogMessage("Setup", false);
+ updateRef.setForceUpdate(true);
+ assertEquals(Result.FORCED, updateRef.update());
+ ObjectId oldHead = db.resolve(Constants.HEAD);
+ assertTrue(rb.equals(oldHead)); // assumption for this test
+ RefLogWriter.writeReflog(db, rb, rb, "Just a message",
+ "refs/heads/prefix/a");
+ assertTrue("internal check, we have a log", new File(db.getDirectory(),
+ "logs/refs/heads/prefix/a").exists());
+
+ // Now this is our test
+ RefRename renameRef = db.renameRef("refs/heads/prefix/a",
+ "refs/heads/prefix");
+ Result result = renameRef.rename();
+ assertEquals(Result.RENAMED, result);
+
+ assertNull(db.resolve("refs/heads/prefix/a"));
+ assertEquals(rb, db.resolve("refs/heads/prefix"));
+ assertEquals(3, db.getReflogReader("prefix").getReverseEntries().size());
+ assertEquals("Branch: renamed prefix/a to prefix", db.getReflogReader(
+ "prefix").getReverseEntries().get(0).getComment());
+ assertEquals("Just a message", db.getReflogReader("prefix")
+ .getReverseEntries().get(1).getComment());
+ assertEquals("Setup", db.getReflogReader("prefix").getReverseEntries()
+ .get(2).getComment());
+ assertEquals("Branch: renamed prefix/a to prefix", db.getReflogReader(
+ "HEAD").getReverseEntries().get(0).getComment());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogReaderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogReaderTest.java
new file mode 100644
index 0000000000..dae7cb8955
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogReaderTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2009, Robin Rosenberg
+ * Copyright (C) 2009, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.text.SimpleDateFormat;
+import java.util.List;
+
+import org.eclipse.jgit.lib.ReflogReader.Entry;
+
+public class ReflogReaderTest extends RepositoryTestCase {
+
+ static byte[] oneLine = "da85355dfc525c9f6f3927b876f379f46ccf826e 3e7549db262d1e836d9bf0af7e22355468f1717c A O Thor Too <authortoo@wri.tr> 1243028200 +0200\tcommit: Add a toString for debugging to RemoteRefUpdate\n"
+ .getBytes();
+
+ static byte[] twoLine = ("0000000000000000000000000000000000000000 c6734895958052a9dbc396cff4459dc1a25029ab A U Thor <thor@committer.au> 1243028201 -0100\tbranch: Created from rr/renamebranchv4\n"
+ + "c6734895958052a9dbc396cff4459dc1a25029ab 54794942a18a237c57a80719afed44bb78172b10 Same A U Thor <same.author@example.com> 1243028202 +0100\trebase finished: refs/heads/rr/renamebranch5 onto c6e3b9fe2da0293f11eae202ec35fb343191a82d\n")
+ .getBytes();
+
+ static byte[] twoLineWithAppendInProgress = ("0000000000000000000000000000000000000000 c6734895958052a9dbc396cff4459dc1a25029ab A U Thor <thor@committer.au> 1243028201 -0100\tbranch: Created from rr/renamebranchv4\n"
+ + "c6734895958052a9dbc396cff4459dc1a25029ab 54794942a18a237c57a80719afed44bb78172b10 Same A U Thor <same.author@example.com> 1243028202 +0100\trebase finished: refs/heads/rr/renamebranch5 onto c6e3b9fe2da0293f11eae202ec35fb343191a82d\n"
+ + "54794942a18a237c57a80719afed44bb78172b10 ")
+ .getBytes();
+
+ static byte[] aLine = "1111111111111111111111111111111111111111 3e7549db262d1e836d9bf0af7e22355468f1717c A U Thor <thor@committer.au> 1243028201 -0100\tbranch: change to a\n"
+ .getBytes();
+
+ static byte[] masterLine = "2222222222222222222222222222222222222222 3e7549db262d1e836d9bf0af7e22355468f1717c A U Thor <thor@committer.au> 1243028201 -0100\tbranch: change to master\n"
+ .getBytes();
+
+ static byte[] headLine = "3333333333333333333333333333333333333333 3e7549db262d1e836d9bf0af7e22355468f1717c A U Thor <thor@committer.au> 1243028201 -0100\tbranch: change to HEAD\n"
+ .getBytes();
+
+ public void testReadOneLine() throws Exception {
+ setupReflog("logs/refs/heads/master", oneLine);
+
+ ReflogReader reader = new ReflogReader(db, "refs/heads/master");
+ Entry e = reader.getLastEntry();
+ assertEquals(ObjectId
+ .fromString("da85355dfc525c9f6f3927b876f379f46ccf826e"), e
+ .getOldId());
+ assertEquals(ObjectId
+ .fromString("3e7549db262d1e836d9bf0af7e22355468f1717c"), e
+ .getNewId());
+ assertEquals("A O Thor Too", e.getWho().getName());
+ assertEquals("authortoo@wri.tr", e.getWho().getEmailAddress());
+ assertEquals(120, e.getWho().getTimeZoneOffset());
+ assertEquals("2009-05-22T23:36:40", iso(e.getWho()));
+ assertEquals("commit: Add a toString for debugging to RemoteRefUpdate",
+ e.getComment());
+ }
+
+ private String iso(PersonIdent id) {
+ final SimpleDateFormat fmt;
+ fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
+ fmt.setTimeZone(id.getTimeZone());
+ return fmt.format(id.getWhen());
+ }
+
+ public void testReadTwoLine() throws Exception {
+ setupReflog("logs/refs/heads/master", twoLine);
+
+ ReflogReader reader = new ReflogReader(db, "refs/heads/master");
+ List<Entry> reverseEntries = reader.getReverseEntries();
+ assertEquals(2, reverseEntries.size());
+ Entry e = reverseEntries.get(0);
+ assertEquals(ObjectId
+ .fromString("c6734895958052a9dbc396cff4459dc1a25029ab"), e
+ .getOldId());
+ assertEquals(ObjectId
+ .fromString("54794942a18a237c57a80719afed44bb78172b10"), e
+ .getNewId());
+ assertEquals("Same A U Thor", e.getWho().getName());
+ assertEquals("same.author@example.com", e.getWho().getEmailAddress());
+ assertEquals(60, e.getWho().getTimeZoneOffset());
+ assertEquals("2009-05-22T22:36:42", iso(e.getWho()));
+ assertEquals(
+ "rebase finished: refs/heads/rr/renamebranch5 onto c6e3b9fe2da0293f11eae202ec35fb343191a82d",
+ e.getComment());
+
+ e = reverseEntries.get(1);
+ assertEquals(ObjectId
+ .fromString("0000000000000000000000000000000000000000"), e
+ .getOldId());
+ assertEquals(ObjectId
+ .fromString("c6734895958052a9dbc396cff4459dc1a25029ab"), e
+ .getNewId());
+ assertEquals("A U Thor", e.getWho().getName());
+ assertEquals("thor@committer.au", e.getWho().getEmailAddress());
+ assertEquals(-60, e.getWho().getTimeZoneOffset());
+ assertEquals("2009-05-22T20:36:41", iso(e.getWho()));
+ assertEquals("branch: Created from rr/renamebranchv4", e.getComment());
+ }
+
+ public void testReadWhileAppendIsInProgress() throws Exception {
+ setupReflog("logs/refs/heads/master", twoLineWithAppendInProgress);
+ ReflogReader reader = new ReflogReader(db, "refs/heads/master");
+ List<Entry> reverseEntries = reader.getReverseEntries();
+ assertEquals(2, reverseEntries.size());
+ Entry e = reverseEntries.get(0);
+ assertEquals(ObjectId
+ .fromString("c6734895958052a9dbc396cff4459dc1a25029ab"), e
+ .getOldId());
+ assertEquals(ObjectId
+ .fromString("54794942a18a237c57a80719afed44bb78172b10"), e
+ .getNewId());
+ assertEquals("Same A U Thor", e.getWho().getName());
+ assertEquals("same.author@example.com", e.getWho().getEmailAddress());
+ assertEquals(60, e.getWho().getTimeZoneOffset());
+ assertEquals("2009-05-22T22:36:42", iso(e.getWho()));
+ assertEquals(
+ "rebase finished: refs/heads/rr/renamebranch5 onto c6e3b9fe2da0293f11eae202ec35fb343191a82d",
+ e.getComment());
+ // while similar to testReadTwoLine, we can assume that if we get the last entry
+ // right, everything else is too
+ }
+
+
+ public void testReadRightLog() throws Exception {
+ setupReflog("logs/refs/heads/a", aLine);
+ setupReflog("logs/refs/heads/master", masterLine);
+ setupReflog("logs/HEAD", headLine);
+ assertEquals("branch: change to master", db.getReflogReader("master")
+ .getLastEntry().getComment());
+ assertEquals("branch: change to a", db.getReflogReader("a")
+ .getLastEntry().getComment());
+ assertEquals("branch: change to HEAD", db.getReflogReader("HEAD")
+ .getLastEntry().getComment());
+ }
+
+ public void testNoLog() throws Exception {
+ assertEquals(0, db.getReflogReader("master").getReverseEntries().size());
+ assertNull(db.getReflogReader("master").getLastEntry());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryCacheTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryCacheTest.java
new file mode 100644
index 0000000000..c0591755f4
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryCacheTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.eclipse.jgit.errors.RepositoryNotFoundException;
+import org.eclipse.jgit.lib.RepositoryCache.FileKey;
+
+public class RepositoryCacheTest extends RepositoryTestCase {
+ public void testNonBareFileKey() {
+ File gitdir = db.getDirectory();
+ File parent = gitdir.getParentFile();
+ File other = new File(parent, "notagit");
+ assertEquals(gitdir, FileKey.exact(gitdir).getFile());
+ assertEquals(parent, FileKey.exact(parent).getFile());
+ assertEquals(other, FileKey.exact(other).getFile());
+
+ assertEquals(gitdir, FileKey.lenient(gitdir).getFile());
+ assertEquals(gitdir, FileKey.lenient(parent).getFile());
+ assertEquals(other, FileKey.lenient(other).getFile());
+ }
+
+ public void testBareFileKey() throws IOException {
+ Repository bare = createNewEmptyRepo(true);
+ File gitdir = bare.getDirectory();
+ File parent = gitdir.getParentFile();
+ String name = gitdir.getName();
+ assertTrue(name.endsWith(".git"));
+ name = name.substring(0, name.length() - 4);
+
+ assertEquals(gitdir, FileKey.exact(gitdir).getFile());
+
+ assertEquals(gitdir, FileKey.lenient(gitdir).getFile());
+ assertEquals(gitdir, FileKey.lenient(new File(parent, name)).getFile());
+ }
+
+ public void testFileKeyOpenExisting() throws IOException {
+ Repository r;
+
+ r = new FileKey(db.getDirectory()).open(true);
+ assertNotNull(r);
+ assertEquals(db.getDirectory(), r.getDirectory());
+ r.close();
+
+ r = new FileKey(db.getDirectory()).open(false);
+ assertNotNull(r);
+ assertEquals(db.getDirectory(), r.getDirectory());
+ r.close();
+ }
+
+ public void testFileKeyOpenNew() throws IOException {
+ final Repository n = createNewEmptyRepo(true);
+ final File gitdir = n.getDirectory();
+ n.close();
+ recursiveDelete(gitdir);
+ assertFalse(gitdir.exists());
+
+ try {
+ new FileKey(gitdir).open(true);
+ fail("incorrectly opened a non existant repository");
+ } catch (RepositoryNotFoundException e) {
+ assertEquals("repository not found: " + gitdir, e.getMessage());
+ }
+
+ final Repository o = new FileKey(gitdir).open(false);
+ assertNotNull(o);
+ assertEquals(gitdir, o.getDirectory());
+ assertFalse(gitdir.exists());
+ }
+
+ public void testCacheRegisterOpen() throws Exception {
+ final File dir = db.getDirectory();
+ RepositoryCache.register(db);
+ assertSame(db, RepositoryCache.open(FileKey.exact(dir)));
+
+ assertEquals(".git", dir.getName());
+ final File parent = dir.getParentFile();
+ assertSame(db, RepositoryCache.open(FileKey.lenient(parent)));
+ }
+
+ public void testCacheOpen() throws Exception {
+ final FileKey loc = FileKey.exact(db.getDirectory());
+ final Repository d2 = RepositoryCache.open(loc);
+ assertNotSame(db, d2);
+ assertSame(d2, RepositoryCache.open(FileKey.exact(loc.getFile())));
+ d2.close();
+ d2.close();
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryConfigTest.java
new file mode 100644
index 0000000000..08e701ab50
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryConfigTest.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
+ * Copyright (C) 2009, Google Inc.
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.util.Arrays;
+import java.util.LinkedList;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.util.SystemReader;
+
+/**
+ * Test reading of git config
+ */
+public class RepositoryConfigTest extends TestCase {
+ public void test001_ReadBareKey() throws ConfigInvalidException {
+ final Config c = parse("[foo]\nbar\n");
+ assertEquals(true, c.getBoolean("foo", null, "bar", false));
+ assertEquals("", c.getString("foo", null, "bar"));
+ }
+
+ public void test002_ReadWithSubsection() throws ConfigInvalidException {
+ final Config c = parse("[foo \"zip\"]\nbar\n[foo \"zap\"]\nbar=false\nn=3\n");
+ assertEquals(true, c.getBoolean("foo", "zip", "bar", false));
+ assertEquals("", c.getString("foo","zip", "bar"));
+ assertEquals(false, c.getBoolean("foo", "zap", "bar", true));
+ assertEquals("false", c.getString("foo", "zap", "bar"));
+ assertEquals(3, c.getInt("foo", "zap", "n", 4));
+ assertEquals(4, c.getInt("foo", "zap","m", 4));
+ }
+
+ public void test003_PutRemote() {
+ final Config c = new Config();
+ c.setString("sec", "ext", "name", "value");
+ c.setString("sec", "ext", "name2", "value2");
+ final String expText = "[sec \"ext\"]\n\tname = value\n\tname2 = value2\n";
+ assertEquals(expText, c.toText());
+ }
+
+ public void test004_PutGetSimple() {
+ Config c = new Config();
+ c.setString("my", null, "somename", "false");
+ assertEquals("false", c.getString("my", null, "somename"));
+ assertEquals("[my]\n\tsomename = false\n", c.toText());
+ }
+
+ public void test005_PutGetStringList() {
+ Config c = new Config();
+ final LinkedList<String> values = new LinkedList<String>();
+ values.add("value1");
+ values.add("value2");
+ c.setStringList("my", null, "somename", values);
+
+ final Object[] expArr = values.toArray();
+ final String[] actArr = c.getStringList("my", null, "somename");
+ assertTrue(Arrays.equals(expArr, actArr));
+
+ final String expText = "[my]\n\tsomename = value1\n\tsomename = value2\n";
+ assertEquals(expText, c.toText());
+ }
+
+ public void test006_readCaseInsensitive() throws ConfigInvalidException {
+ final Config c = parse("[Foo]\nBar\n");
+ assertEquals(true, c.getBoolean("foo", null, "bar", false));
+ assertEquals("", c.getString("foo", null, "bar"));
+ }
+
+ public void test007_readUserConfig() {
+ final MockSystemReader mockSystemReader = new MockSystemReader();
+ SystemReader.setInstance(mockSystemReader);
+ final String hostname = mockSystemReader.getHostname();
+ final Config userGitConfig = mockSystemReader.userGitConfig;
+ final Config localConfig = new Config(userGitConfig);
+ mockSystemReader.values.clear();
+
+ String authorName;
+ String authorEmail;
+
+ // no values defined nowhere
+ authorName = localConfig.get(UserConfig.KEY).getAuthorName();
+ authorEmail = localConfig.get(UserConfig.KEY).getAuthorEmail();
+ assertEquals(Constants.UNKNOWN_USER_DEFAULT, authorName);
+ assertEquals(Constants.UNKNOWN_USER_DEFAULT + "@" + hostname, authorEmail);
+
+ // the system user name is defined
+ mockSystemReader.values.put(Constants.OS_USER_NAME_KEY, "os user name");
+ localConfig.uncache(UserConfig.KEY);
+ authorName = localConfig.get(UserConfig.KEY).getAuthorName();
+ assertEquals("os user name", authorName);
+
+ if (hostname != null && hostname.length() != 0) {
+ authorEmail = localConfig.get(UserConfig.KEY).getAuthorEmail();
+ assertEquals("os user name@" + hostname, authorEmail);
+ }
+
+ // the git environment variables are defined
+ mockSystemReader.values.put(Constants.GIT_AUTHOR_NAME_KEY, "git author name");
+ mockSystemReader.values.put(Constants.GIT_AUTHOR_EMAIL_KEY, "author@email");
+ localConfig.uncache(UserConfig.KEY);
+ authorName = localConfig.get(UserConfig.KEY).getAuthorName();
+ authorEmail = localConfig.get(UserConfig.KEY).getAuthorEmail();
+ assertEquals("git author name", authorName);
+ assertEquals("author@email", authorEmail);
+
+ // the values are defined in the global configuration
+ userGitConfig.setString("user", null, "name", "global username");
+ userGitConfig.setString("user", null, "email", "author@globalemail");
+ authorName = localConfig.get(UserConfig.KEY).getAuthorName();
+ authorEmail = localConfig.get(UserConfig.KEY).getAuthorEmail();
+ assertEquals("global username", authorName);
+ assertEquals("author@globalemail", authorEmail);
+
+ // the values are defined in the local configuration
+ localConfig.setString("user", null, "name", "local username");
+ localConfig.setString("user", null, "email", "author@localemail");
+ authorName = localConfig.get(UserConfig.KEY).getAuthorName();
+ authorEmail = localConfig.get(UserConfig.KEY).getAuthorEmail();
+ assertEquals("local username", authorName);
+ assertEquals("author@localemail", authorEmail);
+
+ authorName = localConfig.get(UserConfig.KEY).getCommitterName();
+ authorEmail = localConfig.get(UserConfig.KEY).getCommitterEmail();
+ assertEquals("local username", authorName);
+ assertEquals("author@localemail", authorEmail);
+ }
+
+ public void testReadBoolean_TrueFalse1() throws ConfigInvalidException {
+ final Config c = parse("[s]\na = true\nb = false\n");
+ assertEquals("true", c.getString("s", null, "a"));
+ assertEquals("false", c.getString("s", null, "b"));
+
+ assertTrue(c.getBoolean("s", "a", false));
+ assertFalse(c.getBoolean("s", "b", true));
+ }
+
+ public void testReadBoolean_TrueFalse2() throws ConfigInvalidException {
+ final Config c = parse("[s]\na = TrUe\nb = fAlSe\n");
+ assertEquals("TrUe", c.getString("s", null, "a"));
+ assertEquals("fAlSe", c.getString("s", null, "b"));
+
+ assertTrue(c.getBoolean("s", "a", false));
+ assertFalse(c.getBoolean("s", "b", true));
+ }
+
+ public void testReadBoolean_YesNo1() throws ConfigInvalidException {
+ final Config c = parse("[s]\na = yes\nb = no\n");
+ assertEquals("yes", c.getString("s", null, "a"));
+ assertEquals("no", c.getString("s", null, "b"));
+
+ assertTrue(c.getBoolean("s", "a", false));
+ assertFalse(c.getBoolean("s", "b", true));
+ }
+
+ public void testReadBoolean_YesNo2() throws ConfigInvalidException {
+ final Config c = parse("[s]\na = yEs\nb = NO\n");
+ assertEquals("yEs", c.getString("s", null, "a"));
+ assertEquals("NO", c.getString("s", null, "b"));
+
+ assertTrue(c.getBoolean("s", "a", false));
+ assertFalse(c.getBoolean("s", "b", true));
+ }
+
+ public void testReadBoolean_OnOff1() throws ConfigInvalidException {
+ final Config c = parse("[s]\na = on\nb = off\n");
+ assertEquals("on", c.getString("s", null, "a"));
+ assertEquals("off", c.getString("s", null, "b"));
+
+ assertTrue(c.getBoolean("s", "a", false));
+ assertFalse(c.getBoolean("s", "b", true));
+ }
+
+ public void testReadBoolean_OnOff2() throws ConfigInvalidException {
+ final Config c = parse("[s]\na = ON\nb = OFF\n");
+ assertEquals("ON", c.getString("s", null, "a"));
+ assertEquals("OFF", c.getString("s", null, "b"));
+
+ assertTrue(c.getBoolean("s", "a", false));
+ assertFalse(c.getBoolean("s", "b", true));
+ }
+
+ public void testReadLong() throws ConfigInvalidException {
+ assertReadLong(1L);
+ assertReadLong(-1L);
+ assertReadLong(Long.MIN_VALUE);
+ assertReadLong(Long.MAX_VALUE);
+ assertReadLong(4L * 1024 * 1024 * 1024, "4g");
+ assertReadLong(3L * 1024 * 1024, "3 m");
+ assertReadLong(8L * 1024, "8 k");
+
+ try {
+ assertReadLong(-1, "1.5g");
+ fail("incorrectly accepted 1.5g");
+ } catch (IllegalArgumentException e) {
+ assertEquals("Invalid integer value: s.a=1.5g", e.getMessage());
+ }
+ }
+
+ private void assertReadLong(long exp) throws ConfigInvalidException {
+ assertReadLong(exp, String.valueOf(exp));
+ }
+
+ private void assertReadLong(long exp, String act)
+ throws ConfigInvalidException {
+ final Config c = parse("[s]\na = " + act + "\n");
+ assertEquals(exp, c.getLong("s", null, "a", 0L));
+ }
+
+ private Config parse(final String content) throws ConfigInvalidException {
+ final Config c = new Config(null);
+ c.fromText(content);
+ return c;
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryTestCase.java
new file mode 100644
index 0000000000..2870e4126a
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryTestCase.java
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2007-2009, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2007, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jgit.util.JGitTestUtil;
+import org.eclipse.jgit.util.SystemReader;
+
+/**
+ * Base class for most JGit unit tests.
+ *
+ * Sets up a predefined test repository and has support for creating additional
+ * repositories and destroying them when the tests are finished.
+ *
+ * A system property <em>jgit.junit.usemmap</em> defines whether memory mapping
+ * is used. Memory mapping has an effect on the file system, in that memory
+ * mapped files in java cannot be deleted as long as they mapped arrays have not
+ * been reclaimed by the garbage collector. The programmer cannot control this
+ * with precision, though hinting using <em>{@link java.lang.System#gc}</em>
+ * often helps.
+ */
+public abstract class RepositoryTestCase extends TestCase {
+
+ protected final File trashParent = new File("trash");
+
+ protected File trash;
+
+ protected File trash_git;
+
+ protected static final PersonIdent jauthor;
+
+ protected static final PersonIdent jcommitter;
+
+ static {
+ jauthor = new PersonIdent("J. Author", "jauthor@example.com");
+ jcommitter = new PersonIdent("J. Committer", "jcommitter@example.com");
+ }
+
+ protected boolean packedGitMMAP;
+
+ /**
+ * Configure JGit before setting up test repositories.
+ */
+ protected void configure() {
+ final WindowCacheConfig c = new WindowCacheConfig();
+ c.setPackedGitLimit(128 * WindowCacheConfig.KB);
+ c.setPackedGitWindowSize(8 * WindowCacheConfig.KB);
+ c.setPackedGitMMAP("true".equals(System.getProperty("jgit.junit.usemmap")));
+ c.setDeltaBaseCacheLimit(8 * WindowCacheConfig.KB);
+ WindowCache.reconfigure(c);
+ }
+
+ /**
+ * Utility method to delete a directory recursively. It is
+ * also used internally. If a file or directory cannot be removed
+ * it throws an AssertionFailure.
+ *
+ * @param dir
+ */
+ protected void recursiveDelete(final File dir) {
+ recursiveDelete(dir, false, getClass().getName() + "." + getName(), true);
+ }
+
+ protected static boolean recursiveDelete(final File dir, boolean silent,
+ final String name, boolean failOnError) {
+ assert !(silent && failOnError);
+ if (!dir.exists())
+ return silent;
+ final File[] ls = dir.listFiles();
+ if (ls != null) {
+ for (int k = 0; k < ls.length; k++) {
+ final File e = ls[k];
+ if (e.isDirectory()) {
+ silent = recursiveDelete(e, silent, name, failOnError);
+ } else {
+ if (!e.delete()) {
+ if (!silent) {
+ reportDeleteFailure(name, failOnError, e);
+ }
+ silent = !failOnError;
+ }
+ }
+ }
+ }
+ if (!dir.delete()) {
+ if (!silent) {
+ reportDeleteFailure(name, failOnError, dir);
+ }
+ silent = !failOnError;
+ }
+ return silent;
+ }
+
+ private static void reportDeleteFailure(final String name,
+ boolean failOnError, final File e) {
+ String severity;
+ if (failOnError)
+ severity = "Error";
+ else
+ severity = "Warning";
+ String msg = severity + ": Failed to delete " + e;
+ if (name != null)
+ msg += " in " + name;
+ if (failOnError)
+ fail(msg);
+ else
+ System.out.println(msg);
+ }
+
+ protected static void copyFile(final File src, final File dst)
+ throws IOException {
+ final FileInputStream fis = new FileInputStream(src);
+ try {
+ final FileOutputStream fos = new FileOutputStream(dst);
+ try {
+ final byte[] buf = new byte[4096];
+ int r;
+ while ((r = fis.read(buf)) > 0) {
+ fos.write(buf, 0, r);
+ }
+ } finally {
+ fos.close();
+ }
+ } finally {
+ fis.close();
+ }
+ }
+
+ protected File writeTrashFile(final String name, final String data)
+ throws IOException {
+ File tf = new File(trash, name);
+ File tfp = tf.getParentFile();
+ if (!tfp.exists() && !tf.getParentFile().mkdirs())
+ throw new Error("Could not create directory " + tf.getParentFile());
+ final OutputStreamWriter fw = new OutputStreamWriter(
+ new FileOutputStream(tf), "UTF-8");
+ try {
+ fw.write(data);
+ } finally {
+ fw.close();
+ }
+ return tf;
+ }
+
+ protected static void checkFile(File f, final String checkData)
+ throws IOException {
+ Reader r = new InputStreamReader(new FileInputStream(f), "ISO-8859-1");
+ try {
+ char[] data = new char[(int) f.length()];
+ if (f.length() != r.read(data))
+ throw new IOException("Internal error reading file data from "+f);
+ assertEquals(checkData, new String(data));
+ } finally {
+ r.close();
+ }
+ }
+
+ protected Repository db;
+
+ private static Thread shutdownhook;
+ private static List<Runnable> shutDownCleanups = new ArrayList<Runnable>();
+ private static int testcount;
+
+ private ArrayList<Repository> repositoriesToClose = new ArrayList<Repository>();
+
+ public void setUp() throws Exception {
+ super.setUp();
+ configure();
+ final String name = getClass().getName() + "." + getName();
+ recursiveDelete(trashParent, true, name, false); // Cleanup old failed stuff
+ trash = new File(trashParent,"trash"+System.currentTimeMillis()+"."+(testcount++));
+ trash_git = new File(trash, ".git").getCanonicalFile();
+ if (shutdownhook == null) {
+ shutdownhook = new Thread() {
+ @Override
+ public void run() {
+ // This may look superfluous, but is an extra attempt
+ // to clean up. First GC to release as many resources
+ // as possible and then try to clean up one test repo
+ // at a time (to record problems) and finally to drop
+ // the directory containing all test repositories.
+ System.gc();
+ for (Runnable r : shutDownCleanups)
+ r.run();
+ recursiveDelete(trashParent, false, null, false);
+ }
+ };
+ Runtime.getRuntime().addShutdownHook(shutdownhook);
+ }
+
+ final MockSystemReader mockSystemReader = new MockSystemReader();
+ mockSystemReader.userGitConfig = new FileBasedConfig(new File(
+ trash_git, "usergitconfig"));
+ SystemReader.setInstance(mockSystemReader);
+
+ db = new Repository(trash_git);
+ db.create();
+
+ final String[] packs = {
+ "pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f",
+ "pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371",
+ "pack-9fb5b411fe6dfa89cc2e6b89d2bd8e5de02b5745",
+ "pack-546ff360fe3488adb20860ce3436a2d6373d2796",
+ "pack-cbdeda40019ae0e6e789088ea0f51f164f489d14",
+ "pack-e6d07037cbcf13376308a0a995d1fa48f8f76aaa",
+ "pack-3280af9c07ee18a87705ef50b0cc4cd20266cf12"
+ };
+ final File packDir = new File(db.getObjectsDirectory(), "pack");
+ for (int k = 0; k < packs.length; k++) {
+ copyFile(JGitTestUtil.getTestResourceFile(packs[k] + ".pack"), new File(packDir,
+ packs[k] + ".pack"));
+ copyFile(JGitTestUtil.getTestResourceFile(packs[k] + ".idx"), new File(packDir,
+ packs[k] + ".idx"));
+ }
+
+ copyFile(JGitTestUtil.getTestResourceFile("packed-refs"), new File(trash_git,"packed-refs"));
+ }
+
+ protected void tearDown() throws Exception {
+ RepositoryCache.clear();
+ db.close();
+ for (Repository r : repositoriesToClose)
+ r.close();
+
+ // 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 (packedGitMMAP)
+ System.gc();
+
+ final String name = getClass().getName() + "." + getName();
+ recursiveDelete(trash, false, name, true);
+ for (Repository r : repositoriesToClose)
+ recursiveDelete(r.getWorkDir(), false, name, true);
+ repositoriesToClose.clear();
+
+ super.tearDown();
+ }
+
+ /**
+ * Helper for creating extra empty repos
+ *
+ * @return a new empty git repository for testing purposes
+ *
+ * @throws IOException
+ */
+ protected Repository createNewEmptyRepo() throws IOException {
+ return createNewEmptyRepo(false);
+ }
+
+ /**
+ * Helper for creating extra empty repos
+ *
+ * @param bare if true, create a bare repository.
+ * @return a new empty git repository for testing purposes
+ *
+ * @throws IOException
+ */
+ protected Repository createNewEmptyRepo(boolean bare) throws IOException {
+ final File newTestRepo = new File(trashParent, "new"
+ + System.currentTimeMillis() + "." + (testcount++)
+ + (bare ? "" : "/") + ".git").getCanonicalFile();
+ assertFalse(newTestRepo.exists());
+ final Repository newRepo = new Repository(newTestRepo);
+ newRepo.create();
+ final String name = getClass().getName() + "." + getName();
+ shutDownCleanups.add(new Runnable() {
+ public void run() {
+ recursiveDelete(newTestRepo, false, name, false);
+ }
+ });
+ repositoriesToClose.add(newRepo);
+ return newRepo;
+ }
+
+ protected void setupReflog(String logName, byte[] data)
+ throws FileNotFoundException, IOException {
+ File logfile = new File(db.getDirectory(), logName);
+ if (!logfile.getParentFile().mkdirs()
+ && !logfile.getParentFile().isDirectory()) {
+ throw new IOException(
+ "oops, cannot create the directory for the test reflog file"
+ + logfile);
+ }
+ FileOutputStream fileOutputStream = new FileOutputStream(logfile);
+ try {
+ fileOutputStream.write(data);
+ } finally {
+ fileOutputStream.close();
+ }
+ }
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_ObjectId.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_ObjectId.java
new file mode 100644
index 0000000000..03176cb8fd
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_ObjectId.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * Copyright (C) 2008, Jonas Fonseca <fonseca@diku.dk>
+ * Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import junit.framework.TestCase;
+
+public class T0001_ObjectId extends TestCase {
+ public void test001_toString() {
+ final String x = "def4c620bc3713bb1bb26b808ec9312548e73946";
+ final ObjectId oid = ObjectId.fromString(x);
+ assertEquals(x, oid.name());
+ }
+
+ public void test002_toString() {
+ final String x = "ff00eedd003713bb1bb26b808ec9312548e73946";
+ final ObjectId oid = ObjectId.fromString(x);
+ assertEquals(x, oid.name());
+ }
+
+ public void test003_equals() {
+ final String x = "def4c620bc3713bb1bb26b808ec9312548e73946";
+ final ObjectId a = ObjectId.fromString(x);
+ final ObjectId b = ObjectId.fromString(x);
+ assertEquals(a.hashCode(), b.hashCode());
+ assertTrue("a and b are same", a.equals(b));
+ }
+
+ public void test004_isId() {
+ assertTrue("valid id", ObjectId
+ .isId("def4c620bc3713bb1bb26b808ec9312548e73946"));
+ }
+
+ public void test005_notIsId() {
+ assertFalse("bob is not an id", ObjectId.isId("bob"));
+ }
+
+ public void test006_notIsId() {
+ assertFalse("39 digits is not an id", ObjectId
+ .isId("def4c620bc3713bb1bb26b808ec9312548e7394"));
+ }
+
+ public void test007_isId() {
+ assertTrue("uppercase is accepted", ObjectId
+ .isId("Def4c620bc3713bb1bb26b808ec9312548e73946"));
+ }
+
+ public void test008_notIsId() {
+ assertFalse("g is not a valid hex digit", ObjectId
+ .isId("gef4c620bc3713bb1bb26b808ec9312548e73946"));
+ }
+
+ public void test009_toString() {
+ final String x = "ff00eedd003713bb1bb26b808ec9312548e73946";
+ final ObjectId oid = ObjectId.fromString(x);
+ assertEquals(x, ObjectId.toString(oid));
+ }
+
+ public void test010_toString() {
+ final String x = "0000000000000000000000000000000000000000";
+ assertEquals(x, ObjectId.toString(null));
+ }
+
+ public void test011_toString() {
+ final String x = "0123456789ABCDEFabcdef1234567890abcdefAB";
+ final ObjectId oid = ObjectId.fromString(x);
+ assertEquals(x.toLowerCase(), oid.name());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_PersonIdent.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_PersonIdent.java
new file mode 100644
index 0000000000..aaa88c0281
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0001_PersonIdent.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2006-2007, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.util.Date;
+import java.util.TimeZone;
+
+import junit.framework.TestCase;
+
+public class T0001_PersonIdent extends TestCase {
+ public void test001_NewIdent() {
+ final PersonIdent p = new PersonIdent("A U Thor", "author@example.com",
+ new Date(1142878501000L), TimeZone.getTimeZone("EST"));
+ assertEquals("A U Thor", p.getName());
+ assertEquals("author@example.com", p.getEmailAddress());
+ assertEquals(1142878501000L, p.getWhen().getTime());
+ assertEquals("A U Thor <author@example.com> 1142878501 -0500", p
+ .toExternalString());
+ }
+
+ public void test002_ParseIdent() {
+ final String i = "A U Thor <author@example.com> 1142878501 -0500";
+ final PersonIdent p = new PersonIdent(i);
+ assertEquals(i, p.toExternalString());
+ assertEquals("A U Thor", p.getName());
+ assertEquals("author@example.com", p.getEmailAddress());
+ assertEquals(1142878501000L, p.getWhen().getTime());
+ }
+
+ public void test003_ParseIdent() {
+ final String i = "A U Thor <author@example.com> 1142878501 +0230";
+ final PersonIdent p = new PersonIdent(i);
+ assertEquals(i, p.toExternalString());
+ assertEquals("A U Thor", p.getName());
+ assertEquals("author@example.com", p.getEmailAddress());
+ assertEquals(1142878501000L, p.getWhen().getTime());
+ }
+
+ public void test004_ParseIdent() {
+ final String i = "A U Thor<author@example.com> 1142878501 +0230";
+ final PersonIdent p = new PersonIdent(i);
+ assertEquals("A U Thor", p.getName());
+ assertEquals("author@example.com", p.getEmailAddress());
+ assertEquals(1142878501000L, p.getWhen().getTime());
+ }
+
+ public void test005_ParseIdent() {
+ final String i = "A U Thor<author@example.com>1142878501 +0230";
+ final PersonIdent p = new PersonIdent(i);
+ assertEquals("A U Thor", p.getName());
+ assertEquals("author@example.com", p.getEmailAddress());
+ assertEquals(1142878501000L, p.getWhen().getTime());
+ }
+
+ public void test006_ParseIdent() {
+ final String i = "A U Thor <author@example.com>1142878501 +0230";
+ final PersonIdent p = new PersonIdent(i);
+ assertEquals("A U Thor", p.getName());
+ assertEquals("author@example.com", p.getEmailAddress());
+ assertEquals(1142878501000L, p.getWhen().getTime());
+ }
+
+ public void test007_ParseIdent() {
+ final String i = "A U Thor<author@example.com>1142878501 +0230 ";
+ final PersonIdent p = new PersonIdent(i);
+ assertEquals("A U Thor", p.getName());
+ assertEquals("author@example.com", p.getEmailAddress());
+ assertEquals(1142878501000L, p.getWhen().getTime());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0002_Tree.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0002_Tree.java
new file mode 100644
index 0000000000..66c3c75f18
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0002_Tree.java
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.util.ArrayList;
+import java.util.List;
+
+public class T0002_Tree extends RepositoryTestCase {
+ private static final ObjectId SOME_FAKE_ID = ObjectId.fromString(
+ "0123456789abcdef0123456789abcdef01234567");
+
+ private int compareNamesUsingSpecialCompare(String a,String b) throws UnsupportedEncodingException {
+ char lasta = '\0';
+ byte[] abytes;
+ if (a.length() > 0 && a.charAt(a.length()-1) == '/') {
+ lasta = '/';
+ a = a.substring(0, a.length() - 1);
+ }
+ abytes = a.getBytes("ISO-8859-1");
+ char lastb = '\0';
+ byte[] bbytes;
+ if (b.length() > 0 && b.charAt(b.length()-1) == '/') {
+ lastb = '/';
+ b = b.substring(0, b.length() - 1);
+ }
+ bbytes = b.getBytes("ISO-8859-1");
+ return Tree.compareNames(abytes, bbytes, lasta, lastb);
+ }
+
+ public void test000_sort_01() throws UnsupportedEncodingException {
+ assertEquals(0, compareNamesUsingSpecialCompare("a","a"));
+ }
+ public void test000_sort_02() throws UnsupportedEncodingException {
+ assertEquals(-1, compareNamesUsingSpecialCompare("a","b"));
+ assertEquals(1, compareNamesUsingSpecialCompare("b","a"));
+ }
+ public void test000_sort_03() throws UnsupportedEncodingException {
+ assertEquals(1, compareNamesUsingSpecialCompare("a:","a"));
+ assertEquals(1, compareNamesUsingSpecialCompare("a/","a"));
+ assertEquals(-1, compareNamesUsingSpecialCompare("a","a/"));
+ assertEquals(-1, compareNamesUsingSpecialCompare("a","a:"));
+ assertEquals(1, compareNamesUsingSpecialCompare("a:","a/"));
+ assertEquals(-1, compareNamesUsingSpecialCompare("a/","a:"));
+ }
+ public void test000_sort_04() throws UnsupportedEncodingException {
+ assertEquals(-1, compareNamesUsingSpecialCompare("a.a","a/a"));
+ assertEquals(1, compareNamesUsingSpecialCompare("a/a","a.a"));
+ }
+ public void test000_sort_05() throws UnsupportedEncodingException {
+ assertEquals(-1, compareNamesUsingSpecialCompare("a.","a/"));
+ assertEquals(1, compareNamesUsingSpecialCompare("a/","a."));
+
+ }
+
+ public void test001_createEmpty() throws IOException {
+ final Tree t = new Tree(db);
+ assertTrue("isLoaded", t.isLoaded());
+ assertTrue("isModified", t.isModified());
+ assertTrue("no parent", t.getParent() == null);
+ assertTrue("isRoot", t.isRoot());
+ assertTrue("no name", t.getName() == null);
+ assertTrue("no nameUTF8", t.getNameUTF8() == null);
+ assertTrue("has entries array", t.members() != null);
+ assertTrue("entries is empty", t.members().length == 0);
+ assertEquals("full name is empty", "", t.getFullName());
+ assertTrue("no id", t.getId() == null);
+ assertTrue("tree is self", t.getTree() == t);
+ assertTrue("database is r", t.getRepository() == db);
+ assertTrue("no foo child", t.findTreeMember("foo") == null);
+ assertTrue("no foo child", t.findBlobMember("foo") == null);
+ }
+
+ public void test002_addFile() throws IOException {
+ final Tree t = new Tree(db);
+ t.setId(SOME_FAKE_ID);
+ assertTrue("has id", t.getId() != null);
+ assertFalse("not modified", t.isModified());
+
+ final String n = "bob";
+ final FileTreeEntry f = t.addFile(n);
+ assertNotNull("have file", f);
+ assertEquals("name matches", n, f.getName());
+ assertEquals("name matches", f.getName(), new String(f.getNameUTF8(),
+ "UTF-8"));
+ assertEquals("full name matches", n, f.getFullName());
+ assertTrue("no id", f.getId() == null);
+ assertTrue("is modified", t.isModified());
+ assertTrue("has no id", t.getId() == null);
+ assertTrue("found bob", t.findBlobMember(f.getName()) == f);
+
+ final TreeEntry[] i = t.members();
+ assertNotNull("members array not null", i);
+ assertTrue("iterator is not empty", i != null && i.length > 0);
+ assertTrue("iterator returns file", i != null && i[0] == f);
+ assertTrue("iterator is empty", i != null && i.length == 1);
+ }
+
+ public void test004_addTree() throws IOException {
+ final Tree t = new Tree(db);
+ t.setId(SOME_FAKE_ID);
+ assertTrue("has id", t.getId() != null);
+ assertFalse("not modified", t.isModified());
+
+ final String n = "bob";
+ final Tree f = t.addTree(n);
+ assertNotNull("have tree", f);
+ assertEquals("name matches", n, f.getName());
+ assertEquals("name matches", f.getName(), new String(f.getNameUTF8(),
+ "UTF-8"));
+ assertEquals("full name matches", n, f.getFullName());
+ assertTrue("no id", f.getId() == null);
+ assertTrue("parent matches", f.getParent() == t);
+ assertTrue("repository matches", f.getRepository() == db);
+ assertTrue("isLoaded", f.isLoaded());
+ assertFalse("has items", f.members().length > 0);
+ assertFalse("is root", f.isRoot());
+ assertTrue("tree is self", f.getTree() == f);
+ assertTrue("parent is modified", t.isModified());
+ assertTrue("parent has no id", t.getId() == null);
+ assertTrue("found bob child", t.findTreeMember(f.getName()) == f);
+
+ final TreeEntry[] i = t.members();
+ assertTrue("iterator is not empty", i.length > 0);
+ assertTrue("iterator returns file", i[0] == f);
+ assertTrue("iterator is empty", i.length == 1);
+ }
+
+ public void test005_addRecursiveFile() throws IOException {
+ final Tree t = new Tree(db);
+ final FileTreeEntry f = t.addFile("a/b/c");
+ assertNotNull("created f", f);
+ assertEquals("c", f.getName());
+ assertEquals("b", f.getParent().getName());
+ assertEquals("a", f.getParent().getParent().getName());
+ assertTrue("t is great-grandparent", t == f.getParent().getParent()
+ .getParent());
+ }
+
+ public void test005_addRecursiveTree() throws IOException {
+ final Tree t = new Tree(db);
+ final Tree f = t.addTree("a/b/c");
+ assertNotNull("created f", f);
+ assertEquals("c", f.getName());
+ assertEquals("b", f.getParent().getName());
+ assertEquals("a", f.getParent().getParent().getName());
+ assertTrue("t is great-grandparent", t == f.getParent().getParent()
+ .getParent());
+ }
+
+ public void test006_addDeepTree() throws IOException {
+ final Tree t = new Tree(db);
+
+ final Tree e = t.addTree("e");
+ assertNotNull("have e", e);
+ assertTrue("e.parent == t", e.getParent() == t);
+ final Tree f = t.addTree("f");
+ assertNotNull("have f", f);
+ assertTrue("f.parent == t", f.getParent() == t);
+ final Tree g = f.addTree("g");
+ assertNotNull("have g", g);
+ assertTrue("g.parent == f", g.getParent() == f);
+ final Tree h = g.addTree("h");
+ assertNotNull("have h", h);
+ assertTrue("h.parent = g", h.getParent() == g);
+
+ h.setId(SOME_FAKE_ID);
+ assertTrue("h not modified", !h.isModified());
+ g.setId(SOME_FAKE_ID);
+ assertTrue("g not modified", !g.isModified());
+ f.setId(SOME_FAKE_ID);
+ assertTrue("f not modified", !f.isModified());
+ e.setId(SOME_FAKE_ID);
+ assertTrue("e not modified", !e.isModified());
+ t.setId(SOME_FAKE_ID);
+ assertTrue("t not modified.", !t.isModified());
+
+ assertEquals("full path of h ok", "f/g/h", h.getFullName());
+ assertTrue("Can find h", t.findTreeMember(h.getFullName()) == h);
+ assertTrue("Can't find f/z", t.findBlobMember("f/z") == null);
+ assertTrue("Can't find y/z", t.findBlobMember("y/z") == null);
+
+ final FileTreeEntry i = h.addFile("i");
+ assertNotNull(i);
+ assertEquals("full path of i ok", "f/g/h/i", i.getFullName());
+ assertTrue("Can find i", t.findBlobMember(i.getFullName()) == i);
+ assertTrue("h modified", h.isModified());
+ assertTrue("g modified", g.isModified());
+ assertTrue("f modified", f.isModified());
+ assertTrue("e not modified", !e.isModified());
+ assertTrue("t modified", t.isModified());
+
+ assertTrue("h no id", h.getId() == null);
+ assertTrue("g no id", g.getId() == null);
+ assertTrue("f no id", f.getId() == null);
+ assertTrue("e has id", e.getId() != null);
+ assertTrue("t no id", t.getId() == null);
+ }
+
+ public void test007_manyFileLookup() throws IOException {
+ final Tree t = new Tree(db);
+ final List<FileTreeEntry> files = new ArrayList<FileTreeEntry>(26 * 26);
+ for (char level1 = 'a'; level1 <= 'z'; level1++) {
+ for (char level2 = 'a'; level2 <= 'z'; level2++) {
+ final String n = "." + level1 + level2 + "9";
+ final FileTreeEntry f = t.addFile(n);
+ assertNotNull("File " + n + " added.", f);
+ assertEquals(n, f.getName());
+ files.add(f);
+ }
+ }
+ assertEquals(files.size(), t.memberCount());
+ final TreeEntry[] ents = t.members();
+ assertNotNull(ents);
+ assertEquals(files.size(), ents.length);
+ for (int k = 0; k < ents.length; k++) {
+ assertTrue("File " + files.get(k).getName()
+ + " is at " + k + ".", files.get(k) == ents[k]);
+ }
+ }
+
+ public void test008_SubtreeInternalSorting() throws IOException {
+ final Tree t = new Tree(db);
+ final FileTreeEntry e0 = t.addFile("a-b");
+ final FileTreeEntry e1 = t.addFile("a-");
+ final FileTreeEntry e2 = t.addFile("a=b");
+ final Tree e3 = t.addTree("a");
+ final FileTreeEntry e4 = t.addFile("a=");
+
+ final TreeEntry[] ents = t.members();
+ assertSame(e1, ents[0]);
+ assertSame(e0, ents[1]);
+ assertSame(e3, ents[2]);
+ assertSame(e4, ents[3]);
+ assertSame(e2, ents[4]);
+ }
+
+ public void test009_SymlinkAndGitlink() throws IOException {
+ final Tree symlinkTree = db.mapTree("symlink");
+ assertTrue("Symlink entry exists", symlinkTree.existsBlob("symlink.txt"));
+ final Tree gitlinkTree = db.mapTree("gitlink");
+ assertTrue("Gitlink entry exists", gitlinkTree.existsBlob("submodule"));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0003_Basic.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0003_Basic.java
new file mode 100644
index 0000000000..d17cea6aec
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0003_Basic.java
@@ -0,0 +1,581 @@
+/*
+ * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
+ * Copyright (C) 2007-2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import org.eclipse.jgit.errors.ConfigInvalidException;
+
+public class T0003_Basic extends RepositoryTestCase {
+ public void test001_Initalize() {
+ final File gitdir = new File(trash, ".git");
+ final File objects = new File(gitdir, "objects");
+ final File objects_pack = new File(objects, "pack");
+ final File objects_info = new File(objects, "info");
+ final File refs = new File(gitdir, "refs");
+ final File refs_heads = new File(refs, "heads");
+ final File refs_tags = new File(refs, "tags");
+ final File HEAD = new File(gitdir, "HEAD");
+
+ assertTrue("Exists " + trash, trash.isDirectory());
+ assertTrue("Exists " + objects, objects.isDirectory());
+ assertTrue("Exists " + objects_pack, objects_pack.isDirectory());
+ assertTrue("Exists " + objects_info, objects_info.isDirectory());
+ assertEquals(2, objects.listFiles().length);
+ assertTrue("Exists " + refs, refs.isDirectory());
+ assertTrue("Exists " + refs_heads, refs_heads.isDirectory());
+ assertTrue("Exists " + refs_tags, refs_tags.isDirectory());
+ assertTrue("Exists " + HEAD, HEAD.isFile());
+ assertEquals(23, HEAD.length());
+ }
+
+ public void test002_WriteEmptyTree() throws IOException {
+ // One of our test packs contains the empty tree object. If the pack is
+ // open when we create it we won't write the object file out as a loose
+ // object (as it already exists in the pack).
+ //
+ final Repository newdb = createNewEmptyRepo();
+ final Tree t = new Tree(newdb);
+ t.accept(new WriteTree(trash, newdb), TreeEntry.MODIFIED_ONLY);
+ assertEquals("4b825dc642cb6eb9a060e54bf8d69288fbee4904", t.getId()
+ .name());
+ final File o = new File(new File(new File(newdb.getDirectory(),
+ "objects"), "4b"), "825dc642cb6eb9a060e54bf8d69288fbee4904");
+ assertTrue("Exists " + o, o.isFile());
+ assertTrue("Read-only " + o, !o.canWrite());
+ }
+
+ public void test002_WriteEmptyTree2() throws IOException {
+ // File shouldn't exist as it is in a test pack.
+ //
+ final Tree t = new Tree(db);
+ t.accept(new WriteTree(trash, db), TreeEntry.MODIFIED_ONLY);
+ assertEquals("4b825dc642cb6eb9a060e54bf8d69288fbee4904", t.getId()
+ .name());
+ final File o = new File(new File(new File(trash_git, "objects"), "4b"),
+ "825dc642cb6eb9a060e54bf8d69288fbee4904");
+ assertFalse("Exists " + o, o.isFile());
+ }
+
+ public void test003_WriteShouldBeEmptyTree() throws IOException {
+ final Tree t = new Tree(db);
+ final ObjectId emptyId = new ObjectWriter(db).writeBlob(new byte[0]);
+ t.addFile("should-be-empty").setId(emptyId);
+ t.accept(new WriteTree(trash, db), TreeEntry.MODIFIED_ONLY);
+ assertEquals("7bb943559a305bdd6bdee2cef6e5df2413c3d30a", t.getId()
+ .name());
+
+ File o;
+ o = new File(new File(new File(trash_git, "objects"), "7b"),
+ "b943559a305bdd6bdee2cef6e5df2413c3d30a");
+ assertTrue("Exists " + o, o.isFile());
+ assertTrue("Read-only " + o, !o.canWrite());
+
+ o = new File(new File(new File(trash_git, "objects"), "e6"),
+ "9de29bb2d1d6434b8b29ae775ad8c2e48c5391");
+ assertTrue("Exists " + o, o.isFile());
+ assertTrue("Read-only " + o, !o.canWrite());
+ }
+
+ public void test004_CheckNewConfig() {
+ final RepositoryConfig c = db.getConfig();
+ assertNotNull(c);
+ assertEquals("0", c.getString("core", null, "repositoryformatversion"));
+ assertEquals("0", c.getString("CoRe", null, "REPOSITORYFoRmAtVeRsIoN"));
+ assertEquals("true", c.getString("core", null, "filemode"));
+ assertEquals("true", c.getString("cOrE", null, "fIlEModE"));
+ assertNull(c.getString("notavalue", null, "reallyNotAValue"));
+ }
+
+ public void test005_ReadSimpleConfig() {
+ final RepositoryConfig c = db.getConfig();
+ assertNotNull(c);
+ assertEquals("0", c.getString("core", null, "repositoryformatversion"));
+ assertEquals("0", c.getString("CoRe", null, "REPOSITORYFoRmAtVeRsIoN"));
+ assertEquals("true", c.getString("core", null, "filemode"));
+ assertEquals("true", c.getString("cOrE", null, "fIlEModE"));
+ assertNull(c.getString("notavalue", null, "reallyNotAValue"));
+ }
+
+ public void test006_ReadUglyConfig() throws IOException,
+ ConfigInvalidException {
+ final RepositoryConfig c = db.getConfig();
+ final File cfg = new File(db.getDirectory(), "config");
+ final FileWriter pw = new FileWriter(cfg);
+ final String configStr = " [core];comment\n\tfilemode = yes\n"
+ + "[user]\n"
+ + " email = A U Thor <thor@example.com> # Just an example...\n"
+ + " name = \"A Thor \\\\ \\\"\\t \"\n"
+ + " defaultCheckInComment = a many line\\n\\\ncomment\\n\\\n"
+ + " to test\n";
+ pw.write(configStr);
+ pw.close();
+ c.load();
+ assertEquals("yes", c.getString("core", null, "filemode"));
+ assertEquals("A U Thor <thor@example.com>", c
+ .getString("user", null, "email"));
+ assertEquals("A Thor \\ \"\t ", c.getString("user", null, "name"));
+ assertEquals("a many line\ncomment\n to test", c.getString("user",
+ null, "defaultCheckInComment"));
+ c.save();
+ final FileReader fr = new FileReader(cfg);
+ final char[] cbuf = new char[configStr.length()];
+ fr.read(cbuf);
+ fr.close();
+ assertEquals(configStr, new String(cbuf));
+ }
+
+ public void test007_Open() throws IOException {
+ final Repository db2 = new Repository(db.getDirectory());
+ assertEquals(db.getDirectory(), db2.getDirectory());
+ assertEquals(db.getObjectsDirectory(), db2.getObjectsDirectory());
+ assertNotSame(db.getConfig(), db2.getConfig());
+ }
+
+ public void test008_FailOnWrongVersion() throws IOException {
+ final File cfg = new File(db.getDirectory(), "config");
+ final FileWriter pw = new FileWriter(cfg);
+ final String badvers = "ihopethisisneveraversion";
+ final String configStr = "[core]\n" + "\trepositoryFormatVersion="
+ + badvers + "\n";
+ pw.write(configStr);
+ pw.close();
+
+ try {
+ new Repository(db.getDirectory());
+ fail("incorrectly opened a bad repository");
+ } catch (IOException ioe) {
+ assertTrue(ioe.getMessage().indexOf("format") > 0);
+ assertTrue(ioe.getMessage().indexOf(badvers) > 0);
+ }
+ }
+
+ public void test009_CreateCommitOldFormat() throws IOException,
+ ConfigInvalidException {
+ writeTrashFile(".git/config", "[core]\n" + "legacyHeaders=1\n");
+ db.getConfig().load();
+
+ final Tree t = new Tree(db);
+ final FileTreeEntry f = t.addFile("i-am-a-file");
+ writeTrashFile(f.getName(), "and this is the data in me\n");
+ t.accept(new WriteTree(trash, db), TreeEntry.MODIFIED_ONLY);
+ assertEquals(ObjectId.fromString("00b1f73724f493096d1ffa0b0f1f1482dbb8c936"),
+ t.getTreeId());
+
+ final Commit c = new Commit(db);
+ c.setAuthor(new PersonIdent(jauthor, 1154236443000L, -4 * 60));
+ c.setCommitter(new PersonIdent(jcommitter, 1154236443000L, -4 * 60));
+ c.setMessage("A Commit\n");
+ c.setTree(t);
+ assertEquals(t.getTreeId(), c.getTreeId());
+ c.commit();
+ final ObjectId cmtid = ObjectId.fromString(
+ "803aec4aba175e8ab1d666873c984c0308179099");
+ assertEquals(cmtid, c.getCommitId());
+
+ // Verify the commit we just wrote is in the correct format.
+ final XInputStream xis = new XInputStream(new FileInputStream(db
+ .toFile(cmtid)));
+ try {
+ assertEquals(0x78, xis.readUInt8());
+ assertEquals(0x9c, xis.readUInt8());
+ assertTrue(0x789c % 31 == 0);
+ } finally {
+ xis.close();
+ }
+
+ // Verify we can read it.
+ final Commit c2 = db.mapCommit(cmtid);
+ assertNotNull(c2);
+ assertEquals(c.getMessage(), c2.getMessage());
+ assertEquals(c.getTreeId(), c2.getTreeId());
+ assertEquals(c.getAuthor(), c2.getAuthor());
+ assertEquals(c.getCommitter(), c2.getCommitter());
+ }
+
+ public void test012_SubtreeExternalSorting() throws IOException {
+ final ObjectId emptyBlob = new ObjectWriter(db).writeBlob(new byte[0]);
+ final Tree t = new Tree(db);
+ final FileTreeEntry e0 = t.addFile("a-");
+ final FileTreeEntry e1 = t.addFile("a-b");
+ final FileTreeEntry e2 = t.addFile("a/b");
+ final FileTreeEntry e3 = t.addFile("a=");
+ final FileTreeEntry e4 = t.addFile("a=b");
+
+ e0.setId(emptyBlob);
+ e1.setId(emptyBlob);
+ e2.setId(emptyBlob);
+ e3.setId(emptyBlob);
+ e4.setId(emptyBlob);
+
+ t.accept(new WriteTree(trash, db), TreeEntry.MODIFIED_ONLY);
+ assertEquals(ObjectId.fromString("b47a8f0a4190f7572e11212769090523e23eb1ea"),
+ t.getId());
+ }
+
+ public void test020_createBlobTag() throws IOException {
+ final ObjectId emptyId = new ObjectWriter(db).writeBlob(new byte[0]);
+ final Tag t = new Tag(db);
+ t.setObjId(emptyId);
+ t.setType("blob");
+ t.setTag("test020");
+ t.setAuthor(new PersonIdent(jauthor, 1154236443000L, -4 * 60));
+ t.setMessage("test020 tagged\n");
+ t.tag();
+ assertEquals("6759556b09fbb4fd8ae5e315134481cc25d46954", t.getTagId().name());
+
+ Tag mapTag = db.mapTag("test020");
+ assertEquals("blob", mapTag.getType());
+ assertEquals("test020 tagged\n", mapTag.getMessage());
+ assertEquals(new PersonIdent(jauthor, 1154236443000L, -4 * 60), mapTag.getAuthor());
+ assertEquals("e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", mapTag.getObjId().name());
+ }
+
+ public void test020b_createBlobPlainTag() throws IOException {
+ test020_createBlobTag();
+ Tag t = new Tag(db);
+ t.setTag("test020b");
+ t.setObjId(ObjectId.fromString("e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"));
+ t.tag();
+
+ Tag mapTag = db.mapTag("test020b");
+ assertEquals("e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", mapTag.getObjId().name());
+
+ // We do not repeat the plain tag test for other object types
+ }
+
+ public void test021_createTreeTag() throws IOException {
+ final ObjectId emptyId = new ObjectWriter(db).writeBlob(new byte[0]);
+ final Tree almostEmptyTree = new Tree(db);
+ almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId, "empty".getBytes(), false));
+ final ObjectId almostEmptyTreeId = new ObjectWriter(db).writeTree(almostEmptyTree);
+ final Tag t = new Tag(db);
+ t.setObjId(almostEmptyTreeId);
+ t.setType("tree");
+ t.setTag("test021");
+ t.setAuthor(new PersonIdent(jauthor, 1154236443000L, -4 * 60));
+ t.setMessage("test021 tagged\n");
+ t.tag();
+ assertEquals("b0517bc8dbe2096b419d42424cd7030733f4abe5", t.getTagId().name());
+
+ Tag mapTag = db.mapTag("test021");
+ assertEquals("tree", mapTag.getType());
+ assertEquals("test021 tagged\n", mapTag.getMessage());
+ assertEquals(new PersonIdent(jauthor, 1154236443000L, -4 * 60), mapTag.getAuthor());
+ assertEquals("417c01c8795a35b8e835113a85a5c0c1c77f67fb", mapTag.getObjId().name());
+ }
+
+ public void test022_createCommitTag() throws IOException {
+ final ObjectId emptyId = new ObjectWriter(db).writeBlob(new byte[0]);
+ final Tree almostEmptyTree = new Tree(db);
+ almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId, "empty".getBytes(), false));
+ final ObjectId almostEmptyTreeId = new ObjectWriter(db).writeTree(almostEmptyTree);
+ final Commit almostEmptyCommit = new Commit(db);
+ almostEmptyCommit.setAuthor(new PersonIdent(jauthor, 1154236443000L, -2 * 60)); // not exactly the same
+ almostEmptyCommit.setCommitter(new PersonIdent(jauthor, 1154236443000L, -2 * 60));
+ almostEmptyCommit.setMessage("test022\n");
+ almostEmptyCommit.setTreeId(almostEmptyTreeId);
+ ObjectId almostEmptyCommitId = new ObjectWriter(db).writeCommit(almostEmptyCommit);
+ final Tag t = new Tag(db);
+ t.setObjId(almostEmptyCommitId);
+ t.setType("commit");
+ t.setTag("test022");
+ t.setAuthor(new PersonIdent(jauthor, 1154236443000L, -4 * 60));
+ t.setMessage("test022 tagged\n");
+ t.tag();
+ assertEquals("0ce2ebdb36076ef0b38adbe077a07d43b43e3807", t.getTagId().name());
+
+ Tag mapTag = db.mapTag("test022");
+ assertEquals("commit", mapTag.getType());
+ assertEquals("test022 tagged\n", mapTag.getMessage());
+ assertEquals(new PersonIdent(jauthor, 1154236443000L, -4 * 60), mapTag.getAuthor());
+ assertEquals("b5d3b45a96b340441f5abb9080411705c51cc86c", mapTag.getObjId().name());
+ }
+
+ public void test023_createCommitNonAnullii() throws IOException {
+ final ObjectId emptyId = new ObjectWriter(db).writeBlob(new byte[0]);
+ final Tree almostEmptyTree = new Tree(db);
+ almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId, "empty".getBytes(), false));
+ final ObjectId almostEmptyTreeId = new ObjectWriter(db).writeTree(almostEmptyTree);
+ Commit commit = new Commit(db);
+ commit.setTreeId(almostEmptyTreeId);
+ commit.setAuthor(new PersonIdent("Joe H\u00e4cker","joe@example.com",4294967295000L,60));
+ commit.setCommitter(new PersonIdent("Joe Hacker","joe2@example.com",4294967295000L,60));
+ commit.setEncoding("UTF-8");
+ commit.setMessage("\u00dcbergeeks");
+ ObjectId cid = new ObjectWriter(db).writeCommit(commit);
+ assertEquals("4680908112778718f37e686cbebcc912730b3154", cid.name());
+ }
+
+ public void test024_createCommitNonAscii() throws IOException {
+ final ObjectId emptyId = new ObjectWriter(db).writeBlob(new byte[0]);
+ final Tree almostEmptyTree = new Tree(db);
+ almostEmptyTree.addEntry(new FileTreeEntry(almostEmptyTree, emptyId, "empty".getBytes(), false));
+ final ObjectId almostEmptyTreeId = new ObjectWriter(db).writeTree(almostEmptyTree);
+ Commit commit = new Commit(db);
+ commit.setTreeId(almostEmptyTreeId);
+ commit.setAuthor(new PersonIdent("Joe H\u00e4cker","joe@example.com",4294967295000L,60));
+ commit.setCommitter(new PersonIdent("Joe Hacker","joe2@example.com",4294967295000L,60));
+ commit.setEncoding("ISO-8859-1");
+ commit.setMessage("\u00dcbergeeks");
+ ObjectId cid = new ObjectWriter(db).writeCommit(commit);
+ assertEquals("2979b39d385014b33287054b87f77bcb3ecb5ebf", cid.name());
+ }
+
+ public void test025_packedRefs() throws IOException {
+ test020_createBlobTag();
+ test021_createTreeTag();
+ test022_createCommitTag();
+
+ if (!new File(db.getDirectory(),"refs/tags/test020").delete()) throw new Error("Cannot delete unpacked tag");
+ if (!new File(db.getDirectory(),"refs/tags/test021").delete()) throw new Error("Cannot delete unpacked tag");
+ if (!new File(db.getDirectory(),"refs/tags/test022").delete()) throw new Error("Cannot delete unpacked tag");
+
+ // We cannot resolve it now, since we have no ref
+ Tag mapTag20missing = db.mapTag("test020");
+ assertNull(mapTag20missing);
+
+ // Construct packed refs file
+ PrintWriter w = new PrintWriter(new FileWriter(new File(db.getDirectory(), "packed-refs")));
+ w.println("# packed-refs with: peeled");
+ w.println("6759556b09fbb4fd8ae5e315134481cc25d46954 refs/tags/test020");
+ w.println("^e69de29bb2d1d6434b8b29ae775ad8c2e48c5391");
+ w.println("b0517bc8dbe2096b419d42424cd7030733f4abe5 refs/tags/test021");
+ w.println("^417c01c8795a35b8e835113a85a5c0c1c77f67fb");
+ w.println("0ce2ebdb36076ef0b38adbe077a07d43b43e3807 refs/tags/test022");
+ w.println("^b5d3b45a96b340441f5abb9080411705c51cc86c");
+ w.close();
+
+ Tag mapTag20 = db.mapTag("test020");
+ assertNotNull("have tag test020", mapTag20);
+ assertEquals("blob", mapTag20.getType());
+ assertEquals("test020 tagged\n", mapTag20.getMessage());
+ assertEquals(new PersonIdent(jauthor, 1154236443000L, -4 * 60), mapTag20.getAuthor());
+ assertEquals("e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", mapTag20.getObjId().name());
+
+ Tag mapTag21 = db.mapTag("test021");
+ assertEquals("tree", mapTag21.getType());
+ assertEquals("test021 tagged\n", mapTag21.getMessage());
+ assertEquals(new PersonIdent(jauthor, 1154236443000L, -4 * 60), mapTag21.getAuthor());
+ assertEquals("417c01c8795a35b8e835113a85a5c0c1c77f67fb", mapTag21.getObjId().name());
+
+ Tag mapTag22 = db.mapTag("test022");
+ assertEquals("commit", mapTag22.getType());
+ assertEquals("test022 tagged\n", mapTag22.getMessage());
+ assertEquals(new PersonIdent(jauthor, 1154236443000L, -4 * 60), mapTag22.getAuthor());
+ assertEquals("b5d3b45a96b340441f5abb9080411705c51cc86c", mapTag22.getObjId().name());
+ }
+
+ public void test025_computeSha1NoStore() throws IOException {
+ byte[] data = "test025 some data, more than 16 bytes to get good coverage"
+ .getBytes("ISO-8859-1");
+ // TODO: but we do not test legacy header writing
+ final ObjectId id = new ObjectWriter(db).computeBlobSha1(data.length,
+ new ByteArrayInputStream(data));
+ assertEquals("4f561df5ecf0dfbd53a0dc0f37262fef075d9dde", id.name());
+ }
+
+ public void test026_CreateCommitMultipleparents() throws IOException {
+ final Tree t = new Tree(db);
+ final FileTreeEntry f = t.addFile("i-am-a-file");
+ writeTrashFile(f.getName(), "and this is the data in me\n");
+ t.accept(new WriteTree(trash, db), TreeEntry.MODIFIED_ONLY);
+ assertEquals(ObjectId.fromString("00b1f73724f493096d1ffa0b0f1f1482dbb8c936"),
+ t.getTreeId());
+
+ final Commit c1 = new Commit(db);
+ c1.setAuthor(new PersonIdent(jauthor, 1154236443000L, -4 * 60));
+ c1.setCommitter(new PersonIdent(jcommitter, 1154236443000L, -4 * 60));
+ c1.setMessage("A Commit\n");
+ c1.setTree(t);
+ assertEquals(t.getTreeId(), c1.getTreeId());
+ c1.commit();
+ final ObjectId cmtid1 = ObjectId.fromString(
+ "803aec4aba175e8ab1d666873c984c0308179099");
+ assertEquals(cmtid1, c1.getCommitId());
+
+ final Commit c2 = new Commit(db);
+ c2.setAuthor(new PersonIdent(jauthor, 1154236443000L, -4 * 60));
+ c2.setCommitter(new PersonIdent(jcommitter, 1154236443000L, -4 * 60));
+ c2.setMessage("A Commit 2\n");
+ c2.setTree(t);
+ assertEquals(t.getTreeId(), c2.getTreeId());
+ c2.setParentIds(new ObjectId[] { c1.getCommitId() } );
+ c2.commit();
+ final ObjectId cmtid2 = ObjectId.fromString(
+ "95d068687c91c5c044fb8c77c5154d5247901553");
+ assertEquals(cmtid2, c2.getCommitId());
+
+ Commit rm2 = db.mapCommit(cmtid2);
+ assertNotSame(c2, rm2); // assert the parsed objects is not from the cache
+ assertEquals(c2.getAuthor(), rm2.getAuthor());
+ assertEquals(c2.getCommitId(), rm2.getCommitId());
+ assertEquals(c2.getMessage(), rm2.getMessage());
+ assertEquals(c2.getTree().getTreeId(), rm2.getTree().getTreeId());
+ assertEquals(1, rm2.getParentIds().length);
+ assertEquals(c1.getCommitId(), rm2.getParentIds()[0]);
+
+ final Commit c3 = new Commit(db);
+ c3.setAuthor(new PersonIdent(jauthor, 1154236443000L, -4 * 60));
+ c3.setCommitter(new PersonIdent(jcommitter, 1154236443000L, -4 * 60));
+ c3.setMessage("A Commit 3\n");
+ c3.setTree(t);
+ assertEquals(t.getTreeId(), c3.getTreeId());
+ c3.setParentIds(new ObjectId[] { c1.getCommitId(), c2.getCommitId() });
+ c3.commit();
+ final ObjectId cmtid3 = ObjectId.fromString(
+ "ce6e1ce48fbeeb15a83f628dc8dc2debefa066f4");
+ assertEquals(cmtid3, c3.getCommitId());
+
+ Commit rm3 = db.mapCommit(cmtid3);
+ assertNotSame(c3, rm3); // assert the parsed objects is not from the cache
+ assertEquals(c3.getAuthor(), rm3.getAuthor());
+ assertEquals(c3.getCommitId(), rm3.getCommitId());
+ assertEquals(c3.getMessage(), rm3.getMessage());
+ assertEquals(c3.getTree().getTreeId(), rm3.getTree().getTreeId());
+ assertEquals(2, rm3.getParentIds().length);
+ assertEquals(c1.getCommitId(), rm3.getParentIds()[0]);
+ assertEquals(c2.getCommitId(), rm3.getParentIds()[1]);
+
+ final Commit c4 = new Commit(db);
+ c4.setAuthor(new PersonIdent(jauthor, 1154236443000L, -4 * 60));
+ c4.setCommitter(new PersonIdent(jcommitter, 1154236443000L, -4 * 60));
+ c4.setMessage("A Commit 4\n");
+ c4.setTree(t);
+ assertEquals(t.getTreeId(), c3.getTreeId());
+ c4.setParentIds(new ObjectId[] { c1.getCommitId(), c2.getCommitId(), c3.getCommitId() });
+ c4.commit();
+ final ObjectId cmtid4 = ObjectId.fromString(
+ "d1fca9fe3fef54e5212eb67902c8ed3e79736e27");
+ assertEquals(cmtid4, c4.getCommitId());
+
+ Commit rm4 = db.mapCommit(cmtid4);
+ assertNotSame(c4, rm3); // assert the parsed objects is not from the cache
+ assertEquals(c4.getAuthor(), rm4.getAuthor());
+ assertEquals(c4.getCommitId(), rm4.getCommitId());
+ assertEquals(c4.getMessage(), rm4.getMessage());
+ assertEquals(c4.getTree().getTreeId(), rm4.getTree().getTreeId());
+ assertEquals(3, rm4.getParentIds().length);
+ assertEquals(c1.getCommitId(), rm4.getParentIds()[0]);
+ assertEquals(c2.getCommitId(), rm4.getParentIds()[1]);
+ assertEquals(c3.getCommitId(), rm4.getParentIds()[2]);
+ }
+
+ public void test027_UnpackedRefHigherPriorityThanPacked() throws IOException {
+ PrintWriter writer = new PrintWriter(new FileWriter(new File(db.getDirectory(), "refs/heads/a")));
+ String unpackedId = "7f822839a2fe9760f386cbbbcb3f92c5fe81def7";
+ writer.print(unpackedId);
+ writer.print('\n');
+ writer.close();
+
+ ObjectId resolved = db.resolve("refs/heads/a");
+ assertEquals(unpackedId, resolved.name());
+ }
+
+ public void test028_LockPackedRef() throws IOException {
+ writeTrashFile(".git/packed-refs", "7f822839a2fe9760f386cbbbcb3f92c5fe81def7 refs/heads/foobar");
+ writeTrashFile(".git/HEAD", "ref: refs/heads/foobar\n");
+
+ ObjectId resolve = db.resolve("HEAD");
+ assertEquals("7f822839a2fe9760f386cbbbcb3f92c5fe81def7", resolve.name());
+
+ RefUpdate lockRef = db.updateRef("HEAD");
+ ObjectId newId = ObjectId.fromString("07f822839a2fe9760f386cbbbcb3f92c5fe81def");
+ lockRef.setNewObjectId(newId);
+ assertEquals(RefUpdate.Result.FORCED, lockRef.forceUpdate());
+
+ assertTrue(new File(db.getDirectory(), "refs/heads/foobar").exists());
+ assertEquals(newId, db.resolve("refs/heads/foobar"));
+
+ // Again. The ref already exists
+ RefUpdate lockRef2 = db.updateRef("HEAD");
+ ObjectId newId2 = ObjectId.fromString("7f822839a2fe9760f386cbbbcb3f92c5fe81def7");
+ lockRef2.setNewObjectId(newId2);
+ assertEquals(RefUpdate.Result.FORCED, lockRef2.forceUpdate());
+
+ assertTrue(new File(db.getDirectory(), "refs/heads/foobar").exists());
+ assertEquals(newId2, db.resolve("refs/heads/foobar"));
+ }
+
+ public void test029_mapObject() throws IOException {
+ assertEquals(new byte[0].getClass(), db.mapObject(ObjectId.fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259"), null).getClass());
+ assertEquals(Commit.class, db.mapObject(ObjectId.fromString("540a36d136cf413e4b064c2b0e0a4db60f77feab"), null).getClass());
+ assertEquals(Tree.class, db.mapObject(ObjectId.fromString("aabf2ffaec9b497f0950352b3e582d73035c2035"), null).getClass());
+ assertEquals(Tag.class, db.mapObject(ObjectId.fromString("17768080a2318cd89bba4c8b87834401e2095703"), null).getClass());
+ }
+
+ public void test30_stripWorkDir() {
+ File relCwd = new File(".");
+ File absCwd = relCwd.getAbsoluteFile();
+ File absBase = new File(new File(absCwd, "repo"), "workdir");
+ File relBase = new File(new File(relCwd, "repo"), "workdir");
+ assertEquals(absBase.getAbsolutePath(), relBase.getAbsolutePath());
+
+ File relBaseFile = new File(new File(relBase, "other"), "module.c");
+ File absBaseFile = new File(new File(absBase, "other"), "module.c");
+ assertEquals("other/module.c", Repository.stripWorkDir(relBase, relBaseFile));
+ assertEquals("other/module.c", Repository.stripWorkDir(relBase, absBaseFile));
+ assertEquals("other/module.c", Repository.stripWorkDir(absBase, relBaseFile));
+ assertEquals("other/module.c", Repository.stripWorkDir(absBase, absBaseFile));
+
+ File relNonFile = new File(new File(relCwd, "not-repo"), ".gitignore");
+ File absNonFile = new File(new File(absCwd, "not-repo"), ".gitignore");
+ assertEquals("", Repository.stripWorkDir(relBase, relNonFile));
+ assertEquals("", Repository.stripWorkDir(absBase, absNonFile));
+
+ assertEquals("", Repository.stripWorkDir(db.getWorkDir(), db.getWorkDir()));
+
+ File file = new File(new File(db.getWorkDir(), "subdir"), "File.java");
+ assertEquals("subdir/File.java", Repository.stripWorkDir(db.getWorkDir(), file));
+
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0004_PackReader.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0004_PackReader.java
new file mode 100644
index 0000000000..adddbfe099
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0004_PackReader.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2008-2009, Google Inc.
+ * Copyright (C) 2008, Imran M Yousuf <imyousuf@smartitengineering.com>
+ * Copyright (C) 2007, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.File;
+import java.io.IOException;
+
+import org.eclipse.jgit.util.JGitTestUtil;
+
+public class T0004_PackReader extends RepositoryTestCase {
+ private static final String PACK_NAME = "pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f";
+ private static final File TEST_PACK = JGitTestUtil.getTestResourceFile(PACK_NAME + ".pack");
+ private static final File TEST_IDX = JGitTestUtil.getTestResourceFile(PACK_NAME + ".idx");
+
+ public void test003_lookupCompressedObject() throws IOException {
+ final PackFile pr;
+ final ObjectId id;
+ final PackedObjectLoader or;
+
+ id = ObjectId.fromString("902d5476fa249b7abc9d84c611577a81381f0327");
+ pr = new PackFile(TEST_IDX, TEST_PACK);
+ or = pr.get(new WindowCursor(), id);
+ assertNotNull(or);
+ assertEquals(Constants.OBJ_TREE, or.getType());
+ assertEquals(35, or.getSize());
+ assertEquals(7738, or.getDataOffset());
+ pr.close();
+ }
+
+ public void test004_lookupDeltifiedObject() throws IOException {
+ final ObjectId id;
+ final ObjectLoader or;
+
+ id = ObjectId.fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259");
+ or = db.openObject(id);
+ assertNotNull(or);
+ assertTrue(or instanceof PackedObjectLoader);
+ assertEquals(Constants.OBJ_BLOB, or.getType());
+ assertEquals(18009, or.getSize());
+ assertEquals(537, ((PackedObjectLoader) or).getDataOffset());
+ }
+
+ public void test005_todopack() throws IOException {
+ final File todopack = JGitTestUtil.getTestResourceFile("todopack");
+ if (!todopack.isDirectory()) {
+ System.err.println("Skipping " + getName() + ": no " + todopack);
+ return;
+ }
+
+ final File packDir = new File(db.getObjectsDirectory(), "pack");
+ final String packname = "pack-2e71952edc41f3ce7921c5e5dd1b64f48204cf35";
+ copyFile(new File(todopack, packname + ".pack"), new File(packDir,
+ packname + ".pack"));
+ copyFile(new File(todopack, packname + ".idx"), new File(packDir,
+ packname + ".idx"));
+ Tree t;
+
+ t = db
+ .mapTree(ObjectId.fromString(
+ "aac9df07f653dd18b935298deb813e02c32d2e6f"));
+ assertNotNull(t);
+ t.memberCount();
+
+ t = db
+ .mapTree(ObjectId.fromString(
+ "6b9ffbebe7b83ac6a61c9477ab941d999f5d0c96"));
+ assertNotNull(t);
+ t.memberCount();
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0007_Index.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0007_Index.java
new file mode 100644
index 0000000000..74e4bfbdea
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0007_Index.java
@@ -0,0 +1,455 @@
+/*
+ * Copyright (C) 2007-2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import org.eclipse.jgit.lib.GitIndex.Entry;
+import org.eclipse.jgit.util.FS;
+
+public class T0007_Index extends RepositoryTestCase {
+
+ static boolean canrungitstatus;
+ static {
+ try {
+ canrungitstatus = system(new File("."),"git --version") == 0;
+ } catch (IOException e) {
+ System.out.println("Warning: cannot invoke native git to validate index");
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+
+ private static int system(File dir, String cmd) throws IOException,
+ InterruptedException {
+ final Process process = Runtime.getRuntime().exec(cmd, null, dir);
+ new Thread() {
+ public void run() {
+ try {
+ InputStream s = process.getErrorStream();
+ for (int c = s.read(); c != -1; c = s.read()) {
+ System.err.print((char) c);
+ }
+ s.close();
+ } catch (IOException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+ }
+ }.start();
+ final Thread t2 = new Thread() {
+ public void run() {
+ synchronized (this) {
+ try {
+ InputStream e = process.getInputStream();
+ for (int c = e.read(); c != -1; c = e.read()) {
+ System.out.print((char) c);
+ }
+ e.close();
+ } catch (IOException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+ }
+ }
+ };
+ t2.start();
+ process.getOutputStream().close();
+ int ret = process.waitFor();
+ synchronized (t2) {
+ return ret;
+ }
+ }
+
+ public void testCreateEmptyIndex() throws Exception {
+ GitIndex index = new GitIndex(db);
+ index.write();
+// native git doesn't like an empty index
+// assertEquals(0,system(trash,"git status"));
+
+ GitIndex indexr = new GitIndex(db);
+ indexr.read();
+ assertEquals(0, indexr.getMembers().length);
+ }
+
+ public void testReadWithNoIndex() throws Exception {
+ GitIndex index = new GitIndex(db);
+ index.read();
+ assertEquals(0, index.getMembers().length);
+ }
+
+ public void testCreateSimpleSortTestIndex() throws Exception {
+ GitIndex index = new GitIndex(db);
+ writeTrashFile("a/b", "data:a/b");
+ writeTrashFile("a:b", "data:a:b");
+ writeTrashFile("a.b", "data:a.b");
+ index.add(trash, new File(trash, "a/b"));
+ index.add(trash, new File(trash, "a:b"));
+ index.add(trash, new File(trash, "a.b"));
+ index.write();
+
+ assertEquals("a/b", index.getEntry("a/b").getName());
+ assertEquals("a:b", index.getEntry("a:b").getName());
+ assertEquals("a.b", index.getEntry("a.b").getName());
+ assertNull(index.getEntry("a*b"));
+
+ // Repeat test for re-read index
+ GitIndex indexr = new GitIndex(db);
+ indexr.read();
+ assertEquals("a/b", indexr.getEntry("a/b").getName());
+ assertEquals("a:b", indexr.getEntry("a:b").getName());
+ assertEquals("a.b", indexr.getEntry("a.b").getName());
+ assertNull(indexr.getEntry("a*b"));
+
+ if (canrungitstatus)
+ assertEquals(0, system(trash, "git status"));
+ }
+
+ public void testUpdateSimpleSortTestIndex() throws Exception {
+ GitIndex index = new GitIndex(db);
+ writeTrashFile("a/b", "data:a/b");
+ writeTrashFile("a:b", "data:a:b");
+ writeTrashFile("a.b", "data:a.b");
+ index.add(trash, new File(trash, "a/b"));
+ index.add(trash, new File(trash, "a:b"));
+ index.add(trash, new File(trash, "a.b"));
+ writeTrashFile("a/b", "data:a/b modified");
+ index.add(trash, new File(trash, "a/b"));
+ index.write();
+ if (canrungitstatus)
+ assertEquals(0, system(trash, "git status"));
+ }
+
+ public void testWriteTree() throws Exception {
+ GitIndex index = new GitIndex(db);
+ writeTrashFile("a/b", "data:a/b");
+ writeTrashFile("a:b", "data:a:b");
+ writeTrashFile("a.b", "data:a.b");
+ index.add(trash, new File(trash, "a/b"));
+ index.add(trash, new File(trash, "a:b"));
+ index.add(trash, new File(trash, "a.b"));
+ index.write();
+
+ ObjectId id = index.writeTree();
+ assertEquals("c696abc3ab8e091c665f49d00eb8919690b3aec3", id.name());
+
+ writeTrashFile("a/b", "data:a/b");
+ index.add(trash, new File(trash, "a/b"));
+
+ if (canrungitstatus)
+ assertEquals(0, system(trash, "git status"));
+ }
+
+ public void testReadTree() throws Exception {
+ // Prepare tree
+ GitIndex index = new GitIndex(db);
+ writeTrashFile("a/b", "data:a/b");
+ writeTrashFile("a:b", "data:a:b");
+ writeTrashFile("a.b", "data:a.b");
+ index.add(trash, new File(trash, "a/b"));
+ index.add(trash, new File(trash, "a:b"));
+ index.add(trash, new File(trash, "a.b"));
+ index.write();
+
+ ObjectId id = index.writeTree();
+ System.out.println("wrote id " + id);
+ assertEquals("c696abc3ab8e091c665f49d00eb8919690b3aec3", id.name());
+ GitIndex index2 = new GitIndex(db);
+
+ index2.readTree(db.mapTree(ObjectId.fromString(
+ "c696abc3ab8e091c665f49d00eb8919690b3aec3")));
+ Entry[] members = index2.getMembers();
+ assertEquals(3, members.length);
+ assertEquals("a.b", members[0].getName());
+ assertEquals("a/b", members[1].getName());
+ assertEquals("a:b", members[2].getName());
+ assertEquals(3, members.length);
+
+ GitIndex indexr = new GitIndex(db);
+ indexr.read();
+ Entry[] membersr = indexr.getMembers();
+ assertEquals(3, membersr.length);
+ assertEquals("a.b", membersr[0].getName());
+ assertEquals("a/b", membersr[1].getName());
+ assertEquals("a:b", membersr[2].getName());
+ assertEquals(3, membersr.length);
+
+ if (canrungitstatus)
+ assertEquals(0, system(trash, "git status"));
+ }
+
+ public void testReadTree2() throws Exception {
+ // Prepare a larger tree to test some odd cases in tree writing
+ GitIndex index = new GitIndex(db);
+ File f1 = writeTrashFile("a/a/a/a", "data:a/a/a/a");
+ File f2 = writeTrashFile("a/c/c", "data:a/c/c");
+ File f3 = writeTrashFile("a/b", "data:a/b");
+ File f4 = writeTrashFile("a:b", "data:a:b");
+ File f5 = writeTrashFile("a/d", "data:a/d");
+ File f6 = writeTrashFile("a.b", "data:a.b");
+ index.add(trash, f1);
+ index.add(trash, f2);
+ index.add(trash, f3);
+ index.add(trash, f4);
+ index.add(trash, f5);
+ index.add(trash, f6);
+ index.write();
+ ObjectId id = index.writeTree();
+ System.out.println("wrote id " + id);
+ assertEquals("ba78e065e2c261d4f7b8f42107588051e87e18e9", id.name());
+ GitIndex index2 = new GitIndex(db);
+
+ index2.readTree(db.mapTree(ObjectId.fromString(
+ "ba78e065e2c261d4f7b8f42107588051e87e18e9")));
+ Entry[] members = index2.getMembers();
+ assertEquals(6, members.length);
+ assertEquals("a.b", members[0].getName());
+ assertEquals("a/a/a/a", members[1].getName());
+ assertEquals("a/b", members[2].getName());
+ assertEquals("a/c/c", members[3].getName());
+ assertEquals("a/d", members[4].getName());
+ assertEquals("a:b", members[5].getName());
+
+ // reread and test
+ GitIndex indexr = new GitIndex(db);
+ indexr.read();
+ Entry[] membersr = indexr.getMembers();
+ assertEquals(6, membersr.length);
+ assertEquals("a.b", membersr[0].getName());
+ assertEquals("a/a/a/a", membersr[1].getName());
+ assertEquals("a/b", membersr[2].getName());
+ assertEquals("a/c/c", membersr[3].getName());
+ assertEquals("a/d", membersr[4].getName());
+ assertEquals("a:b", membersr[5].getName());
+ }
+
+ public void testDelete() throws Exception {
+ GitIndex index = new GitIndex(db);
+ writeTrashFile("a/b", "data:a/b");
+ writeTrashFile("a:b", "data:a:b");
+ writeTrashFile("a.b", "data:a.b");
+ index.add(trash, new File(trash, "a/b"));
+ index.add(trash, new File(trash, "a:b"));
+ index.add(trash, new File(trash, "a.b"));
+ index.write();
+ index.writeTree();
+ index.remove(trash, new File(trash, "a:b"));
+ index.write();
+ assertEquals("a.b", index.getMembers()[0].getName());
+ assertEquals("a/b", index.getMembers()[1].getName());
+
+ GitIndex indexr = new GitIndex(db);
+ indexr.read();
+ assertEquals("a.b", indexr.getMembers()[0].getName());
+ assertEquals("a/b", indexr.getMembers()[1].getName());
+
+ if (canrungitstatus)
+ assertEquals(0, system(trash, "git status"));
+ }
+
+ public void testCheckout() throws Exception {
+ // Prepare tree, remote it and checkout
+ GitIndex index = new GitIndex(db);
+ File aslashb = writeTrashFile("a/b", "data:a/b");
+ File acolonb = writeTrashFile("a:b", "data:a:b");
+ File adotb = writeTrashFile("a.b", "data:a.b");
+ index.add(trash, aslashb);
+ index.add(trash, acolonb);
+ index.add(trash, adotb);
+ index.write();
+ index.writeTree();
+ delete(aslashb);
+ delete(acolonb);
+ delete(adotb);
+ delete(aslashb.getParentFile());
+
+ GitIndex index2 = new GitIndex(db);
+ assertEquals(0, index2.getMembers().length);
+
+ index2.readTree(db.mapTree(ObjectId.fromString(
+ "c696abc3ab8e091c665f49d00eb8919690b3aec3")));
+
+ index2.checkout(trash);
+ assertEquals("data:a/b", content(aslashb));
+ assertEquals("data:a:b", content(acolonb));
+ assertEquals("data:a.b", content(adotb));
+
+ if (canrungitstatus)
+ assertEquals(0, system(trash, "git status"));
+ }
+
+ public void test030_executeBit_coreModeTrue() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, Error, Exception {
+ if (!FS.INSTANCE.supportsExecute()) {
+ System.err.println("Test ignored since platform FS does not support the execute permission");
+ return;
+ }
+ try {
+ // coremode true is the default, typically set to false
+ // by git init (but not jgit!)
+ Method canExecute = File.class.getMethod("canExecute", (Class[])null);
+ Method setExecute = File.class.getMethod("setExecutable", new Class[] { Boolean.TYPE });
+ File execFile = writeTrashFile("exec","exec");
+ if (!((Boolean)setExecute.invoke(execFile, new Object[] { Boolean.TRUE })).booleanValue())
+ throw new Error("could not set execute bit on "+execFile.getAbsolutePath()+"for test");
+ File nonexecFile = writeTrashFile("nonexec","nonexec");
+ if (!((Boolean)setExecute.invoke(nonexecFile, new Object[] { Boolean.FALSE })).booleanValue())
+ throw new Error("could not clear execute bit on "+nonexecFile.getAbsolutePath()+"for test");
+
+ GitIndex index = new GitIndex(db);
+ index.filemode = Boolean.TRUE; // TODO: we need a way to set this using config
+ index.add(trash, execFile);
+ index.add(trash, nonexecFile);
+ Tree tree = db.mapTree(index.writeTree());
+ assertEquals(FileMode.EXECUTABLE_FILE, tree.findBlobMember(execFile.getName()).getMode());
+ assertEquals(FileMode.REGULAR_FILE, tree.findBlobMember(nonexecFile.getName()).getMode());
+
+ index.write();
+
+ if (!execFile.delete())
+ throw new Error("Problem in test, cannot delete test file "+execFile.getAbsolutePath());
+ if (!nonexecFile.delete())
+ throw new Error("Problem in test, cannot delete test file "+nonexecFile.getAbsolutePath());
+ GitIndex index2 = new GitIndex(db);
+ index2.filemode = Boolean.TRUE; // TODO: we need a way to set this using config
+ index2.read();
+ index2.checkout(trash);
+ assertTrue(((Boolean)canExecute.invoke(execFile,(Object[])null)).booleanValue());
+ assertFalse(((Boolean)canExecute.invoke(nonexecFile,(Object[])null)).booleanValue());
+
+ assertFalse(index2.getEntry(execFile.getName()).isModified(trash));
+ assertFalse(index2.getEntry(nonexecFile.getName()).isModified(trash));
+
+ if (!((Boolean)setExecute.invoke(execFile, new Object[] { Boolean.FALSE })).booleanValue())
+ throw new Error("could not clear set execute bit on "+execFile.getAbsolutePath()+"for test");
+ if (!((Boolean)setExecute.invoke(nonexecFile, new Object[] { Boolean.TRUE })).booleanValue())
+ throw new Error("could set execute bit on "+nonexecFile.getAbsolutePath()+"for test");
+
+ assertTrue(index2.getEntry(execFile.getName()).isModified(trash));
+ assertTrue(index2.getEntry(nonexecFile.getName()).isModified(trash));
+
+ } catch (NoSuchMethodException e) {
+ System.err.println("Test ignored when running under JDK < 1.6");
+ return;
+ }
+ }
+
+ public void test031_executeBit_coreModeFalse() throws IllegalArgumentException, IllegalAccessException, InvocationTargetException, Error, Exception {
+ if (!FS.INSTANCE.supportsExecute()) {
+ System.err.println("Test ignored since platform FS does not support the execute permission");
+ return;
+ }
+ try {
+ // coremode true is the default, typically set to false
+ // by git init (but not jgit!)
+ Method canExecute = File.class.getMethod("canExecute", (Class[])null);
+ Method setExecute = File.class.getMethod("setExecutable", new Class[] { Boolean.TYPE });
+ File execFile = writeTrashFile("exec","exec");
+ if (!((Boolean)setExecute.invoke(execFile, new Object[] { Boolean.TRUE })).booleanValue())
+ throw new Error("could not set execute bit on "+execFile.getAbsolutePath()+"for test");
+ File nonexecFile = writeTrashFile("nonexec","nonexec");
+ if (!((Boolean)setExecute.invoke(nonexecFile, new Object[] { Boolean.FALSE })).booleanValue())
+ throw new Error("could not clear execute bit on "+nonexecFile.getAbsolutePath()+"for test");
+
+ GitIndex index = new GitIndex(db);
+ index.filemode = Boolean.FALSE; // TODO: we need a way to set this using config
+ index.add(trash, execFile);
+ index.add(trash, nonexecFile);
+ Tree tree = db.mapTree(index.writeTree());
+ assertEquals(FileMode.REGULAR_FILE, tree.findBlobMember(execFile.getName()).getMode());
+ assertEquals(FileMode.REGULAR_FILE, tree.findBlobMember(nonexecFile.getName()).getMode());
+
+ index.write();
+
+ if (!execFile.delete())
+ throw new Error("Problem in test, cannot delete test file "+execFile.getAbsolutePath());
+ if (!nonexecFile.delete())
+ throw new Error("Problem in test, cannot delete test file "+nonexecFile.getAbsolutePath());
+ GitIndex index2 = new GitIndex(db);
+ index2.filemode = Boolean.FALSE; // TODO: we need a way to set this using config
+ index2.read();
+ index2.checkout(trash);
+ assertFalse(((Boolean)canExecute.invoke(execFile,(Object[])null)).booleanValue());
+ assertFalse(((Boolean)canExecute.invoke(nonexecFile,(Object[])null)).booleanValue());
+
+ assertFalse(index2.getEntry(execFile.getName()).isModified(trash));
+ assertFalse(index2.getEntry(nonexecFile.getName()).isModified(trash));
+
+ if (!((Boolean)setExecute.invoke(execFile, new Object[] { Boolean.FALSE })).booleanValue())
+ throw new Error("could not clear set execute bit on "+execFile.getAbsolutePath()+"for test");
+ if (!((Boolean)setExecute.invoke(nonexecFile, new Object[] { Boolean.TRUE })).booleanValue())
+ throw new Error("could set execute bit on "+nonexecFile.getAbsolutePath()+"for test");
+
+ // no change since we ignore the execute bit
+ assertFalse(index2.getEntry(execFile.getName()).isModified(trash));
+ assertFalse(index2.getEntry(nonexecFile.getName()).isModified(trash));
+
+ } catch (NoSuchMethodException e) {
+ System.err.println("Test ignored when running under JDK < 1.6");
+ return;
+ }
+ }
+
+ private String content(File f) throws IOException {
+ byte[] buf = new byte[(int) f.length()];
+ FileInputStream is = new FileInputStream(f);
+ try {
+ int read = is.read(buf);
+ assertEquals(f.length(), read);
+ return new String(buf, 0);
+ } finally {
+ is.close();
+ }
+ }
+
+ private void delete(File f) throws IOException {
+ if (!f.delete())
+ throw new IOException("Failed to delete f");
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0008_testparserev.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0008_testparserev.java
new file mode 100644
index 0000000000..ac730ff6a2
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/T0008_testparserev.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2008, Jonas Fonseca <fonseca@diku.dk>
+ * Copyright (C) 2007-2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2006, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.IOException;
+
+public class T0008_testparserev extends RepositoryTestCase {
+
+ public void testObjectId_existing() throws IOException {
+ assertEquals("49322bb17d3acc9146f98c97d078513228bbf3c0",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0").name());
+ }
+
+ public void testObjectId_nonexisting() throws IOException {
+ assertEquals("49322bb17d3acc9146f98c97d078513228bbf3c1",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c1").name());
+ }
+
+ public void testObjectId_objectid_implicit_firstparent() throws IOException {
+ assertEquals("6e1475206e57110fcef4b92320436c1e9872a322",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0^").name());
+ assertEquals("1203b03dc816ccbb67773f28b3c19318654b0bc8",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0^^").name());
+ assertEquals("bab66b48f836ed950c99134ef666436fb07a09a0",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0^^^").name());
+ }
+
+ public void testObjectId_objectid_self() throws IOException {
+ assertEquals("49322bb17d3acc9146f98c97d078513228bbf3c0",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0^0").name());
+ assertEquals("49322bb17d3acc9146f98c97d078513228bbf3c0",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0^0^0").name());
+ assertEquals("49322bb17d3acc9146f98c97d078513228bbf3c0",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0^0^0^0").name());
+ }
+
+ public void testObjectId_objectid_explicit_firstparent() throws IOException {
+ assertEquals("6e1475206e57110fcef4b92320436c1e9872a322",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0^1").name());
+ assertEquals("1203b03dc816ccbb67773f28b3c19318654b0bc8",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0^1^1").name());
+ assertEquals("bab66b48f836ed950c99134ef666436fb07a09a0",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0^1^1^1").name());
+ }
+
+ public void testObjectId_objectid_explicit_otherparents() throws IOException {
+ assertEquals("6e1475206e57110fcef4b92320436c1e9872a322",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0^1").name());
+ assertEquals("f73b95671f326616d66b2afb3bdfcdbbce110b44",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0^2").name());
+ assertEquals("d0114ab8ac326bab30e3a657a0397578c5a1af88",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0^3").name());
+ assertEquals("d0114ab8ac326bab30e3a657a0397578c5a1af88",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0^03").name());
+ }
+
+ public void testRef_refname() throws IOException {
+ assertEquals("49322bb17d3acc9146f98c97d078513228bbf3c0",db.resolve("master^0").name());
+ assertEquals("6e1475206e57110fcef4b92320436c1e9872a322",db.resolve("master^").name());
+ assertEquals("6e1475206e57110fcef4b92320436c1e9872a322",db.resolve("refs/heads/master^1").name());
+ }
+
+ public void testDistance() throws IOException {
+ assertEquals("49322bb17d3acc9146f98c97d078513228bbf3c0",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0~0").name());
+ assertEquals("6e1475206e57110fcef4b92320436c1e9872a322",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0~1").name());
+ assertEquals("1203b03dc816ccbb67773f28b3c19318654b0bc8",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0~2").name());
+ assertEquals("bab66b48f836ed950c99134ef666436fb07a09a0",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0~3").name());
+ assertEquals("bab66b48f836ed950c99134ef666436fb07a09a0",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0~03").name());
+ }
+
+ public void testTree() throws IOException {
+ assertEquals("6020a3b8d5d636e549ccbd0c53e2764684bb3125",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0^{tree}").name());
+ assertEquals("02ba32d3649e510002c21651936b7077aa75ffa9",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0^^{tree}").name());
+ }
+
+ public void testHEAD() throws IOException {
+ assertEquals("6020a3b8d5d636e549ccbd0c53e2764684bb3125",db.resolve("HEAD^{tree}").name());
+ }
+
+ public void testDerefCommit() throws IOException {
+ assertEquals("49322bb17d3acc9146f98c97d078513228bbf3c0",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0^{}").name());
+ assertEquals("49322bb17d3acc9146f98c97d078513228bbf3c0",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0^{commit}").name());
+ // double deref
+ assertEquals("6020a3b8d5d636e549ccbd0c53e2764684bb3125",db.resolve("49322bb17d3acc9146f98c97d078513228bbf3c0^{commit}^{tree}").name());
+ }
+
+ public void testDerefTag() throws IOException {
+ assertEquals("17768080a2318cd89bba4c8b87834401e2095703",db.resolve("refs/tags/B").name());
+ assertEquals("d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864",db.resolve("refs/tags/B^{commit}").name());
+ assertEquals("032c063ce34486359e3ee3d4f9e5c225b9e1a4c2",db.resolve("refs/tags/B10th").name());
+ assertEquals("d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864",db.resolve("refs/tags/B10th^{commit}").name());
+ assertEquals("d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864",db.resolve("refs/tags/B10th^{}").name());
+ assertEquals("d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864",db.resolve("refs/tags/B10th^0").name());
+ assertEquals("d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864",db.resolve("refs/tags/B10th~0").name());
+ assertEquals("0966a434eb1a025db6b71485ab63a3bfbea520b6",db.resolve("refs/tags/B10th^").name());
+ assertEquals("0966a434eb1a025db6b71485ab63a3bfbea520b6",db.resolve("refs/tags/B10th^1").name());
+ assertEquals("0966a434eb1a025db6b71485ab63a3bfbea520b6",db.resolve("refs/tags/B10th~1").name());
+ assertEquals("2c349335b7f797072cf729c4f3bb0914ecb6dec9",db.resolve("refs/tags/B10th~2").name());
+ }
+
+ public void testDerefBlob() throws IOException {
+ assertEquals("fd608fbe625a2b456d9f15c2b1dc41f252057dd7",db.resolve("spearce-gpg-pub^{}").name());
+ assertEquals("fd608fbe625a2b456d9f15c2b1dc41f252057dd7",db.resolve("spearce-gpg-pub^{blob}").name());
+ assertEquals("fd608fbe625a2b456d9f15c2b1dc41f252057dd7",db.resolve("fd608fbe625a2b456d9f15c2b1dc41f252057dd7^{}").name());
+ assertEquals("fd608fbe625a2b456d9f15c2b1dc41f252057dd7",db.resolve("fd608fbe625a2b456d9f15c2b1dc41f252057dd7^{blob}").name());
+ }
+
+ public void testDerefTree() throws IOException {
+ assertEquals("032c063ce34486359e3ee3d4f9e5c225b9e1a4c2",db.resolve("refs/tags/B10th").name());
+ assertEquals("856ec208ae6cadac25a6d74f19b12bb27a24fe24",db.resolve("032c063ce34486359e3ee3d4f9e5c225b9e1a4c2^{tree}").name());
+ assertEquals("856ec208ae6cadac25a6d74f19b12bb27a24fe24",db.resolve("refs/tags/B10th^{tree}").name());
+ }
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/TreeIteratorLeafOnlyTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/TreeIteratorLeafOnlyTest.java
new file mode 100644
index 0000000000..6b19cc1e89
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/TreeIteratorLeafOnlyTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2006, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.IOException;
+
+public class TreeIteratorLeafOnlyTest extends RepositoryTestCase {
+
+ /** Empty tree */
+ public void testEmpty() {
+ Tree tree = new Tree(db);
+ TreeIterator i = makeIterator(tree);
+ assertFalse(i.hasNext());
+ }
+
+ /**
+ * one file
+ *
+ * @throws IOException
+ */
+ public void testSimpleF1() throws IOException {
+ Tree tree = new Tree(db);
+ tree.addFile("x");
+ TreeIterator i = makeIterator(tree);
+ assertTrue(i.hasNext());
+ assertEquals("x", i.next().getName());
+ }
+
+ /**
+ * two files
+ *
+ * @throws IOException
+ */
+ public void testSimpleF2() throws IOException {
+ Tree tree = new Tree(db);
+ tree.addFile("a");
+ tree.addFile("x");
+ TreeIterator i = makeIterator(tree);
+ assertTrue(i.hasNext());
+ assertEquals("a", i.next().getName());
+ assertEquals("x", i.next().getName());
+ }
+
+ /**
+ * Empty tree
+ *
+ * @throws IOException
+ */
+ public void testSimpleT() throws IOException {
+ Tree tree = new Tree(db);
+ tree.addTree("a");
+ TreeIterator i = makeIterator(tree);
+ assertFalse(i.hasNext());
+ }
+
+ public void testTricky() throws IOException {
+ Tree tree = new Tree(db);
+ tree.addFile("a.b");
+ tree.addFile("a.c");
+ tree.addFile("a/b.b/b");
+ tree.addFile("a/b");
+ tree.addFile("a/c");
+ tree.addFile("a=c");
+ tree.addFile("a=d");
+
+ TreeIterator i = makeIterator(tree);
+ assertTrue(i.hasNext());
+ assertEquals("a.b", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a.c", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a/b", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a/b.b/b", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a/c", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a=c", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a=d", i.next().getFullName());
+ assertFalse(i.hasNext());
+ }
+
+ private TreeIterator makeIterator(Tree tree) {
+ return new TreeIterator(tree);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/TreeIteratorPostOrderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/TreeIteratorPostOrderTest.java
new file mode 100644
index 0000000000..caf8bff2a7
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/TreeIteratorPostOrderTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2006, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.IOException;
+
+public class TreeIteratorPostOrderTest extends RepositoryTestCase {
+
+ /** Empty tree */
+ public void testEmpty() {
+ Tree tree = new Tree(db);
+ TreeIterator i = makeIterator(tree);
+ assertTrue(i.hasNext());
+ assertEquals("", i.next().getFullName());
+ assertFalse(i.hasNext());
+ }
+
+ /**
+ * one file
+ *
+ * @throws IOException
+ */
+ public void testSimpleF1() throws IOException {
+ Tree tree = new Tree(db);
+ tree.addFile("x");
+ TreeIterator i = makeIterator(tree);
+ assertTrue(i.hasNext());
+ assertEquals("x", i.next().getName());
+ assertTrue(i.hasNext());
+ assertEquals("", i.next().getFullName());
+ assertFalse(i.hasNext());
+ }
+
+ /**
+ * two files
+ *
+ * @throws IOException
+ */
+ public void testSimpleF2() throws IOException {
+ Tree tree = new Tree(db);
+ tree.addFile("a");
+ tree.addFile("x");
+ TreeIterator i = makeIterator(tree);
+ assertTrue(i.hasNext());
+ assertEquals("a", i.next().getName());
+ assertEquals("x", i.next().getName());
+ assertTrue(i.hasNext());
+ assertEquals("", i.next().getFullName());
+ assertFalse(i.hasNext());
+ }
+
+ /**
+ * Empty tree
+ *
+ * @throws IOException
+ */
+ public void testSimpleT() throws IOException {
+ Tree tree = new Tree(db);
+ tree.addTree("a");
+ TreeIterator i = makeIterator(tree);
+ assertTrue(i.hasNext());
+ assertEquals("a", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("", i.next().getFullName());
+ assertFalse(i.hasNext());
+ }
+
+ public void testTricky() throws IOException {
+ Tree tree = new Tree(db);
+ tree.addFile("a.b");
+ tree.addFile("a.c");
+ tree.addFile("a/b.b/b");
+ tree.addFile("a/b");
+ tree.addFile("a/c");
+ tree.addFile("a=c");
+ tree.addFile("a=d");
+
+ TreeIterator i = makeIterator(tree);
+ assertTrue(i.hasNext());
+ assertEquals("a.b", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a.c", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a/b", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a/b.b/b", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a/b.b", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a/c", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a=c", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a=d", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("", i.next().getFullName());
+ assertFalse(i.hasNext());
+ }
+
+ private TreeIterator makeIterator(Tree tree) {
+ return new TreeIterator(tree, TreeIterator.Order.POSTORDER);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/TreeIteratorPreOrderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/TreeIteratorPreOrderTest.java
new file mode 100644
index 0000000000..c6f41446d2
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/TreeIteratorPreOrderTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2006, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.IOException;
+
+public class TreeIteratorPreOrderTest extends RepositoryTestCase {
+
+ /** Empty tree */
+ public void testEmpty() {
+ Tree tree = new Tree(db);
+ TreeIterator i = makeIterator(tree);
+ assertTrue(i.hasNext());
+ assertEquals("", i.next().getFullName());
+ assertFalse(i.hasNext());
+ }
+
+ /**
+ * one file
+ *
+ * @throws IOException
+ */
+ public void testSimpleF1() throws IOException {
+ Tree tree = new Tree(db);
+ tree.addFile("x");
+ TreeIterator i = makeIterator(tree);
+ assertTrue(i.hasNext());
+ assertEquals("", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("x", i.next().getName());
+ assertFalse(i.hasNext());
+ }
+
+ /**
+ * two files
+ *
+ * @throws IOException
+ */
+ public void testSimpleF2() throws IOException {
+ Tree tree = new Tree(db);
+ tree.addFile("a");
+ tree.addFile("x");
+ TreeIterator i = makeIterator(tree);
+ assertTrue(i.hasNext());
+ assertEquals("", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a", i.next().getName());
+ assertEquals("x", i.next().getName());
+ assertFalse(i.hasNext());
+ }
+
+ /**
+ * Empty tree
+ *
+ * @throws IOException
+ */
+ public void testSimpleT() throws IOException {
+ Tree tree = new Tree(db);
+ tree.addTree("a");
+ TreeIterator i = makeIterator(tree);
+ assertTrue(i.hasNext());
+ assertEquals("", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a", i.next().getFullName());
+ assertFalse(i.hasNext());
+ }
+
+ public void testTricky() throws IOException {
+ Tree tree = new Tree(db);
+ tree.addFile("a.b");
+ tree.addFile("a.c");
+ tree.addFile("a/b.b/b");
+ tree.addFile("a/b");
+ tree.addFile("a/c");
+ tree.addFile("a=c");
+ tree.addFile("a=d");
+
+ TreeIterator i = makeIterator(tree);
+ assertTrue(i.hasNext());
+ assertEquals("", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a.b", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a.c", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a/b", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a/b.b", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a/b.b/b", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a/c", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a=c", i.next().getFullName());
+ assertTrue(i.hasNext());
+ assertEquals("a=d", i.next().getFullName());
+ assertFalse(i.hasNext());
+ }
+
+ private TreeIterator makeIterator(Tree tree) {
+ return new TreeIterator(tree, TreeIterator.Order.PREORDER);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ValidRefNameTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ValidRefNameTest.java
new file mode 100644
index 0000000000..79e2eba701
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ValidRefNameTest.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import junit.framework.TestCase;
+
+public class ValidRefNameTest extends TestCase {
+ private static void assertValid(final boolean exp, final String name) {
+ assertEquals("\"" + name + "\"", exp, Repository.isValidRefName(name));
+ }
+
+ public void testEmptyString() {
+ assertValid(false, "");
+ assertValid(false, "/");
+ }
+
+ public void testMustHaveTwoComponents() {
+ assertValid(false, "master");
+ assertValid(true, "heads/master");
+ }
+
+ public void testValidHead() {
+ assertValid(true, "refs/heads/master");
+ assertValid(true, "refs/heads/pu");
+ assertValid(true, "refs/heads/z");
+ assertValid(true, "refs/heads/FoO");
+ }
+
+ public void testValidTag() {
+ assertValid(true, "refs/tags/v1.0");
+ }
+
+ public void testNoLockSuffix() {
+ assertValid(false, "refs/heads/master.lock");
+ }
+
+ public void testNoDirectorySuffix() {
+ assertValid(false, "refs/heads/master/");
+ }
+
+ public void testNoSpace() {
+ assertValid(false, "refs/heads/i haz space");
+ }
+
+ public void testNoAsciiControlCharacters() {
+ for (char c = '\0'; c < ' '; c++)
+ assertValid(false, "refs/heads/mast" + c + "er");
+ }
+
+ public void testNoBareDot() {
+ assertValid(false, "refs/heads/.");
+ assertValid(false, "refs/heads/..");
+ assertValid(false, "refs/heads/./master");
+ assertValid(false, "refs/heads/../master");
+ }
+
+ public void testNoLeadingOrTrailingDot() {
+ assertValid(false, ".");
+ assertValid(false, "refs/heads/.bar");
+ assertValid(false, "refs/heads/..bar");
+ assertValid(false, "refs/heads/bar.");
+ }
+
+ public void testContainsDot() {
+ assertValid(true, "refs/heads/m.a.s.t.e.r");
+ assertValid(false, "refs/heads/master..pu");
+ }
+
+ public void testNoMagicRefCharacters() {
+ assertValid(false, "refs/heads/master^");
+ assertValid(false, "refs/heads/^master");
+ assertValid(false, "^refs/heads/master");
+
+ assertValid(false, "refs/heads/master~");
+ assertValid(false, "refs/heads/~master");
+ assertValid(false, "~refs/heads/master");
+
+ assertValid(false, "refs/heads/master:");
+ assertValid(false, "refs/heads/:master");
+ assertValid(false, ":refs/heads/master");
+ }
+
+ public void testShellGlob() {
+ assertValid(false, "refs/heads/master?");
+ assertValid(false, "refs/heads/?master");
+ assertValid(false, "?refs/heads/master");
+
+ assertValid(false, "refs/heads/master[");
+ assertValid(false, "refs/heads/[master");
+ assertValid(false, "[refs/heads/master");
+
+ assertValid(false, "refs/heads/master*");
+ assertValid(false, "refs/heads/*master");
+ assertValid(false, "*refs/heads/master");
+ }
+
+ public void testValidSpecialCharacters() {
+ assertValid(true, "refs/heads/!");
+ assertValid(true, "refs/heads/\"");
+ assertValid(true, "refs/heads/#");
+ assertValid(true, "refs/heads/$");
+ assertValid(true, "refs/heads/%");
+ assertValid(true, "refs/heads/&");
+ assertValid(true, "refs/heads/'");
+ assertValid(true, "refs/heads/(");
+ assertValid(true, "refs/heads/)");
+ assertValid(true, "refs/heads/+");
+ assertValid(true, "refs/heads/,");
+ assertValid(true, "refs/heads/-");
+ assertValid(true, "refs/heads/;");
+ assertValid(true, "refs/heads/<");
+ assertValid(true, "refs/heads/=");
+ assertValid(true, "refs/heads/>");
+ assertValid(true, "refs/heads/@");
+ assertValid(true, "refs/heads/]");
+ assertValid(true, "refs/heads/_");
+ assertValid(true, "refs/heads/`");
+ assertValid(true, "refs/heads/{");
+ assertValid(true, "refs/heads/|");
+ assertValid(true, "refs/heads/}");
+
+ // This is valid on UNIX, but not on Windows
+ // hence we make in invalid due to non-portability
+ //
+ assertValid(false, "refs/heads/\\");
+ }
+
+ public void testUnicodeNames() {
+ assertValid(true, "refs/heads/\u00e5ngstr\u00f6m");
+ }
+
+ public void testRefLogQueryIsValidRef() {
+ assertValid(false, "refs/heads/master@{1}");
+ assertValid(false, "refs/heads/master@{1.hour.ago}");
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/WindowCacheGetTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/WindowCacheGetTest.java
new file mode 100644
index 0000000000..55b568d8fd
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/WindowCacheGetTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.eclipse.jgit.errors.CorruptObjectException;
+import org.eclipse.jgit.util.JGitTestUtil;
+import org.eclipse.jgit.util.MutableInteger;
+
+public class WindowCacheGetTest extends RepositoryTestCase {
+ private List<TestObject> toLoad;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ toLoad = new ArrayList<TestObject>();
+ final BufferedReader br = new BufferedReader(new InputStreamReader(
+ new FileInputStream(JGitTestUtil
+ .getTestResourceFile("all_packed_objects.txt")),
+ Constants.CHARSET));
+ try {
+ String line;
+ while ((line = br.readLine()) != null) {
+ final String[] parts = line.split(" {1,}");
+ final TestObject o = new TestObject();
+ o.id = ObjectId.fromString(parts[0]);
+ o.setType(parts[1]);
+ o.rawSize = Integer.parseInt(parts[2]);
+ // parts[3] is the size-in-pack
+ o.offset = Long.parseLong(parts[4]);
+ toLoad.add(o);
+ }
+ } finally {
+ br.close();
+ }
+ assertEquals(96, toLoad.size());
+ }
+
+ public void testCache_Defaults() throws IOException {
+ final WindowCacheConfig cfg = new WindowCacheConfig();
+ WindowCache.reconfigure(cfg);
+ doCacheTests();
+ checkLimits(cfg);
+
+ final WindowCache cache = WindowCache.getInstance();
+ assertEquals(6, cache.getOpenFiles());
+ assertEquals(17346, cache.getOpenBytes());
+ }
+
+ public void testCache_TooFewFiles() throws IOException {
+ final WindowCacheConfig cfg = new WindowCacheConfig();
+ cfg.setPackedGitOpenFiles(2);
+ WindowCache.reconfigure(cfg);
+ doCacheTests();
+ checkLimits(cfg);
+ }
+
+ public void testCache_TooSmallLimit() throws IOException {
+ final WindowCacheConfig cfg = new WindowCacheConfig();
+ cfg.setPackedGitWindowSize(4096);
+ cfg.setPackedGitLimit(4096);
+ WindowCache.reconfigure(cfg);
+ doCacheTests();
+ checkLimits(cfg);
+ }
+
+ private void checkLimits(final WindowCacheConfig cfg) {
+ final WindowCache cache = WindowCache.getInstance();
+ assertTrue(cache.getOpenFiles() <= cfg.getPackedGitOpenFiles());
+ assertTrue(cache.getOpenBytes() <= cfg.getPackedGitLimit());
+ assertTrue(0 < cache.getOpenFiles());
+ assertTrue(0 < cache.getOpenBytes());
+ }
+
+ private void doCacheTests() throws IOException {
+ for (final TestObject o : toLoad) {
+ final ObjectLoader or = db.openObject(o.id);
+ assertNotNull(or);
+ assertTrue(or instanceof PackedObjectLoader);
+ assertEquals(o.type, or.getType());
+ assertEquals(o.rawSize, or.getRawSize());
+ assertEquals(o.offset, ((PackedObjectLoader) or).getObjectOffset());
+ }
+ }
+
+ private class TestObject {
+ ObjectId id;
+
+ int type;
+
+ int rawSize;
+
+ long offset;
+
+ void setType(final String typeStr) throws CorruptObjectException {
+ final byte[] typeRaw = Constants.encode(typeStr + " ");
+ final MutableInteger ptr = new MutableInteger();
+ type = Constants.decodeTypeString(id, typeRaw, (byte) ' ', ptr);
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/WindowCacheReconfigureTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/WindowCacheReconfigureTest.java
new file mode 100644
index 0000000000..9e093c85bd
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/WindowCacheReconfigureTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+public class WindowCacheReconfigureTest extends RepositoryTestCase {
+ public void testConfigureCache_PackedGitLimit_0() {
+ try {
+ final WindowCacheConfig cfg = new WindowCacheConfig();
+ cfg.setPackedGitLimit(0);
+ WindowCache.reconfigure(cfg);
+ fail("incorrectly permitted PackedGitLimit = 0");
+ } catch (IllegalArgumentException e) {
+ //
+ }
+ }
+
+ public void testConfigureCache_PackedGitWindowSize_0() {
+ try {
+ final WindowCacheConfig cfg = new WindowCacheConfig();
+ cfg.setPackedGitWindowSize(0);
+ WindowCache.reconfigure(cfg);
+ fail("incorrectly permitted PackedGitWindowSize = 0");
+ } catch (IllegalArgumentException e) {
+ assertEquals("Invalid window size", e.getMessage());
+ }
+ }
+
+ public void testConfigureCache_PackedGitWindowSize_512() {
+ try {
+ final WindowCacheConfig cfg = new WindowCacheConfig();
+ cfg.setPackedGitWindowSize(512);
+ WindowCache.reconfigure(cfg);
+ fail("incorrectly permitted PackedGitWindowSize = 512");
+ } catch (IllegalArgumentException e) {
+ assertEquals("Invalid window size", e.getMessage());
+ }
+ }
+
+ public void testConfigureCache_PackedGitWindowSize_4097() {
+ try {
+ final WindowCacheConfig cfg = new WindowCacheConfig();
+ cfg.setPackedGitWindowSize(4097);
+ WindowCache.reconfigure(cfg);
+ fail("incorrectly permitted PackedGitWindowSize = 4097");
+ } catch (IllegalArgumentException e) {
+ assertEquals("Window size must be power of 2", e.getMessage());
+ }
+ }
+
+ public void testConfigureCache_PackedGitOpenFiles_0() {
+ try {
+ final WindowCacheConfig cfg = new WindowCacheConfig();
+ cfg.setPackedGitOpenFiles(0);
+ WindowCache.reconfigure(cfg);
+ fail("incorrectly permitted PackedGitOpenFiles = 0");
+ } catch (IllegalArgumentException e) {
+ assertEquals("Open files must be >= 1", e.getMessage());
+ }
+ }
+
+ public void testConfigureCache_PackedGitWindowSizeAbovePackedGitLimit() {
+ try {
+ final WindowCacheConfig cfg = new WindowCacheConfig();
+ cfg.setPackedGitLimit(1024);
+ cfg.setPackedGitWindowSize(8192);
+ WindowCache.reconfigure(cfg);
+ fail("incorrectly permitted PackedGitWindowSize > PackedGitLimit");
+ } catch (IllegalArgumentException e) {
+ assertEquals("Window size must be < limit", e.getMessage());
+ }
+ }
+
+ public void testConfigureCache_Limits1() {
+ // This test is just to force coverage over some lower bounds for
+ // the table. We don't want the table to wind up with too small
+ // of a size. This is highly dependent upon the table allocation
+ // algorithm actually implemented in WindowCache.
+ //
+ final WindowCacheConfig cfg = new WindowCacheConfig();
+ cfg.setPackedGitLimit(6 * 4096 / 5);
+ cfg.setPackedGitWindowSize(4096);
+ WindowCache.reconfigure(cfg);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/WorkDirCheckoutTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/WorkDirCheckoutTest.java
new file mode 100644
index 0000000000..2599468faa
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/WorkDirCheckoutTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2007, Dave Watson <dwatson@mimvista.com>
+ * Copyright (C) 2006, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import org.eclipse.jgit.errors.CheckoutConflictException;
+
+public class WorkDirCheckoutTest extends RepositoryTestCase {
+ public void testFindingConflicts() throws IOException {
+ GitIndex index = new GitIndex(db);
+ index.add(trash, writeTrashFile("bar", "bar"));
+ index.add(trash, writeTrashFile("foo/bar/baz/qux", "foo/bar"));
+ recursiveDelete(new File(trash, "bar"));
+ recursiveDelete(new File(trash, "foo"));
+ writeTrashFile("bar/baz/qux/foo", "another nasty one");
+ writeTrashFile("foo", "troublesome little bugger");
+
+ WorkDirCheckout workDirCheckout = new WorkDirCheckout(db, trash, index,
+ index);
+ workDirCheckout.prescanOneTree();
+ ArrayList<String> conflictingEntries = workDirCheckout
+ .getConflicts();
+ ArrayList<String> removedEntries = workDirCheckout.getRemoved();
+ assertEquals("bar/baz/qux/foo", conflictingEntries.get(0));
+ assertEquals("foo", conflictingEntries.get(1));
+
+ GitIndex index2 = new GitIndex(db);
+ recursiveDelete(new File(trash, "bar"));
+ recursiveDelete(new File(trash, "foo"));
+
+ index2.add(trash, writeTrashFile("bar/baz/qux/foo", "bar"));
+ index2.add(trash, writeTrashFile("foo", "lalala"));
+
+ workDirCheckout = new WorkDirCheckout(db, trash, index2, index);
+ workDirCheckout.prescanOneTree();
+
+ conflictingEntries = workDirCheckout.getConflicts();
+ removedEntries = workDirCheckout.getRemoved();
+ assertTrue(conflictingEntries.isEmpty());
+ assertTrue(removedEntries.contains("bar/baz/qux/foo"));
+ assertTrue(removedEntries.contains("foo"));
+ }
+
+ public void testCheckingOutWithConflicts() throws IOException {
+ GitIndex index = new GitIndex(db);
+ index.add(trash, writeTrashFile("bar", "bar"));
+ index.add(trash, writeTrashFile("foo/bar/baz/qux", "foo/bar"));
+ recursiveDelete(new File(trash, "bar"));
+ recursiveDelete(new File(trash, "foo"));
+ writeTrashFile("bar/baz/qux/foo", "another nasty one");
+ writeTrashFile("foo", "troublesome little bugger");
+
+ try {
+ WorkDirCheckout workDirCheckout = new WorkDirCheckout(db, trash,
+ index, index);
+ workDirCheckout.checkout();
+ fail("Should have thrown exception");
+ } catch (CheckoutConflictException e) {
+ // all is well
+ }
+
+ WorkDirCheckout workDirCheckout = new WorkDirCheckout(db, trash, index,
+ index);
+ workDirCheckout.setFailOnConflict(false);
+ workDirCheckout.checkout();
+
+ assertTrue(new File(trash, "bar").isFile());
+ assertTrue(new File(trash, "foo/bar/baz/qux").isFile());
+
+ GitIndex index2 = new GitIndex(db);
+ recursiveDelete(new File(trash, "bar"));
+ recursiveDelete(new File(trash, "foo"));
+ index2.add(trash, writeTrashFile("bar/baz/qux/foo", "bar"));
+ writeTrashFile("bar/baz/qux/bar", "evil? I thought it said WEEVIL!");
+ index2.add(trash, writeTrashFile("foo", "lalala"));
+
+ workDirCheckout = new WorkDirCheckout(db, trash, index2, index);
+ workDirCheckout.setFailOnConflict(false);
+ workDirCheckout.checkout();
+
+ assertTrue(new File(trash, "bar").isFile());
+ assertTrue(new File(trash, "foo/bar/baz/qux").isFile());
+ assertNotNull(index2.getEntry("bar"));
+ assertNotNull(index2.getEntry("foo/bar/baz/qux"));
+ assertNull(index2.getEntry("bar/baz/qux/foo"));
+ assertNull(index2.getEntry("foo"));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/XInputStream.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/XInputStream.java
new file mode 100644
index 0000000000..eef32b9276
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/XInputStream.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2006-2008, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.lib;
+
+import java.io.BufferedInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.jgit.util.NB;
+
+class XInputStream extends BufferedInputStream {
+ private final byte[] intbuf = new byte[8];
+
+ XInputStream(final InputStream s) {
+ super(s);
+ }
+
+ synchronized byte[] readFully(final int len) throws IOException {
+ final byte[] b = new byte[len];
+ readFully(b, 0, len);
+ return b;
+ }
+
+ synchronized void readFully(final byte[] b, int o, int len)
+ throws IOException {
+ int r;
+ while (len > 0 && (r = read(b, o, len)) > 0) {
+ o += r;
+ len -= r;
+ }
+ if (len > 0)
+ throw new EOFException();
+ }
+
+ int readUInt8() throws IOException {
+ final int r = read();
+ if (r < 0)
+ throw new EOFException();
+ return r;
+ }
+
+ long readUInt32() throws IOException {
+ readFully(intbuf, 0, 4);
+ return NB.decodeUInt32(intbuf, 0);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/empty.gitindex.dat b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/empty.gitindex.dat
new file mode 100644
index 0000000000..3330d716f1
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/empty.gitindex.dat
Binary files differ
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/sorttest.gitindex.dat b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/sorttest.gitindex.dat
new file mode 100644
index 0000000000..217f2e3811
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/sorttest.gitindex.dat
Binary files differ
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CherryPickTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CherryPickTest.java
new file mode 100644
index 0000000000..42e653be37
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/CherryPickTest.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * Copyright (C) 2008, Robin Rosenberg
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.merge;
+
+import java.io.ByteArrayInputStream;
+
+import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheBuilder;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.lib.Commit;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectWriter;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+import org.eclipse.jgit.treewalk.TreeWalk;
+
+public class CherryPickTest extends RepositoryTestCase {
+ public void testPick() throws Exception {
+ // B---O
+ // \----P---T
+ //
+ // Cherry-pick "T" onto "O". This shouldn't introduce "p-fail", which
+ // was created by "P", nor should it modify "a", which was done by "P".
+ //
+ final DirCache treeB = DirCache.read(db);
+ final DirCache treeO = DirCache.read(db);
+ final DirCache treeP = DirCache.read(db);
+ final DirCache treeT = DirCache.read(db);
+ {
+ final DirCacheBuilder b = treeB.builder();
+ final DirCacheBuilder o = treeO.builder();
+ final DirCacheBuilder p = treeP.builder();
+ final DirCacheBuilder t = treeT.builder();
+
+ b.add(makeEntry("a", FileMode.REGULAR_FILE));
+
+ o.add(makeEntry("a", FileMode.REGULAR_FILE));
+ o.add(makeEntry("o", FileMode.REGULAR_FILE));
+
+ p.add(makeEntry("a", FileMode.REGULAR_FILE, "q"));
+ p.add(makeEntry("p-fail", FileMode.REGULAR_FILE));
+
+ t.add(makeEntry("a", FileMode.REGULAR_FILE));
+ t.add(makeEntry("t", FileMode.REGULAR_FILE));
+
+ b.finish();
+ o.finish();
+ p.finish();
+ t.finish();
+ }
+
+ final ObjectWriter ow = new ObjectWriter(db);
+ final ObjectId B = commit(ow, treeB, new ObjectId[] {});
+ final ObjectId O = commit(ow, treeO, new ObjectId[] { B });
+ final ObjectId P = commit(ow, treeP, new ObjectId[] { B });
+ final ObjectId T = commit(ow, treeT, new ObjectId[] { P });
+
+ ThreeWayMerger twm = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
+ twm.setBase(P);
+ boolean merge = twm.merge(new ObjectId[] { O, T });
+ assertTrue(merge);
+
+ final TreeWalk tw = new TreeWalk(db);
+ tw.setRecursive(true);
+ tw.reset(twm.getResultTreeId());
+
+ assertTrue(tw.next());
+ assertEquals("a", tw.getPathString());
+ assertCorrectId(treeO, tw);
+
+ assertTrue(tw.next());
+ assertEquals("o", tw.getPathString());
+ assertCorrectId(treeO, tw);
+
+ assertTrue(tw.next());
+ assertEquals("t", tw.getPathString());
+ assertCorrectId(treeT, tw);
+
+ assertFalse(tw.next());
+ }
+
+ private void assertCorrectId(final DirCache treeT, final TreeWalk tw) {
+ assertEquals(treeT.getEntry(tw.getPathString()).getObjectId(), tw
+ .getObjectId(0));
+ }
+
+ private ObjectId commit(final ObjectWriter ow, final DirCache treeB,
+ final ObjectId[] parentIds) throws Exception {
+ final Commit c = new Commit(db);
+ c.setTreeId(treeB.writeTree(ow));
+ c.setAuthor(new PersonIdent("A U Thor", "a.u.thor", 1L, 0));
+ c.setCommitter(c.getAuthor());
+ c.setParentIds(parentIds);
+ c.setMessage("Tree " + c.getTreeId().name());
+ return ow.writeCommit(c);
+ }
+
+ private DirCacheEntry makeEntry(final String path, final FileMode mode)
+ throws Exception {
+ return makeEntry(path, mode, path);
+ }
+
+ private DirCacheEntry makeEntry(final String path, final FileMode mode,
+ final String content) throws Exception {
+ final DirCacheEntry ent = new DirCacheEntry(path);
+ ent.setFileMode(mode);
+ final byte[] contentBytes = Constants.encode(content);
+ ent.setObjectId(new ObjectWriter(db).computeBlobSha1(
+ contentBytes.length, new ByteArrayInputStream(contentBytes)));
+ return ent;
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java
new file mode 100644
index 0000000000..0e50220067
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/merge/SimpleMergeTest.java
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * Copyright (C) 2008, Robin Rosenberg
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.merge;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheBuilder;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.lib.Commit;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectWriter;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+import org.eclipse.jgit.treewalk.TreeWalk;
+
+public class SimpleMergeTest extends RepositoryTestCase {
+
+ public void testOurs() throws IOException {
+ Merger ourMerger = MergeStrategy.OURS.newMerger(db);
+ boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a"), db.resolve("c") });
+ assertTrue(merge);
+ assertEquals(db.mapTree("a").getId(), ourMerger.getResultTreeId());
+ }
+
+ public void testTheirs() throws IOException {
+ Merger ourMerger = MergeStrategy.THEIRS.newMerger(db);
+ boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a"), db.resolve("c") });
+ assertTrue(merge);
+ assertEquals(db.mapTree("c").getId(), ourMerger.getResultTreeId());
+ }
+
+ public void testTrivialTwoWay() throws IOException {
+ Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
+ boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a"), db.resolve("c") });
+ assertTrue(merge);
+ assertEquals("02ba32d3649e510002c21651936b7077aa75ffa9",ourMerger.getResultTreeId().name());
+ }
+
+ public void testTrivialTwoWay_disjointhistories() throws IOException {
+ Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
+ boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a"), db.resolve("c~4") });
+ assertTrue(merge);
+ assertEquals("86265c33b19b2be71bdd7b8cb95823f2743d03a8",ourMerger.getResultTreeId().name());
+ }
+
+ public void testTrivialTwoWay_ok() throws IOException {
+ Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
+ boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("a^0^0^0"), db.resolve("a^0^0^1") });
+ assertTrue(merge);
+ assertEquals(db.mapTree("a^0^0").getId(), ourMerger.getResultTreeId());
+ }
+
+ public void testTrivialTwoWay_conflict() throws IOException {
+ Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
+ boolean merge = ourMerger.merge(new ObjectId[] { db.resolve("f"), db.resolve("g") });
+ assertFalse(merge);
+ }
+
+ public void testTrivialTwoWay_validSubtreeSort() throws Exception {
+ final DirCache treeB = DirCache.read(db);
+ final DirCache treeO = DirCache.read(db);
+ final DirCache treeT = DirCache.read(db);
+ {
+ final DirCacheBuilder b = treeB.builder();
+ final DirCacheBuilder o = treeO.builder();
+ final DirCacheBuilder t = treeT.builder();
+
+ b.add(makeEntry("libelf-po/a", FileMode.REGULAR_FILE));
+ b.add(makeEntry("libelf/c", FileMode.REGULAR_FILE));
+
+ o.add(makeEntry("Makefile", FileMode.REGULAR_FILE));
+ o.add(makeEntry("libelf-po/a", FileMode.REGULAR_FILE));
+ o.add(makeEntry("libelf/c", FileMode.REGULAR_FILE));
+
+ t.add(makeEntry("libelf-po/a", FileMode.REGULAR_FILE));
+ t.add(makeEntry("libelf/c", FileMode.REGULAR_FILE, "blah"));
+
+ b.finish();
+ o.finish();
+ t.finish();
+ }
+
+ final ObjectWriter ow = new ObjectWriter(db);
+ final ObjectId b = commit(ow, treeB, new ObjectId[] {});
+ final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
+ final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
+
+ Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
+ boolean merge = ourMerger.merge(new ObjectId[] { o, t });
+ assertTrue(merge);
+
+ final TreeWalk tw = new TreeWalk(db);
+ tw.setRecursive(true);
+ tw.reset(ourMerger.getResultTreeId());
+
+ assertTrue(tw.next());
+ assertEquals("Makefile", tw.getPathString());
+ assertCorrectId(treeO, tw);
+
+ assertTrue(tw.next());
+ assertEquals("libelf-po/a", tw.getPathString());
+ assertCorrectId(treeO, tw);
+
+ assertTrue(tw.next());
+ assertEquals("libelf/c", tw.getPathString());
+ assertCorrectId(treeT, tw);
+
+ assertFalse(tw.next());
+ }
+
+ public void testTrivialTwoWay_concurrentSubtreeChange() throws Exception {
+ final DirCache treeB = DirCache.read(db);
+ final DirCache treeO = DirCache.read(db);
+ final DirCache treeT = DirCache.read(db);
+ {
+ final DirCacheBuilder b = treeB.builder();
+ final DirCacheBuilder o = treeO.builder();
+ final DirCacheBuilder t = treeT.builder();
+
+ b.add(makeEntry("d/o", FileMode.REGULAR_FILE));
+ b.add(makeEntry("d/t", FileMode.REGULAR_FILE));
+
+ o.add(makeEntry("d/o", FileMode.REGULAR_FILE, "o !"));
+ o.add(makeEntry("d/t", FileMode.REGULAR_FILE));
+
+ t.add(makeEntry("d/o", FileMode.REGULAR_FILE));
+ t.add(makeEntry("d/t", FileMode.REGULAR_FILE, "t !"));
+
+ b.finish();
+ o.finish();
+ t.finish();
+ }
+
+ final ObjectWriter ow = new ObjectWriter(db);
+ final ObjectId b = commit(ow, treeB, new ObjectId[] {});
+ final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
+ final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
+
+ Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
+ boolean merge = ourMerger.merge(new ObjectId[] { o, t });
+ assertTrue(merge);
+
+ final TreeWalk tw = new TreeWalk(db);
+ tw.setRecursive(true);
+ tw.reset(ourMerger.getResultTreeId());
+
+ assertTrue(tw.next());
+ assertEquals("d/o", tw.getPathString());
+ assertCorrectId(treeO, tw);
+
+ assertTrue(tw.next());
+ assertEquals("d/t", tw.getPathString());
+ assertCorrectId(treeT, tw);
+
+ assertFalse(tw.next());
+ }
+
+ public void testTrivialTwoWay_conflictSubtreeChange() throws Exception {
+ final DirCache treeB = DirCache.read(db);
+ final DirCache treeO = DirCache.read(db);
+ final DirCache treeT = DirCache.read(db);
+ {
+ final DirCacheBuilder b = treeB.builder();
+ final DirCacheBuilder o = treeO.builder();
+ final DirCacheBuilder t = treeT.builder();
+
+ b.add(makeEntry("d/o", FileMode.REGULAR_FILE));
+ b.add(makeEntry("d/t", FileMode.REGULAR_FILE));
+
+ o.add(makeEntry("d/o", FileMode.REGULAR_FILE));
+ o.add(makeEntry("d/t", FileMode.REGULAR_FILE, "o !"));
+
+ t.add(makeEntry("d/o", FileMode.REGULAR_FILE, "t !"));
+ t.add(makeEntry("d/t", FileMode.REGULAR_FILE, "t !"));
+
+ b.finish();
+ o.finish();
+ t.finish();
+ }
+
+ final ObjectWriter ow = new ObjectWriter(db);
+ final ObjectId b = commit(ow, treeB, new ObjectId[] {});
+ final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
+ final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
+
+ Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
+ boolean merge = ourMerger.merge(new ObjectId[] { o, t });
+ assertFalse(merge);
+ }
+
+ public void testTrivialTwoWay_leftDFconflict1() throws Exception {
+ final DirCache treeB = DirCache.read(db);
+ final DirCache treeO = DirCache.read(db);
+ final DirCache treeT = DirCache.read(db);
+ {
+ final DirCacheBuilder b = treeB.builder();
+ final DirCacheBuilder o = treeO.builder();
+ final DirCacheBuilder t = treeT.builder();
+
+ b.add(makeEntry("d/o", FileMode.REGULAR_FILE));
+ b.add(makeEntry("d/t", FileMode.REGULAR_FILE));
+
+ o.add(makeEntry("d", FileMode.REGULAR_FILE));
+
+ t.add(makeEntry("d/o", FileMode.REGULAR_FILE));
+ t.add(makeEntry("d/t", FileMode.REGULAR_FILE, "t !"));
+
+ b.finish();
+ o.finish();
+ t.finish();
+ }
+
+ final ObjectWriter ow = new ObjectWriter(db);
+ final ObjectId b = commit(ow, treeB, new ObjectId[] {});
+ final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
+ final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
+
+ Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
+ boolean merge = ourMerger.merge(new ObjectId[] { o, t });
+ assertFalse(merge);
+ }
+
+ public void testTrivialTwoWay_rightDFconflict1() throws Exception {
+ final DirCache treeB = DirCache.read(db);
+ final DirCache treeO = DirCache.read(db);
+ final DirCache treeT = DirCache.read(db);
+ {
+ final DirCacheBuilder b = treeB.builder();
+ final DirCacheBuilder o = treeO.builder();
+ final DirCacheBuilder t = treeT.builder();
+
+ b.add(makeEntry("d/o", FileMode.REGULAR_FILE));
+ b.add(makeEntry("d/t", FileMode.REGULAR_FILE));
+
+ o.add(makeEntry("d/o", FileMode.REGULAR_FILE));
+ o.add(makeEntry("d/t", FileMode.REGULAR_FILE, "o !"));
+
+ t.add(makeEntry("d", FileMode.REGULAR_FILE));
+
+ b.finish();
+ o.finish();
+ t.finish();
+ }
+
+ final ObjectWriter ow = new ObjectWriter(db);
+ final ObjectId b = commit(ow, treeB, new ObjectId[] {});
+ final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
+ final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
+
+ Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
+ boolean merge = ourMerger.merge(new ObjectId[] { o, t });
+ assertFalse(merge);
+ }
+
+ public void testTrivialTwoWay_leftDFconflict2() throws Exception {
+ final DirCache treeB = DirCache.read(db);
+ final DirCache treeO = DirCache.read(db);
+ final DirCache treeT = DirCache.read(db);
+ {
+ final DirCacheBuilder b = treeB.builder();
+ final DirCacheBuilder o = treeO.builder();
+ final DirCacheBuilder t = treeT.builder();
+
+ b.add(makeEntry("d", FileMode.REGULAR_FILE));
+
+ o.add(makeEntry("d", FileMode.REGULAR_FILE, "o !"));
+
+ t.add(makeEntry("d/o", FileMode.REGULAR_FILE));
+
+ b.finish();
+ o.finish();
+ t.finish();
+ }
+
+ final ObjectWriter ow = new ObjectWriter(db);
+ final ObjectId b = commit(ow, treeB, new ObjectId[] {});
+ final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
+ final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
+
+ Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
+ boolean merge = ourMerger.merge(new ObjectId[] { o, t });
+ assertFalse(merge);
+ }
+
+ public void testTrivialTwoWay_rightDFconflict2() throws Exception {
+ final DirCache treeB = DirCache.read(db);
+ final DirCache treeO = DirCache.read(db);
+ final DirCache treeT = DirCache.read(db);
+ {
+ final DirCacheBuilder b = treeB.builder();
+ final DirCacheBuilder o = treeO.builder();
+ final DirCacheBuilder t = treeT.builder();
+
+ b.add(makeEntry("d", FileMode.REGULAR_FILE));
+
+ o.add(makeEntry("d/o", FileMode.REGULAR_FILE));
+
+ t.add(makeEntry("d", FileMode.REGULAR_FILE, "t !"));
+
+ b.finish();
+ o.finish();
+ t.finish();
+ }
+
+ final ObjectWriter ow = new ObjectWriter(db);
+ final ObjectId b = commit(ow, treeB, new ObjectId[] {});
+ final ObjectId o = commit(ow, treeO, new ObjectId[] { b });
+ final ObjectId t = commit(ow, treeT, new ObjectId[] { b });
+
+ Merger ourMerger = MergeStrategy.SIMPLE_TWO_WAY_IN_CORE.newMerger(db);
+ boolean merge = ourMerger.merge(new ObjectId[] { o, t });
+ assertFalse(merge);
+ }
+
+ private void assertCorrectId(final DirCache treeT, final TreeWalk tw) {
+ assertEquals(treeT.getEntry(tw.getPathString()).getObjectId(), tw
+ .getObjectId(0));
+ }
+
+ private ObjectId commit(final ObjectWriter ow, final DirCache treeB,
+ final ObjectId[] parentIds) throws Exception {
+ final Commit c = new Commit(db);
+ c.setTreeId(treeB.writeTree(ow));
+ c.setAuthor(new PersonIdent("A U Thor", "a.u.thor", 1L, 0));
+ c.setCommitter(c.getAuthor());
+ c.setParentIds(parentIds);
+ c.setMessage("Tree " + c.getTreeId().name());
+ return ow.writeCommit(c);
+ }
+
+ private DirCacheEntry makeEntry(final String path, final FileMode mode)
+ throws Exception {
+ return makeEntry(path, mode, path);
+ }
+
+ private DirCacheEntry makeEntry(final String path, final FileMode mode,
+ final String content) throws Exception {
+ final DirCacheEntry ent = new DirCacheEntry(path);
+ ent.setFileMode(mode);
+ final byte[] contentBytes = Constants.encode(content);
+ ent.setObjectId(new ObjectWriter(db).computeBlobSha1(
+ contentBytes.length, new ByteArrayInputStream(contentBytes)));
+ return ent;
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/EditListTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/EditListTest.java
new file mode 100644
index 0000000000..c265bc097b
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/EditListTest.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.patch;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jgit.diff.Edit;
+import org.eclipse.jgit.diff.EditList;
+
+public class EditListTest extends TestCase {
+ public void testHunkHeader() throws IOException {
+ final Patch p = parseTestPatchFile("testGetText_BothISO88591.patch");
+ final FileHeader fh = p.getFiles().get(0);
+
+ final EditList list0 = fh.getHunks().get(0).toEditList();
+ assertEquals(1, list0.size());
+ assertEquals(new Edit(4 - 1, 5 - 1, 4 - 1, 5 - 1), list0.get(0));
+
+ final EditList list1 = fh.getHunks().get(1).toEditList();
+ assertEquals(1, list1.size());
+ assertEquals(new Edit(16 - 1, 17 - 1, 16 - 1, 17 - 1), list1.get(0));
+ }
+
+ public void testFileHeader() throws IOException {
+ final Patch p = parseTestPatchFile("testGetText_BothISO88591.patch");
+ final FileHeader fh = p.getFiles().get(0);
+ final EditList e = fh.toEditList();
+ assertEquals(2, e.size());
+ assertEquals(new Edit(4 - 1, 5 - 1, 4 - 1, 5 - 1), e.get(0));
+ assertEquals(new Edit(16 - 1, 17 - 1, 16 - 1, 17 - 1), e.get(1));
+ }
+
+ public void testTypes() throws IOException {
+ final Patch p = parseTestPatchFile("testEditList_Types.patch");
+ final FileHeader fh = p.getFiles().get(0);
+ final EditList e = fh.toEditList();
+ assertEquals(3, e.size());
+ assertEquals(new Edit(3 - 1, 3 - 1, 3 - 1, 4 - 1), e.get(0));
+ assertEquals(new Edit(17 - 1, 19 - 1, 18 - 1, 18 - 1), e.get(1));
+ assertEquals(new Edit(23 - 1, 25 - 1, 22 - 1, 28 - 1), e.get(2));
+ }
+
+ private Patch parseTestPatchFile(final String patchFile) throws IOException {
+ final InputStream in = getClass().getResourceAsStream(patchFile);
+ if (in == null) {
+ fail("No " + patchFile + " test vector");
+ return null; // Never happens
+ }
+ try {
+ final Patch p = new Patch();
+ p.parse(in);
+ return p;
+ } finally {
+ in.close();
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/FileHeaderTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/FileHeaderTest.java
new file mode 100644
index 0000000000..8d9e302a82
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/FileHeaderTest.java
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.patch;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+
+public class FileHeaderTest extends TestCase {
+ public void testParseGitFileName_Empty() {
+ final FileHeader fh = data("");
+ assertEquals(-1, fh.parseGitFileName(0, fh.buf.length));
+ assertNotNull(fh.getHunks());
+ assertTrue(fh.getHunks().isEmpty());
+ assertFalse(fh.hasMetaDataChanges());
+ }
+
+ public void testParseGitFileName_NoLF() {
+ final FileHeader fh = data("a/ b/");
+ assertEquals(-1, fh.parseGitFileName(0, fh.buf.length));
+ }
+
+ public void testParseGitFileName_NoSecondLine() {
+ final FileHeader fh = data("\n");
+ assertEquals(-1, fh.parseGitFileName(0, fh.buf.length));
+ }
+
+ public void testParseGitFileName_EmptyHeader() {
+ final FileHeader fh = data("\n\n");
+ assertEquals(1, fh.parseGitFileName(0, fh.buf.length));
+ }
+
+ public void testParseGitFileName_Foo() {
+ final String name = "foo";
+ final FileHeader fh = header(name);
+ assertEquals(gitLine(name).length(), fh.parseGitFileName(0,
+ fh.buf.length));
+ assertEquals(name, fh.getOldName());
+ assertSame(fh.getOldName(), fh.getNewName());
+ assertFalse(fh.hasMetaDataChanges());
+ }
+
+ public void testParseGitFileName_FailFooBar() {
+ final FileHeader fh = data("a/foo b/bar\n-");
+ assertTrue(fh.parseGitFileName(0, fh.buf.length) > 0);
+ assertNull(fh.getOldName());
+ assertNull(fh.getNewName());
+ assertFalse(fh.hasMetaDataChanges());
+ }
+
+ public void testParseGitFileName_FooSpBar() {
+ final String name = "foo bar";
+ final FileHeader fh = header(name);
+ assertEquals(gitLine(name).length(), fh.parseGitFileName(0,
+ fh.buf.length));
+ assertEquals(name, fh.getOldName());
+ assertSame(fh.getOldName(), fh.getNewName());
+ assertFalse(fh.hasMetaDataChanges());
+ }
+
+ public void testParseGitFileName_DqFooTabBar() {
+ final String name = "foo\tbar";
+ final String dqName = "foo\\tbar";
+ final FileHeader fh = dqHeader(dqName);
+ assertEquals(dqGitLine(dqName).length(), fh.parseGitFileName(0,
+ fh.buf.length));
+ assertEquals(name, fh.getOldName());
+ assertSame(fh.getOldName(), fh.getNewName());
+ assertFalse(fh.hasMetaDataChanges());
+ }
+
+ public void testParseGitFileName_DqFooSpLfNulBar() {
+ final String name = "foo \n\0bar";
+ final String dqName = "foo \\n\\0bar";
+ final FileHeader fh = dqHeader(dqName);
+ assertEquals(dqGitLine(dqName).length(), fh.parseGitFileName(0,
+ fh.buf.length));
+ assertEquals(name, fh.getOldName());
+ assertSame(fh.getOldName(), fh.getNewName());
+ assertFalse(fh.hasMetaDataChanges());
+ }
+
+ public void testParseGitFileName_SrcFooC() {
+ final String name = "src/foo/bar/argh/code.c";
+ final FileHeader fh = header(name);
+ assertEquals(gitLine(name).length(), fh.parseGitFileName(0,
+ fh.buf.length));
+ assertEquals(name, fh.getOldName());
+ assertSame(fh.getOldName(), fh.getNewName());
+ assertFalse(fh.hasMetaDataChanges());
+ }
+
+ public void testParseGitFileName_SrcFooCNonStandardPrefix() {
+ final String name = "src/foo/bar/argh/code.c";
+ final String header = "project-v-1.0/" + name + " mydev/" + name + "\n";
+ final FileHeader fh = data(header + "-");
+ assertEquals(header.length(), fh.parseGitFileName(0, fh.buf.length));
+ assertEquals(name, fh.getOldName());
+ assertSame(fh.getOldName(), fh.getNewName());
+ assertFalse(fh.hasMetaDataChanges());
+ }
+
+ public void testParseUnicodeName_NewFile() {
+ final FileHeader fh = data("diff --git \"a/\\303\\205ngstr\\303\\266m\" \"b/\\303\\205ngstr\\303\\266m\"\n"
+ + "new file mode 100644\n"
+ + "index 0000000..7898192\n"
+ + "--- /dev/null\n"
+ + "+++ \"b/\\303\\205ngstr\\303\\266m\"\n"
+ + "@@ -0,0 +1 @@\n" + "+a\n");
+ assertParse(fh);
+
+ assertEquals("/dev/null", fh.getOldName());
+ assertSame(FileHeader.DEV_NULL, fh.getOldName());
+ assertEquals("\u00c5ngstr\u00f6m", fh.getNewName());
+
+ assertSame(FileHeader.ChangeType.ADD, fh.getChangeType());
+ assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
+ assertTrue(fh.hasMetaDataChanges());
+
+ assertSame(FileMode.MISSING, fh.getOldMode());
+ assertSame(FileMode.REGULAR_FILE, fh.getNewMode());
+
+ assertEquals("0000000", fh.getOldId().name());
+ assertEquals("7898192", fh.getNewId().name());
+ assertEquals(0, fh.getScore());
+ }
+
+ public void testParseUnicodeName_DeleteFile() {
+ final FileHeader fh = data("diff --git \"a/\\303\\205ngstr\\303\\266m\" \"b/\\303\\205ngstr\\303\\266m\"\n"
+ + "deleted file mode 100644\n"
+ + "index 7898192..0000000\n"
+ + "--- \"a/\\303\\205ngstr\\303\\266m\"\n"
+ + "+++ /dev/null\n"
+ + "@@ -1 +0,0 @@\n" + "-a\n");
+ assertParse(fh);
+
+ assertEquals("\u00c5ngstr\u00f6m", fh.getOldName());
+ assertEquals("/dev/null", fh.getNewName());
+ assertSame(FileHeader.DEV_NULL, fh.getNewName());
+
+ assertSame(FileHeader.ChangeType.DELETE, fh.getChangeType());
+ assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
+ assertTrue(fh.hasMetaDataChanges());
+
+ assertSame(FileMode.REGULAR_FILE, fh.getOldMode());
+ assertSame(FileMode.MISSING, fh.getNewMode());
+
+ assertEquals("7898192", fh.getOldId().name());
+ assertEquals("0000000", fh.getNewId().name());
+ assertEquals(0, fh.getScore());
+ }
+
+ public void testParseModeChange() {
+ final FileHeader fh = data("diff --git a/a b b/a b\n"
+ + "old mode 100644\n" + "new mode 100755\n");
+ assertParse(fh);
+ assertEquals("a b", fh.getOldName());
+ assertEquals("a b", fh.getNewName());
+
+ assertSame(FileHeader.ChangeType.MODIFY, fh.getChangeType());
+ assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
+ assertTrue(fh.hasMetaDataChanges());
+
+ assertNull(fh.getOldId());
+ assertNull(fh.getNewId());
+
+ assertSame(FileMode.REGULAR_FILE, fh.getOldMode());
+ assertSame(FileMode.EXECUTABLE_FILE, fh.getNewMode());
+ assertEquals(0, fh.getScore());
+ }
+
+ public void testParseRename100_NewStyle() {
+ final FileHeader fh = data("diff --git a/a b/ c/\\303\\205ngstr\\303\\266m\n"
+ + "similarity index 100%\n"
+ + "rename from a\n"
+ + "rename to \" c/\\303\\205ngstr\\303\\266m\"\n");
+ int ptr = fh.parseGitFileName(0, fh.buf.length);
+ assertTrue(ptr > 0);
+ assertNull(fh.getOldName()); // can't parse names on a rename
+ assertNull(fh.getNewName());
+
+ ptr = fh.parseGitHeaders(ptr, fh.buf.length);
+ assertTrue(ptr > 0);
+
+ assertEquals("a", fh.getOldName());
+ assertEquals(" c/\u00c5ngstr\u00f6m", fh.getNewName());
+
+ assertSame(FileHeader.ChangeType.RENAME, fh.getChangeType());
+ assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
+ assertTrue(fh.hasMetaDataChanges());
+
+ assertNull(fh.getOldId());
+ assertNull(fh.getNewId());
+
+ assertNull(fh.getOldMode());
+ assertNull(fh.getNewMode());
+
+ assertEquals(100, fh.getScore());
+ }
+
+ public void testParseRename100_OldStyle() {
+ final FileHeader fh = data("diff --git a/a b/ c/\\303\\205ngstr\\303\\266m\n"
+ + "similarity index 100%\n"
+ + "rename old a\n"
+ + "rename new \" c/\\303\\205ngstr\\303\\266m\"\n");
+ int ptr = fh.parseGitFileName(0, fh.buf.length);
+ assertTrue(ptr > 0);
+ assertNull(fh.getOldName()); // can't parse names on a rename
+ assertNull(fh.getNewName());
+
+ ptr = fh.parseGitHeaders(ptr, fh.buf.length);
+ assertTrue(ptr > 0);
+
+ assertEquals("a", fh.getOldName());
+ assertEquals(" c/\u00c5ngstr\u00f6m", fh.getNewName());
+
+ assertSame(FileHeader.ChangeType.RENAME, fh.getChangeType());
+ assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
+ assertTrue(fh.hasMetaDataChanges());
+
+ assertNull(fh.getOldId());
+ assertNull(fh.getNewId());
+
+ assertNull(fh.getOldMode());
+ assertNull(fh.getNewMode());
+
+ assertEquals(100, fh.getScore());
+ }
+
+ public void testParseCopy100() {
+ final FileHeader fh = data("diff --git a/a b/ c/\\303\\205ngstr\\303\\266m\n"
+ + "similarity index 100%\n"
+ + "copy from a\n"
+ + "copy to \" c/\\303\\205ngstr\\303\\266m\"\n");
+ int ptr = fh.parseGitFileName(0, fh.buf.length);
+ assertTrue(ptr > 0);
+ assertNull(fh.getOldName()); // can't parse names on a copy
+ assertNull(fh.getNewName());
+
+ ptr = fh.parseGitHeaders(ptr, fh.buf.length);
+ assertTrue(ptr > 0);
+
+ assertEquals("a", fh.getOldName());
+ assertEquals(" c/\u00c5ngstr\u00f6m", fh.getNewName());
+
+ assertSame(FileHeader.ChangeType.COPY, fh.getChangeType());
+ assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
+ assertTrue(fh.hasMetaDataChanges());
+
+ assertNull(fh.getOldId());
+ assertNull(fh.getNewId());
+
+ assertNull(fh.getOldMode());
+ assertNull(fh.getNewMode());
+
+ assertEquals(100, fh.getScore());
+ }
+
+ public void testParseFullIndexLine_WithMode() {
+ final String oid = "78981922613b2afb6025042ff6bd878ac1994e85";
+ final String nid = "61780798228d17af2d34fce4cfbdf35556832472";
+ final FileHeader fh = data("diff --git a/a b/a\n" + "index " + oid
+ + ".." + nid + " 100644\n" + "--- a/a\n" + "+++ b/a\n");
+ assertParse(fh);
+
+ assertEquals("a", fh.getOldName());
+ assertEquals("a", fh.getNewName());
+
+ assertSame(FileMode.REGULAR_FILE, fh.getOldMode());
+ assertSame(FileMode.REGULAR_FILE, fh.getNewMode());
+ assertFalse(fh.hasMetaDataChanges());
+
+ assertNotNull(fh.getOldId());
+ assertNotNull(fh.getNewId());
+
+ assertTrue(fh.getOldId().isComplete());
+ assertTrue(fh.getNewId().isComplete());
+
+ assertEquals(ObjectId.fromString(oid), fh.getOldId().toObjectId());
+ assertEquals(ObjectId.fromString(nid), fh.getNewId().toObjectId());
+ }
+
+ public void testParseFullIndexLine_NoMode() {
+ final String oid = "78981922613b2afb6025042ff6bd878ac1994e85";
+ final String nid = "61780798228d17af2d34fce4cfbdf35556832472";
+ final FileHeader fh = data("diff --git a/a b/a\n" + "index " + oid
+ + ".." + nid + "\n" + "--- a/a\n" + "+++ b/a\n");
+ assertParse(fh);
+
+ assertEquals("a", fh.getOldName());
+ assertEquals("a", fh.getNewName());
+ assertFalse(fh.hasMetaDataChanges());
+
+ assertNull(fh.getOldMode());
+ assertNull(fh.getNewMode());
+
+ assertNotNull(fh.getOldId());
+ assertNotNull(fh.getNewId());
+
+ assertTrue(fh.getOldId().isComplete());
+ assertTrue(fh.getNewId().isComplete());
+
+ assertEquals(ObjectId.fromString(oid), fh.getOldId().toObjectId());
+ assertEquals(ObjectId.fromString(nid), fh.getNewId().toObjectId());
+ }
+
+ public void testParseAbbrIndexLine_WithMode() {
+ final int a = 7;
+ final String oid = "78981922613b2afb6025042ff6bd878ac1994e85";
+ final String nid = "61780798228d17af2d34fce4cfbdf35556832472";
+ final FileHeader fh = data("diff --git a/a b/a\n" + "index "
+ + oid.substring(0, a - 1) + ".." + nid.substring(0, a - 1)
+ + " 100644\n" + "--- a/a\n" + "+++ b/a\n");
+ assertParse(fh);
+
+ assertEquals("a", fh.getOldName());
+ assertEquals("a", fh.getNewName());
+
+ assertSame(FileMode.REGULAR_FILE, fh.getOldMode());
+ assertSame(FileMode.REGULAR_FILE, fh.getNewMode());
+ assertFalse(fh.hasMetaDataChanges());
+
+ assertNotNull(fh.getOldId());
+ assertNotNull(fh.getNewId());
+
+ assertFalse(fh.getOldId().isComplete());
+ assertFalse(fh.getNewId().isComplete());
+
+ assertEquals(oid.substring(0, a - 1), fh.getOldId().name());
+ assertEquals(nid.substring(0, a - 1), fh.getNewId().name());
+
+ assertTrue(ObjectId.fromString(oid).startsWith(fh.getOldId()));
+ assertTrue(ObjectId.fromString(nid).startsWith(fh.getNewId()));
+ }
+
+ public void testParseAbbrIndexLine_NoMode() {
+ final int a = 7;
+ final String oid = "78981922613b2afb6025042ff6bd878ac1994e85";
+ final String nid = "61780798228d17af2d34fce4cfbdf35556832472";
+ final FileHeader fh = data("diff --git a/a b/a\n" + "index "
+ + oid.substring(0, a - 1) + ".." + nid.substring(0, a - 1)
+ + "\n" + "--- a/a\n" + "+++ b/a\n");
+ assertParse(fh);
+
+ assertEquals("a", fh.getOldName());
+ assertEquals("a", fh.getNewName());
+
+ assertNull(fh.getOldMode());
+ assertNull(fh.getNewMode());
+ assertFalse(fh.hasMetaDataChanges());
+
+ assertNotNull(fh.getOldId());
+ assertNotNull(fh.getNewId());
+
+ assertFalse(fh.getOldId().isComplete());
+ assertFalse(fh.getNewId().isComplete());
+
+ assertEquals(oid.substring(0, a - 1), fh.getOldId().name());
+ assertEquals(nid.substring(0, a - 1), fh.getNewId().name());
+
+ assertTrue(ObjectId.fromString(oid).startsWith(fh.getOldId()));
+ assertTrue(ObjectId.fromString(nid).startsWith(fh.getNewId()));
+ }
+
+ private static void assertParse(final FileHeader fh) {
+ int ptr = fh.parseGitFileName(0, fh.buf.length);
+ assertTrue(ptr > 0);
+ ptr = fh.parseGitHeaders(ptr, fh.buf.length);
+ assertTrue(ptr > 0);
+ }
+
+ private static FileHeader data(final String in) {
+ return new FileHeader(Constants.encodeASCII(in), 0);
+ }
+
+ private static FileHeader header(final String path) {
+ return data(gitLine(path) + "--- " + path + "\n");
+ }
+
+ private static String gitLine(final String path) {
+ return "a/" + path + " b/" + path + "\n";
+ }
+
+ private static FileHeader dqHeader(final String path) {
+ return data(dqGitLine(path) + "--- " + path + "\n");
+ }
+
+ private static String dqGitLine(final String path) {
+ return "\"a/" + path + "\" \"b/" + path + "\"\n";
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/GetTextTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/GetTextTest.java
new file mode 100644
index 0000000000..8d06987fde
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/GetTextTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.patch;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.Charset;
+
+import junit.framework.TestCase;
+
+public class GetTextTest extends TestCase {
+ public void testGetText_BothISO88591() throws IOException {
+ final Charset cs = Charset.forName("ISO-8859-1");
+ final Patch p = parseTestPatchFile();
+ assertTrue(p.getErrors().isEmpty());
+ assertEquals(1, p.getFiles().size());
+ final FileHeader fh = p.getFiles().get(0);
+ assertEquals(2, fh.getHunks().size());
+ assertEquals(readTestPatchFile(cs), fh.getScriptText(cs, cs));
+ }
+
+ public void testGetText_NoBinary() throws IOException {
+ final Charset cs = Charset.forName("ISO-8859-1");
+ final Patch p = parseTestPatchFile();
+ assertTrue(p.getErrors().isEmpty());
+ assertEquals(1, p.getFiles().size());
+ final FileHeader fh = p.getFiles().get(0);
+ assertEquals(0, fh.getHunks().size());
+ assertEquals(readTestPatchFile(cs), fh.getScriptText(cs, cs));
+ }
+
+ public void testGetText_Convert() throws IOException {
+ final Charset csOld = Charset.forName("ISO-8859-1");
+ final Charset csNew = Charset.forName("UTF-8");
+ final Patch p = parseTestPatchFile();
+ assertTrue(p.getErrors().isEmpty());
+ assertEquals(1, p.getFiles().size());
+ final FileHeader fh = p.getFiles().get(0);
+ assertEquals(2, fh.getHunks().size());
+
+ // Read the original file as ISO-8859-1 and fix up the one place
+ // where we changed the character encoding. That makes the exp
+ // string match what we really expect to get back.
+ //
+ String exp = readTestPatchFile(csOld);
+ exp = exp.replace("\303\205ngstr\303\266m", "\u00c5ngstr\u00f6m");
+
+ assertEquals(exp, fh.getScriptText(csOld, csNew));
+ }
+
+ public void testGetText_DiffCc() throws IOException {
+ final Charset csOld = Charset.forName("ISO-8859-1");
+ final Charset csNew = Charset.forName("UTF-8");
+ final Patch p = parseTestPatchFile();
+ assertTrue(p.getErrors().isEmpty());
+ assertEquals(1, p.getFiles().size());
+ final CombinedFileHeader fh = (CombinedFileHeader) p.getFiles().get(0);
+ assertEquals(1, fh.getHunks().size());
+
+ // Read the original file as ISO-8859-1 and fix up the one place
+ // where we changed the character encoding. That makes the exp
+ // string match what we really expect to get back.
+ //
+ String exp = readTestPatchFile(csOld);
+ exp = exp.replace("\303\205ngstr\303\266m", "\u00c5ngstr\u00f6m");
+
+ assertEquals(exp, fh
+ .getScriptText(new Charset[] { csNew, csOld, csNew }));
+ }
+
+ private Patch parseTestPatchFile() throws IOException {
+ final String patchFile = getName() + ".patch";
+ final InputStream in = getClass().getResourceAsStream(patchFile);
+ if (in == null) {
+ fail("No " + patchFile + " test vector");
+ return null; // Never happens
+ }
+ try {
+ final Patch p = new Patch();
+ p.parse(in);
+ return p;
+ } finally {
+ in.close();
+ }
+ }
+
+ private String readTestPatchFile(final Charset cs) throws IOException {
+ final String patchFile = getName() + ".patch";
+ final InputStream in = getClass().getResourceAsStream(patchFile);
+ if (in == null) {
+ fail("No " + patchFile + " test vector");
+ return null; // Never happens
+ }
+ try {
+ final InputStreamReader r = new InputStreamReader(in, cs);
+ char[] tmp = new char[2048];
+ final StringBuilder s = new StringBuilder();
+ int n;
+ while ((n = r.read(tmp)) > 0)
+ s.append(tmp, 0, n);
+ return s.toString();
+ } finally {
+ in.close();
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcErrorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcErrorTest.java
new file mode 100644
index 0000000000..f2bae6eb19
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcErrorTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.patch;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+
+public class PatchCcErrorTest extends TestCase {
+ public void testError_CcTruncatedOld() throws IOException {
+ final Patch p = parseTestPatchFile();
+ assertEquals(1, p.getFiles().size());
+ assertEquals(3, p.getErrors().size());
+ {
+ final FormatError e = p.getErrors().get(0);
+ assertSame(FormatError.Severity.ERROR, e.getSeverity());
+ assertEquals(
+ "Truncated hunk, at least 1 lines is missing for ancestor 1",
+ e.getMessage());
+ assertEquals(346, e.getOffset());
+ assertTrue(e.getLineText().startsWith(
+ "@@@ -55,12 -163,13 +163,15 @@@ public "));
+ }
+ {
+ final FormatError e = p.getErrors().get(1);
+ assertSame(FormatError.Severity.ERROR, e.getSeverity());
+ assertEquals(
+ "Truncated hunk, at least 2 lines is missing for ancestor 2",
+ e.getMessage());
+ assertEquals(346, e.getOffset());
+ assertTrue(e.getLineText().startsWith(
+ "@@@ -55,12 -163,13 +163,15 @@@ public "));
+ }
+ {
+ final FormatError e = p.getErrors().get(2);
+ assertSame(FormatError.Severity.ERROR, e.getSeverity());
+ assertEquals("Truncated hunk, at least 3 new lines is missing", e
+ .getMessage());
+ assertEquals(346, e.getOffset());
+ assertTrue(e.getLineText().startsWith(
+ "@@@ -55,12 -163,13 +163,15 @@@ public "));
+ }
+ }
+
+ private Patch parseTestPatchFile() throws IOException {
+ final String patchFile = getName() + ".patch";
+ final InputStream in = getClass().getResourceAsStream(patchFile);
+ if (in == null) {
+ fail("No " + patchFile + " test vector");
+ return null; // Never happens
+ }
+ try {
+ final Patch p = new Patch();
+ p.parse(in);
+ return p;
+ } finally {
+ in.close();
+ }
+ }
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcTest.java
new file mode 100644
index 0000000000..e97d373d9a
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchCcTest.java
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.patch;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.jgit.lib.FileMode;
+
+import junit.framework.TestCase;
+
+public class PatchCcTest extends TestCase {
+ public void testParse_OneFileCc() throws IOException {
+ final Patch p = parseTestPatchFile();
+ assertEquals(1, p.getFiles().size());
+ assertTrue(p.getErrors().isEmpty());
+
+ final CombinedFileHeader cfh = (CombinedFileHeader) p.getFiles().get(0);
+
+ assertEquals("org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java",
+ cfh.getNewName());
+ assertEquals(cfh.getNewName(), cfh.getOldName());
+
+ assertEquals(98, cfh.startOffset);
+
+ assertEquals(2, cfh.getParentCount());
+ assertSame(cfh.getOldId(0), cfh.getOldId());
+ assertEquals("169356b", cfh.getOldId(0).name());
+ assertEquals("dd8c317", cfh.getOldId(1).name());
+ assertEquals("fd85931", cfh.getNewId().name());
+
+ assertSame(cfh.getOldMode(0), cfh.getOldMode());
+ assertSame(FileMode.REGULAR_FILE, cfh.getOldMode(0));
+ assertSame(FileMode.REGULAR_FILE, cfh.getOldMode(1));
+ assertSame(FileMode.EXECUTABLE_FILE, cfh.getNewMode());
+ assertSame(FileHeader.ChangeType.MODIFY, cfh.getChangeType());
+ assertSame(FileHeader.PatchType.UNIFIED, cfh.getPatchType());
+
+ assertEquals(1, cfh.getHunks().size());
+ {
+ final CombinedHunkHeader h = cfh.getHunks().get(0);
+
+ assertSame(cfh, h.getFileHeader());
+ assertEquals(346, h.startOffset);
+ assertEquals(764, h.endOffset);
+
+ assertSame(h.getOldImage(0), h.getOldImage());
+ assertSame(cfh.getOldId(0), h.getOldImage(0).getId());
+ assertSame(cfh.getOldId(1), h.getOldImage(1).getId());
+
+ assertEquals(55, h.getOldImage(0).getStartLine());
+ assertEquals(12, h.getOldImage(0).getLineCount());
+ assertEquals(3, h.getOldImage(0).getLinesAdded());
+ assertEquals(0, h.getOldImage(0).getLinesDeleted());
+
+ assertEquals(163, h.getOldImage(1).getStartLine());
+ assertEquals(13, h.getOldImage(1).getLineCount());
+ assertEquals(2, h.getOldImage(1).getLinesAdded());
+ assertEquals(0, h.getOldImage(1).getLinesDeleted());
+
+ assertEquals(163, h.getNewStartLine());
+ assertEquals(15, h.getNewLineCount());
+
+ assertEquals(10, h.getLinesContext());
+ }
+ }
+
+ public void testParse_CcNewFile() throws IOException {
+ final Patch p = parseTestPatchFile();
+ assertEquals(1, p.getFiles().size());
+ assertTrue(p.getErrors().isEmpty());
+
+ final CombinedFileHeader cfh = (CombinedFileHeader) p.getFiles().get(0);
+
+ assertSame(FileHeader.DEV_NULL, cfh.getOldName());
+ assertEquals("d", cfh.getNewName());
+
+ assertEquals(187, cfh.startOffset);
+
+ assertEquals(2, cfh.getParentCount());
+ assertSame(cfh.getOldId(0), cfh.getOldId());
+ assertEquals("0000000", cfh.getOldId(0).name());
+ assertEquals("0000000", cfh.getOldId(1).name());
+ assertEquals("4bcfe98", cfh.getNewId().name());
+
+ assertSame(cfh.getOldMode(0), cfh.getOldMode());
+ assertSame(FileMode.MISSING, cfh.getOldMode(0));
+ assertSame(FileMode.MISSING, cfh.getOldMode(1));
+ assertSame(FileMode.REGULAR_FILE, cfh.getNewMode());
+ assertSame(FileHeader.ChangeType.ADD, cfh.getChangeType());
+ assertSame(FileHeader.PatchType.UNIFIED, cfh.getPatchType());
+
+ assertEquals(1, cfh.getHunks().size());
+ {
+ final CombinedHunkHeader h = cfh.getHunks().get(0);
+
+ assertSame(cfh, h.getFileHeader());
+ assertEquals(273, h.startOffset);
+ assertEquals(300, h.endOffset);
+
+ assertSame(h.getOldImage(0), h.getOldImage());
+ assertSame(cfh.getOldId(0), h.getOldImage(0).getId());
+ assertSame(cfh.getOldId(1), h.getOldImage(1).getId());
+
+ assertEquals(1, h.getOldImage(0).getStartLine());
+ assertEquals(0, h.getOldImage(0).getLineCount());
+ assertEquals(1, h.getOldImage(0).getLinesAdded());
+ assertEquals(0, h.getOldImage(0).getLinesDeleted());
+
+ assertEquals(1, h.getOldImage(1).getStartLine());
+ assertEquals(0, h.getOldImage(1).getLineCount());
+ assertEquals(1, h.getOldImage(1).getLinesAdded());
+ assertEquals(0, h.getOldImage(1).getLinesDeleted());
+
+ assertEquals(1, h.getNewStartLine());
+ assertEquals(1, h.getNewLineCount());
+
+ assertEquals(0, h.getLinesContext());
+ }
+ }
+
+ public void testParse_CcDeleteFile() throws IOException {
+ final Patch p = parseTestPatchFile();
+ assertEquals(1, p.getFiles().size());
+ assertTrue(p.getErrors().isEmpty());
+
+ final CombinedFileHeader cfh = (CombinedFileHeader) p.getFiles().get(0);
+
+ assertEquals("a", cfh.getOldName());
+ assertSame(FileHeader.DEV_NULL, cfh.getNewName());
+
+ assertEquals(187, cfh.startOffset);
+
+ assertEquals(2, cfh.getParentCount());
+ assertSame(cfh.getOldId(0), cfh.getOldId());
+ assertEquals("7898192", cfh.getOldId(0).name());
+ assertEquals("2e65efe", cfh.getOldId(1).name());
+ assertEquals("0000000", cfh.getNewId().name());
+
+ assertSame(cfh.getOldMode(0), cfh.getOldMode());
+ assertSame(FileMode.REGULAR_FILE, cfh.getOldMode(0));
+ assertSame(FileMode.REGULAR_FILE, cfh.getOldMode(1));
+ assertSame(FileMode.MISSING, cfh.getNewMode());
+ assertSame(FileHeader.ChangeType.DELETE, cfh.getChangeType());
+ assertSame(FileHeader.PatchType.UNIFIED, cfh.getPatchType());
+
+ assertTrue(cfh.getHunks().isEmpty());
+ }
+
+ private Patch parseTestPatchFile() throws IOException {
+ final String patchFile = getName() + ".patch";
+ final InputStream in = getClass().getResourceAsStream(patchFile);
+ if (in == null) {
+ fail("No " + patchFile + " test vector");
+ return null; // Never happens
+ }
+ try {
+ final Patch p = new Patch();
+ p.parse(in);
+ return p;
+ } finally {
+ in.close();
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchErrorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchErrorTest.java
new file mode 100644
index 0000000000..62a107130e
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchErrorTest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2008-2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.patch;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+
+public class PatchErrorTest extends TestCase {
+ public void testError_DisconnectedHunk() throws IOException {
+ final Patch p = parseTestPatchFile();
+ assertEquals(1, p.getFiles().size());
+ {
+ final FileHeader fh = p.getFiles().get(0);
+ assertEquals(
+ "org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java",
+ fh.getNewName());
+ assertEquals(1, fh.getHunks().size());
+ }
+
+ assertEquals(1, p.getErrors().size());
+ final FormatError e = p.getErrors().get(0);
+ assertSame(FormatError.Severity.ERROR, e.getSeverity());
+ assertEquals("Hunk disconnected from file", e.getMessage());
+ assertEquals(18, e.getOffset());
+ assertTrue(e.getLineText().startsWith("@@ -109,4 +109,11 @@ assert"));
+ }
+
+ public void testError_TruncatedOld() throws IOException {
+ final Patch p = parseTestPatchFile();
+ assertEquals(1, p.getFiles().size());
+ assertEquals(1, p.getErrors().size());
+
+ final FormatError e = p.getErrors().get(0);
+ assertSame(FormatError.Severity.ERROR, e.getSeverity());
+ assertEquals("Truncated hunk, at least 1 old lines is missing", e
+ .getMessage());
+ assertEquals(313, e.getOffset());
+ assertTrue(e.getLineText().startsWith("@@ -236,9 +236,9 @@ protected "));
+ }
+
+ public void testError_TruncatedNew() throws IOException {
+ final Patch p = parseTestPatchFile();
+ assertEquals(1, p.getFiles().size());
+ assertEquals(1, p.getErrors().size());
+
+ final FormatError e = p.getErrors().get(0);
+ assertSame(FormatError.Severity.ERROR, e.getSeverity());
+ assertEquals("Truncated hunk, at least 1 new lines is missing", e
+ .getMessage());
+ assertEquals(313, e.getOffset());
+ assertTrue(e.getLineText().startsWith("@@ -236,9 +236,9 @@ protected "));
+ }
+
+ public void testError_BodyTooLong() throws IOException {
+ final Patch p = parseTestPatchFile();
+ assertEquals(1, p.getFiles().size());
+ assertEquals(1, p.getErrors().size());
+
+ final FormatError e = p.getErrors().get(0);
+ assertSame(FormatError.Severity.WARNING, e.getSeverity());
+ assertEquals("Hunk header 4:11 does not match body line count of 4:12",
+ e.getMessage());
+ assertEquals(349, e.getOffset());
+ assertTrue(e.getLineText().startsWith("@@ -109,4 +109,11 @@ assert"));
+ }
+
+ public void testError_GarbageBetweenFiles() throws IOException {
+ final Patch p = parseTestPatchFile();
+ assertEquals(2, p.getFiles().size());
+ {
+ final FileHeader fh = p.getFiles().get(0);
+ assertEquals(
+ "org.eclipse.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java",
+ fh.getNewName());
+ assertEquals(1, fh.getHunks().size());
+ }
+ {
+ final FileHeader fh = p.getFiles().get(1);
+ assertEquals(
+ "org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java",
+ fh.getNewName());
+ assertEquals(1, fh.getHunks().size());
+ }
+
+ assertEquals(1, p.getErrors().size());
+ final FormatError e = p.getErrors().get(0);
+ assertSame(FormatError.Severity.WARNING, e.getSeverity());
+ assertEquals("Unexpected hunk trailer", e.getMessage());
+ assertEquals(926, e.getOffset());
+ assertEquals("I AM NOT HERE\n", e.getLineText());
+ }
+
+ public void testError_GitBinaryNoForwardHunk() throws IOException {
+ final Patch p = parseTestPatchFile();
+ assertEquals(2, p.getFiles().size());
+ {
+ final FileHeader fh = p.getFiles().get(0);
+ assertEquals("org.spearce.egit.ui/icons/toolbar/fetchd.png", fh
+ .getNewName());
+ assertSame(FileHeader.PatchType.GIT_BINARY, fh.getPatchType());
+ assertTrue(fh.getHunks().isEmpty());
+ assertNull(fh.getForwardBinaryHunk());
+ }
+ {
+ final FileHeader fh = p.getFiles().get(1);
+ assertEquals("org.spearce.egit.ui/icons/toolbar/fetche.png", fh
+ .getNewName());
+ assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
+ assertTrue(fh.getHunks().isEmpty());
+ assertNull(fh.getForwardBinaryHunk());
+ }
+
+ assertEquals(1, p.getErrors().size());
+ final FormatError e = p.getErrors().get(0);
+ assertSame(FormatError.Severity.ERROR, e.getSeverity());
+ assertEquals("Missing forward-image in GIT binary patch", e
+ .getMessage());
+ assertEquals(297, e.getOffset());
+ assertEquals("\n", e.getLineText());
+ }
+
+ private Patch parseTestPatchFile() throws IOException {
+ final String patchFile = getName() + ".patch";
+ final InputStream in = getClass().getResourceAsStream(patchFile);
+ if (in == null) {
+ fail("No " + patchFile + " test vector");
+ return null; // Never happens
+ }
+ try {
+ final Patch p = new Patch();
+ p.parse(in);
+ return p;
+ } finally {
+ in.close();
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchTest.java
new file mode 100644
index 0000000000..52d6e27ca8
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/patch/PatchTest.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2008-2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.patch;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+
+public class PatchTest extends TestCase {
+ public void testEmpty() {
+ final Patch p = new Patch();
+ assertTrue(p.getFiles().isEmpty());
+ assertTrue(p.getErrors().isEmpty());
+ }
+
+ public void testParse_ConfigCaseInsensitive() throws IOException {
+ final Patch p = parseTestPatchFile();
+ assertEquals(2, p.getFiles().size());
+ assertTrue(p.getErrors().isEmpty());
+
+ final FileHeader fRepositoryConfigTest = p.getFiles().get(0);
+ final FileHeader fRepositoryConfig = p.getFiles().get(1);
+
+ assertEquals(
+ "org.eclipse.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java",
+ fRepositoryConfigTest.getNewName());
+
+ assertEquals(
+ "org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java",
+ fRepositoryConfig.getNewName());
+
+ assertEquals(572, fRepositoryConfigTest.startOffset);
+ assertEquals(1490, fRepositoryConfig.startOffset);
+
+ assertEquals("da7e704", fRepositoryConfigTest.getOldId().name());
+ assertEquals("34ce04a", fRepositoryConfigTest.getNewId().name());
+ assertSame(FileHeader.PatchType.UNIFIED, fRepositoryConfigTest
+ .getPatchType());
+ assertSame(FileMode.REGULAR_FILE, fRepositoryConfigTest.getOldMode());
+ assertSame(FileMode.REGULAR_FILE, fRepositoryConfigTest.getNewMode());
+ assertEquals(1, fRepositoryConfigTest.getHunks().size());
+ {
+ final HunkHeader h = fRepositoryConfigTest.getHunks().get(0);
+ assertSame(fRepositoryConfigTest, h.getFileHeader());
+ assertEquals(921, h.startOffset);
+ assertEquals(109, h.getOldImage().getStartLine());
+ assertEquals(4, h.getOldImage().getLineCount());
+ assertEquals(109, h.getNewStartLine());
+ assertEquals(11, h.getNewLineCount());
+
+ assertEquals(4, h.getLinesContext());
+ assertEquals(7, h.getOldImage().getLinesAdded());
+ assertEquals(0, h.getOldImage().getLinesDeleted());
+ assertSame(fRepositoryConfigTest.getOldId(), h.getOldImage()
+ .getId());
+
+ assertEquals(1490, h.endOffset);
+ }
+
+ assertEquals("45c2f8a", fRepositoryConfig.getOldId().name());
+ assertEquals("3291bba", fRepositoryConfig.getNewId().name());
+ assertSame(FileHeader.PatchType.UNIFIED, fRepositoryConfig
+ .getPatchType());
+ assertSame(FileMode.REGULAR_FILE, fRepositoryConfig.getOldMode());
+ assertSame(FileMode.REGULAR_FILE, fRepositoryConfig.getNewMode());
+ assertEquals(3, fRepositoryConfig.getHunks().size());
+ {
+ final HunkHeader h = fRepositoryConfig.getHunks().get(0);
+ assertSame(fRepositoryConfig, h.getFileHeader());
+ assertEquals(1803, h.startOffset);
+ assertEquals(236, h.getOldImage().getStartLine());
+ assertEquals(9, h.getOldImage().getLineCount());
+ assertEquals(236, h.getNewStartLine());
+ assertEquals(9, h.getNewLineCount());
+
+ assertEquals(7, h.getLinesContext());
+ assertEquals(2, h.getOldImage().getLinesAdded());
+ assertEquals(2, h.getOldImage().getLinesDeleted());
+ assertSame(fRepositoryConfig.getOldId(), h.getOldImage().getId());
+
+ assertEquals(2434, h.endOffset);
+ }
+ {
+ final HunkHeader h = fRepositoryConfig.getHunks().get(1);
+ assertEquals(2434, h.startOffset);
+ assertEquals(300, h.getOldImage().getStartLine());
+ assertEquals(7, h.getOldImage().getLineCount());
+ assertEquals(300, h.getNewStartLine());
+ assertEquals(7, h.getNewLineCount());
+
+ assertEquals(6, h.getLinesContext());
+ assertEquals(1, h.getOldImage().getLinesAdded());
+ assertEquals(1, h.getOldImage().getLinesDeleted());
+
+ assertEquals(2816, h.endOffset);
+ }
+ {
+ final HunkHeader h = fRepositoryConfig.getHunks().get(2);
+ assertEquals(2816, h.startOffset);
+ assertEquals(954, h.getOldImage().getStartLine());
+ assertEquals(7, h.getOldImage().getLineCount());
+ assertEquals(954, h.getNewStartLine());
+ assertEquals(7, h.getNewLineCount());
+
+ assertEquals(6, h.getLinesContext());
+ assertEquals(1, h.getOldImage().getLinesAdded());
+ assertEquals(1, h.getOldImage().getLinesDeleted());
+
+ assertEquals(3035, h.endOffset);
+ }
+ }
+
+ public void testParse_NoBinary() throws IOException {
+ final Patch p = parseTestPatchFile();
+ assertEquals(5, p.getFiles().size());
+ assertTrue(p.getErrors().isEmpty());
+
+ for (int i = 0; i < 4; i++) {
+ final FileHeader fh = p.getFiles().get(i);
+ assertSame(FileHeader.ChangeType.ADD, fh.getChangeType());
+ assertNotNull(fh.getOldId());
+ assertNotNull(fh.getNewId());
+ assertEquals("0000000", fh.getOldId().name());
+ assertSame(FileMode.MISSING, fh.getOldMode());
+ assertSame(FileMode.REGULAR_FILE, fh.getNewMode());
+ assertTrue(fh.getNewName().startsWith(
+ "org.spearce.egit.ui/icons/toolbar/"));
+ assertSame(FileHeader.PatchType.BINARY, fh.getPatchType());
+ assertTrue(fh.getHunks().isEmpty());
+ assertTrue(fh.hasMetaDataChanges());
+
+ assertNull(fh.getForwardBinaryHunk());
+ assertNull(fh.getReverseBinaryHunk());
+ }
+
+ final FileHeader fh = p.getFiles().get(4);
+ assertEquals("org.spearce.egit.ui/plugin.xml", fh.getNewName());
+ assertSame(FileHeader.ChangeType.MODIFY, fh.getChangeType());
+ assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
+ assertFalse(fh.hasMetaDataChanges());
+ assertEquals("ee8a5a0", fh.getNewId().name());
+ assertNull(fh.getForwardBinaryHunk());
+ assertNull(fh.getReverseBinaryHunk());
+ assertEquals(1, fh.getHunks().size());
+ assertEquals(272, fh.getHunks().get(0).getOldImage().getStartLine());
+ }
+
+ public void testParse_GitBinaryLiteral() throws IOException {
+ final Patch p = parseTestPatchFile();
+ final int[] binsizes = { 359, 393, 372, 404 };
+ assertEquals(5, p.getFiles().size());
+ assertTrue(p.getErrors().isEmpty());
+
+ for (int i = 0; i < 4; i++) {
+ final FileHeader fh = p.getFiles().get(i);
+ assertSame(FileHeader.ChangeType.ADD, fh.getChangeType());
+ assertNotNull(fh.getOldId());
+ assertNotNull(fh.getNewId());
+ assertEquals(ObjectId.zeroId().name(), fh.getOldId().name());
+ assertSame(FileMode.REGULAR_FILE, fh.getNewMode());
+ assertTrue(fh.getNewName().startsWith(
+ "org.spearce.egit.ui/icons/toolbar/"));
+ assertSame(FileHeader.PatchType.GIT_BINARY, fh.getPatchType());
+ assertTrue(fh.getHunks().isEmpty());
+ assertTrue(fh.hasMetaDataChanges());
+
+ final BinaryHunk fwd = fh.getForwardBinaryHunk();
+ final BinaryHunk rev = fh.getReverseBinaryHunk();
+ assertNotNull(fwd);
+ assertNotNull(rev);
+ assertEquals(binsizes[i], fwd.getSize());
+ assertEquals(0, rev.getSize());
+
+ assertSame(fh, fwd.getFileHeader());
+ assertSame(fh, rev.getFileHeader());
+
+ assertSame(BinaryHunk.Type.LITERAL_DEFLATED, fwd.getType());
+ assertSame(BinaryHunk.Type.LITERAL_DEFLATED, rev.getType());
+ }
+
+ final FileHeader fh = p.getFiles().get(4);
+ assertEquals("org.spearce.egit.ui/plugin.xml", fh.getNewName());
+ assertSame(FileHeader.ChangeType.MODIFY, fh.getChangeType());
+ assertSame(FileHeader.PatchType.UNIFIED, fh.getPatchType());
+ assertFalse(fh.hasMetaDataChanges());
+ assertEquals("ee8a5a0", fh.getNewId().name());
+ assertNull(fh.getForwardBinaryHunk());
+ assertNull(fh.getReverseBinaryHunk());
+ assertEquals(1, fh.getHunks().size());
+ assertEquals(272, fh.getHunks().get(0).getOldImage().getStartLine());
+ }
+
+ public void testParse_GitBinaryDelta() throws IOException {
+ final Patch p = parseTestPatchFile();
+ assertEquals(1, p.getFiles().size());
+ assertTrue(p.getErrors().isEmpty());
+
+ final FileHeader fh = p.getFiles().get(0);
+ assertTrue(fh.getNewName().startsWith("zero.bin"));
+ assertSame(FileHeader.ChangeType.MODIFY, fh.getChangeType());
+ assertSame(FileHeader.PatchType.GIT_BINARY, fh.getPatchType());
+ assertSame(FileMode.REGULAR_FILE, fh.getNewMode());
+
+ assertNotNull(fh.getOldId());
+ assertNotNull(fh.getNewId());
+ assertEquals("08e7df176454f3ee5eeda13efa0adaa54828dfd8", fh.getOldId()
+ .name());
+ assertEquals("d70d8710b6d32ff844af0ee7c247e4b4b051867f", fh.getNewId()
+ .name());
+
+ assertTrue(fh.getHunks().isEmpty());
+ assertFalse(fh.hasMetaDataChanges());
+
+ final BinaryHunk fwd = fh.getForwardBinaryHunk();
+ final BinaryHunk rev = fh.getReverseBinaryHunk();
+ assertNotNull(fwd);
+ assertNotNull(rev);
+ assertEquals(12, fwd.getSize());
+ assertEquals(11, rev.getSize());
+
+ assertSame(fh, fwd.getFileHeader());
+ assertSame(fh, rev.getFileHeader());
+
+ assertSame(BinaryHunk.Type.DELTA_DEFLATED, fwd.getType());
+ assertSame(BinaryHunk.Type.DELTA_DEFLATED, rev.getType());
+
+ assertEquals(496, fh.endOffset);
+ }
+
+ public void testParse_FixNoNewline() throws IOException {
+ final Patch p = parseTestPatchFile();
+ assertEquals(1, p.getFiles().size());
+ assertTrue(p.getErrors().isEmpty());
+
+ final FileHeader f = p.getFiles().get(0);
+
+ assertEquals("a", f.getNewName());
+ assertEquals(252, f.startOffset);
+
+ assertEquals("2e65efe", f.getOldId().name());
+ assertEquals("f2ad6c7", f.getNewId().name());
+ assertSame(FileHeader.PatchType.UNIFIED, f.getPatchType());
+ assertSame(FileMode.REGULAR_FILE, f.getOldMode());
+ assertSame(FileMode.REGULAR_FILE, f.getNewMode());
+ assertEquals(1, f.getHunks().size());
+ {
+ final HunkHeader h = f.getHunks().get(0);
+ assertSame(f, h.getFileHeader());
+ assertEquals(317, h.startOffset);
+ assertEquals(1, h.getOldImage().getStartLine());
+ assertEquals(1, h.getOldImage().getLineCount());
+ assertEquals(1, h.getNewStartLine());
+ assertEquals(1, h.getNewLineCount());
+
+ assertEquals(0, h.getLinesContext());
+ assertEquals(1, h.getOldImage().getLinesAdded());
+ assertEquals(1, h.getOldImage().getLinesDeleted());
+ assertSame(f.getOldId(), h.getOldImage().getId());
+
+ assertEquals(363, h.endOffset);
+ }
+ }
+
+ public void testParse_AddNoNewline() throws IOException {
+ final Patch p = parseTestPatchFile();
+ assertEquals(1, p.getFiles().size());
+ assertTrue(p.getErrors().isEmpty());
+
+ final FileHeader f = p.getFiles().get(0);
+
+ assertEquals("a", f.getNewName());
+ assertEquals(256, f.startOffset);
+
+ assertEquals("f2ad6c7", f.getOldId().name());
+ assertEquals("c59d9b6", f.getNewId().name());
+ assertSame(FileHeader.PatchType.UNIFIED, f.getPatchType());
+ assertSame(FileMode.REGULAR_FILE, f.getOldMode());
+ assertSame(FileMode.REGULAR_FILE, f.getNewMode());
+ assertEquals(1, f.getHunks().size());
+ {
+ final HunkHeader h = f.getHunks().get(0);
+ assertSame(f, h.getFileHeader());
+ assertEquals(321, h.startOffset);
+ assertEquals(1, h.getOldImage().getStartLine());
+ assertEquals(1, h.getOldImage().getLineCount());
+ assertEquals(1, h.getNewStartLine());
+ assertEquals(1, h.getNewLineCount());
+
+ assertEquals(0, h.getLinesContext());
+ assertEquals(1, h.getOldImage().getLinesAdded());
+ assertEquals(1, h.getOldImage().getLinesDeleted());
+ assertSame(f.getOldId(), h.getOldImage().getId());
+
+ assertEquals(367, h.endOffset);
+ }
+ }
+
+ private Patch parseTestPatchFile() throws IOException {
+ final String patchFile = getName() + ".patch";
+ final InputStream in = getClass().getResourceAsStream(patchFile);
+ if (in == null) {
+ fail("No " + patchFile + " test vector");
+ return null; // Never happens
+ }
+ try {
+ final Patch p = new Patch();
+ p.parse(in);
+ return p;
+ } finally {
+ in.close();
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/AlwaysEmptyRevQueueTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/AlwaysEmptyRevQueueTest.java
new file mode 100644
index 0000000000..d752501c12
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/AlwaysEmptyRevQueueTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.revwalk;
+
+public class AlwaysEmptyRevQueueTest extends RevWalkTestCase {
+ private final AbstractRevQueue q = AbstractRevQueue.EMPTY_QUEUE;
+
+ public void testEmpty() throws Exception {
+ assertNull(q.next());
+ assertTrue(q.everbodyHasFlag(RevWalk.UNINTERESTING));
+ assertFalse(q.anybodyHasFlag(RevWalk.UNINTERESTING));
+ assertEquals(0, q.outputType());
+ }
+
+ public void testClear() throws Exception {
+ q.clear();
+ testEmpty();
+ }
+
+ public void testAddFails() throws Exception {
+ try {
+ q.add(commit());
+ fail("Did not throw UnsupportedOperationException");
+ } catch (UnsupportedOperationException e) {
+ // expected result
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/DateRevQueueTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/DateRevQueueTest.java
new file mode 100644
index 0000000000..b3a92951b6
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/DateRevQueueTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.revwalk;
+
+public class DateRevQueueTest extends RevQueueTestCase<DateRevQueue> {
+ protected DateRevQueue create() {
+ return new DateRevQueue();
+ }
+
+ public void testEmpty() throws Exception {
+ super.testEmpty();
+ assertNull(q.peek());
+ assertEquals(Generator.SORT_COMMIT_TIME_DESC, q.outputType());
+ }
+
+ public void testCloneEmpty() throws Exception {
+ q = new DateRevQueue(AbstractRevQueue.EMPTY_QUEUE);
+ assertNull(q.next());
+ }
+
+ public void testInsertOutOfOrder() throws Exception {
+ final RevCommit a = parse(commit());
+ final RevCommit b = parse(commit(10, a));
+ final RevCommit c1 = parse(commit(5, b));
+ final RevCommit c2 = parse(commit(-50, b));
+
+ q.add(c2);
+ q.add(a);
+ q.add(b);
+ q.add(c1);
+
+ assertCommit(c1, q.next());
+ assertCommit(b, q.next());
+ assertCommit(a, q.next());
+ assertCommit(c2, q.next());
+ assertNull(q.next());
+ }
+
+ public void testInsertTie() throws Exception {
+ final RevCommit a = parse(commit());
+ final RevCommit b = parse(commit(0, a));
+ {
+ q = create();
+ q.add(a);
+ q.add(b);
+
+ assertCommit(a, q.next());
+ assertCommit(b, q.next());
+ assertNull(q.next());
+ }
+ {
+ q = create();
+ q.add(b);
+ q.add(a);
+
+ assertCommit(b, q.next());
+ assertCommit(a, q.next());
+ assertNull(q.next());
+ }
+ }
+
+ public void testCloneFIFO() throws Exception {
+ final RevCommit a = parse(commit());
+ final RevCommit b = parse(commit(200, a));
+ final RevCommit c = parse(commit(200, b));
+
+ final FIFORevQueue src = new FIFORevQueue();
+ src.add(a);
+ src.add(b);
+ src.add(c);
+
+ q = new DateRevQueue(src);
+ assertFalse(q.everbodyHasFlag(RevWalk.UNINTERESTING));
+ assertFalse(q.anybodyHasFlag(RevWalk.UNINTERESTING));
+ assertCommit(c, q.peek());
+ assertCommit(c, q.peek());
+
+ assertCommit(c, q.next());
+ assertCommit(b, q.next());
+ assertCommit(a, q.next());
+ assertNull(q.next());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FIFORevQueueTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FIFORevQueueTest.java
new file mode 100644
index 0000000000..3f4daab9f6
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FIFORevQueueTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.revwalk;
+
+import java.util.ArrayList;
+
+public class FIFORevQueueTest extends RevQueueTestCase<FIFORevQueue> {
+ protected FIFORevQueue create() {
+ return new FIFORevQueue();
+ }
+
+ public void testEmpty() throws Exception {
+ super.testEmpty();
+ assertEquals(0, q.outputType());
+ }
+
+ public void testCloneEmpty() throws Exception {
+ q = new FIFORevQueue(AbstractRevQueue.EMPTY_QUEUE);
+ assertNull(q.next());
+ }
+
+ public void testAddLargeBlocks() throws Exception {
+ final ArrayList<RevCommit> lst = new ArrayList<RevCommit>();
+ for (int i = 0; i < 3 * BlockRevQueue.Block.BLOCK_SIZE; i++) {
+ final RevCommit c = commit();
+ lst.add(c);
+ q.add(c);
+ }
+ for (int i = 0; i < lst.size(); i++)
+ assertSame(lst.get(i), q.next());
+ }
+
+ public void testUnpopAtFront() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit();
+ final RevCommit c = commit();
+
+ q.add(a);
+ q.unpop(b);
+ q.unpop(c);
+
+ assertSame(c, q.next());
+ assertSame(b, q.next());
+ assertSame(a, q.next());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FooterLineTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FooterLineTest.java
new file mode 100644
index 0000000000..d199f04ccb
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/FooterLineTest.java
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.revwalk;
+
+import java.util.List;
+
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+
+public class FooterLineTest extends RepositoryTestCase {
+ public void testNoFooters_EmptyBody() {
+ final RevCommit commit = parse("");
+ final List<FooterLine> footers = commit.getFooterLines();
+ assertNotNull(footers);
+ assertEquals(0, footers.size());
+ }
+
+ public void testNoFooters_NewlineOnlyBody1() {
+ final RevCommit commit = parse("\n");
+ final List<FooterLine> footers = commit.getFooterLines();
+ assertNotNull(footers);
+ assertEquals(0, footers.size());
+ }
+
+ public void testNoFooters_NewlineOnlyBody5() {
+ final RevCommit commit = parse("\n\n\n\n\n");
+ final List<FooterLine> footers = commit.getFooterLines();
+ assertNotNull(footers);
+ assertEquals(0, footers.size());
+ }
+
+ public void testNoFooters_OneLineBodyNoLF() {
+ final RevCommit commit = parse("this is a commit");
+ final List<FooterLine> footers = commit.getFooterLines();
+ assertNotNull(footers);
+ assertEquals(0, footers.size());
+ }
+
+ public void testNoFooters_OneLineBodyWithLF() {
+ final RevCommit commit = parse("this is a commit\n");
+ final List<FooterLine> footers = commit.getFooterLines();
+ assertNotNull(footers);
+ assertEquals(0, footers.size());
+ }
+
+ public void testNoFooters_ShortBodyNoLF() {
+ final RevCommit commit = parse("subject\n\nbody of commit");
+ final List<FooterLine> footers = commit.getFooterLines();
+ assertNotNull(footers);
+ assertEquals(0, footers.size());
+ }
+
+ public void testNoFooters_ShortBodyWithLF() {
+ final RevCommit commit = parse("subject\n\nbody of commit\n");
+ final List<FooterLine> footers = commit.getFooterLines();
+ assertNotNull(footers);
+ assertEquals(0, footers.size());
+ }
+
+ public void testSignedOffBy_OneUserNoLF() {
+ final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n"
+ + "Signed-off-by: A. U. Thor <a@example.com>");
+ final List<FooterLine> footers = commit.getFooterLines();
+ FooterLine f;
+
+ assertNotNull(footers);
+ assertEquals(1, footers.size());
+
+ f = footers.get(0);
+ assertEquals("Signed-off-by", f.getKey());
+ assertEquals("A. U. Thor <a@example.com>", f.getValue());
+ assertEquals("a@example.com", f.getEmailAddress());
+ }
+
+ public void testSignedOffBy_OneUserWithLF() {
+ final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n"
+ + "Signed-off-by: A. U. Thor <a@example.com>\n");
+ final List<FooterLine> footers = commit.getFooterLines();
+ FooterLine f;
+
+ assertNotNull(footers);
+ assertEquals(1, footers.size());
+
+ f = footers.get(0);
+ assertEquals("Signed-off-by", f.getKey());
+ assertEquals("A. U. Thor <a@example.com>", f.getValue());
+ assertEquals("a@example.com", f.getEmailAddress());
+ }
+
+ public void testSignedOffBy_IgnoreWhitespace() {
+ // We only ignore leading whitespace on the value, trailing
+ // is assumed part of the value.
+ //
+ final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n"
+ + "Signed-off-by: A. U. Thor <a@example.com> \n");
+ final List<FooterLine> footers = commit.getFooterLines();
+ FooterLine f;
+
+ assertNotNull(footers);
+ assertEquals(1, footers.size());
+
+ f = footers.get(0);
+ assertEquals("Signed-off-by", f.getKey());
+ assertEquals("A. U. Thor <a@example.com> ", f.getValue());
+ assertEquals("a@example.com", f.getEmailAddress());
+ }
+
+ public void testEmptyValueNoLF() {
+ final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n"
+ + "Signed-off-by:");
+ final List<FooterLine> footers = commit.getFooterLines();
+ FooterLine f;
+
+ assertNotNull(footers);
+ assertEquals(1, footers.size());
+
+ f = footers.get(0);
+ assertEquals("Signed-off-by", f.getKey());
+ assertEquals("", f.getValue());
+ assertNull(f.getEmailAddress());
+ }
+
+ public void testEmptyValueWithLF() {
+ final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n"
+ + "Signed-off-by:\n");
+ final List<FooterLine> footers = commit.getFooterLines();
+ FooterLine f;
+
+ assertNotNull(footers);
+ assertEquals(1, footers.size());
+
+ f = footers.get(0);
+ assertEquals("Signed-off-by", f.getKey());
+ assertEquals("", f.getValue());
+ assertNull(f.getEmailAddress());
+ }
+
+ public void testShortKey() {
+ final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n"
+ + "K:V\n");
+ final List<FooterLine> footers = commit.getFooterLines();
+ FooterLine f;
+
+ assertNotNull(footers);
+ assertEquals(1, footers.size());
+
+ f = footers.get(0);
+ assertEquals("K", f.getKey());
+ assertEquals("V", f.getValue());
+ assertNull(f.getEmailAddress());
+ }
+
+ public void testNonDelimtedEmail() {
+ final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n"
+ + "Acked-by: re@example.com\n");
+ final List<FooterLine> footers = commit.getFooterLines();
+ FooterLine f;
+
+ assertNotNull(footers);
+ assertEquals(1, footers.size());
+
+ f = footers.get(0);
+ assertEquals("Acked-by", f.getKey());
+ assertEquals("re@example.com", f.getValue());
+ assertEquals("re@example.com", f.getEmailAddress());
+ }
+
+ public void testNotEmail() {
+ final RevCommit commit = parse("subject\n\nbody of commit\n" + "\n"
+ + "Acked-by: Main Tain Er\n");
+ final List<FooterLine> footers = commit.getFooterLines();
+ FooterLine f;
+
+ assertNotNull(footers);
+ assertEquals(1, footers.size());
+
+ f = footers.get(0);
+ assertEquals("Acked-by", f.getKey());
+ assertEquals("Main Tain Er", f.getValue());
+ assertNull(f.getEmailAddress());
+ }
+
+ public void testSignedOffBy_ManyUsers() {
+ final RevCommit commit = parse("subject\n\nbody of commit\n"
+ + "Not-A-Footer-Line: this line must not be read as a footer\n"
+ + "\n" // paragraph break, now footers appear in final block
+ + "Signed-off-by: A. U. Thor <a@example.com>\n"
+ + "CC: <some.mailing.list@example.com>\n"
+ + "Acked-by: Some Reviewer <sr@example.com>\n"
+ + "Signed-off-by: Main Tain Er <mte@example.com>\n");
+ final List<FooterLine> footers = commit.getFooterLines();
+ FooterLine f;
+
+ assertNotNull(footers);
+ assertEquals(4, footers.size());
+
+ f = footers.get(0);
+ assertEquals("Signed-off-by", f.getKey());
+ assertEquals("A. U. Thor <a@example.com>", f.getValue());
+ assertEquals("a@example.com", f.getEmailAddress());
+
+ f = footers.get(1);
+ assertEquals("CC", f.getKey());
+ assertEquals("<some.mailing.list@example.com>", f.getValue());
+ assertEquals("some.mailing.list@example.com", f.getEmailAddress());
+
+ f = footers.get(2);
+ assertEquals("Acked-by", f.getKey());
+ assertEquals("Some Reviewer <sr@example.com>", f.getValue());
+ assertEquals("sr@example.com", f.getEmailAddress());
+
+ f = footers.get(3);
+ assertEquals("Signed-off-by", f.getKey());
+ assertEquals("Main Tain Er <mte@example.com>", f.getValue());
+ assertEquals("mte@example.com", f.getEmailAddress());
+ }
+
+ public void testSignedOffBy_SkipNonFooter() {
+ final RevCommit commit = parse("subject\n\nbody of commit\n"
+ + "Not-A-Footer-Line: this line must not be read as a footer\n"
+ + "\n" // paragraph break, now footers appear in final block
+ + "Signed-off-by: A. U. Thor <a@example.com>\n"
+ + "CC: <some.mailing.list@example.com>\n"
+ + "not really a footer line but we'll skip it anyway\n"
+ + "Acked-by: Some Reviewer <sr@example.com>\n"
+ + "Signed-off-by: Main Tain Er <mte@example.com>\n");
+ final List<FooterLine> footers = commit.getFooterLines();
+ FooterLine f;
+
+ assertNotNull(footers);
+ assertEquals(4, footers.size());
+
+ f = footers.get(0);
+ assertEquals("Signed-off-by", f.getKey());
+ assertEquals("A. U. Thor <a@example.com>", f.getValue());
+
+ f = footers.get(1);
+ assertEquals("CC", f.getKey());
+ assertEquals("<some.mailing.list@example.com>", f.getValue());
+
+ f = footers.get(2);
+ assertEquals("Acked-by", f.getKey());
+ assertEquals("Some Reviewer <sr@example.com>", f.getValue());
+
+ f = footers.get(3);
+ assertEquals("Signed-off-by", f.getKey());
+ assertEquals("Main Tain Er <mte@example.com>", f.getValue());
+ }
+
+ public void testFilterFootersIgnoreCase() {
+ final RevCommit commit = parse("subject\n\nbody of commit\n"
+ + "Not-A-Footer-Line: this line must not be read as a footer\n"
+ + "\n" // paragraph break, now footers appear in final block
+ + "Signed-Off-By: A. U. Thor <a@example.com>\n"
+ + "CC: <some.mailing.list@example.com>\n"
+ + "Acked-by: Some Reviewer <sr@example.com>\n"
+ + "signed-off-by: Main Tain Er <mte@example.com>\n");
+ final List<String> footers = commit.getFooterLines("signed-off-by");
+
+ assertNotNull(footers);
+ assertEquals(2, footers.size());
+
+ assertEquals("A. U. Thor <a@example.com>", footers.get(0));
+ assertEquals("Main Tain Er <mte@example.com>", footers.get(1));
+ }
+
+ private RevCommit parse(final String msg) {
+ final StringBuilder buf = new StringBuilder();
+ buf.append("tree " + ObjectId.zeroId().name() + "\n");
+ buf.append("author A. U. Thor <a@example.com> 1 +0000\n");
+ buf.append("committer A. U. Thor <a@example.com> 1 +0000\n");
+ buf.append("\n");
+ buf.append(msg);
+
+ final RevWalk walk = new RevWalk(db);
+ walk.setRetainBody(true);
+ final RevCommit c = new RevCommit(ObjectId.zeroId());
+ c.parseCanonical(walk, Constants.encode(buf.toString()));
+ return c;
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/LIFORevQueueTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/LIFORevQueueTest.java
new file mode 100644
index 0000000000..7676a71503
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/LIFORevQueueTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.revwalk;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+public class LIFORevQueueTest extends RevQueueTestCase<LIFORevQueue> {
+ protected LIFORevQueue create() {
+ return new LIFORevQueue();
+ }
+
+ public void testEmpty() throws Exception {
+ super.testEmpty();
+ assertEquals(0, q.outputType());
+ }
+
+ public void testCloneEmpty() throws Exception {
+ q = new LIFORevQueue(AbstractRevQueue.EMPTY_QUEUE);
+ assertNull(q.next());
+ }
+
+ public void testAddLargeBlocks() throws Exception {
+ final ArrayList<RevCommit> lst = new ArrayList<RevCommit>();
+ for (int i = 0; i < 3 * BlockRevQueue.Block.BLOCK_SIZE; i++) {
+ final RevCommit c = commit();
+ lst.add(c);
+ q.add(c);
+ }
+ Collections.reverse(lst);
+ for (int i = 0; i < lst.size(); i++)
+ assertSame(lst.get(i), q.next());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java
new file mode 100644
index 0000000000..7dddeee205
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.revwalk;
+
+public class ObjectWalkTest extends RevWalkTestCase {
+ protected ObjectWalk objw;
+
+ protected RevWalk createRevWalk() {
+ return objw = new ObjectWalk(db);
+ }
+
+ public void testNoCommits() throws Exception {
+ assertNull(objw.next());
+ assertNull(objw.nextObject());
+ }
+
+ public void testTwoCommitsEmptyTree() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ markStart(b);
+
+ assertCommit(b, objw.next());
+ assertCommit(a, objw.next());
+ assertNull(objw.next());
+
+ assertSame(emptyTree, objw.nextObject());
+ assertNull(objw.nextObject());
+ }
+
+ public void testOneCommitOneTreeTwoBlob() throws Exception {
+ final RevBlob f0 = blob("0");
+ final RevBlob f1 = blob("1");
+ final RevTree t = tree(file("0", f0), file("1", f1), file("2", f1));
+ final RevCommit a = commit(t);
+ markStart(a);
+
+ assertCommit(a, objw.next());
+ assertNull(objw.next());
+
+ assertSame(t, objw.nextObject());
+ assertSame(f0, objw.nextObject());
+ assertSame(f1, objw.nextObject());
+ assertNull(objw.nextObject());
+ }
+
+ public void testTwoCommitTwoTreeTwoBlob() throws Exception {
+ final RevBlob f0 = blob("0");
+ final RevBlob f1 = blob("1");
+ final RevBlob f2 = blob("0v2");
+ final RevTree ta = tree(file("0", f0), file("1", f1), file("2", f1));
+ final RevTree tb = tree(file("0", f2), file("1", f1), file("2", f1));
+ final RevCommit a = commit(ta);
+ final RevCommit b = commit(tb, a);
+ markStart(b);
+
+ assertCommit(b, objw.next());
+ assertCommit(a, objw.next());
+ assertNull(objw.next());
+
+ assertSame(tb, objw.nextObject());
+ assertSame(f2, objw.nextObject());
+ assertSame(f1, objw.nextObject());
+
+ assertSame(ta, objw.nextObject());
+ assertSame(f0, objw.nextObject());
+
+ assertNull(objw.nextObject());
+ }
+
+ public void testTwoCommitDeepTree1() throws Exception {
+ final RevBlob f0 = blob("0");
+ final RevBlob f1 = blob("0v2");
+ final RevTree ta = tree(file("a/b/0", f0));
+ final RevTree tb = tree(file("a/b/1", f1));
+ final RevCommit a = commit(ta);
+ final RevCommit b = commit(tb, a);
+ markStart(b);
+
+ assertCommit(b, objw.next());
+ assertCommit(a, objw.next());
+ assertNull(objw.next());
+
+ assertSame(tb, objw.nextObject());
+ assertSame(get(tb, "a"), objw.nextObject());
+ assertSame(get(tb, "a/b"), objw.nextObject());
+ assertSame(f1, objw.nextObject());
+
+ assertSame(ta, objw.nextObject());
+ assertSame(get(ta, "a"), objw.nextObject());
+ assertSame(get(ta, "a/b"), objw.nextObject());
+ assertSame(f0, objw.nextObject());
+
+ assertNull(objw.nextObject());
+ }
+
+ public void testTwoCommitDeepTree2() throws Exception {
+ final RevBlob f1 = blob("1");
+ final RevTree ta = tree(file("a/b/0", f1), file("a/c/q", f1));
+ final RevTree tb = tree(file("a/b/1", f1), file("a/c/q", f1));
+ final RevCommit a = commit(ta);
+ final RevCommit b = commit(tb, a);
+ markStart(b);
+
+ assertCommit(b, objw.next());
+ assertCommit(a, objw.next());
+ assertNull(objw.next());
+
+ assertSame(tb, objw.nextObject());
+ assertSame(get(tb, "a"), objw.nextObject());
+ assertSame(get(tb, "a/b"), objw.nextObject());
+ assertSame(f1, objw.nextObject());
+ assertSame(get(tb, "a/c"), objw.nextObject());
+
+ assertSame(ta, objw.nextObject());
+ assertSame(get(ta, "a"), objw.nextObject());
+ assertSame(get(ta, "a/b"), objw.nextObject());
+
+ assertNull(objw.nextObject());
+ }
+
+ public void testCull() throws Exception {
+ final RevBlob f1 = blob("1");
+ final RevBlob f2 = blob("2");
+ final RevBlob f3 = blob("3");
+ final RevBlob f4 = blob("4");
+
+ final RevTree ta = tree(file("a/1", f1), file("c/3", f3));
+ final RevCommit a = commit(ta);
+
+ final RevTree tb = tree(file("a/1", f2), file("c/3", f3));
+ final RevCommit b1 = commit(tb, a);
+ final RevCommit b2 = commit(tb, b1);
+
+ final RevTree tc = tree(file("a/1", f4));
+ final RevCommit c1 = commit(tc, a);
+ final RevCommit c2 = commit(tc, c1);
+
+ markStart(b2);
+ markUninteresting(c2);
+
+ assertCommit(b2, objw.next());
+ assertCommit(b1, objw.next());
+ assertNull(objw.next());
+
+ assertTrue(a.has(RevFlag.UNINTERESTING));
+ assertTrue(ta.has(RevFlag.UNINTERESTING));
+ assertTrue(f1.has(RevFlag.UNINTERESTING));
+ assertTrue(f3.has(RevFlag.UNINTERESTING));
+
+ assertSame(tb, objw.nextObject());
+ assertSame(get(tb, "a"), objw.nextObject());
+ assertSame(f2, objw.nextObject());
+ assertNull(objw.nextObject());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java
new file mode 100644
index 0000000000..b7e84419c9
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevCommitParseTest.java
@@ -0,0 +1,321 @@
+/*
+ * Copyright (C) 2008-2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.revwalk;
+
+import java.io.ByteArrayOutputStream;
+
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+
+public class RevCommitParseTest extends RepositoryTestCase {
+ public void testParse_NoParents() throws Exception {
+ final ObjectId treeId = id("9788669ad918b6fcce64af8882fc9a81cb6aba67");
+ final String authorName = "A U. Thor";
+ final String authorEmail = "a_u_thor@example.com";
+ final int authorTime = 1218123387;
+
+ final String committerName = "C O. Miter";
+ final String committerEmail = "comiter@example.com";
+ final int committerTime = 1218123390;
+ final StringBuilder body = new StringBuilder();
+
+ body.append("tree ");
+ body.append(treeId.name());
+ body.append("\n");
+
+ body.append("author ");
+ body.append(authorName);
+ body.append(" <");
+ body.append(authorEmail);
+ body.append("> ");
+ body.append(authorTime);
+ body.append(" +0700\n");
+
+ body.append("committer ");
+ body.append(committerName);
+ body.append(" <");
+ body.append(committerEmail);
+ body.append("> ");
+ body.append(committerTime);
+ body.append(" -0500\n");
+
+ body.append("\n");
+
+ final RevWalk rw = new RevWalk(db);
+ final RevCommit c;
+
+ c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
+ assertNull(c.getTree());
+ assertNull(c.parents);
+
+ c.parseCanonical(rw, body.toString().getBytes("UTF-8"));
+ assertNotNull(c.getTree());
+ assertEquals(treeId, c.getTree().getId());
+ assertSame(rw.lookupTree(treeId), c.getTree());
+
+ assertNotNull(c.parents);
+ assertEquals(0, c.parents.length);
+ assertEquals("", c.getFullMessage());
+
+ final PersonIdent cAuthor = c.getAuthorIdent();
+ assertNotNull(cAuthor);
+ assertEquals(authorName, cAuthor.getName());
+ assertEquals(authorEmail, cAuthor.getEmailAddress());
+
+ final PersonIdent cCommitter = c.getCommitterIdent();
+ assertNotNull(cCommitter);
+ assertEquals(committerName, cCommitter.getName());
+ assertEquals(committerEmail, cCommitter.getEmailAddress());
+ }
+
+ private RevCommit create(final String msg) throws Exception {
+ final StringBuilder b = new StringBuilder();
+ b.append("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n");
+ b.append("author A U. Thor <a_u_thor@example.com> 1218123387 +0700\n");
+ b.append("committer C O. Miter <c@example.com> 1218123390 -0500\n");
+ b.append("\n");
+ b.append(msg);
+
+ final RevCommit c;
+ c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
+ c.parseCanonical(new RevWalk(db), b.toString().getBytes("UTF-8"));
+ return c;
+ }
+
+ public void testParse_WeirdHeaderOnlyCommit() throws Exception {
+ final StringBuilder b = new StringBuilder();
+ b.append("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n");
+ b.append("author A U. Thor <a_u_thor@example.com> 1218123387 +0700\n");
+ b.append("committer C O. Miter <c@example.com> 1218123390 -0500\n");
+
+ final RevCommit c;
+ c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
+ c.parseCanonical(new RevWalk(db), b.toString().getBytes("UTF-8"));
+
+ assertEquals("", c.getFullMessage());
+ assertEquals("", c.getShortMessage());
+ }
+
+ public void testParse_implicit_UTF8_encoded() throws Exception {
+ final ByteArrayOutputStream b = new ByteArrayOutputStream();
+ b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes("UTF-8"));
+ b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n".getBytes("UTF-8"));
+ b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n".getBytes("UTF-8"));
+ b.write("\n".getBytes("UTF-8"));
+ b.write("Sm\u00f6rg\u00e5sbord\n".getBytes("UTF-8"));
+ b.write("\n".getBytes("UTF-8"));
+ b.write("\u304d\u308c\u3044\n".getBytes("UTF-8"));
+ final RevCommit c;
+ c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); // bogus id
+ c.parseCanonical(new RevWalk(db), b.toByteArray());
+
+ assertSame(Constants.CHARSET, c.getEncoding());
+ assertEquals("F\u00f6r fattare", c.getAuthorIdent().getName());
+ assertEquals("Sm\u00f6rg\u00e5sbord", c.getShortMessage());
+ assertEquals("Sm\u00f6rg\u00e5sbord\n\n\u304d\u308c\u3044\n", c.getFullMessage());
+ }
+
+ public void testParse_implicit_mixed_encoded() throws Exception {
+ final ByteArrayOutputStream b = new ByteArrayOutputStream();
+ b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes("UTF-8"));
+ b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n".getBytes("ISO-8859-1"));
+ b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n".getBytes("UTF-8"));
+ b.write("\n".getBytes("UTF-8"));
+ b.write("Sm\u00f6rg\u00e5sbord\n".getBytes("UTF-8"));
+ b.write("\n".getBytes("UTF-8"));
+ b.write("\u304d\u308c\u3044\n".getBytes("UTF-8"));
+ final RevCommit c;
+ c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); // bogus id
+ c.parseCanonical(new RevWalk(db), b.toByteArray());
+
+ assertSame(Constants.CHARSET, c.getEncoding());
+ assertEquals("F\u00f6r fattare", c.getAuthorIdent().getName());
+ assertEquals("Sm\u00f6rg\u00e5sbord", c.getShortMessage());
+ assertEquals("Sm\u00f6rg\u00e5sbord\n\n\u304d\u308c\u3044\n", c.getFullMessage());
+ }
+
+ /**
+ * Test parsing of a commit whose encoding is given and works.
+ *
+ * @throws Exception
+ */
+ public void testParse_explicit_encoded() throws Exception {
+ final ByteArrayOutputStream b = new ByteArrayOutputStream();
+ b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes("EUC-JP"));
+ b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n".getBytes("EUC-JP"));
+ b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n".getBytes("EUC-JP"));
+ b.write("encoding euc_JP\n".getBytes("EUC-JP"));
+ b.write("\n".getBytes("EUC-JP"));
+ b.write("\u304d\u308c\u3044\n".getBytes("EUC-JP"));
+ b.write("\n".getBytes("EUC-JP"));
+ b.write("Hi\n".getBytes("EUC-JP"));
+ final RevCommit c;
+ c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); // bogus id
+ c.parseCanonical(new RevWalk(db), b.toByteArray());
+
+ assertEquals("EUC-JP", c.getEncoding().name());
+ assertEquals("F\u00f6r fattare", c.getAuthorIdent().getName());
+ assertEquals("\u304d\u308c\u3044", c.getShortMessage());
+ assertEquals("\u304d\u308c\u3044\n\nHi\n", c.getFullMessage());
+ }
+
+ /**
+ * This is a twisted case, but show what we expect here. We can revise the
+ * expectations provided this case is updated.
+ *
+ * What happens here is that an encoding us given, but data is not encoded
+ * that way (and we can detect it), so we try other encodings.
+ *
+ * @throws Exception
+ */
+ public void testParse_explicit_bad_encoded() throws Exception {
+ final ByteArrayOutputStream b = new ByteArrayOutputStream();
+ b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes("UTF-8"));
+ b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n".getBytes("ISO-8859-1"));
+ b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n".getBytes("UTF-8"));
+ b.write("encoding EUC-JP\n".getBytes("UTF-8"));
+ b.write("\n".getBytes("UTF-8"));
+ b.write("\u304d\u308c\u3044\n".getBytes("UTF-8"));
+ b.write("\n".getBytes("UTF-8"));
+ b.write("Hi\n".getBytes("UTF-8"));
+ final RevCommit c;
+ c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); // bogus id
+ c.parseCanonical(new RevWalk(db), b.toByteArray());
+
+ assertEquals("EUC-JP", c.getEncoding().name());
+ assertEquals("F\u00f6r fattare", c.getAuthorIdent().getName());
+ assertEquals("\u304d\u308c\u3044", c.getShortMessage());
+ assertEquals("\u304d\u308c\u3044\n\nHi\n", c.getFullMessage());
+ }
+
+ /**
+ * This is a twisted case too, but show what we expect here. We can revise the
+ * expectations provided this case is updated.
+ *
+ * What happens here is that an encoding us given, but data is not encoded
+ * that way (and we can detect it), so we try other encodings. Here data could
+ * actually be decoded in the stated encoding, but we override using UTF-8.
+ *
+ * @throws Exception
+ */
+ public void testParse_explicit_bad_encoded2() throws Exception {
+ final ByteArrayOutputStream b = new ByteArrayOutputStream();
+ b.write("tree 9788669ad918b6fcce64af8882fc9a81cb6aba67\n".getBytes("UTF-8"));
+ b.write("author F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n".getBytes("UTF-8"));
+ b.write("committer C O. Miter <c@example.com> 1218123390 -0500\n".getBytes("UTF-8"));
+ b.write("encoding ISO-8859-1\n".getBytes("UTF-8"));
+ b.write("\n".getBytes("UTF-8"));
+ b.write("\u304d\u308c\u3044\n".getBytes("UTF-8"));
+ b.write("\n".getBytes("UTF-8"));
+ b.write("Hi\n".getBytes("UTF-8"));
+ final RevCommit c;
+ c = new RevCommit(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67")); // bogus id
+ c.parseCanonical(new RevWalk(db), b.toByteArray());
+
+ assertEquals("ISO-8859-1", c.getEncoding().name());
+ assertEquals("F\u00f6r fattare", c.getAuthorIdent().getName());
+ assertEquals("\u304d\u308c\u3044", c.getShortMessage());
+ assertEquals("\u304d\u308c\u3044\n\nHi\n", c.getFullMessage());
+ }
+
+ public void testParse_NoMessage() throws Exception {
+ final String msg = "";
+ final RevCommit c = create(msg);
+ assertEquals(msg, c.getFullMessage());
+ assertEquals(msg, c.getShortMessage());
+ }
+
+ public void testParse_OnlyLFMessage() throws Exception {
+ final RevCommit c = create("\n");
+ assertEquals("\n", c.getFullMessage());
+ assertEquals("", c.getShortMessage());
+ }
+
+ public void testParse_ShortLineOnlyNoLF() throws Exception {
+ final String shortMsg = "This is a short message.";
+ final RevCommit c = create(shortMsg);
+ assertEquals(shortMsg, c.getFullMessage());
+ assertEquals(shortMsg, c.getShortMessage());
+ }
+
+ public void testParse_ShortLineOnlyEndLF() throws Exception {
+ final String shortMsg = "This is a short message.";
+ final String fullMsg = shortMsg + "\n";
+ final RevCommit c = create(fullMsg);
+ assertEquals(fullMsg, c.getFullMessage());
+ assertEquals(shortMsg, c.getShortMessage());
+ }
+
+ public void testParse_ShortLineOnlyEmbeddedLF() throws Exception {
+ final String fullMsg = "This is a\nshort message.";
+ final String shortMsg = fullMsg.replace('\n', ' ');
+ final RevCommit c = create(fullMsg);
+ assertEquals(fullMsg, c.getFullMessage());
+ assertEquals(shortMsg, c.getShortMessage());
+ }
+
+ public void testParse_ShortLineOnlyEmbeddedAndEndingLF() throws Exception {
+ final String fullMsg = "This is a\nshort message.\n";
+ final String shortMsg = "This is a short message.";
+ final RevCommit c = create(fullMsg);
+ assertEquals(fullMsg, c.getFullMessage());
+ assertEquals(shortMsg, c.getShortMessage());
+ }
+
+ public void testParse_GitStyleMessage() throws Exception {
+ final String shortMsg = "This fixes a bug.";
+ final String body = "We do it with magic and pixie dust and stuff.\n"
+ + "\n" + "Signed-off-by: A U. Thor <author@example.com>\n";
+ final String fullMsg = shortMsg + "\n" + "\n" + body;
+ final RevCommit c = create(fullMsg);
+ assertEquals(fullMsg, c.getFullMessage());
+ assertEquals(shortMsg, c.getShortMessage());
+ }
+
+ private static ObjectId id(final String str) {
+ return ObjectId.fromString(str);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevFlagSetTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevFlagSetTest.java
new file mode 100644
index 0000000000..13f1cfc4cc
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevFlagSetTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.revwalk;
+
+import java.util.Arrays;
+import java.util.Iterator;
+
+public class RevFlagSetTest extends RevWalkTestCase {
+ public void testEmpty() {
+ final RevFlagSet set = new RevFlagSet();
+ assertEquals(0, set.mask);
+ assertEquals(0, set.size());
+ assertNotNull(set.iterator());
+ assertFalse(set.iterator().hasNext());
+ }
+
+ public void testAddOne() {
+ final String flagName = "flag";
+ final RevFlag flag = rw.newFlag(flagName);
+ assertTrue(0 != flag.mask);
+ assertSame(flagName, flag.name);
+
+ final RevFlagSet set = new RevFlagSet();
+ assertTrue(set.add(flag));
+ assertFalse(set.add(flag));
+ assertEquals(flag.mask, set.mask);
+ assertEquals(1, set.size());
+ final Iterator<RevFlag> i = set.iterator();
+ assertTrue(i.hasNext());
+ assertSame(flag, i.next());
+ assertFalse(i.hasNext());
+ }
+
+ public void testAddTwo() {
+ final RevFlag flag1 = rw.newFlag("flag_1");
+ final RevFlag flag2 = rw.newFlag("flag_2");
+ assertTrue((flag1.mask & flag2.mask) == 0);
+
+ final RevFlagSet set = new RevFlagSet();
+ assertTrue(set.add(flag1));
+ assertTrue(set.add(flag2));
+ assertEquals(flag1.mask | flag2.mask, set.mask);
+ assertEquals(2, set.size());
+ }
+
+ public void testContainsAll() {
+ final RevFlag flag1 = rw.newFlag("flag_1");
+ final RevFlag flag2 = rw.newFlag("flag_2");
+ final RevFlagSet set1 = new RevFlagSet();
+ assertTrue(set1.add(flag1));
+ assertTrue(set1.add(flag2));
+
+ assertTrue(set1.containsAll(set1));
+ assertTrue(set1.containsAll(Arrays
+ .asList(new RevFlag[] { flag1, flag2 })));
+
+ final RevFlagSet set2 = new RevFlagSet();
+ set2.add(rw.newFlag("flag_3"));
+ assertFalse(set1.containsAll(set2));
+ }
+
+ public void testEquals() {
+ final RevFlag flag1 = rw.newFlag("flag_1");
+ final RevFlag flag2 = rw.newFlag("flag_2");
+ final RevFlagSet set = new RevFlagSet();
+ assertTrue(set.add(flag1));
+ assertTrue(set.add(flag2));
+
+ assertTrue(new RevFlagSet(set).equals(set));
+ assertTrue(new RevFlagSet(Arrays.asList(new RevFlag[] { flag1, flag2 }))
+ .equals(set));
+ }
+
+ public void testRemove() {
+ final RevFlag flag1 = rw.newFlag("flag_1");
+ final RevFlag flag2 = rw.newFlag("flag_2");
+ final RevFlagSet set = new RevFlagSet();
+ assertTrue(set.add(flag1));
+ assertTrue(set.add(flag2));
+
+ assertTrue(set.remove(flag1));
+ assertFalse(set.remove(flag1));
+ assertEquals(flag2.mask, set.mask);
+ assertFalse(set.contains(flag1));
+ }
+
+ public void testContains() {
+ final RevFlag flag1 = rw.newFlag("flag_1");
+ final RevFlag flag2 = rw.newFlag("flag_2");
+ final RevFlagSet set = new RevFlagSet();
+ set.add(flag1);
+ assertTrue(set.contains(flag1));
+ assertFalse(set.contains(flag2));
+ assertFalse(set.contains("bob"));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevObjectTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevObjectTest.java
new file mode 100644
index 0000000000..87ecaa8c53
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevObjectTest.java
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.revwalk;
+
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.Constants;
+
+public class RevObjectTest extends RevWalkTestCase {
+ public void testId() throws Exception {
+ final RevCommit a = commit();
+ assertSame(a, a.getId());
+ }
+
+ public void testEqualsIsIdentity() throws Exception {
+ final RevCommit a1 = commit();
+ final RevCommit b1 = commit();
+
+ assertTrue(a1.equals(a1));
+ assertTrue(a1.equals((Object) a1));
+ assertFalse(a1.equals(b1));
+
+ assertFalse(a1.equals(a1.copy()));
+ assertFalse(a1.equals((Object) a1.copy()));
+ assertFalse(a1.equals(""));
+
+ final RevWalk rw2 = new RevWalk(db);
+ final RevCommit a2 = rw2.parseCommit(a1);
+ final RevCommit b2 = rw2.parseCommit(b1);
+ assertNotSame(a1, a2);
+ assertNotSame(b1, b2);
+
+ assertFalse(a1.equals(a2));
+ assertFalse(b1.equals(b2));
+
+ assertEquals(a1.hashCode(), a2.hashCode());
+ assertEquals(b1.hashCode(), b2.hashCode());
+
+ assertTrue(AnyObjectId.equals(a1, a2));
+ assertTrue(AnyObjectId.equals(b1, b2));
+ }
+
+ public void testRevObjectTypes() throws Exception {
+ assertEquals(Constants.OBJ_TREE, emptyTree.getType());
+ assertEquals(Constants.OBJ_COMMIT, commit().getType());
+ assertEquals(Constants.OBJ_BLOB, blob("").getType());
+ assertEquals(Constants.OBJ_TAG, tag("emptyTree", emptyTree).getType());
+ }
+
+ public void testHasRevFlag() throws Exception {
+ final RevCommit a = commit();
+ assertFalse(a.has(RevFlag.UNINTERESTING));
+ a.flags |= RevWalk.UNINTERESTING;
+ assertTrue(a.has(RevFlag.UNINTERESTING));
+ }
+
+ public void testHasAnyFlag() throws Exception {
+ final RevCommit a = commit();
+ final RevFlag flag1 = rw.newFlag("flag1");
+ final RevFlag flag2 = rw.newFlag("flag2");
+ final RevFlagSet s = new RevFlagSet();
+ s.add(flag1);
+ s.add(flag2);
+
+ assertFalse(a.hasAny(s));
+ a.flags |= flag1.mask;
+ assertTrue(a.hasAny(s));
+ }
+
+ public void testHasAllFlag() throws Exception {
+ final RevCommit a = commit();
+ final RevFlag flag1 = rw.newFlag("flag1");
+ final RevFlag flag2 = rw.newFlag("flag2");
+ final RevFlagSet s = new RevFlagSet();
+ s.add(flag1);
+ s.add(flag2);
+
+ assertFalse(a.hasAll(s));
+ a.flags |= flag1.mask;
+ assertFalse(a.hasAll(s));
+ a.flags |= flag2.mask;
+ assertTrue(a.hasAll(s));
+ }
+
+ public void testAddRevFlag() throws Exception {
+ final RevCommit a = commit();
+ final RevFlag flag1 = rw.newFlag("flag1");
+ final RevFlag flag2 = rw.newFlag("flag2");
+ assertEquals(0, a.flags);
+
+ a.add(flag1);
+ assertEquals(flag1.mask, a.flags);
+
+ a.add(flag2);
+ assertEquals(flag1.mask | flag2.mask, a.flags);
+ }
+
+ public void testAddRevFlagSet() throws Exception {
+ final RevCommit a = commit();
+ final RevFlag flag1 = rw.newFlag("flag1");
+ final RevFlag flag2 = rw.newFlag("flag2");
+ final RevFlagSet s = new RevFlagSet();
+ s.add(flag1);
+ s.add(flag2);
+
+ assertEquals(0, a.flags);
+
+ a.add(s);
+ assertEquals(flag1.mask | flag2.mask, a.flags);
+ }
+
+ public void testRemoveRevFlag() throws Exception {
+ final RevCommit a = commit();
+ final RevFlag flag1 = rw.newFlag("flag1");
+ final RevFlag flag2 = rw.newFlag("flag2");
+ a.add(flag1);
+ a.add(flag2);
+ assertEquals(flag1.mask | flag2.mask, a.flags);
+ a.remove(flag2);
+ assertEquals(flag1.mask, a.flags);
+ }
+
+ public void testRemoveRevFlagSet() throws Exception {
+ final RevCommit a = commit();
+ final RevFlag flag1 = rw.newFlag("flag1");
+ final RevFlag flag2 = rw.newFlag("flag2");
+ final RevFlag flag3 = rw.newFlag("flag3");
+ final RevFlagSet s = new RevFlagSet();
+ s.add(flag1);
+ s.add(flag2);
+ a.add(flag3);
+ a.add(s);
+ assertEquals(flag1.mask | flag2.mask | flag3.mask, a.flags);
+ a.remove(s);
+ assertEquals(flag3.mask, a.flags);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevQueueTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevQueueTestCase.java
new file mode 100644
index 0000000000..24e84b041d
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevQueueTestCase.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.revwalk;
+
+public abstract class RevQueueTestCase<T extends AbstractRevQueue> extends
+ RevWalkTestCase {
+ protected T q;
+
+ public void setUp() throws Exception {
+ super.setUp();
+ q = create();
+ }
+
+ protected abstract T create();
+
+ public void testEmpty() throws Exception {
+ assertNull(q.next());
+ assertTrue(q.everbodyHasFlag(RevWalk.UNINTERESTING));
+ assertFalse(q.anybodyHasFlag(RevWalk.UNINTERESTING));
+ }
+
+ public void testClear() throws Exception {
+ final RevCommit a = parse(commit());
+ final RevCommit b = parse(commit(a));
+
+ q.add(a);
+ q.add(b);
+ q.clear();
+ assertNull(q.next());
+ }
+
+ public void testHasFlags() throws Exception {
+ final RevCommit a = parse(commit());
+ final RevCommit b = parse(commit(a));
+
+ q.add(a);
+ q.add(b);
+
+ assertFalse(q.everbodyHasFlag(RevWalk.UNINTERESTING));
+ assertFalse(q.anybodyHasFlag(RevWalk.UNINTERESTING));
+
+ a.flags |= RevWalk.UNINTERESTING;
+ assertFalse(q.everbodyHasFlag(RevWalk.UNINTERESTING));
+ assertTrue(q.anybodyHasFlag(RevWalk.UNINTERESTING));
+
+ b.flags |= RevWalk.UNINTERESTING;
+ assertTrue(q.everbodyHasFlag(RevWalk.UNINTERESTING));
+ assertTrue(q.anybodyHasFlag(RevWalk.UNINTERESTING));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java
new file mode 100644
index 0000000000..8800536d27
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevTagParseTest.java
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2008-2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.revwalk;
+
+import java.io.ByteArrayOutputStream;
+
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+
+public class RevTagParseTest extends RepositoryTestCase {
+ public void testTagBlob() throws Exception {
+ testOneType(Constants.OBJ_BLOB);
+ }
+
+ public void testTagTree() throws Exception {
+ testOneType(Constants.OBJ_TREE);
+ }
+
+ public void testTagCommit() throws Exception {
+ testOneType(Constants.OBJ_COMMIT);
+ }
+
+ public void testTagTag() throws Exception {
+ testOneType(Constants.OBJ_TAG);
+ }
+
+ private void testOneType(final int typeCode) throws Exception {
+ final ObjectId id = id("9788669ad918b6fcce64af8882fc9a81cb6aba67");
+ final StringBuilder b = new StringBuilder();
+ b.append("object " + id.name() + "\n");
+ b.append("type " + Constants.typeString(typeCode) + "\n");
+ b.append("tag v1.2.3.4.5\n");
+ b.append("tagger A U. Thor <a_u_thor@example.com> 1218123387 +0700\n");
+ b.append("\n");
+
+ final RevWalk rw = new RevWalk(db);
+ final RevTag c;
+
+ c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
+ assertNull(c.getObject());
+ assertNull(c.getTagName());
+
+ c.parseCanonical(rw, b.toString().getBytes("UTF-8"));
+ assertNotNull(c.getObject());
+ assertEquals(id, c.getObject().getId());
+ assertSame(rw.lookupAny(id, typeCode), c.getObject());
+ }
+
+ public void testParseAllFields() throws Exception {
+ final ObjectId treeId = id("9788669ad918b6fcce64af8882fc9a81cb6aba67");
+ final String name = "v1.2.3.4.5";
+ final String taggerName = "A U. Thor";
+ final String taggerEmail = "a_u_thor@example.com";
+ final int taggerTime = 1218123387;
+
+ final StringBuilder body = new StringBuilder();
+
+ body.append("object ");
+ body.append(treeId.name());
+ body.append("\n");
+
+ body.append("type tree\n");
+
+ body.append("tag ");
+ body.append(name);
+ body.append("\n");
+
+ body.append("tagger ");
+ body.append(taggerName);
+ body.append(" <");
+ body.append(taggerEmail);
+ body.append("> ");
+ body.append(taggerTime);
+ body.append(" +0700\n");
+
+ body.append("\n");
+
+ final RevWalk rw = new RevWalk(db);
+ final RevTag c;
+
+ c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
+ assertNull(c.getObject());
+ assertNull(c.getTagName());
+
+ c.parseCanonical(rw, body.toString().getBytes("UTF-8"));
+ assertNotNull(c.getObject());
+ assertEquals(treeId, c.getObject().getId());
+ assertSame(rw.lookupTree(treeId), c.getObject());
+
+ assertNotNull(c.getTagName());
+ assertEquals(name, c.getTagName());
+ assertEquals("", c.getFullMessage());
+
+ final PersonIdent cTagger = c.getTaggerIdent();
+ assertNotNull(cTagger);
+ assertEquals(taggerName, cTagger.getName());
+ assertEquals(taggerEmail, cTagger.getEmailAddress());
+ }
+
+ private RevTag create(final String msg) throws Exception {
+ final StringBuilder b = new StringBuilder();
+ b.append("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n");
+ b.append("type tree\n");
+ b.append("tag v1.2.3.4.5\n");
+ b.append("tagger A U. Thor <a_u_thor@example.com> 1218123387 +0700\n");
+ b.append("\n");
+ b.append(msg);
+
+ final RevTag c;
+ c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
+ c.parseCanonical(new RevWalk(db), b.toString().getBytes("UTF-8"));
+ return c;
+ }
+
+ public void testParse_implicit_UTF8_encoded() throws Exception {
+ final ByteArrayOutputStream b = new ByteArrayOutputStream();
+ b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
+ .getBytes("UTF-8"));
+ b.write("type tree\n".getBytes("UTF-8"));
+ b.write("tag v1.2.3.4.5\n".getBytes("UTF-8"));
+
+ b
+ .write("tagger F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n"
+ .getBytes("UTF-8"));
+ b.write("\n".getBytes("UTF-8"));
+ b.write("Sm\u00f6rg\u00e5sbord\n".getBytes("UTF-8"));
+ b.write("\n".getBytes("UTF-8"));
+ b.write("\u304d\u308c\u3044\n".getBytes("UTF-8"));
+ final RevTag c;
+ c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
+ c.parseCanonical(new RevWalk(db), b.toByteArray());
+
+ assertEquals("F\u00f6r fattare", c.getTaggerIdent().getName());
+ assertEquals("Sm\u00f6rg\u00e5sbord", c.getShortMessage());
+ assertEquals("Sm\u00f6rg\u00e5sbord\n\n\u304d\u308c\u3044\n", c
+ .getFullMessage());
+ }
+
+ public void testParse_implicit_mixed_encoded() throws Exception {
+ final ByteArrayOutputStream b = new ByteArrayOutputStream();
+ b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
+ .getBytes("UTF-8"));
+ b.write("type tree\n".getBytes("UTF-8"));
+ b.write("tag v1.2.3.4.5\n".getBytes("UTF-8"));
+ b
+ .write("tagger F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n"
+ .getBytes("ISO-8859-1"));
+ b.write("\n".getBytes("UTF-8"));
+ b.write("Sm\u00f6rg\u00e5sbord\n".getBytes("UTF-8"));
+ b.write("\n".getBytes("UTF-8"));
+ b.write("\u304d\u308c\u3044\n".getBytes("UTF-8"));
+ final RevTag c;
+ c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
+ c.parseCanonical(new RevWalk(db), b.toByteArray());
+
+ assertEquals("F\u00f6r fattare", c.getTaggerIdent().getName());
+ assertEquals("Sm\u00f6rg\u00e5sbord", c.getShortMessage());
+ assertEquals("Sm\u00f6rg\u00e5sbord\n\n\u304d\u308c\u3044\n", c
+ .getFullMessage());
+ }
+
+ /**
+ * Test parsing of a commit whose encoding is given and works.
+ *
+ * @throws Exception
+ */
+ public void testParse_explicit_encoded() throws Exception {
+ final ByteArrayOutputStream b = new ByteArrayOutputStream();
+ b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
+ .getBytes("EUC-JP"));
+ b.write("type tree\n".getBytes("EUC-JP"));
+ b.write("tag v1.2.3.4.5\n".getBytes("EUC-JP"));
+ b
+ .write("tagger F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n"
+ .getBytes("EUC-JP"));
+ b.write("encoding euc_JP\n".getBytes("EUC-JP"));
+ b.write("\n".getBytes("EUC-JP"));
+ b.write("\u304d\u308c\u3044\n".getBytes("EUC-JP"));
+ b.write("\n".getBytes("EUC-JP"));
+ b.write("Hi\n".getBytes("EUC-JP"));
+ final RevTag c;
+ c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
+ c.parseCanonical(new RevWalk(db), b.toByteArray());
+
+ assertEquals("F\u00f6r fattare", c.getTaggerIdent().getName());
+ assertEquals("\u304d\u308c\u3044", c.getShortMessage());
+ assertEquals("\u304d\u308c\u3044\n\nHi\n", c.getFullMessage());
+ }
+
+ /**
+ * This is a twisted case, but show what we expect here. We can revise the
+ * expectations provided this case is updated.
+ *
+ * What happens here is that an encoding us given, but data is not encoded
+ * that way (and we can detect it), so we try other encodings.
+ *
+ * @throws Exception
+ */
+ public void testParse_explicit_bad_encoded() throws Exception {
+ final ByteArrayOutputStream b = new ByteArrayOutputStream();
+ b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
+ .getBytes("UTF-8"));
+ b.write("type tree\n".getBytes("UTF-8"));
+ b.write("tag v1.2.3.4.5\n".getBytes("UTF-8"));
+ b
+ .write("tagger F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n"
+ .getBytes("ISO-8859-1"));
+ b.write("encoding EUC-JP\n".getBytes("UTF-8"));
+ b.write("\n".getBytes("UTF-8"));
+ b.write("\u304d\u308c\u3044\n".getBytes("UTF-8"));
+ b.write("\n".getBytes("UTF-8"));
+ b.write("Hi\n".getBytes("UTF-8"));
+ final RevTag c;
+ c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
+ c.parseCanonical(new RevWalk(db), b.toByteArray());
+
+ assertEquals("F\u00f6r fattare", c.getTaggerIdent().getName());
+ assertEquals("\u304d\u308c\u3044", c.getShortMessage());
+ assertEquals("\u304d\u308c\u3044\n\nHi\n", c.getFullMessage());
+ }
+
+ /**
+ * This is a twisted case too, but show what we expect here. We can revise
+ * the expectations provided this case is updated.
+ *
+ * What happens here is that an encoding us given, but data is not encoded
+ * that way (and we can detect it), so we try other encodings. Here data
+ * could actually be decoded in the stated encoding, but we override using
+ * UTF-8.
+ *
+ * @throws Exception
+ */
+ public void testParse_explicit_bad_encoded2() throws Exception {
+ final ByteArrayOutputStream b = new ByteArrayOutputStream();
+ b.write("object 9788669ad918b6fcce64af8882fc9a81cb6aba67\n"
+ .getBytes("UTF-8"));
+ b.write("type tree\n".getBytes("UTF-8"));
+ b.write("tag v1.2.3.4.5\n".getBytes("UTF-8"));
+ b
+ .write("tagger F\u00f6r fattare <a_u_thor@example.com> 1218123387 +0700\n"
+ .getBytes("UTF-8"));
+ b.write("encoding ISO-8859-1\n".getBytes("UTF-8"));
+ b.write("\n".getBytes("UTF-8"));
+ b.write("\u304d\u308c\u3044\n".getBytes("UTF-8"));
+ b.write("\n".getBytes("UTF-8"));
+ b.write("Hi\n".getBytes("UTF-8"));
+ final RevTag c;
+ c = new RevTag(id("9473095c4cb2f12aefe1db8a355fe3fafba42f67"));
+ c.parseCanonical(new RevWalk(db), b.toByteArray());
+
+ assertEquals("F\u00f6r fattare", c.getTaggerIdent().getName());
+ assertEquals("\u304d\u308c\u3044", c.getShortMessage());
+ assertEquals("\u304d\u308c\u3044\n\nHi\n", c.getFullMessage());
+ }
+
+ public void testParse_NoMessage() throws Exception {
+ final String msg = "";
+ final RevTag c = create(msg);
+ assertEquals(msg, c.getFullMessage());
+ assertEquals(msg, c.getShortMessage());
+ }
+
+ public void testParse_OnlyLFMessage() throws Exception {
+ final RevTag c = create("\n");
+ assertEquals("\n", c.getFullMessage());
+ assertEquals("", c.getShortMessage());
+ }
+
+ public void testParse_ShortLineOnlyNoLF() throws Exception {
+ final String shortMsg = "This is a short message.";
+ final RevTag c = create(shortMsg);
+ assertEquals(shortMsg, c.getFullMessage());
+ assertEquals(shortMsg, c.getShortMessage());
+ }
+
+ public void testParse_ShortLineOnlyEndLF() throws Exception {
+ final String shortMsg = "This is a short message.";
+ final String fullMsg = shortMsg + "\n";
+ final RevTag c = create(fullMsg);
+ assertEquals(fullMsg, c.getFullMessage());
+ assertEquals(shortMsg, c.getShortMessage());
+ }
+
+ public void testParse_ShortLineOnlyEmbeddedLF() throws Exception {
+ final String fullMsg = "This is a\nshort message.";
+ final String shortMsg = fullMsg.replace('\n', ' ');
+ final RevTag c = create(fullMsg);
+ assertEquals(fullMsg, c.getFullMessage());
+ assertEquals(shortMsg, c.getShortMessage());
+ }
+
+ public void testParse_ShortLineOnlyEmbeddedAndEndingLF() throws Exception {
+ final String fullMsg = "This is a\nshort message.\n";
+ final String shortMsg = "This is a short message.";
+ final RevTag c = create(fullMsg);
+ assertEquals(fullMsg, c.getFullMessage());
+ assertEquals(shortMsg, c.getShortMessage());
+ }
+
+ public void testParse_GitStyleMessage() throws Exception {
+ final String shortMsg = "This fixes a bug.";
+ final String body = "We do it with magic and pixie dust and stuff.\n"
+ + "\n" + "Signed-off-by: A U. Thor <author@example.com>\n";
+ final String fullMsg = shortMsg + "\n" + "\n" + body;
+ final RevTag c = create(fullMsg);
+ assertEquals(fullMsg, c.getFullMessage());
+ assertEquals(shortMsg, c.getShortMessage());
+ }
+
+ private static ObjectId id(final String str) {
+ return ObjectId.fromString(str);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkCullTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkCullTest.java
new file mode 100644
index 0000000000..9e879c5f0d
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkCullTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.revwalk;
+
+public class RevWalkCullTest extends RevWalkTestCase {
+ public void testProperlyCullAllAncestors1() throws Exception {
+ // Credit goes to Junio C Hamano <gitster@pobox.com> for this
+ // test case in git-core (t/t6009-rev-list-parent.sh)
+ //
+ // We induce a clock skew so two is dated before one.
+ //
+ final RevCommit a = commit();
+ final RevCommit b = commit(-2400, a);
+ final RevCommit c = commit(b);
+ final RevCommit d = commit(c);
+
+ markStart(a);
+ markUninteresting(d);
+ assertNull(rw.next());
+ }
+
+ public void testProperlyCullAllAncestors2() throws Exception {
+ // Despite clock skew on c1 being very old it should not
+ // produce, neither should a or b, or any part of that chain.
+ //
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c1 = commit(-5, b);
+ final RevCommit c2 = commit(10, b);
+ final RevCommit d = commit(c1, c2);
+
+ markStart(d);
+ markUninteresting(c1);
+ assertCommit(d, rw.next());
+ assertCommit(c2, rw.next());
+ assertNull(rw.next());
+ }
+
+ public void testProperlyCullAllAncestors_LongHistory() throws Exception {
+ final RevCommit a = commit();
+ RevCommit b = commit(a);
+ for (int i = 0; i < 24; i++) {
+ b = commit(b);
+ if ((i & 2) == 0)
+ markUninteresting(b);
+ }
+ final RevCommit c = commit(b);
+
+ markStart(c);
+ markUninteresting(b);
+ assertCommit(c, rw.next());
+ assertNull(rw.next());
+
+ // We should have aborted before we got back so far that "a"
+ // would be parsed. Thus, its parents shouldn't be allocated.
+ //
+ assertNull(a.parents);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFilterTest.java
new file mode 100644
index 0000000000..db4c38e72b
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkFilterTest.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.revwalk;
+
+import java.io.IOException;
+import java.util.Date;
+
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.errors.StopWalkException;
+import org.eclipse.jgit.revwalk.filter.AndRevFilter;
+import org.eclipse.jgit.revwalk.filter.CommitTimeRevFilter;
+import org.eclipse.jgit.revwalk.filter.NotRevFilter;
+import org.eclipse.jgit.revwalk.filter.OrRevFilter;
+import org.eclipse.jgit.revwalk.filter.RevFilter;
+
+public class RevWalkFilterTest extends RevWalkTestCase {
+ private static final MyAll MY_ALL = new MyAll();
+
+ public void testFilter_ALL() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(b);
+
+ rw.setRevFilter(RevFilter.ALL);
+ markStart(c);
+ assertCommit(c, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ public void testFilter_Negate_ALL() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(b);
+
+ rw.setRevFilter(RevFilter.ALL.negate());
+ markStart(c);
+ assertNull(rw.next());
+ }
+
+ public void testFilter_NOT_ALL() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(b);
+
+ rw.setRevFilter(NotRevFilter.create(RevFilter.ALL));
+ markStart(c);
+ assertNull(rw.next());
+ }
+
+ public void testFilter_NONE() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(b);
+
+ rw.setRevFilter(RevFilter.NONE);
+ markStart(c);
+ assertNull(rw.next());
+ }
+
+ public void testFilter_NOT_NONE() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(b);
+
+ rw.setRevFilter(NotRevFilter.create(RevFilter.NONE));
+ markStart(c);
+ assertCommit(c, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ public void testFilter_ALL_And_NONE() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(b);
+
+ rw.setRevFilter(AndRevFilter.create(RevFilter.ALL, RevFilter.NONE));
+ markStart(c);
+ assertNull(rw.next());
+ }
+
+ public void testFilter_NONE_And_ALL() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(b);
+
+ rw.setRevFilter(AndRevFilter.create(RevFilter.NONE, RevFilter.ALL));
+ markStart(c);
+ assertNull(rw.next());
+ }
+
+ public void testFilter_ALL_Or_NONE() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(b);
+
+ rw.setRevFilter(OrRevFilter.create(RevFilter.ALL, RevFilter.NONE));
+ markStart(c);
+ assertCommit(c, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ public void testFilter_NONE_Or_ALL() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(b);
+
+ rw.setRevFilter(OrRevFilter.create(RevFilter.NONE, RevFilter.ALL));
+ markStart(c);
+ assertCommit(c, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ public void testFilter_MY_ALL_And_NONE() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(b);
+
+ rw.setRevFilter(AndRevFilter.create(MY_ALL, RevFilter.NONE));
+ markStart(c);
+ assertNull(rw.next());
+ }
+
+ public void testFilter_NONE_And_MY_ALL() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(b);
+
+ rw.setRevFilter(AndRevFilter.create(RevFilter.NONE, MY_ALL));
+ markStart(c);
+ assertNull(rw.next());
+ }
+
+ public void testFilter_MY_ALL_Or_NONE() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(b);
+
+ rw.setRevFilter(OrRevFilter.create(MY_ALL, RevFilter.NONE));
+ markStart(c);
+ assertCommit(c, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ public void testFilter_NONE_Or_MY_ALL() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(b);
+
+ rw.setRevFilter(OrRevFilter.create(RevFilter.NONE, MY_ALL));
+ markStart(c);
+ assertCommit(c, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ public void testFilter_NO_MERGES() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c1 = commit(b);
+ final RevCommit c2 = commit(b);
+ final RevCommit d = commit(c1, c2);
+ final RevCommit e = commit(d);
+
+ rw.setRevFilter(RevFilter.NO_MERGES);
+ markStart(e);
+ assertCommit(e, rw.next());
+ assertCommit(c2, rw.next());
+ assertCommit(c1, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ public void testCommitTimeRevFilter() throws Exception {
+ final RevCommit a = commit();
+ tick(100);
+
+ final RevCommit b = commit(a);
+ tick(100);
+
+ Date since = new Date(nowTick);
+ final RevCommit c1 = commit(b);
+ tick(100);
+
+ final RevCommit c2 = commit(b);
+ tick(100);
+
+ Date until = new Date(nowTick);
+ final RevCommit d = commit(c1, c2);
+ tick(100);
+
+ final RevCommit e = commit(d);
+
+ {
+ RevFilter after = CommitTimeRevFilter.after(since);
+ assertNotNull(after);
+ rw.setRevFilter(after);
+ markStart(e);
+ assertCommit(e, rw.next());
+ assertCommit(d, rw.next());
+ assertCommit(c2, rw.next());
+ assertCommit(c1, rw.next());
+ assertNull(rw.next());
+ }
+
+ {
+ RevFilter before = CommitTimeRevFilter.before(until);
+ assertNotNull(before);
+ rw.reset();
+ rw.setRevFilter(before);
+ markStart(e);
+ assertCommit(c2, rw.next());
+ assertCommit(c1, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ {
+ RevFilter between = CommitTimeRevFilter.between(since, until);
+ assertNotNull(between);
+ rw.reset();
+ rw.setRevFilter(between);
+ markStart(e);
+ assertCommit(c2, rw.next());
+ assertCommit(c1, rw.next());
+ assertNull(rw.next());
+ }
+ }
+
+ private static class MyAll extends RevFilter {
+ @Override
+ public RevFilter clone() {
+ return this;
+ }
+
+ @Override
+ public boolean include(RevWalk walker, RevCommit cmit)
+ throws StopWalkException, MissingObjectException,
+ IncorrectObjectTypeException, IOException {
+ return true;
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkMergeBaseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkMergeBaseTest.java
new file mode 100644
index 0000000000..10c9f9b12e
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkMergeBaseTest.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.revwalk;
+
+import org.eclipse.jgit.revwalk.filter.RevFilter;
+import org.eclipse.jgit.treewalk.filter.TreeFilter;
+
+public class RevWalkMergeBaseTest extends RevWalkTestCase {
+ public void testNone() throws Exception {
+ final RevCommit c1 = commit(commit(commit()));
+ final RevCommit c2 = commit(commit(commit()));
+
+ rw.setRevFilter(RevFilter.MERGE_BASE);
+ markStart(c1);
+ markStart(c2);
+ assertNull(rw.next());
+ }
+
+ public void testDisallowTreeFilter() throws Exception {
+ final RevCommit c1 = commit();
+ final RevCommit c2 = commit();
+
+ rw.setRevFilter(RevFilter.MERGE_BASE);
+ rw.setTreeFilter(TreeFilter.ANY_DIFF);
+ markStart(c1);
+ markStart(c2);
+ try {
+ assertNull(rw.next());
+ fail("did not throw IllegalStateException");
+ } catch (IllegalStateException ise) {
+ // expected result
+ }
+ }
+
+ public void testSimple() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c1 = commit(commit(commit(commit(commit(b)))));
+ final RevCommit c2 = commit(commit(commit(commit(commit(b)))));
+
+ rw.setRevFilter(RevFilter.MERGE_BASE);
+ markStart(c1);
+ markStart(c2);
+ assertCommit(b, rw.next());
+ assertNull(rw.next());
+ }
+
+ public void testMultipleHeads_SameBase1() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c1 = commit(commit(commit(commit(commit(b)))));
+ final RevCommit c2 = commit(commit(commit(commit(commit(b)))));
+ final RevCommit c3 = commit(commit(commit(b)));
+
+ rw.setRevFilter(RevFilter.MERGE_BASE);
+ markStart(c1);
+ markStart(c2);
+ markStart(c3);
+ assertCommit(b, rw.next());
+ assertNull(rw.next());
+ }
+
+ public void testMultipleHeads_SameBase2() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(b);
+ final RevCommit d1 = commit(commit(commit(commit(commit(b)))));
+ final RevCommit d2 = commit(commit(commit(commit(commit(c)))));
+ final RevCommit d3 = commit(commit(commit(c)));
+
+ rw.setRevFilter(RevFilter.MERGE_BASE);
+ markStart(d1);
+ markStart(d2);
+ markStart(d3);
+ assertCommit(b, rw.next());
+ assertNull(rw.next());
+ }
+
+ public void testCrissCross() throws Exception {
+ // See http://marc.info/?l=git&m=111463358500362&w=2 for a nice
+ // description of what this test is creating. We don't have a
+ // clean merge base for d,e as they each merged the parents b,c
+ // in different orders.
+ //
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(a);
+ final RevCommit d = commit(b, c);
+ final RevCommit e = commit(c, b);
+
+ rw.setRevFilter(RevFilter.MERGE_BASE);
+ markStart(d);
+ markStart(e);
+ assertCommit(c, rw.next());
+ assertCommit(b, rw.next());
+ assertNull(rw.next());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter1Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter1Test.java
new file mode 100644
index 0000000000..986a886566
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter1Test.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.revwalk;
+
+import java.util.Collections;
+
+import org.eclipse.jgit.treewalk.filter.AndTreeFilter;
+import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
+import org.eclipse.jgit.treewalk.filter.TreeFilter;
+
+public class RevWalkPathFilter1Test extends RevWalkTestCase {
+ protected void filter(final String path) {
+ rw.setTreeFilter(AndTreeFilter.create(PathFilterGroup
+ .createFromStrings(Collections.singleton(path)),
+ TreeFilter.ANY_DIFF));
+ }
+
+ public void testEmpty_EmptyTree() throws Exception {
+ final RevCommit a = commit();
+ filter("a");
+ markStart(a);
+ assertNull(rw.next());
+ }
+
+ public void testEmpty_NoMatch() throws Exception {
+ final RevCommit a = commit(tree(file("0", blob("0"))));
+ filter("a");
+ markStart(a);
+ assertNull(rw.next());
+ }
+
+ public void testSimple1() throws Exception {
+ final RevCommit a = commit(tree(file("0", blob("0"))));
+ filter("0");
+ markStart(a);
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ public void testEdits_MatchNone() throws Exception {
+ final RevCommit a = commit(tree(file("0", blob("a"))));
+ final RevCommit b = commit(tree(file("0", blob("b"))), a);
+ final RevCommit c = commit(tree(file("0", blob("c"))), b);
+ final RevCommit d = commit(tree(file("0", blob("d"))), c);
+ filter("a");
+ markStart(d);
+ assertNull(rw.next());
+ }
+
+ public void testEdits_MatchAll() throws Exception {
+ final RevCommit a = commit(tree(file("0", blob("a"))));
+ final RevCommit b = commit(tree(file("0", blob("b"))), a);
+ final RevCommit c = commit(tree(file("0", blob("c"))), b);
+ final RevCommit d = commit(tree(file("0", blob("d"))), c);
+ filter("0");
+ markStart(d);
+ assertCommit(d, rw.next());
+ assertCommit(c, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ public void testStringOfPearls_FilePath1() throws Exception {
+ final RevCommit a = commit(tree(file("d/f", blob("a"))));
+ final RevCommit b = commit(tree(file("d/f", blob("a"))), a);
+ final RevCommit c = commit(tree(file("d/f", blob("b"))), b);
+ filter("d/f");
+ markStart(c);
+
+ assertCommit(c, rw.next());
+ assertEquals(1, c.getParentCount());
+ assertCommit(a, c.getParent(0)); // b was skipped
+
+ assertCommit(a, rw.next());
+ assertEquals(0, a.getParentCount());
+ assertNull(rw.next());
+ }
+
+ public void testStringOfPearls_FilePath2() throws Exception {
+ final RevCommit a = commit(tree(file("d/f", blob("a"))));
+ final RevCommit b = commit(tree(file("d/f", blob("a"))), a);
+ final RevCommit c = commit(tree(file("d/f", blob("b"))), b);
+ final RevCommit d = commit(tree(file("d/f", blob("b"))), c);
+ filter("d/f");
+ markStart(d);
+
+ // d was skipped
+ assertCommit(c, rw.next());
+ assertEquals(1, c.getParentCount());
+ assertCommit(a, c.getParent(0)); // b was skipped
+
+ assertCommit(a, rw.next());
+ assertEquals(0, a.getParentCount());
+ assertNull(rw.next());
+ }
+
+ public void testStringOfPearls_DirPath2() throws Exception {
+ final RevCommit a = commit(tree(file("d/f", blob("a"))));
+ final RevCommit b = commit(tree(file("d/f", blob("a"))), a);
+ final RevCommit c = commit(tree(file("d/f", blob("b"))), b);
+ final RevCommit d = commit(tree(file("d/f", blob("b"))), c);
+ filter("d");
+ markStart(d);
+
+ // d was skipped
+ assertCommit(c, rw.next());
+ assertEquals(1, c.getParentCount());
+ assertCommit(a, c.getParent(0)); // b was skipped
+
+ assertCommit(a, rw.next());
+ assertEquals(0, a.getParentCount());
+ assertNull(rw.next());
+ }
+
+ public void testStringOfPearls_FilePath3() throws Exception {
+ final RevCommit a = commit(tree(file("d/f", blob("a"))));
+ final RevCommit b = commit(tree(file("d/f", blob("a"))), a);
+ final RevCommit c = commit(tree(file("d/f", blob("b"))), b);
+ final RevCommit d = commit(tree(file("d/f", blob("b"))), c);
+ final RevCommit e = commit(tree(file("d/f", blob("b"))), d);
+ final RevCommit f = commit(tree(file("d/f", blob("b"))), e);
+ final RevCommit g = commit(tree(file("d/f", blob("b"))), f);
+ final RevCommit h = commit(tree(file("d/f", blob("b"))), g);
+ final RevCommit i = commit(tree(file("d/f", blob("c"))), h);
+ filter("d/f");
+ markStart(i);
+
+ assertCommit(i, rw.next());
+ assertEquals(1, i.getParentCount());
+ assertCommit(c, i.getParent(0)); // h..d was skipped
+
+ assertCommit(c, rw.next());
+ assertEquals(1, c.getParentCount());
+ assertCommit(a, c.getParent(0)); // b was skipped
+
+ assertCommit(a, rw.next());
+ assertEquals(0, a.getParentCount());
+ assertNull(rw.next());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter6012Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter6012Test.java
new file mode 100644
index 0000000000..73d41eae64
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkPathFilter6012Test.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.revwalk;
+
+import java.lang.reflect.Field;
+import java.util.Collections;
+import java.util.HashMap;
+
+import org.eclipse.jgit.treewalk.filter.AndTreeFilter;
+import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
+import org.eclipse.jgit.treewalk.filter.TreeFilter;
+
+// Note: Much of this test case is broken as it depends upon
+// the graph applying topological sorting *before* doing merge
+// simplification. It also depends upon a difference between
+// full history and non-full history for a path, something we
+// don't quite yet have a distiction for in JGit.
+//
+public class RevWalkPathFilter6012Test extends RevWalkTestCase {
+ private static final String pA = "pA", pF = "pF", pE = "pE";
+
+ private RevCommit a, b, c, d, e, f, g, h, i;
+
+ private HashMap<RevCommit, String> byName;
+
+ public void setUp() throws Exception {
+ super.setUp();
+
+ // Test graph was stolen from git-core t6012-rev-list-simplify
+ // (by Junio C Hamano in 65347030590bcc251a9ff2ed96487a0f1b9e9fa8)
+ //
+ final RevBlob zF = blob("zF");
+ final RevBlob zH = blob("zH");
+ final RevBlob zI = blob("zI");
+ final RevBlob zS = blob("zS");
+ final RevBlob zY = blob("zY");
+
+ a = commit(tree(file(pF, zH)));
+ b = commit(tree(file(pF, zI)), a);
+ c = commit(tree(file(pF, zI)), a);
+ d = commit(tree(file(pA, zS), file(pF, zI)), c);
+ parse(d);
+ e = commit(d.getTree(), d, b);
+ f = commit(tree(file(pA, zS), file(pE, zY), file(pF, zI)), e);
+ parse(f);
+ g = commit(tree(file(pE, zY), file(pF, zI)), b);
+ h = commit(f.getTree(), g, f);
+ i = commit(tree(file(pA, zS), file(pE, zY), file(pF, zF)), h);
+
+ byName = new HashMap<RevCommit, String>();
+ for (Field z : RevWalkPathFilter6012Test.class.getDeclaredFields()) {
+ if (z.getType() == RevCommit.class)
+ byName.put((RevCommit) z.get(this), z.getName());
+ }
+ }
+
+ protected void check(final RevCommit... order) throws Exception {
+ markStart(i);
+ final StringBuilder act = new StringBuilder();
+ for (final RevCommit z : rw) {
+ final String name = byName.get(z);
+ assertNotNull(name);
+ act.append(name);
+ act.append(' ');
+ }
+ final StringBuilder exp = new StringBuilder();
+ for (final RevCommit z : order) {
+ final String name = byName.get(z);
+ assertNotNull(name);
+ exp.append(name);
+ exp.append(' ');
+ }
+ assertEquals(exp.toString(), act.toString());
+ }
+
+ protected void filter(final String path) {
+ rw.setTreeFilter(AndTreeFilter.create(PathFilterGroup
+ .createFromStrings(Collections.singleton(path)),
+ TreeFilter.ANY_DIFF));
+ }
+
+ public void test1() throws Exception {
+ // TODO --full-history
+ check(i, h, g, f, e, d, c, b, a);
+ }
+
+ public void test2() throws Exception {
+ // TODO --full-history
+ filter(pF);
+ // TODO fix broken test
+ // check(i, h, e, c, b, a);
+ }
+
+ public void test3() throws Exception {
+ // TODO --full-history
+ rw.sort(RevSort.TOPO);
+ filter(pF);
+ // TODO fix broken test
+ // check(i, h, e, c, b, a);
+ }
+
+ public void test4() throws Exception {
+ // TODO --full-history
+ rw.sort(RevSort.COMMIT_TIME_DESC);
+ filter(pF);
+ // TODO fix broken test
+ // check(i, h, e, c, b, a);
+ }
+
+ public void test5() throws Exception {
+ // TODO --simplify-merges
+ filter(pF);
+ // TODO fix broken test
+ // check(i, e, c, b, a);
+ }
+
+ public void test6() throws Exception {
+ filter(pF);
+ check(i, b, a);
+ }
+
+ public void test7() throws Exception {
+ rw.sort(RevSort.TOPO);
+ filter(pF);
+ check(i, b, a);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkSortTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkSortTest.java
new file mode 100644
index 0000000000..0d3e0cf5aa
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkSortTest.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.revwalk;
+
+public class RevWalkSortTest extends RevWalkTestCase {
+ public void testSort_Default() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(1, a);
+ final RevCommit c = commit(1, b);
+ final RevCommit d = commit(1, c);
+
+ markStart(d);
+ assertCommit(d, rw.next());
+ assertCommit(c, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ public void testSort_COMMIT_TIME_DESC() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(b);
+ final RevCommit d = commit(c);
+
+ rw.sort(RevSort.COMMIT_TIME_DESC);
+ markStart(d);
+ assertCommit(d, rw.next());
+ assertCommit(c, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ public void testSort_REVERSE() throws Exception {
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(b);
+ final RevCommit d = commit(c);
+
+ rw.sort(RevSort.REVERSE);
+ markStart(d);
+ assertCommit(a, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(c, rw.next());
+ assertCommit(d, rw.next());
+ assertNull(rw.next());
+ }
+
+ public void testSort_COMMIT_TIME_DESC_OutOfOrder1() throws Exception {
+ // Despite being out of order time-wise, a strand-of-pearls must
+ // still maintain topological order.
+ //
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c = commit(-5, b);
+ final RevCommit d = commit(10, c);
+ assertTrue(parse(a).getCommitTime() < parse(d).getCommitTime());
+ assertTrue(parse(c).getCommitTime() < parse(b).getCommitTime());
+
+ rw.sort(RevSort.COMMIT_TIME_DESC);
+ markStart(d);
+ assertCommit(d, rw.next());
+ assertCommit(c, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ public void testSort_COMMIT_TIME_DESC_OutOfOrder2() throws Exception {
+ // c1 is back dated before its parent.
+ //
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c1 = commit(-5, b);
+ final RevCommit c2 = commit(10, b);
+ final RevCommit d = commit(c1, c2);
+
+ rw.sort(RevSort.COMMIT_TIME_DESC);
+ markStart(d);
+ assertCommit(d, rw.next());
+ assertCommit(c2, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a, rw.next());
+ assertCommit(c1, rw.next());
+ assertNull(rw.next());
+ }
+
+ public void testSort_TOPO() throws Exception {
+ // c1 is back dated before its parent.
+ //
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c1 = commit(-5, b);
+ final RevCommit c2 = commit(10, b);
+ final RevCommit d = commit(c1, c2);
+
+ rw.sort(RevSort.TOPO);
+ markStart(d);
+ assertCommit(d, rw.next());
+ assertCommit(c2, rw.next());
+ assertCommit(c1, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(a, rw.next());
+ assertNull(rw.next());
+ }
+
+ public void testSort_TOPO_REVERSE() throws Exception {
+ // c1 is back dated before its parent.
+ //
+ final RevCommit a = commit();
+ final RevCommit b = commit(a);
+ final RevCommit c1 = commit(-5, b);
+ final RevCommit c2 = commit(10, b);
+ final RevCommit d = commit(c1, c2);
+
+ rw.sort(RevSort.TOPO);
+ rw.sort(RevSort.REVERSE, true);
+ markStart(d);
+ assertCommit(a, rw.next());
+ assertCommit(b, rw.next());
+ assertCommit(c1, rw.next());
+ assertCommit(c2, rw.next());
+ assertCommit(d, rw.next());
+ assertNull(rw.next());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java
new file mode 100644
index 0000000000..50fbce41aa
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkTestCase.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.revwalk;
+
+import java.util.Collections;
+import java.util.Date;
+
+import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheBuilder;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.lib.Commit;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectWriter;
+import org.eclipse.jgit.lib.PersonIdent;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+import org.eclipse.jgit.lib.Tag;
+import org.eclipse.jgit.lib.Tree;
+import org.eclipse.jgit.treewalk.TreeWalk;
+import org.eclipse.jgit.treewalk.filter.PathFilterGroup;
+
+/** Support for tests of the {@link RevWalk} class. */
+public abstract class RevWalkTestCase extends RepositoryTestCase {
+ protected ObjectWriter ow;
+
+ protected RevTree emptyTree;
+
+ protected long nowTick;
+
+ protected RevWalk rw;
+
+ public void setUp() throws Exception {
+ super.setUp();
+ ow = new ObjectWriter(db);
+ rw = createRevWalk();
+ emptyTree = rw.parseTree(ow.writeTree(new Tree(db)));
+ nowTick = 1236977987000L;
+ }
+
+ protected RevWalk createRevWalk() {
+ return new RevWalk(db);
+ }
+
+ protected void tick(final int secDelta) {
+ nowTick += secDelta * 1000L;
+ }
+
+ protected RevBlob blob(final String content) throws Exception {
+ return rw.lookupBlob(ow.writeBlob(Constants.encode(content)));
+ }
+
+ protected DirCacheEntry file(final String path, final RevBlob blob)
+ throws Exception {
+ final DirCacheEntry e = new DirCacheEntry(path);
+ e.setFileMode(FileMode.REGULAR_FILE);
+ e.setObjectId(blob);
+ return e;
+ }
+
+ protected RevTree tree(final DirCacheEntry... entries) throws Exception {
+ final DirCache dc = DirCache.newInCore();
+ final DirCacheBuilder b = dc.builder();
+ for (final DirCacheEntry e : entries)
+ b.add(e);
+ b.finish();
+ return rw.lookupTree(dc.writeTree(ow));
+ }
+
+ protected RevObject get(final RevTree tree, final String path)
+ throws Exception {
+ final TreeWalk tw = new TreeWalk(db);
+ tw.setFilter(PathFilterGroup.createFromStrings(Collections
+ .singleton(path)));
+ tw.reset(tree);
+ while (tw.next()) {
+ if (tw.isSubtree() && !path.equals(tw.getPathString())) {
+ tw.enterSubtree();
+ continue;
+ }
+ final ObjectId entid = tw.getObjectId(0);
+ final FileMode entmode = tw.getFileMode(0);
+ return rw.lookupAny(entid, entmode.getObjectType());
+ }
+ fail("Can't find " + path + " in tree " + tree.name());
+ return null; // never reached.
+ }
+
+ protected RevCommit commit(final RevCommit... parents) throws Exception {
+ return commit(1, emptyTree, parents);
+ }
+
+ protected RevCommit commit(final RevTree tree, final RevCommit... parents)
+ throws Exception {
+ return commit(1, tree, parents);
+ }
+
+ protected RevCommit commit(final int secDelta, final RevCommit... parents)
+ throws Exception {
+ return commit(secDelta, emptyTree, parents);
+ }
+
+ protected RevCommit commit(final int secDelta, final RevTree tree,
+ final RevCommit... parents) throws Exception {
+ tick(secDelta);
+ final Commit c = new Commit(db);
+ c.setTreeId(tree);
+ c.setParentIds(parents);
+ c.setAuthor(new PersonIdent(jauthor, new Date(nowTick)));
+ c.setCommitter(new PersonIdent(jcommitter, new Date(nowTick)));
+ c.setMessage("");
+ return rw.lookupCommit(ow.writeCommit(c));
+ }
+
+ protected RevTag tag(final String name, final RevObject dst)
+ throws Exception {
+ final Tag t = new Tag(db);
+ t.setType(Constants.typeString(dst.getType()));
+ t.setObjId(dst.toObjectId());
+ t.setTag(name);
+ t.setTagger(new PersonIdent(jcommitter, new Date(nowTick)));
+ t.setMessage("");
+ return (RevTag) rw.lookupAny(ow.writeTag(t), Constants.OBJ_TAG);
+ }
+
+ protected <T extends RevObject> T parse(final T t) throws Exception {
+ rw.parseBody(t);
+ return t;
+ }
+
+ protected void markStart(final RevCommit commit) throws Exception {
+ rw.markStart(commit);
+ }
+
+ protected void markUninteresting(final RevCommit commit) throws Exception {
+ rw.markUninteresting(commit);
+ }
+
+ protected void assertCommit(final RevCommit exp, final RevCommit act) {
+ assertSame(exp, act);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java
new file mode 100644
index 0000000000..fb9b358b2a
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/BundleWriterTest.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * Copyright (C) 2008, Mike Ralphson <mike@abacus.co.uk>
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.util.Collections;
+import java.util.Set;
+
+import org.eclipse.jgit.errors.MissingBundlePrerequisiteException;
+import org.eclipse.jgit.errors.NotSupportedException;
+import org.eclipse.jgit.errors.TransportException;
+import org.eclipse.jgit.lib.NullProgressMonitor;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+import org.eclipse.jgit.revwalk.RevCommit;
+import org.eclipse.jgit.revwalk.RevWalk;
+
+public class BundleWriterTest extends RepositoryTestCase {
+
+ public void testWrite0() throws Exception {
+ // Create a tiny bundle, (well one of) the first commits only
+ final byte[] bundle = makeBundle("refs/heads/firstcommit",
+ "42e4e7c5e507e113ebbb7801b16b52cf867b7ce1", null);
+
+ // Then we clone a new repo from that bundle and do a simple test. This
+ // makes sure
+ // we could read the bundle we created.
+ Repository newRepo = createNewEmptyRepo();
+ FetchResult fetchResult = fetchFromBundle(newRepo, bundle);
+ Ref advertisedRef = fetchResult
+ .getAdvertisedRef("refs/heads/firstcommit");
+
+ // We expect firstcommit to appear by id
+ assertEquals("42e4e7c5e507e113ebbb7801b16b52cf867b7ce1", advertisedRef
+ .getObjectId().name());
+ // ..and by name as the bundle created a new ref
+ assertEquals("42e4e7c5e507e113ebbb7801b16b52cf867b7ce1", newRepo
+ .resolve("refs/heads/firstcommit").name());
+ }
+
+ /**
+ * Incremental bundle test
+ *
+ * @throws Exception
+ */
+ public void testWrite1() throws Exception {
+ byte[] bundle;
+
+ // Create a small bundle, an early commit
+ bundle = makeBundle("refs/heads/aa", db.resolve("a").name(), null);
+
+ // Then we clone a new repo from that bundle and do a simple test. This
+ // makes sure
+ // we could read the bundle we created.
+ Repository newRepo = createNewEmptyRepo();
+ FetchResult fetchResult = fetchFromBundle(newRepo, bundle);
+ Ref advertisedRef = fetchResult.getAdvertisedRef("refs/heads/aa");
+
+ assertEquals(db.resolve("a").name(), advertisedRef.getObjectId().name());
+ assertEquals(db.resolve("a").name(), newRepo.resolve("refs/heads/aa")
+ .name());
+ assertNull(newRepo.resolve("refs/heads/a"));
+
+ // Next an incremental bundle
+ bundle = makeBundle("refs/heads/cc", db.resolve("c").name(),
+ new RevWalk(db).parseCommit(db.resolve("a").toObjectId()));
+ fetchResult = fetchFromBundle(newRepo, bundle);
+ advertisedRef = fetchResult.getAdvertisedRef("refs/heads/cc");
+ assertEquals(db.resolve("c").name(), advertisedRef.getObjectId().name());
+ assertEquals(db.resolve("c").name(), newRepo.resolve("refs/heads/cc")
+ .name());
+ assertNull(newRepo.resolve("refs/heads/c"));
+ assertNull(newRepo.resolve("refs/heads/a")); // still unknown
+
+ try {
+ // Check that we actually needed the first bundle
+ Repository newRepo2 = createNewEmptyRepo();
+ fetchResult = fetchFromBundle(newRepo2, bundle);
+ fail("We should not be able to fetch from bundle with prerequisites that are not fulfilled");
+ } catch (MissingBundlePrerequisiteException e) {
+ assertTrue(e.getMessage()
+ .indexOf(db.resolve("refs/heads/a").name()) >= 0);
+ }
+ }
+
+ private FetchResult fetchFromBundle(final Repository newRepo,
+ final byte[] bundle) throws URISyntaxException,
+ NotSupportedException, TransportException {
+ final URIish uri = new URIish("in-memory://");
+ final ByteArrayInputStream in = new ByteArrayInputStream(bundle);
+ final RefSpec rs = new RefSpec("refs/heads/*:refs/heads/*");
+ final Set<RefSpec> refs = Collections.singleton(rs);
+ return new TransportBundleStream(newRepo, uri, in).fetch(
+ NullProgressMonitor.INSTANCE, refs);
+ }
+
+ private byte[] makeBundle(final String name,
+ final String anObjectToInclude, final RevCommit assume)
+ throws FileNotFoundException, IOException {
+ final BundleWriter bw;
+
+ bw = new BundleWriter(db, NullProgressMonitor.INSTANCE);
+ bw.include(name, ObjectId.fromString(anObjectToInclude));
+ if (assume != null)
+ bw.assume(assume);
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ bw.writeBundle(out);
+ return out.toByteArray();
+ }
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/IndexPackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/IndexPackTest.java
new file mode 100644
index 0000000000..78f4393c3a
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/IndexPackTest.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * Copyright (C) 2008, Imran M Yousuf <imyousuf@smartitengineering.com>
+ * Copyright (C) 2007-2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.PackFile;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+import org.eclipse.jgit.lib.TextProgressMonitor;
+import org.eclipse.jgit.util.JGitTestUtil;
+
+/**
+ * Test indexing of git packs. A pack is read from a stream, copied
+ * to a new pack and an index is created. Then the packs are tested
+ * to make sure they contain the expected objects (well we don't test
+ * for all of them unless the packs are very small).
+ */
+public class IndexPackTest extends RepositoryTestCase {
+
+ /**
+ * Test indexing one of the test packs in the egit repo. It has deltas.
+ *
+ * @throws IOException
+ */
+ public void test1() throws IOException {
+ File packFile = JGitTestUtil.getTestResourceFile("pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.pack");
+ final InputStream is = new FileInputStream(packFile);
+ try {
+ IndexPack pack = new IndexPack(db, is, new File(trash, "tmp_pack1"));
+ pack.index(new TextProgressMonitor());
+ PackFile file = new PackFile(new File(trash, "tmp_pack1.idx"), new File(trash, "tmp_pack1.pack"));
+ assertTrue(file.hasObject(ObjectId.fromString("4b825dc642cb6eb9a060e54bf8d69288fbee4904")));
+ assertTrue(file.hasObject(ObjectId.fromString("540a36d136cf413e4b064c2b0e0a4db60f77feab")));
+ assertTrue(file.hasObject(ObjectId.fromString("5b6e7c66c276e7610d4a73c70ec1a1f7c1003259")));
+ assertTrue(file.hasObject(ObjectId.fromString("6ff87c4664981e4397625791c8ea3bbb5f2279a3")));
+ assertTrue(file.hasObject(ObjectId.fromString("82c6b885ff600be425b4ea96dee75dca255b69e7")));
+ assertTrue(file.hasObject(ObjectId.fromString("902d5476fa249b7abc9d84c611577a81381f0327")));
+ assertTrue(file.hasObject(ObjectId.fromString("aabf2ffaec9b497f0950352b3e582d73035c2035")));
+ assertTrue(file.hasObject(ObjectId.fromString("c59759f143fb1fe21c197981df75a7ee00290799")));
+ } finally {
+ is.close();
+ }
+ }
+
+ /**
+ * This is just another pack. It so happens that we have two convenient pack to
+ * test with in the repository.
+ *
+ * @throws IOException
+ */
+ public void test2() throws IOException {
+ File packFile = JGitTestUtil.getTestResourceFile("pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.pack");
+ final InputStream is = new FileInputStream(packFile);
+ try {
+ IndexPack pack = new IndexPack(db, is, new File(trash, "tmp_pack2"));
+ pack.index(new TextProgressMonitor());
+ PackFile file = new PackFile(new File(trash, "tmp_pack2.idx"), new File(trash, "tmp_pack2.pack"));
+ assertTrue(file.hasObject(ObjectId.fromString("02ba32d3649e510002c21651936b7077aa75ffa9")));
+ assertTrue(file.hasObject(ObjectId.fromString("0966a434eb1a025db6b71485ab63a3bfbea520b6")));
+ assertTrue(file.hasObject(ObjectId.fromString("09efc7e59a839528ac7bda9fa020dc9101278680")));
+ assertTrue(file.hasObject(ObjectId.fromString("0a3d7772488b6b106fb62813c4d6d627918d9181")));
+ assertTrue(file.hasObject(ObjectId.fromString("1004d0d7ac26fbf63050a234c9b88a46075719d3")));
+ assertTrue(file.hasObject(ObjectId.fromString("10da5895682013006950e7da534b705252b03be6")));
+ assertTrue(file.hasObject(ObjectId.fromString("1203b03dc816ccbb67773f28b3c19318654b0bc8")));
+ assertTrue(file.hasObject(ObjectId.fromString("15fae9e651043de0fd1deef588aa3fbf5a7a41c6")));
+ assertTrue(file.hasObject(ObjectId.fromString("16f9ec009e5568c435f473ba3a1df732d49ce8c3")));
+ assertTrue(file.hasObject(ObjectId.fromString("1fd7d579fb6ae3fe942dc09c2c783443d04cf21e")));
+ assertTrue(file.hasObject(ObjectId.fromString("20a8ade77639491ea0bd667bf95de8abf3a434c8")));
+ assertTrue(file.hasObject(ObjectId.fromString("2675188fd86978d5bc4d7211698b2118ae3bf658")));
+ // and lots more...
+ } finally {
+ is.close();
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/LongMapTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/LongMapTest.java
new file mode 100644
index 0000000000..abb6fe0db0
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/LongMapTest.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import junit.framework.TestCase;
+
+public class LongMapTest extends TestCase {
+ private LongMap<Long> map;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ map = new LongMap<Long>();
+ }
+
+ public void testEmptyMap() {
+ assertFalse(map.containsKey(0));
+ assertFalse(map.containsKey(1));
+
+ assertNull(map.get(0));
+ assertNull(map.get(1));
+
+ assertNull(map.remove(0));
+ assertNull(map.remove(1));
+ }
+
+ public void testInsertMinValue() {
+ final Long min = Long.valueOf(Long.MIN_VALUE);
+ assertNull(map.put(Long.MIN_VALUE, min));
+ assertTrue(map.containsKey(Long.MIN_VALUE));
+ assertSame(min, map.get(Long.MIN_VALUE));
+ assertFalse(map.containsKey(Integer.MIN_VALUE));
+ }
+
+ public void testReplaceMaxValue() {
+ final Long min = Long.valueOf(Long.MAX_VALUE);
+ final Long one = Long.valueOf(1);
+ assertNull(map.put(Long.MAX_VALUE, min));
+ assertSame(min, map.get(Long.MAX_VALUE));
+ assertSame(min, map.put(Long.MAX_VALUE, one));
+ assertSame(one, map.get(Long.MAX_VALUE));
+ }
+
+ public void testRemoveOne() {
+ final long start = 1;
+ assertNull(map.put(start, Long.valueOf(start)));
+ assertEquals(Long.valueOf(start), map.remove(start));
+ assertFalse(map.containsKey(start));
+ }
+
+ public void testRemoveCollision1() {
+ // This test relies upon the fact that we always >>> 1 the value
+ // to derive an unsigned hash code. Thus, 0 and 1 fall into the
+ // same hash bucket. Further it relies on the fact that we add
+ // the 2nd put at the top of the chain, so removing the 1st will
+ // cause a different code path.
+ //
+ assertNull(map.put(0, Long.valueOf(0)));
+ assertNull(map.put(1, Long.valueOf(1)));
+ assertEquals(Long.valueOf(0), map.remove(0));
+
+ assertFalse(map.containsKey(0));
+ assertTrue(map.containsKey(1));
+ }
+
+ public void testRemoveCollision2() {
+ // This test relies upon the fact that we always >>> 1 the value
+ // to derive an unsigned hash code. Thus, 0 and 1 fall into the
+ // same hash bucket. Further it relies on the fact that we add
+ // the 2nd put at the top of the chain, so removing the 2nd will
+ // cause a different code path.
+ //
+ assertNull(map.put(0, Long.valueOf(0)));
+ assertNull(map.put(1, Long.valueOf(1)));
+ assertEquals(Long.valueOf(1), map.remove(1));
+
+ assertTrue(map.containsKey(0));
+ assertFalse(map.containsKey(1));
+ }
+
+ public void testSmallMap() {
+ final long start = 12;
+ final long n = 8;
+ for (long i = start; i < start + n; i++)
+ assertNull(map.put(i, Long.valueOf(i)));
+ for (long i = start; i < start + n; i++)
+ assertEquals(Long.valueOf(i), map.get(i));
+ }
+
+ public void testLargeMap() {
+ final long start = Integer.MAX_VALUE;
+ final long n = 100000;
+ for (long i = start; i < start + n; i++)
+ assertNull(map.put(i, Long.valueOf(i)));
+ for (long i = start; i < start + n; i++)
+ assertEquals(Long.valueOf(i), map.get(i));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/OpenSshConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/OpenSshConfigTest.java
new file mode 100644
index 0000000000..f66e2fd33e
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/OpenSshConfigTest.java
@@ -0,0 +1,228 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+
+import org.eclipse.jgit.lib.RepositoryTestCase;
+import org.eclipse.jgit.transport.OpenSshConfig.Host;
+
+public class OpenSshConfigTest extends RepositoryTestCase {
+ private File home;
+
+ private File configFile;
+
+ private OpenSshConfig osc;
+
+ public void setUp() throws Exception {
+ super.setUp();
+
+ home = new File(trash, "home");
+ home.mkdir();
+
+ configFile = new File(new File(home, ".ssh"), "config");
+ configFile.getParentFile().mkdir();
+
+ System.setProperty("user.name", "jex_junit");
+ osc = new OpenSshConfig(home, configFile);
+ }
+
+ private void config(final String data) throws IOException {
+ final OutputStreamWriter fw = new OutputStreamWriter(
+ new FileOutputStream(configFile), "UTF-8");
+ fw.write(data);
+ fw.close();
+ }
+
+ public void testNoConfig() {
+ final Host h = osc.lookup("repo.or.cz");
+ assertNotNull(h);
+ assertEquals("repo.or.cz", h.getHostName());
+ assertEquals("jex_junit", h.getUser());
+ assertEquals(22, h.getPort());
+ assertNull(h.getIdentityFile());
+ }
+
+ public void testSeparatorParsing() throws Exception {
+ config("Host\tfirst\n" +
+ "\tHostName\tfirst.tld\n" +
+ "\n" +
+ "Host second\n" +
+ " HostName\tsecond.tld\n" +
+ "Host=third\n" +
+ "HostName=third.tld\n\n\n" +
+ "\t Host = fourth\n\n\n" +
+ " \t HostName\t=fourth.tld\n" +
+ "Host\t = last\n" +
+ "HostName \t last.tld");
+ assertNotNull(osc.lookup("first"));
+ assertEquals("first.tld", osc.lookup("first").getHostName());
+ assertNotNull(osc.lookup("second"));
+ assertEquals("second.tld", osc.lookup("second").getHostName());
+ assertNotNull(osc.lookup("third"));
+ assertEquals("third.tld", osc.lookup("third").getHostName());
+ assertNotNull(osc.lookup("fourth"));
+ assertEquals("fourth.tld", osc.lookup("fourth").getHostName());
+ assertNotNull(osc.lookup("last"));
+ assertEquals("last.tld", osc.lookup("last").getHostName());
+ }
+
+ public void testQuoteParsing() throws Exception {
+ config("Host \"good\"\n" +
+ " HostName=\"good.tld\"\n" +
+ " Port=\"6007\"\n" +
+ " User=\"gooduser\"\n" +
+ "Host multiple unquoted and \"quoted\" \"hosts\"\n" +
+ " Port=\"2222\"\n" +
+ "Host \"spaced\"\n" +
+ "# Bad host name, but testing preservation of spaces\n" +
+ " HostName=\" spaced\ttld \"\n" +
+ "# Misbalanced quotes\n" +
+ "Host \"bad\"\n" +
+ "# OpenSSH doesn't allow this but ...\n" +
+ " HostName=bad.tld\"\n");
+ assertEquals("good.tld", osc.lookup("good").getHostName());
+ assertEquals("gooduser", osc.lookup("good").getUser());
+ assertEquals(6007, osc.lookup("good").getPort());
+ assertEquals(2222, osc.lookup("multiple").getPort());
+ assertEquals(2222, osc.lookup("quoted").getPort());
+ assertEquals(2222, osc.lookup("and").getPort());
+ assertEquals(2222, osc.lookup("unquoted").getPort());
+ assertEquals(2222, osc.lookup("hosts").getPort());
+ assertEquals(" spaced\ttld ", osc.lookup("spaced").getHostName());
+ assertEquals("bad.tld\"", osc.lookup("bad").getHostName());
+ }
+
+ public void testAlias_DoesNotMatch() throws Exception {
+ config("Host orcz\n" + "\tHostName repo.or.cz\n");
+ final Host h = osc.lookup("repo.or.cz");
+ assertNotNull(h);
+ assertEquals("repo.or.cz", h.getHostName());
+ assertEquals("jex_junit", h.getUser());
+ assertEquals(22, h.getPort());
+ assertNull(h.getIdentityFile());
+ }
+
+ public void testAlias_OptionsSet() throws Exception {
+ config("Host orcz\n" + "\tHostName repo.or.cz\n" + "\tPort 2222\n"
+ + "\tUser jex\n" + "\tIdentityFile .ssh/id_jex\n"
+ + "\tForwardX11 no\n");
+ final Host h = osc.lookup("orcz");
+ assertNotNull(h);
+ assertEquals("repo.or.cz", h.getHostName());
+ assertEquals("jex", h.getUser());
+ assertEquals(2222, h.getPort());
+ assertEquals(new File(home, ".ssh/id_jex"), h.getIdentityFile());
+ }
+
+ public void testAlias_OptionsKeywordCaseInsensitive() throws Exception {
+ config("hOsT orcz\n" + "\thOsTnAmE repo.or.cz\n" + "\tPORT 2222\n"
+ + "\tuser jex\n" + "\tidentityfile .ssh/id_jex\n"
+ + "\tForwardX11 no\n");
+ final Host h = osc.lookup("orcz");
+ assertNotNull(h);
+ assertEquals("repo.or.cz", h.getHostName());
+ assertEquals("jex", h.getUser());
+ assertEquals(2222, h.getPort());
+ assertEquals(new File(home, ".ssh/id_jex"), h.getIdentityFile());
+ }
+
+ public void testAlias_OptionsInherit() throws Exception {
+ config("Host orcz\n" + "\tHostName repo.or.cz\n" + "\n" + "Host *\n"
+ + "\tHostName not.a.host.example.com\n" + "\tPort 2222\n"
+ + "\tUser jex\n" + "\tIdentityFile .ssh/id_jex\n"
+ + "\tForwardX11 no\n");
+ final Host h = osc.lookup("orcz");
+ assertNotNull(h);
+ assertEquals("repo.or.cz", h.getHostName());
+ assertEquals("jex", h.getUser());
+ assertEquals(2222, h.getPort());
+ assertEquals(new File(home, ".ssh/id_jex"), h.getIdentityFile());
+ }
+
+ public void testAlias_PreferredAuthenticationsDefault() throws Exception {
+ final Host h = osc.lookup("orcz");
+ assertNotNull(h);
+ assertNull(h.getPreferredAuthentications());
+ }
+
+ public void testAlias_PreferredAuthentications() throws Exception {
+ config("Host orcz\n" + "\tPreferredAuthentications publickey\n");
+ final Host h = osc.lookup("orcz");
+ assertNotNull(h);
+ assertEquals("publickey", h.getPreferredAuthentications());
+ }
+
+ public void testAlias_InheritPreferredAuthentications() throws Exception {
+ config("Host orcz\n" + "\tHostName repo.or.cz\n" + "\n" + "Host *\n"
+ + "\tPreferredAuthentications publickey, hostbased\n");
+ final Host h = osc.lookup("orcz");
+ assertNotNull(h);
+ assertEquals("publickey,hostbased", h.getPreferredAuthentications());
+ }
+
+ public void testAlias_BatchModeDefault() throws Exception {
+ final Host h = osc.lookup("orcz");
+ assertNotNull(h);
+ assertEquals(false, h.isBatchMode());
+ }
+
+ public void testAlias_BatchModeYes() throws Exception {
+ config("Host orcz\n" + "\tBatchMode yes\n");
+ final Host h = osc.lookup("orcz");
+ assertNotNull(h);
+ assertEquals(true, h.isBatchMode());
+ }
+
+ public void testAlias_InheritBatchMode() throws Exception {
+ config("Host orcz\n" + "\tHostName repo.or.cz\n" + "\n" + "Host *\n"
+ + "\tBatchMode yes\n");
+ final Host h = osc.lookup("orcz");
+ assertNotNull(h);
+ assertEquals(true, h.isBatchMode());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineInTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineInTest.java
new file mode 100644
index 0000000000..1bcac9e37b
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineInTest.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.MutableObjectId;
+import org.eclipse.jgit.lib.ObjectId;
+
+// Note, test vectors created with:
+//
+// perl -e 'printf "%4.4x%s\n", 4+length($ARGV[0]),$ARGV[0]'
+
+public class PacketLineInTest extends TestCase {
+ private ByteArrayInputStream rawIn;
+
+ private PacketLineIn in;
+
+ // readString
+
+ public void testReadString1() throws IOException {
+ init("0006a\n0007bc\n");
+ assertEquals("a", in.readString());
+ assertEquals("bc", in.readString());
+ assertEOF();
+ }
+
+ public void testReadString2() throws IOException {
+ init("0032want fcfcfb1fd94829c1a1704f894fc111d14770d34e\n");
+ final String act = in.readString();
+ assertEquals("want fcfcfb1fd94829c1a1704f894fc111d14770d34e", act);
+ assertEOF();
+ }
+
+ public void testReadString4() throws IOException {
+ init("0005a0006bc");
+ assertEquals("a", in.readString());
+ assertEquals("bc", in.readString());
+ assertEOF();
+ }
+
+ public void testReadString5() throws IOException {
+ // accept both upper and lower case
+ init("000Fhi i am a s");
+ assertEquals("hi i am a s", in.readString());
+ assertEOF();
+
+ init("000fhi i am a s");
+ assertEquals("hi i am a s", in.readString());
+ assertEOF();
+ }
+
+ public void testReadString_LenHELO() {
+ init("HELO");
+ try {
+ in.readString();
+ fail("incorrectly accepted invalid packet header");
+ } catch (IOException e) {
+ assertEquals("Invalid packet line header: HELO", e.getMessage());
+ }
+ }
+
+ public void testReadString_Len0001() {
+ init("0001");
+ try {
+ in.readString();
+ fail("incorrectly accepted invalid packet header");
+ } catch (IOException e) {
+ assertEquals("Invalid packet line header: 0001", e.getMessage());
+ }
+ }
+
+ public void testReadString_Len0002() {
+ init("0002");
+ try {
+ in.readString();
+ fail("incorrectly accepted invalid packet header");
+ } catch (IOException e) {
+ assertEquals("Invalid packet line header: 0002", e.getMessage());
+ }
+ }
+
+ public void testReadString_Len0003() {
+ init("0003");
+ try {
+ in.readString();
+ fail("incorrectly accepted invalid packet header");
+ } catch (IOException e) {
+ assertEquals("Invalid packet line header: 0003", e.getMessage());
+ }
+ }
+
+ public void testReadString_Len0004() throws IOException {
+ init("0004");
+ final String act = in.readString();
+ assertEquals("", act);
+ assertNotSame(PacketLineIn.END, act);
+ assertEOF();
+ }
+
+ public void testReadString_End() throws IOException {
+ init("0000");
+ assertSame(PacketLineIn.END, in.readString());
+ assertEOF();
+ }
+
+ // readStringNoLF
+
+ public void testReadStringRaw1() throws IOException {
+ init("0005a0006bc");
+ assertEquals("a", in.readStringRaw());
+ assertEquals("bc", in.readStringRaw());
+ assertEOF();
+ }
+
+ public void testReadStringRaw2() throws IOException {
+ init("0031want fcfcfb1fd94829c1a1704f894fc111d14770d34e");
+ final String act = in.readStringRaw();
+ assertEquals("want fcfcfb1fd94829c1a1704f894fc111d14770d34e", act);
+ assertEOF();
+ }
+
+ public void testReadStringRaw3() throws IOException {
+ init("0004");
+ final String act = in.readStringRaw();
+ assertEquals("", act);
+ assertNotSame(PacketLineIn.END, act);
+ assertEOF();
+ }
+
+ public void testReadStringRaw_End() throws IOException {
+ init("0000");
+ assertSame(PacketLineIn.END, in.readStringRaw());
+ assertEOF();
+ }
+
+ public void testReadStringRaw4() {
+ init("HELO");
+ try {
+ in.readStringRaw();
+ fail("incorrectly accepted invalid packet header");
+ } catch (IOException e) {
+ assertEquals("Invalid packet line header: HELO", e.getMessage());
+ }
+ }
+
+ // readACK
+
+ public void testReadACK_NAK() throws IOException {
+ final ObjectId expid = ObjectId
+ .fromString("fcfcfb1fd94829c1a1704f894fc111d14770d34e");
+ final MutableObjectId actid = new MutableObjectId();
+ actid.fromString(expid.name());
+
+ init("0008NAK\n");
+ assertSame(PacketLineIn.AckNackResult.NAK, in.readACK(actid));
+ assertTrue(actid.equals(expid));
+ assertEOF();
+ }
+
+ public void testReadACK_ACK1() throws IOException {
+ final ObjectId expid = ObjectId
+ .fromString("fcfcfb1fd94829c1a1704f894fc111d14770d34e");
+ final MutableObjectId actid = new MutableObjectId();
+
+ init("0031ACK fcfcfb1fd94829c1a1704f894fc111d14770d34e\n");
+ assertSame(PacketLineIn.AckNackResult.ACK, in.readACK(actid));
+ assertTrue(actid.equals(expid));
+ assertEOF();
+ }
+
+ public void testReadACK_ACKcontinue1() throws IOException {
+ final ObjectId expid = ObjectId
+ .fromString("fcfcfb1fd94829c1a1704f894fc111d14770d34e");
+ final MutableObjectId actid = new MutableObjectId();
+
+ init("003aACK fcfcfb1fd94829c1a1704f894fc111d14770d34e continue\n");
+ assertSame(PacketLineIn.AckNackResult.ACK_CONTINUE, in.readACK(actid));
+ assertTrue(actid.equals(expid));
+ assertEOF();
+ }
+
+ public void testReadACK_Invalid1() {
+ init("HELO");
+ try {
+ in.readACK(new MutableObjectId());
+ fail("incorrectly accepted invalid packet header");
+ } catch (IOException e) {
+ assertEquals("Invalid packet line header: HELO", e.getMessage());
+ }
+ }
+
+ public void testReadACK_Invalid2() {
+ init("0009HELO\n");
+ try {
+ in.readACK(new MutableObjectId());
+ fail("incorrectly accepted invalid ACK/NAK");
+ } catch (IOException e) {
+ assertEquals("Expected ACK/NAK, got: HELO", e.getMessage());
+ }
+ }
+
+ public void testReadACK_Invalid3() {
+ init("0000");
+ try {
+ in.readACK(new MutableObjectId());
+ fail("incorrectly accepted no ACK/NAK");
+ } catch (IOException e) {
+ assertEquals("Expected ACK/NAK, found EOF", e.getMessage());
+ }
+ }
+
+ // test support
+
+ private void init(final String msg) {
+ rawIn = new ByteArrayInputStream(Constants.encodeASCII(msg));
+ in = new PacketLineIn(rawIn);
+ }
+
+ private void assertEOF() {
+ assertEquals(-1, rawIn.read());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineOutTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineOutTest.java
new file mode 100644
index 0000000000..6eb98ac126
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PacketLineOutTest.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jgit.lib.Constants;
+
+// Note, test vectors created with:
+//
+// perl -e 'printf "%4.4x%s\n", 4+length($ARGV[0]),$ARGV[0]'
+
+public class PacketLineOutTest extends TestCase {
+ private ByteArrayOutputStream rawOut;
+
+ private PacketLineOut out;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ rawOut = new ByteArrayOutputStream();
+ out = new PacketLineOut(rawOut);
+ }
+
+ // writeString
+
+ public void testWriteString1() throws IOException {
+ out.writeString("a");
+ out.writeString("bc");
+ assertBuffer("0005a0006bc");
+ }
+
+ public void testWriteString2() throws IOException {
+ out.writeString("a\n");
+ out.writeString("bc\n");
+ assertBuffer("0006a\n0007bc\n");
+ }
+
+ public void testWriteString3() throws IOException {
+ out.writeString("");
+ assertBuffer("0004");
+ }
+
+ // end
+
+ public void testWriteEnd() throws IOException {
+ final int[] flushCnt = new int[1];
+ final OutputStream mockout = new OutputStream() {
+ @Override
+ public void write(int arg0) throws IOException {
+ rawOut.write(arg0);
+ }
+
+ @Override
+ public void flush() throws IOException {
+ flushCnt[0]++;
+ }
+ };
+
+ new PacketLineOut(mockout).end();
+ assertBuffer("0000");
+ assertEquals(1, flushCnt[0]);
+ }
+
+ // writePacket
+
+ public void testWritePacket1() throws IOException {
+ out.writePacket(new byte[] { 'a' });
+ assertBuffer("0005a");
+ }
+
+ public void testWritePacket2() throws IOException {
+ out.writePacket(new byte[] { 'a', 'b', 'c', 'd' });
+ assertBuffer("0008abcd");
+ }
+
+ public void testWritePacket3() throws IOException {
+ final int buflen = SideBandOutputStream.MAX_BUF
+ - SideBandOutputStream.HDR_SIZE;
+ final byte[] buf = new byte[buflen];
+ for (int i = 0; i < buf.length; i++) {
+ buf[i] = (byte) i;
+ }
+ out.writePacket(buf);
+ out.flush();
+
+ final byte[] act = rawOut.toByteArray();
+ final String explen = Integer.toString(buf.length + 4, 16);
+ assertEquals(4 + buf.length, act.length);
+ assertEquals(new String(act, 0, 4, "UTF-8"), explen);
+ for (int i = 0, j = 4; i < buf.length; i++, j++) {
+ assertEquals(buf[i], act[j]);
+ }
+ }
+
+ // writeChannelPacket
+
+ public void testWriteChannelPacket1() throws IOException {
+ out.writeChannelPacket(1, new byte[] { 'a' }, 0, 1);
+ assertBuffer("0006\001a");
+ }
+
+ public void testWriteChannelPacket2() throws IOException {
+ out.writeChannelPacket(2, new byte[] { 'b' }, 0, 1);
+ assertBuffer("0006\002b");
+ }
+
+ public void testWriteChannelPacket3() throws IOException {
+ out.writeChannelPacket(3, new byte[] { 'c' }, 0, 1);
+ assertBuffer("0006\003c");
+ }
+
+ // flush
+
+ public void testFlush() throws IOException {
+ final int[] flushCnt = new int[1];
+ final OutputStream mockout = new OutputStream() {
+ @Override
+ public void write(int arg0) throws IOException {
+ fail("should not write");
+ }
+
+ @Override
+ public void flush() throws IOException {
+ flushCnt[0]++;
+ }
+ };
+
+ new PacketLineOut(mockout).flush();
+ assertEquals(1, flushCnt[0]);
+ }
+
+ private void assertBuffer(final String exp) throws IOException {
+ assertEquals(exp, new String(rawOut.toByteArray(),
+ Constants.CHARACTER_ENCODING));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushProcessTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushProcessTest.java
new file mode 100644
index 0000000000..4a47456f69
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PushProcessTest.java
@@ -0,0 +1,418 @@
+/*
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+
+import org.eclipse.jgit.errors.NotSupportedException;
+import org.eclipse.jgit.errors.TransportException;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ProgressMonitor;
+import org.eclipse.jgit.lib.Ref;
+import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+import org.eclipse.jgit.lib.TextProgressMonitor;
+import org.eclipse.jgit.lib.RefUpdate.Result;
+import org.eclipse.jgit.transport.RemoteRefUpdate.Status;
+
+public class PushProcessTest extends RepositoryTestCase {
+ private PushProcess process;
+
+ private MockTransport transport;
+
+ private HashSet<RemoteRefUpdate> refUpdates;
+
+ private HashSet<Ref> advertisedRefs;
+
+ private Status connectionUpdateStatus;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ transport = new MockTransport(db, new URIish());
+ refUpdates = new HashSet<RemoteRefUpdate>();
+ advertisedRefs = new HashSet<Ref>();
+ connectionUpdateStatus = Status.OK;
+ }
+
+ /**
+ * Test for fast-forward remote update.
+ *
+ * @throws IOException
+ */
+ public void testUpdateFastForward() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
+ "refs/heads/master", false, null, null);
+ final Ref ref = new Ref(Ref.Storage.LOOSE, "refs/heads/master",
+ ObjectId.fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
+ testOneUpdateStatus(rru, ref, Status.OK, true);
+ }
+
+ /**
+ * Test for non fast-forward remote update, when remote object is not known
+ * to local repository.
+ *
+ * @throws IOException
+ */
+ public void testUpdateNonFastForwardUnknownObject() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
+ "refs/heads/master", false, null, null);
+ final Ref ref = new Ref(Ref.Storage.LOOSE, "refs/heads/master",
+ ObjectId.fromString("0000000000000000000000000000000000000001"));
+ testOneUpdateStatus(rru, ref, Status.REJECTED_NONFASTFORWARD, null);
+ }
+
+ /**
+ * Test for non fast-forward remote update, when remote object is known to
+ * local repository, but it is not an ancestor of new object.
+ *
+ * @throws IOException
+ */
+ public void testUpdateNonFastForward() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "ac7e7e44c1885efb472ad54a78327d66bfc4ecef",
+ "refs/heads/master", false, null, null);
+ final Ref ref = new Ref(Ref.Storage.LOOSE, "refs/heads/master",
+ ObjectId.fromString("2c349335b7f797072cf729c4f3bb0914ecb6dec9"));
+ testOneUpdateStatus(rru, ref, Status.REJECTED_NONFASTFORWARD, null);
+ }
+
+ /**
+ * Test for non fast-forward remote update, when force update flag is set.
+ *
+ * @throws IOException
+ */
+ public void testUpdateNonFastForwardForced() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "ac7e7e44c1885efb472ad54a78327d66bfc4ecef",
+ "refs/heads/master", true, null, null);
+ final Ref ref = new Ref(Ref.Storage.LOOSE, "refs/heads/master",
+ ObjectId.fromString("2c349335b7f797072cf729c4f3bb0914ecb6dec9"));
+ testOneUpdateStatus(rru, ref, Status.OK, false);
+ }
+
+ /**
+ * Test for remote ref creation.
+ *
+ * @throws IOException
+ */
+ public void testUpdateCreateRef() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "ac7e7e44c1885efb472ad54a78327d66bfc4ecef",
+ "refs/heads/master", false, null, null);
+ testOneUpdateStatus(rru, null, Status.OK, true);
+ }
+
+ /**
+ * Test for remote ref deletion.
+ *
+ * @throws IOException
+ */
+ public void testUpdateDelete() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db, null,
+ "refs/heads/master", false, null, null);
+ final Ref ref = new Ref(Ref.Storage.LOOSE, "refs/heads/master",
+ ObjectId.fromString("2c349335b7f797072cf729c4f3bb0914ecb6dec9"));
+ testOneUpdateStatus(rru, ref, Status.OK, true);
+ }
+
+ /**
+ * Test for remote ref deletion (try), when that ref doesn't exist on remote
+ * repo.
+ *
+ * @throws IOException
+ */
+ public void testUpdateDeleteNonExisting() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db, null,
+ "refs/heads/master", false, null, null);
+ testOneUpdateStatus(rru, null, Status.NON_EXISTING, null);
+ }
+
+ /**
+ * Test for remote ref update, when it is already up to date.
+ *
+ * @throws IOException
+ */
+ public void testUpdateUpToDate() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
+ "refs/heads/master", false, null, null);
+ final Ref ref = new Ref(Ref.Storage.LOOSE, "refs/heads/master",
+ ObjectId.fromString("2c349335b7f797072cf729c4f3bb0914ecb6dec9"));
+ testOneUpdateStatus(rru, ref, Status.UP_TO_DATE, null);
+ }
+
+ /**
+ * Test for remote ref update with expected remote object.
+ *
+ * @throws IOException
+ */
+ public void testUpdateExpectedRemote() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
+ "refs/heads/master", false, null, ObjectId
+ .fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
+ final Ref ref = new Ref(Ref.Storage.LOOSE, "refs/heads/master",
+ ObjectId.fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
+ testOneUpdateStatus(rru, ref, Status.OK, true);
+ }
+
+ /**
+ * Test for remote ref update with expected old object set, when old object
+ * is not that expected one.
+ *
+ * @throws IOException
+ */
+ public void testUpdateUnexpectedRemote() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
+ "refs/heads/master", false, null, ObjectId
+ .fromString("0000000000000000000000000000000000000001"));
+ final Ref ref = new Ref(Ref.Storage.LOOSE, "refs/heads/master",
+ ObjectId.fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
+ testOneUpdateStatus(rru, ref, Status.REJECTED_REMOTE_CHANGED, null);
+ }
+
+ /**
+ * Test for remote ref update with expected old object set, when old object
+ * is not that expected one and force update flag is set (which should have
+ * lower priority) - shouldn't change behavior.
+ *
+ * @throws IOException
+ */
+ public void testUpdateUnexpectedRemoteVsForce() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
+ "refs/heads/master", true, null, ObjectId
+ .fromString("0000000000000000000000000000000000000001"));
+ final Ref ref = new Ref(Ref.Storage.LOOSE, "refs/heads/master",
+ ObjectId.fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
+ testOneUpdateStatus(rru, ref, Status.REJECTED_REMOTE_CHANGED, null);
+ }
+
+ /**
+ * Test for remote ref update, when connection rejects update.
+ *
+ * @throws IOException
+ */
+ public void testUpdateRejectedByConnection() throws IOException {
+ connectionUpdateStatus = Status.REJECTED_OTHER_REASON;
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
+ "refs/heads/master", false, null, null);
+ final Ref ref = new Ref(Ref.Storage.LOOSE, "refs/heads/master",
+ ObjectId.fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
+ testOneUpdateStatus(rru, ref, Status.REJECTED_OTHER_REASON, null);
+ }
+
+ /**
+ * Test for remote refs updates with mixed cases that shouldn't depend on
+ * each other.
+ *
+ * @throws IOException
+ */
+ public void testUpdateMixedCases() throws IOException {
+ final RemoteRefUpdate rruOk = new RemoteRefUpdate(db, null,
+ "refs/heads/master", false, null, null);
+ final Ref refToChange = new Ref(Ref.Storage.LOOSE, "refs/heads/master",
+ ObjectId.fromString("2c349335b7f797072cf729c4f3bb0914ecb6dec9"));
+ final RemoteRefUpdate rruReject = new RemoteRefUpdate(db, null,
+ "refs/heads/nonexisting", false, null, null);
+ refUpdates.add(rruOk);
+ refUpdates.add(rruReject);
+ advertisedRefs.add(refToChange);
+ executePush();
+ assertEquals(Status.OK, rruOk.getStatus());
+ assertEquals(true, rruOk.isFastForward());
+ assertEquals(Status.NON_EXISTING, rruReject.getStatus());
+ }
+
+ /**
+ * Test for local tracking ref update.
+ *
+ * @throws IOException
+ */
+ public void testTrackingRefUpdateEnabled() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
+ "refs/heads/master", false, "refs/remotes/test/master", null);
+ final Ref ref = new Ref(Ref.Storage.LOOSE, "refs/heads/master",
+ ObjectId.fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
+ refUpdates.add(rru);
+ advertisedRefs.add(ref);
+ final PushResult result = executePush();
+ final TrackingRefUpdate tru = result
+ .getTrackingRefUpdate("refs/remotes/test/master");
+ assertNotNull(tru);
+ assertEquals("refs/remotes/test/master", tru.getLocalName());
+ assertEquals(Result.NEW, tru.getResult());
+ }
+
+ /**
+ * Test for local tracking ref update disabled.
+ *
+ * @throws IOException
+ */
+ public void testTrackingRefUpdateDisabled() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
+ "refs/heads/master", false, null, null);
+ final Ref ref = new Ref(Ref.Storage.LOOSE, "refs/heads/master",
+ ObjectId.fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
+ refUpdates.add(rru);
+ advertisedRefs.add(ref);
+ final PushResult result = executePush();
+ assertTrue(result.getTrackingRefUpdates().isEmpty());
+ }
+
+ /**
+ * Test for local tracking ref update when remote update has failed.
+ *
+ * @throws IOException
+ */
+ public void testTrackingRefUpdateOnReject() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "ac7e7e44c1885efb472ad54a78327d66bfc4ecef",
+ "refs/heads/master", false, null, null);
+ final Ref ref = new Ref(Ref.Storage.LOOSE, "refs/heads/master",
+ ObjectId.fromString("2c349335b7f797072cf729c4f3bb0914ecb6dec9"));
+ final PushResult result = testOneUpdateStatus(rru, ref,
+ Status.REJECTED_NONFASTFORWARD, null);
+ assertTrue(result.getTrackingRefUpdates().isEmpty());
+ }
+
+ /**
+ * Test for push operation result - that contains expected elements.
+ *
+ * @throws IOException
+ */
+ public void testPushResult() throws IOException {
+ final RemoteRefUpdate rru = new RemoteRefUpdate(db,
+ "2c349335b7f797072cf729c4f3bb0914ecb6dec9",
+ "refs/heads/master", false, "refs/remotes/test/master", null);
+ final Ref ref = new Ref(Ref.Storage.LOOSE, "refs/heads/master",
+ ObjectId.fromString("ac7e7e44c1885efb472ad54a78327d66bfc4ecef"));
+ refUpdates.add(rru);
+ advertisedRefs.add(ref);
+ final PushResult result = executePush();
+ assertEquals(1, result.getTrackingRefUpdates().size());
+ assertEquals(1, result.getAdvertisedRefs().size());
+ assertEquals(1, result.getRemoteUpdates().size());
+ assertNotNull(result.getTrackingRefUpdate("refs/remotes/test/master"));
+ assertNotNull(result.getAdvertisedRef("refs/heads/master"));
+ assertNotNull(result.getRemoteUpdate("refs/heads/master"));
+ }
+
+ private PushResult testOneUpdateStatus(final RemoteRefUpdate rru,
+ final Ref advertisedRef, final Status expectedStatus,
+ Boolean fastForward) throws NotSupportedException,
+ TransportException {
+ refUpdates.add(rru);
+ if (advertisedRef != null)
+ advertisedRefs.add(advertisedRef);
+ final PushResult result = executePush();
+ assertEquals(expectedStatus, rru.getStatus());
+ if (fastForward != null)
+ assertEquals(fastForward.booleanValue(), rru.isFastForward());
+ return result;
+ }
+
+ private PushResult executePush() throws NotSupportedException,
+ TransportException {
+ process = new PushProcess(transport, refUpdates);
+ return process.execute(new TextProgressMonitor());
+ }
+
+ private class MockTransport extends Transport {
+ MockTransport(Repository local, URIish uri) {
+ super(local, uri);
+ }
+
+ @Override
+ public FetchConnection openFetch() throws NotSupportedException,
+ TransportException {
+ throw new NotSupportedException("mock");
+ }
+
+ @Override
+ public PushConnection openPush() throws NotSupportedException,
+ TransportException {
+ return new MockPushConnection();
+ }
+
+ @Override
+ public void close() {
+ // nothing here
+ }
+ }
+
+ private class MockPushConnection extends BaseConnection implements
+ PushConnection {
+ MockPushConnection() {
+ final Map<String, Ref> refsMap = new HashMap<String, Ref>();
+ for (final Ref r : advertisedRefs)
+ refsMap.put(r.getName(), r);
+ available(refsMap);
+ }
+
+ @Override
+ public void close() {
+ // nothing here
+ }
+
+ public void push(ProgressMonitor monitor,
+ Map<String, RemoteRefUpdate> refsToUpdate)
+ throws TransportException {
+ for (final RemoteRefUpdate rru : refsToUpdate.values()) {
+ assertEquals(Status.NOT_ATTEMPTED, rru.getStatus());
+ rru.setStatus(connectionUpdateStatus);
+ }
+ }
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java
new file mode 100644
index 0000000000..38dbe0962e
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RefSpecTest.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jgit.lib.Ref;
+
+public class RefSpecTest extends TestCase {
+ public void testMasterMaster() {
+ final String sn = "refs/heads/master";
+ final RefSpec rs = new RefSpec(sn + ":" + sn);
+ assertFalse(rs.isForceUpdate());
+ assertFalse(rs.isWildcard());
+ assertEquals(sn, rs.getSource());
+ assertEquals(sn, rs.getDestination());
+ assertEquals(sn + ":" + sn, rs.toString());
+ assertEquals(rs, new RefSpec(rs.toString()));
+
+ Ref r = new Ref(Ref.Storage.LOOSE, sn, null);
+ assertTrue(rs.matchSource(r));
+ assertTrue(rs.matchDestination(r));
+ assertSame(rs, rs.expandFromSource(r));
+
+ r = new Ref(Ref.Storage.LOOSE, sn + "-and-more", null);
+ assertFalse(rs.matchSource(r));
+ assertFalse(rs.matchDestination(r));
+ }
+
+ public void testSplitLastColon() {
+ final String lhs = ":m:a:i:n:t";
+ final String rhs = "refs/heads/maint";
+ final RefSpec rs = new RefSpec(lhs + ":" + rhs);
+ assertFalse(rs.isForceUpdate());
+ assertFalse(rs.isWildcard());
+ assertEquals(lhs, rs.getSource());
+ assertEquals(rhs, rs.getDestination());
+ assertEquals(lhs + ":" + rhs, rs.toString());
+ assertEquals(rs, new RefSpec(rs.toString()));
+ }
+
+ public void testForceMasterMaster() {
+ final String sn = "refs/heads/master";
+ final RefSpec rs = new RefSpec("+" + sn + ":" + sn);
+ assertTrue(rs.isForceUpdate());
+ assertFalse(rs.isWildcard());
+ assertEquals(sn, rs.getSource());
+ assertEquals(sn, rs.getDestination());
+ assertEquals("+" + sn + ":" + sn, rs.toString());
+ assertEquals(rs, new RefSpec(rs.toString()));
+
+ Ref r = new Ref(Ref.Storage.LOOSE, sn, null);
+ assertTrue(rs.matchSource(r));
+ assertTrue(rs.matchDestination(r));
+ assertSame(rs, rs.expandFromSource(r));
+
+ r = new Ref(Ref.Storage.LOOSE, sn + "-and-more", null);
+ assertFalse(rs.matchSource(r));
+ assertFalse(rs.matchDestination(r));
+ }
+
+ public void testMaster() {
+ final String sn = "refs/heads/master";
+ final RefSpec rs = new RefSpec(sn);
+ assertFalse(rs.isForceUpdate());
+ assertFalse(rs.isWildcard());
+ assertEquals(sn, rs.getSource());
+ assertNull(rs.getDestination());
+ assertEquals(sn, rs.toString());
+ assertEquals(rs, new RefSpec(rs.toString()));
+
+ Ref r = new Ref(Ref.Storage.LOOSE, sn, null);
+ assertTrue(rs.matchSource(r));
+ assertFalse(rs.matchDestination(r));
+ assertSame(rs, rs.expandFromSource(r));
+
+ r = new Ref(Ref.Storage.LOOSE, sn + "-and-more", null);
+ assertFalse(rs.matchSource(r));
+ assertFalse(rs.matchDestination(r));
+ }
+
+ public void testForceMaster() {
+ final String sn = "refs/heads/master";
+ final RefSpec rs = new RefSpec("+" + sn);
+ assertTrue(rs.isForceUpdate());
+ assertFalse(rs.isWildcard());
+ assertEquals(sn, rs.getSource());
+ assertNull(rs.getDestination());
+ assertEquals("+" + sn, rs.toString());
+ assertEquals(rs, new RefSpec(rs.toString()));
+
+ Ref r = new Ref(Ref.Storage.LOOSE, sn, null);
+ assertTrue(rs.matchSource(r));
+ assertFalse(rs.matchDestination(r));
+ assertSame(rs, rs.expandFromSource(r));
+
+ r = new Ref(Ref.Storage.LOOSE, sn + "-and-more", null);
+ assertFalse(rs.matchSource(r));
+ assertFalse(rs.matchDestination(r));
+ }
+
+ public void testDeleteMaster() {
+ final String sn = "refs/heads/master";
+ final RefSpec rs = new RefSpec(":" + sn);
+ assertFalse(rs.isForceUpdate());
+ assertFalse(rs.isWildcard());
+ assertNull(rs.getSource());
+ assertEquals(sn, rs.getDestination());
+ assertEquals(":" + sn, rs.toString());
+ assertEquals(rs, new RefSpec(rs.toString()));
+
+ Ref r = new Ref(Ref.Storage.LOOSE, sn, null);
+ assertFalse(rs.matchSource(r));
+ assertTrue(rs.matchDestination(r));
+ assertSame(rs, rs.expandFromSource(r));
+
+ r = new Ref(Ref.Storage.LOOSE, sn + "-and-more", null);
+ assertFalse(rs.matchSource(r));
+ assertFalse(rs.matchDestination(r));
+ }
+
+ public void testForceRemotesOrigin() {
+ final String srcn = "refs/heads/*";
+ final String dstn = "refs/remotes/origin/*";
+ final RefSpec rs = new RefSpec("+" + srcn + ":" + dstn);
+ assertTrue(rs.isForceUpdate());
+ assertTrue(rs.isWildcard());
+ assertEquals(srcn, rs.getSource());
+ assertEquals(dstn, rs.getDestination());
+ assertEquals("+" + srcn + ":" + dstn, rs.toString());
+ assertEquals(rs, new RefSpec(rs.toString()));
+
+ Ref r;
+ RefSpec expanded;
+
+ r = new Ref(Ref.Storage.LOOSE, "refs/heads/master", null);
+ assertTrue(rs.matchSource(r));
+ assertFalse(rs.matchDestination(r));
+ expanded = rs.expandFromSource(r);
+ assertNotSame(rs, expanded);
+ assertTrue(expanded.isForceUpdate());
+ assertFalse(expanded.isWildcard());
+ assertEquals(r.getName(), expanded.getSource());
+ assertEquals("refs/remotes/origin/master", expanded.getDestination());
+
+ r = new Ref(Ref.Storage.LOOSE, "refs/remotes/origin/next", null);
+ assertFalse(rs.matchSource(r));
+ assertTrue(rs.matchDestination(r));
+
+ r = new Ref(Ref.Storage.LOOSE, "refs/tags/v1.0", null);
+ assertFalse(rs.matchSource(r));
+ assertFalse(rs.matchDestination(r));
+ }
+
+ public void testCreateEmpty() {
+ final RefSpec rs = new RefSpec();
+ assertFalse(rs.isForceUpdate());
+ assertFalse(rs.isWildcard());
+ assertEquals("HEAD", rs.getSource());
+ assertNull(rs.getDestination());
+ assertEquals("HEAD", rs.toString());
+ }
+
+ public void testSetForceUpdate() {
+ final String s = "refs/heads/*:refs/remotes/origin/*";
+ final RefSpec a = new RefSpec(s);
+ assertFalse(a.isForceUpdate());
+ RefSpec b = a.setForceUpdate(true);
+ assertNotSame(a, b);
+ assertFalse(a.isForceUpdate());
+ assertTrue(b.isForceUpdate());
+ assertEquals(s, a.toString());
+ assertEquals("+" + s, b.toString());
+ }
+
+ public void testSetSource() {
+ final RefSpec a = new RefSpec();
+ final RefSpec b = a.setSource("refs/heads/master");
+ assertNotSame(a, b);
+ assertEquals("HEAD", a.toString());
+ assertEquals("refs/heads/master", b.toString());
+ }
+
+ public void testSetDestination() {
+ final RefSpec a = new RefSpec();
+ final RefSpec b = a.setDestination("refs/heads/master");
+ assertNotSame(a, b);
+ assertEquals("HEAD", a.toString());
+ assertEquals("HEAD:refs/heads/master", b.toString());
+ }
+
+ public void testSetDestination_SourceNull() {
+ final RefSpec a = new RefSpec();
+ RefSpec b;
+
+ b = a.setDestination("refs/heads/master");
+ b = b.setSource(null);
+ assertNotSame(a, b);
+ assertEquals("HEAD", a.toString());
+ assertEquals(":refs/heads/master", b.toString());
+ }
+
+ public void testSetSourceDestination() {
+ final RefSpec a = new RefSpec();
+ final RefSpec b;
+ b = a.setSourceDestination("refs/heads/*", "refs/remotes/origin/*");
+ assertNotSame(a, b);
+ assertEquals("HEAD", a.toString());
+ assertEquals("refs/heads/*:refs/remotes/origin/*", b.toString());
+ }
+
+ public void testExpandFromDestination_NonWildcard() {
+ final String src = "refs/heads/master";
+ final String dst = "refs/remotes/origin/master";
+ final RefSpec a = new RefSpec(src + ":" + dst);
+ final RefSpec r = a.expandFromDestination(dst);
+ assertSame(a, r);
+ assertFalse(r.isWildcard());
+ assertEquals(src, r.getSource());
+ assertEquals(dst, r.getDestination());
+ }
+
+ public void testExpandFromDestination_Wildcard() {
+ final String src = "refs/heads/master";
+ final String dst = "refs/remotes/origin/master";
+ final RefSpec a = new RefSpec("refs/heads/*:refs/remotes/origin/*");
+ final RefSpec r = a.expandFromDestination(dst);
+ assertNotSame(a, r);
+ assertFalse(r.isWildcard());
+ assertEquals(src, r.getSource());
+ assertEquals(dst, r.getDestination());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RemoteConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RemoteConfigTest.java
new file mode 100644
index 0000000000..3d9b51f9b6
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/RemoteConfigTest.java
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.lib.Config;
+
+public class RemoteConfigTest extends TestCase {
+ private Config config;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ config = new Config();
+ }
+
+ private void readConfig(final String dat) throws ConfigInvalidException {
+ config = new Config();
+ config.fromText(dat);
+ }
+
+ private void checkConfig(final String exp) {
+ assertEquals(exp, config.toText());
+ }
+
+ private static void assertEquals(final String exp, final URIish act) {
+ assertEquals(exp, act != null ? act.toString() : null);
+ }
+
+ public void testSimple() throws Exception {
+ readConfig("[remote \"spearce\"]\n"
+ + "url = http://www.spearce.org/egit.git\n"
+ + "fetch = +refs/heads/*:refs/remotes/spearce/*\n");
+
+ final RemoteConfig rc = new RemoteConfig(config, "spearce");
+ final List<URIish> allURIs = rc.getURIs();
+ RefSpec spec;
+
+ assertEquals("spearce", rc.getName());
+ assertNotNull(allURIs);
+ assertNotNull(rc.getFetchRefSpecs());
+ assertNotNull(rc.getPushRefSpecs());
+ assertNotNull(rc.getTagOpt());
+ assertEquals(0, rc.getTimeout());
+ assertSame(TagOpt.AUTO_FOLLOW, rc.getTagOpt());
+
+ assertEquals(1, allURIs.size());
+ assertEquals("http://www.spearce.org/egit.git", allURIs.get(0));
+
+ assertEquals(1, rc.getFetchRefSpecs().size());
+ spec = rc.getFetchRefSpecs().get(0);
+ assertTrue(spec.isForceUpdate());
+ assertTrue(spec.isWildcard());
+ assertEquals("refs/heads/*", spec.getSource());
+ assertEquals("refs/remotes/spearce/*", spec.getDestination());
+
+ assertEquals(0, rc.getPushRefSpecs().size());
+ }
+
+ public void testSimpleNoTags() throws Exception {
+ readConfig("[remote \"spearce\"]\n"
+ + "url = http://www.spearce.org/egit.git\n"
+ + "fetch = +refs/heads/*:refs/remotes/spearce/*\n"
+ + "tagopt = --no-tags\n");
+ final RemoteConfig rc = new RemoteConfig(config, "spearce");
+ assertSame(TagOpt.NO_TAGS, rc.getTagOpt());
+ }
+
+ public void testSimpleAlwaysTags() throws Exception {
+ readConfig("[remote \"spearce\"]\n"
+ + "url = http://www.spearce.org/egit.git\n"
+ + "fetch = +refs/heads/*:refs/remotes/spearce/*\n"
+ + "tagopt = --tags\n");
+ final RemoteConfig rc = new RemoteConfig(config, "spearce");
+ assertSame(TagOpt.FETCH_TAGS, rc.getTagOpt());
+ }
+
+ public void testMirror() throws Exception {
+ readConfig("[remote \"spearce\"]\n"
+ + "url = http://www.spearce.org/egit.git\n"
+ + "fetch = +refs/heads/*:refs/heads/*\n"
+ + "fetch = refs/tags/*:refs/tags/*\n");
+
+ final RemoteConfig rc = new RemoteConfig(config, "spearce");
+ final List<URIish> allURIs = rc.getURIs();
+ RefSpec spec;
+
+ assertEquals("spearce", rc.getName());
+ assertNotNull(allURIs);
+ assertNotNull(rc.getFetchRefSpecs());
+ assertNotNull(rc.getPushRefSpecs());
+
+ assertEquals(1, allURIs.size());
+ assertEquals("http://www.spearce.org/egit.git", allURIs.get(0));
+
+ assertEquals(2, rc.getFetchRefSpecs().size());
+
+ spec = rc.getFetchRefSpecs().get(0);
+ assertTrue(spec.isForceUpdate());
+ assertTrue(spec.isWildcard());
+ assertEquals("refs/heads/*", spec.getSource());
+ assertEquals("refs/heads/*", spec.getDestination());
+
+ spec = rc.getFetchRefSpecs().get(1);
+ assertFalse(spec.isForceUpdate());
+ assertTrue(spec.isWildcard());
+ assertEquals("refs/tags/*", spec.getSource());
+ assertEquals("refs/tags/*", spec.getDestination());
+
+ assertEquals(0, rc.getPushRefSpecs().size());
+ }
+
+ public void testBackup() throws Exception {
+ readConfig("[remote \"backup\"]\n"
+ + "url = http://www.spearce.org/egit.git\n"
+ + "url = user@repo.or.cz:/srv/git/egit.git\n"
+ + "push = +refs/heads/*:refs/heads/*\n"
+ + "push = refs/tags/*:refs/tags/*\n");
+
+ final RemoteConfig rc = new RemoteConfig(config, "backup");
+ final List<URIish> allURIs = rc.getURIs();
+ RefSpec spec;
+
+ assertEquals("backup", rc.getName());
+ assertNotNull(allURIs);
+ assertNotNull(rc.getFetchRefSpecs());
+ assertNotNull(rc.getPushRefSpecs());
+
+ assertEquals(2, allURIs.size());
+ assertEquals("http://www.spearce.org/egit.git", allURIs.get(0));
+ assertEquals("user@repo.or.cz:/srv/git/egit.git", allURIs.get(1));
+
+ assertEquals(0, rc.getFetchRefSpecs().size());
+
+ assertEquals(2, rc.getPushRefSpecs().size());
+ spec = rc.getPushRefSpecs().get(0);
+ assertTrue(spec.isForceUpdate());
+ assertTrue(spec.isWildcard());
+ assertEquals("refs/heads/*", spec.getSource());
+ assertEquals("refs/heads/*", spec.getDestination());
+
+ spec = rc.getPushRefSpecs().get(1);
+ assertFalse(spec.isForceUpdate());
+ assertTrue(spec.isWildcard());
+ assertEquals("refs/tags/*", spec.getSource());
+ assertEquals("refs/tags/*", spec.getDestination());
+ }
+
+ public void testUploadPack() throws Exception {
+ readConfig("[remote \"example\"]\n"
+ + "url = user@example.com:egit.git\n"
+ + "fetch = +refs/heads/*:refs/remotes/example/*\n"
+ + "uploadpack = /path/to/git/git-upload-pack\n"
+ + "receivepack = /path/to/git/git-receive-pack\n");
+
+ final RemoteConfig rc = new RemoteConfig(config, "example");
+ final List<URIish> allURIs = rc.getURIs();
+ RefSpec spec;
+
+ assertEquals("example", rc.getName());
+ assertNotNull(allURIs);
+ assertNotNull(rc.getFetchRefSpecs());
+ assertNotNull(rc.getPushRefSpecs());
+
+ assertEquals(1, allURIs.size());
+ assertEquals("user@example.com:egit.git", allURIs.get(0));
+
+ assertEquals(1, rc.getFetchRefSpecs().size());
+ spec = rc.getFetchRefSpecs().get(0);
+ assertTrue(spec.isForceUpdate());
+ assertTrue(spec.isWildcard());
+ assertEquals("refs/heads/*", spec.getSource());
+ assertEquals("refs/remotes/example/*", spec.getDestination());
+
+ assertEquals(0, rc.getPushRefSpecs().size());
+
+ assertEquals("/path/to/git/git-upload-pack", rc.getUploadPack());
+ assertEquals("/path/to/git/git-receive-pack", rc.getReceivePack());
+ }
+
+ public void testUnknown() throws Exception {
+ readConfig("");
+
+ final RemoteConfig rc = new RemoteConfig(config, "backup");
+ assertEquals(0, rc.getURIs().size());
+ assertEquals(0, rc.getFetchRefSpecs().size());
+ assertEquals(0, rc.getPushRefSpecs().size());
+ assertEquals("git-upload-pack", rc.getUploadPack());
+ assertEquals("git-receive-pack", rc.getReceivePack());
+ }
+
+ public void testAddURI() throws Exception {
+ readConfig("");
+
+ final URIish uri = new URIish("/some/dir");
+ final RemoteConfig rc = new RemoteConfig(config, "backup");
+ assertEquals(0, rc.getURIs().size());
+
+ assertTrue(rc.addURI(uri));
+ assertEquals(1, rc.getURIs().size());
+ assertSame(uri, rc.getURIs().get(0));
+
+ assertFalse(rc.addURI(new URIish(uri.toString())));
+ assertEquals(1, rc.getURIs().size());
+ }
+
+ public void testRemoveFirstURI() throws Exception {
+ readConfig("");
+
+ final URIish a = new URIish("/some/dir");
+ final URIish b = new URIish("/another/dir");
+ final URIish c = new URIish("/more/dirs");
+ final RemoteConfig rc = new RemoteConfig(config, "backup");
+ assertTrue(rc.addURI(a));
+ assertTrue(rc.addURI(b));
+ assertTrue(rc.addURI(c));
+
+ assertEquals(3, rc.getURIs().size());
+ assertSame(a, rc.getURIs().get(0));
+ assertSame(b, rc.getURIs().get(1));
+ assertSame(c, rc.getURIs().get(2));
+
+ assertTrue(rc.removeURI(a));
+ assertEquals(2, rc.getURIs().size());
+ assertSame(b, rc.getURIs().get(0));
+ assertSame(c, rc.getURIs().get(1));
+ }
+
+ public void testRemoveMiddleURI() throws Exception {
+ readConfig("");
+
+ final URIish a = new URIish("/some/dir");
+ final URIish b = new URIish("/another/dir");
+ final URIish c = new URIish("/more/dirs");
+ final RemoteConfig rc = new RemoteConfig(config, "backup");
+ assertTrue(rc.addURI(a));
+ assertTrue(rc.addURI(b));
+ assertTrue(rc.addURI(c));
+
+ assertEquals(3, rc.getURIs().size());
+ assertSame(a, rc.getURIs().get(0));
+ assertSame(b, rc.getURIs().get(1));
+ assertSame(c, rc.getURIs().get(2));
+
+ assertTrue(rc.removeURI(b));
+ assertEquals(2, rc.getURIs().size());
+ assertSame(a, rc.getURIs().get(0));
+ assertSame(c, rc.getURIs().get(1));
+ }
+
+ public void testRemoveLastURI() throws Exception {
+ readConfig("");
+
+ final URIish a = new URIish("/some/dir");
+ final URIish b = new URIish("/another/dir");
+ final URIish c = new URIish("/more/dirs");
+ final RemoteConfig rc = new RemoteConfig(config, "backup");
+ assertTrue(rc.addURI(a));
+ assertTrue(rc.addURI(b));
+ assertTrue(rc.addURI(c));
+
+ assertEquals(3, rc.getURIs().size());
+ assertSame(a, rc.getURIs().get(0));
+ assertSame(b, rc.getURIs().get(1));
+ assertSame(c, rc.getURIs().get(2));
+
+ assertTrue(rc.removeURI(c));
+ assertEquals(2, rc.getURIs().size());
+ assertSame(a, rc.getURIs().get(0));
+ assertSame(b, rc.getURIs().get(1));
+ }
+
+ public void testRemoveOnlyURI() throws Exception {
+ readConfig("");
+
+ final URIish a = new URIish("/some/dir");
+ final RemoteConfig rc = new RemoteConfig(config, "backup");
+ assertTrue(rc.addURI(a));
+
+ assertEquals(1, rc.getURIs().size());
+ assertSame(a, rc.getURIs().get(0));
+
+ assertTrue(rc.removeURI(a));
+ assertEquals(0, rc.getURIs().size());
+ }
+
+ public void testCreateOrigin() throws Exception {
+ final RemoteConfig rc = new RemoteConfig(config, "origin");
+ rc.addURI(new URIish("/some/dir"));
+ rc.addFetchRefSpec(new RefSpec("+refs/heads/*:refs/remotes/"
+ + rc.getName() + "/*"));
+ rc.update(config);
+ checkConfig("[remote \"origin\"]\n" + "\turl = /some/dir\n"
+ + "\tfetch = +refs/heads/*:refs/remotes/origin/*\n");
+ }
+
+ public void testSaveAddURI() throws Exception {
+ readConfig("[remote \"spearce\"]\n"
+ + "url = http://www.spearce.org/egit.git\n"
+ + "fetch = +refs/heads/*:refs/remotes/spearce/*\n");
+
+ final RemoteConfig rc = new RemoteConfig(config, "spearce");
+ rc.addURI(new URIish("/some/dir"));
+ assertEquals(2, rc.getURIs().size());
+ rc.update(config);
+ checkConfig("[remote \"spearce\"]\n"
+ + "\turl = http://www.spearce.org/egit.git\n"
+ + "\turl = /some/dir\n"
+ + "\tfetch = +refs/heads/*:refs/remotes/spearce/*\n");
+ }
+
+ public void testSaveRemoveLastURI() throws Exception {
+ readConfig("[remote \"spearce\"]\n"
+ + "url = http://www.spearce.org/egit.git\n"
+ + "url = /some/dir\n"
+ + "fetch = +refs/heads/*:refs/remotes/spearce/*\n");
+
+ final RemoteConfig rc = new RemoteConfig(config, "spearce");
+ assertEquals(2, rc.getURIs().size());
+ rc.removeURI(new URIish("/some/dir"));
+ assertEquals(1, rc.getURIs().size());
+ rc.update(config);
+ checkConfig("[remote \"spearce\"]\n"
+ + "\turl = http://www.spearce.org/egit.git\n"
+ + "\tfetch = +refs/heads/*:refs/remotes/spearce/*\n");
+ }
+
+ public void testSaveRemoveFirstURI() throws Exception {
+ readConfig("[remote \"spearce\"]\n"
+ + "url = http://www.spearce.org/egit.git\n"
+ + "url = /some/dir\n"
+ + "fetch = +refs/heads/*:refs/remotes/spearce/*\n");
+
+ final RemoteConfig rc = new RemoteConfig(config, "spearce");
+ assertEquals(2, rc.getURIs().size());
+ rc.removeURI(new URIish("http://www.spearce.org/egit.git"));
+ assertEquals(1, rc.getURIs().size());
+ rc.update(config);
+ checkConfig("[remote \"spearce\"]\n" + "\turl = /some/dir\n"
+ + "\tfetch = +refs/heads/*:refs/remotes/spearce/*\n");
+ }
+
+ public void testSaveNoTags() throws Exception {
+ final RemoteConfig rc = new RemoteConfig(config, "origin");
+ rc.addURI(new URIish("/some/dir"));
+ rc.addFetchRefSpec(new RefSpec("+refs/heads/*:refs/remotes/"
+ + rc.getName() + "/*"));
+ rc.setTagOpt(TagOpt.NO_TAGS);
+ rc.update(config);
+ checkConfig("[remote \"origin\"]\n" + "\turl = /some/dir\n"
+ + "\tfetch = +refs/heads/*:refs/remotes/origin/*\n"
+ + "\ttagopt = --no-tags\n");
+ }
+
+ public void testSaveAllTags() throws Exception {
+ final RemoteConfig rc = new RemoteConfig(config, "origin");
+ rc.addURI(new URIish("/some/dir"));
+ rc.addFetchRefSpec(new RefSpec("+refs/heads/*:refs/remotes/"
+ + rc.getName() + "/*"));
+ rc.setTagOpt(TagOpt.FETCH_TAGS);
+ rc.update(config);
+ checkConfig("[remote \"origin\"]\n" + "\turl = /some/dir\n"
+ + "\tfetch = +refs/heads/*:refs/remotes/origin/*\n"
+ + "\ttagopt = --tags\n");
+ }
+
+ public void testSimpleTimeout() throws Exception {
+ readConfig("[remote \"spearce\"]\n"
+ + "url = http://www.spearce.org/egit.git\n"
+ + "fetch = +refs/heads/*:refs/remotes/spearce/*\n"
+ + "timeout = 12\n");
+ final RemoteConfig rc = new RemoteConfig(config, "spearce");
+ assertEquals(12, rc.getTimeout());
+ }
+
+ public void testSaveTimeout() throws Exception {
+ final RemoteConfig rc = new RemoteConfig(config, "origin");
+ rc.addURI(new URIish("/some/dir"));
+ rc.addFetchRefSpec(new RefSpec("+refs/heads/*:refs/remotes/"
+ + rc.getName() + "/*"));
+ rc.setTimeout(60);
+ rc.update(config);
+ checkConfig("[remote \"origin\"]\n" + "\turl = /some/dir\n"
+ + "\tfetch = +refs/heads/*:refs/remotes/origin/*\n"
+ + "\ttimeout = 60\n");
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandOutputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandOutputStreamTest.java
new file mode 100644
index 0000000000..3c79f138c8
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/SideBandOutputStreamTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jgit.lib.Constants;
+
+// Note, test vectors created with:
+//
+// perl -e 'printf "%4.4x%s\n", 4+length($ARGV[0]),$ARGV[0]'
+
+public class SideBandOutputStreamTest extends TestCase {
+ private ByteArrayOutputStream rawOut;
+
+ private PacketLineOut pckOut;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ rawOut = new ByteArrayOutputStream();
+ pckOut = new PacketLineOut(rawOut);
+ }
+
+ public void testWrite_CH_DATA() throws IOException {
+ final SideBandOutputStream out;
+ out = new SideBandOutputStream(SideBandOutputStream.CH_DATA, pckOut);
+ out.write(new byte[] { 'a', 'b', 'c' });
+ assertBuffer("0008\001abc");
+ }
+
+ public void testWrite_CH_PROGRESS() throws IOException {
+ final SideBandOutputStream out;
+ out = new SideBandOutputStream(SideBandOutputStream.CH_PROGRESS, pckOut);
+ out.write(new byte[] { 'a', 'b', 'c' });
+ assertBuffer("0008\002abc");
+ }
+
+ public void testWrite_CH_ERROR() throws IOException {
+ final SideBandOutputStream out;
+ out = new SideBandOutputStream(SideBandOutputStream.CH_ERROR, pckOut);
+ out.write(new byte[] { 'a', 'b', 'c' });
+ assertBuffer("0008\003abc");
+ }
+
+ public void testWrite_Small() throws IOException {
+ final SideBandOutputStream out;
+ out = new SideBandOutputStream(SideBandOutputStream.CH_DATA, pckOut);
+ out.write('a');
+ out.write('b');
+ out.write('c');
+ assertBuffer("0006\001a0006\001b0006\001c");
+ }
+
+ public void testWrite_Large() throws IOException {
+ final int buflen = SideBandOutputStream.MAX_BUF
+ - SideBandOutputStream.HDR_SIZE;
+ final byte[] buf = new byte[buflen];
+ for (int i = 0; i < buf.length; i++) {
+ buf[i] = (byte) i;
+ }
+
+ final SideBandOutputStream out;
+ out = new SideBandOutputStream(SideBandOutputStream.CH_DATA, pckOut);
+ out.write(buf);
+
+ final byte[] act = rawOut.toByteArray();
+ final String explen = Integer.toString(buf.length + 5, 16);
+ assertEquals(5 + buf.length, act.length);
+ assertEquals(new String(act, 0, 4, "UTF-8"), explen);
+ assertEquals(1, act[4]);
+ for (int i = 0, j = 5; i < buf.length; i++, j++) {
+ assertEquals(buf[i], act[j]);
+ }
+ }
+
+ public void testFlush() throws IOException {
+ final int[] flushCnt = new int[1];
+ final OutputStream mockout = new OutputStream() {
+ @Override
+ public void write(int arg0) throws IOException {
+ fail("should not write");
+ }
+
+ @Override
+ public void flush() throws IOException {
+ flushCnt[0]++;
+ }
+ };
+
+ new SideBandOutputStream(SideBandOutputStream.CH_DATA,
+ new PacketLineOut(mockout)).flush();
+ assertEquals(0, flushCnt[0]);
+
+ new SideBandOutputStream(SideBandOutputStream.CH_ERROR,
+ new PacketLineOut(mockout)).flush();
+ assertEquals(1, flushCnt[0]);
+
+ new SideBandOutputStream(SideBandOutputStream.CH_PROGRESS,
+ new PacketLineOut(mockout)).flush();
+ assertEquals(2, flushCnt[0]);
+ }
+
+ private void assertBuffer(final String exp) throws IOException {
+ assertEquals(exp, new String(rawOut.toByteArray(),
+ Constants.CHARACTER_ENCODING));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportTest.java
new file mode 100644
index 0000000000..75e661bcf9
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/TransportTest.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2008, Marek Zawirski <marek.zawirski@gmail.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+
+import org.eclipse.jgit.lib.RepositoryConfig;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+
+public class TransportTest extends RepositoryTestCase {
+ private Transport transport;
+
+ private RemoteConfig remoteConfig;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ final RepositoryConfig config = db.getConfig();
+ remoteConfig = new RemoteConfig(config, "test");
+ remoteConfig.addURI(new URIish("http://everyones.loves.git/u/2"));
+ transport = null;
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ if (transport != null) {
+ transport.close();
+ transport = null;
+ }
+ super.tearDown();
+ }
+
+ /**
+ * Test RefSpec to RemoteRefUpdate conversion with simple RefSpec - no
+ * wildcard, no tracking ref in repo configuration.
+ *
+ * @throws IOException
+ */
+ public void testFindRemoteRefUpdatesNoWildcardNoTracking()
+ throws IOException {
+ transport = Transport.open(db, remoteConfig);
+ final Collection<RemoteRefUpdate> result = transport
+ .findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec(
+ "refs/heads/master:refs/heads/x")));
+
+ assertEquals(1, result.size());
+ final RemoteRefUpdate rru = result.iterator().next();
+ assertNull(rru.getExpectedOldObjectId());
+ assertFalse(rru.isForceUpdate());
+ assertEquals("refs/heads/master", rru.getSrcRef());
+ assertEquals(db.resolve("refs/heads/master"), rru.getNewObjectId());
+ assertEquals("refs/heads/x", rru.getRemoteName());
+ }
+
+ /**
+ * Test RefSpec to RemoteRefUpdate conversion with no-destination RefSpec
+ * (destination should be set up for the same name as source).
+ *
+ * @throws IOException
+ */
+ public void testFindRemoteRefUpdatesNoWildcardNoDestination()
+ throws IOException {
+ transport = Transport.open(db, remoteConfig);
+ final Collection<RemoteRefUpdate> result = transport
+ .findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec(
+ "+refs/heads/master")));
+
+ assertEquals(1, result.size());
+ final RemoteRefUpdate rru = result.iterator().next();
+ assertNull(rru.getExpectedOldObjectId());
+ assertTrue(rru.isForceUpdate());
+ assertEquals("refs/heads/master", rru.getSrcRef());
+ assertEquals(db.resolve("refs/heads/master"), rru.getNewObjectId());
+ assertEquals("refs/heads/master", rru.getRemoteName());
+ }
+
+ /**
+ * Test RefSpec to RemoteRefUpdate conversion with wildcard RefSpec.
+ *
+ * @throws IOException
+ */
+ public void testFindRemoteRefUpdatesWildcardNoTracking() throws IOException {
+ transport = Transport.open(db, remoteConfig);
+ final Collection<RemoteRefUpdate> result = transport
+ .findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec(
+ "+refs/heads/*:refs/heads/test/*")));
+
+ assertEquals(12, result.size());
+ boolean foundA = false;
+ boolean foundB = false;
+ for (final RemoteRefUpdate rru : result) {
+ if ("refs/heads/a".equals(rru.getSrcRef())
+ && "refs/heads/test/a".equals(rru.getRemoteName()))
+ foundA = true;
+ if ("refs/heads/b".equals(rru.getSrcRef())
+ && "refs/heads/test/b".equals(rru.getRemoteName()))
+ foundB = true;
+ }
+ assertTrue(foundA);
+ assertTrue(foundB);
+ }
+
+ /**
+ * Test RefSpec to RemoteRefUpdate conversion for more than one RefSpecs
+ * handling.
+ *
+ * @throws IOException
+ */
+ public void testFindRemoteRefUpdatesTwoRefSpecs() throws IOException {
+ transport = Transport.open(db, remoteConfig);
+ final RefSpec specA = new RefSpec("+refs/heads/a:refs/heads/b");
+ final RefSpec specC = new RefSpec("+refs/heads/c:refs/heads/d");
+ final Collection<RefSpec> specs = Arrays.asList(specA, specC);
+ final Collection<RemoteRefUpdate> result = transport
+ .findRemoteRefUpdatesFor(specs);
+
+ assertEquals(2, result.size());
+ boolean foundA = false;
+ boolean foundC = false;
+ for (final RemoteRefUpdate rru : result) {
+ if ("refs/heads/a".equals(rru.getSrcRef())
+ && "refs/heads/b".equals(rru.getRemoteName()))
+ foundA = true;
+ if ("refs/heads/c".equals(rru.getSrcRef())
+ && "refs/heads/d".equals(rru.getRemoteName()))
+ foundC = true;
+ }
+ assertTrue(foundA);
+ assertTrue(foundC);
+ }
+
+ /**
+ * Test RefSpec to RemoteRefUpdate conversion for tracking ref search.
+ *
+ * @throws IOException
+ */
+ public void testFindRemoteRefUpdatesTrackingRef() throws IOException {
+ remoteConfig.addFetchRefSpec(new RefSpec(
+ "refs/heads/*:refs/remotes/test/*"));
+ transport = Transport.open(db, remoteConfig);
+ final Collection<RemoteRefUpdate> result = transport
+ .findRemoteRefUpdatesFor(Collections.nCopies(1, new RefSpec(
+ "+refs/heads/a:refs/heads/a")));
+
+ assertEquals(1, result.size());
+ final TrackingRefUpdate tru = result.iterator().next()
+ .getTrackingRefUpdate();
+ assertEquals("refs/remotes/test/a", tru.getLocalName());
+ assertEquals("refs/heads/a", tru.getRemoteName());
+ assertEquals(db.resolve("refs/heads/a"), tru.getNewObjectId());
+ assertNull(tru.getOldObjectId());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java
new file mode 100644
index 0000000000..2598fdc1f5
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/URIishTest.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (C) 2008, Robin Rosenberg <robin.rosenberg@dewire.com>
+ * Copyright (C) 2008, Shawn O. Pearce <spearce@spearce.org>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.transport;
+
+import junit.framework.TestCase;
+
+public class URIishTest extends TestCase {
+
+ public void testUnixFile() throws Exception {
+ final String str = "/home/m y";
+ URIish u = new URIish(str);
+ assertNull(u.getScheme());
+ assertFalse(u.isRemote());
+ assertEquals(str, u.getPath());
+ assertEquals(str, u.toString());
+ assertEquals(u, new URIish(str));
+ }
+
+ public void testWindowsFile() throws Exception {
+ final String str = "D:/m y";
+ URIish u = new URIish(str);
+ assertNull(u.getScheme());
+ assertFalse(u.isRemote());
+ assertEquals(str, u.getPath());
+ assertEquals(str, u.toString());
+ assertEquals(u, new URIish(str));
+ }
+
+ public void testWindowsFile2() throws Exception {
+ final String str = "D:\\m y";
+ URIish u = new URIish(str);
+ assertNull(u.getScheme());
+ assertFalse(u.isRemote());
+ assertEquals("D:/m y", u.getPath());
+ assertEquals("D:/m y", u.toString());
+ assertEquals(u, new URIish(str));
+ }
+
+ public void testUNC() throws Exception {
+ final String str = "\\\\some\\place";
+ URIish u = new URIish(str);
+ assertNull(u.getScheme());
+ assertFalse(u.isRemote());
+ assertEquals("//some/place", u.getPath());
+ assertEquals("//some/place", u.toString());
+ assertEquals(u, new URIish(str));
+ }
+
+ public void testFileProtoUnix() throws Exception {
+ final String str = "file:///home/m y";
+ URIish u = new URIish(str);
+ assertEquals("file", u.getScheme());
+ assertFalse(u.isRemote());
+ assertEquals("/home/m y", u.getPath());
+ assertEquals(str, u.toString());
+ assertEquals(u, new URIish(str));
+ }
+
+ public void testFileProtoWindows() throws Exception {
+ final String str = "file:///D:/m y";
+ URIish u = new URIish(str);
+ assertEquals("file", u.getScheme());
+ assertFalse(u.isRemote());
+ assertEquals("D:/m y", u.getPath());
+ assertEquals(str, u.toString());
+ assertEquals(u, new URIish(str));
+ }
+
+ public void testGitProtoUnix() throws Exception {
+ final String str = "git://example.com/home/m y";
+ URIish u = new URIish(str);
+ assertEquals("git", u.getScheme());
+ assertTrue(u.isRemote());
+ assertEquals("example.com", u.getHost());
+ assertEquals("/home/m y", u.getPath());
+ assertEquals(str, u.toString());
+ assertEquals(u, new URIish(str));
+ }
+
+ public void testGitProtoUnixPort() throws Exception {
+ final String str = "git://example.com:333/home/m y";
+ URIish u = new URIish(str);
+ assertEquals("git", u.getScheme());
+ assertTrue(u.isRemote());
+ assertEquals("example.com", u.getHost());
+ assertEquals("/home/m y", u.getPath());
+ assertEquals(333, u.getPort());
+ assertEquals(str, u.toString());
+ assertEquals(u, new URIish(str));
+ }
+
+ public void testGitProtoWindowsPort() throws Exception {
+ final String str = "git://example.com:338/D:/m y";
+ URIish u = new URIish(str);
+ assertEquals("git", u.getScheme());
+ assertTrue(u.isRemote());
+ assertEquals("D:/m y", u.getPath());
+ assertEquals(338, u.getPort());
+ assertEquals("example.com", u.getHost());
+ assertEquals(str, u.toString());
+ assertEquals(u, new URIish(str));
+ }
+
+ public void testGitProtoWindows() throws Exception {
+ final String str = "git://example.com/D:/m y";
+ URIish u = new URIish(str);
+ assertEquals("git", u.getScheme());
+ assertTrue(u.isRemote());
+ assertEquals("D:/m y", u.getPath());
+ assertEquals("example.com", u.getHost());
+ assertEquals(-1, u.getPort());
+ assertEquals(str, u.toString());
+ assertEquals(u, new URIish(str));
+ }
+
+ public void testScpStyleWithoutUser() throws Exception {
+ final String str = "example.com:some/p ath";
+ URIish u = new URIish(str);
+ assertNull(u.getScheme());
+ assertTrue(u.isRemote());
+ assertEquals("some/p ath", u.getPath());
+ assertEquals("example.com", u.getHost());
+ assertEquals(-1, u.getPort());
+ assertEquals(str, u.toString());
+ assertEquals(u, new URIish(str));
+ }
+
+ public void testScpStyleWithUser() throws Exception {
+ final String str = "user@example.com:some/p ath";
+ URIish u = new URIish(str);
+ assertNull(u.getScheme());
+ assertTrue(u.isRemote());
+ assertEquals("some/p ath", u.getPath());
+ assertEquals("user", u.getUser());
+ assertEquals("example.com", u.getHost());
+ assertEquals(-1, u.getPort());
+ assertEquals(str, u.toString());
+ assertEquals(u, new URIish(str));
+ }
+
+ public void testGitSshProto() throws Exception {
+ final String str = "git+ssh://example.com/some/p ath";
+ URIish u = new URIish(str);
+ assertEquals("git+ssh", u.getScheme());
+ assertTrue(u.isRemote());
+ assertEquals("/some/p ath", u.getPath());
+ assertEquals("example.com", u.getHost());
+ assertEquals(-1, u.getPort());
+ assertEquals(str, u.toString());
+ assertEquals(u, new URIish(str));
+ }
+
+ public void testSshGitProto() throws Exception {
+ final String str = "ssh+git://example.com/some/p ath";
+ URIish u = new URIish(str);
+ assertEquals("ssh+git", u.getScheme());
+ assertTrue(u.isRemote());
+ assertEquals("/some/p ath", u.getPath());
+ assertEquals("example.com", u.getHost());
+ assertEquals(-1, u.getPort());
+ assertEquals(str, u.toString());
+ assertEquals(u, new URIish(str));
+ }
+
+ public void testSshProto() throws Exception {
+ final String str = "ssh://example.com/some/p ath";
+ URIish u = new URIish(str);
+ assertEquals("ssh", u.getScheme());
+ assertTrue(u.isRemote());
+ assertEquals("/some/p ath", u.getPath());
+ assertEquals("example.com", u.getHost());
+ assertEquals(-1, u.getPort());
+ assertEquals(str, u.toString());
+ assertEquals(u, new URIish(str));
+ }
+
+ public void testSshProtoWithUserAndPort() throws Exception {
+ final String str = "ssh://user@example.com:33/some/p ath";
+ URIish u = new URIish(str);
+ assertEquals("ssh", u.getScheme());
+ assertTrue(u.isRemote());
+ assertEquals("/some/p ath", u.getPath());
+ assertEquals("example.com", u.getHost());
+ assertEquals("user", u.getUser());
+ assertNull(u.getPass());
+ assertEquals(33, u.getPort());
+ assertEquals(str, u.toString());
+ assertEquals(u, new URIish(str));
+ }
+
+ public void testSshProtoWithUserPassAndPort() throws Exception {
+ final String str = "ssh://user:pass@example.com:33/some/p ath";
+ URIish u = new URIish(str);
+ assertEquals("ssh", u.getScheme());
+ assertTrue(u.isRemote());
+ assertEquals("/some/p ath", u.getPath());
+ assertEquals("example.com", u.getHost());
+ assertEquals("user", u.getUser());
+ assertEquals("pass", u.getPass());
+ assertEquals(33, u.getPort());
+ assertEquals(str, u.toPrivateString());
+ assertEquals(u.setPass(null).toPrivateString(), u.toString());
+ assertEquals(u, new URIish(str));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/AbstractTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/AbstractTreeIteratorTest.java
new file mode 100644
index 0000000000..e96445a30a
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/AbstractTreeIteratorTest.java
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * Copyright (C) 2009, Tor Arne Vestbø <torarnv@gmail.com>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.treewalk;
+
+import java.io.IOException;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.Repository;
+
+
+public class AbstractTreeIteratorTest extends TestCase {
+ private static String prefix(String path) {
+ final int s = path.lastIndexOf('/');
+ return s > 0 ? path.substring(0, s) : "";
+ }
+
+ public class FakeTreeIterator extends WorkingTreeIterator {
+ public FakeTreeIterator(String pathName, FileMode fileMode) {
+ super(prefix(pathName));
+ mode = fileMode.getBits();
+
+ final int s = pathName.lastIndexOf('/');
+ final byte[] name = Constants.encode(pathName.substring(s + 1));
+ ensurePathCapacity(pathOffset + name.length, pathOffset);
+ System.arraycopy(name, 0, path, pathOffset, name.length);
+ pathLen = pathOffset + name.length;
+ }
+
+ @Override
+ public AbstractTreeIterator createSubtreeIterator(Repository repo)
+ throws IncorrectObjectTypeException, IOException {
+ return null;
+ }
+ }
+
+ public void testPathCompare() throws Exception {
+ assertTrue(new FakeTreeIterator("a", FileMode.REGULAR_FILE).pathCompare(
+ new FakeTreeIterator("a", FileMode.TREE)) < 0);
+
+ assertTrue(new FakeTreeIterator("a", FileMode.TREE).pathCompare(
+ new FakeTreeIterator("a", FileMode.REGULAR_FILE)) > 0);
+
+ assertTrue(new FakeTreeIterator("a", FileMode.REGULAR_FILE).pathCompare(
+ new FakeTreeIterator("a", FileMode.REGULAR_FILE)) == 0);
+
+ assertTrue(new FakeTreeIterator("a", FileMode.TREE).pathCompare(
+ new FakeTreeIterator("a", FileMode.TREE)) == 0);
+ }
+
+ public void testGrowPath() throws Exception {
+ final FakeTreeIterator i = new FakeTreeIterator("ab", FileMode.TREE);
+ final byte[] origpath = i.path;
+ assertEquals(i.path[0], 'a');
+ assertEquals(i.path[1], 'b');
+
+ i.growPath(2);
+
+ assertNotSame(origpath, i.path);
+ assertEquals(origpath.length * 2, i.path.length);
+ assertEquals(i.path[0], 'a');
+ assertEquals(i.path[1], 'b');
+ }
+
+ public void testEnsurePathCapacityFastCase() throws Exception {
+ final FakeTreeIterator i = new FakeTreeIterator("ab", FileMode.TREE);
+ final int want = 50;
+ final byte[] origpath = i.path;
+ assertEquals(i.path[0], 'a');
+ assertEquals(i.path[1], 'b');
+ assertTrue(want < i.path.length);
+
+ i.ensurePathCapacity(want, 2);
+
+ assertSame(origpath, i.path);
+ assertEquals(i.path[0], 'a');
+ assertEquals(i.path[1], 'b');
+ }
+
+ public void testEnsurePathCapacityGrows() throws Exception {
+ final FakeTreeIterator i = new FakeTreeIterator("ab", FileMode.TREE);
+ final int want = 384;
+ final byte[] origpath = i.path;
+ assertEquals(i.path[0], 'a');
+ assertEquals(i.path[1], 'b');
+ assertTrue(i.path.length < want);
+
+ i.ensurePathCapacity(want, 2);
+
+ assertNotSame(origpath, i.path);
+ assertEquals(512, i.path.length);
+ assertEquals(i.path[0], 'a');
+ assertEquals(i.path[1], 'b');
+ }
+
+ public void testEntryFileMode() {
+ for (FileMode m : new FileMode[] { FileMode.TREE,
+ FileMode.REGULAR_FILE, FileMode.EXECUTABLE_FILE,
+ FileMode.GITLINK, FileMode.SYMLINK }) {
+ final FakeTreeIterator i = new FakeTreeIterator("a", m);
+ assertEquals(m.getBits(), i.getEntryRawMode());
+ assertSame(m, i.getEntryFileMode());
+ }
+ }
+
+ public void testEntryPath() {
+ FakeTreeIterator i = new FakeTreeIterator("a/b/cd", FileMode.TREE);
+ assertEquals("a/b/cd", i.getEntryPathString());
+ assertEquals(2, i.getNameLength());
+ byte[] b = new byte[3];
+ b[0] = 0x0a;
+ i.getName(b, 1);
+ assertEquals(0x0a, b[0]);
+ assertEquals('c', b[1]);
+ assertEquals('d', b[2]);
+ }
+
+ public void testCreateEmptyTreeIterator() {
+ FakeTreeIterator i = new FakeTreeIterator("a/b/cd", FileMode.TREE);
+ EmptyTreeIterator e = i.createEmptyTreeIterator();
+ assertNotNull(e);
+ assertEquals(i.getEntryPathString() + "/", e.getEntryPathString());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/CanonicalTreeParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/CanonicalTreeParserTest.java
new file mode 100644
index 0000000000..da25f8d632
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/CanonicalTreeParserTest.java
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2008-2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.treewalk;
+
+import java.io.ByteArrayOutputStream;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.util.RawParseUtils;
+
+public class CanonicalTreeParserTest extends TestCase {
+ private final CanonicalTreeParser ctp = new CanonicalTreeParser();
+
+ private final FileMode m644 = FileMode.REGULAR_FILE;
+
+ private final FileMode mt = FileMode.TREE;
+
+ private final ObjectId hash_a = ObjectId
+ .fromString("6b9c715d21d5486e59083fb6071566aa6ecd4d42");
+
+ private final ObjectId hash_foo = ObjectId
+ .fromString("a213e8e25bb2442326e86cbfb9ef56319f482869");
+
+ private final ObjectId hash_sometree = ObjectId
+ .fromString("daf4bdb0d7bb24319810fe0e73aa317663448c93");
+
+ private byte[] tree1;
+
+ private byte[] tree2;
+
+ private byte[] tree3;
+
+ public void setUp() throws Exception {
+ super.setUp();
+
+ tree1 = mktree(entry(m644, "a", hash_a));
+ tree2 = mktree(entry(m644, "a", hash_a), entry(m644, "foo", hash_foo));
+ tree3 = mktree(entry(m644, "a", hash_a), entry(mt, "b_sometree",
+ hash_sometree), entry(m644, "foo", hash_foo));
+ }
+
+ private static byte[] mktree(final byte[]... data) throws Exception {
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ for (final byte[] e : data)
+ out.write(e);
+ return out.toByteArray();
+ }
+
+ private static byte[] entry(final FileMode mode, final String name,
+ final ObjectId id) throws Exception {
+ final ByteArrayOutputStream out = new ByteArrayOutputStream();
+ mode.copyTo(out);
+ out.write(' ');
+ out.write(Constants.encode(name));
+ out.write(0);
+ id.copyRawTo(out);
+ return out.toByteArray();
+ }
+
+ private String path() {
+ return RawParseUtils.decode(Constants.CHARSET, ctp.path,
+ ctp.pathOffset, ctp.pathLen);
+ }
+
+ public void testEmptyTree_AtEOF() throws Exception {
+ ctp.reset(new byte[0]);
+ assertTrue(ctp.eof());
+ }
+
+ public void testOneEntry_Forward() throws Exception {
+ ctp.reset(tree1);
+
+ assertTrue(ctp.first());
+ assertFalse(ctp.eof());
+ assertEquals(m644.getBits(), ctp.mode);
+ assertEquals("a", path());
+ assertEquals(hash_a, ctp.getEntryObjectId());
+
+ ctp.next(1);
+ assertFalse(ctp.first());
+ assertTrue(ctp.eof());
+ }
+
+ public void testTwoEntries_ForwardOneAtATime() throws Exception {
+ ctp.reset(tree2);
+
+ assertTrue(ctp.first());
+ assertFalse(ctp.eof());
+ assertEquals(m644.getBits(), ctp.mode);
+ assertEquals("a", path());
+ assertEquals(hash_a, ctp.getEntryObjectId());
+
+ ctp.next(1);
+ assertFalse(ctp.eof());
+ assertEquals(m644.getBits(), ctp.mode);
+ assertEquals("foo", path());
+ assertEquals(hash_foo, ctp.getEntryObjectId());
+
+ ctp.next(1);
+ assertFalse(ctp.first());
+ assertTrue(ctp.eof());
+ }
+
+ public void testOneEntry_Seek1IsEOF() throws Exception {
+ ctp.reset(tree1);
+ ctp.next(1);
+ assertTrue(ctp.eof());
+ }
+
+ public void testTwoEntries_Seek2IsEOF() throws Exception {
+ ctp.reset(tree2);
+ ctp.next(2);
+ assertTrue(ctp.eof());
+ }
+
+ public void testThreeEntries_Seek3IsEOF() throws Exception {
+ ctp.reset(tree3);
+ ctp.next(3);
+ assertTrue(ctp.eof());
+ }
+
+ public void testThreeEntries_Seek2() throws Exception {
+ ctp.reset(tree3);
+
+ ctp.next(2);
+ assertFalse(ctp.eof());
+ assertFalse(ctp.eof());
+ assertEquals(m644.getBits(), ctp.mode);
+ assertEquals("foo", path());
+ assertEquals(hash_foo, ctp.getEntryObjectId());
+
+ ctp.next(1);
+ assertTrue(ctp.eof());
+ }
+
+ public void testOneEntry_Backwards() throws Exception {
+ ctp.reset(tree1);
+ ctp.next(1);
+ assertFalse(ctp.first());
+ assertTrue(ctp.eof());
+
+ ctp.back(1);
+ assertTrue(ctp.first());
+ assertFalse(ctp.eof());
+ assertEquals(m644.getBits(), ctp.mode);
+ assertEquals("a", path());
+ assertEquals(hash_a, ctp.getEntryObjectId());
+ }
+
+ public void testTwoEntries_BackwardsOneAtATime() throws Exception {
+ ctp.reset(tree2);
+ ctp.next(2);
+ assertTrue(ctp.eof());
+
+ ctp.back(1);
+ assertFalse(ctp.eof());
+ assertEquals(m644.getBits(), ctp.mode);
+ assertEquals("foo", path());
+ assertEquals(hash_foo, ctp.getEntryObjectId());
+
+ ctp.back(1);
+ assertFalse(ctp.eof());
+ assertEquals(m644.getBits(), ctp.mode);
+ assertEquals("a", path());
+ assertEquals(hash_a, ctp.getEntryObjectId());
+ }
+
+ public void testTwoEntries_BackwardsTwo() throws Exception {
+ ctp.reset(tree2);
+ ctp.next(2);
+ assertTrue(ctp.eof());
+
+ ctp.back(2);
+ assertFalse(ctp.eof());
+ assertEquals(m644.getBits(), ctp.mode);
+ assertEquals("a", path());
+ assertEquals(hash_a, ctp.getEntryObjectId());
+
+ ctp.next(1);
+ assertFalse(ctp.eof());
+ assertEquals(m644.getBits(), ctp.mode);
+ assertEquals("foo", path());
+ assertEquals(hash_foo, ctp.getEntryObjectId());
+
+ ctp.next(1);
+ assertTrue(ctp.eof());
+ }
+
+ public void testThreeEntries_BackwardsTwo() throws Exception {
+ ctp.reset(tree3);
+ ctp.next(3);
+ assertTrue(ctp.eof());
+
+ ctp.back(2);
+ assertFalse(ctp.eof());
+ assertEquals(mt.getBits(), ctp.mode);
+ assertEquals("b_sometree", path());
+ assertEquals(hash_sometree, ctp.getEntryObjectId());
+
+ ctp.next(1);
+ assertFalse(ctp.eof());
+ assertEquals(m644.getBits(), ctp.mode);
+ assertEquals("foo", path());
+ assertEquals(hash_foo, ctp.getEntryObjectId());
+
+ ctp.next(1);
+ assertTrue(ctp.eof());
+ }
+
+ public void testBackwards_ConfusingPathName() throws Exception {
+ final String aVeryConfusingName = "confusing 644 entry 755 and others";
+ ctp.reset(mktree(entry(m644, "a", hash_a), entry(mt, aVeryConfusingName,
+ hash_sometree), entry(m644, "foo", hash_foo)));
+ ctp.next(3);
+ assertTrue(ctp.eof());
+
+ ctp.back(2);
+ assertFalse(ctp.eof());
+ assertEquals(mt.getBits(), ctp.mode);
+ assertEquals(aVeryConfusingName, path());
+ assertEquals(hash_sometree, ctp.getEntryObjectId());
+
+ ctp.back(1);
+ assertFalse(ctp.eof());
+ assertEquals(m644.getBits(), ctp.mode);
+ assertEquals("a", path());
+ assertEquals(hash_a, ctp.getEntryObjectId());
+ }
+
+ public void testBackwords_Prebuilts1() throws Exception {
+ // What is interesting about this test is the ObjectId for the
+ // "darwin-x86" path entry ends in an octal digit (37 == '7').
+ // Thus when scanning backwards we could over scan and consume
+ // part of the SHA-1, and miss the path terminator.
+ //
+ final ObjectId common = ObjectId
+ .fromString("af7bf97cb9bce3f60f1d651a0ef862e9447dd8bc");
+ final ObjectId darwinx86 = ObjectId
+ .fromString("e927f7398240f78face99e1a738dac54ef738e37");
+ final ObjectId linuxx86 = ObjectId
+ .fromString("ac08dd97120c7cb7d06e98cd5b152011183baf21");
+ final ObjectId windows = ObjectId
+ .fromString("6c4c64c221a022bb973165192cca4812033479df");
+
+ ctp.reset(mktree(entry(mt, "common", common), entry(mt, "darwin-x86",
+ darwinx86), entry(mt, "linux-x86", linuxx86), entry(mt,
+ "windows", windows)));
+ ctp.next(3);
+ assertEquals("windows", ctp.getEntryPathString());
+ assertSame(mt, ctp.getEntryFileMode());
+ assertEquals(windows, ctp.getEntryObjectId());
+
+ ctp.back(1);
+ assertEquals("linux-x86", ctp.getEntryPathString());
+ assertSame(mt, ctp.getEntryFileMode());
+ assertEquals(linuxx86, ctp.getEntryObjectId());
+
+ ctp.next(1);
+ assertEquals("windows", ctp.getEntryPathString());
+ assertSame(mt, ctp.getEntryFileMode());
+ assertEquals(windows, ctp.getEntryObjectId());
+ }
+
+ public void testBackwords_Prebuilts2() throws Exception {
+ // What is interesting about this test is the ObjectId for the
+ // "darwin-x86" path entry ends in an octal digit (37 == '7').
+ // Thus when scanning backwards we could over scan and consume
+ // part of the SHA-1, and miss the path terminator.
+ //
+ final ObjectId common = ObjectId
+ .fromString("af7bf97cb9bce3f60f1d651a0ef862e9447dd8bc");
+ final ObjectId darwinx86 = ObjectId
+ .fromString("0000000000000000000000000000000000000037");
+ final ObjectId linuxx86 = ObjectId
+ .fromString("ac08dd97120c7cb7d06e98cd5b152011183baf21");
+ final ObjectId windows = ObjectId
+ .fromString("6c4c64c221a022bb973165192cca4812033479df");
+
+ ctp.reset(mktree(entry(mt, "common", common), entry(mt, "darwin-x86",
+ darwinx86), entry(mt, "linux-x86", linuxx86), entry(mt,
+ "windows", windows)));
+ ctp.next(3);
+ assertEquals("windows", ctp.getEntryPathString());
+ assertSame(mt, ctp.getEntryFileMode());
+ assertEquals(windows, ctp.getEntryObjectId());
+
+ ctp.back(1);
+ assertEquals("linux-x86", ctp.getEntryPathString());
+ assertSame(mt, ctp.getEntryFileMode());
+ assertEquals(linuxx86, ctp.getEntryObjectId());
+
+ ctp.next(1);
+ assertEquals("windows", ctp.getEntryPathString());
+ assertSame(mt, ctp.getEntryFileMode());
+ assertEquals(windows, ctp.getEntryObjectId());
+ }
+
+ public void testFreakingHugePathName() throws Exception {
+ final int n = AbstractTreeIterator.DEFAULT_PATH_SIZE * 4;
+ final StringBuilder b = new StringBuilder(n);
+ for (int i = 0; i < n; i++)
+ b.append('q');
+ final String name = b.toString();
+ ctp.reset(entry(m644, name, hash_a));
+ assertFalse(ctp.eof());
+ assertEquals(name, RawParseUtils.decode(Constants.CHARSET, ctp.path,
+ ctp.pathOffset, ctp.pathLen));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/EmptyTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/EmptyTreeIteratorTest.java
new file mode 100644
index 0000000000..111264b1c9
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/EmptyTreeIteratorTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.treewalk;
+
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+
+public class EmptyTreeIteratorTest extends RepositoryTestCase {
+ public void testAtEOF() throws Exception {
+ final EmptyTreeIterator etp = new EmptyTreeIterator();
+ assertTrue(etp.first());
+ assertTrue(etp.eof());
+ }
+
+ public void testCreateSubtreeIterator() throws Exception {
+ final EmptyTreeIterator etp = new EmptyTreeIterator();
+ final AbstractTreeIterator sub = etp.createSubtreeIterator(db);
+ assertNotNull(sub);
+ assertTrue(sub.first());
+ assertTrue(sub.eof());
+ assertTrue(sub instanceof EmptyTreeIterator);
+ }
+
+ public void testEntryObjectId() throws Exception {
+ final EmptyTreeIterator etp = new EmptyTreeIterator();
+ assertSame(ObjectId.zeroId(), etp.getEntryObjectId());
+ assertNotNull(etp.idBuffer());
+ assertEquals(0, etp.idOffset());
+ assertEquals(ObjectId.zeroId(), ObjectId.fromRaw(etp.idBuffer()));
+ }
+
+ public void testNextDoesNothing() throws Exception {
+ final EmptyTreeIterator etp = new EmptyTreeIterator();
+ etp.next(1);
+ assertTrue(etp.first());
+ assertTrue(etp.eof());
+ assertEquals(ObjectId.zeroId(), ObjectId.fromRaw(etp.idBuffer()));
+
+ etp.next(1);
+ assertTrue(etp.first());
+ assertTrue(etp.eof());
+ assertEquals(ObjectId.zeroId(), ObjectId.fromRaw(etp.idBuffer()));
+ }
+
+ public void testBackDoesNothing() throws Exception {
+ final EmptyTreeIterator etp = new EmptyTreeIterator();
+ etp.back(1);
+ assertTrue(etp.first());
+ assertTrue(etp.eof());
+ assertEquals(ObjectId.zeroId(), ObjectId.fromRaw(etp.idBuffer()));
+
+ etp.back(1);
+ assertTrue(etp.first());
+ assertTrue(etp.eof());
+ assertEquals(ObjectId.zeroId(), ObjectId.fromRaw(etp.idBuffer()));
+ }
+
+ public void testStopWalkCallsParent() throws Exception {
+ final boolean called[] = new boolean[1];
+ assertFalse(called[0]);
+
+ final EmptyTreeIterator parent = new EmptyTreeIterator() {
+ @Override
+ public void stopWalk() {
+ called[0] = true;
+ }
+ };
+ parent.createSubtreeIterator(db).stopWalk();
+ assertTrue(called[0]);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
new file mode 100644
index 0000000000..081290310a
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.treewalk;
+
+import java.io.File;
+import java.security.MessageDigest;
+
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+import org.eclipse.jgit.util.RawParseUtils;
+
+public class FileTreeIteratorTest extends RepositoryTestCase {
+ private final String[] paths = { "a,", "a,b", "a/b", "a0b" };
+
+ private long[] mtime;
+
+ public void setUp() throws Exception {
+ super.setUp();
+
+ // We build the entries backwards so that on POSIX systems we
+ // are likely to get the entries in the trash directory in the
+ // opposite order of what they should be in for the iteration.
+ // This should stress the sorting code better than doing it in
+ // the correct order.
+ //
+ mtime = new long[paths.length];
+ for (int i = paths.length - 1; i >= 0; i--) {
+ final String s = paths[i];
+ writeTrashFile(s, s);
+ mtime[i] = new File(trash, s).lastModified();
+ }
+ }
+
+ public void testEmptyIfRootIsFile() throws Exception {
+ final File r = new File(trash, paths[0]);
+ assertTrue(r.isFile());
+ final FileTreeIterator fti = new FileTreeIterator(r);
+ assertTrue(fti.first());
+ assertTrue(fti.eof());
+ }
+
+ public void testEmptyIfRootDoesNotExist() throws Exception {
+ final File r = new File(trash, "not-existing-file");
+ assertFalse(r.exists());
+ final FileTreeIterator fti = new FileTreeIterator(r);
+ assertTrue(fti.first());
+ assertTrue(fti.eof());
+ }
+
+ public void testEmptyIfRootIsEmpty() throws Exception {
+ final File r = new File(trash, "not-existing-file");
+ assertFalse(r.exists());
+ r.mkdir();
+ assertTrue(r.isDirectory());
+
+ final FileTreeIterator fti = new FileTreeIterator(r);
+ assertTrue(fti.first());
+ assertTrue(fti.eof());
+ }
+
+ public void testSimpleIterate() throws Exception {
+ final FileTreeIterator top = new FileTreeIterator(trash);
+
+ assertTrue(top.first());
+ assertFalse(top.eof());
+ assertEquals(FileMode.REGULAR_FILE.getBits(), top.mode);
+ assertEquals(paths[0], nameOf(top));
+ assertEquals(paths[0].length(), top.getEntryLength());
+ assertEquals(mtime[0], top.getEntryLastModified());
+
+ top.next(1);
+ assertFalse(top.first());
+ assertFalse(top.eof());
+ assertEquals(FileMode.REGULAR_FILE.getBits(), top.mode);
+ assertEquals(paths[1], nameOf(top));
+ assertEquals(paths[1].length(), top.getEntryLength());
+ assertEquals(mtime[1], top.getEntryLastModified());
+
+ top.next(1);
+ assertFalse(top.first());
+ assertFalse(top.eof());
+ assertEquals(FileMode.TREE.getBits(), top.mode);
+
+ final AbstractTreeIterator sub = top.createSubtreeIterator(db);
+ assertTrue(sub instanceof FileTreeIterator);
+ final FileTreeIterator subfti = (FileTreeIterator) sub;
+ assertTrue(sub.first());
+ assertFalse(sub.eof());
+ assertEquals(paths[2], nameOf(sub));
+ assertEquals(paths[2].length(), subfti.getEntryLength());
+ assertEquals(mtime[2], subfti.getEntryLastModified());
+
+ sub.next(1);
+ assertTrue(sub.eof());
+
+ top.next(1);
+ assertFalse(top.first());
+ assertFalse(top.eof());
+ assertEquals(FileMode.REGULAR_FILE.getBits(), top.mode);
+ assertEquals(paths[3], nameOf(top));
+ assertEquals(paths[3].length(), top.getEntryLength());
+ assertEquals(mtime[3], top.getEntryLastModified());
+
+ top.next(1);
+ assertTrue(top.eof());
+ }
+
+ public void testComputeFileObjectId() throws Exception {
+ final FileTreeIterator top = new FileTreeIterator(trash);
+
+ final MessageDigest md = Constants.newMessageDigest();
+ md.update(Constants.encodeASCII(Constants.TYPE_BLOB));
+ md.update((byte) ' ');
+ md.update(Constants.encodeASCII(paths[0].length()));
+ md.update((byte) 0);
+ md.update(Constants.encode(paths[0]));
+ final ObjectId expect = ObjectId.fromRaw(md.digest());
+
+ assertEquals(expect, top.getEntryObjectId());
+
+ // Verify it was cached by removing the file and getting it again.
+ //
+ new File(trash, paths[0]).delete();
+ assertEquals(expect, top.getEntryObjectId());
+ }
+
+ private static String nameOf(final AbstractTreeIterator i) {
+ return RawParseUtils.decode(Constants.CHARSET, i.path, 0, i.pathLen);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/NameConflictTreeWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/NameConflictTreeWalkTest.java
new file mode 100644
index 0000000000..35298b803f
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/NameConflictTreeWalkTest.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.treewalk;
+
+import java.io.ByteArrayInputStream;
+
+import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheBuilder;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.dircache.DirCacheIterator;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectWriter;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+
+public class NameConflictTreeWalkTest extends RepositoryTestCase {
+ private static final FileMode TREE = FileMode.TREE;
+
+ private static final FileMode SYMLINK = FileMode.SYMLINK;
+
+ private static final FileMode MISSING = FileMode.MISSING;
+
+ private static final FileMode REGULAR_FILE = FileMode.REGULAR_FILE;
+
+ private static final FileMode EXECUTABLE_FILE = FileMode.EXECUTABLE_FILE;
+
+ public void testNoDF_NoGap() throws Exception {
+ final DirCache tree0 = DirCache.read(db);
+ final DirCache tree1 = DirCache.read(db);
+ {
+ final DirCacheBuilder b0 = tree0.builder();
+ final DirCacheBuilder b1 = tree1.builder();
+
+ b0.add(makeEntry("a", REGULAR_FILE));
+ b0.add(makeEntry("a.b", EXECUTABLE_FILE));
+ b1.add(makeEntry("a/b", REGULAR_FILE));
+ b0.add(makeEntry("a0b", SYMLINK));
+
+ b0.finish();
+ b1.finish();
+ assertEquals(3, tree0.getEntryCount());
+ assertEquals(1, tree1.getEntryCount());
+ }
+
+ final TreeWalk tw = new TreeWalk(db);
+ tw.reset();
+ tw.addTree(new DirCacheIterator(tree0));
+ tw.addTree(new DirCacheIterator(tree1));
+
+ assertModes("a", REGULAR_FILE, MISSING, tw);
+ assertModes("a.b", EXECUTABLE_FILE, MISSING, tw);
+ assertModes("a", MISSING, TREE, tw);
+ tw.enterSubtree();
+ assertModes("a/b", MISSING, REGULAR_FILE, tw);
+ assertModes("a0b", SYMLINK, MISSING, tw);
+ }
+
+ public void testDF_NoGap() throws Exception {
+ final DirCache tree0 = DirCache.read(db);
+ final DirCache tree1 = DirCache.read(db);
+ {
+ final DirCacheBuilder b0 = tree0.builder();
+ final DirCacheBuilder b1 = tree1.builder();
+
+ b0.add(makeEntry("a", REGULAR_FILE));
+ b0.add(makeEntry("a.b", EXECUTABLE_FILE));
+ b1.add(makeEntry("a/b", REGULAR_FILE));
+ b0.add(makeEntry("a0b", SYMLINK));
+
+ b0.finish();
+ b1.finish();
+ assertEquals(3, tree0.getEntryCount());
+ assertEquals(1, tree1.getEntryCount());
+ }
+
+ final NameConflictTreeWalk tw = new NameConflictTreeWalk(db);
+ tw.reset();
+ tw.addTree(new DirCacheIterator(tree0));
+ tw.addTree(new DirCacheIterator(tree1));
+
+ assertModes("a", REGULAR_FILE, TREE, tw);
+ assertTrue(tw.isSubtree());
+ tw.enterSubtree();
+ assertModes("a/b", MISSING, REGULAR_FILE, tw);
+ assertModes("a.b", EXECUTABLE_FILE, MISSING, tw);
+ assertModes("a0b", SYMLINK, MISSING, tw);
+ }
+
+ public void testDF_GapByOne() throws Exception {
+ final DirCache tree0 = DirCache.read(db);
+ final DirCache tree1 = DirCache.read(db);
+ {
+ final DirCacheBuilder b0 = tree0.builder();
+ final DirCacheBuilder b1 = tree1.builder();
+
+ b0.add(makeEntry("a", REGULAR_FILE));
+ b0.add(makeEntry("a.b", EXECUTABLE_FILE));
+ b1.add(makeEntry("a.b", EXECUTABLE_FILE));
+ b1.add(makeEntry("a/b", REGULAR_FILE));
+ b0.add(makeEntry("a0b", SYMLINK));
+
+ b0.finish();
+ b1.finish();
+ assertEquals(3, tree0.getEntryCount());
+ assertEquals(2, tree1.getEntryCount());
+ }
+
+ final NameConflictTreeWalk tw = new NameConflictTreeWalk(db);
+ tw.reset();
+ tw.addTree(new DirCacheIterator(tree0));
+ tw.addTree(new DirCacheIterator(tree1));
+
+ assertModes("a", REGULAR_FILE, TREE, tw);
+ assertTrue(tw.isSubtree());
+ tw.enterSubtree();
+ assertModes("a/b", MISSING, REGULAR_FILE, tw);
+ assertModes("a.b", EXECUTABLE_FILE, EXECUTABLE_FILE, tw);
+ assertModes("a0b", SYMLINK, MISSING, tw);
+ }
+
+ public void testDF_SkipsSeenSubtree() throws Exception {
+ final DirCache tree0 = DirCache.read(db);
+ final DirCache tree1 = DirCache.read(db);
+ {
+ final DirCacheBuilder b0 = tree0.builder();
+ final DirCacheBuilder b1 = tree1.builder();
+
+ b0.add(makeEntry("a", REGULAR_FILE));
+ b1.add(makeEntry("a.b", EXECUTABLE_FILE));
+ b1.add(makeEntry("a/b", REGULAR_FILE));
+ b0.add(makeEntry("a0b", SYMLINK));
+ b1.add(makeEntry("a0b", SYMLINK));
+
+ b0.finish();
+ b1.finish();
+ assertEquals(2, tree0.getEntryCount());
+ assertEquals(3, tree1.getEntryCount());
+ }
+
+ final NameConflictTreeWalk tw = new NameConflictTreeWalk(db);
+ tw.reset();
+ tw.addTree(new DirCacheIterator(tree0));
+ tw.addTree(new DirCacheIterator(tree1));
+
+ assertModes("a", REGULAR_FILE, TREE, tw);
+ assertTrue(tw.isSubtree());
+ tw.enterSubtree();
+ assertModes("a/b", MISSING, REGULAR_FILE, tw);
+ assertModes("a.b", MISSING, EXECUTABLE_FILE, tw);
+ assertModes("a0b", SYMLINK, SYMLINK, tw);
+ }
+
+ private DirCacheEntry makeEntry(final String path, final FileMode mode)
+ throws Exception {
+ final byte[] pathBytes = Constants.encode(path);
+ final DirCacheEntry ent = new DirCacheEntry(path);
+ ent.setFileMode(mode);
+ ent.setObjectId(new ObjectWriter(db).computeBlobSha1(pathBytes.length,
+ new ByteArrayInputStream(pathBytes)));
+ return ent;
+ }
+
+ private static void assertModes(final String path, final FileMode mode0,
+ final FileMode mode1, final TreeWalk tw) throws Exception {
+ assertTrue("has " + path, tw.next());
+ assertEquals(path, tw.getPathString());
+ assertEquals(mode0, tw.getFileMode(0));
+ assertEquals(mode1, tw.getFileMode(1));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/PostOrderTreeWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/PostOrderTreeWalkTest.java
new file mode 100644
index 0000000000..d136b8f297
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/PostOrderTreeWalkTest.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.treewalk;
+
+import java.io.ByteArrayInputStream;
+
+import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheBuilder;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.dircache.DirCacheIterator;
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectWriter;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+
+import static org.eclipse.jgit.lib.FileMode.REGULAR_FILE;
+import static org.eclipse.jgit.lib.FileMode.TREE;
+
+public class PostOrderTreeWalkTest extends RepositoryTestCase {
+ public void testInitialize_NoPostOrder() throws Exception {
+ final TreeWalk tw = new TreeWalk(db);
+ assertFalse(tw.isPostOrderTraversal());
+ }
+
+ public void testInitialize_TogglePostOrder() throws Exception {
+ final TreeWalk tw = new TreeWalk(db);
+ assertFalse(tw.isPostOrderTraversal());
+ tw.setPostOrderTraversal(true);
+ assertTrue(tw.isPostOrderTraversal());
+ tw.setPostOrderTraversal(false);
+ assertFalse(tw.isPostOrderTraversal());
+ }
+
+ public void testResetDoesNotAffectPostOrder() throws Exception {
+ final TreeWalk tw = new TreeWalk(db);
+ tw.setPostOrderTraversal(true);
+ assertTrue(tw.isPostOrderTraversal());
+ tw.reset();
+ assertTrue(tw.isPostOrderTraversal());
+
+ tw.setPostOrderTraversal(false);
+ assertFalse(tw.isPostOrderTraversal());
+ tw.reset();
+ assertFalse(tw.isPostOrderTraversal());
+ }
+
+ public void testNoPostOrder() throws Exception {
+ final DirCache tree = DirCache.read(db);
+ {
+ final DirCacheBuilder b = tree.builder();
+
+ b.add(makeFile("a"));
+ b.add(makeFile("b/c"));
+ b.add(makeFile("b/d"));
+ b.add(makeFile("q"));
+
+ b.finish();
+ assertEquals(4, tree.getEntryCount());
+ }
+
+ final TreeWalk tw = new TreeWalk(db);
+ tw.reset();
+ tw.setPostOrderTraversal(false);
+ tw.addTree(new DirCacheIterator(tree));
+
+ assertModes("a", REGULAR_FILE, tw);
+ assertModes("b", TREE, tw);
+ assertTrue(tw.isSubtree());
+ assertFalse(tw.isPostChildren());
+ tw.enterSubtree();
+ assertModes("b/c", REGULAR_FILE, tw);
+ assertModes("b/d", REGULAR_FILE, tw);
+ assertModes("q", REGULAR_FILE, tw);
+ }
+
+ public void testWithPostOrder_EnterSubtree() throws Exception {
+ final DirCache tree = DirCache.read(db);
+ {
+ final DirCacheBuilder b = tree.builder();
+
+ b.add(makeFile("a"));
+ b.add(makeFile("b/c"));
+ b.add(makeFile("b/d"));
+ b.add(makeFile("q"));
+
+ b.finish();
+ assertEquals(4, tree.getEntryCount());
+ }
+
+ final TreeWalk tw = new TreeWalk(db);
+ tw.reset();
+ tw.setPostOrderTraversal(true);
+ tw.addTree(new DirCacheIterator(tree));
+
+ assertModes("a", REGULAR_FILE, tw);
+
+ assertModes("b", TREE, tw);
+ assertTrue(tw.isSubtree());
+ assertFalse(tw.isPostChildren());
+ tw.enterSubtree();
+ assertModes("b/c", REGULAR_FILE, tw);
+ assertModes("b/d", REGULAR_FILE, tw);
+
+ assertModes("b", TREE, tw);
+ assertTrue(tw.isSubtree());
+ assertTrue(tw.isPostChildren());
+
+ assertModes("q", REGULAR_FILE, tw);
+ }
+
+ public void testWithPostOrder_NoEnterSubtree() throws Exception {
+ final DirCache tree = DirCache.read(db);
+ {
+ final DirCacheBuilder b = tree.builder();
+
+ b.add(makeFile("a"));
+ b.add(makeFile("b/c"));
+ b.add(makeFile("b/d"));
+ b.add(makeFile("q"));
+
+ b.finish();
+ assertEquals(4, tree.getEntryCount());
+ }
+
+ final TreeWalk tw = new TreeWalk(db);
+ tw.reset();
+ tw.setPostOrderTraversal(true);
+ tw.addTree(new DirCacheIterator(tree));
+
+ assertModes("a", REGULAR_FILE, tw);
+
+ assertModes("b", TREE, tw);
+ assertTrue(tw.isSubtree());
+ assertFalse(tw.isPostChildren());
+
+ assertModes("q", REGULAR_FILE, tw);
+ }
+
+ private DirCacheEntry makeFile(final String path) throws Exception {
+ final byte[] pathBytes = Constants.encode(path);
+ final DirCacheEntry ent = new DirCacheEntry(path);
+ ent.setFileMode(REGULAR_FILE);
+ ent.setObjectId(new ObjectWriter(db).computeBlobSha1(pathBytes.length,
+ new ByteArrayInputStream(pathBytes)));
+ return ent;
+ }
+
+ private static void assertModes(final String path, final FileMode mode0,
+ final TreeWalk tw) throws Exception {
+ assertTrue("has " + path, tw.next());
+ assertEquals(path, tw.getPathString());
+ assertEquals(mode0, tw.getFileMode(0));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkBasicDiffTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkBasicDiffTest.java
new file mode 100644
index 0000000000..581683e34f
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkBasicDiffTest.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.treewalk;
+
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectWriter;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+import org.eclipse.jgit.lib.Tree;
+import org.eclipse.jgit.treewalk.filter.TreeFilter;
+
+public class TreeWalkBasicDiffTest extends RepositoryTestCase {
+ public void testMissingSubtree_DetectFileAdded_FileModified()
+ throws Exception {
+ final ObjectWriter ow = new ObjectWriter(db);
+ final ObjectId aFileId = ow.writeBlob("a".getBytes());
+ final ObjectId bFileId = ow.writeBlob("b".getBytes());
+ final ObjectId cFileId1 = ow.writeBlob("c-1".getBytes());
+ final ObjectId cFileId2 = ow.writeBlob("c-2".getBytes());
+
+ // Create sub-a/empty, sub-c/empty = hello.
+ final ObjectId oldTree;
+ {
+ final Tree root = new Tree(db);
+ {
+ final Tree subA = root.addTree("sub-a");
+ subA.addFile("empty").setId(aFileId);
+ subA.setId(ow.writeTree(subA));
+ }
+ {
+ final Tree subC = root.addTree("sub-c");
+ subC.addFile("empty").setId(cFileId1);
+ subC.setId(ow.writeTree(subC));
+ }
+ oldTree = ow.writeTree(root);
+ }
+
+ // Create sub-a/empty, sub-b/empty, sub-c/empty.
+ final ObjectId newTree;
+ {
+ final Tree root = new Tree(db);
+ {
+ final Tree subA = root.addTree("sub-a");
+ subA.addFile("empty").setId(aFileId);
+ subA.setId(ow.writeTree(subA));
+ }
+ {
+ final Tree subB = root.addTree("sub-b");
+ subB.addFile("empty").setId(bFileId);
+ subB.setId(ow.writeTree(subB));
+ }
+ {
+ final Tree subC = root.addTree("sub-c");
+ subC.addFile("empty").setId(cFileId2);
+ subC.setId(ow.writeTree(subC));
+ }
+ newTree = ow.writeTree(root);
+ }
+
+ final TreeWalk tw = new TreeWalk(db);
+ tw.reset(new ObjectId[] { oldTree, newTree });
+ tw.setRecursive(true);
+ tw.setFilter(TreeFilter.ANY_DIFF);
+
+ assertTrue(tw.next());
+ assertEquals("sub-b/empty", tw.getPathString());
+ assertEquals(FileMode.MISSING, tw.getFileMode(0));
+ assertEquals(FileMode.REGULAR_FILE, tw.getFileMode(1));
+ assertEquals(ObjectId.zeroId(), tw.getObjectId(0));
+ assertEquals(bFileId, tw.getObjectId(1));
+
+ assertTrue(tw.next());
+ assertEquals("sub-c/empty", tw.getPathString());
+ assertEquals(FileMode.REGULAR_FILE, tw.getFileMode(0));
+ assertEquals(FileMode.REGULAR_FILE, tw.getFileMode(1));
+ assertEquals(cFileId1, tw.getObjectId(0));
+ assertEquals(cFileId2, tw.getObjectId(1));
+
+ assertFalse(tw.next());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/AlwaysCloneTreeFilter.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/AlwaysCloneTreeFilter.java
new file mode 100644
index 0000000000..8e2cca44ae
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/AlwaysCloneTreeFilter.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.treewalk.filter;
+
+import org.eclipse.jgit.treewalk.TreeWalk;
+
+class AlwaysCloneTreeFilter extends TreeFilter {
+ @Override
+ public TreeFilter clone() {
+ return new AlwaysCloneTreeFilter();
+ }
+
+ @Override
+ public boolean include(final TreeWalk walker) {
+ return false;
+ }
+
+ @Override
+ public boolean shouldBeRecursive() {
+ return false;
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/NotTreeFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/NotTreeFilterTest.java
new file mode 100644
index 0000000000..7c7ab3e6ae
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/NotTreeFilterTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.treewalk.filter;
+
+import org.eclipse.jgit.lib.RepositoryTestCase;
+import org.eclipse.jgit.treewalk.TreeWalk;
+
+public class NotTreeFilterTest extends RepositoryTestCase {
+ public void testWrap() throws Exception {
+ final TreeWalk tw = new TreeWalk(db);
+ final TreeFilter a = TreeFilter.ALL;
+ final TreeFilter n = NotTreeFilter.create(a);
+ assertNotNull(n);
+ assertTrue(a.include(tw));
+ assertFalse(n.include(tw));
+ }
+
+ public void testNegateIsUnwrap() throws Exception {
+ final TreeFilter a = PathFilter.create("a/b");
+ final TreeFilter n = NotTreeFilter.create(a);
+ assertSame(a, n.negate());
+ }
+
+ public void testShouldBeRecursive_ALL() throws Exception {
+ final TreeFilter a = TreeFilter.ALL;
+ final TreeFilter n = NotTreeFilter.create(a);
+ assertEquals(a.shouldBeRecursive(), n.shouldBeRecursive());
+ }
+
+ public void testShouldBeRecursive_PathFilter() throws Exception {
+ final TreeFilter a = PathFilter.create("a/b");
+ assertTrue(a.shouldBeRecursive());
+ final TreeFilter n = NotTreeFilter.create(a);
+ assertTrue(n.shouldBeRecursive());
+ }
+
+ public void testCloneIsDeepClone() throws Exception {
+ final TreeFilter a = new AlwaysCloneTreeFilter();
+ assertNotSame(a, a.clone());
+ final TreeFilter n = NotTreeFilter.create(a);
+ assertNotSame(n, n.clone());
+ }
+
+ public void testCloneIsSparseWhenPossible() throws Exception {
+ final TreeFilter a = TreeFilter.ALL;
+ assertSame(a, a.clone());
+ final TreeFilter n = NotTreeFilter.create(a);
+ assertSame(n, n.clone());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathSuffixFilterTestCase.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathSuffixFilterTestCase.java
new file mode 100644
index 0000000000..1aaefc415f
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/PathSuffixFilterTestCase.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.treewalk.filter;
+
+import java.io.IOException;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.eclipse.jgit.dircache.DirCache;
+import org.eclipse.jgit.dircache.DirCacheBuilder;
+import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.lib.FileMode;
+import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectWriter;
+import org.eclipse.jgit.lib.RepositoryTestCase;
+import org.eclipse.jgit.treewalk.TreeWalk;
+
+public class PathSuffixFilterTestCase extends RepositoryTestCase {
+
+ public void testNonRecursiveFiltering() throws IOException {
+ final ObjectWriter ow = new ObjectWriter(db);
+ final ObjectId aSth = ow.writeBlob("a.sth".getBytes());
+ final ObjectId aTxt = ow.writeBlob("a.txt".getBytes());
+ final DirCache dc = DirCache.read(db);
+ final DirCacheBuilder builder = dc.builder();
+ final DirCacheEntry aSthEntry = new DirCacheEntry("a.sth");
+ aSthEntry.setFileMode(FileMode.REGULAR_FILE);
+ aSthEntry.setObjectId(aSth);
+ final DirCacheEntry aTxtEntry = new DirCacheEntry("a.txt");
+ aTxtEntry.setFileMode(FileMode.REGULAR_FILE);
+ aTxtEntry.setObjectId(aTxt);
+ builder.add(aSthEntry);
+ builder.add(aTxtEntry);
+ builder.finish();
+ final ObjectId treeId = dc.writeTree(ow);
+
+
+ final TreeWalk tw = new TreeWalk(db);
+ tw.setFilter(PathSuffixFilter.create(".txt"));
+ tw.addTree(treeId);
+
+ List<String> paths = new LinkedList<String>();
+ while (tw.next()) {
+ paths.add(tw.getPathString());
+ }
+
+ List<String> expected = new LinkedList<String>();
+ expected.add("a.txt");
+
+ assertEquals(expected, paths);
+ }
+
+ public void testRecursiveFiltering() throws IOException {
+ final ObjectWriter ow = new ObjectWriter(db);
+ final ObjectId aSth = ow.writeBlob("a.sth".getBytes());
+ final ObjectId aTxt = ow.writeBlob("a.txt".getBytes());
+ final ObjectId bSth = ow.writeBlob("b.sth".getBytes());
+ final ObjectId bTxt = ow.writeBlob("b.txt".getBytes());
+ final DirCache dc = DirCache.read(db);
+ final DirCacheBuilder builder = dc.builder();
+ final DirCacheEntry aSthEntry = new DirCacheEntry("a.sth");
+ aSthEntry.setFileMode(FileMode.REGULAR_FILE);
+ aSthEntry.setObjectId(aSth);
+ final DirCacheEntry aTxtEntry = new DirCacheEntry("a.txt");
+ aTxtEntry.setFileMode(FileMode.REGULAR_FILE);
+ aTxtEntry.setObjectId(aTxt);
+ builder.add(aSthEntry);
+ builder.add(aTxtEntry);
+ final DirCacheEntry bSthEntry = new DirCacheEntry("sub/b.sth");
+ bSthEntry.setFileMode(FileMode.REGULAR_FILE);
+ bSthEntry.setObjectId(bSth);
+ final DirCacheEntry bTxtEntry = new DirCacheEntry("sub/b.txt");
+ bTxtEntry.setFileMode(FileMode.REGULAR_FILE);
+ bTxtEntry.setObjectId(bTxt);
+ builder.add(bSthEntry);
+ builder.add(bTxtEntry);
+ builder.finish();
+ final ObjectId treeId = dc.writeTree(ow);
+
+
+ final TreeWalk tw = new TreeWalk(db);
+ tw.setRecursive(true);
+ tw.setFilter(PathSuffixFilter.create(".txt"));
+ tw.addTree(treeId);
+
+ List<String> paths = new LinkedList<String>();
+ while (tw.next()) {
+ paths.add(tw.getPathString());
+ }
+
+ List<String> expected = new LinkedList<String>();
+ expected.add("a.txt");
+ expected.add("sub/b.txt");
+
+ assertEquals(expected, paths);
+ }
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/TreeFilterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/TreeFilterTest.java
new file mode 100644
index 0000000000..12326eade2
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/filter/TreeFilterTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.treewalk.filter;
+
+import org.eclipse.jgit.lib.RepositoryTestCase;
+import org.eclipse.jgit.treewalk.TreeWalk;
+
+public class TreeFilterTest extends RepositoryTestCase {
+ public void testALL_IncludesAnything() throws Exception {
+ final TreeWalk tw = new TreeWalk(db);
+ assertTrue(TreeFilter.ALL.include(tw));
+ }
+
+ public void testALL_ShouldNotBeRecursive() throws Exception {
+ assertFalse(TreeFilter.ALL.shouldBeRecursive());
+ }
+
+ public void testALL_IdentityClone() throws Exception {
+ assertSame(TreeFilter.ALL, TreeFilter.ALL.clone());
+ }
+
+ public void testNotALL_IncludesNothing() throws Exception {
+ final TreeWalk tw = new TreeWalk(db);
+ assertFalse(TreeFilter.ALL.negate().include(tw));
+ }
+
+ public void testANY_DIFF_IncludesSingleTreeCase() throws Exception {
+ final TreeWalk tw = new TreeWalk(db);
+ assertTrue(TreeFilter.ANY_DIFF.include(tw));
+ }
+
+ public void testANY_DIFF_ShouldNotBeRecursive() throws Exception {
+ assertFalse(TreeFilter.ANY_DIFF.shouldBeRecursive());
+ }
+
+ public void testANY_DIFF_IdentityClone() throws Exception {
+ assertSame(TreeFilter.ANY_DIFF, TreeFilter.ANY_DIFF.clone());
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/IntListTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/IntListTest.java
new file mode 100644
index 0000000000..ecabeeea5b
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/IntListTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util;
+
+import junit.framework.TestCase;
+
+public class IntListTest extends TestCase {
+ public void testEmpty_DefaultCapacity() {
+ final IntList i = new IntList();
+ assertEquals(0, i.size());
+ try {
+ i.get(0);
+ fail("Accepted 0 index on empty list");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testEmpty_SpecificCapacity() {
+ final IntList i = new IntList(5);
+ assertEquals(0, i.size());
+ try {
+ i.get(0);
+ fail("Accepted 0 index on empty list");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testAdd_SmallGroup() {
+ final IntList i = new IntList();
+ final int n = 5;
+ for (int v = 0; v < n; v++)
+ i.add(10 + v);
+ assertEquals(n, i.size());
+
+ for (int v = 0; v < n; v++)
+ assertEquals(10 + v, i.get(v));
+ try {
+ i.get(n);
+ fail("Accepted out of bound index on list");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testAdd_ZeroCapacity() {
+ final IntList i = new IntList(0);
+ assertEquals(0, i.size());
+ i.add(1);
+ assertEquals(1, i.get(0));
+ }
+
+ public void testAdd_LargeGroup() {
+ final IntList i = new IntList();
+ final int n = 500;
+ for (int v = 0; v < n; v++)
+ i.add(10 + v);
+ assertEquals(n, i.size());
+
+ for (int v = 0; v < n; v++)
+ assertEquals(10 + v, i.get(v));
+ try {
+ i.get(n);
+ fail("Accepted out of bound index on list");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testFillTo0() {
+ final IntList i = new IntList();
+ i.fillTo(0, Integer.MIN_VALUE);
+ assertEquals(0, i.size());
+ }
+
+ public void testFillTo1() {
+ final IntList i = new IntList();
+ i.fillTo(1, Integer.MIN_VALUE);
+ assertEquals(1, i.size());
+ i.add(0);
+ assertEquals(Integer.MIN_VALUE, i.get(0));
+ assertEquals(0, i.get(1));
+ }
+
+ public void testFillTo100() {
+ final IntList i = new IntList();
+ i.fillTo(100, Integer.MIN_VALUE);
+ assertEquals(100, i.size());
+ i.add(3);
+ assertEquals(Integer.MIN_VALUE, i.get(99));
+ assertEquals(3, i.get(100));
+ }
+
+ public void testClear() {
+ final IntList i = new IntList();
+ final int n = 5;
+ for (int v = 0; v < n; v++)
+ i.add(10 + v);
+ assertEquals(n, i.size());
+
+ i.clear();
+ assertEquals(0, i.size());
+ try {
+ i.get(0);
+ fail("Accepted 0 index on empty list");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ assertTrue(true);
+ }
+ }
+
+ public void testToString() {
+ final IntList i = new IntList();
+ i.add(1);
+ assertEquals("[1]", i.toString());
+ i.add(13);
+ i.add(5);
+ assertEquals("[1, 13, 5]", i.toString());
+ }
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/JGitTestUtil.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/JGitTestUtil.java
new file mode 100644
index 0000000000..37418417d3
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/JGitTestUtil.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2008-2009, Google Inc.
+ * Copyright (C) 2008, Imran M Yousuf <imyousuf@smartitengineering.com>
+ * Copyright (C) 2008, Jonas Fonseca <fonseca@diku.dk>
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util;
+
+import java.io.File;
+import java.net.URISyntaxException;
+import java.net.URL;
+
+public abstract class JGitTestUtil {
+ public static final String CLASSPATH_TO_RESOURCES = "org/eclipse/jgit/test/resources/";
+
+ private JGitTestUtil() {
+ throw new UnsupportedOperationException();
+ }
+
+ public static File getTestResourceFile(final String fileName) {
+ if (fileName == null || fileName.length() <= 0) {
+ return null;
+ }
+ final URL url = cl().getResource(CLASSPATH_TO_RESOURCES + fileName);
+ if (url == null) {
+ // If URL is null then try to load it as it was being
+ // loaded previously
+ return new File("tst", fileName);
+ }
+ try {
+ return new File(url.toURI());
+ } catch(URISyntaxException e) {
+ return new File(url.getPath());
+ }
+ }
+
+ private static ClassLoader cl() {
+ return JGitTestUtil.class.getClassLoader();
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/NBTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/NBTest.java
new file mode 100644
index 0000000000..21fea9e9d5
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/NBTest.java
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util;
+
+import junit.framework.TestCase;
+
+public class NBTest extends TestCase {
+ public void testCompareUInt32() {
+ assertTrue(NB.compareUInt32(0, 0) == 0);
+ assertTrue(NB.compareUInt32(1, 0) > 0);
+ assertTrue(NB.compareUInt32(0, 1) < 0);
+ assertTrue(NB.compareUInt32(-1, 0) > 0);
+ assertTrue(NB.compareUInt32(0, -1) < 0);
+ assertTrue(NB.compareUInt32(-1, 1) > 0);
+ assertTrue(NB.compareUInt32(1, -1) < 0);
+ }
+
+ public void testDecodeUInt16() {
+ assertEquals(0, NB.decodeUInt16(b(0, 0), 0));
+ assertEquals(0, NB.decodeUInt16(padb(3, 0, 0), 3));
+
+ assertEquals(3, NB.decodeUInt16(b(0, 3), 0));
+ assertEquals(3, NB.decodeUInt16(padb(3, 0, 3), 3));
+
+ assertEquals(0xde03, NB.decodeUInt16(b(0xde, 3), 0));
+ assertEquals(0xde03, NB.decodeUInt16(padb(3, 0xde, 3), 3));
+
+ assertEquals(0x03de, NB.decodeUInt16(b(3, 0xde), 0));
+ assertEquals(0x03de, NB.decodeUInt16(padb(3, 3, 0xde), 3));
+
+ assertEquals(0xffff, NB.decodeUInt16(b(0xff, 0xff), 0));
+ assertEquals(0xffff, NB.decodeUInt16(padb(3, 0xff, 0xff), 3));
+ }
+
+ public void testDecodeInt32() {
+ assertEquals(0, NB.decodeInt32(b(0, 0, 0, 0), 0));
+ assertEquals(0, NB.decodeInt32(padb(3, 0, 0, 0, 0), 3));
+
+ assertEquals(3, NB.decodeInt32(b(0, 0, 0, 3), 0));
+ assertEquals(3, NB.decodeInt32(padb(3, 0, 0, 0, 3), 3));
+
+ assertEquals(0xdeadbeef, NB.decodeInt32(b(0xde, 0xad, 0xbe, 0xef), 0));
+ assertEquals(0xdeadbeef, NB.decodeInt32(
+ padb(3, 0xde, 0xad, 0xbe, 0xef), 3));
+
+ assertEquals(0x0310adef, NB.decodeInt32(b(0x03, 0x10, 0xad, 0xef), 0));
+ assertEquals(0x0310adef, NB.decodeInt32(
+ padb(3, 0x03, 0x10, 0xad, 0xef), 3));
+
+ assertEquals(0xffffffff, NB.decodeInt32(b(0xff, 0xff, 0xff, 0xff), 0));
+ assertEquals(0xffffffff, NB.decodeInt32(
+ padb(3, 0xff, 0xff, 0xff, 0xff), 3));
+ }
+
+ public void testDecodeUInt32() {
+ assertEquals(0L, NB.decodeUInt32(b(0, 0, 0, 0), 0));
+ assertEquals(0L, NB.decodeUInt32(padb(3, 0, 0, 0, 0), 3));
+
+ assertEquals(3L, NB.decodeUInt32(b(0, 0, 0, 3), 0));
+ assertEquals(3L, NB.decodeUInt32(padb(3, 0, 0, 0, 3), 3));
+
+ assertEquals(0xdeadbeefL, NB.decodeUInt32(b(0xde, 0xad, 0xbe, 0xef), 0));
+ assertEquals(0xdeadbeefL, NB.decodeUInt32(padb(3, 0xde, 0xad, 0xbe,
+ 0xef), 3));
+
+ assertEquals(0x0310adefL, NB.decodeUInt32(b(0x03, 0x10, 0xad, 0xef), 0));
+ assertEquals(0x0310adefL, NB.decodeUInt32(padb(3, 0x03, 0x10, 0xad,
+ 0xef), 3));
+
+ assertEquals(0xffffffffL, NB.decodeUInt32(b(0xff, 0xff, 0xff, 0xff), 0));
+ assertEquals(0xffffffffL, NB.decodeUInt32(padb(3, 0xff, 0xff, 0xff,
+ 0xff), 3));
+ }
+
+ public void testDecodeUInt64() {
+ assertEquals(0L, NB.decodeUInt64(b(0, 0, 0, 0, 0, 0, 0, 0), 0));
+ assertEquals(0L, NB.decodeUInt64(padb(3, 0, 0, 0, 0, 0, 0, 0, 0), 3));
+
+ assertEquals(3L, NB.decodeUInt64(b(0, 0, 0, 0, 0, 0, 0, 3), 0));
+ assertEquals(3L, NB.decodeUInt64(padb(3, 0, 0, 0, 0, 0, 0, 0, 3), 3));
+
+ assertEquals(0xdeadbeefL, NB.decodeUInt64(b(0, 0, 0, 0, 0xde, 0xad,
+ 0xbe, 0xef), 0));
+ assertEquals(0xdeadbeefL, NB.decodeUInt64(padb(3, 0, 0, 0, 0, 0xde,
+ 0xad, 0xbe, 0xef), 3));
+
+ assertEquals(0x0310adefL, NB.decodeUInt64(b(0, 0, 0, 0, 0x03, 0x10,
+ 0xad, 0xef), 0));
+ assertEquals(0x0310adefL, NB.decodeUInt64(padb(3, 0, 0, 0, 0, 0x03,
+ 0x10, 0xad, 0xef), 3));
+
+ assertEquals(0xc0ffee78deadbeefL, NB.decodeUInt64(b(0xc0, 0xff, 0xee,
+ 0x78, 0xde, 0xad, 0xbe, 0xef), 0));
+ assertEquals(0xc0ffee78deadbeefL, NB.decodeUInt64(padb(3, 0xc0, 0xff,
+ 0xee, 0x78, 0xde, 0xad, 0xbe, 0xef), 3));
+
+ assertEquals(0x00000000ffffffffL, NB.decodeUInt64(b(0, 0, 0, 0, 0xff,
+ 0xff, 0xff, 0xff), 0));
+ assertEquals(0x00000000ffffffffL, NB.decodeUInt64(padb(3, 0, 0, 0, 0,
+ 0xff, 0xff, 0xff, 0xff), 3));
+ assertEquals(0xffffffffffffffffL, NB.decodeUInt64(b(0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff), 0));
+ assertEquals(0xffffffffffffffffL, NB.decodeUInt64(padb(3, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff), 3));
+ }
+
+ public void testEncodeInt16() {
+ final byte[] out = new byte[16];
+
+ prepareOutput(out);
+ NB.encodeInt16(out, 0, 0);
+ assertOutput(b(0, 0), out, 0);
+
+ prepareOutput(out);
+ NB.encodeInt16(out, 3, 0);
+ assertOutput(b(0, 0), out, 3);
+
+ prepareOutput(out);
+ NB.encodeInt16(out, 0, 3);
+ assertOutput(b(0, 3), out, 0);
+
+ prepareOutput(out);
+ NB.encodeInt16(out, 3, 3);
+ assertOutput(b(0, 3), out, 3);
+
+ prepareOutput(out);
+ NB.encodeInt16(out, 0, 0xdeac);
+ assertOutput(b(0xde, 0xac), out, 0);
+
+ prepareOutput(out);
+ NB.encodeInt16(out, 3, 0xdeac);
+ assertOutput(b(0xde, 0xac), out, 3);
+
+ prepareOutput(out);
+ NB.encodeInt16(out, 3, -1);
+ assertOutput(b(0xff, 0xff), out, 3);
+ }
+
+ public void testEncodeInt32() {
+ final byte[] out = new byte[16];
+
+ prepareOutput(out);
+ NB.encodeInt32(out, 0, 0);
+ assertOutput(b(0, 0, 0, 0), out, 0);
+
+ prepareOutput(out);
+ NB.encodeInt32(out, 3, 0);
+ assertOutput(b(0, 0, 0, 0), out, 3);
+
+ prepareOutput(out);
+ NB.encodeInt32(out, 0, 3);
+ assertOutput(b(0, 0, 0, 3), out, 0);
+
+ prepareOutput(out);
+ NB.encodeInt32(out, 3, 3);
+ assertOutput(b(0, 0, 0, 3), out, 3);
+
+ prepareOutput(out);
+ NB.encodeInt32(out, 0, 0xdeac);
+ assertOutput(b(0, 0, 0xde, 0xac), out, 0);
+
+ prepareOutput(out);
+ NB.encodeInt32(out, 3, 0xdeac);
+ assertOutput(b(0, 0, 0xde, 0xac), out, 3);
+
+ prepareOutput(out);
+ NB.encodeInt32(out, 0, 0xdeac9853);
+ assertOutput(b(0xde, 0xac, 0x98, 0x53), out, 0);
+
+ prepareOutput(out);
+ NB.encodeInt32(out, 3, 0xdeac9853);
+ assertOutput(b(0xde, 0xac, 0x98, 0x53), out, 3);
+
+ prepareOutput(out);
+ NB.encodeInt32(out, 3, -1);
+ assertOutput(b(0xff, 0xff, 0xff, 0xff), out, 3);
+ }
+
+ public void testEncodeInt64() {
+ final byte[] out = new byte[16];
+
+ prepareOutput(out);
+ NB.encodeInt64(out, 0, 0L);
+ assertOutput(b(0, 0, 0, 0, 0, 0, 0, 0), out, 0);
+
+ prepareOutput(out);
+ NB.encodeInt64(out, 3, 0L);
+ assertOutput(b(0, 0, 0, 0, 0, 0, 0, 0), out, 3);
+
+ prepareOutput(out);
+ NB.encodeInt64(out, 0, 3L);
+ assertOutput(b(0, 0, 0, 0, 0, 0, 0, 3), out, 0);
+
+ prepareOutput(out);
+ NB.encodeInt64(out, 3, 3L);
+ assertOutput(b(0, 0, 0, 0, 0, 0, 0, 3), out, 3);
+
+ prepareOutput(out);
+ NB.encodeInt64(out, 0, 0xdeacL);
+ assertOutput(b(0, 0, 0, 0, 0, 0, 0xde, 0xac), out, 0);
+
+ prepareOutput(out);
+ NB.encodeInt64(out, 3, 0xdeacL);
+ assertOutput(b(0, 0, 0, 0, 0, 0, 0xde, 0xac), out, 3);
+
+ prepareOutput(out);
+ NB.encodeInt64(out, 0, 0xdeac9853L);
+ assertOutput(b(0, 0, 0, 0, 0xde, 0xac, 0x98, 0x53), out, 0);
+
+ prepareOutput(out);
+ NB.encodeInt64(out, 3, 0xdeac9853L);
+ assertOutput(b(0, 0, 0, 0, 0xde, 0xac, 0x98, 0x53), out, 3);
+
+ prepareOutput(out);
+ NB.encodeInt64(out, 0, 0xac431242deac9853L);
+ assertOutput(b(0xac, 0x43, 0x12, 0x42, 0xde, 0xac, 0x98, 0x53), out, 0);
+
+ prepareOutput(out);
+ NB.encodeInt64(out, 3, 0xac431242deac9853L);
+ assertOutput(b(0xac, 0x43, 0x12, 0x42, 0xde, 0xac, 0x98, 0x53), out, 3);
+
+ prepareOutput(out);
+ NB.encodeInt64(out, 3, -1L);
+ assertOutput(b(0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff), out, 3);
+ }
+
+ private static void prepareOutput(final byte[] buf) {
+ for (int i = 0; i < buf.length; i++)
+ buf[i] = (byte) (0x77 + i);
+ }
+
+ private static void assertOutput(final byte[] expect, final byte[] buf,
+ final int offset) {
+ for (int i = 0; i < offset; i++)
+ assertEquals((byte) (0x77 + i), buf[i]);
+ for (int i = 0; i < expect.length; i++)
+ assertEquals(expect[i], buf[offset + i]);
+ for (int i = offset + expect.length; i < buf.length; i++)
+ assertEquals((byte) (0x77 + i), buf[i]);
+ }
+
+ private static byte[] b(final int a, final int b) {
+ return new byte[] { (byte) a, (byte) b };
+ }
+
+ private static byte[] padb(final int len, final int a, final int b) {
+ final byte[] r = new byte[len + 2];
+ for (int i = 0; i < len; i++)
+ r[i] = (byte) 0xaf;
+ r[len] = (byte) a;
+ r[len + 1] = (byte) b;
+ return r;
+ }
+
+ private static byte[] b(final int a, final int b, final int c, final int d) {
+ return new byte[] { (byte) a, (byte) b, (byte) c, (byte) d };
+ }
+
+ private static byte[] padb(final int len, final int a, final int b,
+ final int c, final int d) {
+ final byte[] r = new byte[len + 4];
+ for (int i = 0; i < len; i++)
+ r[i] = (byte) 0xaf;
+ r[len] = (byte) a;
+ r[len + 1] = (byte) b;
+ r[len + 2] = (byte) c;
+ r[len + 3] = (byte) d;
+ return r;
+ }
+
+ private static byte[] b(final int a, final int b, final int c, final int d,
+ final int e, final int f, final int g, final int h) {
+ return new byte[] { (byte) a, (byte) b, (byte) c, (byte) d, (byte) e,
+ (byte) f, (byte) g, (byte) h };
+ }
+
+ private static byte[] padb(final int len, final int a, final int b,
+ final int c, final int d, final int e, final int f, final int g,
+ final int h) {
+ final byte[] r = new byte[len + 8];
+ for (int i = 0; i < len; i++)
+ r[i] = (byte) 0xaf;
+ r[len] = (byte) a;
+ r[len + 1] = (byte) b;
+ r[len + 2] = (byte) c;
+ r[len + 3] = (byte) d;
+ r[len + 4] = (byte) e;
+ r[len + 5] = (byte) f;
+ r[len + 6] = (byte) g;
+ r[len + 7] = (byte) h;
+ return r;
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringBourneStyleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringBourneStyleTest.java
new file mode 100644
index 0000000000..b9a721a464
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringBourneStyleTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util;
+
+import static org.eclipse.jgit.util.QuotedString.BOURNE;
+import junit.framework.TestCase;
+
+import org.eclipse.jgit.lib.Constants;
+
+public class QuotedStringBourneStyleTest extends TestCase {
+ private static void assertQuote(final String in, final String exp) {
+ final String r = BOURNE.quote(in);
+ assertNotSame(in, r);
+ assertFalse(in.equals(r));
+ assertEquals('\'' + exp + '\'', r);
+ }
+
+ private static void assertDequote(final String exp, final String in) {
+ final byte[] b = Constants.encode('\'' + in + '\'');
+ final String r = BOURNE.dequote(b, 0, b.length);
+ assertEquals(exp, r);
+ }
+
+ public void testQuote_Empty() {
+ assertEquals("''", BOURNE.quote(""));
+ }
+
+ public void testDequote_Empty1() {
+ assertEquals("", BOURNE.dequote(new byte[0], 0, 0));
+ }
+
+ public void testDequote_Empty2() {
+ assertEquals("", BOURNE.dequote(new byte[] { '\'', '\'' }, 0, 2));
+ }
+
+ public void testDequote_SoleSq() {
+ assertEquals("", BOURNE.dequote(new byte[] { '\'' }, 0, 1));
+ }
+
+ public void testQuote_BareA() {
+ assertQuote("a", "a");
+ }
+
+ public void testDequote_BareA() {
+ final String in = "a";
+ final byte[] b = Constants.encode(in);
+ assertEquals(in, BOURNE.dequote(b, 0, b.length));
+ }
+
+ public void testDequote_BareABCZ_OnlyBC() {
+ final String in = "abcz";
+ final byte[] b = Constants.encode(in);
+ final int p = in.indexOf('b');
+ assertEquals("bc", BOURNE.dequote(b, p, p + 2));
+ }
+
+ public void testDequote_LoneBackslash() {
+ assertDequote("\\", "\\");
+ }
+
+ public void testQuote_NamedEscapes() {
+ assertQuote("'", "'\\''");
+ assertQuote("!", "'\\!'");
+
+ assertQuote("a'b", "a'\\''b");
+ assertQuote("a!b", "a'\\!'b");
+ }
+
+ public void testDequote_NamedEscapes() {
+ assertDequote("'", "'\\''");
+ assertDequote("!", "'\\!'");
+
+ assertDequote("a'b", "a'\\''b");
+ assertDequote("a!b", "a'\\!'b");
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringBourneUserPathStyleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringBourneUserPathStyleTest.java
new file mode 100644
index 0000000000..69201249c0
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringBourneUserPathStyleTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util;
+
+import static org.eclipse.jgit.util.QuotedString.BOURNE_USER_PATH;
+import junit.framework.TestCase;
+
+import org.eclipse.jgit.lib.Constants;
+
+public class QuotedStringBourneUserPathStyleTest extends TestCase {
+ private static void assertQuote(final String in, final String exp) {
+ final String r = BOURNE_USER_PATH.quote(in);
+ assertNotSame(in, r);
+ assertFalse(in.equals(r));
+ assertEquals('\'' + exp + '\'', r);
+ }
+
+ private static void assertDequote(final String exp, final String in) {
+ final byte[] b = Constants.encode('\'' + in + '\'');
+ final String r = BOURNE_USER_PATH.dequote(b, 0, b.length);
+ assertEquals(exp, r);
+ }
+
+ public void testQuote_Empty() {
+ assertEquals("''", BOURNE_USER_PATH.quote(""));
+ }
+
+ public void testDequote_Empty1() {
+ assertEquals("", BOURNE_USER_PATH.dequote(new byte[0], 0, 0));
+ }
+
+ public void testDequote_Empty2() {
+ assertEquals("", BOURNE_USER_PATH.dequote(new byte[] { '\'', '\'' }, 0,
+ 2));
+ }
+
+ public void testDequote_SoleSq() {
+ assertEquals("", BOURNE_USER_PATH.dequote(new byte[] { '\'' }, 0, 1));
+ }
+
+ public void testQuote_BareA() {
+ assertQuote("a", "a");
+ }
+
+ public void testDequote_BareA() {
+ final String in = "a";
+ final byte[] b = Constants.encode(in);
+ assertEquals(in, BOURNE_USER_PATH.dequote(b, 0, b.length));
+ }
+
+ public void testDequote_BareABCZ_OnlyBC() {
+ final String in = "abcz";
+ final byte[] b = Constants.encode(in);
+ final int p = in.indexOf('b');
+ assertEquals("bc", BOURNE_USER_PATH.dequote(b, p, p + 2));
+ }
+
+ public void testDequote_LoneBackslash() {
+ assertDequote("\\", "\\");
+ }
+
+ public void testQuote_NamedEscapes() {
+ assertQuote("'", "'\\''");
+ assertQuote("!", "'\\!'");
+
+ assertQuote("a'b", "a'\\''b");
+ assertQuote("a!b", "a'\\!'b");
+ }
+
+ public void testDequote_NamedEscapes() {
+ assertDequote("'", "'\\''");
+ assertDequote("!", "'\\!'");
+
+ assertDequote("a'b", "a'\\''b");
+ assertDequote("a!b", "a'\\!'b");
+ }
+
+ public void testQuote_User() {
+ assertEquals("~foo/", BOURNE_USER_PATH.quote("~foo"));
+ assertEquals("~foo/", BOURNE_USER_PATH.quote("~foo/"));
+ assertEquals("~/", BOURNE_USER_PATH.quote("~/"));
+
+ assertEquals("~foo/'a'", BOURNE_USER_PATH.quote("~foo/a"));
+ assertEquals("~/'a'", BOURNE_USER_PATH.quote("~/a"));
+ }
+
+ public void testDequote_User() {
+ assertEquals("~foo", BOURNE_USER_PATH.dequote("~foo"));
+ assertEquals("~foo/", BOURNE_USER_PATH.dequote("~foo/"));
+ assertEquals("~/", BOURNE_USER_PATH.dequote("~/"));
+
+ assertEquals("~foo/a", BOURNE_USER_PATH.dequote("~foo/'a'"));
+ assertEquals("~/a", BOURNE_USER_PATH.dequote("~/'a'"));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringGitPathStyleTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringGitPathStyleTest.java
new file mode 100644
index 0000000000..4a161fa01c
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/QuotedStringGitPathStyleTest.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util;
+
+import static org.eclipse.jgit.util.QuotedString.GIT_PATH;
+
+import java.io.UnsupportedEncodingException;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jgit.lib.Constants;
+
+public class QuotedStringGitPathStyleTest extends TestCase {
+ private static void assertQuote(final String exp, final String in) {
+ final String r = GIT_PATH.quote(in);
+ assertNotSame(in, r);
+ assertFalse(in.equals(r));
+ assertEquals('"' + exp + '"', r);
+ }
+
+ private static void assertDequote(final String exp, final String in) {
+ final byte[] b;
+ try {
+ b = ('"' + in + '"').getBytes("ISO-8859-1");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ final String r = GIT_PATH.dequote(b, 0, b.length);
+ assertEquals(exp, r);
+ }
+
+ public void testQuote_Empty() {
+ assertEquals("\"\"", GIT_PATH.quote(""));
+ }
+
+ public void testDequote_Empty1() {
+ assertEquals("", GIT_PATH.dequote(new byte[0], 0, 0));
+ }
+
+ public void testDequote_Empty2() {
+ assertEquals("", GIT_PATH.dequote(new byte[] { '"', '"' }, 0, 2));
+ }
+
+ public void testDequote_SoleDq() {
+ assertEquals("\"", GIT_PATH.dequote(new byte[] { '"' }, 0, 1));
+ }
+
+ public void testQuote_BareA() {
+ final String in = "a";
+ assertSame(in, GIT_PATH.quote(in));
+ }
+
+ public void testDequote_BareA() {
+ final String in = "a";
+ final byte[] b = Constants.encode(in);
+ assertEquals(in, GIT_PATH.dequote(b, 0, b.length));
+ }
+
+ public void testDequote_BareABCZ_OnlyBC() {
+ final String in = "abcz";
+ final byte[] b = Constants.encode(in);
+ final int p = in.indexOf('b');
+ assertEquals("bc", GIT_PATH.dequote(b, p, p + 2));
+ }
+
+ public void testDequote_LoneBackslash() {
+ assertDequote("\\", "\\");
+ }
+
+ public void testQuote_NamedEscapes() {
+ assertQuote("\\a", "\u0007");
+ assertQuote("\\b", "\b");
+ assertQuote("\\f", "\f");
+ assertQuote("\\n", "\n");
+ assertQuote("\\r", "\r");
+ assertQuote("\\t", "\t");
+ assertQuote("\\v", "\u000B");
+ assertQuote("\\\\", "\\");
+ assertQuote("\\\"", "\"");
+ }
+
+ public void testDequote_NamedEscapes() {
+ assertDequote("\u0007", "\\a");
+ assertDequote("\b", "\\b");
+ assertDequote("\f", "\\f");
+ assertDequote("\n", "\\n");
+ assertDequote("\r", "\\r");
+ assertDequote("\t", "\\t");
+ assertDequote("\u000B", "\\v");
+ assertDequote("\\", "\\\\");
+ assertDequote("\"", "\\\"");
+ }
+
+ public void testDequote_OctalAll() {
+ for (int i = 0; i < 127; i++) {
+ assertDequote("" + (char) i, octalEscape(i));
+ }
+ for (int i = 128; i < 256; i++) {
+ int f = 0xC0 | (i >> 6);
+ int s = 0x80 | (i & 0x3f);
+ assertDequote("" + (char) i, octalEscape(f)+octalEscape(s));
+ }
+ }
+
+ private String octalEscape(int i) {
+ String s = Integer.toOctalString(i);
+ while (s.length() < 3) {
+ s = "0" + s;
+ }
+ return "\\"+s;
+ }
+
+ public void testQuote_OctalAll() {
+ assertQuote("\\001", "\1");
+ assertQuote("\\176", "~");
+ assertQuote("\\303\\277", "\u00ff"); // \u00ff in UTF-8
+ }
+
+ public void testDequote_UnknownEscapeQ() {
+ assertDequote("\\q", "\\q");
+ }
+
+ public void testDequote_FooTabBar() {
+ assertDequote("foo\tbar", "foo\\tbar");
+ }
+
+ public void testDequote_Latin1() {
+ assertDequote("\u00c5ngstr\u00f6m", "\\305ngstr\\366m"); // Latin1
+ }
+
+ public void testDequote_UTF8() {
+ assertDequote("\u00c5ngstr\u00f6m", "\\303\\205ngstr\\303\\266m");
+ }
+
+ public void testDequote_RawUTF8() {
+ assertDequote("\u00c5ngstr\u00f6m", "\303\205ngstr\303\266m");
+ }
+
+ public void testDequote_RawLatin1() {
+ assertDequote("\u00c5ngstr\u00f6m", "\305ngstr\366m");
+ }
+
+ public void testQuote_Ang() {
+ assertQuote("\\303\\205ngstr\\303\\266m", "\u00c5ngstr\u00f6m");
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_HexParseTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_HexParseTest.java
new file mode 100644
index 0000000000..a2c9e9dbd1
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_HexParseTest.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jgit.lib.Constants;
+
+public class RawParseUtils_HexParseTest extends TestCase {
+ public void testInt4_1() {
+ assertEquals(0, RawParseUtils.parseHexInt4((byte) '0'));
+ assertEquals(1, RawParseUtils.parseHexInt4((byte) '1'));
+ assertEquals(2, RawParseUtils.parseHexInt4((byte) '2'));
+ assertEquals(3, RawParseUtils.parseHexInt4((byte) '3'));
+ assertEquals(4, RawParseUtils.parseHexInt4((byte) '4'));
+ assertEquals(5, RawParseUtils.parseHexInt4((byte) '5'));
+ assertEquals(6, RawParseUtils.parseHexInt4((byte) '6'));
+ assertEquals(7, RawParseUtils.parseHexInt4((byte) '7'));
+ assertEquals(8, RawParseUtils.parseHexInt4((byte) '8'));
+ assertEquals(9, RawParseUtils.parseHexInt4((byte) '9'));
+ assertEquals(10, RawParseUtils.parseHexInt4((byte) 'a'));
+ assertEquals(11, RawParseUtils.parseHexInt4((byte) 'b'));
+ assertEquals(12, RawParseUtils.parseHexInt4((byte) 'c'));
+ assertEquals(13, RawParseUtils.parseHexInt4((byte) 'd'));
+ assertEquals(14, RawParseUtils.parseHexInt4((byte) 'e'));
+ assertEquals(15, RawParseUtils.parseHexInt4((byte) 'f'));
+
+ assertEquals(10, RawParseUtils.parseHexInt4((byte) 'A'));
+ assertEquals(11, RawParseUtils.parseHexInt4((byte) 'B'));
+ assertEquals(12, RawParseUtils.parseHexInt4((byte) 'C'));
+ assertEquals(13, RawParseUtils.parseHexInt4((byte) 'D'));
+ assertEquals(14, RawParseUtils.parseHexInt4((byte) 'E'));
+ assertEquals(15, RawParseUtils.parseHexInt4((byte) 'F'));
+
+ assertNotHex('q');
+ assertNotHex(' ');
+ assertNotHex('.');
+ }
+
+ private static void assertNotHex(final char c) {
+ try {
+ RawParseUtils.parseHexInt4((byte) c);
+ fail("Incorrectly acccepted " + c);
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // pass
+ }
+ }
+
+ public void testInt16() {
+ assertEquals(0x0000, parse16("0000"));
+ assertEquals(0x0001, parse16("0001"));
+ assertEquals(0x1234, parse16("1234"));
+ assertEquals(0xdead, parse16("dead"));
+ assertEquals(0xBEEF, parse16("BEEF"));
+ assertEquals(0x4321, parse16("4321"));
+ assertEquals(0xffff, parse16("ffff"));
+
+ try {
+ parse16("noth");
+ fail("Incorrectly acccepted \"noth\"");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // pass
+ }
+
+ try {
+ parse16("01");
+ fail("Incorrectly acccepted \"01\"");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // pass
+ }
+
+ try {
+ parse16("000.");
+ fail("Incorrectly acccepted \"000.\"");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // pass
+ }
+ }
+
+ private static int parse16(final String str) {
+ return RawParseUtils.parseHexInt16(Constants.encodeASCII(str), 0);
+ }
+
+ public void testInt32() {
+ assertEquals(0x00000000, parse32("00000000"));
+ assertEquals(0x00000001, parse32("00000001"));
+ assertEquals(0xc0ffEE42, parse32("c0ffEE42"));
+ assertEquals(0xffffffff, parse32("ffffffff"));
+ assertEquals(-1, parse32("ffffffff"));
+
+ try {
+ parse32("noth");
+ fail("Incorrectly acccepted \"noth\"");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // pass
+ }
+
+ try {
+ parse32("notahexs");
+ fail("Incorrectly acccepted \"notahexs\"");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // pass
+ }
+
+ try {
+ parse32("01");
+ fail("Incorrectly acccepted \"01\"");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // pass
+ }
+
+ try {
+ parse32("0000000.");
+ fail("Incorrectly acccepted \"0000000.\"");
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // pass
+ }
+ }
+
+ private static int parse32(final String str) {
+ return RawParseUtils.parseHexInt32(Constants.encodeASCII(str), 0);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_LineMapTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_LineMapTest.java
new file mode 100644
index 0000000000..6dcd56ee0d
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_LineMapTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2008-2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util;
+
+import java.io.UnsupportedEncodingException;
+
+import junit.framework.TestCase;
+
+public class RawParseUtils_LineMapTest extends TestCase {
+ public void testEmpty() {
+ final IntList map = RawParseUtils.lineMap(new byte[] {}, 0, 0);
+ assertNotNull(map);
+ assertEquals(2, map.size());
+ assertEquals(Integer.MIN_VALUE, map.get(0));
+ assertEquals(0, map.get(1));
+ }
+
+ public void testOneBlankLine() {
+ final IntList map = RawParseUtils.lineMap(new byte[] { '\n' }, 0, 1);
+ assertEquals(3, map.size());
+ assertEquals(Integer.MIN_VALUE, map.get(0));
+ assertEquals(0, map.get(1));
+ assertEquals(1, map.get(2));
+ }
+
+ public void testTwoLineFooBar() throws UnsupportedEncodingException {
+ final byte[] buf = "foo\nbar\n".getBytes("ISO-8859-1");
+ final IntList map = RawParseUtils.lineMap(buf, 0, buf.length);
+ assertEquals(4, map.size());
+ assertEquals(Integer.MIN_VALUE, map.get(0));
+ assertEquals(0, map.get(1));
+ assertEquals(4, map.get(2));
+ assertEquals(buf.length, map.get(3));
+ }
+
+ public void testTwoLineNoLF() throws UnsupportedEncodingException {
+ final byte[] buf = "foo\nbar".getBytes("ISO-8859-1");
+ final IntList map = RawParseUtils.lineMap(buf, 0, buf.length);
+ assertEquals(4, map.size());
+ assertEquals(Integer.MIN_VALUE, map.get(0));
+ assertEquals(0, map.get(1));
+ assertEquals(4, map.get(2));
+ assertEquals(buf.length, map.get(3));
+ }
+
+ public void testFourLineBlanks() throws UnsupportedEncodingException {
+ final byte[] buf = "foo\n\n\nbar\n".getBytes("ISO-8859-1");
+ final IntList map = RawParseUtils.lineMap(buf, 0, buf.length);
+ assertEquals(6, map.size());
+ assertEquals(Integer.MIN_VALUE, map.get(0));
+ assertEquals(0, map.get(1));
+ assertEquals(4, map.get(2));
+ assertEquals(5, map.get(3));
+ assertEquals(6, map.get(4));
+ assertEquals(buf.length, map.get(5));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_MatchTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_MatchTest.java
new file mode 100644
index 0000000000..29459326da
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/RawParseUtils_MatchTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jgit.lib.Constants;
+
+public class RawParseUtils_MatchTest extends TestCase {
+ public void testMatch_Equal() {
+ final byte[] src = Constants.encodeASCII(" differ\n");
+ final byte[] dst = Constants.encodeASCII("foo differ\n");
+ assertTrue(RawParseUtils.match(dst, 3, src) == 3 + src.length);
+ }
+
+ public void testMatch_NotEqual() {
+ final byte[] src = Constants.encodeASCII(" differ\n");
+ final byte[] dst = Constants.encodeASCII("a differ\n");
+ assertTrue(RawParseUtils.match(dst, 2, src) < 0);
+ }
+
+ public void testMatch_Prefix() {
+ final byte[] src = Constants.encodeASCII("author ");
+ final byte[] dst = Constants.encodeASCII("author A. U. Thor");
+ assertTrue(RawParseUtils.match(dst, 0, src) == src.length);
+ assertTrue(RawParseUtils.match(dst, 1, src) < 0);
+ }
+
+ public void testMatch_TooSmall() {
+ final byte[] src = Constants.encodeASCII("author ");
+ final byte[] dst = Constants.encodeASCII("author autho");
+ assertTrue(RawParseUtils.match(dst, src.length + 1, src) < 0);
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/StringUtilsTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/StringUtilsTest.java
new file mode 100644
index 0000000000..912380dcd1
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/StringUtilsTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util;
+
+import junit.framework.TestCase;
+
+public class StringUtilsTest extends TestCase {
+ public void testToLowerCaseChar() {
+ assertEquals('a', StringUtils.toLowerCase('A'));
+ assertEquals('z', StringUtils.toLowerCase('Z'));
+
+ assertEquals('a', StringUtils.toLowerCase('a'));
+ assertEquals('z', StringUtils.toLowerCase('z'));
+
+ assertEquals((char) 0, StringUtils.toLowerCase((char) 0));
+ assertEquals((char) 0xffff, StringUtils.toLowerCase((char) 0xffff));
+ }
+
+ public void testToLowerCaseString() {
+ assertEquals("\n abcdefghijklmnopqrstuvwxyz\n", StringUtils
+ .toLowerCase("\n ABCDEFGHIJKLMNOPQRSTUVWXYZ\n"));
+ }
+
+ public void testEqualsIgnoreCase1() {
+ final String a = "FOO";
+ assertTrue(StringUtils.equalsIgnoreCase(a, a));
+ }
+
+ public void testEqualsIgnoreCase2() {
+ assertFalse(StringUtils.equalsIgnoreCase("a", ""));
+ }
+
+ public void testEqualsIgnoreCase3() {
+ assertFalse(StringUtils.equalsIgnoreCase("a", "b"));
+ assertFalse(StringUtils.equalsIgnoreCase("ac", "ab"));
+ }
+
+ public void testEqualsIgnoreCase4() {
+ assertTrue(StringUtils.equalsIgnoreCase("a", "a"));
+ assertTrue(StringUtils.equalsIgnoreCase("A", "a"));
+ assertTrue(StringUtils.equalsIgnoreCase("a", "A"));
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/TemporaryBufferTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/TemporaryBufferTest.java
new file mode 100644
index 0000000000..eb24172249
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/TemporaryBufferTest.java
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Arrays;
+
+import junit.framework.TestCase;
+
+public class TemporaryBufferTest extends TestCase {
+ public void testEmpty() throws IOException {
+ final TemporaryBuffer b = new TemporaryBuffer();
+ try {
+ b.close();
+ assertEquals(0, b.length());
+ final byte[] r = b.toByteArray();
+ assertNotNull(r);
+ assertEquals(0, r.length);
+ } finally {
+ b.destroy();
+ }
+ }
+
+ public void testOneByte() throws IOException {
+ final TemporaryBuffer b = new TemporaryBuffer();
+ final byte test = (byte) new TestRng(getName()).nextInt();
+ try {
+ b.write(test);
+ b.close();
+ assertEquals(1, b.length());
+ {
+ final byte[] r = b.toByteArray();
+ assertNotNull(r);
+ assertEquals(1, r.length);
+ assertEquals(test, r[0]);
+ }
+ {
+ final ByteArrayOutputStream o = new ByteArrayOutputStream();
+ b.writeTo(o, null);
+ o.close();
+ final byte[] r = o.toByteArray();
+ assertEquals(1, r.length);
+ assertEquals(test, r[0]);
+ }
+ } finally {
+ b.destroy();
+ }
+ }
+
+ public void testOneBlock_BulkWrite() throws IOException {
+ final TemporaryBuffer b = new TemporaryBuffer();
+ final byte[] test = new TestRng(getName())
+ .nextBytes(TemporaryBuffer.Block.SZ);
+ try {
+ b.write(test, 0, 2);
+ b.write(test, 2, 4);
+ b.write(test, 6, test.length - 6 - 2);
+ b.write(test, test.length - 2, 2);
+ b.close();
+ assertEquals(test.length, b.length());
+ {
+ final byte[] r = b.toByteArray();
+ assertNotNull(r);
+ assertEquals(test.length, r.length);
+ assertTrue(Arrays.equals(test, r));
+ }
+ {
+ final ByteArrayOutputStream o = new ByteArrayOutputStream();
+ b.writeTo(o, null);
+ o.close();
+ final byte[] r = o.toByteArray();
+ assertEquals(test.length, r.length);
+ assertTrue(Arrays.equals(test, r));
+ }
+ } finally {
+ b.destroy();
+ }
+ }
+
+ public void testOneBlockAndHalf_BulkWrite() throws IOException {
+ final TemporaryBuffer b = new TemporaryBuffer();
+ final byte[] test = new TestRng(getName())
+ .nextBytes(TemporaryBuffer.Block.SZ * 3 / 2);
+ try {
+ b.write(test, 0, 2);
+ b.write(test, 2, 4);
+ b.write(test, 6, test.length - 6 - 2);
+ b.write(test, test.length - 2, 2);
+ b.close();
+ assertEquals(test.length, b.length());
+ {
+ final byte[] r = b.toByteArray();
+ assertNotNull(r);
+ assertEquals(test.length, r.length);
+ assertTrue(Arrays.equals(test, r));
+ }
+ {
+ final ByteArrayOutputStream o = new ByteArrayOutputStream();
+ b.writeTo(o, null);
+ o.close();
+ final byte[] r = o.toByteArray();
+ assertEquals(test.length, r.length);
+ assertTrue(Arrays.equals(test, r));
+ }
+ } finally {
+ b.destroy();
+ }
+ }
+
+ public void testOneBlockAndHalf_SingleWrite() throws IOException {
+ final TemporaryBuffer b = new TemporaryBuffer();
+ final byte[] test = new TestRng(getName())
+ .nextBytes(TemporaryBuffer.Block.SZ * 3 / 2);
+ try {
+ for (int i = 0; i < test.length; i++)
+ b.write(test[i]);
+ b.close();
+ assertEquals(test.length, b.length());
+ {
+ final byte[] r = b.toByteArray();
+ assertNotNull(r);
+ assertEquals(test.length, r.length);
+ assertTrue(Arrays.equals(test, r));
+ }
+ {
+ final ByteArrayOutputStream o = new ByteArrayOutputStream();
+ b.writeTo(o, null);
+ o.close();
+ final byte[] r = o.toByteArray();
+ assertEquals(test.length, r.length);
+ assertTrue(Arrays.equals(test, r));
+ }
+ } finally {
+ b.destroy();
+ }
+ }
+
+ public void testOneBlockAndHalf_Copy() throws IOException {
+ final TemporaryBuffer b = new TemporaryBuffer();
+ final byte[] test = new TestRng(getName())
+ .nextBytes(TemporaryBuffer.Block.SZ * 3 / 2);
+ try {
+ final ByteArrayInputStream in = new ByteArrayInputStream(test);
+ b.write(in.read());
+ b.copy(in);
+ b.close();
+ assertEquals(test.length, b.length());
+ {
+ final byte[] r = b.toByteArray();
+ assertNotNull(r);
+ assertEquals(test.length, r.length);
+ assertTrue(Arrays.equals(test, r));
+ }
+ {
+ final ByteArrayOutputStream o = new ByteArrayOutputStream();
+ b.writeTo(o, null);
+ o.close();
+ final byte[] r = o.toByteArray();
+ assertEquals(test.length, r.length);
+ assertTrue(Arrays.equals(test, r));
+ }
+ } finally {
+ b.destroy();
+ }
+ }
+
+ public void testLarge_SingleWrite() throws IOException {
+ final TemporaryBuffer b = new TemporaryBuffer();
+ final byte[] test = new TestRng(getName())
+ .nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 3);
+ try {
+ b.write(test);
+ b.close();
+ assertEquals(test.length, b.length());
+ {
+ final byte[] r = b.toByteArray();
+ assertNotNull(r);
+ assertEquals(test.length, r.length);
+ assertTrue(Arrays.equals(test, r));
+ }
+ {
+ final ByteArrayOutputStream o = new ByteArrayOutputStream();
+ b.writeTo(o, null);
+ o.close();
+ final byte[] r = o.toByteArray();
+ assertEquals(test.length, r.length);
+ assertTrue(Arrays.equals(test, r));
+ }
+ } finally {
+ b.destroy();
+ }
+ }
+
+ public void testInCoreLimit_SwitchOnAppendByte() throws IOException {
+ final TemporaryBuffer b = new TemporaryBuffer();
+ final byte[] test = new TestRng(getName())
+ .nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT + 1);
+ try {
+ b.write(test, 0, test.length - 1);
+ b.write(test[test.length - 1]);
+ b.close();
+ assertEquals(test.length, b.length());
+ {
+ final byte[] r = b.toByteArray();
+ assertNotNull(r);
+ assertEquals(test.length, r.length);
+ assertTrue(Arrays.equals(test, r));
+ }
+ {
+ final ByteArrayOutputStream o = new ByteArrayOutputStream();
+ b.writeTo(o, null);
+ o.close();
+ final byte[] r = o.toByteArray();
+ assertEquals(test.length, r.length);
+ assertTrue(Arrays.equals(test, r));
+ }
+ } finally {
+ b.destroy();
+ }
+ }
+
+ public void testInCoreLimit_SwitchBeforeAppendByte() throws IOException {
+ final TemporaryBuffer b = new TemporaryBuffer();
+ final byte[] test = new TestRng(getName())
+ .nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 3);
+ try {
+ b.write(test, 0, test.length - 1);
+ b.write(test[test.length - 1]);
+ b.close();
+ assertEquals(test.length, b.length());
+ {
+ final byte[] r = b.toByteArray();
+ assertNotNull(r);
+ assertEquals(test.length, r.length);
+ assertTrue(Arrays.equals(test, r));
+ }
+ {
+ final ByteArrayOutputStream o = new ByteArrayOutputStream();
+ b.writeTo(o, null);
+ o.close();
+ final byte[] r = o.toByteArray();
+ assertEquals(test.length, r.length);
+ assertTrue(Arrays.equals(test, r));
+ }
+ } finally {
+ b.destroy();
+ }
+ }
+
+ public void testInCoreLimit_SwitchOnCopy() throws IOException {
+ final TemporaryBuffer b = new TemporaryBuffer();
+ final byte[] test = new TestRng(getName())
+ .nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 2);
+ try {
+ final ByteArrayInputStream in = new ByteArrayInputStream(test,
+ TemporaryBuffer.DEFAULT_IN_CORE_LIMIT, test.length
+ - TemporaryBuffer.DEFAULT_IN_CORE_LIMIT);
+ b.write(test, 0, TemporaryBuffer.DEFAULT_IN_CORE_LIMIT);
+ b.copy(in);
+ b.close();
+ assertEquals(test.length, b.length());
+ {
+ final byte[] r = b.toByteArray();
+ assertNotNull(r);
+ assertEquals(test.length, r.length);
+ assertTrue(Arrays.equals(test, r));
+ }
+ {
+ final ByteArrayOutputStream o = new ByteArrayOutputStream();
+ b.writeTo(o, null);
+ o.close();
+ final byte[] r = o.toByteArray();
+ assertEquals(test.length, r.length);
+ assertTrue(Arrays.equals(test, r));
+ }
+ } finally {
+ b.destroy();
+ }
+ }
+
+ public void testDestroyWhileOpen() throws IOException {
+ final TemporaryBuffer b = new TemporaryBuffer();
+ try {
+ b.write(new TestRng(getName())
+ .nextBytes(TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 2));
+ } finally {
+ b.destroy();
+ }
+ }
+
+ public void testRandomWrites() throws IOException {
+ final TemporaryBuffer b = new TemporaryBuffer();
+ final TestRng rng = new TestRng(getName());
+ final int max = TemporaryBuffer.DEFAULT_IN_CORE_LIMIT * 2;
+ final byte[] expect = new byte[max];
+ try {
+ int written = 0;
+ boolean onebyte = true;
+ while (written < max) {
+ if (onebyte) {
+ final byte v = (byte) rng.nextInt();
+ b.write(v);
+ expect[written++] = v;
+ } else {
+ final int len = Math
+ .min(rng.nextInt() & 127, max - written);
+ final byte[] tmp = rng.nextBytes(len);
+ b.write(tmp, 0, len);
+ System.arraycopy(tmp, 0, expect, written, len);
+ written += len;
+ }
+ onebyte = !onebyte;
+ }
+ assertEquals(expect.length, written);
+ b.close();
+
+ assertEquals(expect.length, b.length());
+ {
+ final byte[] r = b.toByteArray();
+ assertNotNull(r);
+ assertEquals(expect.length, r.length);
+ assertTrue(Arrays.equals(expect, r));
+ }
+ {
+ final ByteArrayOutputStream o = new ByteArrayOutputStream();
+ b.writeTo(o, null);
+ o.close();
+ final byte[] r = o.toByteArray();
+ assertEquals(expect.length, r.length);
+ assertTrue(Arrays.equals(expect, r));
+ }
+ } finally {
+ b.destroy();
+ }
+ }
+
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/TestRng.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/TestRng.java
new file mode 100644
index 0000000000..4110b55baa
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/TestRng.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util;
+
+/** Toy RNG to ensure we get predictable numbers during unit tests. */
+public class TestRng {
+ private int next;
+
+ public TestRng(final String seed) {
+ next = 0;
+ for (int i = 0; i < seed.length(); i++)
+ next = next * 11 + seed.charAt(i);
+ }
+
+ public byte[] nextBytes(final int cnt) {
+ final byte[] r = new byte[cnt];
+ for (int i = 0; i < cnt; i++)
+ r[i] = (byte) nextInt();
+ return r;
+ }
+
+ public int nextInt() {
+ next = next * 1103515245 + 12345;
+ return next;
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/TimeoutInputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/TimeoutInputStreamTest.java
new file mode 100644
index 0000000000..cd16288b64
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/TimeoutInputStreamTest.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util.io;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jgit.util.NB;
+import org.eclipse.jgit.util.io.InterruptTimer;
+import org.eclipse.jgit.util.io.TimeoutInputStream;
+
+import junit.framework.TestCase;
+
+public class TimeoutInputStreamTest extends TestCase {
+ private static final int timeout = 250;
+
+ private PipedOutputStream out;
+
+ private PipedInputStream in;
+
+ private InterruptTimer timer;
+
+ private TimeoutInputStream is;
+
+ private long start;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ out = new PipedOutputStream();
+ in = new PipedInputStream(out);
+ timer = new InterruptTimer();
+ is = new TimeoutInputStream(in, timer);
+ is.setTimeout(timeout);
+ }
+
+ protected void tearDown() throws Exception {
+ timer.terminate();
+ for (Thread t : active())
+ assertFalse(t instanceof InterruptTimer.AlarmThread);
+ super.tearDown();
+ }
+
+ public void testTimeout_readByte_Success1() throws IOException {
+ out.write('a');
+ assertEquals('a', is.read());
+ }
+
+ public void testTimeout_readByte_Success2() throws IOException {
+ final byte[] exp = new byte[] { 'a', 'b', 'c' };
+ out.write(exp);
+ assertEquals(exp[0], is.read());
+ assertEquals(exp[1], is.read());
+ assertEquals(exp[2], is.read());
+ out.close();
+ assertEquals(-1, is.read());
+ }
+
+ public void testTimeout_readByte_Timeout() throws IOException {
+ beginRead();
+ try {
+ is.read();
+ fail("incorrectly read a byte");
+ } catch (InterruptedIOException e) {
+ // expected
+ }
+ assertTimeout();
+ }
+
+ public void testTimeout_readBuffer_Success1() throws IOException {
+ final byte[] exp = new byte[] { 'a', 'b', 'c' };
+ final byte[] act = new byte[exp.length];
+ out.write(exp);
+ NB.readFully(is, act, 0, act.length);
+ assertTrue(Arrays.equals(exp, act));
+ }
+
+ public void testTimeout_readBuffer_Success2() throws IOException {
+ final byte[] exp = new byte[] { 'a', 'b', 'c' };
+ final byte[] act = new byte[exp.length];
+ out.write(exp);
+ NB.readFully(is, act, 0, 1);
+ NB.readFully(is, act, 1, 1);
+ NB.readFully(is, act, 2, 1);
+ assertTrue(Arrays.equals(exp, act));
+ }
+
+ public void testTimeout_readBuffer_Timeout() throws IOException {
+ beginRead();
+ try {
+ NB.readFully(is, new byte[512], 0, 512);
+ fail("incorrectly read bytes");
+ } catch (InterruptedIOException e) {
+ // expected
+ }
+ assertTimeout();
+ }
+
+ public void testTimeout_skip_Success() throws IOException {
+ final byte[] exp = new byte[] { 'a', 'b', 'c' };
+ out.write(exp);
+ assertEquals(2, is.skip(2));
+ assertEquals('c', is.read());
+ }
+
+ public void testTimeout_skip_Timeout() throws IOException {
+ beginRead();
+ try {
+ is.skip(1024);
+ fail("incorrectly skipped bytes");
+ } catch (InterruptedIOException e) {
+ // expected
+ }
+ assertTimeout();
+ }
+
+ private void beginRead() {
+ start = now();
+ }
+
+ private void assertTimeout() {
+ // Our timeout was supposed to be ~250 ms. Since this is a timing
+ // test we can't assume we spent *exactly* the timeout period, as
+ // there may be other activity going on in the system. Instead we
+ // look for the delta between the start and end times to be within
+ // 50 ms of the expected timeout.
+ //
+ final long wait = now() - start;
+ assertTrue(Math.abs(wait - timeout) < 50);
+ }
+
+ private static List<Thread> active() {
+ Thread[] all = new Thread[16];
+ int n = Thread.currentThread().getThreadGroup().enumerate(all);
+ while (n == all.length) {
+ all = new Thread[all.length * 2];
+ n = Thread.currentThread().getThreadGroup().enumerate(all);
+ }
+ return Arrays.asList(all).subList(0, n);
+ }
+
+ private static long now() {
+ return System.currentTimeMillis();
+ }
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/TimeoutOutputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/TimeoutOutputStreamTest.java
new file mode 100644
index 0000000000..bba8640ff3
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/TimeoutOutputStreamTest.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2009, Google Inc.
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ * names of its contributors may be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package org.eclipse.jgit.util.io;
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.io.OutputStream;
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jgit.util.NB;
+import org.eclipse.jgit.util.io.InterruptTimer;
+import org.eclipse.jgit.util.io.TimeoutOutputStream;
+
+import junit.framework.TestCase;
+
+public class TimeoutOutputStreamTest extends TestCase {
+ private static final int timeout = 250;
+
+ private PipedOutputStream out;
+
+ private FullPipeInputStream in;
+
+ private InterruptTimer timer;
+
+ private TimeoutOutputStream os;
+
+ private long start;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ out = new PipedOutputStream();
+ in = new FullPipeInputStream(out);
+ timer = new InterruptTimer();
+ os = new TimeoutOutputStream(out, timer);
+ os.setTimeout(timeout);
+ }
+
+ protected void tearDown() throws Exception {
+ timer.terminate();
+ for (Thread t : active())
+ assertFalse(t instanceof InterruptTimer.AlarmThread);
+ super.tearDown();
+ }
+
+ public void testTimeout_writeByte_Success1() throws IOException {
+ in.free(1);
+ os.write('a');
+ in.want(1);
+ assertEquals('a', in.read());
+ }
+
+ public void testTimeout_writeByte_Success2() throws IOException {
+ final byte[] exp = new byte[] { 'a', 'b', 'c' };
+ final byte[] act = new byte[exp.length];
+ in.free(exp.length);
+ os.write(exp[0]);
+ os.write(exp[1]);
+ os.write(exp[2]);
+ in.want(exp.length);
+ in.read(act);
+ assertTrue(Arrays.equals(exp, act));
+ }
+
+ public void testTimeout_writeByte_Timeout() throws IOException {
+ beginWrite();
+ try {
+ os.write('\n');
+ fail("incorrectly write a byte");
+ } catch (InterruptedIOException e) {
+ // expected
+ }
+ assertTimeout();
+ }
+
+ public void testTimeout_writeBuffer_Success1() throws IOException {
+ final byte[] exp = new byte[] { 'a', 'b', 'c' };
+ final byte[] act = new byte[exp.length];
+ in.free(exp.length);
+ os.write(exp);
+ in.want(exp.length);
+ in.read(act);
+ assertTrue(Arrays.equals(exp, act));
+ }
+
+ public void testTimeout_writeBuffer_Timeout() throws IOException {
+ beginWrite();
+ try {
+ os.write(new byte[512]);
+ fail("incorrectly wrote bytes");
+ } catch (InterruptedIOException e) {
+ // expected
+ }
+ assertTimeout();
+ }
+
+ public void testTimeout_flush_Success() throws IOException {
+ final boolean[] called = new boolean[1];
+ os = new TimeoutOutputStream(new OutputStream() {
+ @Override
+ public void write(int b) throws IOException {
+ fail("should not have written");
+ }
+
+ @Override
+ public void flush() throws IOException {
+ called[0] = true;
+ }
+ }, timer);
+ os.setTimeout(timeout);
+ os.flush();
+ assertTrue(called[0]);
+ }
+
+ public void testTimeout_flush_Timeout() throws IOException {
+ final boolean[] called = new boolean[1];
+ os = new TimeoutOutputStream(new OutputStream() {
+ @Override
+ public void write(int b) throws IOException {
+ fail("should not have written");
+ }
+
+ @Override
+ public void flush() throws IOException {
+ called[0] = true;
+ for (;;) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ throw new InterruptedIOException();
+ }
+ }
+ }
+ }, timer);
+ os.setTimeout(timeout);
+
+ beginWrite();
+ try {
+ os.flush();
+ fail("incorrectly flushed");
+ } catch (InterruptedIOException e) {
+ // expected
+ }
+ assertTimeout();
+ assertTrue(called[0]);
+ }
+
+ public void testTimeout_close_Success() throws IOException {
+ final boolean[] called = new boolean[1];
+ os = new TimeoutOutputStream(new OutputStream() {
+ @Override
+ public void write(int b) throws IOException {
+ fail("should not have written");
+ }
+
+ @Override
+ public void close() throws IOException {
+ called[0] = true;
+ }
+ }, timer);
+ os.setTimeout(timeout);
+ os.close();
+ assertTrue(called[0]);
+ }
+
+ public void testTimeout_close_Timeout() throws IOException {
+ final boolean[] called = new boolean[1];
+ os = new TimeoutOutputStream(new OutputStream() {
+ @Override
+ public void write(int b) throws IOException {
+ fail("should not have written");
+ }
+
+ @Override
+ public void close() throws IOException {
+ called[0] = true;
+ for (;;) {
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ throw new InterruptedIOException();
+ }
+ }
+ }
+ }, timer);
+ os.setTimeout(timeout);
+
+ beginWrite();
+ try {
+ os.close();
+ fail("incorrectly closed");
+ } catch (InterruptedIOException e) {
+ // expected
+ }
+ assertTimeout();
+ assertTrue(called[0]);
+ }
+
+ private void beginWrite() {
+ start = now();
+ }
+
+ private void assertTimeout() {
+ // Our timeout was supposed to be ~250 ms. Since this is a timing
+ // test we can't assume we spent *exactly* the timeout period, as
+ // there may be other activity going on in the system. Instead we
+ // look for the delta between the start and end times to be within
+ // 50 ms of the expected timeout.
+ //
+ final long wait = now() - start;
+ assertTrue(Math.abs(wait - timeout) < 50);
+ }
+
+ private static List<Thread> active() {
+ Thread[] all = new Thread[16];
+ int n = Thread.currentThread().getThreadGroup().enumerate(all);
+ while (n == all.length) {
+ all = new Thread[all.length * 2];
+ n = Thread.currentThread().getThreadGroup().enumerate(all);
+ }
+ return Arrays.asList(all).subList(0, n);
+ }
+
+ private static long now() {
+ return System.currentTimeMillis();
+ }
+
+ private final class FullPipeInputStream extends PipedInputStream {
+ FullPipeInputStream(PipedOutputStream src) throws IOException {
+ super(src);
+ src.write(new byte[PIPE_SIZE]);
+ }
+
+ void want(int cnt) throws IOException {
+ NB.skipFully(this, PIPE_SIZE - cnt);
+ }
+
+ void free(int cnt) throws IOException {
+ NB.skipFully(this, cnt);
+ }
+ }
+}