Blame tests/diff/patch.c

Packit ae9e2a
#include "clar_libgit2.h"
Packit ae9e2a
#include "git2/sys/repository.h"
Packit ae9e2a
Packit ae9e2a
#include "diff_helpers.h"
Packit ae9e2a
#include "diff.h"
Packit ae9e2a
#include "repository.h"
Packit ae9e2a
#include "buf_text.h"
Packit ae9e2a
Packit ae9e2a
static git_repository *g_repo = NULL;
Packit ae9e2a
Packit ae9e2a
void test_diff_patch__initialize(void)
Packit ae9e2a
{
Packit ae9e2a
}
Packit ae9e2a
Packit ae9e2a
void test_diff_patch__cleanup(void)
Packit ae9e2a
{
Packit ae9e2a
	cl_git_sandbox_cleanup();
Packit ae9e2a
}
Packit ae9e2a
Packit ae9e2a
#define EXPECTED_HEADER "diff --git a/subdir.txt b/subdir.txt\n" \
Packit ae9e2a
	"deleted file mode 100644\n" \
Packit ae9e2a
	"index e8ee89e..0000000\n" \
Packit ae9e2a
	"--- a/subdir.txt\n" \
Packit ae9e2a
	"+++ /dev/null\n"
Packit ae9e2a
Packit ae9e2a
#define EXPECTED_HUNK "@@ -1,2 +0,0 @@\n"
Packit ae9e2a
Packit ae9e2a
static int check_removal_cb(
Packit ae9e2a
	const git_diff_delta *delta,
Packit ae9e2a
	const git_diff_hunk *hunk,
Packit ae9e2a
	const git_diff_line *line,
Packit ae9e2a
	void *payload)
Packit ae9e2a
{
Packit ae9e2a
	switch (line->origin) {
Packit ae9e2a
	case GIT_DIFF_LINE_FILE_HDR:
Packit ae9e2a
		cl_assert_equal_s(EXPECTED_HEADER, line->content);
Packit ae9e2a
		cl_assert(hunk == NULL);
Packit ae9e2a
		goto check_delta;
Packit ae9e2a
Packit ae9e2a
	case GIT_DIFF_LINE_HUNK_HDR:
Packit ae9e2a
		cl_assert_equal_s(EXPECTED_HUNK, line->content);
Packit ae9e2a
		goto check_hunk;
Packit ae9e2a
Packit ae9e2a
	case GIT_DIFF_LINE_CONTEXT:
Packit ae9e2a
	case GIT_DIFF_LINE_DELETION:
Packit ae9e2a
		if (payload != NULL)
Packit ae9e2a
			return *(int *)payload;
Packit ae9e2a
		goto check_hunk;
Packit ae9e2a
Packit ae9e2a
	default:
Packit ae9e2a
		/* unexpected code path */
Packit ae9e2a
		return -1;
Packit ae9e2a
	}
Packit ae9e2a
Packit ae9e2a
check_hunk:
Packit ae9e2a
	cl_assert(hunk != NULL);
Packit ae9e2a
	cl_assert_equal_i(1, hunk->old_start);
Packit ae9e2a
	cl_assert_equal_i(2, hunk->old_lines);
Packit ae9e2a
	cl_assert_equal_i(0, hunk->new_start);
Packit ae9e2a
	cl_assert_equal_i(0, hunk->new_lines);
Packit ae9e2a
Packit ae9e2a
check_delta:
Packit ae9e2a
	cl_assert_equal_s("subdir.txt", delta->old_file.path);
Packit ae9e2a
	cl_assert_equal_s("subdir.txt", delta->new_file.path);
Packit ae9e2a
	cl_assert_equal_i(GIT_DELTA_DELETED, delta->status);
Packit ae9e2a
Packit ae9e2a
	return 0;
Packit ae9e2a
}
Packit ae9e2a
Packit ae9e2a
void test_diff_patch__can_properly_display_the_removal_of_a_file(void)
Packit ae9e2a
{
Packit ae9e2a
	/*
Packit ae9e2a
	* $ git diff 26a125e..735b6a2
Packit ae9e2a
	* diff --git a/subdir.txt b/subdir.txt
Packit ae9e2a
	* deleted file mode 100644
Packit ae9e2a
	* index e8ee89e..0000000
Packit ae9e2a
	* --- a/subdir.txt
Packit ae9e2a
	* +++ /dev/null
Packit ae9e2a
	* @@ -1,2 +0,0 @@
Packit ae9e2a
	* -Is it a bird?
Packit ae9e2a
	* -Is it a plane?
Packit ae9e2a
	*/
Packit ae9e2a
Packit ae9e2a
	const char *one_sha = "26a125e";
Packit ae9e2a
	const char *another_sha = "735b6a2";
Packit ae9e2a
	git_tree *one, *another;
Packit ae9e2a
	git_diff *diff;
Packit ae9e2a
Packit ae9e2a
	g_repo = cl_git_sandbox_init("status");
Packit ae9e2a
Packit ae9e2a
	one = resolve_commit_oid_to_tree(g_repo, one_sha);
Packit ae9e2a
	another = resolve_commit_oid_to_tree(g_repo, another_sha);
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, one, another, NULL));
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_diff_print(
Packit ae9e2a
		diff, GIT_DIFF_FORMAT_PATCH, check_removal_cb, NULL));
