Commit 4535f04409a9379ace7cdda0b53a62d3cdf20676

Russell Belfer 2013-06-27T16:12:44

More diff submodule tests for cache issues The submodules code caches data about submodules in a way that can cause problems. This adds some tests that try making various modifications to the state of a submodule to see where we can catch out problems in the submodule caching. Right now, I've put in an extra git_submodule_reload_all so that the test will pass, but with that commented out, the test fails. I'm working on fixing the broken version of the test at which point I'll commit the fix and delete the extra reload that makes the test pass.

diff --git a/tests-clar/diff/submodules.c b/tests-clar/diff/submodules.c
index c7bdf6d..9b77897 100644
--- a/tests-clar/diff/submodules.c
+++ b/tests-clar/diff/submodules.c
@@ -234,3 +234,153 @@ void test_diff_submodules__submod2_head_to_index(void)
 
 	git_tree_free(head);
 }
+
+void test_diff_submodules__invalid_cache(void)
+{
+	git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
+	git_diff_list *diff = NULL;
+	git_submodule *sm;
+	char *smpath = "sm_changed_head";
+	git_repository *smrepo;
+	git_index *smindex;
+	static const char *expected_baseline[] = {
+		"diff --git a/sm_changed_head b/sm_changed_head\nindex 4800958..3d9386c 160000\n--- a/sm_changed_head\n+++ b/sm_changed_head\n@@ -1 +1 @@\n-Subproject commit 480095882d281ed676fe5b863569520e54a7d5c0\n+Subproject commit 3d9386c507f6b093471a3e324085657a3c2b4247\n", /* sm_changed_head */
+		"<END>"
+	};
+	static const char *expected_unchanged[] = { "<END>" };
+	static const char *expected_dirty[] = {
+		"diff --git a/sm_changed_head b/sm_changed_head\nindex 3d9386c..3d9386c 160000\n--- a/sm_changed_head\n+++ b/sm_changed_head\n@@ -1 +1 @@\n-Subproject commit 3d9386c507f6b093471a3e324085657a3c2b4247\n+Subproject commit 3d9386c507f6b093471a3e324085657a3c2b4247-dirty\n",
+		"<END>"
+	};
+	static const char *expected_moved[] = {
+		"diff --git a/sm_changed_head b/sm_changed_head\nindex 3d9386c..0910a13 160000\n--- a/sm_changed_head\n+++ b/sm_changed_head\n@@ -1 +1 @@\n-Subproject commit 3d9386c507f6b093471a3e324085657a3c2b4247\n+Subproject commit 0910a13dfa2210496f6c590d75bc360dd11b2a1b\n",
+		"<END>"
+	};
+	static const char *expected_moved_dirty[] = {
+		"diff --git a/sm_changed_head b/sm_changed_head\nindex 3d9386c..0910a13 160000\n--- a/sm_changed_head\n+++ b/sm_changed_head\n@@ -1 +1 @@\n-Subproject commit 3d9386c507f6b093471a3e324085657a3c2b4247\n+Subproject commit 0910a13dfa2210496f6c590d75bc360dd11b2a1b-dirty\n",
+		"<END>"
+	};
+
+	setup_submodules2();
+
+	opts.flags = GIT_DIFF_INCLUDE_UNTRACKED;
+	opts.old_prefix = "a"; opts.new_prefix = "b";
+	opts.pathspec.count = 1;
+	opts.pathspec.strings = &smpath;
+
+	/* baseline */
+	cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+	check_diff_patches(diff, expected_baseline);
+	git_diff_list_free(diff);
+
+	/* update index with new HEAD */
+	cl_git_pass(git_submodule_lookup(&sm, g_repo, smpath));
+	cl_git_pass(git_submodule_add_to_index(sm, 1));
+
+	cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+	check_diff_patches(diff, expected_unchanged);
+	git_diff_list_free(diff);
+
+	/* create untracked file in submodule working directory */
+	cl_git_mkfile("submod2/sm_changed_head/new_around_here", "hello");
+	git_submodule_set_ignore(sm, GIT_SUBMODULE_IGNORE_NONE);
+
+	cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+	check_diff_patches(diff, expected_dirty);
+	git_diff_list_free(diff);
+
+	git_submodule_set_ignore(sm, GIT_SUBMODULE_IGNORE_UNTRACKED);
+
+	cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+	check_diff_patches(diff, expected_unchanged);
+	git_diff_list_free(diff);
+
+	/* modify tracked file in submodule working directory */
+	cl_git_append2file(
+		"submod2/sm_changed_head/file_to_modify", "\nmore stuff\n");
+
+	cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+	check_diff_patches(diff, expected_dirty);
+	git_diff_list_free(diff);
+
+	cl_git_pass(git_submodule_reload_all(g_repo));
+	cl_git_pass(git_submodule_lookup(&sm, g_repo, smpath));
+
+	cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+	check_diff_patches(diff, expected_dirty);
+	git_diff_list_free(diff);
+
+	git_submodule_set_ignore(sm, GIT_SUBMODULE_IGNORE_DIRTY);
+
+	cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+	check_diff_patches(diff, expected_unchanged);
+	git_diff_list_free(diff);
+
+	/* add file to index in submodule */
+	cl_git_pass(git_submodule_open(&smrepo, sm));
+	cl_git_pass(git_repository_index(&smindex, smrepo));
+	cl_git_pass(git_index_add_bypath(smindex, "file_to_modify"));
+
+	git_submodule_set_ignore(sm, GIT_SUBMODULE_IGNORE_UNTRACKED);
+
+	cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+	check_diff_patches(diff, expected_dirty);
+	git_diff_list_free(diff);
+
+	git_submodule_set_ignore(sm, GIT_SUBMODULE_IGNORE_DIRTY);
+
+	cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+	check_diff_patches(diff, expected_unchanged);
+	git_diff_list_free(diff);
+
+	/* commit changed index of submodule */
+	{
+		git_object *parent;
+		git_oid tree_id, commit_id;
+		git_tree *tree;
+		git_signature *sig;
+
+		cl_git_pass(git_revparse_single(&parent, smrepo, "HEAD"));
+		cl_git_pass(git_index_write_tree(&tree_id, smindex));
+		cl_git_pass(git_index_write(smindex));
+		cl_git_pass(git_tree_lookup(&tree, smrepo, &tree_id));
+		cl_git_pass(git_signature_new(&sig, "Sm Test", "sm@tester.test", 1372350000, 480));
+		cl_git_pass(git_commit_create_v(
+			&commit_id, smrepo, "HEAD", sig, sig, NULL,
+			"Move it", tree, 1, parent));
+		git_object_free(parent);
+		git_tree_free(tree);
+		git_signature_free(sig);
+	}
+
+	/* THIS RELOAD SHOULD NOT BE REQUIRED */
+	cl_git_pass(git_submodule_reload_all(g_repo));
+	cl_git_pass(git_submodule_lookup(&sm, g_repo, smpath));
+
+	git_submodule_set_ignore(sm, GIT_SUBMODULE_IGNORE_DIRTY);
+
+	cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+	check_diff_patches(diff, expected_moved);
+	git_diff_list_free(diff);
+
+	git_submodule_set_ignore(sm, GIT_SUBMODULE_IGNORE_ALL);
+
+	cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+	check_diff_patches(diff, expected_unchanged);
+	git_diff_list_free(diff);
+
+	git_submodule_set_ignore(sm, GIT_SUBMODULE_IGNORE_NONE);
+
+	cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+	check_diff_patches(diff, expected_moved_dirty);
+	git_diff_list_free(diff);
+
+	p_unlink("submod2/sm_changed_head/new_around_here");
+
+	cl_git_pass(git_diff_index_to_workdir(&diff, g_repo, NULL, &opts));
+	check_diff_patches(diff, expected_moved);
+	git_diff_list_free(diff);
+
+	git_index_free(smindex);
+	git_repository_free(smrepo);
+}