summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJason Haslam <jason@scitools.com>2017-03-30 22:40:47 -0600
committerEdward Thomson <ethomson@edwardthomson.com>2018-11-05 15:53:59 +0000
commit7263057269ee7131093046205abfcf5938a59ebf (patch)
tree9353d0829fec545d5d2c9c0d1ff77eca628dc4e1
parent52e27b840437d1a374c014a04787d0962f05a4f0 (diff)
downloadlibgit2-7263057269ee7131093046205abfcf5938a59ebf.tar.gz
patch: add support for partial patch application
Add hunk callback parameter to git_apply__patch to allow hunks to be skipped.
-rw-r--r--tests/apply/fromdiff.c46
-rw-r--r--tests/apply/partial.c161
-rw-r--r--tests/patch/patch_common.h106
3 files changed, 313 insertions, 0 deletions
diff --git a/tests/apply/fromdiff.c b/tests/apply/fromdiff.c
index 3b156025e..8a6d8fa0a 100644
--- a/tests/apply/fromdiff.c
+++ b/tests/apply/fromdiff.c
@@ -150,6 +150,52 @@ void test_apply_fromdiff__prepend_nocontext(void)
PATCH_ORIGINAL_TO_PREPEND_NOCONTEXT, &diff_opts));
}
+void test_apply_fromdiff__prepend_and_change(void)
+{
+ cl_git_pass(apply_buf(
+ FILE_ORIGINAL, "file.txt",
+ FILE_PREPEND_AND_CHANGE, "file.txt",
+ PATCH_ORIGINAL_TO_PREPEND_AND_CHANGE, NULL));
+}
+
+void test_apply_fromdiff__prepend_and_change_nocontext(void)
+{
+ git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
+ diff_opts.context_lines = 0;
+
+ cl_git_pass(apply_buf(
+ FILE_ORIGINAL, "file.txt",
+ FILE_PREPEND_AND_CHANGE, "file.txt",
+ PATCH_ORIGINAL_TO_PREPEND_AND_CHANGE_NOCONTEXT, &diff_opts));
+}
+
+void test_apply_fromdiff__delete_and_change(void)
+{
+ cl_git_pass(apply_buf(
+ FILE_ORIGINAL, "file.txt",
+ FILE_DELETE_AND_CHANGE, "file.txt",
+ PATCH_ORIGINAL_TO_DELETE_AND_CHANGE, NULL));
+}
+
+void test_apply_fromdiff__delete_and_change_nocontext(void)
+{
+ git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
+ diff_opts.context_lines = 0;
+
+ cl_git_pass(apply_buf(
+ FILE_ORIGINAL, "file.txt",
+ FILE_DELETE_AND_CHANGE, "file.txt",
+ PATCH_ORIGINAL_TO_DELETE_AND_CHANGE_NOCONTEXT, &diff_opts));
+}
+
+void test_apply_fromdiff__delete_firstline(void)
+{
+ cl_git_pass(apply_buf(
+ FILE_ORIGINAL, "file.txt",
+ FILE_DELETE_FIRSTLINE, "file.txt",
+ PATCH_ORIGINAL_TO_DELETE_FIRSTLINE, NULL));
+}
+
void test_apply_fromdiff__append(void)
{
cl_git_pass(apply_buf(
diff --git a/tests/apply/partial.c b/tests/apply/partial.c
new file mode 100644
index 000000000..bdbf35a7f
--- /dev/null
+++ b/tests/apply/partial.c
@@ -0,0 +1,161 @@
+#include "clar_libgit2.h"
+#include "git2/sys/repository.h"
+
+#include "apply.h"
+#include "repository.h"
+#include "buf_text.h"
+
+#include "../patch/patch_common.h"
+
+static git_repository *repo = NULL;
+
+void test_apply_partial__initialize(void)
+{
+ repo = cl_git_sandbox_init("renames");
+}
+
+void test_apply_partial__cleanup(void)
+{
+ cl_git_sandbox_cleanup();
+}
+
+static int skip_addition(
+ const git_diff_hunk *hunk,
+ void *payload)
+{
+ GIT_UNUSED(payload);
+
+ return (hunk->new_lines > hunk->old_lines) ? 1 : 0;
+}
+
+static int skip_deletion(
+ const git_diff_hunk *hunk,
+ void *payload)
+{
+ GIT_UNUSED(payload);
+
+ return (hunk->new_lines < hunk->old_lines) ? 1 : 0;
+}
+
+static int skip_change(
+ const git_diff_hunk *hunk,
+ void *payload)
+{
+ GIT_UNUSED(payload);
+
+ return (hunk->new_lines == hunk->old_lines) ? 1 : 0;
+}
+
+static int apply_buf(
+ const char *old,
+ const char *oldname,
+ const char *new,
+ const char *newname,
+ const char *expected,
+ const git_diff_options *diff_opts,
+ git_apply_hunk_cb hunk_cb,
+ void *payload)
+{
+ git_patch *patch;
+ git_buf result = GIT_BUF_INIT;
+ git_buf patchbuf = GIT_BUF_INIT;
+ git_apply_options opts = GIT_APPLY_OPTIONS_INIT;
+ char *filename;
+ unsigned int mode;
+ int error;
+ size_t oldsize = strlen(old);
+ size_t newsize = strlen(new);
+
+ opts.hunk_cb = hunk_cb;
+ opts.payload = payload;
+
+ cl_git_pass(git_patch_from_buffers(&patch, old, oldsize, oldname, new, newsize, newname, diff_opts));
+ if ((error = git_apply__patch(&result, &filename, &mode, old, oldsize, patch, &opts)) == 0) {
+ cl_assert_equal_s(expected, result.ptr);
+ cl_assert_equal_s(newname, filename);
+ cl_assert_equal_i(0100644, mode);
+ }
+
+ git__free(filename);
+ git_buf_free(&result);
+ git_buf_free(&patchbuf);
+ git_patch_free(patch);
+
+ return error;
+}
+
+void test_apply_partial__prepend_and_change_skip_addition(void)
+{
+ cl_git_pass(apply_buf(
+ FILE_ORIGINAL, "file.txt",
+ FILE_PREPEND_AND_CHANGE, "file.txt",
+ FILE_ORIGINAL, NULL, skip_addition, NULL));
+}
+
+void test_apply_partial__prepend_and_change_nocontext_skip_addition(void)
+{
+ git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
+ diff_opts.context_lines = 0;
+
+ cl_git_pass(apply_buf(
+ FILE_ORIGINAL, "file.txt",
+ FILE_PREPEND_AND_CHANGE, "file.txt",
+ FILE_CHANGE_MIDDLE, &diff_opts, skip_addition, NULL));
+}
+
+void test_apply_partial__prepend_and_change_skip_change(void)
+{
+ cl_git_pass(apply_buf(
+ FILE_ORIGINAL, "file.txt",
+ FILE_PREPEND_AND_CHANGE, "file.txt",
+ FILE_PREPEND_AND_CHANGE, NULL, skip_change, NULL));
+}
+
+void test_apply_partial__prepend_and_change_nocontext_skip_change(void)
+{
+ git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
+ diff_opts.context_lines = 0;
+
+ cl_git_pass(apply_buf(
+ FILE_ORIGINAL, "file.txt",
+ FILE_PREPEND_AND_CHANGE, "file.txt",
+ FILE_PREPEND, &diff_opts, skip_change, NULL));
+}
+
+void test_apply_partial__delete_and_change_skip_deletion(void)
+{
+ cl_git_pass(apply_buf(
+ FILE_ORIGINAL, "file.txt",
+ FILE_DELETE_AND_CHANGE, "file.txt",
+ FILE_ORIGINAL, NULL, skip_deletion, NULL));
+}
+
+void test_apply_partial__delete_and_change_nocontext_skip_deletion(void)
+{
+ git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
+ diff_opts.context_lines = 0;
+
+ cl_git_pass(apply_buf(
+ FILE_ORIGINAL, "file.txt",
+ FILE_DELETE_AND_CHANGE, "file.txt",
+ FILE_CHANGE_MIDDLE, &diff_opts, skip_deletion, NULL));
+}
+
+void test_apply_partial__delete_and_change_skip_change(void)
+{
+ cl_git_pass(apply_buf(
+ FILE_ORIGINAL, "file.txt",
+ FILE_DELETE_AND_CHANGE, "file.txt",
+ FILE_DELETE_AND_CHANGE, NULL, skip_change, NULL));
+}
+
+void test_apply_partial__delete_and_change_nocontext_skip_change(void)
+{
+ git_diff_options diff_opts = GIT_DIFF_OPTIONS_INIT;
+ diff_opts.context_lines = 0;
+
+ cl_git_pass(apply_buf(
+ FILE_ORIGINAL, "file.txt",
+ FILE_DELETE_AND_CHANGE, "file.txt",
+ FILE_DELETE_FIRSTLINE, &diff_opts, skip_change, NULL));
+}
diff --git a/tests/patch/patch_common.h b/tests/patch/patch_common.h
index e838e6089..3f2668ddc 100644
--- a/tests/patch/patch_common.h
+++ b/tests/patch/patch_common.h
@@ -220,6 +220,112 @@
"@@ -0,0 +1 @@\n" \
"+insert at front\n"
+/* An insertion at the beginning of the file and change in the middle */
+
+#define FILE_PREPEND_AND_CHANGE \
+ "insert at front\n" \
+ "hey!\n" \
+ "this is some context!\n" \
+ "around some lines\n" \
+ "that will change\n" \
+ "yes it is!\n" \
+ "(THIS line is changed!)\n" \
+ "and this\n" \
+ "is additional context\n" \
+ "below it!\n"
+
+#define PATCH_ORIGINAL_TO_PREPEND_AND_CHANGE \
+ "diff --git a/file.txt b/file.txt\n" \
+ "index 9432026..f73c8bb 100644\n" \
+ "--- a/file.txt\n" \
+ "+++ b/file.txt\n" \
+ "@@ -1,9 +1,10 @@\n" \
+ "+insert at front\n" \
+ " hey!\n" \
+ " this is some context!\n" \
+ " around some lines\n" \
+ " that will change\n" \
+ " yes it is!\n" \
+ "-(this line is changed)\n" \
+ "+(THIS line is changed!)\n" \
+ " and this\n" \
+ " is additional context\n" \
+ " below it!\n"
+
+#define PATCH_ORIGINAL_TO_PREPEND_AND_CHANGE_NOCONTEXT \
+ "diff --git a/file.txt b/file.txt\n" \
+ "index 9432026..f73c8bb 100644\n" \
+ "--- a/file.txt\n" \
+ "+++ b/file.txt\n" \
+ "@@ -0,0 +1 @@\n" \
+ "+insert at front\n" \
+ "@@ -6 +7 @@ yes it is!\n" \
+ "-(this line is changed)\n" \
+ "+(THIS line is changed!)\n"
+
+/* A deletion at the beginning of the file and a change in the middle */
+
+#define FILE_DELETE_AND_CHANGE \
+ "this is some context!\n" \
+ "around some lines\n" \
+ "that will change\n" \
+ "yes it is!\n" \
+ "(THIS line is changed!)\n" \
+ "and this\n" \
+ "is additional context\n" \
+ "below it!\n"
+
+#define PATCH_ORIGINAL_TO_DELETE_AND_CHANGE \
+ "diff --git a/file.txt b/file.txt\n" \
+ "index 9432026..1e2dfa6 100644\n" \
+ "--- a/file.txt\n" \
+ "+++ b/file.txt\n" \
+ "@@ -1,9 +1,8 @@\n" \
+ "-hey!\n" \
+ " this is some context!\n" \
+ " around some lines\n" \
+ " that will change\n" \
+ " yes it is!\n" \
+ "-(this line is changed)\n" \
+ "+(THIS line is changed!)\n" \
+ " and this\n" \
+ " is additional context\n" \
+ " below it!\n"
+
+#define PATCH_ORIGINAL_TO_DELETE_AND_CHANGE_NOCONTEXT \
+ "diff --git a/file.txt b/file.txt\n" \
+ "index 9432026..1e2dfa6 100644\n" \
+ "--- a/file.txt\n" \
+ "+++ b/file.txt\n" \
+ "@@ -1 +0,0 @@\n" \
+ "-hey!\n" \
+ "@@ -6 +5 @@ yes it is!\n" \
+ "-(this line is changed)\n" \
+ "+(THIS line is changed!)\n"
+
+/* A deletion at the beginning of the file */
+
+#define FILE_DELETE_FIRSTLINE \
+ "this is some context!\n" \
+ "around some lines\n" \
+ "that will change\n" \
+ "yes it is!\n" \
+ "(this line is changed)\n" \
+ "and this\n" \
+ "is additional context\n" \
+ "below it!\n"
+
+#define PATCH_ORIGINAL_TO_DELETE_FIRSTLINE \
+ "diff --git a/file.txt b/file.txt\n" \
+ "index 9432026..f31fa13 100644\n" \
+ "--- a/file.txt\n" \
+ "+++ b/file.txt\n" \
+ "@@ -1,4 +1,3 @@\n" \
+ "-hey!\n" \
+ " this is some context!\n" \
+ " around some lines\n" \
+ " that will change\n"
+
/* An insertion at the end of the file (and the resultant patch) */
#define FILE_APPEND \