Packit ae9e2a
Packit ae9e2a
	git_diff_free(diff);
Packit ae9e2a
Packit ae9e2a
	git_tree_free(another);
Packit ae9e2a
	git_tree_free(one);
Packit ae9e2a
}
Packit ae9e2a
Packit ae9e2a
void test_diff_patch__can_cancel_diff_print(void)
Packit ae9e2a
{
Packit ae9e2a
	const char *one_sha = "26a125e";
Packit ae9e2a
	const char *another_sha = "735b6a2";
Packit ae9e2a
	git_tree *one, *another;
Packit ae9e2a
	git_diff *diff;
Packit ae9e2a
	int fail_with;
Packit ae9e2a
Packit ae9e2a
	g_repo = cl_git_sandbox_init("status");
Packit ae9e2a
Packit ae9e2a
	one = resolve_commit_oid_to_tree(g_repo, one_sha);
Packit ae9e2a
	another = resolve_commit_oid_to_tree(g_repo, another_sha);
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, one, another, NULL));
Packit ae9e2a
Packit ae9e2a
	fail_with = -2323;
Packit ae9e2a
Packit ae9e2a
	cl_git_fail_with(git_diff_print(
Packit ae9e2a
		diff, GIT_DIFF_FORMAT_PATCH, check_removal_cb, &fail_with),
Packit ae9e2a
		fail_with);
Packit ae9e2a
Packit ae9e2a
	fail_with = 45;
Packit ae9e2a
Packit ae9e2a
	cl_git_fail_with(git_diff_print(
Packit ae9e2a
		diff, GIT_DIFF_FORMAT_PATCH, check_removal_cb, &fail_with),
Packit ae9e2a
		fail_with);
Packit ae9e2a
Packit ae9e2a
	git_diff_free(diff);
Packit ae9e2a
Packit ae9e2a
	git_tree_free(another);
Packit ae9e2a
	git_tree_free(one);
Packit ae9e2a
}
Packit ae9e2a
Packit ae9e2a
void test_diff_patch__to_string(void)
Packit ae9e2a
{
Packit ae9e2a
	const char *one_sha = "26a125e";
Packit ae9e2a
	const char *another_sha = "735b6a2";
Packit ae9e2a
	git_tree *one, *another;
Packit ae9e2a
	git_diff *diff;
Packit ae9e2a
	git_patch *patch;
Packit ae9e2a
	git_buf buf = GIT_BUF_INIT;
Packit ae9e2a
	const char *expected = "diff --git a/subdir.txt b/subdir.txt\ndeleted file mode 100644\nindex e8ee89e..0000000\n--- a/subdir.txt\n+++ /dev/null\n@@ -1,2 +0,0 @@\n-Is it a bird?\n-Is it a plane?\n";
Packit ae9e2a
Packit ae9e2a
	g_repo = cl_git_sandbox_init("status");
Packit ae9e2a
Packit ae9e2a
	one = resolve_commit_oid_to_tree(g_repo, one_sha);
Packit ae9e2a
	another = resolve_commit_oid_to_tree(g_repo, another_sha);
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_diff_tree_to_tree(&diff, g_repo, one, another, NULL));
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_i(1, (int)git_diff_num_deltas(diff));
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_patch_from_diff(&patch, diff, 0));
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_patch_to_buf(&buf, patch));
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_s(expected, buf.ptr);
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_sz(31, git_patch_size(patch, 0, 0, 0));
Packit ae9e2a
	cl_assert_equal_sz(31, git_patch_size(patch, 1, 0, 0));
Packit ae9e2a
	cl_assert_equal_sz(31 + 16, git_patch_size(patch, 1, 1, 0));
Packit ae9e2a
	cl_assert_equal_sz(strlen(expected), git_patch_size(patch, 1, 1, 1));
