diff options
author | Matthias Sohn <matthias.sohn@sap.com> | 2021-06-15 00:05:14 +0200 |
---|---|---|
committer | Matthias Sohn <matthias.sohn@sap.com> | 2021-06-15 00:05:14 +0200 |
commit | 6a8afeb9f210f92e17b6c525d989c6072984289f (patch) | |
tree | 130a880a22b83ebfe8bdf3aa7db80b29c510929a /org.eclipse.jgit.test | |
parent | 1aa3cf7f416658a4fafd592732ba70f5a1aee19e (diff) | |
parent | 01b2c4fc90849f43042ffb0bb40fa3ab69541245 (diff) | |
download | jgit-6a8afeb9f210f92e17b6c525d989c6072984289f.tar.gz jgit-6a8afeb9f210f92e17b6c525d989c6072984289f.zip |
Merge branch 'master' into next
* master: (47 commits)
Fix @since from commit 64d0aaa2
Prepare 5.13.0-SNAPSHOT builds
Prepare 5.12.1-SNAPSHOT builds
Teach independent negotiation (no pack file) using an option "wait-for-done"
JGit v5.12.0.202106070339-r
[license-check] Update list of project dependencies
[errorprone] Fix warning InputStreamSlowMultibyteRead
[errorprone] Make operator precedence explicit in OpenSshConfigFile
Update jetty to 9.4.41.v20210516
Prepare 5.1.17-SNAPSHOT builds
JGit v5.1.16.202106041830-r
Update Orbit to R20210602031627
Prepare 5.12.0-SNAPSHOT builds
Fixing visibility for HostEntry constructors.
JGit v5.12.0.202106021050-rc1
Prepare 5.12.0-SNAPSHOT builds
JGit v5.12.0.202106011439-rc1
Clarify operator precedence to fix errorprone error
Prepare 5.12.0-SNAPSHOT builds
Update Orbit to S20210518003616 and ant to 1.10.10.v20210426-1926
...
Change-Id: I76a1f155201648a62df11a41a9e02d97f522d00f
Diffstat (limited to 'org.eclipse.jgit.test')
43 files changed, 1396 insertions, 48 deletions
diff --git a/org.eclipse.jgit.test/.settings/org.eclipse.core.resources.prefs b/org.eclipse.jgit.test/.settings/org.eclipse.core.resources.prefs index 6a9621db1d..cddb99d1d5 100644 --- a/org.eclipse.jgit.test/.settings/org.eclipse.core.resources.prefs +++ b/org.eclipse.jgit.test/.settings/org.eclipse.core.resources.prefs @@ -1,5 +1,6 @@ -#Sat Dec 20 21:21:24 CET 2008 eclipse.preferences.version=1 +encoding//tst-rsrc/org/eclipse/jgit/diff/umlaut.patch=ISO-8859-1 +encoding//tst-rsrc/org/eclipse/jgit/diff/umlaut_PostImage=ISO-8859-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 diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/.gitattributes b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/.gitattributes index c5831d9a8b..28caa2f82a 100644 --- a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/.gitattributes +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/.gitattributes @@ -1,3 +1,5 @@ *.patch -crlf *Image -crlf *.out -crlf +delta* -text +literal* -text diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf.patch new file mode 100644 index 0000000000..01eb0b9510 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf.patch @@ -0,0 +1,9 @@ +diff --git a/crlf b/crlf +index 9206ee6..95dd193 100644 +--- a/crlf ++++ b/crlf +@@ -1,3 +1,3 @@ + foo +-fie ++bar + fum diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf2.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf2.patch new file mode 100644 index 0000000000..5a6210489c --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf2.patch @@ -0,0 +1,9 @@ +diff --git a/crlf2 b/crlf2 +index 05c1c78..91e246d 100644 +--- a/crlf2 ++++ b/crlf2 +@@ -1,3 +1,3 @@ + foo
+-fie
++bar
+ fum
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf2_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf2_PostImage new file mode 100644 index 0000000000..91e246d064 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf2_PostImage @@ -0,0 +1,3 @@ +foo
+bar
+fum
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf2_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf2_PreImage new file mode 100644 index 0000000000..05c1c782e5 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf2_PreImage @@ -0,0 +1,3 @@ +foo
+fie
+fum
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf3.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf3.patch new file mode 100644 index 0000000000..b155148b3e --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf3.patch @@ -0,0 +1,8 @@ +diff --git a/crlf3 b/crlf3 +index e69de29..9206ee6 100644 +--- a/crlf3 ++++ b/crlf3 +@@ -0,0 +1,3 @@ ++foo ++fie ++fum diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf3_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf3_PostImage new file mode 100644 index 0000000000..05c1c782e5 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf3_PostImage @@ -0,0 +1,3 @@ +foo
+fie
+fum
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf3_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf3_PreImage new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf3_PreImage diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf4.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf4.patch new file mode 100644 index 0000000000..0cf606390a --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf4.patch @@ -0,0 +1,9 @@ +diff --git a/crlf4 b/crlf4 +new file mode 100644 +index 0000000..9206ee6 +--- /dev/null ++++ b/crlf4 +@@ -0,0 +1,3 @@ ++foo ++fie ++fum diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf4_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf4_PostImage new file mode 100644 index 0000000000..05c1c782e5 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf4_PostImage @@ -0,0 +1,3 @@ +foo
+fie
+fum
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf_PostImage new file mode 100644 index 0000000000..91e246d064 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf_PostImage @@ -0,0 +1,3 @@ +foo
+bar
+fum
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf_PreImage new file mode 100644 index 0000000000..05c1c782e5 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/crlf_PreImage @@ -0,0 +1,3 @@ +foo
+fie
+fum
diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/delta.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/delta.patch new file mode 100644 index 0000000000..84855308a5 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/delta.patch @@ -0,0 +1,8 @@ +diff --git a/delta b/delta +index b4527005bf9e4da2dd1d7185b51bdac623a4218f..8b370bb5f2bc3261b6b62e80d6edd784a61ec225 100644 +GIT binary patch +delta 14 +ScmZp0Xmwa1z*+$U3j_csN(Dmz + +delta 12 +TcmZp5XmD5{u!xa=5hEi28?FP4 diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/delta_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/delta_PostImage Binary files differnew file mode 100644 index 0000000000..8b370bb5f2 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/delta_PostImage diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/delta_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/delta_PreImage Binary files differnew file mode 100644 index 0000000000..b4527005bf --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/delta_PreImage diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/emptyLine.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/emptyLine.patch new file mode 100644 index 0000000000..18c80c4feb --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/emptyLine.patch @@ -0,0 +1,10 @@ +diff --git a/emptyLine b/emptyLine +index 1fd3fa2..45c2c9b 100644 +--- a/emptyLine ++++ b/emptyLine +@@ -1,4 +1,4 @@ + foo + +-fie ++bar + fum diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/emptyLine_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/emptyLine_PostImage new file mode 100644 index 0000000000..45c2c9ba5b --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/emptyLine_PostImage @@ -0,0 +1,4 @@ +foo + +bar +fum diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/emptyLine_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/emptyLine_PreImage new file mode 100644 index 0000000000..1fd3fa23b0 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/emptyLine_PreImage @@ -0,0 +1,4 @@ +foo + +fie +fum diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/hello.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/hello.patch new file mode 100644 index 0000000000..f015a38062 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/hello.patch @@ -0,0 +1,16 @@ +diff --git a/hello b/hello +index b6fc4c6..0abaeaa 100644 +--- a/hello ++++ b/hello +@@ -1 +1 @@ +-hello +\ No newline at end of file ++bye +\ No newline at end of file +diff --git a/yello b/yello +index 391a8cb..d1ed081 100644 +--- a/yello ++++ b/yello +@@ -1 +1 @@ +-yello ++yellow diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/hello_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/hello_PostImage new file mode 100644 index 0000000000..0abaeaa993 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/hello_PostImage @@ -0,0 +1 @@ +bye
\ No newline at end of file diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/hello_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/hello_PreImage new file mode 100644 index 0000000000..b6fc4c620b --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/hello_PreImage @@ -0,0 +1 @@ +hello
\ No newline at end of file diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal.patch new file mode 100644 index 0000000000..c8811d5bb0 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal.patch @@ -0,0 +1,126 @@ +diff --git a/literal b/literal +index 799df8578e3cae8a5e979182391b8e9a6a3deded..74e4201af6378ac87bf9e118fbab6553c7fd355c 100644 +GIT binary patch +literal 5389 +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 + +literal 1629 +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 +bU%LDkMDBWX&Ru`<00000NkvXXu0mjfJA@b~ + diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_PostImage Binary files differnew file mode 100644 index 0000000000..74e4201af6 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_PostImage diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_PreImage Binary files differnew file mode 100644 index 0000000000..799df8578e --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_PreImage diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_add.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_add.patch new file mode 100644 index 0000000000..bb6a9e42a3 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_add.patch @@ -0,0 +1,40 @@ +diff --git a/literal_add b/literal_add +new file mode 100644 +index 0000000000000000000000000000000000000000..799df8578e3cae8a5e979182391b8e9a6a3deded +GIT binary patch +literal 1629 +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 +bU%LDkMDBWX&Ru`<00000NkvXXu0mjfJA@b~ + +literal 0 +HcmV?d00001 diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_add_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_add_PostImage Binary files differnew file mode 100644 index 0000000000..799df8578e --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/literal_add_PostImage diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/smudgetest.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/smudgetest.patch new file mode 100644 index 0000000000..ab4d4265a0 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/smudgetest.patch @@ -0,0 +1,9 @@ +diff --git a/smudgetest b/smudgetest +index a24d41e..762c4d0 100644 +--- a/smudgetest ++++ b/smudgetest +@@ -1,3 +1,3 @@ + PERLE +-HEBLE ++sprich + speak diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/smudgetest_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/smudgetest_PostImage new file mode 100644 index 0000000000..ad630893df --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/smudgetest_PostImage @@ -0,0 +1,3 @@ +PARLA +sprich +speak diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/smudgetest_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/smudgetest_PreImage new file mode 100644 index 0000000000..9bbd8c763e --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/smudgetest_PreImage @@ -0,0 +1,3 @@ +PARLA +HABLA +speak diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/umlaut.patch b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/umlaut.patch new file mode 100644 index 0000000000..7380dbed82 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/umlaut.patch @@ -0,0 +1,7 @@ +diff --git a/umlaut b/umlaut +index 003a054..557f72f 100644 +--- a/umlaut ++++ b/umlaut +@@ -1 +1 @@ +-ÄÖÜ ++ÄÖÜ diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/umlaut_PostImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/umlaut_PostImage new file mode 100644 index 0000000000..557f72f513 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/umlaut_PostImage @@ -0,0 +1 @@ +ÄÖÜ diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/umlaut_PreImage b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/umlaut_PreImage new file mode 100644 index 0000000000..003a054114 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/diff/umlaut_PreImage @@ -0,0 +1 @@ +ÄÖÜ diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/util/io/delta1.forward b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/util/io/delta1.forward new file mode 100644 index 0000000000..878b167ae9 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/util/io/delta1.forward @@ -0,0 +1 @@ +ScmZp0Xmwa1z*+$U3j_csN(Dmz diff --git a/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/util/io/delta1.reverse b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/util/io/delta1.reverse new file mode 100644 index 0000000000..7ff7a08ad0 --- /dev/null +++ b/org.eclipse.jgit.test/tst-rsrc/org/eclipse/jgit/util/io/delta1.reverse @@ -0,0 +1 @@ +TcmZp5XmD5{u!xa=5hEi28?FP4 diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java index 055eba7184..867310b60c 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ApplyCommandTest.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011, 2020 IBM Corporation and others + * Copyright (C) 2011, 2021 IBM Corporation and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at @@ -9,6 +9,7 @@ */ package org.eclipse.jgit.api; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -18,11 +19,20 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; import org.eclipse.jgit.api.errors.PatchApplyException; import org.eclipse.jgit.api.errors.PatchFormatException; +import org.eclipse.jgit.attributes.FilterCommand; +import org.eclipse.jgit.attributes.FilterCommandFactory; +import org.eclipse.jgit.attributes.FilterCommandRegistry; import org.eclipse.jgit.diff.RawText; import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.lib.Config; +import org.eclipse.jgit.lib.ConfigConstants; +import org.eclipse.jgit.util.IO; import org.junit.Test; public class ApplyCommandTest extends RepositoryTestCase { @@ -58,6 +68,260 @@ public class ApplyCommandTest extends RepositoryTestCase { } @Test + public void testCrLf() throws Exception { + try { + db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_AUTOCRLF, true); + ApplyResult result = init("crlf", true, true); + assertEquals(1, result.getUpdatedFiles().size()); + assertEquals(new File(db.getWorkTree(), "crlf"), + result.getUpdatedFiles().get(0)); + checkFile(new File(db.getWorkTree(), "crlf"), + b.getString(0, b.size(), false)); + } finally { + db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_AUTOCRLF); + } + } + + @Test + public void testCrLfOff() throws Exception { + try { + db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_AUTOCRLF, false); + ApplyResult result = init("crlf", true, true); + assertEquals(1, result.getUpdatedFiles().size()); + assertEquals(new File(db.getWorkTree(), "crlf"), + result.getUpdatedFiles().get(0)); + checkFile(new File(db.getWorkTree(), "crlf"), + b.getString(0, b.size(), false)); + } finally { + db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_AUTOCRLF); + } + } + + @Test + public void testCrLfEmptyCommitted() throws Exception { + try { + db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_AUTOCRLF, true); + ApplyResult result = init("crlf3", true, true); + assertEquals(1, result.getUpdatedFiles().size()); + assertEquals(new File(db.getWorkTree(), "crlf3"), + result.getUpdatedFiles().get(0)); + checkFile(new File(db.getWorkTree(), "crlf3"), + b.getString(0, b.size(), false)); + } finally { + db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_AUTOCRLF); + } + } + + @Test + public void testCrLfNewFile() throws Exception { + try { + db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_AUTOCRLF, true); + ApplyResult result = init("crlf4", false, true); + assertEquals(1, result.getUpdatedFiles().size()); + assertEquals(new File(db.getWorkTree(), "crlf4"), + result.getUpdatedFiles().get(0)); + checkFile(new File(db.getWorkTree(), "crlf4"), + b.getString(0, b.size(), false)); + } finally { + db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_AUTOCRLF); + } + } + + @Test + public void testPatchWithCrLf() throws Exception { + try { + db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_AUTOCRLF, false); + ApplyResult result = init("crlf2", true, true); + assertEquals(1, result.getUpdatedFiles().size()); + assertEquals(new File(db.getWorkTree(), "crlf2"), + result.getUpdatedFiles().get(0)); + checkFile(new File(db.getWorkTree(), "crlf2"), + b.getString(0, b.size(), false)); + } finally { + db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_AUTOCRLF); + } + } + + @Test + public void testPatchWithCrLf2() throws Exception { + String name = "crlf2"; + try (Git git = new Git(db)) { + db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_AUTOCRLF, false); + a = new RawText(readFile(name + "_PreImage")); + write(new File(db.getWorkTree(), name), + a.getString(0, a.size(), false)); + + git.add().addFilepattern(name).call(); + git.commit().setMessage("PreImage").call(); + + b = new RawText(readFile(name + "_PostImage")); + + db.getConfig().setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_AUTOCRLF, true); + ApplyResult result = git.apply() + .setPatch(getTestResource(name + ".patch")).call(); + assertEquals(1, result.getUpdatedFiles().size()); + assertEquals(new File(db.getWorkTree(), name), + result.getUpdatedFiles().get(0)); + checkFile(new File(db.getWorkTree(), name), + b.getString(0, b.size(), false)); + } finally { + db.getConfig().unset(ConfigConstants.CONFIG_CORE_SECTION, null, + ConfigConstants.CONFIG_KEY_AUTOCRLF); + } + } + + // Clean/smudge filter for testFiltering. The smudgetest test resources were + // created with C git using a clean filter sed -e "s/A/E/g" and the smudge + // filter sed -e "s/E/A/g". To keep the test independent of the presence of + // sed, implement this with a built-in filter. + private static class ReplaceFilter extends FilterCommand { + + private final char toReplace; + + private final char replacement; + + ReplaceFilter(InputStream in, OutputStream out, char toReplace, + char replacement) { + super(in, out); + this.toReplace = toReplace; + this.replacement = replacement; + } + + @Override + public int run() throws IOException { + int b = in.read(); + if (b < 0) { + in.close(); + out.close(); + return -1; + } + if ((b & 0xFF) == toReplace) { + b = replacement; + } + out.write(b); + return 1; + } + } + + @Test + public void testFiltering() throws Exception { + // Set up filter + FilterCommandFactory clean = (repo, in, out) -> { + return new ReplaceFilter(in, out, 'A', 'E'); + }; + FilterCommandFactory smudge = (repo, in, out) -> { + return new ReplaceFilter(in, out, 'E', 'A'); + }; + FilterCommandRegistry.register("jgit://builtin/a2e/clean", clean); + FilterCommandRegistry.register("jgit://builtin/a2e/smudge", smudge); + try (Git git = new Git(db)) { + Config config = db.getConfig(); + config.setString(ConfigConstants.CONFIG_FILTER_SECTION, "a2e", + "clean", "jgit://builtin/a2e/clean"); + config.setString(ConfigConstants.CONFIG_FILTER_SECTION, "a2e", + "smudge", "jgit://builtin/a2e/smudge"); + write(new File(db.getWorkTree(), ".gitattributes"), + "smudgetest filter=a2e"); + git.add().addFilepattern(".gitattributes").call(); + git.commit().setMessage("Attributes").call(); + ApplyResult result = init("smudgetest", true, true); + assertEquals(1, result.getUpdatedFiles().size()); + assertEquals(new File(db.getWorkTree(), "smudgetest"), + result.getUpdatedFiles().get(0)); + checkFile(new File(db.getWorkTree(), "smudgetest"), + b.getString(0, b.size(), false)); + + } finally { + // Tear down filter + FilterCommandRegistry.unregister("jgit://builtin/a2e/clean"); + FilterCommandRegistry.unregister("jgit://builtin/a2e/smudge"); + } + } + + private void checkBinary(String name, boolean hasPreImage) + throws Exception { + checkBinary(name, hasPreImage, 1); + } + + private void checkBinary(String name, boolean hasPreImage, + int numberOfFiles) throws Exception { + try (Git git = new Git(db)) { + byte[] post = IO + .readWholeStream(getTestResource(name + "_PostImage"), 0) + .array(); + File f = new File(db.getWorkTree(), name); + if (hasPreImage) { + byte[] pre = IO + .readWholeStream(getTestResource(name + "_PreImage"), 0) + .array(); + Files.write(f.toPath(), pre); + git.add().addFilepattern(name).call(); + git.commit().setMessage("PreImage").call(); + } + ApplyResult result = git.apply() + .setPatch(getTestResource(name + ".patch")).call(); + assertEquals(numberOfFiles, result.getUpdatedFiles().size()); + assertEquals(f, result.getUpdatedFiles().get(0)); + assertArrayEquals(post, Files.readAllBytes(f.toPath())); + } + } + + @Test + public void testBinaryDelta() throws Exception { + checkBinary("delta", true); + } + + @Test + public void testBinaryLiteral() throws Exception { + checkBinary("literal", true); + } + + @Test + public void testBinaryLiteralAdd() throws Exception { + checkBinary("literal_add", false); + } + + @Test + public void testEncodingChange() throws Exception { + // This is a text patch that changes a file containing ÄÖÜ in UTF-8 to + // the same characters in ISO-8859-1. The patch file itself uses mixed + // encoding. Since checkFile() works with strings use the binary check. + checkBinary("umlaut", true); + } + + @Test + public void testEmptyLine() throws Exception { + // C git accepts completely empty lines as empty context lines. + // According to comments in the C git sources (apply.c), newer GNU diff + // may produce such diffs. + checkBinary("emptyLine", true); + } + + @Test + public void testMultiFileNoNewline() throws Exception { + // This test needs two files. One is in the test resources. + try (Git git = new Git(db)) { + Files.write(db.getWorkTree().toPath().resolve("yello"), + "yello".getBytes(StandardCharsets.US_ASCII)); + git.add().addFilepattern("yello").call(); + git.commit().setMessage("yello").call(); + } + checkBinary("hello", true, 2); + } + + @Test public void testAddA1() throws Exception { ApplyResult result = init("A1", false, true); assertEquals(1, result.getUpdatedFiles().size()); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RenameDetectorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RenameDetectorTest.java index 2ea3cd7ebe..5edb60ce37 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RenameDetectorTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/RenameDetectorTest.java @@ -580,6 +580,57 @@ public class RenameDetectorTest extends RepositoryTestCase { } @Test + public void testExactRenameForBinaryFile_isIdentified() throws Exception { + ObjectId aId = blob("a\nb\nc\n\0\0\0\0d\n"); + + DiffEntry a = DiffEntry.add(PATH_A, aId); + DiffEntry b = DiffEntry.delete(PATH_Q, aId); + + rd.add(a); + rd.add(b); + + List<DiffEntry> entries = rd.compute(); + assertEquals(1, entries.size()); + assertRename(b, a, 100, entries.get(0)); + } + + @Test + public void testInexactRenameForBinaryFile_identifiedByDefault() throws Exception { + ObjectId aId = blob("a\nb\nc\n\0\0\0\0d\n"); + ObjectId bId = blob("a\nb\nc\n\0\0\0d\n"); + + DiffEntry a = DiffEntry.add(PATH_A, aId); + DiffEntry b = DiffEntry.delete(PATH_Q, bId); + + rd.add(a); + rd.add(b); + rd.setRenameScore(40); + + List<DiffEntry> entries = rd.compute(); + assertEquals(1, entries.size()); + assertRename(b, a, 50, entries.get(0)); + } + + @Test + public void testInexactRenameForBinaryFile_notIdentifiedIfSkipParameterSet() throws Exception { + ObjectId aId = blob("a\nb\nc\n\0\0\0\0d\n"); + ObjectId bId = blob("a\nb\nc\n\0\0\0d\n"); + + DiffEntry a = DiffEntry.add(PATH_A, aId); + DiffEntry b = DiffEntry.delete(PATH_Q, bId); + + rd.add(a); + rd.add(b); + rd.setRenameScore(40); + rd.setSkipContentRenamesForBinaryFiles(true); + + List<DiffEntry> entries = rd.compute(); + assertEquals(2, entries.size()); + assertAdd(PATH_A, aId, FileMode.REGULAR_FILE, entries.get(0)); + assertDelete(PATH_Q, bId, FileMode.REGULAR_FILE, entries.get(1)); + } + + @Test public void testSetRenameScore_IllegalArgs() throws Exception { try { rd.setRenameScore(-1); diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java index ae4db0b7d8..509adc2cb2 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java @@ -46,6 +46,8 @@ import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.storage.file.FileBasedConfig; import org.eclipse.jgit.treewalk.TreeWalk; import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.IO; +import org.eclipse.jgit.util.RawParseUtils; import org.junit.Test; public class RepoCommandTest extends RepositoryTestCase { @@ -749,7 +751,53 @@ public class RepoCommandTest extends RepositoryTestCase { String gitlink = localDb.resolve(Constants.HEAD + ":foo").name(); assertEquals("The gitlink is same as remote head", oldCommitId.name(), gitlink); + + File dotmodules = new File(localDb.getWorkTree(), + Constants.DOT_GIT_MODULES); + assertTrue(dotmodules.exists()); + // The .gitmodules file should have "branch" lines + String gitModulesContents = RawParseUtils + .decode(IO.readFully(dotmodules)); + assertTrue(gitModulesContents.contains("branch = branch")); + } + } + + @Test + public void testRevisionBare_ignoreTags() throws Exception { + Repository remoteDb = createBareRepository(); + Repository tempDb = createWorkRepository(); + + StringBuilder xmlContent = new StringBuilder(); + xmlContent.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") + .append("<manifest>") + .append("<remote name=\"remote1\" fetch=\".\" />") + .append("<default revision=\"").append("refs/tags/" + TAG) + .append("\" remote=\"remote1\" />") + .append("<project path=\"foo\" name=\"") + .append(defaultUri) + .append("\" />").append("</manifest>"); + JGitTestUtil.writeTrashFile(tempDb, "manifest.xml", + xmlContent.toString()); + RepoCommand command = new RepoCommand(remoteDb); + command.setPath( + tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml") + .setURI(rootUri).call(); + // Clone it + File directory = createTempDirectory("testReplaceManifestBare"); + File dotmodules; + try (Repository localDb = Git.cloneRepository().setDirectory(directory) + .setURI(remoteDb.getDirectory().toURI().toString()).call() + .getRepository()) { + dotmodules = new File(localDb.getWorkTree(), + Constants.DOT_GIT_MODULES); + assertTrue(dotmodules.exists()); } + + // The .gitmodules file should not have "branch" lines + String gitModulesContents = RawParseUtils + .decode(IO.readFully(dotmodules)); + assertFalse(gitModulesContents.contains("branch")); + assertTrue(gitModulesContents.contains("ref = refs/tags/" + TAG)); } @Test diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BatchRefUpdateTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BatchRefUpdateTest.java index 25cd227f02..6357a0b9a8 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BatchRefUpdateTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/BatchRefUpdateTest.java @@ -190,15 +190,28 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { if (atomic) { assertResults(cmds, TRANSACTION_ABORTED, REJECTED_NONFASTFORWARD); assertRefs("refs/heads/master", A, "refs/heads/masters", B); - assertEquals(1, refsChangedEvents); } else { assertResults(cmds, OK, REJECTED_NONFASTFORWARD); assertRefs("refs/heads/master", B, "refs/heads/masters", B); - assertEquals(2, refsChangedEvents); } } @Test + public void simpleNoForceRefsChangedEvents() throws IOException { + writeLooseRefs("refs/heads/master", A, "refs/heads/masters", B); + int initialRefsChangedEvents = refsChangedEvents; + + List<ReceiveCommand> cmds = Arrays.asList( + new ReceiveCommand(A, B, "refs/heads/master", UPDATE), + new ReceiveCommand(B, A, "refs/heads/masters", + UPDATE_NONFASTFORWARD)); + execute(newBatchUpdate(cmds)); + + assertEquals(atomic ? initialRefsChangedEvents + : initialRefsChangedEvents + 1, refsChangedEvents); + } + + @Test public void simpleForce() throws IOException { writeLooseRefs("refs/heads/master", A, "refs/heads/masters", B); @@ -210,7 +223,21 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { assertResults(cmds, OK, OK); assertRefs("refs/heads/master", B, "refs/heads/masters", A); - assertEquals(batchesRefUpdates() ? 2 : 3, refsChangedEvents); + } + + @Test + public void simpleForceRefsChangedEvents() throws IOException { + writeLooseRefs("refs/heads/master", A, "refs/heads/masters", B); + int initialRefsChangedEvents = refsChangedEvents; + + List<ReceiveCommand> cmds = Arrays.asList( + new ReceiveCommand(A, B, "refs/heads/master", UPDATE), + new ReceiveCommand(B, A, "refs/heads/masters", + UPDATE_NONFASTFORWARD)); + execute(newBatchUpdate(cmds).setAllowNonFastForwards(true)); + + assertEquals(batchesRefUpdates() ? initialRefsChangedEvents + 1 + : initialRefsChangedEvents + 2, refsChangedEvents); } @Test @@ -232,7 +259,27 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { assertResults(cmds, OK); assertRefs("refs/heads/master", A); - assertEquals(2, refsChangedEvents); + } + + @Test + public void nonFastForwardDoesNotDoExpensiveMergeCheckRefsChangedEvents() + throws IOException { + writeLooseRef("refs/heads/master", B); + int initialRefsChangedEvents = refsChangedEvents; + + List<ReceiveCommand> cmds = Arrays.asList(new ReceiveCommand(B, A, + "refs/heads/master", UPDATE_NONFASTFORWARD)); + try (RevWalk rw = new RevWalk(diskRepo) { + @Override + public boolean isMergedInto(RevCommit base, RevCommit tip) { + throw new AssertionError("isMergedInto() should not be called"); + } + }) { + newBatchUpdate(cmds).setAllowNonFastForwards(true).execute(rw, + new StrictWorkMonitor()); + } + + assertEquals(initialRefsChangedEvents + 1, refsChangedEvents); } @Test @@ -251,17 +298,30 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { assertResults(cmds, LOCK_FAILURE, TRANSACTION_ABORTED, TRANSACTION_ABORTED); assertRefs("refs/heads/master", A, "refs/heads/masters", B); - assertEquals(1, refsChangedEvents); } else { // Non-atomic updates are applied in order: master succeeds, then // master/x fails due to conflict. assertResults(cmds, OK, LOCK_FAILURE, LOCK_FAILURE); assertRefs("refs/heads/master", B, "refs/heads/masters", B); - assertEquals(2, refsChangedEvents); } } @Test + public void fileDirectoryConflictRefsChangedEvents() throws IOException { + writeLooseRefs("refs/heads/master", A, "refs/heads/masters", B); + int initialRefsChangedEvents = refsChangedEvents; + + List<ReceiveCommand> cmds = Arrays.asList( + new ReceiveCommand(A, B, "refs/heads/master", UPDATE), + new ReceiveCommand(zeroId(), A, "refs/heads/master/x", CREATE), + new ReceiveCommand(zeroId(), A, "refs/heads", CREATE)); + execute(newBatchUpdate(cmds).setAllowNonFastForwards(true), false); + + assertEquals(atomic ? initialRefsChangedEvents + : initialRefsChangedEvents + 1, refsChangedEvents); + } + + @Test public void conflictThanksToDelete() throws IOException { writeLooseRefs("refs/heads/master", A, "refs/heads/masters", B); @@ -273,15 +333,21 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { assertResults(cmds, OK, OK, OK); assertRefs("refs/heads/master", B, "refs/heads/masters/x", A); - if (atomic) { - assertEquals(2, refsChangedEvents); - } else if (!useReftable) { - // The non-atomic case actually produces 5 events, but that's an - // implementation detail. We expect at least 4 events, one for the - // initial read due to writeLooseRef(), and then one for each - // successful ref update. - assertTrue(refsChangedEvents >= 4); - } + } + + @Test + public void conflictThanksToDeleteRefsChangedEvents() throws IOException { + writeLooseRefs("refs/heads/master", A, "refs/heads/masters", B); + int initialRefsChangedEvents = refsChangedEvents; + + List<ReceiveCommand> cmds = Arrays.asList( + new ReceiveCommand(A, B, "refs/heads/master", UPDATE), + new ReceiveCommand(zeroId(), A, "refs/heads/masters/x", CREATE), + new ReceiveCommand(B, zeroId(), "refs/heads/masters", DELETE)); + execute(newBatchUpdate(cmds).setAllowNonFastForwards(true)); + + assertEquals(batchesRefUpdates() ? initialRefsChangedEvents + 1 + : initialRefsChangedEvents + 3, refsChangedEvents); } @Test @@ -298,15 +364,29 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { if (atomic) { assertResults(cmds, REJECTED_MISSING_OBJECT, TRANSACTION_ABORTED); assertRefs("refs/heads/master", A); - assertEquals(1, refsChangedEvents); } else { assertResults(cmds, REJECTED_MISSING_OBJECT, OK); assertRefs("refs/heads/master", A, "refs/heads/foo2", B); - assertEquals(2, refsChangedEvents); } } @Test + public void updateToMissingObjectRefsChangedEvents() throws IOException { + writeLooseRef("refs/heads/master", A); + int initialRefsChangedEvents = refsChangedEvents; + + ObjectId bad = ObjectId + .fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); + List<ReceiveCommand> cmds = Arrays.asList( + new ReceiveCommand(A, bad, "refs/heads/master", UPDATE), + new ReceiveCommand(zeroId(), B, "refs/heads/foo2", CREATE)); + execute(newBatchUpdate(cmds).setAllowNonFastForwards(true), false); + + assertEquals(atomic ? initialRefsChangedEvents + : initialRefsChangedEvents + 1, refsChangedEvents); + } + + @Test public void addMissingObject() throws IOException { writeLooseRef("refs/heads/master", A); @@ -320,15 +400,29 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { if (atomic) { assertResults(cmds, TRANSACTION_ABORTED, REJECTED_MISSING_OBJECT); assertRefs("refs/heads/master", A); - assertEquals(1, refsChangedEvents); } else { assertResults(cmds, OK, REJECTED_MISSING_OBJECT); assertRefs("refs/heads/master", B); - assertEquals(2, refsChangedEvents); } } @Test + public void addMissingObjectRefsChangedEvents() throws IOException { + writeLooseRef("refs/heads/master", A); + int initialRefsChangedEvents = refsChangedEvents; + + ObjectId bad = ObjectId + .fromString("deadbeefdeadbeefdeadbeefdeadbeefdeadbeef"); + List<ReceiveCommand> cmds = Arrays.asList( + new ReceiveCommand(A, B, "refs/heads/master", UPDATE), + new ReceiveCommand(zeroId(), bad, "refs/heads/foo2", CREATE)); + execute(newBatchUpdate(cmds).setAllowNonFastForwards(true), false); + + assertEquals(atomic ? initialRefsChangedEvents + : initialRefsChangedEvents + 1, refsChangedEvents); + } + + @Test public void oneNonExistentRef() throws IOException { List<ReceiveCommand> cmds = Arrays.asList( new ReceiveCommand(A, B, "refs/heads/foo1", UPDATE), @@ -358,15 +452,27 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { if (atomic) { assertResults(cmds, LOCK_FAILURE, TRANSACTION_ABORTED); assertRefs("refs/heads/master", A); - assertEquals(1, refsChangedEvents); } else { assertResults(cmds, LOCK_FAILURE, OK); assertRefs("refs/heads/master", A, "refs/heads/foo2", B); - assertEquals(2, refsChangedEvents); } } @Test + public void oneRefWrongOldValueRefsChangedEvents() throws IOException { + writeLooseRef("refs/heads/master", A); + int initialRefsChangedEvents = refsChangedEvents; + + List<ReceiveCommand> cmds = Arrays.asList( + new ReceiveCommand(B, B, "refs/heads/master", UPDATE), + new ReceiveCommand(zeroId(), B, "refs/heads/foo2", CREATE)); + execute(newBatchUpdate(cmds).setAllowNonFastForwards(true)); + + assertEquals(atomic ? initialRefsChangedEvents + : initialRefsChangedEvents + 1, refsChangedEvents); + } + + @Test public void nonExistentRef() throws IOException { writeLooseRef("refs/heads/master", A); @@ -378,17 +484,31 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { if (atomic) { assertResults(cmds, TRANSACTION_ABORTED, LOCK_FAILURE); assertRefs("refs/heads/master", A); - assertEquals(1, refsChangedEvents); } else { assertResults(cmds, OK, LOCK_FAILURE); assertRefs("refs/heads/master", B); - assertEquals(2, refsChangedEvents); } } @Test + public void nonExistentRefRefsChangedEvents() throws IOException { + writeLooseRef("refs/heads/master", A); + + int initialRefsChangedEvents = refsChangedEvents; + + List<ReceiveCommand> cmds = Arrays.asList( + new ReceiveCommand(A, B, "refs/heads/master", UPDATE), + new ReceiveCommand(A, zeroId(), "refs/heads/foo2", DELETE)); + execute(newBatchUpdate(cmds).setAllowNonFastForwards(true)); + + assertEquals(atomic ? initialRefsChangedEvents + : initialRefsChangedEvents + 1, refsChangedEvents); + } + + @Test public void noRefLog() throws IOException { writeRef("refs/heads/master", A); + int initialRefsChangedEvents = refsChangedEvents; Map<String, ReflogEntry> oldLogs = getLastReflogs("refs/heads/master", "refs/heads/branch"); @@ -402,7 +522,8 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { assertResults(cmds, OK, OK); assertRefs("refs/heads/master", B, "refs/heads/branch", B); - assertEquals(batchesRefUpdates() ? 2 : 3, refsChangedEvents); + assertEquals(batchesRefUpdates() ? initialRefsChangedEvents + 1 + : initialRefsChangedEvents + 2, refsChangedEvents); assertReflogUnchanged(oldLogs, "refs/heads/master"); assertReflogUnchanged(oldLogs, "refs/heads/branch"); } @@ -411,6 +532,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { public void reflogDefaultIdent() throws IOException { writeRef("refs/heads/master", A); writeRef("refs/heads/branch2", A); + int initialRefsChangedEvents = refsChangedEvents; Map<String, ReflogEntry> oldLogs = getLastReflogs("refs/heads/master", "refs/heads/branch1", "refs/heads/branch2"); @@ -423,7 +545,8 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { assertResults(cmds, OK, OK); assertRefs("refs/heads/master", B, "refs/heads/branch1", B, "refs/heads/branch2", A); - assertEquals(batchesRefUpdates() ? 3 : 4, refsChangedEvents); + assertEquals(batchesRefUpdates() ? initialRefsChangedEvents + 1 + : initialRefsChangedEvents + 2, refsChangedEvents); assertReflogEquals(reflog(A, B, new PersonIdent(diskRepo), "a reflog"), getLastReflog("refs/heads/master")); assertReflogEquals( @@ -436,6 +559,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { public void reflogAppendStatusNoMessage() throws IOException { writeRef("refs/heads/master", A); writeRef("refs/heads/branch1", B); + int initialRefsChangedEvents = refsChangedEvents; List<ReceiveCommand> cmds = Arrays.asList( new ReceiveCommand(A, B, "refs/heads/master", UPDATE), @@ -448,7 +572,8 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { assertResults(cmds, OK, OK, OK); assertRefs("refs/heads/master", B, "refs/heads/branch1", A, "refs/heads/branch2", A); - assertEquals(batchesRefUpdates() ? 3 : 5, refsChangedEvents); + assertEquals(batchesRefUpdates() ? initialRefsChangedEvents + 1 + : initialRefsChangedEvents + 3, refsChangedEvents); assertReflogEquals( // Always forced; setAllowNonFastForwards(true) bypasses the // check. @@ -465,6 +590,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { @Test public void reflogAppendStatusFastForward() throws IOException { writeRef("refs/heads/master", A); + int initialRefsChangedEvents = refsChangedEvents; List<ReceiveCommand> cmds = Arrays .asList(new ReceiveCommand(A, B, "refs/heads/master", UPDATE)); @@ -472,7 +598,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { assertResults(cmds, OK); assertRefs("refs/heads/master", B); - assertEquals(2, refsChangedEvents); + assertEquals(initialRefsChangedEvents + 1, refsChangedEvents); assertReflogEquals( reflog(A, B, new PersonIdent(diskRepo), "fast-forward"), getLastReflog("refs/heads/master")); @@ -481,6 +607,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { @Test public void reflogAppendStatusWithMessage() throws IOException { writeRef("refs/heads/master", A); + int initialRefsChangedEvents = refsChangedEvents; List<ReceiveCommand> cmds = Arrays.asList( new ReceiveCommand(A, B, "refs/heads/master", UPDATE), @@ -489,7 +616,8 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { assertResults(cmds, OK, OK); assertRefs("refs/heads/master", B, "refs/heads/branch", A); - assertEquals(batchesRefUpdates() ? 2 : 3, refsChangedEvents); + assertEquals(batchesRefUpdates() ? initialRefsChangedEvents + 1 + : initialRefsChangedEvents + 2, refsChangedEvents); assertReflogEquals( reflog(A, B, new PersonIdent(diskRepo), "a reflog: fast-forward"), @@ -503,6 +631,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { @Test public void reflogCustomIdent() throws IOException { writeRef("refs/heads/master", A); + int initialRefsChangedEvents = refsChangedEvents; List<ReceiveCommand> cmds = Arrays.asList( new ReceiveCommand(A, B, "refs/heads/master", UPDATE), @@ -513,7 +642,8 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { .setRefLogIdent(ident)); assertResults(cmds, OK, OK); - assertEquals(batchesRefUpdates() ? 2 : 3, refsChangedEvents); + assertEquals(batchesRefUpdates() ? initialRefsChangedEvents + 1 + : initialRefsChangedEvents + 2, refsChangedEvents); assertRefs("refs/heads/master", B, "refs/heads/branch", B); assertReflogEquals(reflog(A, B, ident, "a reflog"), getLastReflog("refs/heads/master"), true); @@ -525,6 +655,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { public void reflogDelete() throws IOException { writeRef("refs/heads/master", A); writeRef("refs/heads/branch", A); + int initialRefsChangedEvents = refsChangedEvents; assertEquals(2, getLastReflogs("refs/heads/master", "refs/heads/branch") .size()); @@ -535,7 +666,8 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { assertResults(cmds, OK, OK); assertRefs("refs/heads/branch", B); - assertEquals(batchesRefUpdates() ? 3 : 4, refsChangedEvents); + assertEquals(batchesRefUpdates() ? initialRefsChangedEvents + 1 + : initialRefsChangedEvents + 2, refsChangedEvents); if (useReftable) { // reftable retains reflog entries for deleted branches. assertReflogEquals( @@ -551,6 +683,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { @Test public void reflogFileDirectoryConflict() throws IOException { writeRef("refs/heads/master", A); + int initialRefsChangedEvents = refsChangedEvents; List<ReceiveCommand> cmds = Arrays.asList( new ReceiveCommand(A, zeroId(), "refs/heads/master", DELETE), @@ -559,7 +692,8 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { assertResults(cmds, OK, OK); assertRefs("refs/heads/master/x", A); - assertEquals(batchesRefUpdates() ? 2 : 3, refsChangedEvents); + assertEquals(batchesRefUpdates() ? initialRefsChangedEvents + 1 + : initialRefsChangedEvents + 2, refsChangedEvents); if (!useReftable) { // reftable retains reflog entries for deleted branches. assertNull(getLastReflog("refs/heads/master")); @@ -572,6 +706,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { @Test public void reflogOnLockFailure() throws IOException { writeRef("refs/heads/master", A); + int initialRefsChangedEvents = refsChangedEvents; Map<String, ReflogEntry> oldLogs = getLastReflogs("refs/heads/master", "refs/heads/branch"); @@ -583,12 +718,12 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { if (atomic) { assertResults(cmds, TRANSACTION_ABORTED, LOCK_FAILURE); - assertEquals(1, refsChangedEvents); + assertEquals(initialRefsChangedEvents, refsChangedEvents); assertReflogUnchanged(oldLogs, "refs/heads/master"); assertReflogUnchanged(oldLogs, "refs/heads/branch"); } else { assertResults(cmds, OK, LOCK_FAILURE); - assertEquals(2, refsChangedEvents); + assertEquals(initialRefsChangedEvents + 1, refsChangedEvents); assertReflogEquals( reflog(A, B, new PersonIdent(diskRepo), "a reflog"), getLastReflog("refs/heads/master")); @@ -599,6 +734,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { @Test public void overrideRefLogMessage() throws Exception { writeRef("refs/heads/master", A); + int initialRefsChangedEvents = refsChangedEvents; List<ReceiveCommand> cmds = Arrays.asList( new ReceiveCommand(A, B, "refs/heads/master", UPDATE), @@ -609,7 +745,8 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { .setRefLogMessage("a reflog", true)); assertResults(cmds, OK, OK); - assertEquals(batchesRefUpdates() ? 2 : 3, refsChangedEvents); + assertEquals(batchesRefUpdates() ? initialRefsChangedEvents + 1 + : initialRefsChangedEvents + 2, refsChangedEvents); assertReflogEquals(reflog(A, B, ident, "custom log"), getLastReflog("refs/heads/master"), true); assertReflogEquals(reflog(zeroId(), B, ident, "a reflog: created"), @@ -619,6 +756,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { @Test public void overrideDisableRefLog() throws Exception { writeRef("refs/heads/master", A); + int initialRefsChangedEvents = refsChangedEvents; Map<String, ReflogEntry> oldLogs = getLastReflogs("refs/heads/master", "refs/heads/branch"); @@ -630,7 +768,8 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { execute(newBatchUpdate(cmds).setRefLogMessage("a reflog", true)); assertResults(cmds, OK, OK); - assertEquals(batchesRefUpdates() ? 2 : 3, refsChangedEvents); + assertEquals(batchesRefUpdates() ? initialRefsChangedEvents + 1 + : initialRefsChangedEvents + 2, refsChangedEvents); assertReflogUnchanged(oldLogs, "refs/heads/master"); assertReflogEquals( reflog(zeroId(), B, new PersonIdent(diskRepo), @@ -641,6 +780,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { @Test public void refLogNotWrittenWithoutConfigOption() throws Exception { assumeFalse(useReftable); + setLogAllRefUpdates(false); writeRef("refs/heads/master", A); @@ -661,6 +801,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { @Test public void forceRefLogInUpdate() throws Exception { assumeFalse(useReftable); + setLogAllRefUpdates(false); writeRef("refs/heads/master", A); assertTrue(getLastReflogs("refs/heads/master", "refs/heads/branch") @@ -683,6 +824,7 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { @Test public void forceRefLogInCommand() throws Exception { assumeFalse(useReftable); + setLogAllRefUpdates(false); writeRef("refs/heads/master", A); @@ -723,13 +865,11 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { if (atomic) { assertResults(cmds, LOCK_FAILURE, TRANSACTION_ABORTED); assertRefs("refs/heads/master", A); - assertEquals(1, refsChangedEvents); } else { // Only operates on loose refs, doesn't care that packed-refs is // locked. assertResults(cmds, OK, OK); assertRefs("refs/heads/master", B, "refs/heads/branch", B); - assertEquals(3, refsChangedEvents); } } finally { myLock.unlock(); @@ -737,6 +877,28 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { } @Test + public void packedRefsLockFailureRefsChangedEvents() throws Exception { + assumeFalse(useReftable); + + writeLooseRef("refs/heads/master", A); + int initialRefsChangedEvents = refsChangedEvents; + + List<ReceiveCommand> cmds = Arrays.asList( + new ReceiveCommand(A, B, "refs/heads/master", UPDATE), + new ReceiveCommand(zeroId(), B, "refs/heads/branch", CREATE)); + + LockFile myLock = refdir.lockPackedRefs(); + try { + execute(newBatchUpdate(cmds).setAllowNonFastForwards(true)); + + assertEquals(atomic ? initialRefsChangedEvents + : initialRefsChangedEvents + 2, refsChangedEvents); + } finally { + myLock.unlock(); + } + } + + @Test public void oneRefLockFailure() throws Exception { assumeFalse(useReftable); @@ -757,11 +919,9 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { if (atomic) { assertResults(cmds, TRANSACTION_ABORTED, LOCK_FAILURE); assertRefs("refs/heads/master", A); - assertEquals(1, refsChangedEvents); } else { assertResults(cmds, OK, LOCK_FAILURE); assertRefs("refs/heads/branch", B, "refs/heads/master", A); - assertEquals(2, refsChangedEvents); } } finally { myLock.unlock(); @@ -769,8 +929,32 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { } @Test + public void oneRefLockFailureRefsChangedEvents() throws Exception { + assumeFalse(useReftable); + + writeLooseRef("refs/heads/master", A); + int initialRefsChangedEvents = refsChangedEvents; + + List<ReceiveCommand> cmds = Arrays.asList( + new ReceiveCommand(zeroId(), B, "refs/heads/branch", CREATE), + new ReceiveCommand(A, B, "refs/heads/master", UPDATE)); + + LockFile myLock = new LockFile(refdir.fileFor("refs/heads/master")); + assertTrue(myLock.lock()); + try { + execute(newBatchUpdate(cmds).setAllowNonFastForwards(true)); + + assertEquals(atomic ? initialRefsChangedEvents + : initialRefsChangedEvents + 1, refsChangedEvents); + } finally { + myLock.unlock(); + } + } + + @Test public void singleRefUpdateDoesNotRequirePackedRefsLock() throws Exception { assumeFalse(useReftable); + writeLooseRef("refs/heads/master", A); List<ReceiveCommand> cmds = Arrays @@ -782,7 +966,6 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { assertFalse(getLockFile("refs/heads/master").exists()); assertResults(cmds, OK); - assertEquals(2, refsChangedEvents); assertRefs("refs/heads/master", B); } finally { myLock.unlock(); @@ -790,6 +973,27 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { } @Test + public void singleRefUpdateDoesNotRequirePackedRefsLockRefsChangedEvents() + throws Exception { + assumeFalse(useReftable); + + writeLooseRef("refs/heads/master", A); + int initialRefsChangedEvents = refsChangedEvents; + + List<ReceiveCommand> cmds = Arrays + .asList(new ReceiveCommand(A, B, "refs/heads/master", UPDATE)); + + LockFile myLock = refdir.lockPackedRefs(); + try { + execute(newBatchUpdate(cmds).setAllowNonFastForwards(true)); + + assertEquals(initialRefsChangedEvents + 1, refsChangedEvents); + } finally { + myLock.unlock(); + } + } + + @Test public void atomicUpdateRespectsInProcessLock() throws Exception { assumeTrue(atomic); assumeFalse(useReftable); @@ -838,10 +1042,56 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { } assertResults(cmds, OK, OK); - assertEquals(2, refsChangedEvents); assertRefs("refs/heads/master", B, "refs/heads/branch", B); } + @Test + public void atomicUpdateRespectsInProcessLockRefsChangedEvents() + throws Exception { + assumeTrue(atomic); + assumeFalse(useReftable); + + writeLooseRef("refs/heads/master", A); + int initialRefsChangedEvents = refsChangedEvents; + + List<ReceiveCommand> cmds = Arrays.asList( + new ReceiveCommand(A, B, "refs/heads/master", UPDATE), + new ReceiveCommand(zeroId(), B, "refs/heads/branch", CREATE)); + + Thread t = new Thread(() -> { + try { + execute(newBatchUpdate(cmds).setAllowNonFastForwards(true)); + } catch (Exception e) { + throw new RuntimeException(e); + } + }); + + ReentrantLock l = refdir.inProcessPackedRefsLock; + l.lock(); + try { + t.start(); + long timeoutSecs = 10; + + // Hold onto the lock until we observe the worker thread has + // attempted to + // acquire it. + while (l.getQueueLength() == 0) { + Thread.sleep(3); + } + + // Once we unlock, the worker thread should finish the update + // promptly. + l.unlock(); + t.join(SECONDS.toMillis(timeoutSecs)); + } finally { + if (l.isHeldByCurrentThread()) { + l.unlock(); + } + } + + assertEquals(initialRefsChangedEvents + 1, refsChangedEvents); + } + private void setLogAllRefUpdates(boolean enable) throws Exception { StoredConfig cfg = diskRepo.getConfig(); cfg.load(); @@ -855,6 +1105,11 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { writeRef(name, id); } else { write(new File(diskRepo.getDirectory(), name), id.name() + "\n"); + // force the refs-changed event to be fired for the loose ref that + // was created. We do this to get the events fired during the test + // 'setup' out of the way and this allows us to now accurately + // assert only for the new events fired during the BatchRefUpdate. + refdir.exactRef(name); } } @@ -957,11 +1212,11 @@ public class BatchRefUpdateTest extends LocalDiskRepositoryTestCase { } enum Result { - OK(ReceiveCommand.Result.OK), LOCK_FAILURE( - ReceiveCommand.Result.LOCK_FAILURE), REJECTED_NONFASTFORWARD( - ReceiveCommand.Result.REJECTED_NONFASTFORWARD), REJECTED_MISSING_OBJECT( - ReceiveCommand.Result.REJECTED_MISSING_OBJECT), TRANSACTION_ABORTED( - ReceiveCommand::isTransactionAborted); + OK(ReceiveCommand.Result.OK), + LOCK_FAILURE(ReceiveCommand.Result.LOCK_FAILURE), + REJECTED_NONFASTFORWARD(ReceiveCommand.Result.REJECTED_NONFASTFORWARD), + REJECTED_MISSING_OBJECT(ReceiveCommand.Result.REJECTED_MISSING_OBJECT), + TRANSACTION_ABORTED(ReceiveCommand::isTransactionAborted); @SuppressWarnings("ImmutableEnumChecker") final Predicate<? super ReceiveCommand> p; diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java index 5045e9464e..b0b5f68efa 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java @@ -999,6 +999,108 @@ public class UploadPackTest { } @Test + public void testV2FetchWithoutWaitForDoneReceivesPackfile() + throws Exception { + String commonInBlob = "abcdefghijklmnopqrstuvwxyz"; + + RevBlob parentBlob = remote.blob(commonInBlob + "a"); + RevCommit parent = remote + .commit(remote.tree(remote.file("foo", parentBlob))); + remote.update("branch1", parent); + + RevCommit localParent = null; + RevCommit localChild = null; + try (TestRepository<InMemoryRepository> local = new TestRepository<>( + client)) { + RevBlob localParentBlob = local.blob(commonInBlob + "a"); + localParent = local + .commit(local.tree(local.file("foo", localParentBlob))); + RevBlob localChildBlob = local.blob(commonInBlob + "b"); + localChild = local.commit( + local.tree(local.file("foo", localChildBlob)), localParent); + local.update("branch1", localChild); + } + + ByteArrayInputStream recvStream = uploadPackV2("command=fetch\n", + PacketLineIn.delimiter(), + "have " + localParent.toObjectId().getName() + "\n", + "have " + localChild.toObjectId().getName() + "\n", + PacketLineIn.end()); + PacketLineIn pckIn = new PacketLineIn(recvStream); + assertThat(pckIn.readString(), is("acknowledgments")); + assertThat(Arrays.asList(pckIn.readString()), + hasItems("ACK " + parent.toObjectId().getName())); + assertThat(pckIn.readString(), is("ready")); + assertTrue(PacketLineIn.isDelimiter(pckIn.readString())); + assertThat(pckIn.readString(), is("packfile")); + parsePack(recvStream); + } + + @Test + public void testV2FetchWithWaitForDoneOnlyDoesNegotiation() + throws Exception { + String commonInBlob = "abcdefghijklmnopqrstuvwxyz"; + + RevBlob parentBlob = remote.blob(commonInBlob + "a"); + RevCommit parent = remote + .commit(remote.tree(remote.file("foo", parentBlob))); + remote.update("branch1", parent); + + RevCommit localParent = null; + RevCommit localChild = null; + try (TestRepository<InMemoryRepository> local = new TestRepository<>( + client)) { + RevBlob localParentBlob = local.blob(commonInBlob + "a"); + localParent = local + .commit(local.tree(local.file("foo", localParentBlob))); + RevBlob localChildBlob = local.blob(commonInBlob + "b"); + localChild = local.commit( + local.tree(local.file("foo", localChildBlob)), localParent); + local.update("branch1", localChild); + } + + ByteArrayInputStream recvStream = uploadPackV2("command=fetch\n", + PacketLineIn.delimiter(), "wait-for-done\n", + "have " + localParent.toObjectId().getName() + "\n", + "have " + localChild.toObjectId().getName() + "\n", + PacketLineIn.end()); + PacketLineIn pckIn = new PacketLineIn(recvStream); + assertThat(pckIn.readString(), is("acknowledgments")); + assertThat(Arrays.asList(pckIn.readString()), + hasItems("ACK " + parent.toObjectId().getName())); + assertTrue(PacketLineIn.isEnd(pckIn.readString())); + } + + @Test + public void testV2FetchWithWaitForDoneOnlyDoesNegotiationAndNothingToAck() + throws Exception { + String commonInBlob = "abcdefghijklmnopqrstuvwxyz"; + + RevCommit localParent = null; + RevCommit localChild = null; + try (TestRepository<InMemoryRepository> local = new TestRepository<>( + client)) { + RevBlob localParentBlob = local.blob(commonInBlob + "a"); + localParent = local + .commit(local.tree(local.file("foo", localParentBlob))); + RevBlob localChildBlob = local.blob(commonInBlob + "b"); + localChild = local.commit( + local.tree(local.file("foo", localChildBlob)), localParent); + local.update("branch1", localChild); + } + + ByteArrayInputStream recvStream = uploadPackV2("command=fetch\n", + PacketLineIn.delimiter(), "wait-for-done\n", + "have " + localParent.toObjectId().getName() + "\n", + "have " + localChild.toObjectId().getName() + "\n", + PacketLineIn.end()); + PacketLineIn pckIn = new PacketLineIn(recvStream); + assertThat(pckIn.readString(), is("acknowledgments")); + assertThat(pckIn.readString(), is("NAK")); + assertTrue(PacketLineIn.isEnd(pckIn.readString())); + } + + @Test public void testV2FetchThinPack() throws Exception { String commonInBlob = "abcdefghijklmnopqrstuvwxyz"; diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/Base85Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/Base85Test.java new file mode 100644 index 0000000000..a49878cc76 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/Base85Test.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2021 Thomas Wolf <thomas.wolf@paranor.ch> and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.util; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; +import static org.junit.Assert.assertTrue; + +import java.nio.charset.StandardCharsets; + +import org.junit.Test; + +/** + * Tests for {@link Base85}. + */ +public class Base85Test { + + private static final String VALID_CHARS = "0123456789" + + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + + "!#$%&()*+-;<=>?@^_`{|}~"; + + @Test + public void testChars() { + for (int i = 0; i < 256; i++) { + byte[] testData = { '1', '2', '3', '4', (byte) i }; + if (VALID_CHARS.indexOf(i) >= 0) { + byte[] decoded = Base85.decode(testData, 4); + assertNotNull(decoded); + } else { + assertThrows(IllegalArgumentException.class, + () -> Base85.decode(testData, 4)); + } + } + } + + private void roundtrip(byte[] data, int expectedLength) { + byte[] encoded = Base85.encode(data); + assertEquals(expectedLength, encoded.length); + assertArrayEquals(data, Base85.decode(encoded, data.length)); + } + + private void roundtrip(String data, int expectedLength) { + roundtrip(data.getBytes(StandardCharsets.US_ASCII), expectedLength); + } + + @Test + public void testPadding() { + roundtrip("", 0); + roundtrip("a", 5); + roundtrip("ab", 5); + roundtrip("abc", 5); + roundtrip("abcd", 5); + roundtrip("abcde", 10); + roundtrip("abcdef", 10); + roundtrip("abcdefg", 10); + roundtrip("abcdefgh", 10); + roundtrip("abcdefghi", 15); + } + + @Test + public void testBinary() { + roundtrip(new byte[] { 1 }, 5); + roundtrip(new byte[] { 1, 2 }, 5); + roundtrip(new byte[] { 1, 2, 3 }, 5); + roundtrip(new byte[] { 1, 2, 3, 4 }, 5); + roundtrip(new byte[] { 1, 2, 3, 4, 5 }, 10); + roundtrip(new byte[] { 1, 2, 3, 4, 5, 0, 0, 0 }, 10); + roundtrip(new byte[] { 1, 2, 3, 4, 0, 0, 0, 5 }, 10); + } + + @Test + public void testOverflow() { + IllegalArgumentException e = assertThrows( + IllegalArgumentException.class, + () -> Base85.decode(new byte[] { '~', '~', '~', '~', '~' }, 4)); + assertTrue(e.getMessage().contains("overflow")); + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/BinaryDeltaInputStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/BinaryDeltaInputStreamTest.java new file mode 100644 index 0000000000..d9297fcd9c --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/BinaryDeltaInputStreamTest.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2021 Thomas Wolf <thomas.wolf@paranor.ch> and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.util.io; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayOutputStream; +import java.io.InputStream; +import java.util.zip.InflaterInputStream; + +import org.junit.Test; + +/** + * Crude tests for the {@link BinaryDeltaInputStream} using delta diffs + * generated by C git. + */ +public class BinaryDeltaInputStreamTest { + + private InputStream getBinaryHunk(String name) { + return this.getClass().getResourceAsStream(name); + } + + @Test + public void testBinaryDelta() throws Exception { + // Prepare our test data + byte[] data = new byte[8192]; + for (int i = 0; i < data.length; i++) { + data[i] = (byte) (255 - (i % 256)); + } + // Same, but with five 'x' inserted in the middle. + int middle = data.length / 2; + byte[] newData = new byte[data.length + 5]; + System.arraycopy(data, 0, newData, 0, middle); + for (int i = 0; i < 5; i++) { + newData[middle + i] = 'x'; + } + System.arraycopy(data, middle, newData, middle + 5, middle); + // delta1.forward has the instructions + // @formatter:off + // COPY 0 4096 + // INSERT 5 xxxxx + // COPY 0 4096 + // @formatter:on + // Note that the way we built newData could be expressed as + // @formatter:off + // COPY 0 4096 + // INSERT 5 xxxxx + // COPY 4096 4096 + // @formatter:on + try (ByteArrayOutputStream out = new ByteArrayOutputStream(); + BinaryDeltaInputStream input = new BinaryDeltaInputStream(data, + new InflaterInputStream(new BinaryHunkInputStream( + getBinaryHunk("delta1.forward"))))) { + byte[] buf = new byte[1024]; + int n; + while ((n = input.read(buf)) >= 0) { + out.write(buf, 0, n); + } + assertArrayEquals(newData, out.toByteArray()); + assertTrue(input.isFullyConsumed()); + } + // delta1.reverse has the instructions + // @formatter:off + // COPY 0 4096 + // COPY 256 3840 + // COPY 256 256 + // @formatter:on + // Note that there are alternatives, for instance + // @formatter:off + // COPY 0 4096 + // COPY 4101 4096 + // @formatter:on + // or + // @formatter:off + // COPY 0 4096 + // COPY 0 4096 + // @formatter:on + try (ByteArrayOutputStream out = new ByteArrayOutputStream(); + BinaryDeltaInputStream input = new BinaryDeltaInputStream( + newData, + new InflaterInputStream(new BinaryHunkInputStream( + getBinaryHunk("delta1.reverse"))))) { + long expectedSize = input.getExpectedResultSize(); + assertEquals(data.length, expectedSize); + byte[] buf = new byte[1024]; + int n; + while ((n = input.read(buf)) >= 0) { + out.write(buf, 0, n); + } + assertArrayEquals(data, out.toByteArray()); + assertTrue(input.isFullyConsumed()); + } + } +} diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/BinaryHunkStreamTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/BinaryHunkStreamTest.java new file mode 100644 index 0000000000..b198c32a78 --- /dev/null +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/util/io/BinaryHunkStreamTest.java @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2021 Thomas Wolf <thomas.wolf@paranor.ch> and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Distribution License v. 1.0 which is available at + * https://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +package org.eclipse.jgit.util.io; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.util.Arrays; + +import org.junit.Test; + +/** + * Tests for {@link BinaryHunkInputStream} and {@link BinaryHunkOutputStream}. + */ +public class BinaryHunkStreamTest { + + @Test + public void testRoundtripWholeBuffer() throws IOException { + for (int length = 1; length < 520 + 52; length++) { + byte[] data = new byte[length]; + for (int i = 0; i < data.length; i++) { + data[i] = (byte) (255 - (i % 256)); + } + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); + BinaryHunkOutputStream out = new BinaryHunkOutputStream( + bos)) { + out.write(data); + out.flush(); + byte[] encoded = bos.toByteArray(); + assertFalse(Arrays.equals(data, encoded)); + try (BinaryHunkInputStream in = new BinaryHunkInputStream( + new ByteArrayInputStream(encoded))) { + byte[] decoded = new byte[data.length]; + int newLength = in.read(decoded); + assertEquals(newLength, decoded.length); + assertEquals(-1, in.read()); + assertArrayEquals(data, decoded); + } + } + } + } + + @Test + public void testRoundtripChunks() throws IOException { + for (int length = 1; length < 520 + 52; length++) { + byte[] data = new byte[length]; + for (int i = 0; i < data.length; i++) { + data[i] = (byte) (255 - (i % 256)); + } + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); + BinaryHunkOutputStream out = new BinaryHunkOutputStream( + bos)) { + out.write(data, 0, data.length / 2); + out.write(data, data.length / 2, data.length - data.length / 2); + out.flush(); + byte[] encoded = bos.toByteArray(); + assertFalse(Arrays.equals(data, encoded)); + try (BinaryHunkInputStream in = new BinaryHunkInputStream( + new ByteArrayInputStream(encoded))) { + byte[] decoded = new byte[data.length]; + int p = 0; + int n; + while ((n = in.read(decoded, p, + Math.min(decoded.length - p, 57))) >= 0) { + p += n; + if (p == decoded.length) { + break; + } + } + assertEquals(p, decoded.length); + assertEquals(-1, in.read()); + assertArrayEquals(data, decoded); + } + } + } + } + + @Test + public void testRoundtripBytes() throws IOException { + for (int length = 1; length < 520 + 52; length++) { + byte[] data = new byte[length]; + for (int i = 0; i < data.length; i++) { + data[i] = (byte) (255 - (i % 256)); + } + try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); + BinaryHunkOutputStream out = new BinaryHunkOutputStream( + bos)) { + for (int i = 0; i < data.length; i++) { + out.write(data[i]); + } + out.flush(); + byte[] encoded = bos.toByteArray(); + assertFalse(Arrays.equals(data, encoded)); + try (BinaryHunkInputStream in = new BinaryHunkInputStream( + new ByteArrayInputStream(encoded))) { + byte[] decoded = new byte[data.length]; + for (int i = 0; i < decoded.length; i++) { + int val = in.read(); + assertTrue(0 <= val && val <= 255); + decoded[i] = (byte) val; + } + assertEquals(-1, in.read()); + assertArrayEquals(data, decoded); + } + } + } + } + + @Test + public void testRoundtripWithClose() throws IOException { + for (int length = 1; length < 520 + 52; length++) { + byte[] data = new byte[length]; + for (int i = 0; i < data.length; i++) { + data[i] = (byte) (255 - (i % 256)); + } + try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) { + try (BinaryHunkOutputStream out = new BinaryHunkOutputStream( + bos)) { + out.write(data); + } + byte[] encoded = bos.toByteArray(); + assertFalse(Arrays.equals(data, encoded)); + try (BinaryHunkInputStream in = new BinaryHunkInputStream( + new ByteArrayInputStream(encoded))) { + byte[] decoded = new byte[data.length]; + int newLength = in.read(decoded); + assertEquals(newLength, decoded.length); + assertEquals(-1, in.read()); + assertArrayEquals(data, decoded); + } + } + } + } +} |