summaryrefslogtreecommitdiffstats
path: root/org.eclipse.jgit.test
diff options
context:
space:
mode:
Diffstat (limited to 'org.eclipse.jgit.test')
-rw-r--r--org.eclipse.jgit.test/.classpath11
-rw-r--r--org.eclipse.jgit.test/.gitignore3
-rw-r--r--org.eclipse.jgit.test/.project17
-rw-r--r--org.eclipse.jgit.test/.settings/org.eclipse.core.resources.prefs6
-rw-r--r--org.eclipse.jgit.test/.settings/org.eclipse.core.runtime.prefs3
-rw-r--r--org.eclipse.jgit.test/.settings/org.eclipse.jdt.core.prefs320
-rw-r--r--org.eclipse.jgit.test/.settings/org.eclipse.jdt.ui.prefs10
-rw-r--r--org.eclipse.jgit.test/exttst/org/eclipse/jgit/lib/SpeedTestBase.java116
-rw-r--r--org.eclipse.jgit.test/exttst/org/eclipse/jgit/lib/T0005_ShallowSpeedTest.java91
-rw-r--r--org.eclipse.jgit.test/exttst/org/eclipse/jgit/lib/T0006_DeepSpeedTest.java94
-rw-r--r--org.eclipse.jgit.test/exttst/org/eclipse/jgit/patch/EGitPatchHistoryTest.java227
-rw-r--r--org.eclipse.jgit.test/org.eclipse.jgit.core--All-External-Tests (Java 6).launch21
-rw-r--r--org.eclipse.jgit.test/org.eclipse.jgit.core--All-External-Tests.launch20
-rw-r--r--org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests (Java 6).launch21
-rw-r--r--org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests.launch20
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/E.patch6
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/E_PostImage1
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/E_PreImage0
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/X.patch24
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/X_PostImage28
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/X_PreImage25
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Y.patch8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Y_PostImage1
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Y_PreImage1
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Z.patch8
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Z_PostImage1
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Z_PreImage1
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext0.out18
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext1.out24
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext10.out37
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext100.out37
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext3.out30
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext5.out34
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/.gitattributes1
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testEditList_Types.patch24
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_BodyTooLong.patch17
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_CcTruncatedOld.patch24
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_DisconnectedHunk.patch30
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_GarbageBetweenFiles.patch33
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_GitBinaryNoForwardHunk.patch10
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_TruncatedNew.patch15
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_TruncatedOld.patch15
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testGetText_BothISO88591.patch21
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testGetText_Convert.patch21
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testGetText_DiffCc.patch13
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testGetText_NoBinary.patch4
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_AddNoNewline.patch20
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_CcDeleteFile.patch12
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_CcNewFile.patch14
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_ConfigCaseInsensitive.patch67
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_FixNoNewline.patch20
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_GitBinaryDelta.patch21
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_GitBinaryLiteral.patch135
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_NoBinary.patch83
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_OneFileCc.patch27
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/all_packed_objects.txt96
-rwxr-xr-xorg.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/create-second-pack166
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.indexbin0 -> 134799 bytes
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.lsfiles1437
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.lstree331
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-3280af9c07ee18a87705ef50b0cc4cd20266cf12.idxbin0 -> 1296 bytes
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-3280af9c07ee18a87705ef50b0cc4cd20266cf12.packbin0 -> 562 bytes
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.idxbin0 -> 1256 bytes
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.idxV2bin0 -> 1296 bytes
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.packbin0 -> 7811 bytes
-rwxr-xr-xorg.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-546ff360fe3488adb20860ce3436a2d6373d2796.idxbin0 -> 1324 bytes
-rwxr-xr-xorg.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-546ff360fe3488adb20860ce3436a2d6373d2796.packbin0 -> 1265 bytes
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-9fb5b411fe6dfa89cc2e6b89d2bd8e5de02b5745.idxbin0 -> 1100 bytes
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-9fb5b411fe6dfa89cc2e6b89d2bd8e5de02b5745.packbin0 -> 164 bytes
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.idxbin0 -> 1240 bytes
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.packbin0 -> 651 bytes
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.idxbin0 -> 2976 bytes
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.idxV2bin0 -> 2976 bytes
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.packbin0 -> 5901 bytes
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-e6d07037cbcf13376308a0a995d1fa48f8f76aaa.idxbin0 -> 1112 bytes
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-e6d07037cbcf13376308a0a995d1fa48f8f76aaa.packbin0 -> 1643 bytes
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-huge.idxbin0 -> 2368 bytes
-rw-r--r--org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/packed-refs36
-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
191 files changed, 27674 insertions, 0 deletions
diff --git a/org.eclipse.jgit.test/.classpath b/org.eclipse.jgit.test/.classpath
new file mode 100644
index 0000000000..cb944bd388
--- /dev/null
+++ b/org.eclipse.jgit.test/.classpath
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry excluding="**/*.idx|**/*.pack" kind="src" path="tst"/>
+ <classpathentry kind="src" path="tst-rsrc"/>
+ <classpathentry kind="src" path="exttst"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/J2SE-1.5"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/org.eclipse.jgit"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3.8.1"/>
+ <classpathentry kind="lib" path="/org.eclipse.jgit/lib/jsch-0.1.37.jar" sourcepath="/org.eclipse.jgit/lib/jsch-0.1.37.zip"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/org.eclipse.jgit.test/.gitignore b/org.eclipse.jgit.test/.gitignore
new file mode 100644
index 0000000000..9d7d1382b7
--- /dev/null
+++ b/org.eclipse.jgit.test/.gitignore
@@ -0,0 +1,3 @@
+bin
+tst/todopack
+trash
diff --git a/org.eclipse.jgit.test/.project b/org.eclipse.jgit.test/.project
new file mode 100644
index 0000000000..a7242a0684
--- /dev/null
+++ b/org.eclipse.jgit.test/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>org.eclipse.jgit.test</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/org.eclipse.jgit.test/.settings/org.eclipse.core.resources.prefs b/org.eclipse.jgit.test/.settings/org.eclipse.core.resources.prefs
new file mode 100644
index 0000000000..6a9621db1d
--- /dev/null
+++ b/org.eclipse.jgit.test/.settings/org.eclipse.core.resources.prefs
@@ -0,0 +1,6 @@
+#Sat Dec 20 21:21:24 CET 2008
+eclipse.preferences.version=1
+encoding//tst-rsrc/org/eclipse/jgit/patch/testGetText_BothISO88591.patch=ISO-8859-1
+encoding//tst-rsrc/org/eclipse/jgit/patch/testGetText_Convert.patch=ISO-8859-1
+encoding//tst-rsrc/org/eclipse/jgit/patch/testGetText_DiffCc.patch=ISO-8859-1
+encoding/<project>=UTF-8
diff --git a/org.eclipse.jgit.test/.settings/org.eclipse.core.runtime.prefs b/org.eclipse.jgit.test/.settings/org.eclipse.core.runtime.prefs
new file mode 100644
index 0000000000..72987c2521
--- /dev/null
+++ b/org.eclipse.jgit.test/.settings/org.eclipse.core.runtime.prefs
@@ -0,0 +1,3 @@
+#Mon Mar 24 18:55:56 EDT 2008
+eclipse.preferences.version=1
+line.separator=\n
diff --git a/org.eclipse.jgit.test/.settings/org.eclipse.jdt.core.prefs b/org.eclipse.jgit.test/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000000..8bfa5f141a
--- /dev/null
+++ b/org.eclipse.jgit.test/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,320 @@
+#Tue Feb 05 00:01:29 CET 2008
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.5
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.doc.comment.support=enabled
+org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.autoboxing=warning
+org.eclipse.jdt.core.compiler.problem.deprecation=warning
+org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled
+org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled
+org.eclipse.jdt.core.compiler.problem.discouragedReference=warning
+org.eclipse.jdt.core.compiler.problem.emptyStatement=warning
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning
+org.eclipse.jdt.core.compiler.problem.fieldHiding=warning
+org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning
+org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=error
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=error
+org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=error
+org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning
+org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=warning
+org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=error
+org.eclipse.jdt.core.compiler.problem.invalidJavadoc=error
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTags=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsDeprecatedRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsNotVisibleRef=enabled
+org.eclipse.jdt.core.compiler.problem.invalidJavadocTagsVisibility=private
+org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning
+org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=error
+org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocComments=ignore
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocCommentsVisibility=public
+org.eclipse.jdt.core.compiler.problem.missingJavadocTags=error
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.missingJavadocTagsVisibility=private
+org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=ignore
+org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning
+org.eclipse.jdt.core.compiler.problem.noEffectAssignment=error
+org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=error
+org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore
+org.eclipse.jdt.core.compiler.problem.nullReference=warning
+org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning
+org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore
+org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=error
+org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning
+org.eclipse.jdt.core.compiler.problem.rawTypeReference=ignore
+org.eclipse.jdt.core.compiler.problem.redundantNullCheck=warning
+org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled
+org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=error
+org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled
+org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning
+org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning
+org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=warning
+org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning
+org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=error
+org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=error
+org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled
+org.eclipse.jdt.core.compiler.problem.unusedImport=error
+org.eclipse.jdt.core.compiler.problem.unusedLabel=error
+org.eclipse.jdt.core.compiler.problem.unusedLocal=error
+org.eclipse.jdt.core.compiler.problem.unusedParameter=warning
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled
+org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled
+org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=error
+org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=error
+org.eclipse.jdt.core.compiler.source=1.5
+org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_assignment=0
+org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
+org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
+org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
+org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
+org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
+org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
+org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
+org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
+org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_after_package=1
+org.eclipse.jdt.core.formatter.blank_lines_before_field=1
+org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
+org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
+org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
+org.eclipse.jdt.core.formatter.blank_lines_before_method=1
+org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
+org.eclipse.jdt.core.formatter.blank_lines_before_package=0
+org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
+org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
+org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
+org.eclipse.jdt.core.formatter.comment.clear_blank_lines=false
+org.eclipse.jdt.core.formatter.comment.format_comments=true
+org.eclipse.jdt.core.formatter.comment.format_header=false
+org.eclipse.jdt.core.formatter.comment.format_html=true
+org.eclipse.jdt.core.formatter.comment.format_source_code=true
+org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
+org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
+org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
+org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
+org.eclipse.jdt.core.formatter.comment.line_length=80
+org.eclipse.jdt.core.formatter.compact_else_if=true
+org.eclipse.jdt.core.formatter.continuation_indentation=2
+org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
+org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
+org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
+org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_empty_lines=false
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
+org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
+org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
+org.eclipse.jdt.core.formatter.indentation.size=4
+org.eclipse.jdt.core.formatter.insert_new_line_after_annotation=insert
+org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
+org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
+org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
+org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
+org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
+org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
+org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
+org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
+org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
+org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
+org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
+org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
+org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
+org.eclipse.jdt.core.formatter.lineSplit=80
+org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
+org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
+org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
+org.eclipse.jdt.core.formatter.tabulation.char=tab
+org.eclipse.jdt.core.formatter.tabulation.size=4
+org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=false
diff --git a/org.eclipse.jgit.test/.settings/org.eclipse.jdt.ui.prefs b/org.eclipse.jgit.test/.settings/org.eclipse.jdt.ui.prefs
new file mode 100644
index 0000000000..fce94cf0c2
--- /dev/null
+++ b/org.eclipse.jgit.test/.settings/org.eclipse.jdt.ui.prefs
@@ -0,0 +1,10 @@
+#Thu Dec 20 01:31:04 CET 2007
+eclipse.preferences.version=1
+formatter_profile=_JGit
+formatter_settings_version=10
+internal.default.compliance=default
+org.eclipse.jdt.ui.ignorelowercasenames=true
+org.eclipse.jdt.ui.importorder=java;javax;org;com;
+org.eclipse.jdt.ui.ondemandthreshold=99
+org.eclipse.jdt.ui.staticondemandthreshold=99
+org.eclipse.jdt.ui.text.custom_code_templates=<?xml version\="1.0" encoding\="UTF-8"?><templates/>
diff --git a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/lib/SpeedTestBase.java b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/lib/SpeedTestBase.java
new file mode 100644
index 0000000000..b53a4e4304
--- /dev/null
+++ b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/lib/SpeedTestBase.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2008, Google Inc.
+ * Copyright (C) 2007-2008, 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.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStream;
+
+import junit.framework.TestCase;
+
+/**
+ * Base class for performance unit test.
+ */
+public abstract class SpeedTestBase extends TestCase {
+
+ /**
+ * The time used by native git as this is our reference.
+ */
+ protected long nativeTime;
+
+ /**
+ * Reference to the location of the Linux kernel repo.
+ */
+ protected String kernelrepo;
+
+ /**
+ * Prepare test by running a test against the Linux kernel repo first.
+ *
+ * @param refcmd
+ * git command to execute
+ *
+ * @throws Exception
+ */
+ protected void prepare(String[] refcmd) throws Exception {
+ try {
+ BufferedReader bufferedReader = new BufferedReader(new FileReader("kernel.ref"));
+ try {
+ kernelrepo = bufferedReader.readLine();
+ } finally {
+ bufferedReader.close();
+ }
+ timeNativeGit(kernelrepo, refcmd);
+ nativeTime = timeNativeGit(kernelrepo, refcmd);
+ } catch (Exception e) {
+ System.out.println("Create a file named kernel.ref and put the path to the Linux kernels repository there");
+ throw e;
+ }
+ }
+
+ private static long timeNativeGit(String kernelrepo, String[] refcmd) throws IOException,
+ InterruptedException, Exception {
+ long start = System.currentTimeMillis();
+ Process p = Runtime.getRuntime().exec(refcmd, null, new File(kernelrepo,".."));
+ InputStream inputStream = p.getInputStream();
+ InputStream errorStream = p.getErrorStream();
+ byte[] buf=new byte[1024*1024];
+ for (;;)
+ if (inputStream.read(buf) < 0)
+ break;
+ if (p.waitFor()!=0) {
+ int c;
+ while ((c=errorStream.read())!=-1)
+ System.err.print((char)c);
+ throw new Exception("git log failed");
+ }
+ inputStream.close();
+ errorStream.close();
+ long stop = System.currentTimeMillis();
+ return stop - start;
+ }
+}
diff --git a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/lib/T0005_ShallowSpeedTest.java b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/lib/T0005_ShallowSpeedTest.java
new file mode 100644
index 0000000000..97b1cf97d7
--- /dev/null
+++ b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/lib/T0005_ShallowSpeedTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007-2008, 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.IOException;
+
+import junit.textui.TestRunner;
+
+public class T0005_ShallowSpeedTest extends SpeedTestBase {
+
+ protected void setUp() throws Exception {
+ prepare(new String[] { "git", "rev-list", "365bbe0d0caaf2ba74d56556827babf0bc66965d" });
+ }
+
+ public void testShallowHistoryScan() throws IOException {
+ long start = System.currentTimeMillis();
+ Repository db = new Repository(new File(kernelrepo));
+ Commit commit = db.mapCommit("365bbe0d0caaf2ba74d56556827babf0bc66965d");
+ int n = 1;
+ for (;;) {
+ ObjectId[] parents = commit.getParentIds();
+ if (parents.length == 0)
+ break;
+ ObjectId parentId = parents[0];
+ commit = db.mapCommit(parentId);
+ commit.getCommitId().name();
+ ++n;
+ }
+ assertEquals(12275, n);
+ long stop = System.currentTimeMillis();
+ long time = stop - start;
+ System.out.println("native="+nativeTime);
+ System.out.println("jgit="+time);
+ // ~0.750s (hot cache), ok
+ /*
+native=1795
+jgit=722
+ */
+ // native git seems to run SLOWER than jgit here, at roughly half the speed
+ // creating the git process is not the issue here, btw.
+ long factor10 = (nativeTime*150/time+50)/100;
+ assertEquals(3, factor10);
+ }
+
+ public static void main(String[] args) {
+ TestRunner.run(T0005_ShallowSpeedTest.class);
+ }
+}
diff --git a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/lib/T0006_DeepSpeedTest.java b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/lib/T0006_DeepSpeedTest.java
new file mode 100644
index 0000000000..8843ae35b3
--- /dev/null
+++ b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/lib/T0006_DeepSpeedTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2007-2008, 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.IOException;
+
+import junit.textui.TestRunner;
+
+public class T0006_DeepSpeedTest extends SpeedTestBase {
+
+ protected void setUp() throws Exception {
+ prepare(new String[] { "git", "rev-list", "365bbe0d0caaf2ba74d56556827babf0bc66965d","--","net/netfilter/nf_queue.c" });
+ }
+
+ public void testDeepHistoryScan() throws IOException {
+ long start = System.currentTimeMillis();
+ Repository db = new Repository(new File(kernelrepo));
+ Commit commit = db.mapCommit("365bbe0d0caaf2ba74d56556827babf0bc66965d");
+ int n = 1;
+ for (;;) {
+ ObjectId[] parents = commit.getParentIds();
+ if (parents.length == 0)
+ break;
+ ObjectId parentId = parents[0];
+ commit = db.mapCommit(parentId);
+ TreeEntry m = commit.getTree().findBlobMember("net/netfilter/nf_queue.c");
+ if (m != null)
+ commit.getCommitId().name();
+ ++n;
+ }
+
+ assertEquals(12275, n);
+ long stop = System.currentTimeMillis();
+ long time = stop - start;
+ System.out.println("native="+nativeTime);
+ System.out.println("jgit="+time);
+ /*
+ native=1355
+ jgit=5449
+ */
+ // This is not an exact factor, but we'd expect native git to perform this
+ // about 4 times quicker. If for some reason we find jgit to be faster than
+ // this the cause should be found and secured.
+ long factor = (time*110/nativeTime+50)/100;
+ assertEquals(4, factor);
+ }
+
+ public static void main(String[] args) {
+ TestRunner.run(T0006_DeepSpeedTest.class);
+ }
+}
diff --git a/org.eclipse.jgit.test/exttst/org/eclipse/jgit/patch/EGitPatchHistoryTest.java b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/patch/EGitPatchHistoryTest.java
new file mode 100644
index 0000000000..60d3853d85
--- /dev/null
+++ b/org.eclipse.jgit.test/exttst/org/eclipse/jgit/patch/EGitPatchHistoryTest.java
@@ -0,0 +1,227 @@
+/*
+ * 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.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+import java.util.HashSet;
+
+import junit.framework.TestCase;
+
+import org.eclipse.jgit.lib.Constants;
+import org.eclipse.jgit.util.MutableInteger;
+import org.eclipse.jgit.util.RawParseUtils;
+import org.eclipse.jgit.util.TemporaryBuffer;
+
+public class EGitPatchHistoryTest extends TestCase {
+ public void testParseHistory() throws Exception {
+ final NumStatReader numstat = new NumStatReader();
+ numstat.read();
+
+ final HashMap<String, HashMap<String, StatInfo>> stats = numstat.stats;
+ assertEquals(1211, stats.size());
+
+ new PatchReader(stats).read();
+ }
+
+ static class StatInfo {
+ int added, deleted;
+ }
+
+ static class PatchReader extends CommitReader {
+ final HashSet<String> offBy1;
+
+ final HashMap<String, HashMap<String, StatInfo>> stats;
+
+ int errors;
+
+ PatchReader(final HashMap<String, HashMap<String, StatInfo>> s)
+ throws IOException {
+ super(new String[] { "-p" });
+ stats = s;
+
+ offBy1 = new HashSet<String>();
+ offBy1.add("9bda5ece6806cd797416eaa47c7b927cc6e9c3b2");
+ }
+
+ @Override
+ void onCommit(String cid, byte[] buf) {
+ final HashMap<String, StatInfo> files = stats.remove(cid);
+ assertNotNull("No files for " + cid, files);
+
+ final Patch p = new Patch();
+ p.parse(buf, 0, buf.length - 1);
+ assertEquals("File count " + cid, files.size(), p.getFiles().size());
+ if (!p.getErrors().isEmpty()) {
+ for (final FormatError e : p.getErrors()) {
+ System.out.println("error " + e.getMessage());
+ System.out.println(" at " + e.getLineText());
+ }
+ dump(buf);
+ fail("Unexpected error in " + cid);
+ }
+
+ for (final FileHeader fh : p.getFiles()) {
+ final String fileName;
+ if (fh.getChangeType() != FileHeader.ChangeType.DELETE)
+ fileName = fh.getNewName();
+ else
+ fileName = fh.getOldName();
+ final StatInfo s = files.remove(fileName);
+ final String nid = fileName + " in " + cid;
+ assertNotNull("No " + nid, s);
+ int added = 0, deleted = 0;
+ for (final HunkHeader h : fh.getHunks()) {
+ added += h.getOldImage().getLinesAdded();
+ deleted += h.getOldImage().getLinesDeleted();
+ }
+
+ if (s.added == added) {
+ //
+ } else if (s.added == added + 1 && offBy1.contains(cid)) {
+ //
+ } else {
+ dump(buf);
+ assertEquals("Added diff in " + nid, s.added, added);
+ }
+
+ if (s.deleted == deleted) {
+ //
+ } else if (s.deleted == deleted + 1 && offBy1.contains(cid)) {
+ //
+ } else {
+ dump(buf);
+ assertEquals("Deleted diff in " + nid, s.deleted, deleted);
+ }
+ }
+ assertTrue("Missed files in " + cid, files.isEmpty());
+ }
+
+ private static void dump(final byte[] buf) {
+ String str;
+ try {
+ str = new String(buf, 0, buf.length - 1, "ISO-8859-1");
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e);
+ }
+ System.out.println("<<" + str + ">>");
+ }
+ }
+
+ static class NumStatReader extends CommitReader {
+ final HashMap<String, HashMap<String, StatInfo>> stats = new HashMap<String, HashMap<String, StatInfo>>();
+
+ NumStatReader() throws IOException {
+ super(new String[] { "--numstat" });
+ }
+
+ @Override
+ void onCommit(String commitId, byte[] buf) {
+ final HashMap<String, StatInfo> files = new HashMap<String, StatInfo>();
+ final MutableInteger ptr = new MutableInteger();
+ while (ptr.value < buf.length) {
+ if (buf[ptr.value] == '\n')
+ break;
+ final StatInfo i = new StatInfo();
+ i.added = RawParseUtils.parseBase10(buf, ptr.value, ptr);
+ i.deleted = RawParseUtils.parseBase10(buf, ptr.value + 1, ptr);
+ final int eol = RawParseUtils.nextLF(buf, ptr.value);
+ final String name = RawParseUtils.decode(Constants.CHARSET,
+ buf, ptr.value + 1, eol - 1);
+ files.put(name, i);
+ ptr.value = eol;
+ }
+ stats.put(commitId, files);
+ }
+ }
+
+ static abstract class CommitReader {
+ private Process proc;
+
+ CommitReader(final String[] args) throws IOException {
+ final String[] realArgs = new String[3 + args.length + 1];
+ realArgs[0] = "git";
+ realArgs[1] = "log";
+ realArgs[2] = "--pretty=format:commit %H";
+ System.arraycopy(args, 0, realArgs, 3, args.length);
+ realArgs[3 + args.length] = "a4b98ed15ea5f165a7aa0f2fd2ea6fcce6710925";
+
+ proc = Runtime.getRuntime().exec(realArgs);
+ proc.getOutputStream().close();
+ proc.getErrorStream().close();
+ }
+
+ void read() throws IOException, InterruptedException {
+ final BufferedReader in = new BufferedReader(new InputStreamReader(
+ proc.getInputStream(), "ISO-8859-1"));
+ String commitId = null;
+ TemporaryBuffer buf = null;
+ for (;;) {
+ String line = in.readLine();
+ if (line == null)
+ break;
+ if (line.startsWith("commit ")) {
+ if (buf != null) {
+ buf.close();
+ onCommit(commitId, buf.toByteArray());
+ buf.destroy();
+ }
+ commitId = line.substring("commit ".length());
+ buf = new TemporaryBuffer();
+ } else if (buf != null) {
+ buf.write(line.getBytes("ISO-8859-1"));
+ buf.write('\n');
+ }
+ }
+ in.close();
+ assertEquals(0, proc.waitFor());
+ proc = null;
+ }
+
+ abstract void onCommit(String commitId, byte[] buf);
+ }
+}
diff --git a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-External-Tests (Java 6).launch b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-External-Tests (Java 6).launch
new file mode 100644
index 0000000000..9a9ca124d3
--- /dev/null
+++ b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-External-Tests (Java 6).launch
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="4"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.jgit.test"/>
+<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
+<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
+<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/org.eclipse.jgit.test"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.jgit.test/exttst"/>
+<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit3"/>
+</launchConfiguration>
diff --git a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-External-Tests.launch b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-External-Tests.launch
new file mode 100644
index 0000000000..6735fb0a26
--- /dev/null
+++ b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-External-Tests.launch
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="4"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.jgit.test"/>
+<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
+<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
+<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/org.eclipse.jgit.test"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.jgit.test/exttst"/>
+<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit3"/>
+</launchConfiguration>
diff --git a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests (Java 6).launch b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests (Java 6).launch
new file mode 100644
index 0000000000..a0aecf920c
--- /dev/null
+++ b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests (Java 6).launch
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/org.eclipse.jgit.test/tst"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="2"/>
+</listAttribute>
+<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
+<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
+<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
+<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.jgit.test/tst"/>
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit3"/>
+<stringAttribute key="org.eclipse.jdt.launching.JRE_CONTAINER" value="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.jgit.test"/>
+</launchConfiguration>
diff --git a/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests.launch b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests.launch
new file mode 100644
index 0000000000..bff41ecf07
--- /dev/null
+++ b/org.eclipse.jgit.test/org.eclipse.jgit.core--All-Tests.launch
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<launchConfiguration type="org.eclipse.jdt.junit.launchconfig">
+<booleanAttribute key="org.eclipse.jdt.junit.KEEPRUNNING_ATTR" value="false"/>
+<stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value=""/>
+<stringAttribute key="org.eclipse.jdt.junit.TESTNAME" value=""/>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
+<listEntry value="4"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="org.eclipse.jgit.test"/>
+<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
+<listEntry value="org.eclipse.debug.ui.launchGroup.debug"/>
+<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
+</listAttribute>
+<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
+<listEntry value="/org.eclipse.jgit.test"/>
+</listAttribute>
+<stringAttribute key="org.eclipse.jdt.junit.CONTAINER" value="=org.eclipse.jgit.test/tst"/>
+<booleanAttribute key="org.eclipse.debug.core.appendEnvironmentVariables" value="true"/>
+<stringAttribute key="org.eclipse.jdt.junit.TEST_KIND" value="org.eclipse.jdt.junit.loader.junit3"/>
+</launchConfiguration>
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/E.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/E.patch
new file mode 100644
index 0000000000..9b8fa98cf7
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/E.patch
@@ -0,0 +1,6 @@
+diff --git a/E b/E
+index e69de29..7898192 100644
+--- a/E
++++ b/E
+@@ -0,0 +1 @@
++a
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/E_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/E_PostImage
new file mode 100644
index 0000000000..7898192261
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/E_PostImage
@@ -0,0 +1 @@
+a
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/E_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/E_PreImage
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/E_PreImage
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/X.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/X.patch
new file mode 100644
index 0000000000..e5363eb204
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/X.patch
@@ -0,0 +1,24 @@
+diff --git a/X b/X
+index a3648a1..2d44096 100644
+--- a/X
++++ b/X
+@@ -2,2 +2,3 @@ a
+ b
++c
+ d
+@@ -16,4 +17,2 @@ p
+ q
+-r
+-s
+ t
+@@ -22,4 +21,8 @@ v
+ w
+-x
+-y
++0
++1
++2
++3
++4
++5
+ z
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/X_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/X_PostImage
new file mode 100644
index 0000000000..2d44096024
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/X_PostImage
@@ -0,0 +1,28 @@
+a
+b
+c
+d
+e
+f
+g
+h
+i
+j
+k
+l
+m
+n
+o
+p
+q
+t
+u
+v
+w
+0
+1
+2
+3
+4
+5
+z
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/X_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/X_PreImage
new file mode 100644
index 0000000000..a3648a1eba
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/X_PreImage
@@ -0,0 +1,25 @@
+a
+b
+d
+e
+f
+g
+h
+i
+j
+k
+l
+m
+n
+o
+p
+q
+r
+s
+t
+u
+v
+w
+x
+y
+z
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Y.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Y.patch
new file mode 100644
index 0000000000..a2c9a0bb45
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Y.patch
@@ -0,0 +1,8 @@
+diff --git a/Y b/Y
+index 2e65efe..7898192 100644
+--- a/Y
++++ b/Y
+@@ -1 +1 @@
+-a
+\ No newline at end of file
++a
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Y_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Y_PostImage
new file mode 100644
index 0000000000..7898192261
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Y_PostImage
@@ -0,0 +1 @@
+a
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Y_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Y_PreImage
new file mode 100644
index 0000000000..2e65efe2a1
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Y_PreImage
@@ -0,0 +1 @@
+a \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Z.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Z.patch
new file mode 100644
index 0000000000..35a06d6473
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Z.patch
@@ -0,0 +1,8 @@
+diff --git a/Z b/Z
+index 7898192..2e65efe 100644
+--- a/Z
++++ b/Z
+@@ -1 +1 @@
+-a
++a
+\ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Z_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Z_PostImage
new file mode 100644
index 0000000000..2e65efe2a1
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Z_PostImage
@@ -0,0 +1 @@
+a \ No newline at end of file
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Z_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Z_PreImage
new file mode 100644
index 0000000000..7898192261
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/Z_PreImage
@@ -0,0 +1 @@
+a
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext0.out b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext0.out
new file mode 100644
index 0000000000..d36e3fa0b3
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext0.out
@@ -0,0 +1,18 @@
+diff --git a/X b/X
+index a3648a1..2d44096 100644
+--- a/X
++++ b/X
+@@ -2,0 +3 @@
++c
+@@ -17,2 +17,0 @@
+-r
+-s
+@@ -23,2 +22,6 @@
+-x
+-y
++0
++1
++2
++3
++4
++5
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext1.out b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext1.out
new file mode 100644
index 0000000000..d0d847d608
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext1.out
@@ -0,0 +1,24 @@
+diff --git a/X b/X
+index a3648a1..2d44096 100644
+--- a/X
++++ b/X
+@@ -2,2 +2,3 @@
+ b
++c
+ d
+@@ -16,4 +17,2 @@
+ q
+-r
+-s
+ t
+@@ -22,4 +21,8 @@
+ w
+-x
+-y
++0
++1
++2
++3
++4
++5
+ z
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext10.out b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext10.out
new file mode 100644
index 0000000000..1d4f242779
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext10.out
@@ -0,0 +1,37 @@
+diff --git a/X b/X
+index a3648a1..2d44096 100644
+--- a/X
++++ b/X
+@@ -1,25 +1,28 @@
+ a
+ b
++c
+ d
+ e
+ f
+ g
+ h
+ i
+ j
+ k
+ l
+ m
+ n
+ o
+ p
+ q
+-r
+-s
+ t
+ u
+ v
+ w
+-x
+-y
++0
++1
++2
++3
++4
++5
+ z
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext100.out b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext100.out
new file mode 100644
index 0000000000..1d4f242779
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext100.out
@@ -0,0 +1,37 @@
+diff --git a/X b/X
+index a3648a1..2d44096 100644
+--- a/X
++++ b/X
+@@ -1,25 +1,28 @@
+ a
+ b
++c
+ d
+ e
+ f
+ g
+ h
+ i
+ j
+ k
+ l
+ m
+ n
+ o
+ p
+ q
+-r
+-s
+ t
+ u
+ v
+ w
+-x
+-y
++0
++1
++2
++3
++4
++5
+ z
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext3.out b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext3.out
new file mode 100644
index 0000000000..2564016648
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext3.out
@@ -0,0 +1,30 @@
+diff --git a/X b/X
+index a3648a1..2d44096 100644
+--- a/X
++++ b/X
+@@ -1,5 +1,6 @@
+ a
+ b
++c
+ d
+ e
+ f
+@@ -14,12 +15,14 @@
+ o
+ p
+ q
+-r
+-s
+ t
+ u
+ v
+ w
+-x
+-y
++0
++1
++2
++3
++4
++5
+ z
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext5.out b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext5.out
new file mode 100644
index 0000000000..3073c5f09e
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/testContext5.out
@@ -0,0 +1,34 @@
+diff --git a/X b/X
+index a3648a1..2d44096 100644
+--- a/X
++++ b/X
+@@ -1,7 +1,8 @@
+ a
+ b
++c
+ d
+ e
+ f
+ g
+ h
+@@ -12,14 +13,16 @@
+ m
+ n
+ o
+ p
+ q
+-r
+-s
+ t
+ u
+ v
+ w
+-x
+-y
++0
++1
++2
++3
++4
++5
+ z
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/.gitattributes b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/.gitattributes
new file mode 100644
index 0000000000..b38f87f9e3
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/.gitattributes
@@ -0,0 +1 @@
+*.patch -crlf
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testEditList_Types.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testEditList_Types.patch
new file mode 100644
index 0000000000..e5363eb204
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testEditList_Types.patch
@@ -0,0 +1,24 @@
+diff --git a/X b/X
+index a3648a1..2d44096 100644
+--- a/X
++++ b/X
+@@ -2,2 +2,3 @@ a
+ b
++c
+ d
+@@ -16,4 +17,2 @@ p
+ q
+-r
+-s
+ t
+@@ -22,4 +21,8 @@ v
+ w
+-x
+-y
++0
++1
++2
++3
++4
++5
+ z
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_BodyTooLong.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_BodyTooLong.patch
new file mode 100644
index 0000000000..9506198b1d
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_BodyTooLong.patch
@@ -0,0 +1,17 @@
+diff --git a/org.eclipse.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java b/org.eclipse.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java
+index da7e704..34ce04a 100644
+--- a/org.eclipse.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java
++++ b/org.eclipse.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java
+@@ -109,4 +109,11 @@ assertTrue(Arrays.equals(values.toArray(), repositoryConfig
+ .getStringList("my", null, "somename")));
+ checkFile(cfgFile, "[my]\n\tsomename = value1\n\tsomename = value2\n");
+ }
++
++ public void test006_readCaseInsensitive() throws IOException {
++ final File path = writeTrashFile("config_001", "[Foo]\nBar\n");
++ RepositoryConfig repositoryConfig = new RepositoryConfig(null, path);
++BAD LINE
++ assertEquals(true, repositoryConfig.getBoolean("foo", null, "bar", false));
++ assertEquals("", repositoryConfig.getString("foo", null, "bar"));
++ }
+ }
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_CcTruncatedOld.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_CcTruncatedOld.patch
new file mode 100644
index 0000000000..1bbcfb54de
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_CcTruncatedOld.patch
@@ -0,0 +1,24 @@
+commit 1a56639bbea8e8cbfbe5da87746de97f9217ce9b
+Date: Tue May 13 00:43:56 2008 +0200
+ ...
+
+diff --cc org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java
+index 169356b,dd8c317..fd85931
+mode 100644,100644..100755
+--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java
++++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java
+@@@ -55,12 -163,13 +163,15 @@@ public class UIText extends NLS
+
+ /** */
+ public static String ResourceHistory_toggleCommentWrap;
++
+ /** */
+ + /** */
+ public static String ResourceHistory_toggleRevDetail;
+ /** */
+ public static String ResourceHistory_toggleRevComment;
+ /** */
+ public static String ResourceHistory_toggleTooltips;
+
+
+commit 1a56639bbea8e8cbfbe5da87746de97f9217ce9b
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_DisconnectedHunk.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_DisconnectedHunk.patch
new file mode 100644
index 0000000000..3235970412
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_DisconnectedHunk.patch
@@ -0,0 +1,30 @@
+From: A. U. Thor
+
+@@ -109,4 +109,11 @@ assertTrue(Arrays.equals(values.toArray(), repositoryConfig
+ .getStringList("my", null, "somename")));
+ checkFile(cfgFile, "[my]\n\tsomename = value1\n\tsomename = value2\n");
+ }
++
++ public void test006_readCaseInsensitive() throws IOException {
++ final File path = writeTrashFile("config_001", "[Foo]\nBar\n");
++ RepositoryConfig repositoryConfig = new RepositoryConfig(null, path);
++ assertEquals(true, repositoryConfig.getBoolean("foo", null, "bar", false));
++ assertEquals("", repositoryConfig.getString("foo", null, "bar"));
++ }
+ }
+diff --git a/org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java b/org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
+index 45c2f8a..3291bba 100644
+--- a/org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
++++ b/org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
+@@ -236,9 +236,9 @@ protected boolean getBoolean(final String section, String subsection,
+ return defaultValue;
+
+ n = n.toLowerCase();
+- if (MAGIC_EMPTY_VALUE.equals(n) || "yes".equals(n) || "true".equals(n) || "1".equals(n)) {
++ if (MAGIC_EMPTY_VALUE.equals(n) || "yes".equalsIgnoreCase(n) || "true".equalsIgnoreCase(n) || "1".equals(n)) {
+ return true;
+- } else if ("no".equals(n) || "false".equals(n) || "0".equals(n)) {
++ } else if ("no".equalsIgnoreCase(n) || "false".equalsIgnoreCase(n) || "0".equalsIgnoreCase(n)) {
+ return false;
+ } else {
+ throw new IllegalArgumentException("Invalid boolean value: "
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_GarbageBetweenFiles.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_GarbageBetweenFiles.patch
new file mode 100644
index 0000000000..9f6fd6b8f6
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_GarbageBetweenFiles.patch
@@ -0,0 +1,33 @@
+diff --git a/org.eclipse.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java b/org.eclipse.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java
+index da7e704..34ce04a 100644
+--- a/org.eclipse.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java
++++ b/org.eclipse.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java
+@@ -109,4 +109,11 @@ assertTrue(Arrays.equals(values.toArray(), repositoryConfig
+ .getStringList("my", null, "somename")));
+ checkFile(cfgFile, "[my]\n\tsomename = value1\n\tsomename = value2\n");
+ }
++
++ public void test006_readCaseInsensitive() throws IOException {
++ final File path = writeTrashFile("config_001", "[Foo]\nBar\n");
++ RepositoryConfig repositoryConfig = new RepositoryConfig(null, path);
++ assertEquals(true, repositoryConfig.getBoolean("foo", null, "bar", false));
++ assertEquals("", repositoryConfig.getString("foo", null, "bar"));
++ }
+ }
+I AM NOT HERE
+diff --git a/org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java b/org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
+index 45c2f8a..3291bba 100644
+--- a/org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
++++ b/org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
+@@ -236,9 +236,9 @@ protected boolean getBoolean(final String section, String subsection,
+ return defaultValue;
+
+ n = n.toLowerCase();
+- if (MAGIC_EMPTY_VALUE.equals(n) || "yes".equals(n) || "true".equals(n) || "1".equals(n)) {
++ if (MAGIC_EMPTY_VALUE.equals(n) || "yes".equalsIgnoreCase(n) || "true".equalsIgnoreCase(n) || "1".equals(n)) {
+ return true;
+- } else if ("no".equals(n) || "false".equals(n) || "0".equals(n)) {
++ } else if ("no".equalsIgnoreCase(n) || "false".equalsIgnoreCase(n) || "0".equalsIgnoreCase(n)) {
+ return false;
+ } else {
+ throw new IllegalArgumentException("Invalid boolean value: "
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_GitBinaryNoForwardHunk.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_GitBinaryNoForwardHunk.patch
new file mode 100644
index 0000000000..e3f33075ae
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_GitBinaryNoForwardHunk.patch
@@ -0,0 +1,10 @@
+ create mode 100644 org.spearce.egit.ui/icons/toolbar/pushe.png
+
+diff --git a/org.spearce.egit.ui/icons/toolbar/fetchd.png b/org.spearce.egit.ui/icons/toolbar/fetchd.png
+new file mode 100644
+index 0000000000000000000000000000000000000000..4433c543f2a52b586a3ed5e31b138244107bc239
+GIT binary patch
+
+diff --git a/org.spearce.egit.ui/icons/toolbar/fetche.png b/org.spearce.egit.ui/icons/toolbar/fetche.png
+new file mode 100644
+index 0000000000000000000000000000000000000000..0ffeb419e6ab302caa5e58661854b33853dc43dc
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_TruncatedNew.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_TruncatedNew.patch
new file mode 100644
index 0000000000..f10a433be8
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_TruncatedNew.patch
@@ -0,0 +1,15 @@
+diff --git a/org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java b/org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
+index 45c2f8a..3291bba 100644
+--- a/org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
++++ b/org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
+@@ -236,9 +236,9 @@ protected boolean getBoolean(final String section, String subsection,
+ return defaultValue;
+
+ n = n.toLowerCase();
+- if (MAGIC_EMPTY_VALUE.equals(n) || "yes".equals(n) || "true".equals(n) || "1".equals(n)) {
+ return true;
+- } else if ("no".equals(n) || "false".equals(n) || "0".equals(n)) {
++ } else if ("no".equalsIgnoreCase(n) || "false".equalsIgnoreCase(n) || "0".equalsIgnoreCase(n)) {
+ return false;
+ } else {
+ throw new IllegalArgumentException("Invalid boolean value: "
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_TruncatedOld.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_TruncatedOld.patch
new file mode 100644
index 0000000000..42363c61c8
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testError_TruncatedOld.patch
@@ -0,0 +1,15 @@
+diff --git a/org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java b/org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
+index 45c2f8a..3291bba 100644
+--- a/org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
++++ b/org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
+@@ -236,9 +236,9 @@ protected boolean getBoolean(final String section, String subsection,
+ return defaultValue;
+
+ n = n.toLowerCase();
+- if (MAGIC_EMPTY_VALUE.equals(n) || "yes".equals(n) || "true".equals(n) || "1".equals(n)) {
++ if (MAGIC_EMPTY_VALUE.equals(n) || "yes".equalsIgnoreCase(n) || "true".equalsIgnoreCase(n) || "1".equals(n)) {
+ return true;
++ } else if ("no".equalsIgnoreCase(n) || "false".equalsIgnoreCase(n) || "0".equalsIgnoreCase(n)) {
+ return false;
+ } else {
+ throw new IllegalArgumentException("Invalid boolean value: "
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testGetText_BothISO88591.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testGetText_BothISO88591.patch
new file mode 100644
index 0000000000..8224fcc21d
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testGetText_BothISO88591.patch
@@ -0,0 +1,21 @@
+diff --git a/X b/X
+index 014ef30..8c80a36 100644
+--- a/X
++++ b/X
+@@ -1,7 +1,7 @@
+ a
+ b
+ c
+-Ångström
++line 4 Ångström
+ d
+ e
+ f
+@@ -13,6 +13,6 @@ k
+ l
+ m
+ n
+-Ångström
++Ångström; line 16
+ o
+ p
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testGetText_Convert.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testGetText_Convert.patch
new file mode 100644
index 0000000000..a43fef584d
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testGetText_Convert.patch
@@ -0,0 +1,21 @@
+diff --git a/X b/X
+index 014ef30..209db0d 100644
+--- a/X
++++ b/X
+@@ -1,7 +1,7 @@
+ a
+ b
+ c
+-Ångström
++Ångström
+ d
+ e
+ f
+@@ -13,6 +13,6 @@ k
+ l
+ m
+ n
+-Ångström
++Ångström
+ o
+ p
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testGetText_DiffCc.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testGetText_DiffCc.patch
new file mode 100644
index 0000000000..3f74a52234
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testGetText_DiffCc.patch
@@ -0,0 +1,13 @@
+diff --cc X
+index bdfc9f4,209db0d..474bd69
+--- a/X
++++ b/X
+@@@ -1,7 -1,7 +1,7 @@@
+ a
+--b
+ c
+ +test Ångström
++ Ångström
+ d
+ e
+ f
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testGetText_NoBinary.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testGetText_NoBinary.patch
new file mode 100644
index 0000000000..e4968dc4eb
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testGetText_NoBinary.patch
@@ -0,0 +1,4 @@
+diff --git a/org.spearce.egit.ui/icons/toolbar/fetchd.png b/org.spearce.egit.ui/icons/toolbar/fetchd.png
+new file mode 100644
+index 0000000..4433c54
+Binary files /dev/null and b/org.spearce.egit.ui/icons/toolbar/fetchd.png differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_AddNoNewline.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_AddNoNewline.patch
new file mode 100644
index 0000000000..3060952e33
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_AddNoNewline.patch
@@ -0,0 +1,20 @@
+From ca4719a4b2d93a469f61d1ddfb3e39ecbabfcd69 Mon Sep 17 00:00:00 2001
+From: Shawn O. Pearce <sop@google.com>
+Date: Fri, 12 Dec 2008 12:35:14 -0800
+Subject: [PATCH] introduce no lf again
+
+---
+ a | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/a b/a
+index f2ad6c7..c59d9b6 100644
+--- a/a
++++ b/a
+@@ -1 +1 @@
+-c
++d
+\ No newline at end of file
+--
+1.6.1.rc2.306.ge5d5e
+
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_CcDeleteFile.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_CcDeleteFile.patch
new file mode 100644
index 0000000000..2654e09799
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_CcDeleteFile.patch
@@ -0,0 +1,12 @@
+commit 740709ece2412856c0c3eabd4dc4a4cf115b0de6
+Merge: 5c19b43... 13a2c0d...
+Author: Shawn O. Pearce <sop@google.com>
+Date: Fri Dec 12 13:26:52 2008 -0800
+
+ Merge branch 'b' into d
+
+diff --cc a
+index 7898192,2e65efe..0000000
+deleted file mode 100644,100644
+--- a/a
++++ /dev/null
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_CcNewFile.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_CcNewFile.patch
new file mode 100644
index 0000000000..1a9b7b0ee3
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_CcNewFile.patch
@@ -0,0 +1,14 @@
+commit 6cb8160a4717d51fd3cc0baf721946daa60cf921
+Merge: 5c19b43... 13a2c0d...
+Author: Shawn O. Pearce <sop@google.com>
+Date: Fri Dec 12 13:26:52 2008 -0800
+
+ Merge branch 'b' into d
+
+diff --cc d
+index 0000000,0000000..4bcfe98
+new file mode 100644
+--- /dev/null
++++ b/d
+@@@ -1,0 -1,0 +1,1 @@@
+++d
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_ConfigCaseInsensitive.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_ConfigCaseInsensitive.patch
new file mode 100644
index 0000000000..bfb9b15dce
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_ConfigCaseInsensitive.patch
@@ -0,0 +1,67 @@
+From ce9b593ddf2530613f6da9d7f7e4a5ff93da8b36 Mon Sep 17 00:00:00 2001
+From: Robin Rosenberg <robin.rosenberg@dewire.com>
+Date: Mon, 13 Oct 2008 00:50:59 +0200
+Subject: [PATCH] git config file is case insensitive
+
+Keys are now always compared with ignore case rules.
+
+Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
+Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
+---
+ .../org/spearce/jgit/lib/RepositoryConfigTest.java | 7 +++++++
+ .../src/org/spearce/jgit/lib/RepositoryConfig.java | 8 ++++----
+ 2 files changed, 11 insertions(+), 4 deletions(-)
+
+diff --git a/org.eclipse.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java b/org.eclipse.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java
+index da7e704..34ce04a 100644
+--- a/org.eclipse.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java
++++ b/org.eclipse.jgit.test/tst/org/spearce/jgit/lib/RepositoryConfigTest.java
+@@ -109,4 +109,11 @@ assertTrue(Arrays.equals(values.toArray(), repositoryConfig
+ .getStringList("my", null, "somename")));
+ checkFile(cfgFile, "[my]\n\tsomename = value1\n\tsomename = value2\n");
+ }
++
++ public void test006_readCaseInsensitive() throws IOException {
++ final File path = writeTrashFile("config_001", "[Foo]\nBar\n");
++ RepositoryConfig repositoryConfig = new RepositoryConfig(null, path);
++ assertEquals(true, repositoryConfig.getBoolean("foo", null, "bar", false));
++ assertEquals("", repositoryConfig.getString("foo", null, "bar"));
++ }
+ }
+diff --git a/org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java b/org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
+index 45c2f8a..3291bba 100644
+--- a/org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
++++ b/org.eclipse.jgit/src/org/spearce/jgit/lib/RepositoryConfig.java
+@@ -236,9 +236,9 @@ protected boolean getBoolean(final String section, String subsection,
+ return defaultValue;
+
+ n = n.toLowerCase();
+- if (MAGIC_EMPTY_VALUE.equals(n) || "yes".equals(n) || "true".equals(n) || "1".equals(n)) {
++ if (MAGIC_EMPTY_VALUE.equals(n) || "yes".equalsIgnoreCase(n) || "true".equalsIgnoreCase(n) || "1".equals(n)) {
+ return true;
+- } else if ("no".equals(n) || "false".equals(n) || "0".equals(n)) {
++ } else if ("no".equalsIgnoreCase(n) || "false".equalsIgnoreCase(n) || "0".equalsIgnoreCase(n)) {
+ return false;
+ } else {
+ throw new IllegalArgumentException("Invalid boolean value: "
+@@ -300,7 +300,7 @@ public String getString(final String section, String subsection, final String na
+ final Set<String> result = new HashSet<String>();
+
+ for (final Entry e : entries) {
+- if (section.equals(e.base) && e.extendedBase != null)
++ if (section.equalsIgnoreCase(e.base) && e.extendedBase != null)
+ result.add(e.extendedBase);
+ }
+ if (baseConfig != null)
+@@ -954,7 +954,7 @@ private static boolean eq(final String a, final String b) {
+ return true;
+ if (a == null || b == null)
+ return false;
+- return a.equals(b);
++ return a.equalsIgnoreCase(b);
+ }
+ }
+ }
+--
+1.6.1.rc2.299.gead4c
+
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_FixNoNewline.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_FixNoNewline.patch
new file mode 100644
index 0000000000..e8af2e719a
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_FixNoNewline.patch
@@ -0,0 +1,20 @@
+From 1beb3ec1fe68ff18b0287396096442e12c34787a Mon Sep 17 00:00:00 2001
+From: Shawn O. Pearce <sop@google.com>
+Date: Fri, 12 Dec 2008 12:29:45 -0800
+Subject: [PATCH] make c and add lf
+
+---
+ a | 2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/a b/a
+index 2e65efe..f2ad6c7 100644
+--- a/a
++++ b/a
+@@ -1 +1 @@
+-a
+\ No newline at end of file
++c
+--
+1.6.1.rc2.306.ge5d5e
+
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_GitBinaryDelta.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_GitBinaryDelta.patch
new file mode 100644
index 0000000000..5b2c9c6260
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_GitBinaryDelta.patch
@@ -0,0 +1,21 @@
+From 7e49721ad0efdec3a81e20bc58e385ea5d2b87b7 Mon Sep 17 00:00:00 2001
+From: Shawn O. Pearce <sop@google.com>
+Date: Fri, 12 Dec 2008 12:45:17 -0800
+Subject: [PATCH] make zero have a 3
+
+---
+ zero.bin | Bin 4096 -> 4096 bytes
+ 1 files changed, 0 insertions(+), 0 deletions(-)
+
+diff --git a/zero.bin b/zero.bin
+index 08e7df176454f3ee5eeda13efa0adaa54828dfd8..d70d8710b6d32ff844af0ee7c247e4b4b051867f 100644
+GIT binary patch
+delta 12
+TcmZorXi%6C%4ociaTPxR8IA+R
+
+delta 11
+ScmZorXi(Uguz-JJK>`37u>@iO
+
+--
+1.6.1.rc2.306.ge5d5e
+
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_GitBinaryLiteral.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_GitBinaryLiteral.patch
new file mode 100644
index 0000000000..ab7b235919
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_GitBinaryLiteral.patch
@@ -0,0 +1,135 @@
+From 8363f12135a7d0ff0b5fea7d5a35d294c0479518 Mon Sep 17 00:00:00 2001
+From: Robin Rosenberg <robin.rosenberg.lists@dewire.com>
+Date: Tue, 23 Sep 2008 22:19:19 +0200
+Subject: [PATCH] Push and fetch icons for the toolbar
+
+Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
+Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
+---
+ org.spearce.egit.ui/icons/toolbar/fetchd.png | Bin 0 -> 359 bytes
+ org.spearce.egit.ui/icons/toolbar/fetche.png | Bin 0 -> 393 bytes
+ org.spearce.egit.ui/icons/toolbar/pushd.png | Bin 0 -> 372 bytes
+ org.spearce.egit.ui/icons/toolbar/pushe.png | Bin 0 -> 404 bytes
+ org.spearce.egit.ui/plugin.xml | 32 ++++++++++++++-----------
+ 5 files changed, 18 insertions(+), 14 deletions(-)
+ create mode 100644 org.spearce.egit.ui/icons/toolbar/fetchd.png
+ create mode 100644 org.spearce.egit.ui/icons/toolbar/fetche.png
+ create mode 100644 org.spearce.egit.ui/icons/toolbar/pushd.png
+ create mode 100644 org.spearce.egit.ui/icons/toolbar/pushe.png
+
+diff --git a/org.spearce.egit.ui/icons/toolbar/fetchd.png b/org.spearce.egit.ui/icons/toolbar/fetchd.png
+new file mode 100644
+index 0000000000000000000000000000000000000000..4433c543f2a52b586a3ed5e31b138244107bc239
+GIT binary patch
+literal 359
+zcmV-t0hs=YP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0003lNkl<ZIE|%~
+zF{;8q6h+U7BBn4qm_`dxuy6}@!NzsCfLTKp;5yPsN=p|I(rKe&p~M74Bq5ObRRW{%
+zje4sYc=ybGk2gYV%`a+{hvjnl6{!Lo4hNJ{A44jDl#(C_K2BmJ09dV7A3>VW2}+n!
+zO1rKr0DRxqm&=7b&q>piUayDaIKlvw2}+e_&-3(PFkmzq(Q380-|r+zg6Da9KA(#Q
+zPa2QMl^Gz*GK3HmMPby1VQ9_(U^bf>W`H=3+3)uhMZxuY<#al++wJIfyXFi47K?>p
+z2GCj~rNp*vI-L&fb{osGh@!|$@ci;S2_arv_(sil1xb<+1Odb0kjLY}`F!ShJaW6;
+z>Lr*?r);;|7ihoV2SC*MjhoFzuh;A9KAB9aMXCk(Pk$Loi}X0uxcmSB002ovPDHLk
+FV1lxPoI3yj
+
+literal 0
+HcmV?d00001
+
+diff --git a/org.spearce.egit.ui/icons/toolbar/fetche.png b/org.spearce.egit.ui/icons/toolbar/fetche.png
+new file mode 100644
+index 0000000000000000000000000000000000000000..0ffeb419e6ab302caa5e58661854b33853dc43dc
+GIT binary patch
+literal 393
+zcmV;40e1e0P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0003{Nkl<ZIE|%}
+z%Su8~6o$WjJd|h&)kLg8qatclklHDbhzOh%4SI>*L3{^aqJcvRqCsRQ6~SndH7ExK
+zk=KcyE?#y6(aupYt$(ujUi|ChXYD1Vl>A3Z=W-tL|B2KE=%pm#uoxNA1!yxqxEMW&
+zB>{jQO^yT+ogtn_{8Ep$Aq3h-C?o|y>g-6?-!e46K4}{7I2X6^?w$w$wKqXWo#uE<
+zlN$@u$mIiCW0N$hIYc2#Jf_L5pe_`875HfeP>nhW1zLv1R!iSvNdTZ7`q(*62#YbV
+zQhB;#V#z_Hl;tD;jPm%3!!_Fv=xqj&EpW_lqPo^m>_wFE9KxQ3t1@8v1#@h(gk?2k
+zU%h_@BTD_vVB{6b=^Lij^3<ya#!DI7eU*yg9xg#(&qL<HX{n_QH=dOmU|OU>Dkk>j
+n^=YB|UiI3T3toz$0fY1nZ1068v8@+b00000NkvXXu0mjfWwNMg
+
+literal 0
+HcmV?d00001
+
+diff --git a/org.spearce.egit.ui/icons/toolbar/pushd.png b/org.spearce.egit.ui/icons/toolbar/pushd.png
+new file mode 100644
+index 0000000000000000000000000000000000000000..22c3f7bf17b8b5a931c7527d768af13607b03bce
+GIT binary patch
+literal 372
+zcmV-)0gL{LP)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV0003yNkl<ZIE|%~
+zF{%PF6h%)&8w)Kgg)~~o6c%=-wG$iH;R0NP3veAG$Sh>A(?&%>K?5S92zkHxGyeyN
+zQSnxRymxZ%OQJ-CZ<LQ0VHnEcaNzNHaJ${8)oOIRUG)l}M1;v?B8^6aVzEe}P~dX8
+zV6A1h+tKg$Ga)&E`~8km3g?`+IiJs8M#ur2PA68Y70x-1$0OVAmgRCusZ@FoAR=h3
+zDVNJsDix~LD)oBZD;$r<sngD7(Utm(zh18y4u?;WOu&C>t%;)O$w?l-T1yl~1VO;{
+zdS$=gv)ODopU<8HfZ1#YAcMg`B@Q~B4vWRYJJDL}%|UCO8Yd6XZnu?)$aFeQidwCf
+z_mE--u|}hjN&o=H7-fukIg4hqnKXNVchu|kh_lCf`xbzwX88RJ-{>O;Y5D>6^@Sy#
+SDlMe|0000<MNUMnLSTZnn4{zX
+
+literal 0
+HcmV?d00001
+
+diff --git a/org.spearce.egit.ui/icons/toolbar/pushe.png b/org.spearce.egit.ui/icons/toolbar/pushe.png
+new file mode 100644
+index 0000000000000000000000000000000000000000..1f99f0a702983d674f15eedae5f1218f0a30b5a0
+GIT binary patch
+literal 404
+zcmV;F0c-w=P)<h;3K|Lk000e1NJLTq000mG000mO1^@s6AM^iV00047Nkl<ZIE|%~
+z%Su8~6o$WjJO~|4C>w|sG%6%VHSk(UL<B+v4SI>*L41dvA&3Z?G>L*BB*n0rWDTl8
+zL8Pb?Jzc!)CSJ}#$rF8}#a?Uu`(JCbg_M&2pmu`H$+oP&=V*R^(bPY1%&ibu+ZV$G
+zgp`tt<A@B;jw3Z6E&C{q>NBF4=c=f%6i@vsq5!CR9fSfc-IT0lZ>^0`E2vbS?r{1v
+z8l^m+g%^~^H#FDePyq!%wm_SSqPmu`yJKk6QAXzdroz+R(7<gg074jZz1Vo3Dy2y#
+zMW2W=)MJ~7I|%3fPE-KBpis_UGqzZuUe(cG%h>L#RCJHY0YK_74TR+C&ZX!&h^>3c
+zJvdA^W^@l;f6eS*z&I*^D|{frVpE>&7273F76LY=;y1$BWF(Q0qALI}5jqkZAq&fh
+y^_oorR)}l`>CE22@+$y+&Cvb}|KU##2Jr)k?t0Dap2#Es0000<MNUMnLSTZgH?cGT
+
+literal 0
+HcmV?d00001
+
+diff --git a/org.spearce.egit.ui/plugin.xml b/org.spearce.egit.ui/plugin.xml
+index 7c98688..ee8a5a0 100644
+--- a/org.spearce.egit.ui/plugin.xml
++++ b/org.spearce.egit.ui/plugin.xml
+@@ -272,22 +272,26 @@
+ </separator>
+ </menu>
+ <action
+- class="org.spearce.egit.ui.internal.actions.FetchAction"
+- id="org.spearce.egit.ui.actionfetch"
+- label="%FetchAction_label"
+- style="push"
+- menubarPath="org.spearce.egit.ui.gitmenu/repo"
+- toolbarPath="org.spearce.egit.ui"
+- tooltip="%FetchAction_tooltip">
++ class="org.spearce.egit.ui.internal.actions.FetchAction"
++ disabledIcon="icons/toolbar/fetchd.png"
++ icon="icons/toolbar/fetche.png"
++ id="org.spearce.egit.ui.actionfetch"
++ label="%FetchAction_label"
++ menubarPath="org.spearce.egit.ui.gitmenu/repo"
++ style="push"
++ toolbarPath="org.spearce.egit.ui"
++ tooltip="%FetchAction_tooltip">
+ </action>
+ <action
+- class="org.spearce.egit.ui.internal.actions.PushAction"
+- id="org.spearce.egit.ui.actionpush"
+- label="%PushAction_label"
+- style="push"
+- menubarPath="org.spearce.egit.ui.gitmenu/repo"
+- toolbarPath="org.spearce.egit.ui"
+- tooltip="%PushAction_tooltip">
++ class="org.spearce.egit.ui.internal.actions.PushAction"
++ disabledIcon="icons/toolbar/pushd.png"
++ icon="icons/toolbar/pushe.png"
++ id="org.spearce.egit.ui.actionpush"
++ label="%PushAction_label"
++ menubarPath="org.spearce.egit.ui.gitmenu/repo"
++ style="push"
++ toolbarPath="org.spearce.egit.ui"
++ tooltip="%PushAction_tooltip">
+ </action>
+ <action
+ class="org.spearce.egit.ui.internal.actions.BranchAction"
+--
+1.6.1.rc2.306.ge5d5e
+
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_NoBinary.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_NoBinary.patch
new file mode 100644
index 0000000000..684b13c824
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_NoBinary.patch
@@ -0,0 +1,83 @@
+From 8363f12135a7d0ff0b5fea7d5a35d294c0479518 Mon Sep 17 00:00:00 2001
+From: Robin Rosenberg <robin.rosenberg.lists@dewire.com>
+Date: Tue, 23 Sep 2008 22:19:19 +0200
+Subject: [PATCH] Push and fetch icons for the toolbar
+
+Signed-off-by: Robin Rosenberg <robin.rosenberg@dewire.com>
+Signed-off-by: Shawn O. Pearce <spearce@spearce.org>
+---
+ org.spearce.egit.ui/icons/toolbar/fetchd.png | Bin 0 -> 359 bytes
+ org.spearce.egit.ui/icons/toolbar/fetche.png | Bin 0 -> 393 bytes
+ org.spearce.egit.ui/icons/toolbar/pushd.png | Bin 0 -> 372 bytes
+ org.spearce.egit.ui/icons/toolbar/pushe.png | Bin 0 -> 404 bytes
+ org.spearce.egit.ui/plugin.xml | 32 ++++++++++++++-----------
+ 5 files changed, 18 insertions(+), 14 deletions(-)
+ create mode 100644 org.spearce.egit.ui/icons/toolbar/fetchd.png
+ create mode 100644 org.spearce.egit.ui/icons/toolbar/fetche.png
+ create mode 100644 org.spearce.egit.ui/icons/toolbar/pushd.png
+ create mode 100644 org.spearce.egit.ui/icons/toolbar/pushe.png
+
+diff --git a/org.spearce.egit.ui/icons/toolbar/fetchd.png b/org.spearce.egit.ui/icons/toolbar/fetchd.png
+new file mode 100644
+index 0000000..4433c54
+Binary files /dev/null and b/org.spearce.egit.ui/icons/toolbar/fetchd.png differ
+diff --git a/org.spearce.egit.ui/icons/toolbar/fetche.png b/org.spearce.egit.ui/icons/toolbar/fetche.png
+new file mode 100644
+index 0000000..0ffeb41
+Binary files /dev/null and b/org.spearce.egit.ui/icons/toolbar/fetche.png differ
+diff --git a/org.spearce.egit.ui/icons/toolbar/pushd.png b/org.spearce.egit.ui/icons/toolbar/pushd.png
+new file mode 100644
+index 0000000..22c3f7b
+Binary files /dev/null and b/org.spearce.egit.ui/icons/toolbar/pushd.png differ
+diff --git a/org.spearce.egit.ui/icons/toolbar/pushe.png b/org.spearce.egit.ui/icons/toolbar/pushe.png
+new file mode 100644
+index 0000000..1f99f0a
+Binary files /dev/null and b/org.spearce.egit.ui/icons/toolbar/pushe.png differ
+diff --git a/org.spearce.egit.ui/plugin.xml b/org.spearce.egit.ui/plugin.xml
+index 7c98688..ee8a5a0 100644
+--- a/org.spearce.egit.ui/plugin.xml
++++ b/org.spearce.egit.ui/plugin.xml
+@@ -272,22 +272,26 @@
+ </separator>
+ </menu>
+ <action
+- class="org.spearce.egit.ui.internal.actions.FetchAction"
+- id="org.spearce.egit.ui.actionfetch"
+- label="%FetchAction_label"
+- style="push"
+- menubarPath="org.spearce.egit.ui.gitmenu/repo"
+- toolbarPath="org.spearce.egit.ui"
+- tooltip="%FetchAction_tooltip">
++ class="org.spearce.egit.ui.internal.actions.FetchAction"
++ disabledIcon="icons/toolbar/fetchd.png"
++ icon="icons/toolbar/fetche.png"
++ id="org.spearce.egit.ui.actionfetch"
++ label="%FetchAction_label"
++ menubarPath="org.spearce.egit.ui.gitmenu/repo"
++ style="push"
++ toolbarPath="org.spearce.egit.ui"
++ tooltip="%FetchAction_tooltip">
+ </action>
+ <action
+- class="org.spearce.egit.ui.internal.actions.PushAction"
+- id="org.spearce.egit.ui.actionpush"
+- label="%PushAction_label"
+- style="push"
+- menubarPath="org.spearce.egit.ui.gitmenu/repo"
+- toolbarPath="org.spearce.egit.ui"
+- tooltip="%PushAction_tooltip">
++ class="org.spearce.egit.ui.internal.actions.PushAction"
++ disabledIcon="icons/toolbar/pushd.png"
++ icon="icons/toolbar/pushe.png"
++ id="org.spearce.egit.ui.actionpush"
++ label="%PushAction_label"
++ menubarPath="org.spearce.egit.ui.gitmenu/repo"
++ style="push"
++ toolbarPath="org.spearce.egit.ui"
++ tooltip="%PushAction_tooltip">
+ </action>
+ <action
+ class="org.spearce.egit.ui.internal.actions.BranchAction"
+--
+1.6.1.rc2.306.ge5d5e
+
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_OneFileCc.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_OneFileCc.patch
new file mode 100644
index 0000000000..c096b330af
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/patch/testParse_OneFileCc.patch
@@ -0,0 +1,27 @@
+commit 1a56639bbea8e8cbfbe5da87746de97f9217ce9b
+Date: Tue May 13 00:43:56 2008 +0200
+ ...
+
+diff --cc org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java
+index 169356b,dd8c317..fd85931
+mode 100644,100644..100755
+--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java
++++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/UIText.java
+@@@ -55,12 -163,13 +163,15 @@@ public class UIText extends NLS
+
+ /** */
+ public static String ResourceHistory_toggleCommentWrap;
++
+ /** */
+ + public static String ResourceHistory_toggleCommentFill;
+ + /** */
+ public static String ResourceHistory_toggleRevDetail;
++
+ /** */
+ public static String ResourceHistory_toggleRevComment;
++
+ /** */
+ public static String ResourceHistory_toggleTooltips;
+
+
+commit 1a56639bbea8e8cbfbe5da87746de97f9217ce9b
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/all_packed_objects.txt b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/all_packed_objects.txt
new file mode 100644
index 0000000000..a97f662455
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/all_packed_objects.txt
@@ -0,0 +1,96 @@
+4b825dc642cb6eb9a060e54bf8d69288fbee4904 tree 0 9 7782
+540a36d136cf413e4b064c2b0e0a4db60f77feab commit 191 131 339
+5b6e7c66c276e7610d4a73c70ec1a1f7c1003259 blob 11 40 516 1 6ff87c4664981e4397625791c8ea3bbb5f2279a3
+6ff87c4664981e4397625791c8ea3bbb5f2279a3 blob 18787 7180 556
+82c6b885ff600be425b4ea96dee75dca255b69e7 commit 245 166 12
+902d5476fa249b7abc9d84c611577a81381f0327 tree 35 46 7736
+aabf2ffaec9b497f0950352b3e582d73035c2035 tree 35 46 470
+c59759f143fb1fe21c197981df75a7ee00290799 commit 240 161 178
+02ba32d3649e510002c21651936b7077aa75ffa9 tree 122 127 3806
+0966a434eb1a025db6b71485ab63a3bfbea520b6 commit 287 197 2611
+09efc7e59a839528ac7bda9fa020dc9101278680 tree 68 71 5497
+0a3d7772488b6b106fb62813c4d6d627918d9181 tree 98 95 3367
+1004d0d7ac26fbf63050a234c9b88a46075719d3 tree 68 72 3504
+10da5895682013006950e7da534b705252b03be6 blob 6 15 3591
+1203b03dc816ccbb67773f28b3c19318654b0bc8 commit 222 152 758
+15fae9e651043de0fd1deef588aa3fbf5a7a41c6 blob 6 15 3474
+16f9ec009e5568c435f473ba3a1df732d49ce8c3 blob 3 12 4196
+1fd7d579fb6ae3fe942dc09c2c783443d04cf21e blob 6 15 3678
+20a8ade77639491ea0bd667bf95de8abf3a434c8 tree 66 77 5663
+2675188fd86978d5bc4d7211698b2118ae3bf658 tree 68 72 4124
+2c349335b7f797072cf729c4f3bb0914ecb6dec9 commit 221 154 2457
+2cc3f4155a8eda5c3f1bc85de0988c0155c8cc1c tree 68 72 4717
+30a7b072d441dbfcfe0266b1c5fce94c22c447da tree 38 48 5784
+42e4e7c5e507e113ebbb7801b16b52cf867b7ce1 commit 184 133 1407
+49322bb17d3acc9146f98c97d078513228bbf3c0 commit 338 223 12
+49c5f851406e8004b816b8170f6f18e30ee877b9 tree 68 72 3606
+55a1a760df4b86a02094a904dfa511deb5655905 blob 6 15 3693
+58be4659bb571194ed4562d04b359d26216f526e commit 226 156 2962
+59706a11bde2b9899a278838ef20a97e8f8795d2 commit 222 153 1692
+5f25aaf573e7a094697987a927b833e088134674 tree 66 76 5184
+6020a3b8d5d636e549ccbd0c53e2764684bb3125 tree 122 126 3241
+62b15c9ddac853efbb00f59123f484b05b06d8b3 tree 28 37 4431
+6462e7d8024396b14d7651e2ec11e2bbf07a05c4 commit 221 153 1254
+6c83a9d0a09ce6d12292314ed3d9e1f60e39feb0 tree 66 76 5587
+6c8b137b1c652731597c89668f417b8695f28dd7 commit 172 123 3118
+6db9c2ebf75590eef973081736730a9ea169a0c4 commit 222 152 2153
+6e1475206e57110fcef4b92320436c1e9872a322 commit 282 192 566
+7f822839a2fe9760f386cbbbcb3f92c5fe81def7 commit 222 152 1540
+81e462df7c747d5b8783af18bf83bffbef8dc2bc tree 34 45 5139
+8230f48330e0055d9e0bc5a2a77718f6dd9324b8 blob 10 19 5568
+82b1d08466e9505f8666b778744f9a3471a70c81 blob 20 22 3708
+82fb2e7873759b74c41020a00abaea9c378a7a15 tree 66 76 4801
+835da11381dee94c71a04164cdaa533d0673e4e5 tree 34 45 4468
+83834a7afdaa1a1260568567f6ad90020389f664 commit 282 192 1062
+83d2f0431bcdc9c2fd2c17b828143be6ee4fbe80 commit 221 155 1998
+856ec208ae6cadac25a6d74f19b12bb27a24fe24 tree 66 76 5260
+86265c33b19b2be71bdd7b8cb95823f2743d03a8 tree 94 102 4208
+86cec6b57d80fda40300fb0d667965a5c3c3572f blob 6 15 3576
+8d6a2f2af0b2b96f320dd62fb6d9916fd2497dd9 tree 66 77 5420
+8f50ba15d49353813cc6e20298002c0d17b0a9ee tree 94 102 4961
+9188910f5d18434c2c8a3d78e8bef1a469c5626e tree 68 72 3933
+965361132e2f15897c9fd6c727beb5753057c38a blob 6 15 3489
+968a4b6caa8b55a68098e0495fbd9e75a7d05efa tree 68 72 4310
+a288d2cc3ee7d82f482e70ae7b6fedb4a039dd09 tree 28 37 4394
+a33a091b7c8de98b3a2ad2f21f88ea86f395d787 tree 94 102 4615
+a4e0e50de469ac6e2fdf2ee81808f253d5b78fd3 tree 68 72 5336
+ac7e7e44c1885efb472ad54a78327d66bfc4ecef commit 221 154 2808
+acd0220f06f7e4db50ea5ba242f0dfed297b27af tree 94 102 4513
+ae9304576a6ec3419b231b2b9c8e33a06f97f9fb blob 3 12 4382
+b9877f83f4c2ba0c3dd8fb2f6b5f04a0aaf18594 tree 66 76 5063
+bab66b48f836ed950c99134ef666436fb07a09a0 commit 222 152 910
+be9b45333b66013bde1c7314efc50fabd9b39c6d tree 7 18 4005 1 02ba32d3649e510002c21651936b7077aa75ffa9
+c070ad8c08840c8116da865b2d65593a6bb9cd2a commit 282 192 235
+c17b9ee9d0501fecadfac3b60ca485b14f5dbe98 tree 38 49 5832
+c1827f07e114c20547dc6a7296588870a4b5b62c blob 3 12 5408
+c9c6af7f78bc47490dbf3e822cf2f3c24d4b9061 blob 3 12 4949
+cd4bcfc27da62c6b840de700be1c60a7e69952a5 tree 66 76 3730
+d0114ab8ac326bab30e3a657a0397578c5a1af88 commit 84 95 427 1 c070ad8c08840c8116da865b2d65593a6bb9cd2a
+d31f5a60d406e831d056b8ac2538d515100c2df2 commit 221 153 1845
+d4b9b11fc8006af3b05cf2b4611077ed6a9b8c07 tree 68 72 4877
+d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864 commit 222 152 2305
+da0f8ed91a8f2f0f067b3bdf26265d5ca48cf82c blob 3 12 3462
+e4ff0b72cb0994dbf7a9da260aeb461c9d882bb5 tree 34 44 5740
+e6bfff5c1d0f0ecd501552b43a1e13d8008abc31 blob 3 12 4789
+f2aacb9368806d6502a03aa9da0834d4b50b9f0e tree 94 101 4023
+f73b95671f326616d66b2afb3bdfcdbbce110b44 commit 33 44 522 2 d0114ab8ac326bab30e3a657a0397578c5a1af88
+17768080a2318cd89bba4c8b87834401e2095703 tag 140 132 12
+032c063ce34486359e3ee3d4f9e5c225b9e1a4c2 tag 152 138 12
+1170b77a48d3ea2d58b043648b1ec63d606e3efa tag 150 138 971
+214cae792433672d28b3aeb9f75c1ae84fd54628 tag 150 136 1109
+8dfd42699e7b10e568fa1eaebe249e33e98da81e tag 150 138 833
+a773cd2d9dbca00d08793dac0d7002a49f0428c0 tag 150 138 422
+bf5123bb77c7b5a379f7de9c1293558e3e24dfb8 tag 150 135 287
+d54e006ebbef94b7d3a5cd56d154f1e6f08efb94 tag 150 137 560
+dd144af286452bfd6a1ea02b0d3745bcdb555e9d tag 150 137 150
+efee904c794b943a06931c76c576dd552212e8bc tag 150 136 697
+8bbde7aacf771a9afb6992434f1ae413e010c6d8 tag 630 436 1187
+fd608fbe625a2b456d9f15c2b1dc41f252057dd7 blob 1512 1175 12
+06b8692d5c4f29a6bc4987e1bec04e9bb2ec54a2 tree 29 40 330
+164bf8c9e69a5c192acd28e95aefd9a5d6f254df blob 7 16 370
+175d5b80bd9768884d8fced02e9bd33488174396 commit 56 68 160 1 47d3697c3747e8184e0dc479ccbd01e359023577
+3d2770618bb1132e59c314dea328b83ac7c83232 tree 29 40 488
+3df983efd6acdf73dfc7b451a2e30f7ed42e7736 blob 5 14 528
+47d3697c3747e8184e0dc479ccbd01e359023577 commit 217 148 12
+5e28f2d1ee99ddf4595a7a1ff31efa1a107c11e7 tree 94 102 386
+737d98fe75742dd9a8f4bce5e176e7f8d99d9de3 tree 94 102 228
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/create-second-pack b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/create-second-pack
new file mode 100755
index 0000000000..7241fa694c
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/create-second-pack
@@ -0,0 +1,166 @@
+#!/bin/bash -ex
+
+export GIT_COMMITTER_NAME="A U Thor"
+export GIT_AUTHOR_NAME="A U Thor"
+export GIT_COMMITTER_EMAIL="a.u.thor@example.com"
+export GIT_AUTHOR_EMAIL="a.u.thor@example.com"
+
+test_tick () {
+ # from git/t/test-lib.sh
+ if test -z "${test_tick+set}"
+ then
+ test_tick=1112911993
+ else
+ test_tick=$(($test_tick + 60))
+ fi
+ GIT_COMMITTER_DATE="$test_tick -0700"
+ GIT_AUTHOR_DATE="$test_tick -0700"
+ export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
+}
+
+git_commit () {
+ test_tick
+ git commit "$@"
+}
+
+git_merge () {
+ test_tick
+ git merge "$@"
+
+}
+
+test_tick
+rm -rf .git *.txt ?
+git init
+echo "On master" >>master.txt
+git add master.txt
+git_commit -a -m "On master"
+
+echo "On master" >>master.txt
+git_commit -a -m "On master again"
+
+git checkout -b a 6c8b137b1c652731597c89668f417b8695f28dd7
+mkdir a
+
+echo a1 >>a/a1.txt
+git add a/a1.txt
+git_commit -a -m "First a/a1"
+
+echo a2 >>a/a2.txt
+git add a/a2.txt
+git_commit -a -m "First a/a2"
+
+git merge master
+
+echo a1 >>a/a1.txt
+git add a/a1.txt
+git_commit -a -m "Second a/a1"
+git branch pa
+
+echo a2 >>a/a2.txt
+git add a/a2.txt
+git_commit -a -m "Second a/a2"
+
+git checkout -b b 58be4659bb571194ed4562d04b359d26216f526e
+
+mkdir b
+echo b1 >>b/b1.txt
+git add b/b1.txt
+git_commit -a -m "First b/b1"
+
+echo b2 >>b/b2.txt
+git add b/b2.txt
+git_commit -a -m "First b/b2"
+
+git merge a
+
+echo b1 >>b/b1.txt
+git add b/b1.txt
+git_commit -a -m "Second b/b1"
+
+echo b2 >>b/b2.txt
+git add b/b2.txt
+git_commit -a -m "Second b/b2"
+
+rm -rf a b c master.txt
+mkdir c
+rm -f ./git/index
+echo ref: refs/heads/c >.git/HEAD
+
+echo c1 >>c/c1.txt
+git add c/c1.txt
+git_commit -a -m "First c/c1, no parent"
+
+echo c2 >>c/c2.txt
+git add c/c2.txt
+git_commit -a -m "First c/c2"
+
+git_merge a
+
+echo c1 >>c/c1.txt
+git add c/c2.txt
+git_commit -a -m "Second c/c1"
+
+echo c2 >>c/c2.txt
+git add c/c2.txt
+git_commit -a -m "Second c/c2"
+
+git_merge b
+
+git checkout -b d a
+
+echo "a1" >>a/a1
+git add a/a1
+git_commit -a -m "Third a/a1"
+
+git checkout -b e a
+
+echo "a1" >>a/a1
+git add a/a1
+git_commit -a -m "Fourth a/a1"
+
+git checkout master
+
+git_merge c d e
+
+git repack -d
+
+git tag A a
+git tag -a -m "An annotated tag" B a^
+
+git repack -d
+
+Bnth=B
+for nth in 2nd 3rd 4th 5th 6th 7th 8th 9th 10th; do
+ git tag -a -m "An $nth level annotated tag" "B$nth" "$Bnth"
+ Bnth="B$nth"
+done
+
+git repack -d
+
+git checkout -b f a
+mkdir f
+echo "an eff" >f/f
+git add f/f
+git commit -m "An eff"
+git checkout -b g a
+mkdir f
+echo "an F" >f/f
+git add f/f
+git commit -m "An F"
+
+git repack -d
+
+git checkout -b symlink master
+ln -s c/c1.txt symlink.txt
+git add symlink.txt
+git_commit -m "A symlink"
+
+git checkout -b gitlink master
+git submodule add "$(pwd)/.git" submodule
+git_commit -m "A gitlink"
+
+git repack -d
+git pack-refs --all
+
+gitk --all master
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.index b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.index
new file mode 100644
index 0000000000..215da649e1
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.index
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.lsfiles b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.lsfiles
new file mode 100644
index 0000000000..27fe5c2347
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.lsfiles
@@ -0,0 +1,1437 @@
+100644 6b9c715d21d5486e59083fb6071566aa6ecd4d42 0 .gitattributes
+100644 a213e8e25bb2442326e86cbfb9ef56319f482869 0 .gitignore
+100644 373476bdc03f718b4c01471dd9996ee4497f43a8 0 .mailmap
+100644 9651afc89d5e789abd9cedaa4f3b92dde7dd1412 0 .project
+100644 6ff87c4664981e4397625791c8ea3bbb5f2279a3 0 COPYING
+100644 ddb030137d54ef3fb0ee01d973ec5cee4bb2b2b3 0 Documentation/.gitattributes
+100644 d8edd904065fbc4bd06365ce378f57d4cd8f9f0d 0 Documentation/.gitignore
+100644 f628c1f3b7b706f9d585b96041e5a4b12bc0f62c 0 Documentation/CodingGuidelines
+100644 62269e39c4edf95b2cf2e6a60bff2a33b239b07e 0 Documentation/Makefile
+100644 fea3f9935b7794ce86f04d22c9d68fb9d537167d 0 Documentation/RelNotes-1.5.0.1.txt
+100644 b061e50ff05b5e13211bb315e240974e898de32c 0 Documentation/RelNotes-1.5.0.2.txt
+100644 cd500f96bfd73e288577b05cfdfe337d7f2b85bb 0 Documentation/RelNotes-1.5.0.3.txt
+100644 feefa5dfd4eee5f493fcf3091ec0de116d414fc1 0 Documentation/RelNotes-1.5.0.4.txt
+100644 eeec3d73d01a0e9f61df666bad8a48a4f423438a 0 Documentation/RelNotes-1.5.0.5.txt
+100644 c02015ad5fdb1953ad1a8cf5b0edd7ef7c04fbac 0 Documentation/RelNotes-1.5.0.6.txt
+100644 670ad32b85678c938709b47c37d6caacbb5ebe29 0 Documentation/RelNotes-1.5.0.7.txt
+100644 daf4bdb0d7bb24319810fe0e73aa317663448c93 0 Documentation/RelNotes-1.5.0.txt
+100644 91471213bdec8d95209db256f594b0e1b3f3ec2a 0 Documentation/RelNotes-1.5.1.1.txt
+100644 d88456306c503d9e604ffbb699fb7cadacb2e733 0 Documentation/RelNotes-1.5.1.2.txt
+100644 876408b65a0e0841567a2c9b97c6f6e62cb86b81 0 Documentation/RelNotes-1.5.1.3.txt
+100644 df2f66ccb5d2a6a038d1fcf9306e7ed7aae05f39 0 Documentation/RelNotes-1.5.1.4.txt
+100644 b0ab8eb371ccb05346781e63c5ec4b71dab8be34 0 Documentation/RelNotes-1.5.1.5.txt
+100644 55f3ac13e3c242acc4bb1b873272d7d8ff4ef84d 0 Documentation/RelNotes-1.5.1.6.txt
+100644 daed3672709f6b94478fc6ad425897abe3433c9a 0 Documentation/RelNotes-1.5.1.txt
+100644 ebf20e22a74284f7085a5027f588ba295fb767d0 0 Documentation/RelNotes-1.5.2.1.txt
+100644 f6393f8a94f454f4f7b5cc5bb42881b6662cadff 0 Documentation/RelNotes-1.5.2.2.txt
+100644 addb22955b4e4e5344f7f139076a798cb50024ff 0 Documentation/RelNotes-1.5.2.3.txt
+100644 75cff475f6546402dc3486c43e0b6e7557ae621e 0 Documentation/RelNotes-1.5.2.4.txt
+100644 e8281c72a0b997e90cba2c9a2c4153f8607a7b76 0 Documentation/RelNotes-1.5.2.5.txt
+100644 6195715dc78a26ce9ac452bd64852455fb79137c 0 Documentation/RelNotes-1.5.2.txt
+100644 7ff546c743b3ac2e75610473e496d93e44a6dbe9 0 Documentation/RelNotes-1.5.3.1.txt
+100644 4bbde3cab4dc6dc0815aeae5a0a79f88ab784b23 0 Documentation/RelNotes-1.5.3.2.txt
+100644 d2138469511d3dc111d81b9354f100ed344d9524 0 Documentation/RelNotes-1.5.3.3.txt
+100644 b04b3a45a5629cf852c970ac995bfb80bde846d2 0 Documentation/RelNotes-1.5.3.4.txt
+100644 7ff1d5d0d100fc632208f4cbb67189ecbf58e9a4 0 Documentation/RelNotes-1.5.3.5.txt
+100644 069a2b2cf9e9f28a2f9e6dc0817723a38b25f475 0 Documentation/RelNotes-1.5.3.6.txt
+100644 2f690616c8327f8c86477998358ee0dd17ee467f 0 Documentation/RelNotes-1.5.3.7.txt
+100644 0e3ff58a46f3cc2b987f9c3216e4844bab2317a5 0 Documentation/RelNotes-1.5.3.8.txt
+100644 d03894b92645f2dd0d7cb464d3ab1905d8cb62ed 0 Documentation/RelNotes-1.5.3.txt
+100644 d4e44b8b09d7176c137d826d5de305bd6822e862 0 Documentation/RelNotes-1.5.4.1.txt
+100644 21d0df59fbb08ab148e275e21f0ed182c5aab1a1 0 Documentation/RelNotes-1.5.4.2.txt
+100644 b0fc67fb2ade1c7e318d309ee4d55d37964021f3 0 Documentation/RelNotes-1.5.4.3.txt
+100644 89fa6d03bc038d6210e94d7fe9fbbffdbc84d883 0 Documentation/RelNotes-1.5.4.4.txt
+100644 02823413987d5a10364d936327e3a1cfb38cbac2 0 Documentation/RelNotes-1.5.4.5.txt
+100644 3e3c3e55a31fd7f6d51e1aa5a1d57532484dacaf 0 Documentation/RelNotes-1.5.4.6.txt
+100644 f1323b61746ee5d7f2a9d2fc3835c2cd75e76434 0 Documentation/RelNotes-1.5.4.txt
+100644 7de419708f77fff6f61e749b917b5fcecbe9a292 0 Documentation/RelNotes-1.5.5.1.txt
+100644 391a7b02eaf32d930e7c9c274dfd2a2edf081f75 0 Documentation/RelNotes-1.5.5.2.txt
+100644 f22f98b734f82101d47a6aa2453d5374d5dd8175 0 Documentation/RelNotes-1.5.5.3.txt
+100644 2d0279ecce622aab935e8e25914a5bd132fa95f3 0 Documentation/RelNotes-1.5.5.4.txt
+100644 30fa3615c77d6198a5a08ebd8e8c63f4cd21b295 0 Documentation/RelNotes-1.5.5.5.txt
+100644 29322124881bf65c3ee6f5d613251b09f4a98d9a 0 Documentation/RelNotes-1.5.5.txt
+100644 4864b16445f3ca1854cee608f7c15f5a6e0933d8 0 Documentation/RelNotes-1.5.6.1.txt
+100644 5902a85a78610ec38f4cf160ccd3c01267b4f9a1 0 Documentation/RelNotes-1.5.6.2.txt
+100644 942611299d59abd4bdd820e1258662067a304d62 0 Documentation/RelNotes-1.5.6.3.txt
+100644 d8968f1ecbd930463858870ee872efd8cb672bab 0 Documentation/RelNotes-1.5.6.4.txt
+100644 e143d8d61be1bb2fac024b5d5f270b33f4f898d4 0 Documentation/RelNotes-1.5.6.txt
+100644 2542cf53d2e40b06afe918fcf1cd35de19126d9e 0 Documentation/RelNotes-1.6.0.txt
+100644 841bead9db18a025638570c10cac72bcf4791f68 0 Documentation/SubmittingPatches
+100644 40d43b78ee9d6c3827bcf631c1f41f54d0e3dfbc 0 Documentation/asciidoc.conf
+100644 5428111d732cb38dbb257ddfa860ebd04088b4e9 0 Documentation/blame-options.txt
+100755 ba4205e0302a267a5da6bef504f3e69eb0c4aa6d 0 Documentation/build-docdep.perl
+100644 6a361a21367bfed4ae325049556f2e82e7e1dbe4 0 Documentation/callouts.xsl
+100755 dbc133cd3c1f19dd507014477e68b8ada78eab5e 0 Documentation/cat-texi.perl
+100755 04f99778d81def42e9e129b2f5b2b0551a0c760f 0 Documentation/cmd-list.perl
+100644 61c376057c0f2b9510bf6f1b2beb42f9859b7f46 0 Documentation/config.txt
+100644 400cbb3b1c120b93278472678ee7bdb87a74f95b 0 Documentation/diff-format.txt
+100644 517e1eba3c56907ebcb1d478dceb184e53fceda4 0 Documentation/diff-generate-patch.txt
+100644 cba90fd27c6a1baaca884328e96adc8a6da8fc36 0 Documentation/diff-options.txt
+100644 b878b385c6967f4c64ba30bdfe8f9bd24bef91e3 0 Documentation/docbook-xsl.css
+100644 9a6912c641edf52083b8996fdce3a0be2f4dba45 0 Documentation/docbook.xsl
+100644 e598cdda45cf0b953a106d6786765b3316e2cc16 0 Documentation/everyday.txt
+100644 d313795fdbc420e3395adc42aebe82fabda037d4 0 Documentation/fetch-options.txt
+100755 ff7d78f620a35fb66c47e50c4eceecff00b643b3 0 Documentation/fix-texi.perl
+100644 2b6d6c86547b2cec370d34b14ddef25264404892 0 Documentation/git-add.txt
+100644 c45c53ec2404725394563a9fba40f31cd314adb2 0 Documentation/git-am.txt
+100644 8b6b56a54409dd586047a1a6cdf1138e8bb0e77b 0 Documentation/git-annotate.txt
+100644 feb51f124ac8a806e65d41f6274c58de64d2991f 0 Documentation/git-apply.txt
+100644 c7a6e3ec050b7ceeec79d468b5ffa123314c8f5d 0 Documentation/git-archimport.txt
+100644 41cbf9c0819872a322321455b8a5cb805efcc26b 0 Documentation/git-archive.txt
+100644 c7981efcd9b86287bbea9ddcaf187a9bd48c77eb 0 Documentation/git-bisect.txt
+100644 fba374d652723161c3683d1be98c08ba573057cc 0 Documentation/git-blame.txt
+100644 6103d62fe3dca23c78b16dbdbb5ba231a6b39bf7 0 Documentation/git-branch.txt
+100644 1b66ab743c64d980a43a028d57ca2f6505d97845 0 Documentation/git-bundle.txt
+100644 d35e8a04fe28b095b5405ae2e0b09e3ab448bf63 0 Documentation/git-cat-file.txt
+100644 2b821f2a1d70fa108ce279135fd5028453a04fd9 0 Documentation/git-check-attr.txt
+100644 034223cc5ace81dd0b63da44d79db5e83a1d492a 0 Documentation/git-check-ref-format.txt
+100644 62d84836b8a0d77c2a6ea534566ff8462b0eb37a 0 Documentation/git-checkout-index.txt
+100644 5aa69c0e12a6756fd6f79c117008a373f65ba5f5 0 Documentation/git-checkout.txt
+100644 837fb08b7971a8b948dd7d039bab4a3c2e54cac7 0 Documentation/git-cherry-pick.txt
+100644 74d14c4e7fc88e702e4781b22eb8ed5ce0480c6f 0 Documentation/git-cherry.txt
+100644 670cb02b6cc035e4fbcf1a1016f66b7a85cd4ef7 0 Documentation/git-citool.txt
+100644 7dcc1ba58c3879cb14ce243a4af00bca9e850799 0 Documentation/git-clean.txt
+100644 26fd1b111798461b9150f1416721aa460f1ea525 0 Documentation/git-clone.txt
+100644 feec58400b64c65c8f96f2d1834016455c89829e 0 Documentation/git-commit-tree.txt
+100644 0e25bb862704eee4a22fe5349c04823d14ea9cba 0 Documentation/git-commit.txt
+100644 28e1861094a1689cdb042df6b1d788620ffdf213 0 Documentation/git-config.txt
+100644 75a8da1ca906aee4cc6a7d0c3ff19862b8e0fc2f 0 Documentation/git-count-objects.txt
+100644 2da8588f4fd6edb842a9824181165b3f043ec87b 0 Documentation/git-cvsexportcommit.txt
+100644 b7a8c10b8709108c1c8a0d14f661c179c2b4f22c 0 Documentation/git-cvsimport.txt
+100644 c2d3c90d27084e7de7e0f7c37b40f130f6960244 0 Documentation/git-cvsserver.txt
+100644 4ba4b75c1126d87c48935e7697e05f0d5210ad2d 0 Documentation/git-daemon.txt
+100644 7fdda04bae34790eb2345427dda746e8bf097c1a 0 Documentation/git-describe.txt
+100644 5c8c1d95a89b15e936816f486a8114cbc6788fb9 0 Documentation/git-diff-files.txt
+100644 26920d4f63cd213ff17ab28d8dd0dbea94482147 0 Documentation/git-diff-index.txt
+100644 8c8f35b7a762d42d3c45ff9f4eee1cb32d3917b6 0 Documentation/git-diff-tree.txt
+100644 c53eba557d0a242a0d8553d9569ce8b2eb86331b 0 Documentation/git-diff.txt
+100644 b974e2115b01f17f0ac809b691baf2f4e4d32169 0 Documentation/git-fast-export.txt
+100644 c2f483a8d2aed8dc017f3172e2d5fff4bed2c450 0 Documentation/git-fast-import.txt
+100644 47448da22eeebf51fe5829717df2dc7129a9b17e 0 Documentation/git-fetch-pack.txt
+100644 d3164c5c88db6b9e02a4186c398e19c425bc204b 0 Documentation/git-fetch.txt
+100644 7ba9dab5e6c0b32f927d24de800e17b71a06b84b 0 Documentation/git-filter-branch.txt
+100644 1c24796d66d5aeaeeccfd152c69cddba1953fd6c 0 Documentation/git-fmt-merge-msg.txt
+100644 727d84e6735417baa82fe7abff5b6945f6d6cef4 0 Documentation/git-for-each-ref.txt
+100644 010d9e432231f41a179023df2e85610583b572cf 0 Documentation/git-format-patch.txt
+100644 965a8279c1b17df6fbf82f4fbcadbd254049a7d5 0 Documentation/git-fsck-objects.txt
+100644 d5a76472196a5e67bc6e62411d90377ec3b46e3a 0 Documentation/git-fsck.txt
+100644 7086eea74a38b036130f61db362bae209a065e47 0 Documentation/git-gc.txt
+100644 84f23ee525336fc2bdd289991b97eafecddc14b2 0 Documentation/git-get-tar-commit-id.txt
+100644 fa4d133c1bccc088d3c8da65bce4e15cafd394aa 0 Documentation/git-grep.txt
+100644 0e650f497bd456e633334a91bd929053a08eb0d3 0 Documentation/git-gui.txt
+100644 ac928e198e75595a6fcd4e83b89aaf68987bd420 0 Documentation/git-hash-object.txt
+100644 f414583fc48e85e4785fbf5f9431bb81a96ccd9d 0 Documentation/git-help.txt
+100644 e7c796155fdd0ad644decf5dc488c6d780a2d164 0 Documentation/git-http-fetch.txt
+100644 aef383e0b142bd603b77620cad720c102d70c4b7 0 Documentation/git-http-push.txt
+100644 b3d8da33ee64730794821440c287f30c4bb85789 0 Documentation/git-imap-send.txt
+100644 4b5c743c1e5f11281e2b9df7508d57e9878ee5d2 0 Documentation/git-index-pack.txt
+100644 1fd0ff2610a1375bcf0defe2a234b2dee1a7997a 0 Documentation/git-init-db.txt
+100644 71749c09d309f4cae2da9788969359d2620224a9 0 Documentation/git-init.txt
+100644 22da21a54f625c434216945889127ec283d3d09f 0 Documentation/git-instaweb.txt
+100644 05cbac56aced6ad27f36fe63f8f536e794794f9f 0 Documentation/git-log.txt
+100644 602b8d5d4de8f7649cb88e6622108c012f484933 0 Documentation/git-lost-found.txt
+100644 9f85d60b5fb6d6ae1b4d8c2e65a6131cbe21450b 0 Documentation/git-ls-files.txt
+100644 abe7bf9ff9eb9a3ddb1924938de071291520797a 0 Documentation/git-ls-remote.txt
+100644 4c7262f1cd82ca8d9ea6be638d23b18d9bba3738 0 Documentation/git-ls-tree.txt
+100644 31eccea5bc0697ee461503734942429c2133ef3f 0 Documentation/git-mailinfo.txt
+100644 5cc94ec53daf3057f57c993983d659543962abec 0 Documentation/git-mailsplit.txt
+100644 1a7ecbf8f39381b0c7b2da513dfa26eacec15cf6 0 Documentation/git-merge-base.txt
+100644 024ec015a3a3e0d3677a82e082e72a36c4572827 0 Documentation/git-merge-file.txt
+100644 ff088c5c294527dd97c542012483aafe3ca64314 0 Documentation/git-merge-index.txt
+100644 dc8a96adb00c0b674e12e071a4a56f89bfe8583d 0 Documentation/git-merge-one-file.txt
+100644 dbb0c18668ff0fb60c31c12b02c27d92b430c24a 0 Documentation/git-merge-tree.txt
+100644 2db88809898592c691166427efdd106d844d42d9 0 Documentation/git-merge.txt
+100644 31570b1e27af6a603df98868c627da08d91c17cc 0 Documentation/git-mergetool.txt
+100644 8bcc11443dce7322ac5b0fa70e07b2465f762615 0 Documentation/git-mktag.txt
+100644 af19f06ed738bdecc7ab9a72a5c9a216b816f4c2 0 Documentation/git-mktree.txt
+100644 9c5660275b326661bf7dc9a5162e5177b8a62b0f 0 Documentation/git-mv.txt
+100644 6e77ab135353aaf713b638a70701717db1706c2c 0 Documentation/git-name-rev.txt
+100644 8c354bd47014825de71243d73158b6b080ecb350 0 Documentation/git-pack-objects.txt
+100644 5f9435e59b49fec1e37c65f1bfdc38be3704c4e5 0 Documentation/git-pack-redundant.txt
+100644 a5244d35f49f10b7954d8fa52164663e3d167d4b 0 Documentation/git-pack-refs.txt
+100644 cd43069874d59504627211e011250a3554aeee5a 0 Documentation/git-parse-remote.txt
+100644 477785e13418e1971156f5210015da4ab9d77cab 0 Documentation/git-patch-id.txt
+100644 8282a5e82b6e897ac501ef05c982d5e69415363f 0 Documentation/git-peek-remote.txt
+100644 b5f26cee132622185457d92522fb932302dec97d 0 Documentation/git-prune-packed.txt
+100644 54f1dab38de9e01d8452753ac6028875b91d5f6b 0 Documentation/git-prune.txt
+100644 7578623edba9e2ddc5232f1a981bcb297182638d 0 Documentation/git-pull.txt
+100644 050c3ddae2732fdf4cb9f3b0f798e3d2d190fa4e 0 Documentation/git-push.txt
+100644 d4037de5124010e9c90dcc97e8b64e6011dbed21 0 Documentation/git-quiltimport.txt
+100644 6f4b9b017f7b504a2b9e909639a61b1ef7750af0 0 Documentation/git-read-tree.txt
+100644 59c1b021a6c410e1097df21d6d47365aec6689e2 0 Documentation/git-rebase.txt
+100644 6b2f8c4de7c32927f270e561362d4766193986fa 0 Documentation/git-receive-pack.txt
+100644 d99236e14d5238c936304029bd48efc6ac9dd024 0 Documentation/git-reflog.txt
+100644 25ff8f9dcbe0db52675338f1429e9169052b9cf1 0 Documentation/git-relink.txt
+100644 bb99810ec76f93ff1cdc59aacdf592c64419701a 0 Documentation/git-remote.txt
+100644 38ac60947bc6c4cbfc8aae70a92f9163fefed442 0 Documentation/git-repack.txt
+100644 e5bdb5533e61687874ad36d30534b2ac9e58d7cb 0 Documentation/git-repo-config.txt
+100644 19335fddae2b706cd785258a8c02a5595c525667 0 Documentation/git-request-pull.txt
+100644 89f321b414212a555f1e0fb0ff0ce6f4c180fd06 0 Documentation/git-rerere.txt
+100644 6abaeac28cb70bcff809c803d732f79630c8046f 0 Documentation/git-reset.txt
+100644 fd1de92e34b459cdc89928e1561ee6934cd63c19 0 Documentation/git-rev-list.txt
+100644 2921da320d2b84df4d15ec2745e6d94093dd6907 0 Documentation/git-rev-parse.txt
+100644 98cfa3c0d0f27e0cb603f07c76285f85ef07a771 0 Documentation/git-revert.txt
+100644 4d0c495bc3ecb5482165a46956efe73dfdc5ee72 0 Documentation/git-rm.txt
+100644 afbb294a7faadc7ff6d4039246dc1c085575cd4f 0 Documentation/git-send-email.txt
+100644 399821832c2a5cd6a718a7dc37a87e6b5bc0b213 0 Documentation/git-send-pack.txt
+100644 18f14b5be89b4e0240f59b13313308f3c09d012c 0 Documentation/git-sh-setup.txt
+100644 ff420f8f8c52eb598976a134916000da9b8f3976 0 Documentation/git-shell.txt
+100644 7ccf31ccc401fd35a0ed65667be001805436249b 0 Documentation/git-shortlog.txt
+100644 d3f258869f5d441bea16b46d8030eb64ecb7df99 0 Documentation/git-show-branch.txt
+100644 e3285aacfd310cc269cdb03aa9243c939c24def7 0 Documentation/git-show-index.txt
+100644 9a4389981ca067633d773e28393a1d72ac6552ae 0 Documentation/git-show-ref.txt
+100644 1642cfd8236a5b57420f67da580b42066afaa4f6 0 Documentation/git-show.txt
+100644 7d50d74cc9a945f0dd82b0c26509bf0392eff837 0 Documentation/git-stash.txt
+100644 84f60f3407499c40a8e0caadf9d40ed5e9b8386b 0 Documentation/git-status.txt
+100644 7508c0e42d2cd50ac522fc80a3a866411b7b51c5 0 Documentation/git-stripspace.txt
+100644 35efeefb3056ac69cf02689dc338956340e9efc9 0 Documentation/git-submodule.txt
+100644 f230125a81baab9f13bf84e3543b63fc77a8e827 0 Documentation/git-svn.txt
+100644 210fde03a12cd757769f81754e789a2a5934f02c 0 Documentation/git-symbolic-ref.txt
+100644 046ab3542bab4048fe07c8a6718d63f9cd9e3791 0 Documentation/git-tag.txt
+100644 a5d9558dd1eabd71e838026721d707c5f1ecc369 0 Documentation/git-tar-tree.txt
+100644 a96403cb8cb720dbf094b06a0dc0b430147298fc 0 Documentation/git-tools.txt
+100644 995db9feadf68df6f22de745d90790a145128e44 0 Documentation/git-unpack-file.txt
+100644 36d1038056101a459a33e32b6729d75e03f127ce 0 Documentation/git-unpack-objects.txt
+100644 1d9d81a702d26706047ae6ea29b4ca62ebe59460 0 Documentation/git-update-index.txt
+100644 9639f705afafab6fcf0cd21ad2693627ab42f66d 0 Documentation/git-update-ref.txt
+100644 35d27b0c7f0e4b7a1d0851140958e71fabb0e6bc 0 Documentation/git-update-server-info.txt
+100644 bbd7617587084b0c66fd8e0b9f623cac50be2c03 0 Documentation/git-upload-archive.txt
+100644 b8e49dce4a19a4d7083459468f27c273c1d91fea 0 Documentation/git-upload-pack.txt
+100644 3647dd6c8f9c74a688f7a143119386ba89a8f13d 0 Documentation/git-var.txt
+100644 c8611632d1d501d57eb7000de0ec3c3b36810b80 0 Documentation/git-verify-pack.txt
+100644 ba837df4bc66e2b828fcd49c94f35957c27322df 0 Documentation/git-verify-tag.txt
+100644 36afad8d4e0d67a8d9dd33d3bc590789e9f6604d 0 Documentation/git-web--browse.txt
+100644 cadfbd90403766d44598c8d96d89dc5a0e4e2ef8 0 Documentation/git-whatchanged.txt
+100644 26d3850e7317c22dcf0999e0c4a6afe9a5ea2e03 0 Documentation/git-write-tree.txt
+100644 44ea35e949dbbc0e5785ba2831072059881058f8 0 Documentation/git.txt
+100644 d7b41142d2c843bc5460f03c73c609b1c53ff4a6 0 Documentation/gitattributes.txt
+100644 29e5929db22257346a2bed16cbd5ca6531698676 0 Documentation/gitcli.txt
+100644 49179b0a00fad1ecda1fdf0537ccbce77f5fc494 0 Documentation/gitcore-tutorial.txt
+100644 aaa7ef737a4c190c60e37e2849ce42f3bdb5dda7 0 Documentation/gitcvs-migration.txt
+100644 2bdbc3d4f6a97c1a1d970f0c5f27222ef9e31274 0 Documentation/gitdiffcore.txt
+100644 565719ed5f8516e17229ec11bbec5e1354580397 0 Documentation/gitglossary.txt
+100644 046a2a7fe7cf8ec301d3a20f7ebc587a09d210e3 0 Documentation/githooks.txt
+100644 59321a2e82b1e141746d94c439452b52b84994ad 0 Documentation/gitignore.txt
+100644 e02ecf57444df14d61d82dcf2f9e0c3f6b990b91 0 Documentation/gitk.txt
+100644 f8d122a8b90ca7cb4920768ca23fd9a27574ffdf 0 Documentation/gitmodules.txt
+100644 a969b3fbc3efc99ce490455b93c8bfb912994e2e 0 Documentation/gitrepository-layout.txt
+100644 660904686c656fd00078aa272d0b9a5a198e1833 0 Documentation/gittutorial-2.txt
+100644 48d1454a90cf9453e5e3c9fa01b3dbc369a58f1f 0 Documentation/gittutorial.txt
+100644 9b4a4f45e900a96c4ddeb214816877f39cca15a5 0 Documentation/glossary-content.txt
+100755 34aa30c5b9ffc617e1519878317c2ae83bed6a6a 0 Documentation/howto-index.sh
+100644 4357e269131fad960367534ae4161fe078fee30a 0 Documentation/howto/maintain-git.txt
+100644 554909fe08de380aa02f2bf37f0f3b43b0233f4b 0 Documentation/howto/rebase-and-edit.txt
+100644 d214d4bf9d0e539c6bf58ba24dcd12aabbaea1d8 0 Documentation/howto/rebase-from-internal-branch.txt
+100644 48c67568d3418b2d6608f362f4b76e02ec450abc 0 Documentation/howto/rebuild-from-update-hook.txt
+100644 323b513ed0e0ce8b749672f589a375073a050b97 0 Documentation/howto/recover-corrupted-blob-object.txt
+100644 e70d8a31e7b05e8efc70c6a56f476324065d57a6 0 Documentation/howto/revert-branch-rebase.txt
+100644 6d3eb8ed00e1779efce8abe201d37c8cff07ec29 0 Documentation/howto/separating-topic-branches.txt
+100644 40327486084ac02874faff70fd100b619af83214 0 Documentation/howto/setup-git-server-over-http.txt
+100644 697d9188850e9a685045da5bd37844b02978752d 0 Documentation/howto/update-hook-example.txt
+100644 4e2f75cb6167633c97ec1981d2b6659368cc0170 0 Documentation/howto/use-git-daemon.txt
+100644 0953a50b693307976977c81a4c0b611fd5dfb490 0 Documentation/howto/using-merge-subtree.txt
+100644 fb0d7da56b902217f8f1f4d4bc85186d6bf0dc4c 0 Documentation/i18n.txt
+100755 35f440876ed182de319b6d3f0b8296b1a1ede29d 0 Documentation/install-doc-quick.sh
+100755 2135a8ee1f4f56a8c799437949ba76d7526164c0 0 Documentation/install-webdoc.sh
+100644 4065a3a27a38be73132b9f509e1d63546b3fddef 0 Documentation/manpage-1.72.xsl
+100644 48ce747cf4dad592d642735856eb156e93d6cf30 0 Documentation/merge-config.txt
+100644 007909a82fe77325e46c54799d00dc78493a47f9 0 Documentation/merge-options.txt
+100644 1276f858ade29bec40716d19cf56fe6e3882fc25 0 Documentation/merge-strategies.txt
+100644 c11d4957714db202a012209e2437b9e050a28ae0 0 Documentation/pretty-formats.txt
+100644 6d66c74cc11e6622892061f8328d04dfe38f87bf 0 Documentation/pretty-options.txt
+100644 00a8d210476089257be3d09ac8a16d1f8e1dd8dc 0 Documentation/pull-fetch-param.txt
+100644 3aa38097e6350a02c50873d5c670e108003fab22 0 Documentation/rev-list-options.txt
+100644 8aa891daee050f03cf265a6ea991ff9ebb60815e 0 Documentation/technical/.gitignore
+100644 43dbe09f735525b0a1549ccfb4de2f2ca87252a0 0 Documentation/technical/api-allocation-growing.txt
+100644 7ede1e64e5d40ec8f742e900d7273d6f961605e2 0 Documentation/technical/api-builtin.txt
+100644 1d52a6ce14416c7308f6c2c5d6a3dd2a43184e91 0 Documentation/technical/api-decorate.txt
+100644 20b0241d30026747391fa4b6b38de5cf959cee70 0 Documentation/technical/api-diff.txt
+100644 5bbd18f0206604416c3833b7541a5b55b7e63976 0 Documentation/technical/api-directory-listing.txt
+100644 9d97eaa9dee99eef7e66072c4c51cfff3000bba3 0 Documentation/technical/api-gitattributes.txt
+100644 a69cc8964d585db41b1907a8ce7cb8d0a9511ef2 0 Documentation/technical/api-grep.txt
+100644 c784d3edcb2537b84bfb5db3da55faaf45995155 0 Documentation/technical/api-hash.txt
+100644 e9559790a32185b1d4ac8ae72881f4f63f082538 0 Documentation/technical/api-history-graph.txt
+100644 adbdbf5d75d8e17e38e1ba0e3694b4ff210f5799 0 Documentation/technical/api-in-core-index.txt
+100644 af7cc2e395f1399830f9eacc52468376b216fb86 0 Documentation/technical/api-index-skel.txt
+100755 9c3f4131b8586408acd81d1e60912b51688575ed 0 Documentation/technical/api-index.sh
+100644 dd894043ae8b04269b3aa2108f96cb935217181d 0 Documentation/technical/api-lockfile.txt
+100644 03bb0e950dd1616b00f950f83263835c57bfa70a 0 Documentation/technical/api-object-access.txt
+100644 539863b1f920f8f34ad9272907cbacbd35a7fcbd 0 Documentation/technical/api-parse-options.txt
+100644 e8a1bce94e05f06c5b2aa51d2b610fb9da15d0bb 0 Documentation/technical/api-quote.txt
+100644 073b22bd83badb5aada47e061bb29e48d5f95518 0 Documentation/technical/api-remote.txt
+100644 996da0503acfa3e3a0ed0f57a951d0fbc1500fb8 0 Documentation/technical/api-revision-walking.txt
+100644 75aa5d49234ec36857a7c8d2f3900001af5cbcde 0 Documentation/technical/api-run-command.txt
+100644 4f63a04d7db0e7b578c5034c2856ba95a7ef5739 0 Documentation/technical/api-setup.txt
+100644 a9668e5f2d2b1a7ffac45e4111ca6d8a4818af2b 0 Documentation/technical/api-strbuf.txt
+100644 293bb15d206e71f57e906b33ca27ee05e3429521 0 Documentation/technical/api-string-list.txt
+100644 e3ddf912841298d6317a682a29cbaf628e86f156 0 Documentation/technical/api-tree-walking.txt
+100644 6296ecad1d65511f943fcd82ded188954a33b052 0 Documentation/technical/api-xdiff-interface.txt
+100644 1803e64e465fa4f8f0fe520fc0fd95d0c9def5bd 0 Documentation/technical/pack-format.txt
+100644 103eb5d989349c8e7e0147920b2e218caba9daf9 0 Documentation/technical/pack-heuristics.txt
+100644 9cd48b48597f9b7e822fc3d81e0bc556d6631b02 0 Documentation/technical/pack-protocol.txt
+100644 6bdf034b3af55c8d881fee9153d5cd1824660692 0 Documentation/technical/racy-git.txt
+100644 681efe42190fa28f8e6bc8f1eb569bfcf160ed4b 0 Documentation/technical/send-pack-pipeline.txt
+100644 559263af485f139d6c33d982bed9342aa4110e50 0 Documentation/technical/shallow.txt
+100644 24c84100b0790be22330464e01ea876e5d30fc9a 0 Documentation/technical/trivial-merge.txt
+100644 504ae8a53bca42d7c9ec560b65ddfe14699387a4 0 Documentation/urls-remotes.txt
+100644 fa34c6747194aaecf9e8124462129b8bbc9ae7d4 0 Documentation/urls.txt
+100644 339b30919e6cd9791a5cc30b93395a88fb5e9d96 0 Documentation/user-manual.conf
+100644 00256ca57cc7453ef4a0dce90169078ee96e95e3 0 Documentation/user-manual.txt
+100755 cb7cd4b53827fa6820e84b1318572d0115b3b17f 0 GIT-VERSION-GEN
+100644 7d0c2c2f865d6ed969038e7543dbeb8933723ec3 0 INSTALL
+100644 52c67c1a472455dcce5c19a21bbfd0520ff7dd26 0 Makefile
+100644 548142c327a6790ff8821d67c2ee1eff7a656b52 0 README
+120000 b9a53c3416991b66e1d35c2bbf663b48340b0041 0 RelNotes
+100644 0d561246e0a958d9a7284409b1900a82876eebf3 0 abspath.c
+100644 ccb1108c94436035d0da8b1d6f08f859b68294a3 0 alias.c
+100644 216c23a6f854c614d38c743cd7687a37f304161b 0 alloc.c
+100644 13029619e5ec34bac4ba61a6fc08800ab36f4a1b 0 archive-tar.c
+100644 cf285044e3576d0127c3215cb1253443d67517dc 0 archive-zip.c
+100644 f834b5f51f4cf5d3b73d21dfd99198caef3b19f8 0 archive.c
+100644 0b15b35143fffcc13764e4e668ee452b191cc609 0 archive.h
+100644 9e3ae038e818f4e21bc50f864fc5204f6fa44daa 0 arm/sha1.c
+100644 3952646349cf9d033177e69ba9433652a378c0e9 0 arm/sha1.h
+100644 8c1cb99fb403875af85e4d1524d21f7eb818f59b 0 arm/sha1_arm.S
+100644 17f6a4dca521d9690377f2e93a0192d8a874d2ad 0 attr.c
+100644 f1c2038b0923d3130937eef965667204a8634e6d 0 attr.h
+100644 b88270f90844095b3d352cc4213cbebd95a7f420 0 base85.c
+100644 bd7d078e1ae5fe4ce0a16fda62a2c1743237941b 0 blob.c
+100644 ea5d9e9f8b63be2c7048d19ee53feb06b0795c80 0 blob.h
+100644 b1e59f2196b933ab7169a30efc5d1d340f8f9c5c 0 branch.c
+100644 9f0c2a2c1fab9a312f436880956da0973c68ead8 0 branch.h
+100644 fc3f96eaefff91e4e85adb92162716939f0ecd72 0 builtin-add.c
+100644 fc43eed36b55e4966796490b8c0a02fae790229c 0 builtin-annotate.c
+100644 2216a0bf7cd53adc31346f66a3b9786a1d688bad 0 builtin-apply.c
+100644 22445acbfc5279f391ac6afa855b21064ec54535 0 builtin-archive.c
+100644 8b6b09b10b8f9dcda0b7224f31c860bb803945f0 0 builtin-blame.c
+100644 b1a2ad7a6b3b150cda8d031a87352a4daedc40ea 0 builtin-branch.c
+100644 ac476e7a4b45fc55b6b6d1e4d02be0c35aba2c7b 0 builtin-bundle.c
+100644 7441a56acdbefdd8044a406f4d756ce8a4f06644 0 builtin-cat-file.c
+100644 cb783fc77e75515a02ed2268dfb37ee3bbd03749 0 builtin-check-attr.c
+100644 fe04be77a9312c11fa054897c5982fa6c74b8e5e 0 builtin-check-ref-format.c
+100644 71ebabf9903bd90b7da59c47f1c0819b5f25c538 0 builtin-checkout-index.c
+100644 411cc513c65ba854221ad52dd6aeaaac7d213c9d 0 builtin-checkout.c
+100644 48bf29f40a5e06fd588b34c468535e04abcf206b 0 builtin-clean.c
+100644 e086a40b41810c30a4f5228daa4e38857dae84d5 0 builtin-clone.c
+100644 7a9a309be0543da7d27e7710ef82271f2582e0a9 0 builtin-commit-tree.c
+100644 f7c053a0106c2e42833d0d7c7255b7b636d09a93 0 builtin-commit.c
+100644 91fdc4985d8e64fae12209174dd4aa2d887793e5 0 builtin-config.c
+100644 91b5487478998e39bb8ae4a5cb667360cff82c9a 0 builtin-count-objects.c
+100644 ec404c839b6542deb4e15ca342fd3c0afbbedd2e 0 builtin-describe.c
+100644 9bf10bb37e2f56ec2a10239d7419db8fbb641745 0 builtin-diff-files.c
+100644 17d851b29ee5de33e01745eabcd5cd735c30b352 0 builtin-diff-index.c
+100644 415cb1612f5322da89850874ba81885e41808678 0 builtin-diff-tree.c
+100644 7ffea975059f9e13b07ca680e6707ffc14973f90 0 builtin-diff.c
+100644 070971616dbb12d005c5c9a1f82cc5b0c5391f62 0 builtin-fast-export.c
+100644 7460ab7fce2a4e6a7e014f448819140e2204ccb7 0 builtin-fetch--tool.c
+100644 273239af3be61736ee4ff484d628950c4de7311a 0 builtin-fetch-pack.c
+100644 7eec4a0e43ad5760f1060a7d5bcf2a5083015130 0 builtin-fetch.c
+100644 df02ba7afdd615492361a1897a9dedd6ab233c96 0 builtin-fmt-merge-msg.c
+100644 445039e19c75e4c9321f7ee64289ef8201a25c14 0 builtin-for-each-ref.c
+100644 6eb7da88d3e8591a8c544acc61a42e00babff120 0 builtin-fsck.c
+100644 fac200e0b08360625afc81b02913128c9b87f486 0 builtin-gc.c
+100644 631129ddfd0ffe06f919882d22cfc494d9553f50 0 builtin-grep.c
+100644 3a062487a7eacd01ed824b46a9124dd343cd2e60 0 builtin-http-fetch.c
+100644 baf0d09ac4ea372b4015d399560a133b401b55cc 0 builtin-init-db.c
+100644 f4975cf35f7f1555739f7657ee62ed983d18cb84 0 builtin-log.c
+100644 e8d568eed7ab700bc338af8f589d2f61e81f323c 0 builtin-ls-files.c
+100644 c21b841e7c5e8d27a6e66e7f70786d77aa4653b5 0 builtin-ls-remote.c
+100644 d25767a1f7eb0a8b45bc1eed6b9aa95de0847f18 0 builtin-ls-tree.c
+100644 f974b9df968c74c5d62d58b2a09493e6abb4322e 0 builtin-mailinfo.c
+100644 71f3b3b8741e505fc652e6c74c75972f19211f71 0 builtin-mailsplit.c
+100644 3382b1382a7dcbd525126a35209072da4b4d8041 0 builtin-merge-base.c
+100644 3605960c2d9692514a6df0f344f3c3269cf1de3c 0 builtin-merge-file.c
+100644 8f5bbaf402e020e308e7af9cedb7df1b2ec5a2b7 0 builtin-merge-ours.c
+100644 43e55bf90154c51b94527b2ab7eb7c60fe36e9ec 0 builtin-merge-recursive.c
+100644 dde0c7ed33118ff8d0cc421e8a0366e342c6d011 0 builtin-merge.c
+100644 4f65b5ae9baf66953e79886fd93fe31786b24d36 0 builtin-mv.c
+100644 85612c4dcb719b460623204046e35486e9d9fe97 0 builtin-name-rev.c
+100644 2dadec1630c266bbaf42e84810f7059ed5c43b1e 0 builtin-pack-objects.c
+100644 34246df4ec946273d9f42e6f0848b02d8510beea 0 builtin-pack-refs.c
+100644 10cb8df8457fd5f2ba9be62ecd0f9384e21c3e63 0 builtin-prune-packed.c
+100644 947de8cf258c73d8a327ef3a1daed417ba533f1b 0 builtin-prune.c
+100644 c1ed68d938f67343c6938cfef54d5ff69a522a63 0 builtin-push.c
+100644 72a6de302f88728af17ce5c5c6983c5267afc6f6 0 builtin-read-tree.c
+100644 0c34e378199064e87aa09caf0fa0a2346333ec69 0 builtin-reflog.c
+100644 54d1c3e3d16b2cebcff0c6c57d98756e48472b67 0 builtin-remote.c
+100644 dd4573fe8dcd9dc8edd5a7d41bc8daa83034ee7e 0 builtin-rerere.c
+100644 c24c21909194014b467c86fd3598796e7db576b3 0 builtin-reset.c
+100644 893762c80f4910fadf2d6df414bd835cccb7faaa 0 builtin-rev-list.c
+100644 9aa049ec170b0125fddde29adda3c720c8a7b8ee 0 builtin-rev-parse.c
+100644 e9da870d22c14c32a0e0a6cb71b933c79a2d8b53 0 builtin-revert.c
+100644 ee8247b08cd007f73d5dfffa560a9efe33d327b9 0 builtin-rm.c
+100644 7588d22885d0af24ae80f1d687ccd097fe365021 0 builtin-send-pack.c
+100644 d03f14fdad3d17dde06734d78ddb4aade6ed4f2b 0 builtin-shortlog.c
+100644 233eed499d0b8790781326ff0455bdc7f09fe4d4 0 builtin-show-branch.c
+100644 add16004f11375b1ad2b97f9b1bf1ced5c437f81 0 builtin-show-ref.c
+100644 c0b21301ba4c126a49ed38b6983756b99a25aae0 0 builtin-stripspace.c
+100644 bfc78bb3f6eff2f8e39649b9649ae7263f143ad9 0 builtin-symbolic-ref.c
+100644 325b1b2632e44121c23bc6df556bf3aa4e32ba04 0 builtin-tag.c
+100644 f4bea4a322c26a54734286073c5e67444555c2d9 0 builtin-tar-tree.c
+100644 a8918666655bb91f952ccdac18715bd9ba4a09f2 0 builtin-unpack-objects.c
+100644 38eb53ccba2b97a0fccf50d6ba0b7424fe2d1bcb 0 builtin-update-index.c
+100644 56a0b1b39cf4c4fc51dbbff256240655bc36a038 0 builtin-update-ref.c
+100644 a9b02fa32f372a6810867c10560a20d58b5b2a91 0 builtin-upload-archive.c
+100644 f4ac595695b1fff1317ff7d14ea9427780327aea 0 builtin-verify-pack.c
+100644 729a1593e61d87ad4596f07e7faedac81de64e81 0 builtin-verify-tag.c
+100644 52a3c015ff8e4611522bd41078bdb2934d288d35 0 builtin-write-tree.c
+100644 f3502d305e4f65e9707fe8b738f64be6e49f7f84 0 builtin.h
+100644 00b2aabefca49b634f49143523ee31556baa7777 0 bundle.c
+100644 e2aedd60d6ad1482bb6da173c853e6ba4805c8d7 0 bundle.h
+100644 5f8ee87bb1c446341b640c2f978a658d6bfcfcd0 0 cache-tree.c
+100644 cf8b790874c4a4f5890b360c237ccdd4a5a03de4 0 cache-tree.h
+100644 2475de9fa837596303284157e08b3080d64351ee 0 cache.h
+100755 d6fe6cf1749ebcd6189fa36cbb4e14a532d2d17b 0 check-builtins.sh
+100644 00d92a16631a80ff8ec4e995dafcd3e55434fad5 0 check-racy.c
+100755 a1c4c3e8d845e8e791d7df0c1387e1b2262b5ecf 0 check_bindir
+100644 fc0b72ad59b13e4bd86372e5e81b4f400c99d26e 0 color.c
+100644 6cf5c88aaf8d0e38e2853e6fd212e3cdd6c180cb 0 color.h
+100644 9f80a1c5e3a461afd11966625589684d61187911 0 combine-diff.c
+100644 3583a33ee90647d8e6ded02643eb75753760d94f 0 command-list.txt
+100644 dc0c5bfdab7296bf7febb6f1b1aad64550838c15 0 commit.c
+100644 77de9621d9c926c6fb8a2bf9ca81c6c376a2ad41 0 commit.h
+100644 1f4ead5f981688ee9e29ae2ee281e3904c9131f6 0 compat/fnmatch.c
+100644 cc3ec379400e9334a37cf3f07a61a77f264da885 0 compat/fnmatch.h
+100644 b5ca142fedf2ac0e0cedde1011ab385f65010fdf 0 compat/fopen.c
+100644 069c555da47ea168eea937fcc2d788294bf92ef5 0 compat/hstrerror.c
+100644 f44498258d4c2a0ebd1379ed818d9d04b56f0761 0 compat/inet_ntop.c
+100644 4078fc0877ca99c82152acdd6b7a9eef70a9f8a4 0 compat/inet_pton.c
+100644 cd0d8773641f2fdc808d8b246a8dd2bcd0e5814d 0 compat/memmem.c
+100644 772cad510d5d260fdf33b4f7d6ff79f9f3367b05 0 compat/mingw.c
+100644 290a9e6f822df97984b9f769508aab36419eaf02 0 compat/mingw.h
+100644 34d4b49818b0896b9db19b2b1387f142cbbbd42b 0 compat/mkdtemp.c
+100644 c9d46d174259f42a3e2a2eb073475aba517044be 0 compat/mmap.c
+100644 978cac4ec91e6bb2f81539d85422bb37e4941a51 0 compat/pread.c
+100644 d93dce2cf8fa33bd1fbefe131d2e41a6b954da61 0 compat/qsort.c
+100644 87b33e46697b9a5dd9a9e8391ca3607f7e2ff569 0 compat/regex.c
+100644 6eb64f14020db0a20ba596de5b58b3c552157f16 0 compat/regex.h
+100644 3a22ea7b751efb768d72afa2f97fd963e10eec7e 0 compat/setenv.c
+100644 580966e56a3455b9970b7eef33143c1e9c57d41c 0 compat/snprintf.c
+100644 26896deca64c531f57b4c48ea92134f876b8e537 0 compat/strcasestr.c
+100644 4024c360301ebe7d58ac5b84dcbb692341b649ed 0 compat/strlcpy.c
+100644 5541353a77a22d48ccebd20ede2f510ae20d1492 0 compat/strtoumax.c
+100644 eb29f5e0849370afe90c400271fea12e0f9090aa 0 compat/unsetenv.c
+100644 e2d96dfe6f75213de567174261d9aeba3e663d9d 0 compat/winansi.c
+100644 53f04a076a7275965090edd4ca2a34652c4f5679 0 config.c
+100644 b776149531025c85f5665d971e6e072f0cc64893 0 config.mak.in
+100644 7c2856efc92ca55e3cf03fcf1c72ffb70318f7c3 0 configure.ac
+100644 574f42fa47ffa69328217eb25afee6f85db9595e 0 connect.c
+100644 05f291c1f1d3d1018f390618816f94d0cd58951b 0 contrib/README
+100644 fada5ce909876168f68a85c8ca9a8bc269048acb 0 contrib/blameview/README
+100755 1dec00137b2dd8a888a962edd62f01aad89e4186 0 contrib/blameview/blameview.perl
+100755 30d870187e64e33ed430dc1fab1ea37036a07f58 0 contrib/completion/git-completion.bash
+100644 4009a151deceb45030fb26c5bfcf1b75a423a493 0 contrib/continuous/cidaemon
+100644 b8f5a609af464f3af8b624246cc69eb335ce81d1 0 contrib/continuous/post-receive-cinotify
+100644 90e7900e6d7aff2fadf9ba04f8d982733493411c 0 contrib/convert-objects/convert-objects.c
+100644 9718abf86d8cd36ddae1eae8cf2337e35b927959 0 contrib/convert-objects/git-convert-objects.txt
+100644 c531d9867f6c223be1daf0f6da7538feb11966d8 0 contrib/emacs/.gitignore
+100644 a48540a92b4aa5140a87469b36c1f9b3d8e46e7f 0 contrib/emacs/Makefile
+100644 4fa70c5ad47fcd717d9cbdb23a8142f89227f630 0 contrib/emacs/git-blame.el
+100644 c1cf1cbcc014e5d6c01a1c33efa2d7bd3b76df88 0 contrib/emacs/git.el
+100644 b8f6be5c0af64dfbe7e136f984404f22aea68130 0 contrib/emacs/vc-git.el
+100755 1a7689a48f07a6ed2bb156f745bfea19a10e3eb9 0 contrib/examples/git-checkout.sh
+100755 01c95e9fe8a19afcf331ed5ffd47eea478886213 0 contrib/examples/git-clean.sh
+100755 547228e13ce60e575d0b4a10a322edfff6c0622c 0 contrib/examples/git-clone.sh
+100755 2c4a4062a5317c51601fc4c644c96a7f75e1ef2c 0 contrib/examples/git-commit.sh
+100755 e44af2c86d8e7e44bc79aafcc8ccef3806804720 0 contrib/examples/git-fetch.sh
+100755 1597e9f33f5e001995085639a448f1214010b561 0 contrib/examples/git-gc.sh
+100755 fec70bbf88c614a2dadfc40950fdd7abdf7f2c63 0 contrib/examples/git-ls-remote.sh
+100755 29dba4ba3a57c15bd430bd23c1cebe78e6dc03be 0 contrib/examples/git-merge-ours.sh
+100755 e9588eec33ba5b64d186ff048bb040c18c57e6bc 0 contrib/examples/git-merge.sh
+100755 36bd54c985080f8dd5558a3e7a4e19ede9fbab93 0 contrib/examples/git-remote.perl
+100755 4f692091e73bf633cf986ba2c9bed38bc2c78538 0 contrib/examples/git-rerere.perl
+100755 bafeb52cd113ad8a07ffd1912191f2bc17a7ef7a 0 contrib/examples/git-reset.sh
+100755 0ee1bd898ecbb725d13385408b4ed4bcb413f503 0 contrib/examples/git-resolve.sh
+100755 49f00321b28833c24ebb78ea2104f34091d43017 0 contrib/examples/git-revert.sh
+100755 a13bb6afec2fe5e0b5249523ec8c62d8e517de88 0 contrib/examples/git-svnimport.perl
+100644 71aad8b45bd4c5f59c2ce3746cb3299821729c2a 0 contrib/examples/git-svnimport.txt
+100755 e9f3a228af472c932f6cec5fa25ae49cd841b239 0 contrib/examples/git-tag.sh
+100755 0902a5c21adc4123e36856f73acc1409e17eb0ac 0 contrib/examples/git-verify-tag.sh
+100755 f9fef6db28dbba0ef67589f05eeb937760d2facf 0 contrib/fast-import/git-import.perl
+100755 0ca7718d0518db2e559ecd17eb6f7f57338b80fd 0 contrib/fast-import/git-import.sh
+100755 6ae0429c2dde435f8ae33991ad10f40485aefdc6 0 contrib/fast-import/git-p4
+100644 9f97e884f5c3cae9e89164c9590959ba487a89bd 0 contrib/fast-import/git-p4.bat
+100644 b16a8384bcfbfe33dc33e1076c64f5d36e75e803 0 contrib/fast-import/git-p4.txt
+100755 23aeb257b9557cb146586868084ce1b20d7e7ac8 0 contrib/fast-import/import-tars.perl
+100755 c674fa2d1b5c6ab47ebb5e828c427c6d47bb50fc 0 contrib/fast-import/import-zips.py
+100755 4c99dfb9038ca034d86b72cbe342373d12ae8cc6 0 contrib/gitview/gitview
+100644 77c29de305fabc518edf060b0e6634d9c5c9f71e 0 contrib/gitview/gitview.txt
+100755 7b03204ed18500756ba55818f0808b52db68d048 0 contrib/hg-to-git/hg-to-git.py
+100644 91f8fe6410c06308b6dce47ca28f4c1b8536c5bb 0 contrib/hg-to-git/hg-to-git.txt
+100644 41368950d6b29121089ee9239b8e07ece209a31e 0 contrib/hooks/post-receive-email
+100644 0096f57b7e09f33108d7177405d02eec05811c03 0 contrib/hooks/pre-auto-gc-battery
+100644 dab7c8e3a1829b31f2b10eafe8becf0f067b5a05 0 contrib/hooks/setgitperms.perl
+100644 d18b317b2f018d1d1a5a9677a7bdaf8956d65186 0 contrib/hooks/update-paranoid
+100644 b9892b679320d17c1e9812633d892a7e057865aa 0 contrib/p4import/README
+100644 0f3d97b67eef3108728265e26f5d79c4526d11ac 0 contrib/p4import/git-p4import.py
+100644 9967587fe6bef0cf7cc3e93467bd179f6f58b032 0 contrib/p4import/git-p4import.txt
+100644 f2b08b4f4a5ea29ac6125f5717fa661e11b7d5f9 0 contrib/patches/docbook-xsl-manpages-charmap.patch
+100755 1cda19f66af96fa828de81cbb21817abca0c06ea 0 contrib/remotes2config.sh
+100755 e27fd088be1bd3ecc3da116d5f32ce10d89897ac 0 contrib/stats/git-common-hash
+100755 4b852e2455bab324e3bd16e02ec712fbacbf34b0 0 contrib/stats/mailmap.pl
+100755 f4a7b62cd9f1a397118b95792c04c2f70f910f9e 0 contrib/stats/packinfo.pl
+100644 39f96aa115e0a20024d2f41138db6b2b8c6d5320 0 contrib/thunderbird-patch-inline/README
+100755 cc518f3c890158d29e751e008436e0c3790746ee 0 contrib/thunderbird-patch-inline/appp.sh
+100644 9e7881fea923e47c3c35028ebbc00bce395d4005 0 contrib/vim/README
+100644 332121b40e9c54de9f55362cb57760136039e9fd 0 contrib/vim/syntax/gitcommit.vim
+100755 7959eab902d28bb3307c542514ca4c5f49deee0f 0 contrib/workdir/git-new-workdir
+100644 78efed800d4d64898d438d9590b01be008cfcd36 0 convert.c
+100644 e54d15aced7595ccb11423b0de121db9051ad1f3 0 copy.c
+100644 ace64f165e4a01fb99892e9b89e7df791a7f4ca1 0 csum-file.c
+100644 72c9487f4fd9fcab5e02fc2dc6afd3cb7f9c036a 0 csum-file.h
+100644 ee06eb7f48f1d3e818b3037369b4e056fe7e5be7 0 ctype.c
+100644 4540e8df5ab8bc8ff66549144d7db2928e12199b 0 daemon.c
+100644 35a52576c53e5e1406d40ed4402b8834a29b9f0e 0 date.c
+100644 d9668d2ef94c73e4a7a5602011ff13a9fd9d8c6a 0 decorate.c
+100644 1fa4ad9beb08f23888814b99183487ab85378bfd 0 decorate.h
+100644 40ccf5a1e95f62d840a006274f7024fa43208b1c 0 delta.h
+100644 a4e28df714b4834e5efe42fa3abb647711913d71 0 diff-delta.c
+100644 e7eaff9a68ccbcc692522c9956f0dae9af45f3f1 0 diff-lib.c
+100644 7d68b7f1bef1039b4996e662fb17968c4e3e3e79 0 diff-no-index.c
+100644 cbf25473c594abfd1fc13473108dc9c15e2f1d15 0 diff.c
+100644 50fb5ddb0bec02b0cd5498d6ecc37d44bf874476 0 diff.h
+100644 31cdcfe8bcdae7df65b0387071846299a14bb7be 0 diffcore-break.c
+100644 e670f8512558c38d9a9d6e754cfc609b042b1195 0 diffcore-delta.c
+100644 23e93852d8c701760d56e7e728dba7c08367fbe8 0 diffcore-order.c
+100644 af9fffe6e8e145b066157da8791c749257e7c8e9 0 diffcore-pickaxe.c
+100644 1b2ebb40014d820fe4fb679509ab694d453be7b4 0 diffcore-rename.c
+100644 cc96c20734bf4184970f5381416637cf6e45ea13 0 diffcore.h
+100644 29d1d5ba31def46ba8b55905dc60773cc6cc167e 0 dir.c
+100644 2df15defb6720a742282f24721233c4816deceb6 0 dir.h
+100644 1f73f1ea7dfa6a14dedf384c99751e86c8121ff4 0 dump-cache-tree.c
+100644 eebc3e95fe0c7e61f7c29fa5412ea9d4a5900f92 0 editor.c
+100644 222aaa374b8268828e9d529a8afacb8830acc281 0 entry.c
+100644 0c6d11f6a0c6fa5dbab2f36c4b4ad4de5aba4ac9 0 environment.c
+100644 ce6741eb682b59ad638c7bee6ca31e2fcd53f281 0 exec_cmd.c
+100644 594f961387240c221020c9ea0bccd8a39ff69595 0 exec_cmd.h
+100644 7089e6f9e6c5fa9142f468e54afe7d33a6d2eec7 0 fast-import.c
+100644 8bd9c32561e79d194d27fa10cc98a26aa2cb673c 0 fetch-pack.h
+100755 63dfa4c475ae3632fc5cfd093d949a41683a5458 0 fixup-builtins
+100644 797e3178ae279f444d2efa7e3758652ad0898dd7 0 fsck.c
+100644 990ee02335a2e2693e32baa82b259c23843f2aa0 0 fsck.h
+100755 a2913c2a2cd1ec158157ada3e2deb666892b734b 0 generate-cmdlist.sh
+100755 da768ee7acc22e6480f0a067e109239561d43927 0 git-add--interactive.perl
+100755 6aa819280ef99ccbbdeefde037e99fae3e6f0110 0 git-am.sh
+100755 98f3ede566a6cb0c902ce84795f7de8f8afbe633 0 git-archimport.perl
+100755 3cac20db79e1e408a321b0e9d272501985a3c49b 0 git-bisect.sh
+100644 cf89cdf4598b3796724a85aa707f740245155cdc 0 git-compat-util.h
+100755 6d9f0ef0f989133422cf8c0302e63dab15a999d5 0 git-cvsexportcommit.perl
+100755 e2664ef01308fd0fb65d47b25e0ae73a65aa6262 0 git-cvsimport.perl
+100755 b0a805c688f59af29e1f25b514d73f3991285dee 0 git-cvsserver.perl
+100755 182822a24e214fe7e93a2df68fdda3dd40b5896d 0 git-filter-branch.sh
+100644 6483b21cbfc73601602d628a2c609d3ca84f9e53 0 git-gui/.gitignore
+100755 0ab478ef90aba9048a2de785d538da16e1bae431 0 git-gui/GIT-VERSION-GEN
+100644 55765c8a3aa6b3702b230e8efe3c2ab47a6e73e5 0 git-gui/Makefile
+100755 14b2d9aacd1d28084f195365b434747df2ddc95d 0 git-gui/git-gui.sh
+100644 241ab892cd5b731f07571acf7a0ca3150a763f4f 0 git-gui/lib/about.tcl
+100644 b6e42cbc8fe0a49c301335f78cc2941bd9d59870 0 git-gui/lib/blame.tcl
+100644 777eeb79c1355ec49ce175cc5c33a13df6e41c97 0 git-gui/lib/branch.tcl
+100644 6603703ea163d830c7de1478aa2dd737c4d9d499 0 git-gui/lib/branch_checkout.tcl
+100644 3817771b944cc363205b86c91f7b4801c1d568f9 0 git-gui/lib/branch_create.tcl
+100644 ef1930b4911591566be4561b8c17c24e1cfbfaad 0 git-gui/lib/branch_delete.tcl
+100644 166538808f461275075e2b03c56ddc15b5813e1a 0 git-gui/lib/branch_rename.tcl
+100644 ab470d12648c1dd3560b411e70ea210cc4381e3e 0 git-gui/lib/browser.tcl
+100644 caca88831b7066c573917542d24a52e832dcff34 0 git-gui/lib/checkout_op.tcl
+100644 56443b042c62bc10765aaf6484ad1077a843cb30 0 git-gui/lib/choose_font.tcl
+100644 318078615862adab052d0d0f637f82176a0a785a 0 git-gui/lib/choose_repository.tcl
+100644 c8821c146386f850c0794df70f605cd9f18dcff3 0 git-gui/lib/choose_rev.tcl
+100644 dc2141192a21e7416268cc94beda78d6ceb8f86f 0 git-gui/lib/class.tcl
+100644 40a710355751836e78b65101592b753266f507ca 0 git-gui/lib/commit.tcl
+100644 c112464ec367a2db707a3f28ff6c588aefe7985f 0 git-gui/lib/console.tcl
+100644 a18ac8b4308d8263a0688058524282b72bafe77a 0 git-gui/lib/database.tcl
+100644 abe82992b6529cf49983029d85348df5d27ceaf5 0 git-gui/lib/date.tcl
+100644 52b79e4a1f476c2ee9b65087f66a352a25ed0903 0 git-gui/lib/diff.tcl
+100644 7f06b0d47f0fa214c98644757f99f8a036b9689e 0 git-gui/lib/encoding.tcl
+100644 75650157e551e34dab650d89f3fa6d25afc91d6a 0 git-gui/lib/error.tcl
+100644 334cfa5a1a59c320e86789ccf4ed3320584a0215 0 git-gui/lib/git-gui.ico
+100644 3c1fce7475d362d1880d915ff4bdf168fda28593 0 git-gui/lib/index.tcl
+100644 5ff76692f5eeeb51bcca0905385f51963d1e6531 0 git-gui/lib/logo.tcl
+100644 5c01875b051305b5b40a17ac7a2245f69081f41b 0 git-gui/lib/merge.tcl
+100644 ffb3f00ff0a992254804cc047b5a63ce82aa5bd9 0 git-gui/lib/option.tcl
+100644 0e86ddac0981fbb575a7dd5294ddaed29f7c3917 0 git-gui/lib/remote.tcl
+100644 c7b81486984d46a9dca59867c406a8e247d76313 0 git-gui/lib/remote_branch_delete.tcl
+100644 38c3151b05c732d919943e44629bfc0a8c9fb617 0 git-gui/lib/shortcut.tcl
+100644 78f344f08f34842c134b6b0e22b6eb8c49b1dbbd 0 git-gui/lib/spellcheck.tcl
+100644 51d4177551b911c35cfd8004a36fca4259367d24 0 git-gui/lib/status_bar.tcl
+100644 8e6a9d0a6010cf5efee069a2d488124bcbdb54cd 0 git-gui/lib/transport.tcl
+100644 d7f93d045d1a2b3a14d2fdb4907697622b5973a8 0 git-gui/lib/win32.tcl
+100644 117923f8860bb8f0f04c1664d8cbe38804a59831 0 git-gui/lib/win32_shortcut.js
+100644 ddbe6334a258dae46b6c333d53590f3b920a9cab 0 git-gui/macosx/AppMain.tcl
+100644 b3bf15fa1c1a41265460664417caf47265553a4f 0 git-gui/macosx/Info.plist
+100644 77d88a77a7669667335cf6fd5767c8b40f3ce6e7 0 git-gui/macosx/git-gui.icns
+100644 a89cf4496990737117d7558a7465f68aa058e465 0 git-gui/po/.gitignore
+100644 5e77a7d7d2d9e82311c1573035fa020c8d08b38c 0 git-gui/po/README
+100644 f20955c18520bf2b0cc8826da9e1dc93a5624ac3 0 git-gui/po/de.po
+100644 89b6d51ea011d5b0fc8a343ffdda078d659571cb 0 git-gui/po/fr.po
+100644 813199f782968cb0949d24119145e8b3e4a174cd 0 git-gui/po/git-gui.pot
+100644 749aa2e7ec1b02e6af3427516b1197f77bd48795 0 git-gui/po/glossary/Makefile
+100644 35764d1d22da45e90638b2db3e0bfbcb332e8696 0 git-gui/po/glossary/de.po
+100644 27c006abb2adca055ebf7e44ce9a4ec351af19c5 0 git-gui/po/glossary/fr.po
+100644 40eb3e9c07a4d39091972655d8a99110fd361be5 0 git-gui/po/glossary/git-gui-glossary.pot
+100644 9b31f69152025e484ddf467d7884c2bf2140a894 0 git-gui/po/glossary/git-gui-glossary.txt
+100644 bb46b48d6b84446a23c14af88c339fda7e417718 0 git-gui/po/glossary/it.po
+100755 49bf7c5365130ec290948ee8abba28d757774381 0 git-gui/po/glossary/txt-to-pot.sh
+100644 158835b5c1c9364735167e618af62272c8bb7a8d 0 git-gui/po/glossary/zh_cn.po
+100644 28760ed97838d39effd035ab4f1159c0085221f8 0 git-gui/po/hu.po
+100644 11cc79bb5ec9c8f1a158ceb457157705b04d4adf 0 git-gui/po/it.po
+100644 28e6d6246b5a07bc0dfe29dde4727be0cf0ba40c 0 git-gui/po/ja.po
+100644 b7c4bf3fdffb3d04b8c01b25e99a706e499de0d1 0 git-gui/po/po2msg.sh
+100644 db55b3e0a69813cba16932212ee1b2ce0f5b2b9a 0 git-gui/po/ru.po
+100644 4da687bb41f5471eaa6dd49c2ffae1eaa053ec68 0 git-gui/po/sv.po
+100644 d2c686667163ec4cd83045efd429e3413564290e 0 git-gui/po/zh_cn.po
+100644 53c3a94686813936445efbb055dc4f02885c70e9 0 git-gui/windows/git-gui.sh
+100755 0843372b57371b62cd68f2818f634209f55d5395 0 git-instaweb.sh
+100755 9cedaf80ceac1d4100adf3cfb152c76c7f945e4d 0 git-lost-found.sh
+100755 645e1147dc886f2b1ca6d2020b44db746b082bf0 0 git-merge-octopus.sh
+100755 e1eb9632660146396a0b5f3f2a410d8cb027ff9d 0 git-merge-one-file.sh
+100755 93bcfc2f5dce418d00f26257788932d5c738785c 0 git-merge-resolve.sh
+100755 94187c306ccb05d977f2bb35e81828130ab49a61 0 git-mergetool.sh
+100755 695a4094bb4230341618bd6f16d0bea9bff2e826 0 git-parse-remote.sh
+100755 75c36100a2f858bcf2663d2b4560654787963175 0 git-pull.sh
+100755 cebaee1cc9dfc28d80173583b144a480be2f9bfd 0 git-quiltimport.sh
+100755 4e334ba41dad3067394b79c15ebfe610b2d3e178 0 git-rebase--interactive.sh
+100755 412e135c3ae88d76b5bdf3f08083b153da220a95 0 git-rebase.sh
+100755 937c69a74858a8a3c63bb41a23705b579df1b3a3 0 git-relink.perl
+100755 683960b04d6b743e687b2eb640d2b0e00ccfd313 0 git-repack.sh
+100755 073a314c8043e0ff30afde65e012e356ff0d186f 0 git-request-pull.sh
+100755 d2fd89907688a044ffe0d2520744e00a9b33c942 0 git-send-email.perl
+100755 dbdf209ec0e7d6468c199d1905c3e7788a9cd246 0 git-sh-setup.sh
+100755 d4609ed66e56dc6021c800d60286bec38615ff39 0 git-stash.sh
+100755 b40f876a2ca9fe985cedc622ab28a9f461edc5ab 0 git-submodule.sh
+100755 cf6dbbc42773fef394c27cd87109b69c3144753c 0 git-svn.perl
+100755 384148a59fc492d8fb1d6ea4fc4532aa1e5ffc22 0 git-web--browse.sh
+100644 37b1d76a08ca59f3de54e11890dce962403cf8d3 0 git.c
+100644 c6492e5be2763eab81358424ff625a34a5ff2fba 0 git.spec.in
+100644 e1b6045605865cbfc4ae0d57039111d5df825649 0 gitk-git/Makefile
+100644 fddcb45817ed6839ba95965d7e57e9a2e04ae30a 0 gitk-git/gitk
+100644 e358dd1903352f5cd65ac77e777ae14d6887adc0 0 gitk-git/po/.gitignore
+100644 b9867bf8e05d06f7effb9919f00879f77690e185 0 gitk-git/po/de.po
+100644 2cb148624723adf82fd7f4a361133dbc8909db93 0 gitk-git/po/es.po
+100644 d0f4c2e19ac15b10c01d6df968f823914cdbba4a 0 gitk-git/po/it.po
+100644 c63248e3752b8b479f75ad2fe772dd40f684be54 0 gitk-git/po/po2msg.sh
+100644 f6b080df4cf313edaba241eb54c232e9f282a38c 0 gitk-git/po/sv.po
+100644 26967e201aca8ea1c799e6b21cad468484753779 0 gitweb/INSTALL
+100644 825162a0b6dce8c354de67a30abfbad94d29fdde 0 gitweb/README
+100644 de637c0608090162a6ce6b51d5f9bfe512cf8bcf 0 gitweb/git-favicon.png
+100644 16ae8d5382de5ffe63b54139245143513a87446e 0 gitweb/git-logo.png
+100644 aa0eeca24786dbd5143354fc3bb5e8cdb3ef831f 0 gitweb/gitweb.css
+100755 90cd99bf916135e5c0a9e1bd7d5e9ff45555c489 0 gitweb/gitweb.perl
+100644 e2633f8376eb7b12706dcd4c698e2b3f6be2b433 0 graph.c
+100644 eab4e3daba9812293d4e005c3ebe28f9a97744ce 0 graph.h
+100644 f67d6716ea5f42c3384a7a4cb2eb973b02785fba 0 grep.c
+100644 d252dd25f81526d9b8663b4d3c9585d69a901397 0 grep.h
+100644 46c06a9552dac5475afc607c3fe2bf00801eb055 0 hash-object.c
+100644 1cd4c9d5c0945994b84bb25edd6e4685cf76b5c5 0 hash.c
+100644 69e33a47b9861df9ac12c354eae180b4f8fea857 0 hash.h
+100644 3cb19628965685ce59a5377b81bef975851996e8 0 help.c
+100644 68052888570af7d09535db8831b8cf3ef2881589 0 http-push.c
+100644 9dc6b27b457a2979a95018679a0b885e6fb62d9a 0 http-walker.c
+100644 1108ab4a3101fb4768cad420ccfdb52d87890a18 0 http.c
+100644 905b4629a47789705c13745fd56ce0c91adea41b 0 http.h
+100644 b35504a8d25594a8d243ae7490733eae5a262712 0 ident.c
+100644 1ec131092109aa3fbed3cd20f10b56a864584a94 0 imap-send.c
+100644 52064befdbbbdf671bd08e369a133d4f1fee03c1 0 index-pack.c
+100644 7f03bd99c5b66afa6cc7fa11a2430301a3042656 0 interpolate.c
+100644 77407e67dca97eb85274c69e2e7469e1d4d40b3b 0 interpolate.h
+100644 c8b8375e4983794e601ba69a1c217a3c711835e9 0 list-objects.c
+100644 0f41391ecc00eac324ea76de7654781c4fce094e 0 list-objects.h
+100644 9837c842a3f215ebee7cbe9690e42e216fb5c76c 0 ll-merge.c
+100644 5388422d091ede134d42406291989c49553f7428 0 ll-merge.h
+100644 4023797b00fe21ecbabe3407ef8a12fca0690607 0 lockfile.c
+100644 bd8b9e45ab46b8664c8b7016b33bee22f86c9e0d 0 log-tree.c
+100644 59ba4c48b7966db34c6345a445ab0b10e235ac83 0 log-tree.h
+100644 88fc6f394684436967002ca477eac1e084537348 0 mailmap.c
+100644 6e48f83cedd13e24d50cddf47f037791ddc5ad4b 0 mailmap.h
+100644 0fd6df7d6ed839eaed536bc332312c2688a6bbad 0 match-trees.c
+100644 2a939c9dd835a7e7946eb1548e4cf637ae3ca329 0 merge-file.c
+100644 7491c56ad25332fb4aae6a075bf0577a1d800c3b 0 merge-index.c
+100644 f37630a8ad07709ae106ddde44a34daf6bad8b16 0 merge-recursive.h
+100644 02fc10f7e622ba1c53065e7cf4563ff10af0c41f 0 merge-tree.c
+100644 0b34341f711a903d4a12fe96dc6ef63e55fb2f5b 0 mktag.c
+100644 e0da110a98d3a7376dc78df71fabc10fc5664296 0 mktree.c
+100644 3f06b835675206912777a774d91c3ba611fa5a06 0 mozilla-sha1/sha1.c
+100644 16f2d3d43ca8bee1eeb306308277bef8c707a972 0 mozilla-sha1/sha1.h
+100644 0031d78e8c98a32d61cd0dc0f939a033e24ed890 0 name-hash.c
+100644 50b6528001fe4bafdfe70126dc2078860c3d1969 0 object.c
+100644 036bd66fe9b6591e959e6df51160e636ab1a682e 0 object.h
+100644 f596bf2db5e0a0065e6856b8caa3ded8a134f74d 0 pack-check.c
+100644 25b81a445c8fafe0c00ce30082b7d9a7c22ccf1e 0 pack-redundant.c
+100644 848d311c2b2c651dbb14893c260584f00c639357 0 pack-refs.c
+100644 518acfb370ad72be18399a3ac5e8ca17880281c9 0 pack-refs.h
+100644 cd300bdff5b524a4d509ba5276e9ef21f443013d 0 pack-revindex.c
+100644 36a514a6cf600e7e77794e50998a9d160e30c8e9 0 pack-revindex.h
+100644 a8f02699366c87de960d7637e9f69c26c2241693 0 pack-write.c
+100644 76e6aa2aad06545e7c44fc2c1e117ea668356ccf 0 pack.h
+100644 6b5c9e44b4ded338ddb344ae454d83a685b7569a 0 pager.c
+100644 71a7acf4e22bd12c0919f277410d6ec52dd5efc8 0 parse-options.c
+100644 bc317e7512af7a1cc86641a651ae5415d28e71c4 0 parse-options.h
+100644 ed9db81fa82c812c9ffa07f5a40540dbb15da0d3 0 patch-delta.c
+100644 9349bc5580456b378d41da7cc2518e4fa9a7e81a 0 patch-id.c
+100644 3be5d3165e0009761a0ca69e15e4a9132c6cfaff 0 patch-ids.c
+100644 c8c7ca110ad34def12a3594a1560b3c3052eb701 0 patch-ids.h
+100644 9df447bd6dcfaddf7f05fe5f0b624700ff1f40d7 0 path.c
+100644 98b24772c7ebe838d513d8e24f3c8acff7839cb9 0 perl/.gitignore
+100644 d99e7782002e01079b3866003cc8555b7e130e3f 0 perl/Git.pm
+100644 b8547db2c64ac1242725b5f71fb646b5bca38ef3 0 perl/Makefile
+100644 320253eb8e91eb1d914aa4e34f7d3af4649b9b39 0 perl/Makefile.PL
+100644 11e9cd9a02eb3f85a9150c6fb06d1fc76abd9b09 0 perl/private-Error.pm
+100644 f5d00863a6234c16db33637d19fefd2014780e87 0 pkt-line.c
+100644 9df653f6f5afe720870658d7093bddbf3e66beaf 0 pkt-line.h
+100644 738e36c1e81def4822ccc2a66bc2761402a07f26 0 ppc/sha1.c
+100644 c3c51aa4d487f2e85c02b0257c1f0b57d6158d76 0 ppc/sha1.h
+100644 f132696ee72bf4a2e3d608a24322a6839f9a03a8 0 ppc/sha1ppc.S
+100644 33ef34a4119812674726254fee3f391fb5734fdb 0 pretty.c
+100644 55a8687ad15788f8ea5a5beb463d216908f618b2 0 progress.c
+100644 611e4c4d42d8d1164add09f926ad5b2ce088db5e 0 progress.h
+100644 6a520855d6c418ecb1384ef9571b122b134af1af 0 quote.c
+100644 c5eea6f18e2dfabd071b73e6507c34c2b7b5e39f 0 quote.h
+100644 3b1c18ff9b9060d0dd437ce89aedb8871c66c54c 0 reachable.c
+100644 40751810b64f8bbf9c0a633472a0ef27d23ed1a5 0 reachable.h
+100644 2c03ec3069decb20f7557af4ac7dbe295f2dcf9c 0 read-cache.c
+100644 d44c19e6b577023dcbaa188a0e67130ff4e5bd9a 0 receive-pack.c
+100644 f751fdc8d832cae54647c1a70d888e979d324fd8 0 reflog-walk.c
+100644 7ca1438f4d74b652f962c6bdfddd08fe0d75802d 0 reflog-walk.h
+100644 39a3b23804d2da715c564459bf320be23d41c1bf 0 refs.c
+100644 06ad26055661a9b9e475d0f8a7bd6d1cfb42e792 0 refs.h
+100644 f61a3ab399aa6960fb8eba050321cea4a3b05344 0 remote.c
+100644 091b1d041f8a4d255f59bfc001e098e692dbc15c 0 remote.h
+100644 323e493dafee46c0d3f95e3c4cd9c4c9b463bbef 0 rerere.c
+100644 f9b03862fe78b560ee606637be3b1ce972a2cc14 0 rerere.h
+100644 3897fec53170c50921eb1952bc4bdf9c08480638 0 revision.c
+100644 f64e8ce7ff999e9fe4a01205ae51775827484ed4 0 revision.h
+100644 a3b28a64dc2d1b888b0ba2a135be10fe04651201 0 run-command.c
+100644 5203a9ebb10b14bd06862abafed0ab73d7514a3d 0 run-command.h
+100644 8ff1dc35390083c3648c4ee5790f35633d956069 0 send-pack.h
+100644 c1c073b2f05a48772a45602cdc711eef6e211695 0 server-info.c
+100644 6cf909463d4ad3681a2f35269db9dc944f4389c2 0 setup.c
+100644 da357479cf19aad4bebc64f874c76fdf8566712b 0 sha1-lookup.c
+100644 3249a81b3d664afc89c98e6d9dd6b512092a82f9 0 sha1-lookup.h
+100644 e281c14f01d37ab7623998c2990914aca49a7a3b 0 sha1_file.c
+100644 4fb77f8863ec075de38b84171d3ef039a00cee4c 0 sha1_name.c
+100644 4d90eda19efe0a80c1cb39e8897ab3ed5e6fcf56 0 shallow.c
+100644 6a48de05ff80f86050715ef3dab87a48b0a86ac9 0 shell.c
+100644 bc02cc29ef0d5f640ab390614def995f30fe4691 0 shortlog.h
+100644 45bb535773fd9c36f73502df9462f7de800009c8 0 show-index.c
+100644 b6777812cb92c1c169ee395164d53a0c2e6eceb2 0 sideband.c
+100644 a84b6917c7a17b5f8a922540801e98d46aa24431 0 sideband.h
+100644 720737d856b694bc5239f0c18af372959c99e744 0 strbuf.c
+100644 eba7ba423a2d3a383ef93f663c95695438269edf 0 strbuf.h
+100644 ddd83c8c76112cecd5d23668aaca467601855a72 0 string-list.c
+100644 4d6a7051fe5bccf04a0d0c32a90e5cf9c00dba3c 0 string-list.h
+100644 5a5e781a15d7d9cb60797958433eca896b31ec85 0 symlinks.c
+100644 1b97c5465b7d9e4404e11668b44c5c507a302d4a 0 t/.gitattributes
+100644 b27e280083867ac03c4abc188f0f37291eb123a0 0 t/.gitignore
+100644 0d65cedaa6566a6dd654753cb574c9ee64b1c90b 0 t/Makefile
+100644 8f12d48fe8b4ffe4a4b37dcd16ce58e50837433f 0 t/README
+100755 d5bab75d7da49ebb53e368d67f6b867f5417a125 0 t/aggregate-results.sh
+100644 cacb273afff1fbddf152bb440451fa141589cf33 0 t/annotate-tests.sh
+100644 4bddeb591ecc17ec532164d0d6cf1ad1a54eb996 0 t/diff-lib.sh
+100644 a841df2a9e3a9ed64e81ab7b9778e59cfc714cad 0 t/lib-git-svn.sh
+100644 dc473dfb53d5ffafee72738a55caf21732fa4fb1 0 t/lib-httpd.sh
+100644 4717c2d33b70af6527f8951ec8a414e8caf87095 0 t/lib-httpd/apache.conf
+100644 6dab2579cbf9658c3ac2bd55c8a66333d67eda47 0 t/lib-httpd/ssl.cnf
+100644 168329adbc4edeedc98501575ccc9b9c81f0c061 0 t/lib-read-tree-m-3way.sh
+100755 70df15cbd8339b552a56a95ca0c0893138550201 0 t/t0000-basic.sh
+100755 620da5b32041b1ad69bfdcb6d139f2705386a5ff 0 t/t0001-init.sh
+100755 4db4ac44c9611398db46dfbe2688c95e3b03605b 0 t/t0002-gitfile.sh
+100755 3d8e06a20fade230136d50736a2f621d3c96002c 0 t/t0003-attributes.sh
+100755 63e1217e7162435c3da8ec7984b5f6a53b3a10e2 0 t/t0004-unwritable.sh
+100755 e45a9e40e432524454e94a041599b201a092879a 0 t/t0010-racy-git.sh
+100755 1be7446d8d9f8a46b463f2474a8c25bdd33044d2 0 t/t0020-crlf.sh
+100755 8fc39d77cec6168dae930beef785597dace24aa3 0 t/t0021-conversion.sh
+100755 7d1ce2d0563b3734d754c171d21580075264bbb2 0 t/t0022-crlf-rename.sh
+100755 6f8a4347d5397b8b396db800c12c6e045a0d2b7c 0 t/t0023-crlf-am.sh
+100755 ccb0a3cb61be3bb591033564b221726a4cd3968d 0 t/t0030-stripspace.sh
+100755 03dbe00102626e05c37e45d8a3b1364b99644942 0 t/t0040-parse-options.sh
+100755 b177174ef53e7689cc8c18b134afdbe90be72744 0 t/t0050-filesystem.sh
+100755 6e7501f352ee97636280357da54c50d73ceb0138 0 t/t0060-path-utils.sh
+100755 807fb83af8c65304f1dae2ee35ba0f2909ddf465 0 t/t1000-read-tree-m-3way.sh
+100755 4b44e131b27df0cc6a73590b045c2eb87b104f59 0 t/t1001-read-tree-m-2way.sh
+100755 aa9dd580a658ffd980ec9689b01f7964580661f2 0 t/t1002-read-tree-m-u-2way.sh
+100755 8c6d67edda1468ba0f1c7afc6d13ea3a7bbe0a90 0 t/t1003-read-tree-prefix.sh
+100755 570d3729bd2312a8d9cf90f3d2e1121a58f43de6 0 t/t1004-read-tree-m-u-wf.sh
+100755 b0d31f5a9bb8b3474665147327d94ad5067fa206 0 t/t1005-read-tree-reset.sh
+100755 d8b7f2ffbcc0427b1ae9d48feb4387f580e81d61 0 t/t1006-cat-file.sh
+100755 1ec0535138c72bbd1e497c35c21bc5ea46b0315f 0 t/t1007-hash-object.sh
+100755 fc386ba033ac165a5f4a9fca0c6c6f5db49a314e 0 t/t1020-subdirectory.sh
+100755 7f7fc36734d96de96801c59af41024db97dc614d 0 t/t1100-commit-tree-options.sh
+100755 09a8199335cbdf96f8aba75d47a321f0cfb828d9 0 t/t1200-tutorial.sh
+100755 64567fb94d5c3f9587b643333212cdb37a4661ac 0 t/t1300-repo-config.sh
+100755 dc85e8b60a5c10e57047d1692e383f177e2c478d 0 t/t1301-shared-repo.sh
+100755 8d305b43725f8cf60e7ee802df1923feb98eeae5 0 t/t1302-repo-version.sh
+100755 f98f4c51796e6f7a7181568a134e21ecd9dc2c4f 0 t/t1303-wacky-config.sh
+100755 b31e4b1ac66e56d67ba48ab213c4ef9c32f05ea8 0 t/t1400-update-ref.sh
+100755 73f830db2374e751fb46e25b345e860979b9dd05 0 t/t1410-reflog.sh
+100755 dc9e402c55574d981e161d4e38e74617c411f46d 0 t/t1420-lost-found.sh
+100755 85da4caa7ed1b8bcaca7b21e218f2d1839d2db82 0 t/t1500-rev-parse.sh
+100755 2ee88d8a069288d0d9f6931231162e04d6b0917a 0 t/t1501-worktree.sh
+100755 997002d4c40dd8e66e3be5a701e3d99bab1c57c4 0 t/t1502-rev-parse-parseopt.sh
+100755 95244c9bcf54de8cb3584b4022e53a84051d496f 0 t/t1503-rev-parse-verify.sh
+100755 91b704a3a4ce6771071d19bd84aa228856fe6875 0 t/t1504-ceiling-dirs.sh
+100755 f7e1a735ec8699616280a086f59dc50c078bfaa7 0 t/t2000-checkout-cache-clash.sh
+100755 ef007532b15108d72445f7c95a2906a3039fbbbb 0 t/t2001-checkout-cache-clash.sh
+100755 70361c806e1baf1b26810983374c53eb49ea2f2d 0 t/t2002-checkout-cache-u.sh
+100755 71894b37439bd1b9c72194cbbabe37680d2f9743 0 t/t2003-checkout-cache-mkdir.sh
+100755 39133b8c7a4b56cb7273cec607ea89081a426eff 0 t/t2004-checkout-cache-temp.sh
+100755 a84c5a6af9e69ffec7689827ce1ba653a658a73f 0 t/t2005-checkout-index-symlinks.sh
+100755 0526fce163fc13273daf035a0920a6b53a3acefb 0 t/t2007-checkout-symlink.sh
+100755 3e098ab31e1944abe8e5815c0f219947620b6618 0 t/t2008-checkout-subdir.sh
+100755 f3c21520877e271506be13b5cabad5e7906f0c91 0 t/t2009-checkout-statinfo.sh
+100755 7cc0a3582ef1bb1598bc5dfc5334bfbe006c3f5a 0 t/t2010-checkout-ambiguous.sh
+100755 88f268b9d7a696a06f5ce560c1e8ed0f3d8dc3a3 0 t/t2050-git-dir-relative.sh
+100755 6ef2dcfd8afece86aaf6345630179af179eb2ed9 0 t/t2100-update-cache-badpath.sh
+100755 59b560bfdf240e87516aadd6a31a2fe84e85d49a 0 t/t2101-update-index-reupdate.sh
+100755 19d0894d260787d37a43199d7a3f6c3aa37d32aa 0 t/t2102-update-index-symlinks.sh
+100755 332694e7d38083fad18b3e53e4def268d54e9423 0 t/t2103-update-index-ignore-missing.sh
+100755 f57a6e077c3b85dcdedc3f4813150feebc8e647d 0 t/t2200-add-update.sh
+100755 d24c7d9e5fce0e9c0f8ef5576dab86ffdbc11331 0 t/t2201-add-update-typechange.sh
+100755 6a8151064c8256bd03a90460eb1bd6970428f2f0 0 t/t2202-add-addremove.sh
+100755 bc0a3513920cab41e4335b8c1b5163e25e8354d3 0 t/t3000-ls-files-others.sh
+100755 1caeacafa7ae70506e626498d274dbfa25f1b036 0 t/t3001-ls-files-others-exclude.sh
+100755 8704b04e1b4150357a7a01c91ac59bb1f22cbb8e 0 t/t3002-ls-files-dashpath.sh
+100755 ec1404063701eef04667d5ffbbb4bdc8051c773b 0 t/t3010-ls-files-killed-modified.sh
+100755 af8c4121abfc28b7e289b39936df45bd5b82cf22 0 t/t3020-ls-files-error-unmatch.sh
+100755 aff360303ae2a304bff4799def6906defdb85843 0 t/t3030-merge-recursive.sh
+100755 f6973e96a59916c6048222bfa0064aec5dea3746 0 t/t3040-subprojects-basic.sh
+100755 4261e9641e00fb3b543384b6a8dbbcc1a214b598 0 t/t3050-subprojects-fetch.sh
+100755 3ce501bb9794900b99fbbf2f2ccfbb330f7947a7 0 t/t3060-ls-files-with-tree.sh
+100755 6e6a2542a22712006ae23874069c55943a3cba27 0 t/t3100-ls-tree-restrict.sh
+100755 4dd7d12bac62eae23516686c0ece0edf037f0317 0 t/t3101-ls-tree-dirname.sh
+100755 7a83fbfe4f6b47dc5dbaa3df59c8633ae5c2c8f8 0 t/t3200-branch.sh
+100755 f86f4bc5ebcc0e36ddb4071a6aeb855e1039faa6 0 t/t3201-branch-contains.sh
+100755 7fe4a6ecb05df0fbfb825fbb08207f7672e1775f 0 t/t3202-show-branch-octopus.sh
+100755 c2dec1c6320a0f9b555e3cd38d164c4e3efcb51e 0 t/t3210-pack-refs.sh
+100755 0574ef1f101df172a30755726b0ea1b6c2ef5f7d 0 t/t3300-funny-names.sh
+100755 91bb5e1d9eea0b2f1ff7a1120d97ca2876a8f277 0 t/t3400-rebase.sh
+100755 166ddb1447db4c33a79f0e9aea21cb00e8a151f2 0 t/t3401-rebase-partial.sh
+100755 7b7d07269ae35f56dd02a223f350ae0da97bae85 0 t/t3402-rebase-merge.sh
+100755 0d33c71daa557e68268dfb2279a02fe2afca1ed7 0 t/t3403-rebase-skip.sh
+100755 ffe3dd97b7b1c056d854e28795e1313ce1633452 0 t/t3404-rebase-interactive.sh
+100755 e5ad67c643ffee9b79fce813673732faa950714f 0 t/t3405-rebase-malformed.sh
+100755 539108094345e3e0ba4cf03fc20a5ca6486fa230 0 t/t3406-rebase-message.sh
+100755 4de550a632e6ead08c9629e80901e4735c53f55c 0 t/t3407-rebase-abort.sh
+100755 e12cd578e8663ad8717aecde310bb0b6a500c2a2 0 t/t3408-rebase-multi-line.sh
+100755 4911c48378a137471d2ad56747ceed11d0115be5 0 t/t3500-cherry.sh
+100755 6da212825a447866364979c2fb10778b6bbc02d5 0 t/t3501-revert-cherry-pick.sh
+100755 0ab52da902c8d602e9c4d64660aa4a7e8e35544f 0 t/t3502-cherry-pick-merge.sh
+100755 b0faa299183df5fe06ccaf383bce47cbb9a0cf89 0 t/t3503-cherry-pick-root.sh
+100755 79c06adf1f035cf727771974b2f9713da9d2fb8c 0 t/t3600-rm.sh
+100755 7d123d17fc156c61a8e85a399c3762e8075485de 0 t/t3700-add.sh
+100755 e95663d8e66d5b94e574a6b956625fccfd341a05 0 t/t3701-add-interactive.sh
+100755 c851db8ca9373a890ede7c230710690d5b4b4165 0 t/t3800-mktag.sh
+100755 883281dbd6c02ea7b2d90336c2629eafacee0257 0 t/t3900-i18n-commit.sh
+100644 ee31e1973829739baebbdc1ba0a56391adb2fe2f 0 t/t3900/1-UTF-8.txt
+100644 63f4f8f121dffe43c1902d1a7357b6303072714d 0 t/t3900/2-UTF-8.txt
+100644 546f2aac01b67e39d19de601f5586097b34a8325 0 t/t3900/EUCJP.txt
+100644 74b533042f6d1dfd5cb8fae5a538a43938c2df8d 0 t/t3900/ISO-2022-JP.txt
+100644 7cbef0ee6f430c611134a06a6dd6c12fbea589d5 0 t/t3900/ISO-8859-1.txt
+100755 38c21a6a7fa9a643030f68fd6dd1269b9c640608 0 t/t3901-8859-1.txt
+100755 235f372832cb32aefff0a00c4f2ac0e19de2e55d 0 t/t3901-i18n-patch.sh
+100755 5f5205cd022ba3a96eb8e5eb73292bd0d4a8ab87 0 t/t3901-utf8.txt
+100755 fe4fb5116ac4c482c357f0af3f0a34da27cee237 0 t/t3902-quoted.sh
+100755 8d4804b65818f7fc55f0c0736fde673ac7512a8a 0 t/t3903-stash.sh
+100755 c44b27aeb24816a346f0aa84d70546a0ffd83b2a 0 t/t4000-diff-format.sh
+100755 a32692417db73444dbdc143e6908b7371be79d42 0 t/t4001-diff-rename.sh
+100755 a4cfde6b2927a4655f582d7e92dad4568f7b5f89 0 t/t4002-diff-basic.sh
+100755 8b1f875286b25b5fc1a527b5b0281f866724a82d 0 t/t4003-diff-rename-1.sh
+100755 3d25be7a6709cdd23e0d583a8f1a3e19a3927cd8 0 t/t4004-diff-rename-symlink.sh
+100755 66300173124eee8480e7214322faf8bc493ad940 0 t/t4005-diff-rename-2.sh
+100755 4e92fce1d00a55cfbc39e55b53f95cc309e96ff2 0 t/t4006-diff-mode.sh
+100755 104a4e1492b65a64d061e1ce1df0b0a2a49fb20e 0 t/t4007-rename-3.sh
+100755 26c2e4aa65c539c527ae8e2d71b5abb40c21fbbd 0 t/t4008-diff-break-rewrite.sh
+100755 d2b45e7b8fb3902cb740e0df582f92195a295f24 0 t/t4009-diff-rename-4.sh
+100755 ad3d9e48454d2e72afce682df009cdaaee9ba3c5 0 t/t4010-diff-pathspec.sh
+100755 c6d13693ba45b594704c2ef55d40540ee3f9c25f 0 t/t4011-diff-symlink.sh
+100755 eced1f30fb8475739aef52230bbb79946a0f76d8 0 t/t4012-diff-binary.sh
+100755 9337b81064bbdbe4e7f590830b458c48226c4a17 0 t/t4013-diff-various.sh
+100644 78f8970e2be272114368ee28ca2d55f345a6494a 0 t/t4013/diff.config_format.subjectprefix_DIFFERENT_PREFIX
+100644 3a9f78a09df1bb12aefbb2b5fb75fd0b9455ed06 0 t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_master
+100644 a61ad8cb130093ed63bba5335a0b283f9136177e 0 t/t4013/diff.diff-tree_--cc_--patch-with-stat_--summary_side
+100644 49f23b9215c3179d8923915ee2e497ccbc53875a 0 t/t4013/diff.diff-tree_--cc_--patch-with-stat_master
+100644 cc6eb3b3d50f2d620df7116bf64992a4dd42b736 0 t/t4013/diff.diff-tree_--cc_--stat_--summary_master
+100644 50362be7bf851759885ad17847f5913e5dfb0b3c 0 t/t4013/diff.diff-tree_--cc_--stat_--summary_side
+100644 fae7f33255faef186aa7b987c29adfe33d0365f1 0 t/t4013/diff.diff-tree_--cc_--stat_master
+100644 5ecb4e14ae4718bb26dbe5657abd5660dc45914e 0 t/t4013/diff.diff-tree_--cc_master
+100644 fc177ab3f24c7eddc71d76b803515f7314d9b136 0 t/t4013/diff.diff-tree_--patch-with-raw_initial
+100644 bd905b1c573056f92d7f3b11ad4898d19fd0e5f8 0 t/t4013/diff.diff-tree_--patch-with-stat_initial
+100644 7bb8b45e3eea89b4015cabb70d34483352b40f1a 0 t/t4013/diff.diff-tree_--pretty=oneline_--patch-with-raw_initial
+100644 cbdde4f400fe96ea565dcf28b6b474c2218b6104 0 t/t4013/diff.diff-tree_--pretty=oneline_--patch-with-stat_initial
+100644 cd79f1a0ff23a4399416d85737f312e0b8652a38 0 t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-raw_initial
+100644 d5c333a378c9407abf179d6cc3f5233ca8b5f116 0 t/t4013/diff.diff-tree_--pretty=oneline_--root_--patch-with-stat_initial
+100644 3c5092c6993f454dc7392a3846b93cc3fa47f7e5 0 t/t4013/diff.diff-tree_--pretty=oneline_--root_-p_initial
+100644 08920ac658b07ed83376bdd492020f7787ad1ad5 0 t/t4013/diff.diff-tree_--pretty=oneline_--root_initial
+100644 94b76bfef159a0d8e2d7c48194110cb8465545c2 0 t/t4013/diff.diff-tree_--pretty=oneline_-p_initial
+100644 d50970d5745278a47da683aa20968a912493cb01 0 t/t4013/diff.diff-tree_--pretty=oneline_initial
+100644 3a85316d8a3416e2f280e01d02e0bf3cfce13cc8 0 t/t4013/diff.diff-tree_--pretty_--patch-with-raw_initial
+100644 2e08239a46a72e76aad4e38940cdc822ca511793 0 t/t4013/diff.diff-tree_--pretty_--patch-with-stat_initial
+100644 4d30e7eddc05aa561b43519b031f89de8a30fd98 0 t/t4013/diff.diff-tree_--pretty_--patch-with-stat_side
+100644 a3203bd19bd74f1308ca75396fd9a3cfa2064ac8 0 t/t4013/diff.diff-tree_--pretty_--root_--patch-with-raw_initial
+100644 7dfa6af3c97b1ad469135bb9a9f3c1f8d6d4b60d 0 t/t4013/diff.diff-tree_--pretty_--root_--patch-with-stat_initial
+100644 43bfce253eaf451e2f0a19042c9cbb8879c6fef1 0 t/t4013/diff.diff-tree_--pretty_--root_--stat_--summary_initial
+100644 9154aa4d4700b4a7c1e4c205f43694c198419ece 0 t/t4013/diff.diff-tree_--pretty_--root_--stat_initial
+100644 ccdaafb3772e80571441f5e4263f79a7b8bc5bfd 0 t/t4013/diff.diff-tree_--pretty_--root_--summary_-r_initial
+100644 58e5f74aeae880c69776bfa8e51bc9e5fe2463cf 0 t/t4013/diff.diff-tree_--pretty_--root_--summary_initial
+100644 d0411f64ec5d104de3169da28453276880984917 0 t/t4013/diff.diff-tree_--pretty_--root_-p_initial
+100644 94e32eabb1f82eb614f1a92d64d0ada403a4df16 0 t/t4013/diff.diff-tree_--pretty_--root_initial
+100644 c22983ac4ae05a8c8d9591c91c0a44bc8f42052e 0 t/t4013/diff.diff-tree_--pretty_--stat_--summary_initial
+100644 8fdcfb4c0ad64bc92ddda2418cb5f7fa1138cc7a 0 t/t4013/diff.diff-tree_--pretty_--stat_initial
+100644 9bc2c4fbad20e42dd0a007eaa23c5994eb675588 0 t/t4013/diff.diff-tree_--pretty_--summary_initial
+100644 3c9942faf4b1a1e6d8c3bbbab5627a32ecc96be6 0 t/t4013/diff.diff-tree_--pretty_-p_initial
+100644 b993aa7b893c9ba6c276045a400fe0a849265fcd 0 t/t4013/diff.diff-tree_--pretty_-p_side
+100644 14715bf7d08ff7696da2572544092f6be9029e18 0 t/t4013/diff.diff-tree_--pretty_initial
+100644 e9b6e1c10211c4fb60262a55a28a503c3ed9bb47 0 t/t4013/diff.diff-tree_--pretty_side
+100644 5aa84b2a866262a4e6b2d496e7da5b6f7b9d4d88 0 t/t4013/diff.diff-tree_--root_--abbrev_initial
+100644 d295e475ddc626dc18381a5c5e839d3b2c26126e 0 t/t4013/diff.diff-tree_--root_--patch-with-raw_initial
+100644 1562b627085ff0ad8ffaea61cc42ed39a9d94fc8 0 t/t4013/diff.diff-tree_--root_--patch-with-stat_initial
+100644 3219c72fcbce5ee5a1c2b4e7bb87e696db9a0b18 0 t/t4013/diff.diff-tree_--root_-p_initial
+100644 0c5361688c54c2599e240252ce70e4fad457c924 0 t/t4013/diff.diff-tree_--root_-r_--abbrev=4_initial
+100644 c7b460faf6900e5730a08ab3b90bfda8e1ad48ca 0 t/t4013/diff.diff-tree_--root_-r_--abbrev_initial
+100644 eed435e175d40a3f6fa8b3a0a534936360e86eea 0 t/t4013/diff.diff-tree_--root_-r_initial
+100644 ddf6b068abe26f7516c37ceb1dca1d646343a499 0 t/t4013/diff.diff-tree_--root_initial
+100644 b8e4aa2530717abc7d7b8bea62f12d615dfcd759 0 t/t4013/diff.diff-tree_-c_--abbrev_master
+100644 ac9f641fb48272f25f3385dfbbd05777564f16bc 0 t/t4013/diff.diff-tree_-c_--stat_--summary_master
+100644 2afcca11f4d0c4db6e259e85540e4d90f8c76a10 0 t/t4013/diff.diff-tree_-c_--stat_--summary_side
+100644 c2fe6a98c5f9818f9caf5e0a314aee45831e5329 0 t/t4013/diff.diff-tree_-c_--stat_master
+100644 e2d2bb26114ac886fbf2467dc7a33ec8cfab5daf 0 t/t4013/diff.diff-tree_-c_master
+100644 b60bea039d991675e9d1480d5089c416aa68200a 0 t/t4013/diff.diff-tree_-p_-m_master
+100644 e20ce883702ae0e430350ae849b28c44a081487f 0 t/t4013/diff.diff-tree_-p_initial
+100644 b182875fb2fb3f0020dbf49fd9fd4c80e016e651 0 t/t4013/diff.diff-tree_-p_master
+100644 c5a3aa5aa4688cb354bff44cbb6062ef8259a617 0 t/t4013/diff.diff-tree_-r_--abbrev=4_initial
+100644 0b689b773c67dfef103d95c55ee9958f1b8f32ed 0 t/t4013/diff.diff-tree_-r_--abbrev_initial
+100644 1765d83ce461d78e59cf7d505ec63331a7c70577 0 t/t4013/diff.diff-tree_-r_initial
+100644 b49fc5345730346ab50142f55a1b8796545ead89 0 t/t4013/diff.diff-tree_initial
+100644 fe9226f8a12323c3a36ff2c0c2fd9938852575c8 0 t/t4013/diff.diff-tree_master
+100644 a88e66f81774579c511b6cd546f5043a9c975c36 0 t/t4013/diff.diff_--abbrev_initial..side
+100644 d0d96aaa91eec7f5a6cb833e43bbd3ec89efad98 0 t/t4013/diff.diff_--name-status_dir2_dir
+100644 6a47584777a65cff71e2ebfac8c8f12944de17bb 0 t/t4013/diff.diff_--no-index_--name-status_dir2_dir
+100644 3590dc79a65af7299c4b56fd632489920b62f0fb 0 t/t4013/diff.diff_--patch-with-raw_-r_initial..side
+100644 b21d5dc6f391fe977cc7c9b9c6badf9b261c5f72 0 t/t4013/diff.diff_--patch-with-raw_initial..side
+100644 9ed317a198c71fcec0b44a7b736b61550eed9394 0 t/t4013/diff.diff_--patch-with-stat_-r_initial..side
+100644 8b50629e668a385179eb9586b472c51237492232 0 t/t4013/diff.diff_--patch-with-stat_initial..side
+100644 0517b5d63129f44275b16f51819d9c08bf37d430 0 t/t4013/diff.diff_--stat_initial..side
+100644 245220d3f9b475b4281395639d85122feaa7948d 0 t/t4013/diff.diff_-r_--stat_initial..side
+100644 5bb2fe2f280d2def45c113b5c0daa7ab789faed0 0 t/t4013/diff.diff_-r_initial..side
+100644 c8adaf595863e66fb9ae061cd20176c981316372 0 t/t4013/diff.diff_initial..side
+100644 43346b9ba443fe22b56f0874a7cc885461d2aa81 0 t/t4013/diff.format-patch_--attach_--stdout_initial..master
+100644 d7490a9fd729890c80a4b8fc3da0783997f81a04 0 t/t4013/diff.format-patch_--attach_--stdout_initial..master^
+100644 38f790290a41311e490c493bdaf71774853cc861 0 t/t4013/diff.format-patch_--attach_--stdout_initial..side
+100644 fca5cce373767d96fd68a17a196889c8c9ea172f 0 t/t4013/diff.format-patch_--inline_--stdout_--subject-prefix=TESTCASE_initial..master
+100644 6d6fac390849c964e75b56e48808a78dd3428ce1 0 t/t4013/diff.format-patch_--inline_--stdout_initial..master
+100644 18a1110def4bbe25c0bd7020d35df589ef6f528f 0 t/t4013/diff.format-patch_--inline_--stdout_initial..master^
+100644 4f258b8858df79ecf475514b69df904e83e29ffa 0 t/t4013/diff.format-patch_--inline_--stdout_initial..master^^
+100644 e86dce69a3a78d5cfe5cd82067df0381b0f635bd 0 t/t4013/diff.format-patch_--inline_--stdout_initial..side
+100644 8dab4bf93ebd5f3e5ee6e899890d6e53af9ab967 0 t/t4013/diff.format-patch_--stdout_--cover-letter_-n_initial..master^
+100644 8b88ca49276695aead0083ad49c53715874e11dc 0 t/t4013/diff.format-patch_--stdout_initial..master
+100644 47a4b88637d4dc8650f0480278ae67b907eb5080 0 t/t4013/diff.format-patch_--stdout_initial..master^
+100644 e7650884755b993661ef14fbc812edd7c2710702 0 t/t4013/diff.format-patch_--stdout_initial..side
+100644 3ceb8e73c5d4e963a2c08eddf41197431ad52178 0 t/t4013/diff.log_--patch-with-stat_--summary_master_--_dir_
+100644 43d77761f988b7f43f46a5d8fd85d406ef9caa42 0 t/t4013/diff.log_--patch-with-stat_master
+100644 5187a26816723476b049c44bb3801816e8672cdf 0 t/t4013/diff.log_--patch-with-stat_master_--_dir_
+100644 c9640976a8f3bd724004f945b00d71f43f00c8ea 0 t/t4013/diff.log_--root_--cc_--patch-with-stat_--summary_master
+100644 ad050af55ffa6983bc08ef5919dd20229584fd59 0 t/t4013/diff.log_--root_--patch-with-stat_--summary_master
+100644 628c6c03bc6195268c3e7e003478fd042ef36db2 0 t/t4013/diff.log_--root_--patch-with-stat_master
+100644 5d4e0f13b59652b170c0b2498319f970d071f774 0 t/t4013/diff.log_--root_-c_--patch-with-stat_--summary_master
+100644 217a2eb203718b91ccd79a04e0369f4c5d2905aa 0 t/t4013/diff.log_--root_-p_master
+100644 e17ccfc2340eadbb8c393de0aa2793f6f899ba56 0 t/t4013/diff.log_--root_master
+100644 5e3243897294d1fc4193c1de3fec95ce58ab22af 0 t/t4013/diff.log_-SF_-p_master
+100644 c1599f2f520090b0717d951a69ade5a9960f8038 0 t/t4013/diff.log_-SF_master
+100644 f8fefef2c3869337ba048d5cd6d95169dc60cf00 0 t/t4013/diff.log_-p_master
+100644 e9d9e7b40a08d803901ac001e4bf9f0c37ad8b15 0 t/t4013/diff.log_master
+100644 221b46a7cc2c174ec605cab02211de97bf84f010 0 t/t4013/diff.show_--patch-with-raw_side
+100644 377f2b7b7a34a1e83bbcf0f2d72981685a678c24 0 t/t4013/diff.show_--patch-with-stat_--summary_side
+100644 fb14c530d2dd79730320badff2547ebf755bd350 0 t/t4013/diff.show_--patch-with-stat_side
+100644 8c89136c4d84091da3f2b9f6eaf582112f90a9ba 0 t/t4013/diff.show_--root_initial
+100644 5bd597762869443cfd91ba8ebdaeff6e8b515ebf 0 t/t4013/diff.show_--stat_--summary_side
+100644 3b22327e48122187af12db46027f17526c8e9caf 0 t/t4013/diff.show_--stat_side
+100644 4c4066ae48e213b6a0f4bf51226c4322ac9348c4 0 t/t4013/diff.show_initial
+100644 9e6e1f27105ca50262e5eb3f2ff132b46c12fe45 0 t/t4013/diff.show_master
+100644 530a073b19d75e37aeb241200b6b306e6803ca09 0 t/t4013/diff.show_side
+100644 6a467cccc190449049b7baed2dde0a2f9027e663 0 t/t4013/diff.whatchanged_--patch-with-stat_--summary_master_--_dir_
+100644 1e1bbe19638eeeffb4e656239545ea91fda3dbf2 0 t/t4013/diff.whatchanged_--patch-with-stat_master
+100644 13789f169b6803ba71680470197c50b51795e4e4 0 t/t4013/diff.whatchanged_--patch-with-stat_master_--_dir_
+100644 5facf2543db0135ceb3aafdc5ffe0395b429f44c 0 t/t4013/diff.whatchanged_--root_--cc_--patch-with-stat_--summary_master
+100644 02911535870b012720c9ae095499c61e6e242c7e 0 t/t4013/diff.whatchanged_--root_--patch-with-stat_--summary_master
+100644 9b0349cd555eb17836b8c056d7aae8cf1eabe537 0 t/t4013/diff.whatchanged_--root_--patch-with-stat_master
+100644 10f6767e498b0d5bdadd73067e4ef2dd5f028e89 0 t/t4013/diff.whatchanged_--root_-c_--patch-with-stat_--summary_master
+100644 ebf1f0661e07bd06098d1609a5a22b8e9bbae436 0 t/t4013/diff.whatchanged_--root_-p_master
+100644 a405cb6138857d3a1bc1b590aa55565c34770e4c 0 t/t4013/diff.whatchanged_--root_master
+100644 f39da84822845984e0f431cf84e71fc48853a3c8 0 t/t4013/diff.whatchanged_-SF_-p_master
+100644 0499321d0ebf57fc2d583afd46ce7813a1ba9fde 0 t/t4013/diff.whatchanged_-SF_master
+100644 f18d43209c0a90d2d6fd474e849690f1b2120cfe 0 t/t4013/diff.whatchanged_-p_master
+100644 cd3bcc2c7269c17ff25504c8b7ca02b55ba8d8ed 0 t/t4013/diff.whatchanged_master
+100755 7fe853c20d1111e40371a3796d82bb8485f5ebcf 0 t/t4014-format-patch.sh
+100755 a27fccc8dce431169ce41f7137fb75f44149719c 0 t/t4015-diff-whitespace.sh
+100755 f07035ab7ec72557be7a0cba9ea286bcbaa79da9 0 t/t4016-diff-quote.sh
+100755 60dd2014d5ae5d5e9e168b8b60278d90ef93cc53 0 t/t4017-diff-retval.sh
+100755 e747e842272df5935f863f78ccfc3b311f64228b 0 t/t4017-quiet.sh
+100755 833d6cbcfc063f336d97689ae4e547cf5e956b69 0 t/t4018-diff-funcname.sh
+100755 0d9cbb62615c0d94da784f63907989988b0e8151 0 t/t4019-diff-wserror.sh
+100755 637b4e19d52e81cf1472a4ed9dcfb0c9ff00da2b 0 t/t4020-diff-external.sh
+100644 db2f89090c1c4de05e4f82ea39ea118fccfd48dd 0 t/t4020/diff.NUL
+100755 43d64bbd826049c5a0a8cf365ed5cb3f4489752c 0 t/t4021-format-patch-numbered.sh
+100755 ba43f185494630c50fc2a168df8dcd45c0b2421b 0 t/t4021-format-patch-signer-mime.sh
+100755 bf996fc414d3b5ea16488a8b274973a8347b29cb 0 t/t4022-diff-rewrite.sh
+100755 4dbfc6e8b751a6c93b1f9dfee8ce649235c98c93 0 t/t4023-diff-rename-typechange.sh
+100755 c4d733f5db6a4d390762505b770954cdbf6cc82f 0 t/t4024-diff-optimize-common.sh
+100755 7a3dbc1ea22fd19a54da8949abc368c112377b19 0 t/t4025-hunk-header.sh
+100755 b61e5169f4e9e8d9f87b9ea16e71dfcf1fb9f340 0 t/t4026-color.sh
+100755 ba6679c6e4032bb12e4206226f95770946ece8cc 0 t/t4027-diff-submodule.sh
+100755 204ba673cb58f905f2f35ff5b83294b2a2943f48 0 t/t4028-format-patch-mime-headers.sh
+100755 e0c67740a5ef85aaa3edc9a4514da72c92ce30ec 0 t/t4100-apply-stat.sh
+100644 540e64db85575e10fe02b3b85af6a353999aab8f 0 t/t4100/t-apply-1.expect
+100644 90ab54f0f586c87ace077be87fba396c8f2781a0 0 t/t4100/t-apply-1.patch
+100644 d1e6459749fe3dd4635c9136ccbb148a85405676 0 t/t4100/t-apply-2.expect
+100644 f5c7d601fc955b15d15012a5b49df83364b6ebf4 0 t/t4100/t-apply-2.patch
+100644 912a552a7a67be283c963da84bf044fa779fe633 0 t/t4100/t-apply-3.expect
+100644 90cdbaa5bb62a4adfa0a5eb3f6fe223b9de50e7b 0 t/t4100/t-apply-3.patch
+100644 1ec028b3d05d79fab29d2ac61027c8ef00bf8401 0 t/t4100/t-apply-4.expect
+100644 4a56ab5cf416e2144b5dbdbe06d10b51255fabe2 0 t/t4100/t-apply-4.patch
+100644 b387df15d4fc81574ac18f41174205c86a6ad503 0 t/t4100/t-apply-5.expect
+100644 5f6ddc105950eac20bcacb7987fabff015320ee3 0 t/t4100/t-apply-5.patch
+100644 1c343d459eb8fc129f53d3a13f0e0ffa79058139 0 t/t4100/t-apply-6.expect
+100644 a72729a712038dc64f55d154eb9a94713e3269c9 0 t/t4100/t-apply-6.patch
+100644 1283164d9909164c2428bc1a08cbff1d819fe71c 0 t/t4100/t-apply-7.expect
+100644 07c6589e74fa5afbff9bdfd8d7b7b41f873a005b 0 t/t4100/t-apply-7.patch
+100644 eef7f2e65cc3e2192935b9bde3ea001244b6db18 0 t/t4100/t-apply-8.expect
+100644 5ca13e65949047b5a1e8170422519cd69418da88 0 t/t4100/t-apply-8.patch
+100644 eef7f2e65cc3e2192935b9bde3ea001244b6db18 0 t/t4100/t-apply-9.expect
+100644 875d57d567e2b807587a7e4d2a9bb7771225e28c 0 t/t4100/t-apply-9.patch
+100755 da8abcf36418dbd2e9d8ec85871c245991f96fda 0 t/t4101-apply-nonl.sh
+100644 1010a88f4727373c20e7ab46515a79b9d3cd9675 0 t/t4101/diff.0-1
+100644 36460a243ac10e256df270cec10a7498a0a32009 0 t/t4101/diff.0-2
+100644 b281c43e5b5f4926e365cbd168e43420e8a4a63a 0 t/t4101/diff.0-3
+100644 f0a2e92770870d78d32bef7fe2ed63ad4ca105de 0 t/t4101/diff.1-0
+100644 2a440a5ce2adae53a23363a3cd3b6af5ff915fd0 0 t/t4101/diff.1-2
+100644 61aff975b69f49430ccb0b6ebd14193fd9f78b4e 0 t/t4101/diff.1-3
+100644 c2e71ee344d032ee38bf325099ed6386f180f287 0 t/t4101/diff.2-0
+100644 a66d9fd3a137b22edf5a49cf811970fc85c985d9 0 t/t4101/diff.2-1
+100644 5633c831de0bb2d5d482acc89c32bb3cb39d02d7 0 t/t4101/diff.2-3
+100644 10b1a41edf734aef77feb4a5f40cf358a8f48db3 0 t/t4101/diff.3-0
+100644 c799c60fb9d460ff24160082a9c1346c0751dd4b 0 t/t4101/diff.3-1
+100644 f8d1ba6dc24669ff19530e0d3ed064db2c8e7077 0 t/t4101/diff.3-2
+100755 d42abff1ad59343fa1c84bded9a82c3212370da0 0 t/t4102-apply-rename.sh
+100755 7da0b4bb8bfa96765b9f6eaa1693e2e24e82d335 0 t/t4103-apply-binary.sh
+100755 e7e2913de745cc9f7639103757933f6238fdd564 0 t/t4104-apply-boundary.sh
+100755 3266e394003958b62509b7bfe6652abd03fdfcb7 0 t/t4105-apply-fuzz.sh
+100755 ac58083fe224100987800e9b5ee3e388d9b4d97c 0 t/t4109-apply-multifrag.sh
+100644 1db5ff10501497459d07e227f02764576a6010e1 0 t/t4109/expect-1
+100644 bc52924112ba857784169157d3f650eb35a931ba 0 t/t4109/expect-2
+100644 cd2a475feb2280a24b05870c00f0693dd1de605b 0 t/t4109/expect-3
+100644 1d411fc3ccebe33ee086cfeaea7cea1beb041a6a 0 t/t4109/patch1.patch
+100644 8c6b06d536a06d786f0752ec2aa2a7fae22c8926 0 t/t4109/patch2.patch
+100644 d696c55a752ac61b86691192d46da2566e299830 0 t/t4109/patch3.patch
+100644 4b085909b160a093e9edb4f91de87f7637f218b5 0 t/t4109/patch4.patch
+100755 09f58112e0229a41ea2a5d2ea6e8c23d2523298d 0 t/t4110-apply-scan.sh
+100644 87cc493ec8a0f6f042a5df3c302433c6e45d8dd3 0 t/t4110/expect
+100644 56139080dc157ab9e58dec01399c40362a9e710e 0 t/t4110/patch1.patch
+100644 04974247ec927d9b25bf0b30c372e4669321dad0 0 t/t4110/patch2.patch
+100644 26bd4427f808bb1d0929833f2784e384e35ab961 0 t/t4110/patch3.patch
+100644 9ffb9c2d7ecd2e87eb3a92ed99be90beba3e16be 0 t/t4110/patch4.patch
+100644 c5ac6914f987d3a41266dca735d872e4c131d02c 0 t/t4110/patch5.patch
+100755 f9ad183758c28ff648890d1bd4bbd599562cd795 0 t/t4112-apply-renames.sh
+100755 66fa51591eb7ee8f102fd86e30e54af2da3ea310 0 t/t4113-apply-ending.sh
+100755 55334927abb33864a55f8ff49fd0c0c94a3c1769 0 t/t4114-apply-typechange.sh
+100755 9ace578f17a07aafc050ccaf935aef8a4a3cab4e 0 t/t4115-apply-symlink.sh
+100755 2298ece8019d79ef718ef658bdac74493d265b92 0 t/t4116-apply-reverse.sh
+100755 e9ccd161ee96a5bdbb4bf77de406ea51dacfb5de 0 t/t4117-apply-reject.sh
+100755 f92e259cc6f251ec6f89edee3fc16720f264d82f 0 t/t4118-apply-empty-context.sh
+100755 3c73a783a7e908070308fb1f972f6b5d152e12a4 0 t/t4119-apply-config.sh
+100755 83d4ba679850c2ae2548bcfcce3f22227fcde8c7 0 t/t4120-apply-popt.sh
+100755 aff551a1d787477eb2db34d96217f66ca03c435d 0 t/t4121-apply-diffs.sh
+100755 841773f75fc085d07836b39b3775f49bde5d8d19 0 t/t4122-apply-symlink-inside.sh
+100755 984157f03b9744aa491c888fab9e6aef95dfdc6b 0 t/t4123-apply-shrink.sh
+100755 85f3da2b98a881647837323e3af0378ce59a9db5 0 t/t4124-apply-ws-rule.sh
+100755 3b471b641ba2d3274dd1ab89948485ff8ce4dfdb 0 t/t4125-apply-ws-fuzz.sh
+100755 ceb6a79fe0c8ca5b26a9e148215556f2aa344eb9 0 t/t4126-apply-empty.sh
+100755 1f859dd908cb298bf89a13822e8fc19882060689 0 t/t4127-apply-same-fn.sh
+100755 2dd0c75f964b690977e40a3a8235cc324dc6826e 0 t/t4128-apply-root.sh
+100755 6e6aaf59364456e21bb1deda960edb5295a71131 0 t/t4150-am.sh
+100755 7d86cdff64522f588a3d3e781cf2b272087cfd88 0 t/t4151-am-abort.sh
+100755 b68ab11f2915789cd04ac6bd43363aeab2079198 0 t/t4200-rerere.sh
+100755 405b97119175a1c0fa75a9db30c6b1ab076cc44e 0 t/t4201-shortlog.sh
+100755 4c8af45f834d034529c2a627768a0a3e6f1aac8d 0 t/t4202-log.sh
+100755 e395ff4e341bacea21cc5cd909304b7bb4fcb044 0 t/t5000-tar-tree.sh
+100755 e9f3e72c7ee5584d956d46126956c641a7d53905 0 t/t5100-mailinfo.sh
+100644 f5892c9da73eae30d7629ca5e7f0ba6a4c621c73 0 t/t5100/0010
+100644 8c052777e0d216e84bb8464b1ceaff1bc7721154 0 t/t5100/info0001
+100644 49bb0fec85323c8c19182bc2a50ceb64ce8307fb 0 t/t5100/info0002
+100644 bd0d1221aa34973159390642efc67773a6bfef17 0 t/t5100/info0003
+100644 616c3092a28223d9aa1b3c68aa0bd49fc394dd85 0 t/t5100/info0004
+100644 46a46fc77283fe31bd583444f76ae2cb7085a35a 0 t/t5100/info0005
+100644 8c052777e0d216e84bb8464b1ceaff1bc7721154 0 t/t5100/info0006
+100644 49bb0fec85323c8c19182bc2a50ceb64ce8307fb 0 t/t5100/info0007
+100644 e8a295138317864b814b24af63ad3cf9c64cf79a 0 t/t5100/info0008
+100644 2a66321c8032cc0ee0cba25486e57f790d1f6ce8 0 t/t5100/info0009
+100644 1791241e46dc44994c58b365e339c093704a6006 0 t/t5100/info0010
+100644 b275a9a9b21c762814ed09c0d3a6eb103aa59370 0 t/t5100/msg0001
+100644 e2546ec7332b6b0483f4951906a40436da6383e0 0 t/t5100/msg0002
+100644 1ac68101b135f4aaf6dacd4bcc0b7586a29d6584 0 t/t5100/msg0003
+100644 6f8ba3b8e0e504d0aa343e45fffc044a211cc7ca 0 t/t5100/msg0004
+100644 dd94cd7b9f52247fd33a891e4fdd9b715c7f59b7 0 t/t5100/msg0005
+100644 b275a9a9b21c762814ed09c0d3a6eb103aa59370 0 t/t5100/msg0006
+100644 71b23c0236bddbedabfbdb982e4e73c5e266da28 0 t/t5100/msg0007
+100644 a80ecb97ef9dabb6d25d24d42212dabd5eab6249 0 t/t5100/msg0008
+100644 9ffe1314891f0998bf90f6c6b1e02c56c405e2f2 0 t/t5100/msg0009
+100644 a96c230092340037ef1c99ae91f24096eceacf44 0 t/t5100/msg0010
+100644 d7d680f631b14ea75adf34ba5052043be311e72f 0 t/t5100/nul-b64.expect
+100644 16540d961f8e6eb791300e085d2d6e82e01bd2c4 0 t/t5100/nul-b64.in
+100644 3d40691787b855cc0133514a19052492eb853d21 0 t/t5100/nul-plain
+100644 8ce155167d51de1868fdd2395c312c46b9cc2c63 0 t/t5100/patch0001
+100644 8ce155167d51de1868fdd2395c312c46b9cc2c63 0 t/t5100/patch0002
+100644 8ce155167d51de1868fdd2395c312c46b9cc2c63 0 t/t5100/patch0003
+100644 196458e44e1974188cc1d1523a92c2bbef1ed506 0 t/t5100/patch0004
+100644 7d24b24af83c861a1dc615c19cbaa392fdd69dec 0 t/t5100/patch0005
+100644 8ce155167d51de1868fdd2395c312c46b9cc2c63 0 t/t5100/patch0006
+100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 t/t5100/patch0007
+100644 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0 t/t5100/patch0008
+100644 65615c34af6ea70a53102e6bbef4bd60344cbf1c 0 t/t5100/patch0009
+100644 f055481d567212b7b43e7ca8251351b3f83b143b 0 t/t5100/patch0010
+100644 aba57f922b33b6ab708afbbf82c7e56f6e37bb8d 0 t/t5100/sample.mbox
+100755 645583f9d729cb04ea7bd9638b0c49c48128822e 0 t/t5300-pack-object.sh
+100755 073ac0c6f9dd3d06474b1b81c8c7b622dcfee663 0 t/t5301-sliding-window.sh
+100755 0639772ac4e1e2c6563e793b16c2c10faf06758a 0 t/t5302-pack-index.sh
+100755 31b20b21d23c2066fd124bf6a33dbdc689930170 0 t/t5303-pack-corruption-resilience.sh
+100755 9fd9d0700033027921c90290cedc0a31d71c7733 0 t/t5304-prune.sh
+100755 fb471a08c698b431cd2440e9d4f0e77e2fef6b08 0 t/t5305-include-tag.sh
+100755 68c2ae688c2b7ff96ec927622f92fd512e7beefe 0 t/t5400-send-pack.sh
+100755 ee769d6695ee91120671c485924d804f14c80424 0 t/t5401-update-hooks.sh
+100755 1394047a8dc3e87476e223db42936d59845f803b 0 t/t5402-post-merge-hook.sh
+100755 823239a251f9ba9607649382d595db1b6cc6dcb2 0 t/t5403-post-checkout-hook.sh
+100755 c24003565d635722f07333bb662c8e102d577c9e 0 t/t5404-tracking-branches.sh
+100755 86abc6227105e27fdb9ad99e34193efb90a6242f 0 t/t5405-send-pack-rewind.sh
+100755 59e80a5ea253607bf83ac4eed670744df950eb81 0 t/t5406-remote-rejects.sh
+100755 362cf7e928090fb3752936317f78a4d128810127 0 t/t5500-fetch-pack.sh
+100755 16eadd6b68664884836976aafb6dcbb582603c09 0 t/t5502-quickfetch.sh
+100755 4074e23ffa2c7a93fdbd4a367e273118224b9038 0 t/t5503-tagfollow.sh
+100755 be9ee9326fc4590dcc875e31b6cf64b800451bc5 0 t/t5505-remote.sh
+100755 13d1d826c20293c26c739c70c0a36ed48bbb41d1 0 t/t5510-fetch.sh
+100755 22ba380034775e7584a33ca606294af34f568443 0 t/t5511-refspec.sh
+100755 1dd8eed5bb3cb0f320a8f0780452e52fa7d8da16 0 t/t5512-ls-remote.sh
+100755 9e7486274b3f0079cb993acbd03e90afc5638e38 0 t/t5513-fetch-track.sh
+100755 8becbc3f38fde02371ebbcd9a39a320a1c00c290 0 t/t5515-fetch-merge-logic.sh
+100644 2e0414f6c3d006ac6f06b884a13397c67f6b7df1 0 t/t5515/fetch.br-branches-default
+100644 ca2cc1d1b44e3edc8cd42e2e77d0f85658a52195 0 t/t5515/fetch.br-branches-default-merge
+100644 7d947cd80f9cf656024206f1ea31da0d9f10f493 0 t/t5515/fetch.br-branches-default-merge_branches-default
+100644 ec39c54b7e242ddbeec76f55b98f555d562aa271 0 t/t5515/fetch.br-branches-default-octopus
+100644 6bf42e24b67b526bac49e3cdb287e32513f4a6c4 0 t/t5515/fetch.br-branches-default-octopus_branches-default
+100644 4a2bf3c95ca474417d1dd54d1ac0bcc02bb5f402 0 t/t5515/fetch.br-branches-default_branches-default
+100644 12ac8d20fba1c8a9402b92aa71e2e6797101a042 0 t/t5515/fetch.br-branches-one
+100644 b4b3b35ce0e2f46a16b015a74b771eb90ed3ebad 0 t/t5515/fetch.br-branches-one-merge
+100644 2ecef384eb7d823104581bfe2b4bd240b449e5df 0 t/t5515/fetch.br-branches-one-merge_branches-one
+100644 96e3029416b46ab4192d3e4aaa285a02489e4054 0 t/t5515/fetch.br-branches-one-octopus
+100644 55e0bad621cde0c93e6a6fb92dc259c61986aba5 0 t/t5515/fetch.br-branches-one-octopus_branches-one
+100644 281fa09d481a2d04788d5c1b0a67b8f569203ebc 0 t/t5515/fetch.br-branches-one_branches-one
+100644 e2fa9c8654647e46baa89d24501b050209aefdc1 0 t/t5515/fetch.br-config-explicit
+100644 ec1a7231aa7875df2cebd32411bad4861c233dcd 0 t/t5515/fetch.br-config-explicit-merge
+100644 54f689151ff1006561309f6f7ca5e3523f8626c4 0 t/t5515/fetch.br-config-explicit-merge_config-explicit
+100644 7011dfc18140aade896592c853bec85567d4ccc8 0 t/t5515/fetch.br-config-explicit-octopus
+100644 bdad51f87163b51c378aaa1ca9bed8fe4a461af1 0 t/t5515/fetch.br-config-explicit-octopus_config-explicit
+100644 1b237dde6e03b9bb1f4b9ad0b5ab75ae31127b57 0 t/t5515/fetch.br-config-explicit_config-explicit
+100644 e75ec2f72b4420cf27bcb959ab83518d93e115b1 0 t/t5515/fetch.br-config-glob
+100644 ce8f739a0d5f53d24d1408e0e39719c0411e3c0d 0 t/t5515/fetch.br-config-glob-merge
+100644 5817bed8f88fcc11b9d5e67ce0863249339eeb2c 0 t/t5515/fetch.br-config-glob-merge_config-glob
+100644 938e532db25e684599b39d1c862680a1caf8ea23 0 t/t5515/fetch.br-config-glob-octopus
+100644 c9225bf6ff060118ae85b5c666085b3a558db16e 0 t/t5515/fetch.br-config-glob-octopus_config-glob
+100644 a6c20f92ce6e708f915b285310a94b7080eab1e3 0 t/t5515/fetch.br-config-glob_config-glob
+100644 83534d2ec85e30dee5c32b8d385dd717cf4930a2 0 t/t5515/fetch.br-remote-explicit
+100644 a9064dd65a0e569cc3e7ce5ae2368313f6bfa7ec 0 t/t5515/fetch.br-remote-explicit-merge
+100644 732a37e4d358f0239687770b28c109051c438070 0 t/t5515/fetch.br-remote-explicit-merge_remote-explicit
+100644 ecf020d9298e7a031833e9986f2deb787712cb89 0 t/t5515/fetch.br-remote-explicit-octopus
+100644 af7753101140d43e2a592ec37b88d57d53d45bde 0 t/t5515/fetch.br-remote-explicit-octopus_remote-explicit
+100644 51fae567c8765fc6f447d7ee93a9796e022663a5 0 t/t5515/fetch.br-remote-explicit_remote-explicit
+100644 94e6ad31e301a87b52160f2287b54051e27b4e18 0 t/t5515/fetch.br-remote-glob
+100644 09362e25af564342ccb5ed9507caa103676aedf6 0 t/t5515/fetch.br-remote-glob-merge
+100644 e2eabec62e12b29be2b8cd0c8e6d0cc9ad042f4d 0 t/t5515/fetch.br-remote-glob-merge_remote-glob
+100644 b08e0461954dcedc90df43c03302e3d4257c6f4b 0 t/t5515/fetch.br-remote-glob-octopus
+100644 d4d547c84733f0faacc85c88c7b7fa138933e4a6 0 t/t5515/fetch.br-remote-glob-octopus_remote-glob
+100644 646dbc877008edae3644ceef92fd5bed990eb784 0 t/t5515/fetch.br-remote-glob_remote-glob
+100644 65ce6d99e2631fd777de10e11b3a58db5859c29a 0 t/t5515/fetch.br-unconfig
+100644 8258c808689d883b97867b3d07ca89e08146de12 0 t/t5515/fetch.br-unconfig_--tags_.._.git
+100644 284bb1fb613cafff208741069aea2d4041ec07cd 0 t/t5515/fetch.br-unconfig_.._.git
+100644 11eb5a6ef22d52b794dd7a0a3e29d2ff515791c2 0 t/t5515/fetch.br-unconfig_.._.git_one
+100644 f02bab2fb4a1e07c6128fb899bf42183d1f0965e 0 t/t5515/fetch.br-unconfig_.._.git_one_tag_tag-one_tag_tag-three-file
+100644 3f1be224b8b46ba18bb45ffdbc155d9bd312376c 0 t/t5515/fetch.br-unconfig_.._.git_one_two
+100644 85de41109ecfb6fd4ac3a1b3b15489b83506a63c 0 t/t5515/fetch.br-unconfig_.._.git_tag_tag-one-tree_tag_tag-three-file
+100644 0da2337f1b95b2011524b3d047a291747bd80305 0 t/t5515/fetch.br-unconfig_.._.git_tag_tag-one_tag_tag-three
+100644 fc7041eefc2150417abc504e25f9d82049b3102e 0 t/t5515/fetch.br-unconfig_branches-default
+100644 e94cde745b58aeb360e2db064466260f2362cf87 0 t/t5515/fetch.br-unconfig_branches-one
+100644 01a283e70d9d10373c363d1fe15b39949bba8d89 0 t/t5515/fetch.br-unconfig_config-explicit
+100644 3a556c5e964785046cc43e9c13351818f436b857 0 t/t5515/fetch.br-unconfig_config-glob
+100644 db216dfa562e894999c565d44d43abb6c6dd562e 0 t/t5515/fetch.br-unconfig_remote-explicit
+100644 aee65c204d1b1468adaee9d41dc5c0a47a3ae999 0 t/t5515/fetch.br-unconfig_remote-glob
+100644 950fd078db7ccbe27825183cb0236a0dcc45139a 0 t/t5515/fetch.master
+100644 0e59950c7b5e18521b59a17d3aaddc3a314a6f9c 0 t/t5515/fetch.master_--tags_.._.git
+100644 66d1aaddae6cb34d83bbd0e728fbe89fd26227b1 0 t/t5515/fetch.master_.._.git
+100644 35deddbd2ca6c28c7a50dfc28c3da09b79b7b6a6 0 t/t5515/fetch.master_.._.git_one
+100644 82868524ca40041b243e146064f4451d6899f3c4 0 t/t5515/fetch.master_.._.git_one_tag_tag-one_tag_tag-three-file
+100644 35ec5782c8a6076a76cf314fb5021da8a641e782 0 t/t5515/fetch.master_.._.git_one_two
+100644 2e133eff296d291045e86fe6a8cba958106b9aae 0 t/t5515/fetch.master_.._.git_tag_tag-one-tree_tag_tag-three-file
+100644 92b18b40ccc883bede4d2067aa4bf7a529d2f059 0 t/t5515/fetch.master_.._.git_tag_tag-one_tag_tag-three
+100644 603d6d23312b6a58d95a685803d8b19f0e0ac4e2 0 t/t5515/fetch.master_branches-default
+100644 fe9bb0b7982951ccf85934e42ff7c9620e2312b4 0 t/t5515/fetch.master_branches-one
+100644 4be97c75752571d46aef0283f164abea025a1be8 0 t/t5515/fetch.master_config-explicit
+100644 cb0726ff8d7ea9e801497b564b680710c2a273af 0 t/t5515/fetch.master_config-glob
+100644 44a1ca84296079356eabc3fd37d04529a3492409 0 t/t5515/fetch.master_remote-explicit
+100644 724e8db0a533248cab6784696c90db02ca1435f3 0 t/t5515/fetch.master_remote-glob
+100644 21917c1e5dba7133d451403984f754f445657908 0 t/t5515/refs.br-branches-default
+100644 21917c1e5dba7133d451403984f754f445657908 0 t/t5515/refs.br-branches-default-merge
+100644 21917c1e5dba7133d451403984f754f445657908 0 t/t5515/refs.br-branches-default-merge_branches-default
+100644 21917c1e5dba7133d451403984f754f445657908 0 t/t5515/refs.br-branches-default-octopus
+100644 21917c1e5dba7133d451403984f754f445657908 0 t/t5515/refs.br-branches-default-octopus_branches-default
+100644 21917c1e5dba7133d451403984f754f445657908 0 t/t5515/refs.br-branches-default_branches-default
+100644 8a705a5df252f6f9d4cd32b1557a221ca4f7dc6f 0 t/t5515/refs.br-branches-one
+100644 8a705a5df252f6f9d4cd32b1557a221ca4f7dc6f 0 t/t5515/refs.br-branches-one-merge
+100644 8a705a5df252f6f9d4cd32b1557a221ca4f7dc6f 0 t/t5515/refs.br-branches-one-merge_branches-one
+100644 8a705a5df252f6f9d4cd32b1557a221ca4f7dc6f 0 t/t5515/refs.br-branches-one-octopus
+100644 8a705a5df252f6f9d4cd32b1557a221ca4f7dc6f 0 t/t5515/refs.br-branches-one-octopus_branches-one
+100644 8a705a5df252f6f9d4cd32b1557a221ca4f7dc6f 0 t/t5515/refs.br-branches-one_branches-one
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-config-explicit
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-config-explicit-merge
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-config-explicit-merge_config-explicit
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-config-explicit-octopus
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-config-explicit-octopus_config-explicit
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-config-explicit_config-explicit
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-config-glob
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-config-glob-merge
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-config-glob-merge_config-glob
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-config-glob-octopus
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-config-glob-octopus_config-glob
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-config-glob_config-glob
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-remote-explicit
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-remote-explicit-merge
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-remote-explicit-merge_remote-explicit
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-remote-explicit-octopus
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-remote-explicit-octopus_remote-explicit
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-remote-explicit_remote-explicit
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-remote-glob
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-remote-glob-merge
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-remote-glob-merge_remote-glob
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-remote-glob-octopus
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-remote-glob-octopus_remote-glob
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-remote-glob_remote-glob
+100644 13e4ad2e4602154808a384fe298497b220ac9d6a 0 t/t5515/refs.br-unconfig
+100644 13e4ad2e4602154808a384fe298497b220ac9d6a 0 t/t5515/refs.br-unconfig_--tags_.._.git
+100644 70962eaac152f7063e965da7c6a61abee410e0bc 0 t/t5515/refs.br-unconfig_.._.git
+100644 70962eaac152f7063e965da7c6a61abee410e0bc 0 t/t5515/refs.br-unconfig_.._.git_one
+100644 13e4ad2e4602154808a384fe298497b220ac9d6a 0 t/t5515/refs.br-unconfig_.._.git_one_tag_tag-one_tag_tag-three-file
+100644 70962eaac152f7063e965da7c6a61abee410e0bc 0 t/t5515/refs.br-unconfig_.._.git_one_two
+100644 13e4ad2e4602154808a384fe298497b220ac9d6a 0 t/t5515/refs.br-unconfig_.._.git_tag_tag-one-tree_tag_tag-three-file
+100644 13e4ad2e4602154808a384fe298497b220ac9d6a 0 t/t5515/refs.br-unconfig_.._.git_tag_tag-one_tag_tag-three
+100644 21917c1e5dba7133d451403984f754f445657908 0 t/t5515/refs.br-unconfig_branches-default
+100644 8a705a5df252f6f9d4cd32b1557a221ca4f7dc6f 0 t/t5515/refs.br-unconfig_branches-one
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-unconfig_config-explicit
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-unconfig_config-glob
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-unconfig_remote-explicit
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.br-unconfig_remote-glob
+100644 13e4ad2e4602154808a384fe298497b220ac9d6a 0 t/t5515/refs.master
+100644 13e4ad2e4602154808a384fe298497b220ac9d6a 0 t/t5515/refs.master_--tags_.._.git
+100644 70962eaac152f7063e965da7c6a61abee410e0bc 0 t/t5515/refs.master_.._.git
+100644 70962eaac152f7063e965da7c6a61abee410e0bc 0 t/t5515/refs.master_.._.git_one
+100644 13e4ad2e4602154808a384fe298497b220ac9d6a 0 t/t5515/refs.master_.._.git_one_tag_tag-one_tag_tag-three-file
+100644 70962eaac152f7063e965da7c6a61abee410e0bc 0 t/t5515/refs.master_.._.git_one_two
+100644 13e4ad2e4602154808a384fe298497b220ac9d6a 0 t/t5515/refs.master_.._.git_tag_tag-one-tree_tag_tag-three-file
+100644 13e4ad2e4602154808a384fe298497b220ac9d6a 0 t/t5515/refs.master_.._.git_tag_tag-one_tag_tag-three
+100644 21917c1e5dba7133d451403984f754f445657908 0 t/t5515/refs.master_branches-default
+100644 8a705a5df252f6f9d4cd32b1557a221ca4f7dc6f 0 t/t5515/refs.master_branches-one
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.master_config-explicit
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.master_config-glob
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.master_remote-explicit
+100644 9bbbfd9fc5332911f35826763b821d2eeb758d6f 0 t/t5515/refs.master_remote-glob
+100755 f0030ad00e4a6478fcb3ccfc503e576bd58003bd 0 t/t5516-fetch-push.sh
+100755 ea49dedbf8867694d83cd550c8212ff107361920 0 t/t5517-push-mirror.sh
+100755 c6bc65faa06adeaced0733064fb09eb82add585e 0 t/t5518-fetch-exit-status.sh
+100755 997b2db827c4f37512c6b5d2f861e12105e2a32d 0 t/t5520-pull.sh
+100755 1a15817cd5f8e838812723ad14dbec59a108680c 0 t/t5530-upload-pack-error.sh
+100755 f8c17cd96cc86ca8f2db2ff51467f712d65f8956 0 t/t5540-http-push.sh
+100755 3c013e2b6aa5c659c80134baf43c99e0d89e2e38 0 t/t5600-clone-fail-cleanup.sh
+100755 d785b3df78e8507d81ffa03ff694846791edfc87 0 t/t5601-clone.sh
+100755 8367a6845f6ea3cdbc2f4f0e096144975fa3aef2 0 t/t5602-clone-remote-exec.sh
+100755 1c109160690d273451f7a089be42e45f36a3b5bb 0 t/t5700-clone-reference.sh
+100755 8dfaaa456e115e85e36c438bb998d8053534104e 0 t/t5701-clone-local.sh
+100755 328e4d9a339101d04bb22e441a8955f6c2e1f260 0 t/t5702-clone-options.sh
+100755 ef7127c1b3943a494692ac8027ec321608a31b9c 0 t/t5710-info-alternate.sh
+100755 f55627b641682e72d58a2282639ca589b38fa744 0 t/t6000lib.sh
+100755 b2131cdacd93e0b62f4ef8fdc62b6a81c6aef6fc 0 t/t6001-rev-list-graft.sh
+100755 8f5de097ecd703ae5f6f889ecb735f7277f361be 0 t/t6002-rev-list-bisect.sh
+100755 5daa0be8cc856bff513905bc6583854e0b5ae53a 0 t/t6003-rev-list-topo-order.sh
+100755 5dabf1c5e354c28cc593bd0ea8e4b0d5f0d56d67 0 t/t6004-rev-list-path-optim.sh
+100755 0b64822bf621dee5c9544f76013c0342412eaee6 0 t/t6005-rev-list-count.sh
+100755 9176484db2f78122f71c0f11889e01382effcfb9 0 t/t6006-rev-list-format.sh
+100755 4b8611ce2092f9062aeaeb62ce19a9121d5be537 0 t/t6007-rev-list-cherry-pick-file.sh
+100755 c4af9ca0a7edf6230dc6ca8ec10848545971fce7 0 t/t6008-rev-list-submodule.sh
+100755 c8a96a9a994badde602c8bf7a7decda048a00525 0 t/t6009-rev-list-parent.sh
+100755 b6e57b2426728cce308a57315247cd2a66cabf4a 0 t/t6010-merge-base.sh
+100755 e51eb41f4b9575d2b51d8d4d255ff5ab7a0889ad 0 t/t6011-rev-list-with-bad-commit.sh
+100755 a19d49de28c457d1a5726400d25c1f731506a05f 0 t/t6020-merge-df.sh
+100755 331b9b07d4eedb07377de605ebb87691427b7bb4 0 t/t6021-merge-criss-cross.sh
+100755 e3f7ae8120aa2a46b25dd3830597cb863a5f5e20 0 t/t6022-merge-rename.sh
+100755 f674c48cab3e80d63b5a5831c667b8e08b542905 0 t/t6023-merge-file.sh
+100755 65be95fbaaef4861189a7fc6b3a25bb6d7feb0a7 0 t/t6023-merge-rename-nocruft.sh
+100755 802d0d06ebddec9db6e3a109e689b3974f1e0ff1 0 t/t6024-recursive-merge.sh
+100755 fc58456a11eef7ecb4cf60d37a9e9d5cbe13f970 0 t/t6025-merge-symlinks.sh
+100755 56fc34176859b81137b4d88af90398b9a74a18f7 0 t/t6026-merge-attr.sh
+100755 92ca1f0f8ccabe6f01159ea3e4a73683387ec4a3 0 t/t6027-merge-binary.sh
+100755 f8f3e3ff2c00df468f5703a4e0ac31f52e42e06d 0 t/t6028-merge-up-to-date.sh
+100755 5bbfa44e8d9ee3eebb18eb07e93380c802741a18 0 t/t6029-merge-subtree.sh
+100755 244fda62a5cd34d778cf0789961654eaa37fe589 0 t/t6030-bisect-porcelain.sh
+100755 8073e0c3efb2ac01e4a81e722fc357bcab13f5d4 0 t/t6031-merge-recursive.sh
+100755 eac5ebac24a0174fa20625a19835861573147a26 0 t/t6032-merge-large-rename.sh
+100755 75d9602de4d4238b4182956127540525f711d33f 0 t/t6033-merge-crlf.sh
+100755 aac212e936331db9a596fda0c4a9c0382e123797 0 t/t6040-tracking-info.sh
+100755 919552a2fc5544c130268befca322a6e6a8081c3 0 t/t6101-rev-parse-parents.sh
+100755 2fb672c3b43a9efe4cb9c85465f6b33f23724e48 0 t/t6120-describe.sh
+100755 bc74349416d858834c43f6c648daa95c8b9f3a7a 0 t/t6200-fmt-merge-msg.sh
+100755 a3c8941c726d77fd993a3cfcd7fde4e9aa43da74 0 t/t6300-for-each-ref.sh
+100755 910a28c7e29b6dd8bd30d1ccb156681b44e51bca 0 t/t7001-mv.sh
+100755 c8b4f65f380f3941c75bd6ed52975777d2b28d67 0 t/t7002-grep.sh
+100755 a0ab096c8fdee153a89a1428f85c9bf107badada 0 t/t7003-filter-branch.sh
+100755 bc7ce2cbbb712f890245688da03be96146a1d9ed 0 t/t7004-tag.sh
+100644 83855fa4e1c6c37afe550c17afa1e7971042ded5 0 t/t7004/pubring.gpg
+100644 8fed1339ed0a744e5663f4a5e6b6ac9bae3d8524 0 t/t7004/random_seed
+100644 d831cd9eb3eee613d3c0e1a71093ae01ea7347e3 0 t/t7004/secring.gpg
+100644 abace962b8bf84be688a6f27e4ebd0ee7052f210 0 t/t7004/trustdb.gpg
+100755 2d919d69ef110408b820c76185d6b8da63ea183e 0 t/t7005-editor.sh
+100755 d8a7c798525728ddc8fc5fa9bd8335d8d1f0a710 0 t/t7010-setup.sh
+100755 0d9874bfd7082f9ef16c1f6b3ff8a848a19d8937 0 t/t7101-reset.sh
+100755 29f5678b4c93485ad492fa865a5da58a3cc05b7c 0 t/t7102-reset.sh
+100755 cdecebe456c7a9cf30465b112a24ce7bcf76f344 0 t/t7103-reset-bare.sh
+100755 f136ee7bb5300966c0c3c9d2250dc81763db9feb 0 t/t7104-reset.sh
+100755 9ad5d635a2881c920fff8e524aea0ed931f68e6c 0 t/t7201-co.sh
+100755 2b51c0d7d8ab727a5fb0be8338938f1d3b2eb6a3 0 t/t7300-clean.sh
+100755 cbc0c34ce2487959ef0e8f89f7c2a5d4a68be826 0 t/t7400-submodule-basic.sh
+100755 bf12dbdeef6e307850a91eb6be5ebe537b2de0c8 0 t/t7401-submodule-summary.sh
+100755 f919c8d34de41b2ec3fe08c217dd2c6276cf8472 0 t/t7402-submodule-rebase.sh
+100755 d89f91a6fb7fa12d41cc4a346829bff7cbd3e76b 0 t/t7500-commit.sh
+100755 a72e65c8910f71b8ea562ef5ed641c54fbd89a8e 0 t/t7500/add-comments
+100755 2fa3d86a108d1fc410d82173809066db0b32b062 0 t/t7500/add-content
+100755 e1d856af6d8b59fed20e3beb272006612ba4e8a5 0 t/t7500/add-signed-off
+100755 0edd9ddf73b7053c21595ce1ac1dd157c77d1bca 0 t/t7501-commit.sh
+100755 f1112639b698faca38b2c8fc743e422d14dc15f6 0 t/t7502-commit.sh
+100755 38a48b57c70a888838cfa114be843e1d4aea00d8 0 t/t7502-status.sh
+100755 b06909599564a1c8afa027b0f9c71ef6bb61d6e4 0 t/t7503-pre-commit-hook.sh
+100755 47680e6df41c2bc14f23514b010a8aefb3fedcd7 0 t/t7504-commit-msg-hook.sh
+100755 cd6c7c834218fd4c46c49396b79da1ddeef42772 0 t/t7505-prepare-commit-msg-hook.sh
+100755 a75130cdbb55be157c915f4fc1397227a78441ec 0 t/t7506-status-submodule.sh
+100755 5eeb6c2b2708d582a6e86cd2e06e2b00b7b7b391 0 t/t7600-merge.sh
+100755 55aa6b5f2716255b2b5aa74f1cac9d285de6d6a8 0 t/t7601-merge-pull-config.sh
+100755 fcb8285746420ed721713d9c8e527d23cafb05cf 0 t/t7602-merge-octopus-many.sh
+100755 17b19dc11f2b1a5d26a16f447733880f3cf30d26 0 t/t7603-merge-reduce-heads.sh
+100755 6081677d234f1fcb88b6b9160f707ebf0274f38a 0 t/t7604-merge-custom-message.sh
+100755 ee21a107fd99e35b9d6325a040b7549b7a6c2502 0 t/t7605-merge-resolve.sh
+100755 9285071c473dcfe7d37845d01ba20226b5ab585d 0 t/t7610-mergetool.sh
+100755 31c340fd389ed2688bb94a29acbf892be6f0c564 0 t/t7701-repack-unpack-unreachable.sh
+100755 eabec2e06e2f97fc1790cd4ce30a80e402d4a205 0 t/t8001-annotate.sh
+100755 92ece30fa94784bdad8ae50fc370487e60bbcb5c 0 t/t8002-blame.sh
+100755 966bb0a61a89ed63dec085338d3c45f766a7f777 0 t/t8003-blame.sh
+100755 ba19ac127e630c01e009fa6eda1fac0086d7184d 0 t/t8004-blame.sh
+100755 1c857cf4ab6e359d7009d2c6b5018bb61c916e93 0 t/t9001-send-email.sh
+100755 843a5013b96c675a629bd7f738eca220861e6ff8 0 t/t9100-git-svn-basic.sh
+100755 f420796c31db2746b71ba9d7090f37363eba214a 0 t/t9101-git-svn-props.sh
+100755 0e7ce34b9b1e254873a2700cf58095318b49b15c 0 t/t9102-git-svn-deep-rmdir.sh
+100755 9ffd8458ef9d58fa5d3c42fd61f4629219b4d80a 0 t/t9103-git-svn-tracked-directory-removed.sh
+100755 4d964e2db7cc3c96fc64911bd58c4f2f9679a6cd 0 t/t9104-git-svn-follow-parent.sh
+100755 63230367bb1566384e66e1b5ddd6a68e1ae98c8f 0 t/t9105-git-svn-commit-diff.sh
+100755 83896e96876d8cca24496c7cb278732a308e3d92 0 t/t9106-git-svn-commit-diff-clobber.sh
+100755 bc37db9d62071ba92463276524675964c3e91593 0 t/t9106-git-svn-dcommit-clobber-series.sh
+100755 d9b553ad55b1f7024af0689a450a9c6c65dcb034 0 t/t9107-git-svn-migrate.sh
+100755 f6f71d0545c869a7216eb0e81f260085f6ffdec1 0 t/t9108-git-svn-glob.sh
+100755 04d2a65c087de78fa8126b68774673532497276e 0 t/t9110-git-svn-use-svm-props.sh
+100644 cc799c238de91a2b466735d678a0bc7415ebefc2 0 t/t9110/svm.dump
+100755 a8d74dcd3aba7c462d46ea33c722d4307d24bded 0 t/t9111-git-svn-use-svnsync-props.sh
+100644 499fa9594fafe5d45a32005c189634b6a3048777 0 t/t9111/svnsync.dump
+100755 d470a920e4864ab0c494da1261fe835ff80474eb 0 t/t9112-git-svn-md5less-file.sh
+100755 8da8ce58eb1b29210a6ac95fdd3a3fcb547ca36f 0 t/t9113-git-svn-dcommit-new-file.sh
+100755 61d7781616eed4374c014cabd75a297c2baa348d 0 t/t9114-git-svn-dcommit-merge.sh
+100755 f0fbd3aff7e63f64f8ba388db805013c43b4b22c 0 t/t9115-git-svn-dcommit-funky-renames.sh
+100644 42422f791ea4240495e0b9cb5173bb7a27989958 0 t/t9115/funky-names.dump
+100755 4b2cc878f685e65b2ccd5d8153efb533320d6ee9 0 t/t9116-git-svn-log.sh
+100755 7a689bb1cd1d9daa1f17c0dcaaafa4d68ebd78fa 0 t/t9117-git-svn-init-clone.sh
+100755 3281cbd3472a8da58c4f6f0f3965b5810705b0e9 0 t/t9118-git-svn-funky-branch-names.sh
+100755 cc619115931cb74a85a171ade915ca2c47639c9b 0 t/t9119-git-svn-info.sh
+100755 5979e133b9d5b9d85ddca31a40763ed4fb6feba3 0 t/t9120-git-svn-clone-with-percent-escapes.sh
+100755 99230b08107102836f752c14e1b0a67804b35ea3 0 t/t9121-git-svn-fetch-renamed-dir.sh
+100644 5f9127be92616ea8fb8ace1cff80a37037cb15ec 0 t/t9121/renamed-dir.dump
+100755 1190576a658d08a680e177b748cfc5e69caa3ddb 0 t/t9122-git-svn-author.sh
+100755 c18878fad16a6565fe846cc958417fea73289dce 0 t/t9123-git-svn-rebuild-with-rewriteroot.sh
+100755 8223c5909e6ff6936cb0ccf4d0badfe43491af46 0 t/t9124-git-svn-dcommit-auto-props.sh
+100755 3e32e84e6cd32413f98b5189f869bfb8f0a7f354 0 t/t9200-git-cvsexportcommit.sh
+100755 1fc06c5a23b50d54c33755a9fce4ddd9ed3b9c79 0 t/t9300-fast-import.sh
+100755 c19b4a2bab586b21da43c7a838ba85626f913568 0 t/t9301-fast-export.sh
+100755 4b91f8d4c45dad075d69028c9c70aa9cb1959e2b 0 t/t9400-git-cvsserver-server.sh
+100755 e27a1c5f85bbecac652ce8d224f8fc5e99b02a4e 0 t/t9401-git-cvsserver-crlf.sh
+100755 ae7082be1d903e1f4d5758610d5166152f2847cc 0 t/t9500-gitweb-standalone-no-errors.sh
+100755 0d7786a8c730d17fa194346f1da2978d23256da9 0 t/t9600-cvsimport.sh
+100755 9706ee5773692bd8fcfbc9015ef062947c0a2da5 0 t/t9700-perl-git.sh
+100755 4d2312548a81762918ac05b9a0014195b08ea532 0 t/t9700/test.pl
+100644 11c027571b44c429b4f6fdca88bff9c3360c7545 0 t/test-lib.sh
+100644 7b181d15cebb4c86a6ad7fed3dbf30ce2223b4c5 0 t/test4012.png
+100644 7b181d15cebb4c86a6ad7fed3dbf30ce2223b4c5 0 t/test9200a.png
+100644 ac22ccbd3ee9f03a3b38249ac8efdbe96b5da2cd 0 t/test9200b.png
+100644 4470d2bf78e1fbb00d00e487f41daa4373cf48e1 0 tag.c
+100644 7a0cb0070d46ba8c49d71029dc0704188805ea62 0 tag.h
+100644 3467705e9b0e14a0230473186079e83a582e4345 0 tar.h
+100644 6759ecbf98f8a90d96b4918c130babdd87889f69 0 templates/.gitignore
+100644 9f3f1fc352dea624bd36e55802de190ead0ad9dd 0 templates/Makefile
+100644 fae88709a636f3a06cc813dd64b28bfee7fa2073 0 templates/branches--
+100755 8b2a2fe84feaeaba56953d6d4d0d649b3cf755eb 0 templates/hooks--applypatch-msg.sample
+100755 6ef1d29d09a10a5b6c3cbec0ac481931cd0d85fc 0 templates/hooks--commit-msg.sample
+100755 22668216a3cec5a00d804dc5e9a904a10fd0fd09 0 templates/hooks--post-commit.sample
+100755 18d2e0f72768c103d593cc2cf6d2b7a4bc8a9a01 0 templates/hooks--post-receive.sample
+100755 5323b56b81b9dd3d7f9fb86d8892241becbb5e7e 0 templates/hooks--post-update.sample
+100755 b1f187c2e9acaba942639bca90a63c5b4f058967 0 templates/hooks--pre-applypatch.sample
+100755 0e49279c7f7b805c78f1bc4760a0d1c70a84a0d9 0 templates/hooks--pre-commit.sample
+100755 be1b06e25043146f22261b55548229e6ab524b7c 0 templates/hooks--pre-rebase.sample
+100755 365242499dcf0ee35c26ccb2917724d6e559be69 0 templates/hooks--prepare-commit-msg.sample
+100755 93c605594fc06683088b934273873165215ccbb5 0 templates/hooks--update.sample
+100644 2c87b72dff61f8394b3f1f32e21c1d936314ec2e 0 templates/info--exclude
+100644 c6f25e80b8bcf0a21db2bea368b9e444c19bc0bf 0 templates/this--description
+100644 90da448ebec3e5375b7725ba7f297c1c74199b87 0 test-chmtime.c
+100644 62e8f2387a1cab97ec1c71d1993d082274e17bf5 0 test-date.c
+100644 3d885ff37ee7fc43dec05dd827679d68cee5516b 0 test-delta.c
+100644 8cefe6cfed87c8fe0c11d1263dae01639d2bd0f0 0 test-genrandom.c
+100644 a3c4688778d9db28c83c9149c9cff1609b69b93f 0 test-match-trees.c
+100644 2a79e729a4018ddb2da9ff633f4bf3b102fa8f88 0 test-parse-options.c
+100644 a0bcb0e210523124fa977c8bf46667cf25d0335f 0 test-path-utils.c
+100644 78d7e983a7a05ba0652132425a66477ef5773304 0 test-sha1.c
+100755 0f0bc5d02f4dcbd67c6d405350e5aaeb39f44bfb 0 test-sha1.sh
+100644 55e7e2904eb5f95cedaec2520ddd1d158ee93c7a 0 thread-utils.c
+100644 cce4b77bd6452e2ec589d8c0dc0e8156352dd67b 0 thread-utils.h
+100644 4713f9165c54405d51e81c3e90847120ee907e5d 0 trace.c
+100644 6eb65b873afc9dfd457e974b63d88350bb8dc913 0 transport.c
+100644 d0b52053fff9bc463438674232bffb6024f3b1fc 0 transport.h
+100644 bbb126fc46cfb28a0bc92cc0842c0dc72017751d 0 tree-diff.c
+100644 02e2aed7737207225f1b96eed774a1b75dd6d8d9 0 tree-walk.c
+100644 42110a465f9a8c91d1bc643dfae7a9b9c32e3719 0 tree-walk.h
+100644 03e782a9cabc0a12ed5baec0ef59c99f19dbc843 0 tree.c
+100644 2ff01a4f839ecc2206fcc1c13fee9d5d202b1128 0 tree.h
+100644 bcdc8bbb3b44a43aa43db6035a31478158e070af 0 unpack-file.c
+100644 cba0aca062f201c5cd5f8799f2190d4a6f06e7c7 0 unpack-trees.c
+100644 94e567265af9a69a30dd5c578439b6444e50004d 0 unpack-trees.h
+100644 7e8209ea4b43995737b36bc58db47e7dd6eadb19 0 update-server-info.c
+100644 c911e70c9aa47b70dac41b7f4de2f0b4b6c1f948 0 upload-pack.c
+100644 a5fc4ec5fae66823266862fa0254474696c220e6 0 usage.c
+100644 dc3735364f85273c2a119b994ddb405c09dc395c 0 utf8.c
+100644 98cce1b038a908bec51ccd2f7e1c1f648cb429a1 0 utf8.h
+100644 724ba87a7c9ccb16bc506fc3f25710a4b78e3006 0 var.c
+100644 0e68ee6d2e2fb1b866ecec00c5f6446af366a62e 0 walker.c
+100644 8a149e11084eeec4501b5b2c5d22e5266f4852e7 0 walker.h
+100644 93562f03eef21b26945d2d9bbdc96818f4de6567 0 wrapper.c
+100644 4c29255df1b637f93ab3d59e0dcab1fa3b40e10b 0 write_or_die.c
+100644 7a7ff130a34942506e6068105ac5946c9404bf18 0 ws.c
+100644 889e50f89fc24984f700d14f7033600fa9fdf642 0 wt-status.c
+100644 78add09bd67c727babb61cd1eaa773bcd0c6e55e 0 wt-status.h
+100644 61dc5c547019776b971dc89d009f628bbac134fd 0 xdiff-interface.c
+100644 f7f791d96b9a34ef0f08db4b007c5309b9adc3d6 0 xdiff-interface.h
+100644 413082e1fdf537d230a0f58940cee7466b965d0e 0 xdiff/xdiff.h
+100644 1bad8462fb32cffdc9ff20a278d513e7a444b257 0 xdiff/xdiffi.c
+100644 3e099dc445d6130f6a0ce2c6270a3b06d6ee119f 0 xdiff/xdiffi.h
+100644 d3d9c845c6420e4881636d779c7029f900a0b067 0 xdiff/xemit.c
+100644 440a7390fa4abb0411c336cfba616e3229484e86 0 xdiff/xemit.h
+100644 526ccb344d231fb978f53b80deb17ec6c8fed368 0 xdiff/xinclude.h
+100644 8ef232cfad12d706aaafe705bf16c546f3597182 0 xdiff/xmacros.h
+100644 82b3573e7ada8c6df13ac24a78650b80af91ea73 0 xdiff/xmerge.c
+100644 e87ab57c652b56b1a684e2a0a56885c1d1b27ef7 0 xdiff/xprepare.c
+100644 8fb06a537451cbf3335ab4bdacb0f992e9744338 0 xdiff/xprepare.h
+100644 2511aef8d89ab52be5ec6a5e46236b4b6bcd07ea 0 xdiff/xtypes.h
+100644 d7974d1a3e612a235b0c8adfde08ba802e782b5a 0 xdiff/xutils.c
+100644 d5de8292e05e7c36c4b68857c1cf9855e3d2f70a 0 xdiff/xutils.h
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.lstree b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.lstree
new file mode 100644
index 0000000000..2d1fad46f0
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/gitgit.lstree
@@ -0,0 +1,331 @@
+100644 blob 6b9c715d21d5486e59083fb6071566aa6ecd4d42 .gitattributes
+100644 blob a213e8e25bb2442326e86cbfb9ef56319f482869 .gitignore
+100644 blob 373476bdc03f718b4c01471dd9996ee4497f43a8 .mailmap
+100644 blob 9651afc89d5e789abd9cedaa4f3b92dde7dd1412 .project
+100644 blob 6ff87c4664981e4397625791c8ea3bbb5f2279a3 COPYING
+040000 tree fe83e22f0c04b81c62a335ef09d59c23ff93d6ca Documentation
+100755 blob cb7cd4b53827fa6820e84b1318572d0115b3b17f GIT-VERSION-GEN
+100644 blob 7d0c2c2f865d6ed969038e7543dbeb8933723ec3 INSTALL
+100644 blob 52c67c1a472455dcce5c19a21bbfd0520ff7dd26 Makefile
+100644 blob 548142c327a6790ff8821d67c2ee1eff7a656b52 README
+120000 blob b9a53c3416991b66e1d35c2bbf663b48340b0041 RelNotes
+100644 blob 0d561246e0a958d9a7284409b1900a82876eebf3 abspath.c
+100644 blob ccb1108c94436035d0da8b1d6f08f859b68294a3 alias.c
+100644 blob 216c23a6f854c614d38c743cd7687a37f304161b alloc.c
+100644 blob 13029619e5ec34bac4ba61a6fc08800ab36f4a1b archive-tar.c
+100644 blob cf285044e3576d0127c3215cb1253443d67517dc archive-zip.c
+100644 blob f834b5f51f4cf5d3b73d21dfd99198caef3b19f8 archive.c
+100644 blob 0b15b35143fffcc13764e4e668ee452b191cc609 archive.h
+040000 tree 36753f6455e2308e746447cde2c2113285bc9b02 arm
+100644 blob 17f6a4dca521d9690377f2e93a0192d8a874d2ad attr.c
+100644 blob f1c2038b0923d3130937eef965667204a8634e6d attr.h
+100644 blob b88270f90844095b3d352cc4213cbebd95a7f420 base85.c
+100644 blob bd7d078e1ae5fe4ce0a16fda62a2c1743237941b blob.c
+100644 blob ea5d9e9f8b63be2c7048d19ee53feb06b0795c80 blob.h
+100644 blob b1e59f2196b933ab7169a30efc5d1d340f8f9c5c branch.c
+100644 blob 9f0c2a2c1fab9a312f436880956da0973c68ead8 branch.h
+100644 blob fc3f96eaefff91e4e85adb92162716939f0ecd72 builtin-add.c
+100644 blob fc43eed36b55e4966796490b8c0a02fae790229c builtin-annotate.c
+100644 blob 2216a0bf7cd53adc31346f66a3b9786a1d688bad builtin-apply.c
+100644 blob 22445acbfc5279f391ac6afa855b21064ec54535 builtin-archive.c
+100644 blob 8b6b09b10b8f9dcda0b7224f31c860bb803945f0 builtin-blame.c
+100644 blob b1a2ad7a6b3b150cda8d031a87352a4daedc40ea builtin-branch.c
+100644 blob ac476e7a4b45fc55b6b6d1e4d02be0c35aba2c7b builtin-bundle.c
+100644 blob 7441a56acdbefdd8044a406f4d756ce8a4f06644 builtin-cat-file.c
+100644 blob cb783fc77e75515a02ed2268dfb37ee3bbd03749 builtin-check-attr.c
+100644 blob fe04be77a9312c11fa054897c5982fa6c74b8e5e builtin-check-ref-format.c
+100644 blob 71ebabf9903bd90b7da59c47f1c0819b5f25c538 builtin-checkout-index.c
+100644 blob 411cc513c65ba854221ad52dd6aeaaac7d213c9d builtin-checkout.c
+100644 blob 48bf29f40a5e06fd588b34c468535e04abcf206b builtin-clean.c
+100644 blob e086a40b41810c30a4f5228daa4e38857dae84d5 builtin-clone.c
+100644 blob 7a9a309be0543da7d27e7710ef82271f2582e0a9 builtin-commit-tree.c
+100644 blob f7c053a0106c2e42833d0d7c7255b7b636d09a93 builtin-commit.c
+100644 blob 91fdc4985d8e64fae12209174dd4aa2d887793e5 builtin-config.c
+100644 blob 91b5487478998e39bb8ae4a5cb667360cff82c9a builtin-count-objects.c
+100644 blob ec404c839b6542deb4e15ca342fd3c0afbbedd2e builtin-describe.c
+100644 blob 9bf10bb37e2f56ec2a10239d7419db8fbb641745 builtin-diff-files.c
+100644 blob 17d851b29ee5de33e01745eabcd5cd735c30b352 builtin-diff-index.c
+100644 blob 415cb1612f5322da89850874ba81885e41808678 builtin-diff-tree.c
+100644 blob 7ffea975059f9e13b07ca680e6707ffc14973f90 builtin-diff.c
+100644 blob 070971616dbb12d005c5c9a1f82cc5b0c5391f62 builtin-fast-export.c
+100644 blob 7460ab7fce2a4e6a7e014f448819140e2204ccb7 builtin-fetch--tool.c
+100644 blob 273239af3be61736ee4ff484d628950c4de7311a builtin-fetch-pack.c
+100644 blob 7eec4a0e43ad5760f1060a7d5bcf2a5083015130 builtin-fetch.c
+100644 blob df02ba7afdd615492361a1897a9dedd6ab233c96 builtin-fmt-merge-msg.c
+100644 blob 445039e19c75e4c9321f7ee64289ef8201a25c14 builtin-for-each-ref.c
+100644 blob 6eb7da88d3e8591a8c544acc61a42e00babff120 builtin-fsck.c
+100644 blob fac200e0b08360625afc81b02913128c9b87f486 builtin-gc.c
+100644 blob 631129ddfd0ffe06f919882d22cfc494d9553f50 builtin-grep.c
+100644 blob 3a062487a7eacd01ed824b46a9124dd343cd2e60 builtin-http-fetch.c
+100644 blob baf0d09ac4ea372b4015d399560a133b401b55cc builtin-init-db.c
+100644 blob f4975cf35f7f1555739f7657ee62ed983d18cb84 builtin-log.c
+100644 blob e8d568eed7ab700bc338af8f589d2f61e81f323c builtin-ls-files.c
+100644 blob c21b841e7c5e8d27a6e66e7f70786d77aa4653b5 builtin-ls-remote.c
+100644 blob d25767a1f7eb0a8b45bc1eed6b9aa95de0847f18 builtin-ls-tree.c
+100644 blob f974b9df968c74c5d62d58b2a09493e6abb4322e builtin-mailinfo.c
+100644 blob 71f3b3b8741e505fc652e6c74c75972f19211f71 builtin-mailsplit.c
+100644 blob 3382b1382a7dcbd525126a35209072da4b4d8041 builtin-merge-base.c
+100644 blob 3605960c2d9692514a6df0f344f3c3269cf1de3c builtin-merge-file.c
+100644 blob 8f5bbaf402e020e308e7af9cedb7df1b2ec5a2b7 builtin-merge-ours.c
+100644 blob 43e55bf90154c51b94527b2ab7eb7c60fe36e9ec builtin-merge-recursive.c
+100644 blob dde0c7ed33118ff8d0cc421e8a0366e342c6d011 builtin-merge.c
+100644 blob 4f65b5ae9baf66953e79886fd93fe31786b24d36 builtin-mv.c
+100644 blob 85612c4dcb719b460623204046e35486e9d9fe97 builtin-name-rev.c
+100644 blob 2dadec1630c266bbaf42e84810f7059ed5c43b1e builtin-pack-objects.c
+100644 blob 34246df4ec946273d9f42e6f0848b02d8510beea builtin-pack-refs.c
+100644 blob 10cb8df8457fd5f2ba9be62ecd0f9384e21c3e63 builtin-prune-packed.c
+100644 blob 947de8cf258c73d8a327ef3a1daed417ba533f1b builtin-prune.c
+100644 blob c1ed68d938f67343c6938cfef54d5ff69a522a63 builtin-push.c
+100644 blob 72a6de302f88728af17ce5c5c6983c5267afc6f6 builtin-read-tree.c
+100644 blob 0c34e378199064e87aa09caf0fa0a2346333ec69 builtin-reflog.c
+100644 blob 54d1c3e3d16b2cebcff0c6c57d98756e48472b67 builtin-remote.c
+100644 blob dd4573fe8dcd9dc8edd5a7d41bc8daa83034ee7e builtin-rerere.c
+100644 blob c24c21909194014b467c86fd3598796e7db576b3 builtin-reset.c
+100644 blob 893762c80f4910fadf2d6df414bd835cccb7faaa builtin-rev-list.c
+100644 blob 9aa049ec170b0125fddde29adda3c720c8a7b8ee builtin-rev-parse.c
+100644 blob e9da870d22c14c32a0e0a6cb71b933c79a2d8b53 builtin-revert.c
+100644 blob ee8247b08cd007f73d5dfffa560a9efe33d327b9 builtin-rm.c
+100644 blob 7588d22885d0af24ae80f1d687ccd097fe365021 builtin-send-pack.c
+100644 blob d03f14fdad3d17dde06734d78ddb4aade6ed4f2b builtin-shortlog.c
+100644 blob 233eed499d0b8790781326ff0455bdc7f09fe4d4 builtin-show-branch.c
+100644 blob add16004f11375b1ad2b97f9b1bf1ced5c437f81 builtin-show-ref.c
+100644 blob c0b21301ba4c126a49ed38b6983756b99a25aae0 builtin-stripspace.c
+100644 blob bfc78bb3f6eff2f8e39649b9649ae7263f143ad9 builtin-symbolic-ref.c
+100644 blob 325b1b2632e44121c23bc6df556bf3aa4e32ba04 builtin-tag.c
+100644 blob f4bea4a322c26a54734286073c5e67444555c2d9 builtin-tar-tree.c
+100644 blob a8918666655bb91f952ccdac18715bd9ba4a09f2 builtin-unpack-objects.c
+100644 blob 38eb53ccba2b97a0fccf50d6ba0b7424fe2d1bcb builtin-update-index.c
+100644 blob 56a0b1b39cf4c4fc51dbbff256240655bc36a038 builtin-update-ref.c
+100644 blob a9b02fa32f372a6810867c10560a20d58b5b2a91 builtin-upload-archive.c
+100644 blob f4ac595695b1fff1317ff7d14ea9427780327aea builtin-verify-pack.c
+100644 blob 729a1593e61d87ad4596f07e7faedac81de64e81 builtin-verify-tag.c
+100644 blob 52a3c015ff8e4611522bd41078bdb2934d288d35 builtin-write-tree.c
+100644 blob f3502d305e4f65e9707fe8b738f64be6e49f7f84 builtin.h
+100644 blob 00b2aabefca49b634f49143523ee31556baa7777 bundle.c
+100644 blob e2aedd60d6ad1482bb6da173c853e6ba4805c8d7 bundle.h
+100644 blob 5f8ee87bb1c446341b640c2f978a658d6bfcfcd0 cache-tree.c
+100644 blob cf8b790874c4a4f5890b360c237ccdd4a5a03de4 cache-tree.h
+100644 blob 2475de9fa837596303284157e08b3080d64351ee cache.h
+100755 blob d6fe6cf1749ebcd6189fa36cbb4e14a532d2d17b check-builtins.sh
+100644 blob 00d92a16631a80ff8ec4e995dafcd3e55434fad5 check-racy.c
+100755 blob a1c4c3e8d845e8e791d7df0c1387e1b2262b5ecf check_bindir
+100644 blob fc0b72ad59b13e4bd86372e5e81b4f400c99d26e color.c
+100644 blob 6cf5c88aaf8d0e38e2853e6fd212e3cdd6c180cb color.h
+100644 blob 9f80a1c5e3a461afd11966625589684d61187911 combine-diff.c
+100644 blob 3583a33ee90647d8e6ded02643eb75753760d94f command-list.txt
+100644 blob dc0c5bfdab7296bf7febb6f1b1aad64550838c15 commit.c
+100644 blob 77de9621d9c926c6fb8a2bf9ca81c6c376a2ad41 commit.h
+040000 tree 3612b1a756de51eb5beb16e0c3b958e74f8bc53d compat
+100644 blob 53f04a076a7275965090edd4ca2a34652c4f5679 config.c
+100644 blob b776149531025c85f5665d971e6e072f0cc64893 config.mak.in
+100644 blob 7c2856efc92ca55e3cf03fcf1c72ffb70318f7c3 configure.ac
+100644 blob 574f42fa47ffa69328217eb25afee6f85db9595e connect.c
+040000 tree ed65cee05eb473aca9cfae781f109d464dcbd711 contrib
+100644 blob 78efed800d4d64898d438d9590b01be008cfcd36 convert.c
+100644 blob e54d15aced7595ccb11423b0de121db9051ad1f3 copy.c
+100644 blob ace64f165e4a01fb99892e9b89e7df791a7f4ca1 csum-file.c
+100644 blob 72c9487f4fd9fcab5e02fc2dc6afd3cb7f9c036a csum-file.h
+100644 blob ee06eb7f48f1d3e818b3037369b4e056fe7e5be7 ctype.c
+100644 blob 4540e8df5ab8bc8ff66549144d7db2928e12199b daemon.c
+100644 blob 35a52576c53e5e1406d40ed4402b8834a29b9f0e date.c
+100644 blob d9668d2ef94c73e4a7a5602011ff13a9fd9d8c6a decorate.c
+100644 blob 1fa4ad9beb08f23888814b99183487ab85378bfd decorate.h
+100644 blob 40ccf5a1e95f62d840a006274f7024fa43208b1c delta.h
+100644 blob a4e28df714b4834e5efe42fa3abb647711913d71 diff-delta.c
+100644 blob e7eaff9a68ccbcc692522c9956f0dae9af45f3f1 diff-lib.c
+100644 blob 7d68b7f1bef1039b4996e662fb17968c4e3e3e79 diff-no-index.c
+100644 blob cbf25473c594abfd1fc13473108dc9c15e2f1d15 diff.c
+100644 blob 50fb5ddb0bec02b0cd5498d6ecc37d44bf874476 diff.h
+100644 blob 31cdcfe8bcdae7df65b0387071846299a14bb7be diffcore-break.c
+100644 blob e670f8512558c38d9a9d6e754cfc609b042b1195 diffcore-delta.c
+100644 blob 23e93852d8c701760d56e7e728dba7c08367fbe8 diffcore-order.c
+100644 blob af9fffe6e8e145b066157da8791c749257e7c8e9 diffcore-pickaxe.c
+100644 blob 1b2ebb40014d820fe4fb679509ab694d453be7b4 diffcore-rename.c
+100644 blob cc96c20734bf4184970f5381416637cf6e45ea13 diffcore.h
+100644 blob 29d1d5ba31def46ba8b55905dc60773cc6cc167e dir.c
+100644 blob 2df15defb6720a742282f24721233c4816deceb6 dir.h
+100644 blob 1f73f1ea7dfa6a14dedf384c99751e86c8121ff4 dump-cache-tree.c
+100644 blob eebc3e95fe0c7e61f7c29fa5412ea9d4a5900f92 editor.c
+100644 blob 222aaa374b8268828e9d529a8afacb8830acc281 entry.c
+100644 blob 0c6d11f6a0c6fa5dbab2f36c4b4ad4de5aba4ac9 environment.c
+100644 blob ce6741eb682b59ad638c7bee6ca31e2fcd53f281 exec_cmd.c
+100644 blob 594f961387240c221020c9ea0bccd8a39ff69595 exec_cmd.h
+100644 blob 7089e6f9e6c5fa9142f468e54afe7d33a6d2eec7 fast-import.c
+100644 blob 8bd9c32561e79d194d27fa10cc98a26aa2cb673c fetch-pack.h
+100755 blob 63dfa4c475ae3632fc5cfd093d949a41683a5458 fixup-builtins
+100644 blob 797e3178ae279f444d2efa7e3758652ad0898dd7 fsck.c
+100644 blob 990ee02335a2e2693e32baa82b259c23843f2aa0 fsck.h
+100755 blob a2913c2a2cd1ec158157ada3e2deb666892b734b generate-cmdlist.sh
+100755 blob da768ee7acc22e6480f0a067e109239561d43927 git-add--interactive.perl
+100755 blob 6aa819280ef99ccbbdeefde037e99fae3e6f0110 git-am.sh
+100755 blob 98f3ede566a6cb0c902ce84795f7de8f8afbe633 git-archimport.perl
+100755 blob 3cac20db79e1e408a321b0e9d272501985a3c49b git-bisect.sh
+100644 blob cf89cdf4598b3796724a85aa707f740245155cdc git-compat-util.h
+100755 blob 6d9f0ef0f989133422cf8c0302e63dab15a999d5 git-cvsexportcommit.perl
+100755 blob e2664ef01308fd0fb65d47b25e0ae73a65aa6262 git-cvsimport.perl
+100755 blob b0a805c688f59af29e1f25b514d73f3991285dee git-cvsserver.perl
+100755 blob 182822a24e214fe7e93a2df68fdda3dd40b5896d git-filter-branch.sh
+040000 tree 320e89a01513e3630eb681d9524ff835d56f6690 git-gui
+100755 blob 0843372b57371b62cd68f2818f634209f55d5395 git-instaweb.sh
+100755 blob 9cedaf80ceac1d4100adf3cfb152c76c7f945e4d git-lost-found.sh
+100755 blob 645e1147dc886f2b1ca6d2020b44db746b082bf0 git-merge-octopus.sh
+100755 blob e1eb9632660146396a0b5f3f2a410d8cb027ff9d git-merge-one-file.sh
+100755 blob 93bcfc2f5dce418d00f26257788932d5c738785c git-merge-resolve.sh
+100755 blob 94187c306ccb05d977f2bb35e81828130ab49a61 git-mergetool.sh
+100755 blob 695a4094bb4230341618bd6f16d0bea9bff2e826 git-parse-remote.sh
+100755 blob 75c36100a2f858bcf2663d2b4560654787963175 git-pull.sh
+100755 blob cebaee1cc9dfc28d80173583b144a480be2f9bfd git-quiltimport.sh
+100755 blob 4e334ba41dad3067394b79c15ebfe610b2d3e178 git-rebase--interactive.sh
+100755 blob 412e135c3ae88d76b5bdf3f08083b153da220a95 git-rebase.sh
+100755 blob 937c69a74858a8a3c63bb41a23705b579df1b3a3 git-relink.perl
+100755 blob 683960b04d6b743e687b2eb640d2b0e00ccfd313 git-repack.sh
+100755 blob 073a314c8043e0ff30afde65e012e356ff0d186f git-request-pull.sh
+100755 blob d2fd89907688a044ffe0d2520744e00a9b33c942 git-send-email.perl
+100755 blob dbdf209ec0e7d6468c199d1905c3e7788a9cd246 git-sh-setup.sh
+100755 blob d4609ed66e56dc6021c800d60286bec38615ff39 git-stash.sh
+100755 blob b40f876a2ca9fe985cedc622ab28a9f461edc5ab git-submodule.sh
+100755 blob cf6dbbc42773fef394c27cd87109b69c3144753c git-svn.perl
+100755 blob 384148a59fc492d8fb1d6ea4fc4532aa1e5ffc22 git-web--browse.sh
+100644 blob 37b1d76a08ca59f3de54e11890dce962403cf8d3 git.c
+100644 blob c6492e5be2763eab81358424ff625a34a5ff2fba git.spec.in
+040000 tree 615732133b5e3dcd80f5477f3ca94574e4430957 gitk-git
+040000 tree e3fbfd0f5bfe5e8927abb7fe37a59585aef9a405 gitweb
+100644 blob e2633f8376eb7b12706dcd4c698e2b3f6be2b433 graph.c
+100644 blob eab4e3daba9812293d4e005c3ebe28f9a97744ce graph.h
+100644 blob f67d6716ea5f42c3384a7a4cb2eb973b02785fba grep.c
+100644 blob d252dd25f81526d9b8663b4d3c9585d69a901397 grep.h
+100644 blob 46c06a9552dac5475afc607c3fe2bf00801eb055 hash-object.c
+100644 blob 1cd4c9d5c0945994b84bb25edd6e4685cf76b5c5 hash.c
+100644 blob 69e33a47b9861df9ac12c354eae180b4f8fea857 hash.h
+100644 blob 3cb19628965685ce59a5377b81bef975851996e8 help.c
+100644 blob 68052888570af7d09535db8831b8cf3ef2881589 http-push.c
+100644 blob 9dc6b27b457a2979a95018679a0b885e6fb62d9a http-walker.c
+100644 blob 1108ab4a3101fb4768cad420ccfdb52d87890a18 http.c
+100644 blob 905b4629a47789705c13745fd56ce0c91adea41b http.h
+100644 blob b35504a8d25594a8d243ae7490733eae5a262712 ident.c
+100644 blob 1ec131092109aa3fbed3cd20f10b56a864584a94 imap-send.c
+100644 blob 52064befdbbbdf671bd08e369a133d4f1fee03c1 index-pack.c
+100644 blob 7f03bd99c5b66afa6cc7fa11a2430301a3042656 interpolate.c
+100644 blob 77407e67dca97eb85274c69e2e7469e1d4d40b3b interpolate.h
+100644 blob c8b8375e4983794e601ba69a1c217a3c711835e9 list-objects.c
+100644 blob 0f41391ecc00eac324ea76de7654781c4fce094e list-objects.h
+100644 blob 9837c842a3f215ebee7cbe9690e42e216fb5c76c ll-merge.c
+100644 blob 5388422d091ede134d42406291989c49553f7428 ll-merge.h
+100644 blob 4023797b00fe21ecbabe3407ef8a12fca0690607 lockfile.c
+100644 blob bd8b9e45ab46b8664c8b7016b33bee22f86c9e0d log-tree.c
+100644 blob 59ba4c48b7966db34c6345a445ab0b10e235ac83 log-tree.h
+100644 blob 88fc6f394684436967002ca477eac1e084537348 mailmap.c
+100644 blob 6e48f83cedd13e24d50cddf47f037791ddc5ad4b mailmap.h
+100644 blob 0fd6df7d6ed839eaed536bc332312c2688a6bbad match-trees.c
+100644 blob 2a939c9dd835a7e7946eb1548e4cf637ae3ca329 merge-file.c
+100644 blob 7491c56ad25332fb4aae6a075bf0577a1d800c3b merge-index.c
+100644 blob f37630a8ad07709ae106ddde44a34daf6bad8b16 merge-recursive.h
+100644 blob 02fc10f7e622ba1c53065e7cf4563ff10af0c41f merge-tree.c
+100644 blob 0b34341f711a903d4a12fe96dc6ef63e55fb2f5b mktag.c
+100644 blob e0da110a98d3a7376dc78df71fabc10fc5664296 mktree.c
+040000 tree 930c4b2743737c3dd8a58309fd66f019f08ab12f mozilla-sha1
+100644 blob 0031d78e8c98a32d61cd0dc0f939a033e24ed890 name-hash.c
+100644 blob 50b6528001fe4bafdfe70126dc2078860c3d1969 object.c
+100644 blob 036bd66fe9b6591e959e6df51160e636ab1a682e object.h
+100644 blob f596bf2db5e0a0065e6856b8caa3ded8a134f74d pack-check.c
+100644 blob 25b81a445c8fafe0c00ce30082b7d9a7c22ccf1e pack-redundant.c
+100644 blob 848d311c2b2c651dbb14893c260584f00c639357 pack-refs.c
+100644 blob 518acfb370ad72be18399a3ac5e8ca17880281c9 pack-refs.h
+100644 blob cd300bdff5b524a4d509ba5276e9ef21f443013d pack-revindex.c
+100644 blob 36a514a6cf600e7e77794e50998a9d160e30c8e9 pack-revindex.h
+100644 blob a8f02699366c87de960d7637e9f69c26c2241693 pack-write.c
+100644 blob 76e6aa2aad06545e7c44fc2c1e117ea668356ccf pack.h
+100644 blob 6b5c9e44b4ded338ddb344ae454d83a685b7569a pager.c
+100644 blob 71a7acf4e22bd12c0919f277410d6ec52dd5efc8 parse-options.c
+100644 blob bc317e7512af7a1cc86641a651ae5415d28e71c4 parse-options.h
+100644 blob ed9db81fa82c812c9ffa07f5a40540dbb15da0d3 patch-delta.c
+100644 blob 9349bc5580456b378d41da7cc2518e4fa9a7e81a patch-id.c
+100644 blob 3be5d3165e0009761a0ca69e15e4a9132c6cfaff patch-ids.c
+100644 blob c8c7ca110ad34def12a3594a1560b3c3052eb701 patch-ids.h
+100644 blob 9df447bd6dcfaddf7f05fe5f0b624700ff1f40d7 path.c
+040000 tree 7f5daf8444afe10cabcfff7b46dcf101777301cb perl
+100644 blob f5d00863a6234c16db33637d19fefd2014780e87 pkt-line.c
+100644 blob 9df653f6f5afe720870658d7093bddbf3e66beaf pkt-line.h
+040000 tree 6f6159f0245784352414ff38ffb68bae80f30bd6 ppc
+100644 blob 33ef34a4119812674726254fee3f391fb5734fdb pretty.c
+100644 blob 55a8687ad15788f8ea5a5beb463d216908f618b2 progress.c
+100644 blob 611e4c4d42d8d1164add09f926ad5b2ce088db5e progress.h
+100644 blob 6a520855d6c418ecb1384ef9571b122b134af1af quote.c
+100644 blob c5eea6f18e2dfabd071b73e6507c34c2b7b5e39f quote.h
+100644 blob 3b1c18ff9b9060d0dd437ce89aedb8871c66c54c reachable.c
+100644 blob 40751810b64f8bbf9c0a633472a0ef27d23ed1a5 reachable.h
+100644 blob 2c03ec3069decb20f7557af4ac7dbe295f2dcf9c read-cache.c
+100644 blob d44c19e6b577023dcbaa188a0e67130ff4e5bd9a receive-pack.c
+100644 blob f751fdc8d832cae54647c1a70d888e979d324fd8 reflog-walk.c
+100644 blob 7ca1438f4d74b652f962c6bdfddd08fe0d75802d reflog-walk.h
+100644 blob 39a3b23804d2da715c564459bf320be23d41c1bf refs.c
+100644 blob 06ad26055661a9b9e475d0f8a7bd6d1cfb42e792 refs.h
+100644 blob f61a3ab399aa6960fb8eba050321cea4a3b05344 remote.c
+100644 blob 091b1d041f8a4d255f59bfc001e098e692dbc15c remote.h
+100644 blob 323e493dafee46c0d3f95e3c4cd9c4c9b463bbef rerere.c
+100644 blob f9b03862fe78b560ee606637be3b1ce972a2cc14 rerere.h
+100644 blob 3897fec53170c50921eb1952bc4bdf9c08480638 revision.c
+100644 blob f64e8ce7ff999e9fe4a01205ae51775827484ed4 revision.h
+100644 blob a3b28a64dc2d1b888b0ba2a135be10fe04651201 run-command.c
+100644 blob 5203a9ebb10b14bd06862abafed0ab73d7514a3d run-command.h
+100644 blob 8ff1dc35390083c3648c4ee5790f35633d956069 send-pack.h
+100644 blob c1c073b2f05a48772a45602cdc711eef6e211695 server-info.c
+100644 blob 6cf909463d4ad3681a2f35269db9dc944f4389c2 setup.c
+100644 blob da357479cf19aad4bebc64f874c76fdf8566712b sha1-lookup.c
+100644 blob 3249a81b3d664afc89c98e6d9dd6b512092a82f9 sha1-lookup.h
+100644 blob e281c14f01d37ab7623998c2990914aca49a7a3b sha1_file.c
+100644 blob 4fb77f8863ec075de38b84171d3ef039a00cee4c sha1_name.c
+100644 blob 4d90eda19efe0a80c1cb39e8897ab3ed5e6fcf56 shallow.c
+100644 blob 6a48de05ff80f86050715ef3dab87a48b0a86ac9 shell.c
+100644 blob bc02cc29ef0d5f640ab390614def995f30fe4691 shortlog.h
+100644 blob 45bb535773fd9c36f73502df9462f7de800009c8 show-index.c
+100644 blob b6777812cb92c1c169ee395164d53a0c2e6eceb2 sideband.c
+100644 blob a84b6917c7a17b5f8a922540801e98d46aa24431 sideband.h
+100644 blob 720737d856b694bc5239f0c18af372959c99e744 strbuf.c
+100644 blob eba7ba423a2d3a383ef93f663c95695438269edf strbuf.h
+100644 blob ddd83c8c76112cecd5d23668aaca467601855a72 string-list.c
+100644 blob 4d6a7051fe5bccf04a0d0c32a90e5cf9c00dba3c string-list.h
+100644 blob 5a5e781a15d7d9cb60797958433eca896b31ec85 symlinks.c
+040000 tree 40b1d0c852cbaf154abff6e8f5e94537c1184548 t
+100644 blob 4470d2bf78e1fbb00d00e487f41daa4373cf48e1 tag.c
+100644 blob 7a0cb0070d46ba8c49d71029dc0704188805ea62 tag.h
+100644 blob 3467705e9b0e14a0230473186079e83a582e4345 tar.h
+040000 tree b9afb0508810e32cc63b582eb84bc72c8d2225cd templates
+100644 blob 90da448ebec3e5375b7725ba7f297c1c74199b87 test-chmtime.c
+100644 blob 62e8f2387a1cab97ec1c71d1993d082274e17bf5 test-date.c
+100644 blob 3d885ff37ee7fc43dec05dd827679d68cee5516b test-delta.c
+100644 blob 8cefe6cfed87c8fe0c11d1263dae01639d2bd0f0 test-genrandom.c
+100644 blob a3c4688778d9db28c83c9149c9cff1609b69b93f test-match-trees.c
+100644 blob 2a79e729a4018ddb2da9ff633f4bf3b102fa8f88 test-parse-options.c
+100644 blob a0bcb0e210523124fa977c8bf46667cf25d0335f test-path-utils.c
+100644 blob 78d7e983a7a05ba0652132425a66477ef5773304 test-sha1.c
+100755 blob 0f0bc5d02f4dcbd67c6d405350e5aaeb39f44bfb test-sha1.sh
+100644 blob 55e7e2904eb5f95cedaec2520ddd1d158ee93c7a thread-utils.c
+100644 blob cce4b77bd6452e2ec589d8c0dc0e8156352dd67b thread-utils.h
+100644 blob 4713f9165c54405d51e81c3e90847120ee907e5d trace.c
+100644 blob 6eb65b873afc9dfd457e974b63d88350bb8dc913 transport.c
+100644 blob d0b52053fff9bc463438674232bffb6024f3b1fc transport.h
+100644 blob bbb126fc46cfb28a0bc92cc0842c0dc72017751d tree-diff.c
+100644 blob 02e2aed7737207225f1b96eed774a1b75dd6d8d9 tree-walk.c
+100644 blob 42110a465f9a8c91d1bc643dfae7a9b9c32e3719 tree-walk.h
+100644 blob 03e782a9cabc0a12ed5baec0ef59c99f19dbc843 tree.c
+100644 blob 2ff01a4f839ecc2206fcc1c13fee9d5d202b1128 tree.h
+100644 blob bcdc8bbb3b44a43aa43db6035a31478158e070af unpack-file.c
+100644 blob cba0aca062f201c5cd5f8799f2190d4a6f06e7c7 unpack-trees.c
+100644 blob 94e567265af9a69a30dd5c578439b6444e50004d unpack-trees.h
+100644 blob 7e8209ea4b43995737b36bc58db47e7dd6eadb19 update-server-info.c
+100644 blob c911e70c9aa47b70dac41b7f4de2f0b4b6c1f948 upload-pack.c
+100644 blob a5fc4ec5fae66823266862fa0254474696c220e6 usage.c
+100644 blob dc3735364f85273c2a119b994ddb405c09dc395c utf8.c
+100644 blob 98cce1b038a908bec51ccd2f7e1c1f648cb429a1 utf8.h
+100644 blob 724ba87a7c9ccb16bc506fc3f25710a4b78e3006 var.c
+100644 blob 0e68ee6d2e2fb1b866ecec00c5f6446af366a62e walker.c
+100644 blob 8a149e11084eeec4501b5b2c5d22e5266f4852e7 walker.h
+100644 blob 93562f03eef21b26945d2d9bbdc96818f4de6567 wrapper.c
+100644 blob 4c29255df1b637f93ab3d59e0dcab1fa3b40e10b write_or_die.c
+100644 blob 7a7ff130a34942506e6068105ac5946c9404bf18 ws.c
+100644 blob 889e50f89fc24984f700d14f7033600fa9fdf642 wt-status.c
+100644 blob 78add09bd67c727babb61cd1eaa773bcd0c6e55e wt-status.h
+100644 blob 61dc5c547019776b971dc89d009f628bbac134fd xdiff-interface.c
+100644 blob f7f791d96b9a34ef0f08db4b007c5309b9adc3d6 xdiff-interface.h
+040000 tree 88b6f65753131f1f2c0dbceb1f37950e3494833a xdiff
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-3280af9c07ee18a87705ef50b0cc4cd20266cf12.idx b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-3280af9c07ee18a87705ef50b0cc4cd20266cf12.idx
new file mode 100644
index 0000000000..300c0cea48
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-3280af9c07ee18a87705ef50b0cc4cd20266cf12.idx
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-3280af9c07ee18a87705ef50b0cc4cd20266cf12.pack b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-3280af9c07ee18a87705ef50b0cc4cd20266cf12.pack
new file mode 100644
index 0000000000..fca3460ed2
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-3280af9c07ee18a87705ef50b0cc4cd20266cf12.pack
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.idx b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.idx
new file mode 100644
index 0000000000..84a6c0fbea
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.idx
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.idxV2 b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.idxV2
new file mode 100644
index 0000000000..1d45fa811a
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.idxV2
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.pack b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.pack
new file mode 100644
index 0000000000..99f4fdf232
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-34be9032ac282b11fa9babdc2b2a93ca996c9c2f.pack
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-546ff360fe3488adb20860ce3436a2d6373d2796.idx b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-546ff360fe3488adb20860ce3436a2d6373d2796.idx
new file mode 100755
index 0000000000..60331335d9
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-546ff360fe3488adb20860ce3436a2d6373d2796.idx
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-546ff360fe3488adb20860ce3436a2d6373d2796.pack b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-546ff360fe3488adb20860ce3436a2d6373d2796.pack
new file mode 100755
index 0000000000..203c157657
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-546ff360fe3488adb20860ce3436a2d6373d2796.pack
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-9fb5b411fe6dfa89cc2e6b89d2bd8e5de02b5745.idx b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-9fb5b411fe6dfa89cc2e6b89d2bd8e5de02b5745.idx
new file mode 100644
index 0000000000..58b712f6c5
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-9fb5b411fe6dfa89cc2e6b89d2bd8e5de02b5745.idx
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-9fb5b411fe6dfa89cc2e6b89d2bd8e5de02b5745.pack b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-9fb5b411fe6dfa89cc2e6b89d2bd8e5de02b5745.pack
new file mode 100644
index 0000000000..0b0001020a
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-9fb5b411fe6dfa89cc2e6b89d2bd8e5de02b5745.pack
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.idx b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.idx
new file mode 100644
index 0000000000..a5aed7def2
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.idx
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.pack b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.pack
new file mode 100644
index 0000000000..24f69429a0
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-cbdeda40019ae0e6e789088ea0f51f164f489d14.pack
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.idx b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.idx
new file mode 100644
index 0000000000..3ff5423774
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.idx
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.idxV2 b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.idxV2
new file mode 100644
index 0000000000..ccbf00e34f
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.idxV2
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.pack b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.pack
new file mode 100644
index 0000000000..ef56d7e941
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-df2982f284bbabb6bdb59ee3fcc6eb0983e20371.pack
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-e6d07037cbcf13376308a0a995d1fa48f8f76aaa.idx b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-e6d07037cbcf13376308a0a995d1fa48f8f76aaa.idx
new file mode 100644
index 0000000000..d515f905f2
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-e6d07037cbcf13376308a0a995d1fa48f8f76aaa.idx
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-e6d07037cbcf13376308a0a995d1fa48f8f76aaa.pack b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-e6d07037cbcf13376308a0a995d1fa48f8f76aaa.pack
new file mode 100644
index 0000000000..72712b20be
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-e6d07037cbcf13376308a0a995d1fa48f8f76aaa.pack
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-huge.idx b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-huge.idx
new file mode 100644
index 0000000000..0a5bbfb6a6
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/pack-huge.idx
Binary files differ
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/packed-refs b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/packed-refs
new file mode 100644
index 0000000000..82fb0d7b34
--- /dev/null
+++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/test/resources/packed-refs
@@ -0,0 +1,36 @@
+# pack-refs with: peeled
+6db9c2ebf75590eef973081736730a9ea169a0c4 refs/heads/a
+7f822839a2fe9760f386cbbbcb3f92c5fe81def7 refs/heads/b
+6e1475206e57110fcef4b92320436c1e9872a322 refs/heads/c
+f73b95671f326616d66b2afb3bdfcdbbce110b44 refs/heads/d
+d0114ab8ac326bab30e3a657a0397578c5a1af88 refs/heads/e
+47d3697c3747e8184e0dc479ccbd01e359023577 refs/heads/f
+175d5b80bd9768884d8fced02e9bd33488174396 refs/heads/g
+175d5b80bd9768884d8fced02e9bd33488174396 refs/heads/prefix/a
+68cb1f232964f3cd698afc1dafe583937203c587 refs/heads/gitlink
+49322bb17d3acc9146f98c97d078513228bbf3c0 refs/heads/master
+d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864 refs/heads/pa
+5ce00008cf3fb8f194f52742020bd40d78f3f1b3 refs/heads/symlink
+6db9c2ebf75590eef973081736730a9ea169a0c4 refs/tags/A
+17768080a2318cd89bba4c8b87834401e2095703 refs/tags/B
+^d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864
+032c063ce34486359e3ee3d4f9e5c225b9e1a4c2 refs/tags/B10th
+^d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864
+214cae792433672d28b3aeb9f75c1ae84fd54628 refs/tags/B2nd
+^d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864
+1170b77a48d3ea2d58b043648b1ec63d606e3efa refs/tags/B3rd
+^d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864
+8dfd42699e7b10e568fa1eaebe249e33e98da81e refs/tags/B4th
+^d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864
+efee904c794b943a06931c76c576dd552212e8bc refs/tags/B5th
+^d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864
+d54e006ebbef94b7d3a5cd56d154f1e6f08efb94 refs/tags/B6th
+^d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864
+a773cd2d9dbca00d08793dac0d7002a49f0428c0 refs/tags/B7th
+^d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864
+bf5123bb77c7b5a379f7de9c1293558e3e24dfb8 refs/tags/B8th
+^d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864
+dd144af286452bfd6a1ea02b0d3745bcdb555e9d refs/tags/B9th
+^d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864
+8bbde7aacf771a9afb6992434f1ae413e010c6d8 refs/tags/spearce-gpg-pub
+^fd608fbe625a2b456d9f15c2b1dc41f252057dd7
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);
+ }
+ }
+}