Packit ae9e2a
Packit ae9e2a
	git_buf_free(&buf;;
Packit ae9e2a
	git_patch_free(patch);
Packit ae9e2a
	git_diff_free(diff);
Packit ae9e2a
	git_tree_free(another);
Packit ae9e2a
	git_tree_free(one);
Packit ae9e2a
}
Packit ae9e2a
Packit ae9e2a
void test_diff_patch__config_options(void)
Packit ae9e2a
{
Packit ae9e2a
	const char *one_sha = "26a125e"; /* current HEAD */
Packit ae9e2a
	git_tree *one;
Packit ae9e2a
	git_config *cfg;
Packit ae9e2a
	git_diff *diff;
Packit ae9e2a
	git_patch *patch;
Packit ae9e2a
	git_buf buf = GIT_BUF_INIT;
Packit ae9e2a
	git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
Packit ae9e2a
	char *onefile = "staged_changes_modified_file";
Packit ae9e2a
	const char *expected1 = "diff --git c/staged_changes_modified_file i/staged_changes_modified_file\nindex 70bd944..906ee77 100644\n--- c/staged_changes_modified_file\n+++ i/staged_changes_modified_file\n@@ -1 +1,2 @@\n staged_changes_modified_file\n+staged_changes_modified_file\n";
Packit ae9e2a
	const char *expected2 = "diff --git i/staged_changes_modified_file w/staged_changes_modified_file\nindex 906ee77..011c344 100644\n--- i/staged_changes_modified_file\n+++ w/staged_changes_modified_file\n@@ -1,2 +1,3 @@\n staged_changes_modified_file\n staged_changes_modified_file\n+staged_changes_modified_file\n";
Packit ae9e2a
	const char *expected3 = "diff --git staged_changes_modified_file staged_changes_modified_file\nindex 906ee77..011c344 100644\n--- staged_changes_modified_file\n+++ staged_changes_modified_file\n@@ -1,2 +1,3 @@\n staged_changes_modified_file\n staged_changes_modified_file\n+staged_changes_modified_file\n";
Packit ae9e2a
	const char *expected4 = "diff --git staged_changes_modified_file staged_changes_modified_file\nindex 70bd9443ada0..906ee7711f4f 100644\n--- staged_changes_modified_file\n+++ staged_changes_modified_file\n@@ -1 +1,2 @@\n staged_changes_modified_file\n+staged_changes_modified_file\n";
Packit ae9e2a
Packit ae9e2a
	g_repo = cl_git_sandbox_init("status");
Packit ae9e2a
	cl_git_pass(git_repository_config(&cfg, g_repo));
Packit ae9e2a
	one = resolve_commit_oid_to_tree(g_repo, one_sha);
Packit ae9e2a
	opts.pathspec.count = 1;
Packit ae9e2a
	opts.pathspec.strings = &onefile;
Packit ae9e2a
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_config_set_string(cfg, "diff.mnemonicprefix", "true"));
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_diff_tree_to_index(&diff, g_repo, one, NULL, &opts));
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_i(1, (int)git_diff_num_deltas(diff));
Packit ae9e2a
	cl_git_pass(git_patch_from_diff(&patch, diff, 0));
Packit ae9e2a
	cl_git_pass(git_patch_to_buf(&buf, patch));
Packit ae9e2a
	cl_assert_equal_s(expected1, buf.ptr);
Packit ae9e2a
Packit ae9e2a
	git_buf_clear(&buf;;
Packit ae9e2a
	git_patch_free(patch);
Packit ae9e2a
	git_diff_free(diff);
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_i(1, (int)git_diff_num_deltas(diff));
Packit ae9e2a
	cl_git_pass(git_patch_from_diff(&patch, diff, 0));
Packit ae9e2a
	cl_git_pass(git_patch_to_buf(&buf, patch));
Packit ae9e2a
	cl_assert_equal_s(expected2, buf.ptr);
Packit ae9e2a
Packit ae9e2a
	git_buf_clear(&buf;;
Packit ae9e2a
	git_patch_free(patch);
Packit ae9e2a
	git_diff_free(diff);
Packit ae9e2a
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_config_set_string(cfg, "diff.noprefix", "true"));
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_i(1, (int)git_diff_num_deltas(diff));
Packit ae9e2a
	cl_git_pass(git_patch_from_diff(&patch, diff, 0));
Packit ae9e2a
	cl_git_pass(git_patch_to_buf(&buf, patch));
Packit ae9e2a
	cl_assert_equal_s(expected3, buf.ptr);
Packit ae9e2a
Packit ae9e2a
	git_buf_clear(&buf;;
Packit ae9e2a
	git_patch_free(patch);
Packit ae9e2a
	git_diff_free(diff);
Packit ae9e2a
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_config_set_int32(cfg, "core.abbrev", 12));
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_diff_tree_to_index(&diff, g_repo, one, NULL, &opts));
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_i(1, (int)git_diff_num_deltas(diff));
Packit ae9e2a
	cl_git_pass(git_patch_from_diff(&patch, diff, 0));
Packit ae9e2a
	cl_git_pass(git_patch_to_buf(&buf, patch));
Packit ae9e2a
	cl_assert_equal_s(expected4, buf.ptr);
Packit ae9e2a
Packit ae9e2a
	git_buf_clear(&buf;;
Packit ae9e2a
	git_patch_free(patch);
Packit ae9e2a
	git_diff_free(diff);
Packit ae9e2a
Packit ae9e2a
	git_buf_free(&buf;;
Packit ae9e2a
	git_tree_free(one);
Packit ae9e2a
	git_config_free(cfg);
Packit ae9e2a
}
Packit ae9e2a
Packit ae9e2a
void test_diff_patch__hunks_have_correct_line_numbers(void)
Packit ae9e2a
{
Packit ae9e2a
	git_config *cfg;
Packit ae9e2a
	git_tree *head;
Packit ae9e2a
	git_diff_options opt = GIT_DIFF_OPTIONS_INIT;
Packit ae9e2a
	git_diff *diff;
Packit ae9e2a
	git_patch *patch;
Packit ae9e2a
	const git_diff_delta *delta;
Packit ae9e2a
	const git_diff_hunk *hunk;
Packit ae9e2a
	const git_diff_line *line;
Packit ae9e2a
	size_t hunklen;
Packit ae9e2a
	git_buf old_content = GIT_BUF_INIT, actual = GIT_BUF_INIT;
Packit ae9e2a
	const char *new_content = "The Song of Seven Cities\n------------------------\n\nI WAS Lord of Cities very sumptuously builded.\nSeven roaring Cities paid me tribute from afar.\nIvory their outposts were--the guardrooms of them gilded,\nAnd garrisoned with Amazons invincible in war.\n\nThis is some new text;\nNot as good as the old text;\nBut here it is.\n\nSo they warred and trafficked only yesterday, my Cities.\nTo-day there is no mark or mound of where my Cities stood.\nFor the River rose at midnight and it washed away my Cities.\nThey are evened with Atlantis and the towns before the Flood.\n\nRain on rain-gorged channels raised the water-levels round them,\nFreshet backed on freshet swelled and swept their world from sight,\nTill the emboldened floods linked arms and, flashing forward, drowned them--\nDrowned my Seven Cities and their peoples in one night!\n\nLow among the alders lie their derelict foundations,\nThe beams wherein they trusted and the plinths whereon they built--\nMy rulers and their treasure and their unborn populations,\nDead, destroyed, aborted, and defiled with mud and silt!\n\nAnother replacement;\nBreaking up the poem;\nGenerating some hunks.\n\nTo the sound of trumpets shall their seed restore my Cities\nWealthy and well-weaponed, that once more may I behold\nAll the world go softly when it walks before my Cities,\nAnd the horses and the chariots fleeing from them as of old!\n\n  -- Rudyard Kipling\n";
Packit ae9e2a
Packit ae9e2a
	g_repo = cl_git_sandbox_init("renames");
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_config_new(&cfg));
Packit ae9e2a
	git_repository_set_config(g_repo, cfg);
Packit ae9e2a
	git_config_free(cfg);
Packit ae9e2a
Packit ae9e2a
	git_repository_reinit_filesystem(g_repo, false);
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(
Packit ae9e2a
		git_futils_readbuffer(&old_content, "renames/songof7cities.txt"));
Packit ae9e2a
Packit ae9e2a
	cl_git_rewritefile("renames/songof7cities.txt", new_content);
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_repository_head_tree(&head, g_repo));
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, head, &opt));
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_i(1, (int)git_diff_num_deltas(diff));
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_patch_from_diff(&patch, diff, 0));
Packit ae9e2a
	cl_assert((delta = git_patch_get_delta(patch)) != NULL);
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_i(GIT_DELTA_MODIFIED, (int)delta->status);
Packit ae9e2a
	cl_assert_equal_i(2, (int)git_patch_num_hunks(patch));
Packit ae9e2a
Packit ae9e2a
	/* check hunk 0 */
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(
Packit ae9e2a
		git_patch_get_hunk(&hunk, &hunklen, patch, 0));
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_i(18, (int)hunklen);
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_i(6, (int)hunk->old_start);
Packit ae9e2a
	cl_assert_equal_i(15, (int)hunk->old_lines);
Packit ae9e2a
	cl_assert_equal_i(6, (int)hunk->new_start);
Packit ae9e2a
	cl_assert_equal_i(9, (int)hunk->new_lines);
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_i(18, (int)git_patch_num_lines_in_hunk(patch, 0));
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_patch_get_line_in_hunk(&line, patch, 0, 0));
Packit ae9e2a
	cl_assert_equal_i(GIT_DIFF_LINE_CONTEXT, (int)line->origin);
Packit ae9e2a
	cl_git_pass(git_buf_set(&actual, line->content, line->content_len));
Packit ae9e2a
	cl_assert_equal_s("Ivory their outposts were--the guardrooms of them gilded,\n", actual.ptr);
Packit ae9e2a
	cl_assert_equal_i(6, line->old_lineno);
Packit ae9e2a
	cl_assert_equal_i(6, line->new_lineno);
Packit ae9e2a
	cl_assert_equal_i(-1, line->content_offset);
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_patch_get_line_in_hunk(&line, patch, 0, 3));
Packit ae9e2a
	cl_assert_equal_i(GIT_DIFF_LINE_DELETION, (int)line->origin);
Packit ae9e2a
	cl_git_pass(git_buf_set(&actual, line->content, line->content_len));
Packit ae9e2a
	cl_assert_equal_s("All the world went softly when it walked before my Cities--\n", actual.ptr);
Packit ae9e2a
	cl_assert_equal_i(9, line->old_lineno);
Packit ae9e2a
	cl_assert_equal_i(-1, line->new_lineno);
Packit ae9e2a
	cl_assert_equal_i(252, line->content_offset);
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_patch_get_line_in_hunk(&line, patch, 0, 12));
Packit ae9e2a
	cl_assert_equal_i(GIT_DIFF_LINE_ADDITION, (int)line->origin);
Packit ae9e2a
	cl_git_pass(git_buf_set(&actual, line->content, line->content_len));
Packit ae9e2a
	cl_assert_equal_s("This is some new text;\n", actual.ptr);
Packit ae9e2a
	cl_assert_equal_i(-1, line->old_lineno);
Packit ae9e2a
	cl_assert_equal_i(9, line->new_lineno);
Packit ae9e2a
	cl_assert_equal_i(252, line->content_offset);
Packit ae9e2a
Packit ae9e2a
	/* check hunk 1 */
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_patch_get_hunk(&hunk, &hunklen, patch, 1));
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_i(18, (int)hunklen);
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_i(31, (int)hunk->old_start);
Packit ae9e2a
	cl_assert_equal_i(15, (int)hunk->old_lines);
Packit ae9e2a
	cl_assert_equal_i(25, (int)hunk->new_start);
Packit ae9e2a
	cl_assert_equal_i(9, (int)hunk->new_lines);
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_i(18, (int)git_patch_num_lines_in_hunk(patch, 1));
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_patch_get_line_in_hunk(&line, patch, 1, 0));
Packit ae9e2a
	cl_assert_equal_i(GIT_DIFF_LINE_CONTEXT, (int)line->origin);
Packit ae9e2a
	cl_git_pass(git_buf_set(&actual, line->content, line->content_len));
Packit ae9e2a
	cl_assert_equal_s("My rulers and their treasure and their unborn populations,\n", actual.ptr);
Packit ae9e2a
	cl_assert_equal_i(31, line->old_lineno);
Packit ae9e2a
	cl_assert_equal_i(25, line->new_lineno);
Packit ae9e2a
	cl_assert_equal_i(-1, line->content_offset);
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_patch_get_line_in_hunk(&line, patch, 1, 3));
Packit ae9e2a
	cl_assert_equal_i(GIT_DIFF_LINE_DELETION, (int)line->origin);
Packit ae9e2a
	cl_git_pass(git_buf_set(&actual, line->content, line->content_len));
Packit ae9e2a
	cl_assert_equal_s("The Daughters of the Palace whom they cherished in my Cities,\n", actual.ptr);
Packit ae9e2a
	cl_assert_equal_i(34, line->old_lineno);
Packit ae9e2a
	cl_assert_equal_i(-1, line->new_lineno);
Packit ae9e2a
	cl_assert_equal_i(1468, line->content_offset);
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_patch_get_line_in_hunk(&line, patch, 1, 12));
Packit ae9e2a
	cl_assert_equal_i(GIT_DIFF_LINE_ADDITION, (int)line->origin);
Packit ae9e2a
	cl_git_pass(git_buf_set(&actual, line->content, line->content_len));
Packit ae9e2a
	cl_assert_equal_s("Another replacement;\n", actual.ptr);
Packit ae9e2a
	cl_assert_equal_i(-1, line->old_lineno);
Packit ae9e2a
	cl_assert_equal_i(28, line->new_lineno);
Packit ae9e2a
	cl_assert_equal_i(1066, line->content_offset);
Packit ae9e2a
Packit ae9e2a
	git_patch_free(patch);
Packit ae9e2a
	git_diff_free(diff);
Packit ae9e2a
Packit ae9e2a
	/* Let's check line numbers when there is no newline */
Packit ae9e2a
Packit ae9e2a
	git_buf_rtrim(&old_content);
Packit ae9e2a
	cl_git_rewritefile("renames/songof7cities.txt", old_content.ptr);
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_diff_tree_to_workdir(&diff, g_repo, head, &opt));
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_i(1, (int)git_diff_num_deltas(diff));
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_patch_from_diff(&patch, diff, 0));
Packit ae9e2a
	cl_assert((delta = git_patch_get_delta(patch)) != NULL);
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_i(GIT_DELTA_MODIFIED, (int)delta->status);
Packit ae9e2a
	cl_assert_equal_i(1, (int)git_patch_num_hunks(patch));
Packit ae9e2a
Packit ae9e2a
	/* check hunk 0 */
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_patch_get_hunk(&hunk, &hunklen, patch, 0));
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_i(6, (int)hunklen);
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_i(46, (int)hunk->old_start);
Packit ae9e2a
	cl_assert_equal_i(4, (int)hunk->old_lines);
Packit ae9e2a
	cl_assert_equal_i(46, (int)hunk->new_start);
Packit ae9e2a
	cl_assert_equal_i(4, (int)hunk->new_lines);
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_i(6, (int)git_patch_num_lines_in_hunk(patch, 0));
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_patch_get_line_in_hunk(&line, patch, 0, 1));
Packit ae9e2a
	cl_assert_equal_i(GIT_DIFF_LINE_CONTEXT, (int)line->origin);
Packit ae9e2a
	cl_git_pass(git_buf_set(&actual, line->content, line->content_len));
Packit ae9e2a
	cl_assert_equal_s("And the horses and the chariots fleeing from them as of old!\n", actual.ptr);
Packit ae9e2a
	cl_assert_equal_i(47, line->old_lineno);
Packit ae9e2a
	cl_assert_equal_i(47, line->new_lineno);
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_patch_get_line_in_hunk(&line, patch, 0, 2));
Packit ae9e2a
	cl_assert_equal_i(GIT_DIFF_LINE_CONTEXT, (int)line->origin);
Packit ae9e2a
	cl_git_pass(git_buf_set(&actual, line->content, line->content_len));
Packit ae9e2a
	cl_assert_equal_s("\n", actual.ptr);
Packit ae9e2a
	cl_assert_equal_i(48, line->old_lineno);
Packit ae9e2a
	cl_assert_equal_i(48, line->new_lineno);
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_patch_get_line_in_hunk(&line, patch, 0, 3));
Packit ae9e2a
	cl_assert_equal_i(GIT_DIFF_LINE_DELETION, (int)line->origin);
Packit ae9e2a
	cl_git_pass(git_buf_set(&actual, line->content, line->content_len));
Packit ae9e2a
	cl_assert_equal_s("  -- Rudyard Kipling\n", actual.ptr);
Packit ae9e2a
	cl_assert_equal_i(49, line->old_lineno);
Packit ae9e2a
	cl_assert_equal_i(-1, line->new_lineno);
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_patch_get_line_in_hunk(&line, patch, 0, 4));
Packit ae9e2a
	cl_assert_equal_i(GIT_DIFF_LINE_ADDITION, (int)line->origin);
Packit ae9e2a
	cl_git_pass(git_buf_set(&actual, line->content, line->content_len));
Packit ae9e2a
	cl_assert_equal_s("  -- Rudyard Kipling", actual.ptr);
Packit ae9e2a
	cl_assert_equal_i(-1, line->old_lineno);
Packit ae9e2a
	cl_assert_equal_i(49, line->new_lineno);
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_patch_get_line_in_hunk(&line, patch, 0, 5));
Packit ae9e2a
	cl_assert_equal_i(GIT_DIFF_LINE_DEL_EOFNL, (int)line->origin);
Packit ae9e2a
	cl_git_pass(git_buf_set(&actual, line->content, line->content_len));
Packit ae9e2a
	cl_assert_equal_s("\n\\ No newline at end of file\n", actual.ptr);
Packit ae9e2a
	cl_assert_equal_i(-1, line->old_lineno);
Packit ae9e2a
	cl_assert_equal_i(49, line->new_lineno);
Packit ae9e2a
Packit ae9e2a
	git_patch_free(patch);
Packit ae9e2a
	git_diff_free(diff);
Packit ae9e2a
Packit ae9e2a
	git_buf_free(&actual);
Packit ae9e2a
	git_buf_free(&old_content);
Packit ae9e2a
	git_tree_free(head);
Packit ae9e2a
}
Packit ae9e2a
Packit ae9e2a
static void check_single_patch_stats(
Packit ae9e2a
	git_repository *repo, size_t hunks,
Packit ae9e2a
	size_t adds, size_t dels, size_t ctxt, size_t *sizes,
Packit ae9e2a
	const char *expected)
Packit ae9e2a
{
Packit ae9e2a
	git_diff *diff;
Packit ae9e2a
	git_patch *patch;
Packit ae9e2a
	const git_diff_delta *delta;
Packit ae9e2a
	size_t actual_ctxt, actual_adds, actual_dels;
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_diff_index_to_workdir(&diff, repo, NULL, NULL));
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_i(1, (int)git_diff_num_deltas(diff));
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_patch_from_diff(&patch, diff, 0));
Packit ae9e2a
	cl_assert((delta = git_patch_get_delta(patch)) != NULL);
Packit ae9e2a
	cl_assert_equal_i(GIT_DELTA_MODIFIED, (int)delta->status);
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_i((int)hunks, (int)git_patch_num_hunks(patch));
Packit ae9e2a
Packit ae9e2a
	cl_git_pass( git_patch_line_stats(
Packit ae9e2a
		&actual_ctxt, &actual_adds, &actual_dels, patch) );
Packit ae9e2a
Packit ae9e2a
	cl_assert_equal_sz(ctxt, actual_ctxt);
Packit ae9e2a
	cl_assert_equal_sz(adds, actual_adds);
Packit ae9e2a
	cl_assert_equal_sz(dels, actual_dels);
Packit ae9e2a
Packit ae9e2a
	if (expected != NULL) {
Packit ae9e2a
		git_buf buf = GIT_BUF_INIT;
Packit ae9e2a
		cl_git_pass(git_patch_to_buf(&buf, patch));
Packit ae9e2a
		cl_assert_equal_s(expected, buf.ptr);
Packit ae9e2a
		git_buf_free(&buf;;
Packit ae9e2a
Packit ae9e2a
		cl_assert_equal_sz(
Packit ae9e2a
			strlen(expected), git_patch_size(patch, 1, 1, 1));
Packit ae9e2a
	}
Packit ae9e2a
Packit ae9e2a
	if (sizes) {
Packit ae9e2a
		if (sizes[0])
Packit ae9e2a
			cl_assert_equal_sz(sizes[0], git_patch_size(patch, 0, 0, 0));
Packit ae9e2a
		if (sizes[1])
Packit ae9e2a
			cl_assert_equal_sz(sizes[1], git_patch_size(patch, 1, 0, 0));
Packit ae9e2a
		if (sizes[2])
Packit ae9e2a
			cl_assert_equal_sz(sizes[2], git_patch_size(patch, 1, 1, 0));
Packit ae9e2a
	}
Packit ae9e2a
Packit ae9e2a
	/* walk lines in hunk with basic sanity checks */
Packit ae9e2a
	for (; hunks > 0; --hunks) {
Packit ae9e2a
		size_t i, max_i;
Packit ae9e2a
		const git_diff_line *line;
Packit ae9e2a
		int last_new_lineno = -1, last_old_lineno = -1;
Packit ae9e2a
Packit ae9e2a
		max_i = git_patch_num_lines_in_hunk(patch, hunks - 1);
Packit ae9e2a
Packit ae9e2a
		for (i = 0; i < max_i; ++i) {
Packit ae9e2a
			int expected = 1;
Packit ae9e2a
Packit ae9e2a
			cl_git_pass(
Packit ae9e2a
				git_patch_get_line_in_hunk(&line, patch, hunks - 1, i));
Packit ae9e2a
Packit ae9e2a
			if (line->origin == GIT_DIFF_LINE_ADD_EOFNL ||
Packit ae9e2a
				line->origin == GIT_DIFF_LINE_DEL_EOFNL ||
Packit ae9e2a
				line->origin == GIT_DIFF_LINE_CONTEXT_EOFNL)
Packit ae9e2a
				expected = 0;
Packit ae9e2a
Packit ae9e2a
			if (line->old_lineno >= 0) {
Packit ae9e2a
				if (last_old_lineno >= 0)
Packit ae9e2a
					cl_assert_equal_i(
Packit ae9e2a
						expected, line->old_lineno - last_old_lineno);
Packit ae9e2a
				last_old_lineno = line->old_lineno;
Packit ae9e2a
			}
Packit ae9e2a
Packit ae9e2a
			if (line->new_lineno >= 0) {
Packit ae9e2a
				if (last_new_lineno >= 0)
Packit ae9e2a
					cl_assert_equal_i(
Packit ae9e2a
						expected, line->new_lineno - last_new_lineno);
Packit ae9e2a
				last_new_lineno = line->new_lineno;
Packit ae9e2a
			}
Packit ae9e2a
		}
Packit ae9e2a
	}
Packit ae9e2a
Packit ae9e2a
	git_patch_free(patch);
Packit ae9e2a
	git_diff_free(diff);
Packit ae9e2a
}
Packit ae9e2a
Packit ae9e2a
void test_diff_patch__line_counts_with_eofnl(void)
Packit ae9e2a
{
Packit ae9e2a
	git_config *cfg;
Packit ae9e2a
	git_buf content = GIT_BUF_INIT;
Packit ae9e2a
	const char *end;
Packit ae9e2a
	git_index *index;
Packit ae9e2a
	const char *expected =
Packit ae9e2a
		/* below is pasted output of 'git diff' with fn context removed */
Packit ae9e2a
		"diff --git a/songof7cities.txt b/songof7cities.txt\n"
Packit ae9e2a
		"index 378a7d9..3d0154e 100644\n"
Packit ae9e2a
		"--- a/songof7cities.txt\n"
Packit ae9e2a
		"+++ b/songof7cities.txt\n"
Packit ae9e2a
		"@@ -42,7 +42,7 @@ With peoples undefeated of the dark, enduring blood.\n"
Packit ae9e2a
		" \n"
Packit ae9e2a
		" To the sound of trumpets shall their seed restore my Cities\n"
Packit ae9e2a
		" Wealthy and well-weaponed, that once more may I behold\n"
Packit ae9e2a
		"-All the world go softly when it walks before my Cities,\n"
Packit ae9e2a
		"+#All the world go softly when it walks before my Cities,\n"
Packit ae9e2a
		" And the horses and the chariots fleeing from them as of old!\n"
Packit ae9e2a
		" \n"
Packit ae9e2a
		"   -- Rudyard Kipling\n"
Packit ae9e2a
		"\\ No newline at end of file\n";
Packit ae9e2a
	size_t expected_sizes[3] = { 115, 119 + 115 + 114, 119 + 115 + 114 + 71 };
Packit ae9e2a
Packit ae9e2a
	g_repo = cl_git_sandbox_init("renames");
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_config_new(&cfg));
Packit ae9e2a
	git_repository_set_config(g_repo, cfg);
Packit ae9e2a
	git_config_free(cfg);
Packit ae9e2a
Packit ae9e2a
	git_repository_reinit_filesystem(g_repo, false);
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_futils_readbuffer(&content, "renames/songof7cities.txt"));
Packit ae9e2a
Packit ae9e2a
	/* remove first line */
Packit ae9e2a
Packit ae9e2a
	end = git_buf_cstr(&content) + git_buf_find(&content, '\n') + 1;
Packit ae9e2a
	git_buf_consume(&content, end);
Packit ae9e2a
	cl_git_rewritefile("renames/songof7cities.txt", content.ptr);
Packit ae9e2a
Packit ae9e2a
	check_single_patch_stats(g_repo, 1, 0, 1, 3, NULL, NULL);
Packit ae9e2a
Packit ae9e2a
	/* remove trailing whitespace */
Packit ae9e2a
Packit ae9e2a
	git_buf_rtrim(&content);
Packit ae9e2a
	cl_git_rewritefile("renames/songof7cities.txt", content.ptr);
Packit ae9e2a
Packit ae9e2a
	check_single_patch_stats(g_repo, 2, 1, 2, 6, NULL, NULL);
Packit ae9e2a
Packit ae9e2a
	/* add trailing whitespace */
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_repository_index(&index, g_repo));
Packit ae9e2a
	cl_git_pass(git_index_add_bypath(index, "songof7cities.txt"));
Packit ae9e2a
	cl_git_pass(git_index_write(index));
Packit ae9e2a
	git_index_free(index);
Packit ae9e2a
Packit ae9e2a
	cl_git_pass(git_buf_putc(&content, '\n'));
Packit ae9e2a
	cl_git_rewritefile("renames/songof7cities.txt", content.ptr);
Packit ae9e2a
Packit ae9e2a
	check_single_patch_stats(g_repo, 1, 1, 1, 3, NULL, NULL);
Packit ae9e2a
Packit ae9e2a
	/* no trailing whitespace as context line */
Packit ae9e2a
Packit ae9e2a
	{
Packit ae9e2a
		/* walk back a couple lines, make space and insert char */
Packit ae9e2a
		char *scan = content.ptr + content.size;
Packit ae9e2a
		int i;
Packit ae9e2a
Packit ae9e2a
		for (i = 0; i < 5; ++i) {
Packit ae9e2a
			for (--scan; scan > content.ptr && *scan != '\n'; --scan)
Packit ae9e2a
				/* seek to prev \n */;
Packit ae9e2a
		}
Packit ae9e2a
		cl_assert(scan > content.ptr);
Packit ae9e2a
Packit ae9e2a
		/* overwrite trailing \n with right-shifted content */
Packit ae9e2a
		memmove(scan + 1, scan, content.size - (scan - content.ptr) - 1);
Packit ae9e2a
		/* insert '#' char into space we created */
Packit ae9e2a
		scan[1] = '#';
Packit ae9e2a
	}
Packit ae9e2a
	cl_git_rewritefile("renames/songof7cities.txt", content.ptr);
Packit ae9e2a
Packit ae9e2a
	check_single_patch_stats(
Packit ae9e2a
		g_repo, 1, 1, 1, 6, expected_sizes, expected);
Packit ae9e2a
Packit ae9e2a
	git_buf_free(&content);
Packit ae9e2a
}