Initial commit

This commit is contained in:
jiapengyu
2026-07-27 13:37:48 +08:00
commit ecba71e2a5
39123 changed files with 5989154 additions and 0 deletions
+37
View File
@@ -0,0 +1,37 @@
#include "clar_libgit2.h"
void test_config_add__initialize(void)
{
cl_fixture_sandbox("config/config10");
}
void test_config_add__cleanup(void)
{
cl_fixture_cleanup("config10");
}
void test_config_add__to_existing_section(void)
{
git_config *cfg;
int32_t i;
cl_git_pass(git_config_open_ondisk(&cfg, "config10"));
cl_git_pass(git_config_set_int32(cfg, "empty.tmp", 5));
cl_git_pass(git_config_get_int32(&i, cfg, "empty.tmp"));
cl_assert(i == 5);
cl_git_pass(git_config_delete_entry(cfg, "empty.tmp"));
git_config_free(cfg);
}
void test_config_add__to_new_section(void)
{
git_config *cfg;
int32_t i;
cl_git_pass(git_config_open_ondisk(&cfg, "config10"));
cl_git_pass(git_config_set_int32(cfg, "section.tmp", 5));
cl_git_pass(git_config_get_int32(&i, cfg, "section.tmp"));
cl_assert(i == 5);
cl_git_pass(git_config_delete_entry(cfg, "section.tmp"));
git_config_free(cfg);
}
+24
View File
@@ -0,0 +1,24 @@
#include "clar_libgit2.h"
#include "git2/sys/config.h"
void test_config_backend__checks_version(void)
{
git_config *cfg;
git_config_backend backend = GIT_CONFIG_BACKEND_INIT;
const git_error *err;
backend.version = 1024;
cl_git_pass(git_config_new(&cfg));
cl_git_fail(git_config_add_backend(cfg, &backend, 0, NULL, false));
err = git_error_last();
cl_assert_equal_i(GIT_ERROR_INVALID, err->klass);
git_error_clear();
backend.version = 1024;
cl_git_fail(git_config_add_backend(cfg, &backend, 0, NULL, false));
err = git_error_last();
cl_assert_equal_i(GIT_ERROR_INVALID, err->klass);
git_config_free(cfg);
}
+148
View File
@@ -0,0 +1,148 @@
#include "clar_libgit2.h"
#include "buffer.h"
#include "futils.h"
#include "repository.h"
#ifdef GIT_WIN32
# define ROOT_PREFIX "C:"
#else
# define ROOT_PREFIX
#endif
static git_repository *_repo;
void test_config_conditionals__initialize(void)
{
_repo = cl_git_sandbox_init("empty_standard_repo");
}
void test_config_conditionals__cleanup(void)
{
cl_git_sandbox_cleanup();
}
static void assert_condition_includes(const char *keyword, const char *path, bool expected)
{
git_buf buf = GIT_BUF_INIT;
git_config *cfg;
cl_git_pass(git_buf_printf(&buf, "[includeIf \"%s:%s\"]\n", keyword, path));
cl_git_pass(git_buf_puts(&buf, "path = other\n"));
cl_git_mkfile("empty_standard_repo/.git/config", buf.ptr);
cl_git_mkfile("empty_standard_repo/.git/other", "[foo]\nbar=baz\n");
_repo = cl_git_sandbox_reopen();
cl_git_pass(git_repository_config(&cfg, _repo));
if (expected) {
git_buf_clear(&buf);
cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar"));
cl_assert_equal_s("baz", git_buf_cstr(&buf));
} else {
cl_git_fail_with(GIT_ENOTFOUND,
git_config_get_string_buf(&buf, cfg, "foo.bar"));
}
git_buf_dispose(&buf);
git_config_free(cfg);
}
static char *sandbox_path(git_buf *buf, const char *suffix)
{
char *path = p_realpath(clar_sandbox_path(), NULL);
cl_assert(path);
cl_git_pass(git_buf_attach(buf, path, 0));
cl_git_pass(git_buf_joinpath(buf, buf->ptr, suffix));
return buf->ptr;
}
void test_config_conditionals__gitdir(void)
{
git_buf path = GIT_BUF_INIT;
assert_condition_includes("gitdir", ROOT_PREFIX "/", true);
assert_condition_includes("gitdir", "empty_stand", false);
assert_condition_includes("gitdir", "empty_stand/", false);
assert_condition_includes("gitdir", "empty_stand/.git", false);
assert_condition_includes("gitdir", "empty_stand/.git/", false);
assert_condition_includes("gitdir", "empty_stand*/", true);
assert_condition_includes("gitdir", "empty_stand*/.git", true);
assert_condition_includes("gitdir", "empty_stand*/.git/", false);
assert_condition_includes("gitdir", "empty_standard_repo", false);
assert_condition_includes("gitdir", "empty_standard_repo/", true);
assert_condition_includes("gitdir", "empty_standard_repo/.git", true);
assert_condition_includes("gitdir", "empty_standard_repo/.git/", false);
assert_condition_includes("gitdir", "./", false);
assert_condition_includes("gitdir", ROOT_PREFIX "/nonexistent", false);
assert_condition_includes("gitdir", ROOT_PREFIX "/empty_standard_repo", false);
assert_condition_includes("gitdir", "~/empty_standard_repo", false);
assert_condition_includes("gitdir", sandbox_path(&path, "/"), true);
assert_condition_includes("gitdir", sandbox_path(&path, "/*"), false);
assert_condition_includes("gitdir", sandbox_path(&path, "/**"), true);
assert_condition_includes("gitdir", sandbox_path(&path, "empty_standard_repo"), false);
assert_condition_includes("gitdir", sandbox_path(&path, "empty_standard_repo/"), true);
assert_condition_includes("gitdir", sandbox_path(&path, "empty_standard_repo/"), true);
assert_condition_includes("gitdir", sandbox_path(&path, "Empty_Standard_Repo"), false);
assert_condition_includes("gitdir", sandbox_path(&path, "Empty_Standard_Repo/"), false);
git_buf_dispose(&path);
}
void test_config_conditionals__gitdir_i(void)
{
git_buf path = GIT_BUF_INIT;
assert_condition_includes("gitdir/i", sandbox_path(&path, "empty_standard_repo/"), true);
assert_condition_includes("gitdir/i", sandbox_path(&path, "EMPTY_STANDARD_REPO/"), true);
git_buf_dispose(&path);
}
void test_config_conditionals__invalid_conditional_fails(void)
{
assert_condition_includes("foobar", ".git", false);
}
static void set_head(git_repository *repo, const char *name)
{
cl_git_pass(git_repository_create_head(git_repository_path(repo), name));
}
void test_config_conditionals__onbranch(void)
{
assert_condition_includes("onbranch", "master", true);
assert_condition_includes("onbranch", "m*", true);
assert_condition_includes("onbranch", "*", true);
assert_condition_includes("onbranch", "master/", false);
assert_condition_includes("onbranch", "foo", false);
set_head(_repo, "foo");
assert_condition_includes("onbranch", "master", false);
assert_condition_includes("onbranch", "foo", true);
assert_condition_includes("onbranch", "f*o", true);
set_head(_repo, "dir/ref");
assert_condition_includes("onbranch", "dir/ref", true);
assert_condition_includes("onbranch", "dir/", true);
assert_condition_includes("onbranch", "dir/*", true);
assert_condition_includes("onbranch", "dir/**", true);
assert_condition_includes("onbranch", "**", true);
assert_condition_includes("onbranch", "dir", false);
assert_condition_includes("onbranch", "dir*", false);
set_head(_repo, "dir/subdir/ref");
assert_condition_includes("onbranch", "dir/subdir/", true);
assert_condition_includes("onbranch", "dir/subdir/*", true);
assert_condition_includes("onbranch", "dir/subdir/ref", true);
assert_condition_includes("onbranch", "dir/", true);
assert_condition_includes("onbranch", "dir/**", true);
assert_condition_includes("onbranch", "**", true);
assert_condition_includes("onbranch", "dir", false);
assert_condition_includes("onbranch", "dir*", false);
assert_condition_includes("onbranch", "dir/*", false);
}
+68
View File
@@ -0,0 +1,68 @@
#include "clar_libgit2.h"
#include "config_helpers.h"
#include "repository.h"
#include "buffer.h"
void assert_config_entry_existence(
git_repository *repo,
const char *name,
bool is_supposed_to_exist)
{
git_config *config;
git_config_entry *entry = NULL;
int result;
cl_git_pass(git_repository_config__weakptr(&config, repo));
result = git_config_get_entry(&entry, config, name);
git_config_entry_free(entry);
if (is_supposed_to_exist)
cl_git_pass(result);
else
cl_assert_equal_i(GIT_ENOTFOUND, result);
}
void assert_config_entry_value(
git_repository *repo,
const char *name,
const char *expected_value)
{
git_config *config;
git_buf buf = GIT_BUF_INIT;
cl_git_pass(git_repository_config__weakptr(&config, repo));
cl_git_pass(git_config_get_string_buf(&buf, config, name));
cl_assert_equal_s(expected_value, git_buf_cstr(&buf));
git_buf_dispose(&buf);
}
static int count_config_entries_cb(
const git_config_entry *entry,
void *payload)
{
int *how_many = (int *)payload;
GIT_UNUSED(entry);
(*how_many)++;
return 0;
}
int count_config_entries_match(git_repository *repo, const char *pattern)
{
git_config *config;
int how_many = 0;
cl_git_pass(git_repository_config(&config, repo));
cl_assert_equal_i(0, git_config_foreach_match(
config, pattern, count_config_entries_cb, &how_many));
git_config_free(config);
return how_many;
}
+13
View File
@@ -0,0 +1,13 @@
extern void assert_config_entry_existence(
git_repository *repo,
const char *name,
bool is_supposed_to_exist);
extern void assert_config_entry_value(
git_repository *repo,
const char *name,
const char *expected_value);
extern int count_config_entries_match(
git_repository *repo,
const char *pattern);
+73
View File
@@ -0,0 +1,73 @@
#include "clar_libgit2.h"
void test_config_configlevel__adding_the_same_level_twice_returns_EEXISTS(void)
{
int error;
git_config *cfg;
cl_git_pass(git_config_new(&cfg));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"),
GIT_CONFIG_LEVEL_LOCAL, NULL, 0));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"),
GIT_CONFIG_LEVEL_GLOBAL, NULL, 0));
error = git_config_add_file_ondisk(cfg, cl_fixture("config/config16"),
GIT_CONFIG_LEVEL_GLOBAL, NULL, 0);
cl_git_fail(error);
cl_assert_equal_i(GIT_EEXISTS, error);
git_config_free(cfg);
}
void test_config_configlevel__can_replace_a_config_file_at_an_existing_level(void)
{
git_config *cfg;
git_buf buf = {0};
cl_git_pass(git_config_new(&cfg));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config18"),
GIT_CONFIG_LEVEL_LOCAL, NULL, 1));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config19"),
GIT_CONFIG_LEVEL_LOCAL, NULL, 1));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.stringglobal"));
cl_assert_equal_s("don't find me!", buf.ptr);
git_buf_dispose(&buf);
git_config_free(cfg);
}
void test_config_configlevel__can_read_from_a_single_level_focused_file_after_parent_config_has_been_freed(void)
{
git_config *cfg;
git_config *single_level_cfg;
git_buf buf = {0};
cl_git_pass(git_config_new(&cfg));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config18"),
GIT_CONFIG_LEVEL_GLOBAL, NULL, 0));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config19"),
GIT_CONFIG_LEVEL_LOCAL, NULL, 0));
cl_git_pass(git_config_open_level(&single_level_cfg, cfg, GIT_CONFIG_LEVEL_LOCAL));
git_config_free(cfg);
cl_git_pass(git_config_get_string_buf(&buf, single_level_cfg, "core.stringglobal"));
cl_assert_equal_s("don't find me!", buf.ptr);
git_buf_dispose(&buf);
git_config_free(single_level_cfg);
}
void test_config_configlevel__fetching_a_level_from_an_empty_compound_config_returns_ENOTFOUND(void)
{
git_config *cfg;
git_config *local_cfg;
cl_git_pass(git_config_new(&cfg));
cl_assert_equal_i(GIT_ENOTFOUND, git_config_open_level(&local_cfg, cfg, GIT_CONFIG_LEVEL_LOCAL));
git_config_free(cfg);
}
+171
View File
@@ -0,0 +1,171 @@
#include "clar_libgit2.h"
#include "buffer.h"
#include "futils.h"
void test_config_global__initialize(void)
{
git_buf path = GIT_BUF_INIT;
cl_git_pass(git_futils_mkdir_r("home", 0777));
cl_git_pass(git_path_prettify(&path, "home", NULL));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, path.ptr));
cl_git_pass(git_futils_mkdir_r("xdg/git", 0777));
cl_git_pass(git_path_prettify(&path, "xdg/git", NULL));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_XDG, path.ptr));
cl_git_pass(git_futils_mkdir_r("etc", 0777));
cl_git_pass(git_path_prettify(&path, "etc", NULL));
cl_git_pass(git_libgit2_opts(
GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_SYSTEM, path.ptr));
git_buf_dispose(&path);
}
void test_config_global__cleanup(void)
{
cl_sandbox_set_search_path_defaults();
cl_git_pass(git_futils_rmdir_r("home", NULL, GIT_RMDIR_REMOVE_FILES));
cl_git_pass(git_futils_rmdir_r("xdg", NULL, GIT_RMDIR_REMOVE_FILES));
cl_git_pass(git_futils_rmdir_r("etc", NULL, GIT_RMDIR_REMOVE_FILES));
}
void test_config_global__open_global(void)
{
git_config *cfg, *global, *selected, *dummy;
int32_t value;
cl_git_mkfile("home/.gitconfig", "[global]\n test = 4567\n");
cl_git_pass(git_config_open_default(&cfg));
cl_git_pass(git_config_get_int32(&value, cfg, "global.test"));
cl_assert_equal_i(4567, value);
cl_git_pass(git_config_open_level(&global, cfg, GIT_CONFIG_LEVEL_GLOBAL));
cl_git_pass(git_config_get_int32(&value, global, "global.test"));
cl_assert_equal_i(4567, value);
cl_git_fail(git_config_open_level(&dummy, cfg, GIT_CONFIG_LEVEL_XDG));
cl_git_pass(git_config_open_global(&selected, cfg));
cl_git_pass(git_config_get_int32(&value, selected, "global.test"));
cl_assert_equal_i(4567, value);
git_config_free(selected);
git_config_free(global);
git_config_free(cfg);
}
void test_config_global__open_symlinked_global(void)
{
#ifndef GIT_WIN32
git_config *cfg;
int32_t value;
cl_git_mkfile("home/.gitconfig.linked", "[global]\n test = 4567\n");
cl_must_pass(symlink(".gitconfig.linked", "home/.gitconfig"));
cl_git_pass(git_config_open_default(&cfg));
cl_git_pass(git_config_get_int32(&value, cfg, "global.test"));
cl_assert_equal_i(4567, value);
git_config_free(cfg);
#endif
}
void test_config_global__lock_missing_global_config(void)
{
git_config *cfg;
git_config_entry *entry;
git_transaction *transaction;
p_unlink("home/.gitconfig"); /* No global config */
cl_git_pass(git_config_open_default(&cfg));
cl_git_pass(git_config_lock(&transaction, cfg));
cl_git_pass(git_config_set_string(cfg, "assertion.fail", "boom"));
cl_git_pass(git_transaction_commit(transaction));
git_transaction_free(transaction);
/* cfg is updated */
cl_git_pass(git_config_get_entry(&entry, cfg, "assertion.fail"));
cl_assert_equal_s("boom", entry->value);
git_config_entry_free(entry);
git_config_free(cfg);
/* We can reread the new value from the global config */
cl_git_pass(git_config_open_default(&cfg));
cl_git_pass(git_config_get_entry(&entry, cfg, "assertion.fail"));
cl_assert_equal_s("boom", entry->value);
git_config_entry_free(entry);
git_config_free(cfg);
}
void test_config_global__open_xdg(void)
{
git_config *cfg, *xdg, *selected;
const char *str = "teststring";
const char *key = "this.variable";
git_buf buf = {0};
cl_git_mkfile("xdg/git/config", "# XDG config\n[core]\n test = 1\n");
cl_git_pass(git_config_open_default(&cfg));
cl_git_pass(git_config_open_level(&xdg, cfg, GIT_CONFIG_LEVEL_XDG));
cl_git_pass(git_config_open_global(&selected, cfg));
cl_git_pass(git_config_set_string(xdg, key, str));
cl_git_pass(git_config_get_string_buf(&buf, selected, key));
cl_assert_equal_s(str, buf.ptr);
git_buf_dispose(&buf);
git_config_free(selected);
git_config_free(xdg);
git_config_free(cfg);
}
void test_config_global__open_programdata(void)
{
git_config *cfg;
git_repository *repo;
git_buf config_path = GIT_BUF_INIT;
git_buf var_contents = GIT_BUF_INIT;
if (cl_is_env_set("GITTEST_INVASIVE_FS_STRUCTURE"))
cl_skip();
cl_git_pass(git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH,
GIT_CONFIG_LEVEL_PROGRAMDATA, &config_path));
if (!git_path_isdir(config_path.ptr))
cl_git_pass(p_mkdir(config_path.ptr, 0777));
cl_git_pass(git_buf_puts(&config_path, "/config"));
cl_git_pass(git_config_open_ondisk(&cfg, config_path.ptr));
cl_git_pass(git_config_set_string(cfg, "programdata.var", "even higher level"));
git_buf_dispose(&config_path);
git_config_free(cfg);
git_config_open_default(&cfg);
cl_git_pass(git_config_get_string_buf(&var_contents, cfg, "programdata.var"));
cl_assert_equal_s("even higher level", var_contents.ptr);
git_config_free(cfg);
git_buf_dispose(&var_contents);
cl_git_pass(git_repository_init(&repo, "./foo.git", true));
cl_git_pass(git_repository_config(&cfg, repo));
cl_git_pass(git_config_get_string_buf(&var_contents, cfg, "programdata.var"));
cl_assert_equal_s("even higher level", var_contents.ptr);
git_config_free(cfg);
git_buf_dispose(&var_contents);
git_repository_free(repo);
cl_fixture_cleanup("./foo.git");
}
+234
View File
@@ -0,0 +1,234 @@
#include "clar_libgit2.h"
#include "buffer.h"
#include "futils.h"
static git_config *cfg;
static git_buf buf;
void test_config_include__initialize(void)
{
cfg = NULL;
git_buf_init(&buf, 0);
}
void test_config_include__cleanup(void)
{
git_config_free(cfg);
git_buf_dispose(&buf);
}
void test_config_include__relative(void)
{
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config-include")));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar.baz"));
cl_assert_equal_s("huzzah", git_buf_cstr(&buf));
}
void test_config_include__absolute(void)
{
cl_git_pass(git_buf_printf(&buf, "[include]\npath = %s/config-included", cl_fixture("config")));
cl_git_mkfile("config-include-absolute", git_buf_cstr(&buf));
git_buf_dispose(&buf);
cl_git_pass(git_config_open_ondisk(&cfg, "config-include-absolute"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar.baz"));
cl_assert_equal_s("huzzah", git_buf_cstr(&buf));
cl_git_pass(p_unlink("config-include-absolute"));
}
void test_config_include__homedir(void)
{
cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, cl_fixture("config")));
cl_git_mkfile("config-include-homedir", "[include]\npath = ~/config-included");
cl_git_pass(git_config_open_ondisk(&cfg, "config-include-homedir"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar.baz"));
cl_assert_equal_s("huzzah", git_buf_cstr(&buf));
cl_sandbox_set_search_path_defaults();
cl_git_pass(p_unlink("config-include-homedir"));
}
/* We need to pretend that the variables were defined where the file was included */
void test_config_include__ordering(void)
{
cl_git_mkfile("included", "[foo \"bar\"]\nbaz = hurrah\nfrotz = hiya");
cl_git_mkfile("including",
"[foo \"bar\"]\nfrotz = hello\n"
"[include]\npath = included\n"
"[foo \"bar\"]\nbaz = huzzah\n");
cl_git_pass(git_config_open_ondisk(&cfg, "including"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar.frotz"));
cl_assert_equal_s("hiya", git_buf_cstr(&buf));
git_buf_clear(&buf);
cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar.baz"));
cl_assert_equal_s("huzzah", git_buf_cstr(&buf));
cl_git_pass(p_unlink("included"));
cl_git_pass(p_unlink("including"));
}
/* We need to pretend that the variables were defined where the file was included */
void test_config_include__depth(void)
{
cl_git_mkfile("a", "[include]\npath = b");
cl_git_mkfile("b", "[include]\npath = a");
cl_git_fail(git_config_open_ondisk(&cfg, "a"));
cl_git_pass(p_unlink("a"));
cl_git_pass(p_unlink("b"));
}
void test_config_include__empty_path_sanely_handled(void)
{
cl_git_mkfile("a", "[include]\npath");
cl_git_pass(git_config_open_ondisk(&cfg, "a"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "include.path"));
cl_assert_equal_s("", git_buf_cstr(&buf));
cl_git_pass(p_unlink("a"));
}
void test_config_include__missing(void)
{
cl_git_mkfile("including", "[include]\npath = nonexistentfile\n[foo]\nbar = baz");
git_error_clear();
cl_git_pass(git_config_open_ondisk(&cfg, "including"));
cl_assert(git_error_last() == NULL);
cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar"));
cl_assert_equal_s("baz", git_buf_cstr(&buf));
cl_git_pass(p_unlink("including"));
}
void test_config_include__missing_homedir(void)
{
cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, cl_fixture("config")));
cl_git_mkfile("including", "[include]\npath = ~/.nonexistentfile\n[foo]\nbar = baz");
git_error_clear();
cl_git_pass(git_config_open_ondisk(&cfg, "including"));
cl_assert(git_error_last() == NULL);
cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar"));
cl_assert_equal_s("baz", git_buf_cstr(&buf));
cl_sandbox_set_search_path_defaults();
cl_git_pass(p_unlink("including"));
}
#define replicate10(s) s s s s s s s s s s
void test_config_include__depth2(void)
{
const char *content = "[include]\n" replicate10(replicate10("path=bottom\n"));
cl_git_mkfile("top-level", "[include]\npath = middle\n[foo]\nbar = baz");
cl_git_mkfile("middle", content);
cl_git_mkfile("bottom", "[foo]\nbar2 = baz2");
cl_git_pass(git_config_open_ondisk(&cfg, "top-level"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar"));
cl_assert_equal_s("baz", git_buf_cstr(&buf));
git_buf_clear(&buf);
cl_git_pass(git_config_get_string_buf(&buf, cfg, "foo.bar2"));
cl_assert_equal_s("baz2", git_buf_cstr(&buf));
cl_git_pass(p_unlink("top-level"));
cl_git_pass(p_unlink("middle"));
cl_git_pass(p_unlink("bottom"));
}
void test_config_include__removing_include_removes_values(void)
{
cl_git_mkfile("top-level", "[include]\npath = included");
cl_git_mkfile("included", "[foo]\nbar = value");
cl_git_pass(git_config_open_ondisk(&cfg, "top-level"));
cl_git_mkfile("top-level", "");
cl_git_fail(git_config_get_string_buf(&buf, cfg, "foo.bar"));
cl_git_pass(p_unlink("top-level"));
cl_git_pass(p_unlink("included"));
}
void test_config_include__rewriting_include_refreshes_values(void)
{
cl_git_mkfile("top-level", "[include]\npath = first\n[include]\npath = second");
cl_git_mkfile("first", "[first]\nfoo = bar");
cl_git_mkfile("second", "[second]\nfoo = bar");
cl_git_pass(git_config_open_ondisk(&cfg, "top-level"));
cl_git_mkfile("first", "[first]\nother = value");
cl_git_fail(git_config_get_string_buf(&buf, cfg, "foo.bar"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "first.other"));
cl_assert_equal_s(buf.ptr, "value");
cl_git_pass(p_unlink("top-level"));
cl_git_pass(p_unlink("first"));
cl_git_pass(p_unlink("second"));
}
void test_config_include__included_variables_cannot_be_deleted(void)
{
cl_git_mkfile("top-level", "[include]\npath = included\n");
cl_git_mkfile("included", "[foo]\nbar = value");
cl_git_pass(git_config_open_ondisk(&cfg, "top-level"));
cl_git_fail(git_config_delete_entry(cfg, "foo.bar"));
cl_git_pass(p_unlink("top-level"));
cl_git_pass(p_unlink("included"));
}
void test_config_include__included_variables_cannot_be_modified(void)
{
cl_git_mkfile("top-level", "[include]\npath = included\n");
cl_git_mkfile("included", "[foo]\nbar = value");
cl_git_pass(git_config_open_ondisk(&cfg, "top-level"));
cl_git_fail(git_config_set_string(cfg, "foo.bar", "other-value"));
cl_git_pass(p_unlink("top-level"));
cl_git_pass(p_unlink("included"));
}
void test_config_include__variables_in_included_override_including(void)
{
int i;
cl_git_mkfile("top-level", "[foo]\nbar = 1\n[include]\npath = included");
cl_git_mkfile("included", "[foo]\nbar = 2");
cl_git_pass(git_config_open_ondisk(&cfg, "top-level"));
cl_git_pass(git_config_get_int32(&i, cfg, "foo.bar"));
cl_assert_equal_i(i, 2);
cl_git_pass(p_unlink("top-level"));
cl_git_pass(p_unlink("included"));
}
void test_config_include__variables_in_including_override_included(void)
{
int i;
cl_git_mkfile("top-level", "[include]\npath = included\n[foo]\nbar = 1");
cl_git_mkfile("included", "[foo]\nbar = 2");
cl_git_pass(git_config_open_ondisk(&cfg, "top-level"));
cl_git_pass(git_config_get_int32(&i, cfg, "foo.bar"));
cl_assert_equal_i(i, 1);
cl_git_pass(p_unlink("top-level"));
cl_git_pass(p_unlink("included"));
}
+139
View File
@@ -0,0 +1,139 @@
#include "clar_libgit2.h"
#include "config_backend.h"
static git_config_backend *backend;
void test_config_memory__initialize(void)
{
backend = NULL;
}
void test_config_memory__cleanup(void)
{
git_config_backend_free(backend);
}
static void assert_config_contains(git_config_backend *backend,
const char *name, const char *value)
{
git_config_entry *entry;
cl_git_pass(git_config_backend_get_string(&entry, backend, name));
cl_assert_equal_s(entry->value, value);
}
struct expected_entry {
const char *name;
const char *value;
int seen;
};
static int contains_all_cb(const git_config_entry *entry, void *payload)
{
struct expected_entry *entries = (struct expected_entry *) payload;
int i;
for (i = 0; entries[i].name; i++) {
if (strcmp(entries[i].name, entry->name) ||
strcmp(entries[i].value , entry->value))
continue;
if (entries[i].seen)
cl_fail("Entry seen more than once");
entries[i].seen = 1;
return 0;
}
cl_fail("Unexpected entry");
return -1;
}
static void assert_config_contains_all(git_config_backend *backend,
struct expected_entry *entries)
{
int i;
cl_git_pass(git_config_backend_foreach(backend, contains_all_cb, entries));
for (i = 0; entries[i].name; i++)
cl_assert(entries[i].seen);
}
static void setup_backend(const char *cfg)
{
cl_git_pass(git_config_backend_from_string(&backend, cfg, strlen(cfg)));
cl_git_pass(git_config_backend_open(backend, 0, NULL));
}
void test_config_memory__write_operations_fail(void)
{
setup_backend("");
cl_git_fail(git_config_backend_set_string(backend, "general.foo", "var"));
cl_git_fail(git_config_backend_delete(backend, "general.foo"));
cl_git_fail(git_config_backend_lock(backend));
cl_git_fail(git_config_backend_unlock(backend, 0));
}
void test_config_memory__simple(void)
{
setup_backend(
"[general]\n"
"foo=bar\n");
assert_config_contains(backend, "general.foo", "bar");
}
void test_config_memory__malformed_fails_to_open(void)
{
const char *cfg =
"[general\n"
"foo=bar\n";
cl_git_pass(git_config_backend_from_string(&backend, cfg, strlen(cfg)));
cl_git_fail(git_config_backend_open(backend, 0, NULL));
}
void test_config_memory__multiple_vars(void)
{
setup_backend(
"[general]\n"
"foo=bar\n"
"key=value\n");
assert_config_contains(backend, "general.foo", "bar");
assert_config_contains(backend, "general.key", "value");
}
void test_config_memory__multiple_sections(void)
{
setup_backend(
"[general]\n"
"foo=bar\n"
"\n"
"[other]\n"
"key=value\n");
assert_config_contains(backend, "general.foo", "bar");
assert_config_contains(backend, "other.key", "value");
}
void test_config_memory__multivar_gets_correct_string(void)
{
setup_backend(
"[general]\n"
"foo=bar1\n"
"foo=bar2\n");
assert_config_contains(backend, "general.foo", "bar2");
}
void test_config_memory__foreach_sees_multivar(void)
{
struct expected_entry entries[] = {
{ "general.foo", "bar1", 0 },
{ "general.foo", "bar2", 0 },
{ NULL, NULL, 0 },
};
setup_backend(
"[general]\n"
"foo=bar1\n"
"foo=bar2\n");
assert_config_contains_all(backend, entries);
}
+288
View File
@@ -0,0 +1,288 @@
#include "clar_libgit2.h"
static const char *_name = "remote.ab.url";
void test_config_multivar__initialize(void)
{
cl_fixture_sandbox("config");
}
void test_config_multivar__cleanup(void)
{
cl_fixture_cleanup("config");
}
static int mv_read_cb(const git_config_entry *entry, void *data)
{
int *n = (int *) data;
if (!strcmp(entry->name, _name))
(*n)++;
return 0;
}
void test_config_multivar__foreach(void)
{
git_config *cfg;
int n = 0;
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config11")));
cl_git_pass(git_config_foreach(cfg, mv_read_cb, &n));
cl_assert(n == 2);
git_config_free(cfg);
}
static int cb(const git_config_entry *entry, void *data)
{
int *n = (int *) data;
GIT_UNUSED(entry);
(*n)++;
return 0;
}
static void check_get_multivar_foreach(
git_config *cfg, int expected, int expected_patterned)
{
int n = 0;
if (expected > 0) {
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
cl_assert_equal_i(expected, n);
} else {
cl_assert_equal_i(GIT_ENOTFOUND,
git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
}
n = 0;
if (expected_patterned > 0) {
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, "example", cb, &n));
cl_assert_equal_i(expected_patterned, n);
} else {
cl_assert_equal_i(GIT_ENOTFOUND,
git_config_get_multivar_foreach(cfg, _name, "example", cb, &n));
}
}
static void check_get_multivar(git_config *cfg, int expected)
{
git_config_iterator *iter;
git_config_entry *entry;
int n = 0;
cl_git_pass(git_config_multivar_iterator_new(&iter, cfg, _name, NULL));
while (git_config_next(&entry, iter) == 0)
n++;
cl_assert_equal_i(expected, n);
git_config_iterator_free(iter);
}
void test_config_multivar__get(void)
{
git_config *cfg;
cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
check_get_multivar_foreach(cfg, 2, 1);
/* add another that has the _name entry */
cl_git_pass(git_config_add_file_ondisk(cfg, "config/config9", GIT_CONFIG_LEVEL_SYSTEM, NULL, 1));
check_get_multivar_foreach(cfg, 3, 2);
/* add another that does not have the _name entry */
cl_git_pass(git_config_add_file_ondisk(cfg, "config/config0", GIT_CONFIG_LEVEL_GLOBAL, NULL, 1));
check_get_multivar_foreach(cfg, 3, 2);
/* add another that does not have the _name entry at the end */
cl_git_pass(git_config_add_file_ondisk(cfg, "config/config1", GIT_CONFIG_LEVEL_APP, NULL, 1));
check_get_multivar_foreach(cfg, 3, 2);
/* drop original file */
cl_git_pass(git_config_add_file_ondisk(cfg, "config/config2", GIT_CONFIG_LEVEL_LOCAL, NULL, 1));
check_get_multivar_foreach(cfg, 1, 1);
/* drop other file with match */
cl_git_pass(git_config_add_file_ondisk(cfg, "config/config3", GIT_CONFIG_LEVEL_SYSTEM, NULL, 1));
check_get_multivar_foreach(cfg, 0, 0);
/* reload original file (add different place in order) */
cl_git_pass(git_config_add_file_ondisk(cfg, "config/config11", GIT_CONFIG_LEVEL_SYSTEM, NULL, 1));
check_get_multivar_foreach(cfg, 2, 1);
check_get_multivar(cfg, 2);
git_config_free(cfg);
}
void test_config_multivar__add(void)
{
git_config *cfg;
int n;
cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
cl_git_pass(git_config_set_multivar(cfg, _name, "nonexistant", "git://git.otherplace.org/libgit2"));
n = 0;
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
cl_assert_equal_i(n, 3);
n = 0;
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, "otherplace", cb, &n));
cl_assert_equal_i(n, 1);
git_config_free(cfg);
/* We know it works in memory, let's see if the file is written correctly */
cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
n = 0;
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
cl_assert_equal_i(n, 3);
n = 0;
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, "otherplace", cb, &n));
cl_assert_equal_i(n, 1);
git_config_free(cfg);
}
void test_config_multivar__add_new(void)
{
const char *var = "a.brand.new";
git_config *cfg;
int n;
cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
cl_git_pass(git_config_set_multivar(cfg, var, "$^", "variable"));
n = 0;
cl_git_pass(git_config_get_multivar_foreach(cfg, var, NULL, cb, &n));
cl_assert_equal_i(n, 1);
git_config_free(cfg);
}
void test_config_multivar__replace(void)
{
git_config *cfg;
int n;
cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
n = 0;
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
cl_assert(n == 2);
cl_git_pass(git_config_set_multivar(cfg, _name, "github", "git://git.otherplace.org/libgit2"));
n = 0;
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
cl_assert(n == 2);
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
n = 0;
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
cl_assert(n == 2);
git_config_free(cfg);
}
void test_config_multivar__replace_multiple(void)
{
git_config *cfg;
int n;
cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
cl_git_pass(git_config_set_multivar(cfg, _name, "git://", "git://git.otherplace.org/libgit2"));
n = 0;
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, "otherplace", cb, &n));
cl_assert_equal_i(n, 2);
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
n = 0;
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, "otherplace", cb, &n));
cl_assert_equal_i(n, 2);
git_config_free(cfg);
}
void test_config_multivar__delete(void)
{
git_config *cfg;
int n;
cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
n = 0;
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
cl_assert_equal_i(2, n);
cl_git_pass(git_config_delete_multivar(cfg, _name, "github"));
n = 0;
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
cl_assert_equal_i(1, n);
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
n = 0;
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
cl_assert_equal_i(1, n);
git_config_free(cfg);
}
void test_config_multivar__delete_multiple(void)
{
git_config *cfg;
int n;
cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
n = 0;
cl_git_pass(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n));
cl_assert(n == 2);
cl_git_pass(git_config_delete_multivar(cfg, _name, "git"));
n = 0;
cl_git_fail_with(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n), GIT_ENOTFOUND);
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
n = 0;
cl_git_fail_with(git_config_get_multivar_foreach(cfg, _name, NULL, cb, &n), GIT_ENOTFOUND);
git_config_free(cfg);
}
void test_config_multivar__delete_notfound(void)
{
git_config *cfg;
cl_git_pass(git_config_open_ondisk(&cfg, "config/config11"));
cl_git_fail_with(git_config_delete_multivar(cfg, "remote.ab.noturl", "git"), GIT_ENOTFOUND);
git_config_free(cfg);
}
+34
View File
@@ -0,0 +1,34 @@
#include "clar_libgit2.h"
#include "filebuf.h"
#include "futils.h"
#include "posix.h"
#define TEST_CONFIG "git-new-config"
void test_config_new__write_new_config(void)
{
git_config *config;
git_buf buf = GIT_BUF_INIT;
cl_git_mkfile(TEST_CONFIG, "");
cl_git_pass(git_config_open_ondisk(&config, TEST_CONFIG));
cl_git_pass(git_config_set_string(config, "color.ui", "auto"));
cl_git_pass(git_config_set_string(config, "core.editor", "ed"));
git_config_free(config);
cl_git_pass(git_config_open_ondisk(&config, TEST_CONFIG));
cl_git_pass(git_config_get_string_buf(&buf, config, "color.ui"));
cl_assert_equal_s("auto", git_buf_cstr(&buf));
git_buf_clear(&buf);
cl_git_pass(git_config_get_string_buf(&buf, config, "core.editor"));
cl_assert_equal_s("ed", git_buf_cstr(&buf));
git_buf_dispose(&buf);
git_config_free(config);
p_unlink(TEST_CONFIG);
}
+913
View File
@@ -0,0 +1,913 @@
#include "clar_libgit2.h"
#include "buffer.h"
#include "path.h"
static git_buf buf = GIT_BUF_INIT;
void test_config_read__cleanup(void)
{
git_buf_dispose(&buf);
}
void test_config_read__simple_read(void)
{
git_config *cfg;
int32_t i;
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config0")));
cl_git_pass(git_config_get_int32(&i, cfg, "core.repositoryformatversion"));
cl_assert(i == 0);
cl_git_pass(git_config_get_bool(&i, cfg, "core.filemode"));
cl_assert(i == 1);
cl_git_pass(git_config_get_bool(&i, cfg, "core.bare"));
cl_assert(i == 0);
cl_git_pass(git_config_get_bool(&i, cfg, "core.logallrefupdates"));
cl_assert(i == 1);
git_config_free(cfg);
}
void test_config_read__case_sensitive(void)
{
git_config *cfg;
int i;
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config1")));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "this.that.other"));
cl_assert_equal_s("true", git_buf_cstr(&buf));
git_buf_clear(&buf);
cl_git_pass(git_config_get_string_buf(&buf, cfg, "this.That.other"));
cl_assert_equal_s("yes", git_buf_cstr(&buf));
cl_git_pass(git_config_get_bool(&i, cfg, "this.that.other"));
cl_assert(i == 1);
cl_git_pass(git_config_get_bool(&i, cfg, "this.That.other"));
cl_assert(i == 1);
/* This one doesn't exist */
cl_must_fail(git_config_get_bool(&i, cfg, "this.thaT.other"));
git_config_free(cfg);
}
/*
* If \ is the last non-space character on the line, we read the next
* one, separating each line with SP.
*/
void test_config_read__multiline_value(void)
{
git_config *cfg;
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config2")));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "this.That.and"));
cl_assert_equal_s("one one one two two three three", git_buf_cstr(&buf));
git_config_free(cfg);
}
static void clean_test_config(void *unused)
{
GIT_UNUSED(unused);
cl_fixture_cleanup("./testconfig");
}
void test_config_read__multiline_value_and_eof(void)
{
git_config *cfg;
cl_set_cleanup(&clean_test_config, NULL);
cl_git_mkfile("./testconfig", "[header]\n key1 = foo\\\n");
cl_git_pass(git_config_open_ondisk(&cfg, "./testconfig"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "header.key1"));
cl_assert_equal_s("foo", git_buf_cstr(&buf));
git_config_free(cfg);
}
void test_config_read__multiline_eof(void)
{
git_config *cfg;
cl_set_cleanup(&clean_test_config, NULL);
cl_git_mkfile("./testconfig", "[header]\n key1 = \\\n");
cl_git_pass(git_config_open_ondisk(&cfg, "./testconfig"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "header.key1"));
cl_assert_equal_s("", git_buf_cstr(&buf));
git_config_free(cfg);
}
/*
* This kind of subsection declaration is case-insensitive
*/
void test_config_read__subsection_header(void)
{
git_config *cfg;
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config3")));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "section.subsection.var"));
cl_assert_equal_s("hello", git_buf_cstr(&buf));
/* The subsection is transformed to lower-case */
cl_must_fail(git_config_get_string_buf(&buf, cfg, "section.subSectIon.var"));
git_config_free(cfg);
}
void test_config_read__lone_variable(void)
{
git_config *cfg;
int i;
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config4")));
cl_git_fail(git_config_get_int32(&i, cfg, "some.section.variable"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "some.section.variable"));
cl_assert_equal_s("", git_buf_cstr(&buf));
git_buf_clear(&buf);
cl_git_pass(git_config_get_bool(&i, cfg, "some.section.variable"));
cl_assert(i == 1);
cl_git_pass(git_config_get_string_buf(&buf, cfg, "some.section.variableeq"));
cl_assert_equal_s("", git_buf_cstr(&buf));
cl_git_pass(git_config_get_bool(&i, cfg, "some.section.variableeq"));
cl_assert(i == 0);
git_config_free(cfg);
}
void test_config_read__number_suffixes(void)
{
git_config *cfg;
int64_t i;
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config5")));
cl_git_pass(git_config_get_int64(&i, cfg, "number.simple"));
cl_assert(i == 1);
cl_git_pass(git_config_get_int64(&i, cfg, "number.k"));
cl_assert(i == 1 * 1024);
cl_git_pass(git_config_get_int64(&i, cfg, "number.kk"));
cl_assert(i == 1 * 1024);
cl_git_pass(git_config_get_int64(&i, cfg, "number.m"));
cl_assert(i == 1 * 1024 * 1024);
cl_git_pass(git_config_get_int64(&i, cfg, "number.mm"));
cl_assert(i == 1 * 1024 * 1024);
cl_git_pass(git_config_get_int64(&i, cfg, "number.g"));
cl_assert(i == 1 * 1024 * 1024 * 1024);
cl_git_pass(git_config_get_int64(&i, cfg, "number.gg"));
cl_assert(i == 1 * 1024 * 1024 * 1024);
git_config_free(cfg);
}
void test_config_read__blank_lines(void)
{
git_config *cfg;
int i;
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config6")));
cl_git_pass(git_config_get_bool(&i, cfg, "valid.subsection.something"));
cl_assert(i == 1);
cl_git_pass(git_config_get_bool(&i, cfg, "something.else.something"));
cl_assert(i == 0);
git_config_free(cfg);
}
void test_config_read__invalid_ext_headers(void)
{
git_config *cfg;
cl_must_fail(git_config_open_ondisk(&cfg, cl_fixture("config/config7")));
}
void test_config_read__empty_files(void)
{
git_config *cfg;
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config8")));
git_config_free(cfg);
}
void test_config_read__symbol_headers(void)
{
git_config *cfg;
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config20")));
git_config_free(cfg);
}
void test_config_read__header_in_last_line(void)
{
git_config *cfg;
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config10")));
git_config_free(cfg);
}
void test_config_read__prefixes(void)
{
git_config *cfg;
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config9")));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "remote.ab.url"));
cl_assert_equal_s("http://example.com/git/ab", git_buf_cstr(&buf));
git_buf_clear(&buf);
cl_git_pass(git_config_get_string_buf(&buf, cfg, "remote.abba.url"));
cl_assert_equal_s("http://example.com/git/abba", git_buf_cstr(&buf));
git_config_free(cfg);
}
void test_config_read__escaping_quotes(void)
{
git_config *cfg;
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config13")));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.editor"));
cl_assert_equal_s("\"C:/Program Files/Nonsense/bah.exe\" \"--some option\"", git_buf_cstr(&buf));
git_config_free(cfg);
}
void test_config_read__invalid_escape_sequence(void)
{
git_config *cfg;
cl_set_cleanup(&clean_test_config, NULL);
cl_git_mkfile("./testconfig", "[header]\n key1 = \\\\\\;\n key2 = value2\n");
cl_git_fail(git_config_open_ondisk(&cfg, "./testconfig"));
git_config_free(cfg);
}
static int count_cfg_entries_and_compare_levels(
const git_config_entry *entry, void *payload)
{
int *count = payload;
if (!strcmp(entry->value, "7") || !strcmp(entry->value, "17"))
cl_assert(entry->level == GIT_CONFIG_LEVEL_GLOBAL);
else
cl_assert(entry->level == GIT_CONFIG_LEVEL_SYSTEM);
(*count)++;
return 0;
}
static int cfg_callback_countdown(const git_config_entry *entry, void *payload)
{
int *count = payload;
GIT_UNUSED(entry);
(*count)--;
if (*count == 0)
return -100;
return 0;
}
void test_config_read__foreach(void)
{
git_config *cfg;
int count, ret;
cl_git_pass(git_config_new(&cfg));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"),
GIT_CONFIG_LEVEL_SYSTEM, NULL, 0));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"),
GIT_CONFIG_LEVEL_GLOBAL, NULL, 0));
count = 0;
cl_git_pass(git_config_foreach(cfg, count_cfg_entries_and_compare_levels, &count));
cl_assert_equal_i(7, count);
count = 3;
cl_git_fail(ret = git_config_foreach(cfg, cfg_callback_countdown, &count));
cl_assert_equal_i(-100, ret);
git_config_free(cfg);
}
void test_config_read__iterator(void)
{
const char *keys[] = {
"core.dummy2",
"core.verylong",
"core.dummy",
"remote.ab.url",
"remote.abba.url",
"core.dummy2",
"core.global"
};
git_config *cfg;
git_config_iterator *iter;
git_config_entry *entry;
int count, ret;
cl_git_pass(git_config_new(&cfg));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"),
GIT_CONFIG_LEVEL_SYSTEM, NULL, 0));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"),
GIT_CONFIG_LEVEL_GLOBAL, NULL, 0));
count = 0;
cl_git_pass(git_config_iterator_new(&iter, cfg));
while ((ret = git_config_next(&entry, iter)) == 0) {
cl_assert_equal_s(entry->name, keys[count]);
count++;
}
git_config_iterator_free(iter);
cl_assert_equal_i(GIT_ITEROVER, ret);
cl_assert_equal_i(7, count);
count = 3;
cl_git_pass(git_config_iterator_new(&iter, cfg));
git_config_iterator_free(iter);
git_config_free(cfg);
}
static int count_cfg_entries(const git_config_entry *entry, void *payload)
{
int *count = payload;
GIT_UNUSED(entry);
(*count)++;
return 0;
}
void test_config_read__foreach_match(void)
{
git_config *cfg;
int count;
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config9")));
count = 0;
cl_git_pass(
git_config_foreach_match(cfg, "core.*", count_cfg_entries, &count));
cl_assert_equal_i(3, count);
count = 0;
cl_git_pass(
git_config_foreach_match(cfg, "remote\\.ab.*", count_cfg_entries, &count));
cl_assert_equal_i(2, count);
count = 0;
cl_git_pass(
git_config_foreach_match(cfg, ".*url$", count_cfg_entries, &count));
cl_assert_equal_i(2, count);
count = 0;
cl_git_pass(
git_config_foreach_match(cfg, ".*dummy.*", count_cfg_entries, &count));
cl_assert_equal_i(2, count);
count = 0;
cl_git_pass(
git_config_foreach_match(cfg, ".*nomatch.*", count_cfg_entries, &count));
cl_assert_equal_i(0, count);
git_config_free(cfg);
}
static void check_glob_iter(git_config *cfg, const char *regexp, int expected)
{
git_config_iterator *iter;
git_config_entry *entry;
int count, error;
cl_git_pass(git_config_iterator_glob_new(&iter, cfg, regexp));
count = 0;
while ((error = git_config_next(&entry, iter)) == 0)
count++;
cl_assert_equal_i(GIT_ITEROVER, error);
cl_assert_equal_i(expected, count);
git_config_iterator_free(iter);
}
void test_config_read__iterator_invalid_glob(void)
{
git_config *cfg;
git_config_iterator *iter;
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config9")));
cl_git_fail(git_config_iterator_glob_new(&iter, cfg, "*"));
git_config_free(cfg);
}
void test_config_read__iterator_glob(void)
{
git_config *cfg;
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config9")));
check_glob_iter(cfg, "core.*", 3);
check_glob_iter(cfg, "remote\\.ab.*", 2);
check_glob_iter(cfg, ".*url$", 2);
check_glob_iter(cfg, ".*dummy.*", 2);
check_glob_iter(cfg, ".*nomatch.*", 0);
git_config_free(cfg);
}
void test_config_read__whitespace_not_required_around_assignment(void)
{
git_config *cfg;
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config14")));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "a.b"));
cl_assert_equal_s("c", git_buf_cstr(&buf));
git_buf_clear(&buf);
cl_git_pass(git_config_get_string_buf(&buf, cfg, "d.e"));
cl_assert_equal_s("f", git_buf_cstr(&buf));
git_config_free(cfg);
}
void test_config_read__read_git_config_entry(void)
{
git_config *cfg;
git_config_entry *entry;
cl_git_pass(git_config_new(&cfg));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"),
GIT_CONFIG_LEVEL_SYSTEM, NULL, 0));
cl_git_pass(git_config_get_entry(&entry, cfg, "core.dummy2"));
cl_assert_equal_s("core.dummy2", entry->name);
cl_assert_equal_s("42", entry->value);
cl_assert_equal_i(GIT_CONFIG_LEVEL_SYSTEM, entry->level);
git_config_entry_free(entry);
git_config_free(cfg);
}
/*
* At the beginning of the test:
* - config9 has: core.dummy2=42
* - config15 has: core.dummy2=7
* - config16 has: core.dummy2=28
*/
void test_config_read__local_config_overrides_global_config_overrides_system_config(void)
{
git_config *cfg;
int32_t i;
cl_git_pass(git_config_new(&cfg));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"),
GIT_CONFIG_LEVEL_SYSTEM, NULL, 0));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"),
GIT_CONFIG_LEVEL_GLOBAL, NULL, 0));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config16"),
GIT_CONFIG_LEVEL_LOCAL, NULL, 0));
cl_git_pass(git_config_get_int32(&i, cfg, "core.dummy2"));
cl_assert_equal_i(28, i);
git_config_free(cfg);
cl_git_pass(git_config_new(&cfg));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"),
GIT_CONFIG_LEVEL_SYSTEM, NULL, 0));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"),
GIT_CONFIG_LEVEL_GLOBAL, NULL, 0));
cl_git_pass(git_config_get_int32(&i, cfg, "core.dummy2"));
cl_assert_equal_i(7, i);
git_config_free(cfg);
}
/*
* At the beginning of the test:
* - config9 has: core.global does not exist
* - config15 has: core.global=17
* - config16 has: core.global=29
*
* And also:
* - config9 has: core.system does not exist
* - config15 has: core.system does not exist
* - config16 has: core.system=11
*/
void test_config_read__fallback_from_local_to_global_and_from_global_to_system(void)
{
git_config *cfg;
int32_t i;
cl_git_pass(git_config_new(&cfg));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config9"),
GIT_CONFIG_LEVEL_SYSTEM, NULL, 0));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config15"),
GIT_CONFIG_LEVEL_GLOBAL, NULL, 0));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config16"),
GIT_CONFIG_LEVEL_LOCAL, NULL, 0));
cl_git_pass(git_config_get_int32(&i, cfg, "core.global"));
cl_assert_equal_i(17, i);
cl_git_pass(git_config_get_int32(&i, cfg, "core.system"));
cl_assert_equal_i(11, i);
git_config_free(cfg);
}
void test_config_read__parent_dir_is_file(void)
{
git_config *cfg;
int count;
cl_git_pass(git_config_new(&cfg));
/*
* Verify we can add non-existing files when the parent directory is not
* a directory.
*/
cl_git_pass(git_config_add_file_ondisk(cfg, "/dev/null/.gitconfig",
GIT_CONFIG_LEVEL_SYSTEM, NULL, 0));
count = 0;
cl_git_pass(git_config_foreach(cfg, count_cfg_entries_and_compare_levels, &count));
cl_assert_equal_i(0, count);
git_config_free(cfg);
}
/*
* At the beginning of the test, config18 has:
* int32global = 28
* int64global = 9223372036854775803
* boolglobal = true
* stringglobal = I'm a global config value!
*
* And config19 has:
* int32global = -1
* int64global = -2
* boolglobal = false
* stringglobal = don't find me!
*
*/
void test_config_read__simple_read_from_specific_level(void)
{
git_config *cfg, *cfg_specific;
int i;
int64_t l, expected = +9223372036854775803;
cl_git_pass(git_config_new(&cfg));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config18"),
GIT_CONFIG_LEVEL_GLOBAL, NULL, 0));
cl_git_pass(git_config_add_file_ondisk(cfg, cl_fixture("config/config19"),
GIT_CONFIG_LEVEL_SYSTEM, NULL, 0));
cl_git_pass(git_config_open_level(&cfg_specific, cfg, GIT_CONFIG_LEVEL_GLOBAL));
cl_git_pass(git_config_get_int32(&i, cfg_specific, "core.int32global"));
cl_assert_equal_i(28, i);
cl_git_pass(git_config_get_int64(&l, cfg_specific, "core.int64global"));
cl_assert(l == expected);
cl_git_pass(git_config_get_bool(&i, cfg_specific, "core.boolglobal"));
cl_assert_equal_b(true, i);
cl_git_pass(git_config_get_string_buf(&buf, cfg_specific, "core.stringglobal"));
cl_assert_equal_s("I'm a global config value!", git_buf_cstr(&buf));
git_config_free(cfg_specific);
git_config_free(cfg);
}
void test_config_read__can_load_and_parse_an_empty_config_file(void)
{
git_config *cfg;
int i;
cl_set_cleanup(&clean_test_config, NULL);
cl_git_mkfile("./testconfig", "");
cl_git_pass(git_config_open_ondisk(&cfg, "./testconfig"));
cl_assert_equal_i(GIT_ENOTFOUND, git_config_get_int32(&i, cfg, "nope.neither"));
git_config_free(cfg);
}
void test_config_read__corrupt_header(void)
{
git_config *cfg;
cl_set_cleanup(&clean_test_config, NULL);
cl_git_mkfile("./testconfig", "[sneaky ] \"quoted closing quote mark\\\"");
cl_git_fail(git_config_open_ondisk(&cfg, "./testconfig"));
git_config_free(cfg);
}
void test_config_read__corrupt_header2(void)
{
git_config *cfg;
cl_set_cleanup(&clean_test_config, NULL);
cl_git_mkfile("./testconfig", "[unclosed \"bracket\"\n lib = git2\n");
cl_git_fail(git_config_open_ondisk(&cfg, "./testconfig"));
git_config_free(cfg);
}
void test_config_read__corrupt_header3(void)
{
git_config *cfg;
cl_set_cleanup(&clean_test_config, NULL);
cl_git_mkfile("./testconfig", "[unclosed \"slash\\\"]\n lib = git2\n");
cl_git_fail(git_config_open_ondisk(&cfg, "./testconfig"));
git_config_free(cfg);
}
void test_config_read__invalid_key_chars(void)
{
git_config *cfg;
cl_set_cleanup(&clean_test_config, NULL);
cl_git_mkfile("./testconfig", "[foo]\n has_underscore = git2\n");
cl_git_fail(git_config_open_ondisk(&cfg, "./testconfig"));
cl_git_rewritefile("./testconfig", "[foo]\n has/slash = git2\n");
cl_git_fail(git_config_open_ondisk(&cfg, "./testconfig"));
cl_git_rewritefile("./testconfig", "[foo]\n has+plus = git2\n");
cl_git_fail(git_config_open_ondisk(&cfg, "./testconfig"));
cl_git_rewritefile("./testconfig", "[no_key]\n = git2\n");
cl_git_fail(git_config_open_ondisk(&cfg, "./testconfig"));
git_config_free(cfg);
}
void test_config_read__lone_variable_with_trailing_whitespace(void)
{
git_config *cfg;
int b;
cl_set_cleanup(&clean_test_config, NULL);
cl_git_mkfile("./testconfig", "[foo]\n lonevariable \n");
cl_git_pass(git_config_open_ondisk(&cfg, "./testconfig"));
cl_git_pass(git_config_get_bool(&b, cfg, "foo.lonevariable"));
cl_assert_equal_b(true, b);
git_config_free(cfg);
}
void test_config_read__override_variable(void)
{
git_config *cfg;
cl_set_cleanup(&clean_test_config, NULL);
cl_git_mkfile("./testconfig", "[some] var = one\nvar = two");
cl_git_pass(git_config_open_ondisk(&cfg, "./testconfig"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "some.var"));
cl_assert_equal_s("two", git_buf_cstr(&buf));
git_config_free(cfg);
}
void test_config_read__path(void)
{
git_config *cfg;
git_buf path = GIT_BUF_INIT;
git_buf old_path = GIT_BUF_INIT;
git_buf home_path = GIT_BUF_INIT;
git_buf expected_path = GIT_BUF_INIT;
cl_git_pass(p_mkdir("fakehome", 0777));
cl_git_pass(git_path_prettify(&home_path, "fakehome", NULL));
cl_git_pass(git_libgit2_opts(GIT_OPT_GET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, &old_path));
cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, home_path.ptr));
cl_git_mkfile("./testconfig", "[some]\n path = ~/somefile");
cl_git_pass(git_path_join_unrooted(&expected_path, "somefile", home_path.ptr, NULL));
cl_git_pass(git_config_open_ondisk(&cfg, "./testconfig"));
cl_git_pass(git_config_get_path(&path, cfg, "some.path"));
cl_assert_equal_s(expected_path.ptr, path.ptr);
git_buf_dispose(&path);
cl_git_mkfile("./testconfig", "[some]\n path = ~/");
cl_git_pass(git_path_join_unrooted(&expected_path, "", home_path.ptr, NULL));
cl_git_pass(git_config_get_path(&path, cfg, "some.path"));
cl_assert_equal_s(expected_path.ptr, path.ptr);
git_buf_dispose(&path);
cl_git_mkfile("./testconfig", "[some]\n path = ~");
cl_git_pass(git_buf_sets(&expected_path, home_path.ptr));
cl_git_pass(git_config_get_path(&path, cfg, "some.path"));
cl_assert_equal_s(expected_path.ptr, path.ptr);
git_buf_dispose(&path);
cl_git_mkfile("./testconfig", "[some]\n path = ~user/foo");
cl_git_fail(git_config_get_path(&path, cfg, "some.path"));
cl_git_pass(git_libgit2_opts(GIT_OPT_SET_SEARCH_PATH, GIT_CONFIG_LEVEL_GLOBAL, old_path.ptr));
git_buf_dispose(&old_path);
git_buf_dispose(&home_path);
git_buf_dispose(&expected_path);
git_config_free(cfg);
}
void test_config_read__crlf_style_line_endings(void)
{
git_buf buf = GIT_BUF_INIT;
git_config *cfg;
cl_set_cleanup(&clean_test_config, NULL);
cl_git_mkfile("./testconfig", "[some]\r\n var = value\r\n");
cl_git_pass(git_config_open_ondisk(&cfg, "./testconfig"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "some.var"));
cl_assert_equal_s(buf.ptr, "value");
git_config_free(cfg);
git_buf_dispose(&buf);
}
void test_config_read__trailing_crlf(void)
{
git_buf buf = GIT_BUF_INIT;
git_config *cfg;
cl_set_cleanup(&clean_test_config, NULL);
cl_git_mkfile("./testconfig", "[some]\r\n var = value\r\n\r\n");
cl_git_pass(git_config_open_ondisk(&cfg, "./testconfig"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "some.var"));
cl_assert_equal_s(buf.ptr, "value");
git_config_free(cfg);
git_buf_dispose(&buf);
}
void test_config_read__bom(void)
{
git_buf buf = GIT_BUF_INIT;
git_config *cfg;
cl_set_cleanup(&clean_test_config, NULL);
cl_git_mkfile("./testconfig", "\xEF\xBB\xBF[some]\n var = value\n");
cl_git_pass(git_config_open_ondisk(&cfg, "./testconfig"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "some.var"));
cl_assert_equal_s(buf.ptr, "value");
git_config_free(cfg);
git_buf_dispose(&buf);
}
void test_config_read__arbitrary_whitespace_before_subsection(void)
{
git_buf buf = GIT_BUF_INIT;
git_config *cfg;
cl_set_cleanup(&clean_test_config, NULL);
cl_git_mkfile("./testconfig", "[some \t \"subsection\"]\n var = value\n");
cl_git_pass(git_config_open_ondisk(&cfg, "./testconfig"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "some.subsection.var"));
cl_assert_equal_s(buf.ptr, "value");
git_config_free(cfg);
git_buf_dispose(&buf);
}
void test_config_read__no_whitespace_after_subsection(void)
{
git_config *cfg;
cl_set_cleanup(&clean_test_config, NULL);
cl_git_mkfile("./testconfig", "[some \"subsection\" ]\n var = value\n");
cl_git_fail(git_config_open_ondisk(&cfg, "./testconfig"));
git_config_free(cfg);
}
void test_config_read__invalid_space_section(void)
{
git_config *cfg;
cl_set_cleanup(&clean_test_config, NULL);
cl_git_mkfile("./testconfig", "\xEF\xBB\xBF[some section]\n var = value\n");
cl_git_fail(git_config_open_ondisk(&cfg, "./testconfig"));
git_config_free(cfg);
}
void test_config_read__invalid_quoted_first_section(void)
{
git_config *cfg;
cl_set_cleanup(&clean_test_config, NULL);
cl_git_mkfile("./testconfig", "\xEF\xBB\xBF[\"some\"]\n var = value\n");
cl_git_fail(git_config_open_ondisk(&cfg, "./testconfig"));
git_config_free(cfg);
}
void test_config_read__invalid_unquoted_subsection(void)
{
git_config *cfg;
cl_set_cleanup(&clean_test_config, NULL);
cl_git_mkfile("./testconfig", "\xEF\xBB\xBF[some sub section]\n var = value\n");
cl_git_fail(git_config_open_ondisk(&cfg, "./testconfig"));
git_config_free(cfg);
}
void test_config_read__invalid_quoted_third_section(void)
{
git_config *cfg;
cl_set_cleanup(&clean_test_config, NULL);
cl_git_mkfile("./testconfig", "\xEF\xBB\xBF[some sub \"section\"]\n var = value\n");
cl_git_fail(git_config_open_ondisk(&cfg, "./testconfig"));
git_config_free(cfg);
}
void test_config_read__single_line(void)
{
git_buf buf = GIT_BUF_INIT;
git_config *cfg;
cl_set_cleanup(&clean_test_config, NULL);
cl_git_mkfile("./testconfig", "[some] var = value\n[some \"OtheR\"] var = value");
cl_git_pass(git_config_open_ondisk(&cfg, "./testconfig"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "some.var"));
cl_assert_equal_s(buf.ptr, "value");
git_buf_clear(&buf);
cl_git_pass(git_config_get_string_buf(&buf, cfg, "some.OtheR.var"));
cl_assert_equal_s(buf.ptr, "value");
git_config_free(cfg);
cl_git_mkfile("./testconfig", "[some] var = value\n[some \"OtheR\"]var = value");
cl_git_pass(git_config_open_ondisk(&cfg, "./testconfig"));
git_buf_clear(&buf);
cl_git_pass(git_config_get_string_buf(&buf, cfg, "some.var"));
cl_assert_equal_s(buf.ptr, "value");
git_buf_clear(&buf);
cl_git_pass(git_config_get_string_buf(&buf, cfg, "some.OtheR.var"));
cl_assert_equal_s(buf.ptr, "value");
git_config_free(cfg);
git_buf_dispose(&buf);
}
static int read_nosection_cb(const git_config_entry *entry, void *payload) {
int *seen = (int*)payload;
if (strcmp(entry->name, "key") == 0) {
(*seen)++;
}
return 0;
}
/* This would ideally issue a warning, if we had a way to do so. */
void test_config_read__nosection(void)
{
git_config *cfg;
git_buf buf = GIT_BUF_INIT;
int seen = 0;
cl_git_pass(git_config_open_ondisk(&cfg, cl_fixture("config/config-nosection")));
/*
* Given a key with no section, we do not allow reading it,
* but we do include it in an iteration over the config
* store. This appears to match how git's own APIs (and
* git-config(1)) behave.
*/
cl_git_fail_with(git_config_get_string_buf(&buf, cfg, "key"), GIT_EINVALIDSPEC);
cl_git_pass(git_config_foreach(cfg, read_nosection_cb, &seen));
cl_assert_equal_i(seen, 1);
git_buf_dispose(&buf);
git_config_free(cfg);
}
+65
View File
@@ -0,0 +1,65 @@
#include "clar_libgit2.h"
#include "config_backend.h"
#include "config.h"
#include "path.h"
static git_config *cfg;
void test_config_readonly__initialize(void)
{
cl_git_pass(git_config_new(&cfg));
}
void test_config_readonly__cleanup(void)
{
git_config_free(cfg);
cfg = NULL;
}
void test_config_readonly__writing_to_readonly_fails(void)
{
git_config_backend *backend;
cl_git_pass(git_config_backend_from_file(&backend, "global"));
backend->readonly = 1;
cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_GLOBAL, NULL, 0));
cl_git_fail_with(GIT_ENOTFOUND, git_config_set_string(cfg, "foo.bar", "baz"));
cl_assert(!git_path_exists("global"));
}
void test_config_readonly__writing_to_cfg_with_rw_precedence_succeeds(void)
{
git_config_backend *backend;
cl_git_pass(git_config_backend_from_file(&backend, "global"));
backend->readonly = 1;
cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_GLOBAL, NULL, 0));
cl_git_pass(git_config_backend_from_file(&backend, "local"));
cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_LOCAL, NULL, 0));
cl_git_pass(git_config_set_string(cfg, "foo.bar", "baz"));
cl_assert(git_path_exists("local"));
cl_assert(!git_path_exists("global"));
cl_git_pass(p_unlink("local"));
}
void test_config_readonly__writing_to_cfg_with_ro_precedence_succeeds(void)
{
git_config_backend *backend;
cl_git_pass(git_config_backend_from_file(&backend, "local"));
backend->readonly = 1;
cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_LOCAL, NULL, 0));
cl_git_pass(git_config_backend_from_file(&backend, "global"));
cl_git_pass(git_config_add_backend(cfg, backend, GIT_CONFIG_LEVEL_GLOBAL, NULL, 0));
cl_git_pass(git_config_set_string(cfg, "foo.bar", "baz"));
cl_assert(!git_path_exists("local"));
cl_assert(git_path_exists("global"));
cl_git_pass(p_unlink("global"));
}
+89
View File
@@ -0,0 +1,89 @@
#include "clar_libgit2.h"
#include "config.h"
static git_repository *g_repo = NULL;
static git_config *g_config = NULL;
void test_config_rename__initialize(void)
{
g_repo = cl_git_sandbox_init("testrepo.git");
cl_git_pass(git_repository_config(&g_config, g_repo));
}
void test_config_rename__cleanup(void)
{
git_config_free(g_config);
g_config = NULL;
cl_git_sandbox_cleanup();
g_repo = NULL;
}
void test_config_rename__can_rename(void)
{
git_config_entry *ce;
cl_git_pass(git_config_get_entry(
&ce, g_config, "branch.track-local.remote"));
cl_assert_equal_s(".", ce->value);
git_config_entry_free(ce);
cl_git_fail(git_config_get_entry(
&ce, g_config, "branch.local-track.remote"));
cl_git_pass(git_config_rename_section(
g_repo, "branch.track-local", "branch.local-track"));
cl_git_pass(git_config_get_entry(
&ce, g_config, "branch.local-track.remote"));
cl_assert_equal_s(".", ce->value);
git_config_entry_free(ce);
cl_git_fail(git_config_get_entry(
&ce, g_config, "branch.track-local.remote"));
}
void test_config_rename__prevent_overwrite(void)
{
git_config_entry *ce;
cl_git_pass(git_config_set_string(
g_config, "branch.local-track.remote", "yellow"));
cl_git_pass(git_config_get_entry(
&ce, g_config, "branch.local-track.remote"));
cl_assert_equal_s("yellow", ce->value);
git_config_entry_free(ce);
cl_git_pass(git_config_rename_section(
g_repo, "branch.track-local", "branch.local-track"));
cl_git_pass(git_config_get_entry(
&ce, g_config, "branch.local-track.remote"));
cl_assert_equal_s(".", ce->value);
git_config_entry_free(ce);
/* so, we don't currently prevent overwrite... */
/* {
const git_error *err;
cl_assert((err = git_error_last()) != NULL);
cl_assert(err->message != NULL);
} */
}
static void assert_invalid_config_section_name(
git_repository *repo, const char *name)
{
cl_git_fail_with(
git_config_rename_section(repo, "branch.remoteless", name),
GIT_EINVALIDSPEC);
}
void test_config_rename__require_a_valid_new_name(void)
{
assert_invalid_config_section_name(g_repo, "");
assert_invalid_config_section_name(g_repo, "bra\nch");
assert_invalid_config_section_name(g_repo, "branc#");
assert_invalid_config_section_name(g_repo, "bra\nch.duh");
assert_invalid_config_section_name(g_repo, "branc#.duh");
}
+139
View File
@@ -0,0 +1,139 @@
#include "clar_libgit2.h"
#include "config_backend.h"
static git_config *cfg;
static git_config *snapshot;
void test_config_snapshot__cleanup(void)
{
git_config_free(cfg);
cfg = NULL;
git_config_free(snapshot);
snapshot = NULL;
}
void test_config_snapshot__create_snapshot(void)
{
int32_t i;
cl_git_mkfile("config", "[old]\nvalue = 5\n");
cl_git_pass(git_config_open_ondisk(&cfg, "config"));
cl_git_pass(git_config_get_int32(&i, cfg, "old.value"));
cl_assert_equal_i(5, i);
cl_git_pass(git_config_snapshot(&snapshot, cfg));
/* Change the value on the file itself (simulate external process) */
cl_git_mkfile("config", "[old]\nvalue = 56\n");
cl_git_pass(git_config_get_int32(&i, cfg, "old.value"));
cl_assert_equal_i(56, i);
cl_git_pass(git_config_get_int32(&i, snapshot, "old.value"));
cl_assert_equal_i(5, i);
/* Change the value on the file itself (simulate external process) */
cl_git_mkfile("config", "[old]\nvalue = 999\n");
/* Old snapshot should still have the old value */
cl_git_pass(git_config_get_int32(&i, snapshot, "old.value"));
cl_assert_equal_i(5, i);
/* New snapshot should see new value */
git_config_free(snapshot);
cl_git_pass(git_config_snapshot(&snapshot, cfg));
cl_git_pass(git_config_get_int32(&i, snapshot, "old.value"));
cl_assert_equal_i(999, i);
cl_git_pass(p_unlink("config"));
}
static int count_me(const git_config_entry *entry, void *payload)
{
int *n = (int *) payload;
GIT_UNUSED(entry);
(*n)++;
return 0;
}
void test_config_snapshot__multivar(void)
{
int count;
count = 0;
cl_git_mkfile("config", "[old]\nvalue = 5\nvalue = 6\n");
cl_git_pass(git_config_open_ondisk(&cfg, "config"));
cl_git_pass(git_config_get_multivar_foreach(cfg, "old.value", NULL, count_me, &count));
cl_assert_equal_i(2, count);
count = 0;
cl_git_pass(git_config_snapshot(&snapshot, cfg));
cl_git_pass(git_config_get_multivar_foreach(snapshot, "old.value", NULL, count_me, &count));
cl_assert_equal_i(2, count);
cl_git_pass(p_unlink("config"));
}
void test_config_snapshot__includes(void)
{
int i;
cl_git_mkfile("including", "[include]\npath = included");
cl_git_mkfile("included", "[section]\nkey = 1\n");
cl_git_pass(git_config_open_ondisk(&cfg, "including"));
cl_git_pass(git_config_snapshot(&snapshot, cfg));
cl_git_pass(git_config_get_int32(&i, snapshot, "section.key"));
cl_assert_equal_i(i, 1);
/* Rewrite "included" config */
cl_git_mkfile("included", "[section]\nkey = 11\n");
/* Assert that the live config changed, but snapshot remained the same */
cl_git_pass(git_config_get_int32(&i, cfg, "section.key"));
cl_assert_equal_i(i, 11);
cl_git_pass(git_config_get_int32(&i, snapshot, "section.key"));
cl_assert_equal_i(i, 1);
cl_git_pass(p_unlink("including"));
cl_git_pass(p_unlink("included"));
}
void test_config_snapshot__snapshot(void)
{
git_config *snapshot_snapshot;
int i;
cl_git_mkfile("configfile", "[section]\nkey = 1\n");
cl_git_pass(git_config_open_ondisk(&cfg, "configfile"));
cl_git_pass(git_config_snapshot(&snapshot, cfg));
cl_git_pass(git_config_snapshot(&snapshot_snapshot, snapshot));
cl_git_pass(git_config_get_int32(&i, snapshot_snapshot, "section.key"));
cl_assert_equal_i(i, 1);
git_config_free(snapshot_snapshot);
cl_git_pass(p_unlink("configfile"));
}
void test_config_snapshot__snapshot_from_in_memony(void)
{
const char *configuration = "[section]\nkey = 1\n";
git_config_backend *backend;
int i;
cl_git_pass(git_config_new(&cfg));
cl_git_pass(git_config_backend_from_string(&backend, configuration, strlen(configuration)));
cl_git_pass(git_config_add_backend(cfg, backend, 0, NULL, 0));
cl_git_pass(git_config_snapshot(&snapshot, cfg));
cl_git_pass(git_config_get_int32(&i, snapshot, "section.key"));
cl_assert_equal_i(i, 1);
}
+201
View File
@@ -0,0 +1,201 @@
#include "clar_libgit2.h"
#include "filebuf.h"
#include "futils.h"
#include "posix.h"
#define TEST_CONFIG "git-test-config"
static git_buf buf = GIT_BUF_INIT;
void test_config_stress__initialize(void)
{
git_filebuf file = GIT_FILEBUF_INIT;
cl_git_pass(git_filebuf_open(&file, TEST_CONFIG, 0, 0666));
git_filebuf_printf(&file, "[color]\n\tui = auto\n");
git_filebuf_printf(&file, "[core]\n\teditor = \n");
cl_git_pass(git_filebuf_commit(&file));
}
void test_config_stress__cleanup(void)
{
git_buf_dispose(&buf);
p_unlink(TEST_CONFIG);
}
void test_config_stress__dont_break_on_invalid_input(void)
{
git_config *config;
cl_assert(git_path_exists(TEST_CONFIG));
cl_git_pass(git_config_open_ondisk(&config, TEST_CONFIG));
cl_git_pass(git_config_get_string_buf(&buf, config, "color.ui"));
cl_git_pass(git_config_get_string_buf(&buf, config, "core.editor"));
git_config_free(config);
}
void assert_config_value(git_config *config, const char *key, const char *value)
{
git_buf_clear(&buf);
cl_git_pass(git_config_get_string_buf(&buf, config, key));
cl_assert_equal_s(value, git_buf_cstr(&buf));
}
void test_config_stress__comments(void)
{
git_config *config;
cl_git_pass(git_config_open_ondisk(&config, cl_fixture("config/config12")));
assert_config_value(config, "some.section.test2", "hello");
assert_config_value(config, "some.section.test3", "welcome");
assert_config_value(config, "some.section.other", "hello! \" ; ; ; ");
assert_config_value(config, "some.section.other2", "cool! \" # # # ");
assert_config_value(config, "some.section.multi", "hi, this is a ; multiline comment # with ;\n special chars and other stuff !@#");
assert_config_value(config, "some.section.multi2", "good, this is a ; multiline comment # with ;\n special chars and other stuff !@#");
assert_config_value(config, "some.section.back", "this is \ba phrase");
git_config_free(config);
}
void test_config_stress__escape_subsection_names(void)
{
git_config *config;
cl_assert(git_path_exists("git-test-config"));
cl_git_pass(git_config_open_ondisk(&config, TEST_CONFIG));
cl_git_pass(git_config_set_string(config, "some.sec\\tion.other", "foo"));
git_config_free(config);
cl_git_pass(git_config_open_ondisk(&config, TEST_CONFIG));
assert_config_value(config, "some.sec\\tion.other", "foo");
git_config_free(config);
}
void test_config_stress__trailing_backslash(void)
{
git_config *config;
const char *path = "C:\\iam\\some\\windows\\path\\";
cl_assert(git_path_exists("git-test-config"));
cl_git_pass(git_config_open_ondisk(&config, TEST_CONFIG));
cl_git_pass(git_config_set_string(config, "windows.path", path));
git_config_free(config);
cl_git_pass(git_config_open_ondisk(&config, TEST_CONFIG));
assert_config_value(config, "windows.path", path);
git_config_free(config);
}
void test_config_stress__complex(void)
{
git_config *config;
const char *path = "./config-immediate-multiline";
cl_git_mkfile(path, "[imm]\n multi = \"\\\nfoo\"");
cl_git_pass(git_config_open_ondisk(&config, path));
assert_config_value(config, "imm.multi", "foo");
git_config_free(config);
}
void test_config_stress__quick_write(void)
{
git_config *config_w, *config_r;
const char *path = "./config-quick-write";
const char *key = "quick.write";
int32_t i;
/* Create an external writer for one instance with the other one */
cl_git_pass(git_config_open_ondisk(&config_w, path));
cl_git_pass(git_config_open_ondisk(&config_r, path));
/* Write and read in the same second (repeat to increase the chance of it happening) */
for (i = 0; i < 10; i++) {
int32_t val;
cl_git_pass(git_config_set_int32(config_w, key, i));
cl_msleep(1);
cl_git_pass(git_config_get_int32(&val, config_r, key));
cl_assert_equal_i(i, val);
}
git_config_free(config_r);
git_config_free(config_w);
}
static int foreach_cb(const git_config_entry *entry, void *payload)
{
if (!strcmp(entry->name, "key.value")) {
*(char **)payload = git__strdup(entry->value);
return 0;
}
return -1;
}
void test_config_stress__foreach_refreshes(void)
{
git_config *config_w, *config_r;
char *value = NULL;
cl_git_pass(git_config_open_ondisk(&config_w, "./cfg"));
cl_git_pass(git_config_open_ondisk(&config_r, "./cfg"));
cl_git_pass(git_config_set_string(config_w, "key.value", "1"));
cl_git_pass(git_config_foreach_match(config_r, "key.value", foreach_cb, &value));
cl_assert_equal_s(value, "1");
git_config_free(config_r);
git_config_free(config_w);
git__free(value);
}
void test_config_stress__foreach_refreshes_snapshot(void)
{
git_config *config, *snapshot;
char *value = NULL;
cl_git_pass(git_config_open_ondisk(&config, "./cfg"));
cl_git_pass(git_config_set_string(config, "key.value", "1"));
cl_git_pass(git_config_snapshot(&snapshot, config));
cl_git_pass(git_config_foreach_match(snapshot, "key.value", foreach_cb, &value));
cl_assert_equal_s(value, "1");
git_config_free(snapshot);
git_config_free(config);
git__free(value);
}
void test_config_stress__huge_section_with_many_values(void)
{
git_config *config;
if (!cl_is_env_set("GITTEST_INVASIVE_SPEED"))
cl_skip();
/*
* The config file is structured in such a way that is
* has a section header that is approximately 500kb of
* size followed by 40k entries. While the resulting
* configuration file itself is roughly 650kb in size and
* thus considered to be rather small, in the past we'd
* balloon to more than 20GB of memory (20000x500kb)
* while parsing the file. It thus was a trivial way to
* cause an out-of-memory situation and thus cause denial
* of service, e.g. via gitmodules.
*/
cl_git_pass(git_config_open_ondisk(&config, cl_fixture("config/config-oom")));
git_config_free(config);
}
+49
View File
@@ -0,0 +1,49 @@
#include "clar_libgit2.h"
#include "config.h"
static git_config *cfg;
void test_config_validkeyname__initialize(void)
{
cl_fixture_sandbox("config/config10");
cl_git_pass(git_config_open_ondisk(&cfg, "config10"));
}
void test_config_validkeyname__cleanup(void)
{
git_config_free(cfg);
cfg = NULL;
cl_fixture_cleanup("config10");
}
static void assert_invalid_config_key_name(const char *name)
{
git_buf buf = GIT_BUF_INIT;
cl_git_fail_with(git_config_get_string_buf(&buf, cfg, name),
GIT_EINVALIDSPEC);
cl_git_fail_with(git_config_set_string(cfg, name, "42"),
GIT_EINVALIDSPEC);
cl_git_fail_with(git_config_delete_entry(cfg, name),
GIT_EINVALIDSPEC);
cl_git_fail_with(git_config_get_multivar_foreach(cfg, name, "*", NULL, NULL),
GIT_EINVALIDSPEC);
cl_git_fail_with(git_config_set_multivar(cfg, name, "*", "42"),
GIT_EINVALIDSPEC);
}
void test_config_validkeyname__accessing_requires_a_valid_name(void)
{
assert_invalid_config_key_name("");
assert_invalid_config_key_name(".");
assert_invalid_config_key_name("..");
assert_invalid_config_key_name("core.");
assert_invalid_config_key_name("d#ff.dirstat.lines");
assert_invalid_config_key_name("diff.dirstat.lines#");
assert_invalid_config_key_name("dif\nf.dirstat.lines");
assert_invalid_config_key_name("dif.dir\nstat.lines");
assert_invalid_config_key_name("dif.dirstat.li\nes");
}
+746
View File
@@ -0,0 +1,746 @@
#include "clar_libgit2.h"
#include "buffer.h"
#include "futils.h"
#include "git2/sys/config.h"
#include "config.h"
void test_config_write__initialize(void)
{
cl_fixture_sandbox("config/config9");
cl_fixture_sandbox("config/config15");
cl_fixture_sandbox("config/config17");
}
void test_config_write__cleanup(void)
{
cl_fixture_cleanup("config9");
cl_fixture_cleanup("config15");
cl_fixture_cleanup("config17");
}
void test_config_write__replace_value(void)
{
git_config *cfg;
int i;
int64_t l, expected = +9223372036854775803;
/* By freeing the config, we make sure we flush the values */
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
cl_git_pass(git_config_set_int32(cfg, "core.dummy", 5));
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
cl_git_pass(git_config_get_int32(&i, cfg, "core.dummy"));
cl_assert(i == 5);
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
cl_git_pass(git_config_set_int32(cfg, "core.dummy", 1));
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
cl_git_pass(git_config_set_int64(cfg, "core.verylong", expected));
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
cl_git_pass(git_config_get_int64(&l, cfg, "core.verylong"));
cl_assert(l == expected);
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
cl_must_fail(git_config_get_int32(&i, cfg, "core.verylong"));
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
cl_git_pass(git_config_set_int64(cfg, "core.verylong", 1));
git_config_free(cfg);
}
void test_config_write__delete_value(void)
{
git_config *cfg;
int32_t i;
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
cl_git_pass(git_config_set_int32(cfg, "core.dummy", 5));
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
cl_git_pass(git_config_delete_entry(cfg, "core.dummy"));
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
cl_assert(git_config_get_int32(&i, cfg, "core.dummy") == GIT_ENOTFOUND);
cl_git_pass(git_config_set_int32(cfg, "core.dummy", 1));
git_config_free(cfg);
}
/*
* At the beginning of the test:
* - config9 has: core.dummy2=42
* - config15 has: core.dummy2=7
*/
void test_config_write__delete_value_at_specific_level(void)
{
git_config *cfg, *cfg_specific;
int32_t i;
cl_git_pass(git_config_open_ondisk(&cfg, "config15"));
cl_git_pass(git_config_get_int32(&i, cfg, "core.dummy2"));
cl_assert(i == 7);
git_config_free(cfg);
cl_git_pass(git_config_new(&cfg));
cl_git_pass(git_config_add_file_ondisk(cfg, "config9",
GIT_CONFIG_LEVEL_LOCAL, NULL, 0));
cl_git_pass(git_config_add_file_ondisk(cfg, "config15",
GIT_CONFIG_LEVEL_GLOBAL, NULL, 0));
cl_git_pass(git_config_open_level(&cfg_specific, cfg, GIT_CONFIG_LEVEL_GLOBAL));
cl_git_pass(git_config_delete_entry(cfg_specific, "core.dummy2"));
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, "config15"));
cl_assert(git_config_get_int32(&i, cfg, "core.dummy2") == GIT_ENOTFOUND);
cl_git_pass(git_config_set_int32(cfg, "core.dummy2", 7));
git_config_free(cfg_specific);
git_config_free(cfg);
}
/*
* This test exposes a bug where duplicate empty section headers could prevent
* deletion of config entries.
*/
void test_config_write__delete_value_with_duplicate_header(void)
{
const char *file_name = "config-duplicate-header";
const char *entry_name = "remote.origin.url";
git_config *cfg;
git_config_entry *entry;
/* This config can occur after removing and re-adding the origin remote */
const char *file_content =
"[remote \"origin\"]\n" \
"[branch \"master\"]\n" \
" remote = \"origin\"\n" \
"[remote \"origin\"]\n" \
" url = \"foo\"\n";
/* Write the test config and make sure the expected entry exists */
cl_git_mkfile(file_name, file_content);
cl_git_pass(git_config_open_ondisk(&cfg, file_name));
cl_git_pass(git_config_get_entry(&entry, cfg, entry_name));
/* Delete that entry */
cl_git_pass(git_config_delete_entry(cfg, entry_name));
/* Reopen the file and make sure the entry no longer exists */
git_config_entry_free(entry);
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, file_name));
cl_git_fail(git_config_get_entry(&entry, cfg, entry_name));
/* Cleanup */
git_config_entry_free(entry);
git_config_free(cfg);
}
/*
* This test exposes a bug where duplicate section headers could cause
* config_write to add a new entry when one already exists.
*/
void test_config_write__add_value_with_duplicate_header(void)
{
const char *file_name = "config-duplicate-insert";
const char *entry_name = "foo.c";
const char *old_val = "old";
const char *new_val = "new";
const char *str;
git_config *cfg, *snapshot;
/* c = old should be replaced by c = new.
* The bug causes c = new to be inserted under the first 'foo' header.
*/
const char *file_content =
"[foo]\n" \
" a = b\n" \
"[other]\n" \
" a = b\n" \
"[foo]\n" \
" c = old\n";
/* Write the test config */
cl_git_mkfile(file_name, file_content);
cl_git_pass(git_config_open_ondisk(&cfg, file_name));
/* make sure the expected entry (foo.c) exists */
cl_git_pass(git_config_snapshot(&snapshot, cfg));
cl_git_pass(git_config_get_string(&str, snapshot, entry_name));
cl_assert_equal_s(old_val, str);
git_config_free(snapshot);
/* Try setting foo.c to something else */
cl_git_pass(git_config_set_string(cfg, entry_name, new_val));
git_config_free(cfg);
/* Reopen the file and make sure the new value was set */
cl_git_pass(git_config_open_ondisk(&cfg, file_name));
cl_git_pass(git_config_snapshot(&snapshot, cfg));
cl_git_pass(git_config_get_string(&str, snapshot, entry_name));
cl_assert_equal_s(new_val, str);
/* Cleanup */
git_config_free(snapshot);
git_config_free(cfg);
}
void test_config_write__overwrite_value_with_duplicate_header(void)
{
const char *file_name = "config-duplicate-header";
const char *entry_name = "remote.origin.url";
git_config *cfg;
git_config_entry *entry;
/* This config can occur after removing and re-adding the origin remote */
const char *file_content =
"[remote \"origin\"]\n" \
"[branch \"master\"]\n" \
" remote = \"origin\"\n" \
"[remote \"origin\"]\n" \
" url = \"foo\"\n";
/* Write the test config and make sure the expected entry exists */
cl_git_mkfile(file_name, file_content);
cl_git_pass(git_config_open_ondisk(&cfg, file_name));
cl_git_pass(git_config_get_entry(&entry, cfg, entry_name));
/* Update that entry */
cl_git_pass(git_config_set_string(cfg, entry_name, "newurl"));
/* Reopen the file and make sure the entry was updated */
git_config_entry_free(entry);
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, file_name));
cl_git_pass(git_config_get_entry(&entry, cfg, entry_name));
cl_assert_equal_s("newurl", entry->value);
/* Cleanup */
git_config_entry_free(entry);
git_config_free(cfg);
}
static int multivar_cb(const git_config_entry *entry, void *data)
{
int *n = (int *)data;
cl_assert_equal_s(entry->value, "newurl");
(*n)++;
return 0;
}
void test_config_write__overwrite_multivar_within_duplicate_header(void)
{
const char *file_name = "config-duplicate-header";
const char *entry_name = "remote.origin.url";
git_config *cfg;
git_config_entry *entry;
int n = 0;
/* This config can occur after removing and re-adding the origin remote */
const char *file_content =
"[remote \"origin\"]\n" \
" url = \"bar\"\n" \
"[branch \"master\"]\n" \
" remote = \"origin\"\n" \
"[remote \"origin\"]\n" \
" url = \"foo\"\n";
/* Write the test config and make sure the expected entry exists */
cl_git_mkfile(file_name, file_content);
cl_git_pass(git_config_open_ondisk(&cfg, file_name));
cl_git_pass(git_config_get_entry(&entry, cfg, entry_name));
/* Update that entry */
cl_git_pass(git_config_set_multivar(cfg, entry_name, ".*", "newurl"));
git_config_entry_free(entry);
git_config_free(cfg);
/* Reopen the file and make sure the entry was updated */
cl_git_pass(git_config_open_ondisk(&cfg, file_name));
cl_git_pass(git_config_get_multivar_foreach(cfg, entry_name, NULL, multivar_cb, &n));
cl_assert_equal_i(2, n);
/* Cleanup */
git_config_free(cfg);
}
void test_config_write__write_subsection(void)
{
git_config *cfg;
git_buf buf = GIT_BUF_INIT;
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
cl_git_pass(git_config_set_string(cfg, "my.own.var", "works"));
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "my.own.var"));
cl_assert_equal_s("works", git_buf_cstr(&buf));
git_buf_dispose(&buf);
git_config_free(cfg);
}
void test_config_write__delete_inexistent(void)
{
git_config *cfg;
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
cl_assert(git_config_delete_entry(cfg, "core.imaginary") == GIT_ENOTFOUND);
git_config_free(cfg);
}
void test_config_write__value_containing_quotes(void)
{
git_config *cfg;
git_buf buf = GIT_BUF_INIT;
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
cl_git_pass(git_config_set_string(cfg, "core.somevar", "this \"has\" quotes"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar"));
cl_assert_equal_s("this \"has\" quotes", git_buf_cstr(&buf));
git_buf_clear(&buf);
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar"));
cl_assert_equal_s("this \"has\" quotes", git_buf_cstr(&buf));
git_buf_clear(&buf);
git_config_free(cfg);
/* The code path for values that already exist is different, check that one as well */
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
cl_git_pass(git_config_set_string(cfg, "core.somevar", "this also \"has\" quotes"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar"));
cl_assert_equal_s("this also \"has\" quotes", git_buf_cstr(&buf));
git_buf_clear(&buf);
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar"));
cl_assert_equal_s("this also \"has\" quotes", git_buf_cstr(&buf));
git_buf_dispose(&buf);
git_config_free(cfg);
}
void test_config_write__escape_value(void)
{
git_config *cfg;
git_buf buf = GIT_BUF_INIT;
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
cl_git_pass(git_config_set_string(cfg, "core.somevar", "this \"has\" quotes and \t"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar"));
cl_assert_equal_s("this \"has\" quotes and \t", git_buf_cstr(&buf));
git_buf_clear(&buf);
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.somevar"));
cl_assert_equal_s("this \"has\" quotes and \t", git_buf_cstr(&buf));
git_buf_dispose(&buf);
git_config_free(cfg);
}
void test_config_write__add_value_at_specific_level(void)
{
git_config *cfg, *cfg_specific;
int i;
int64_t l, expected = +9223372036854775803;
git_buf buf = GIT_BUF_INIT;
/* open config15 as global level config file */
cl_git_pass(git_config_new(&cfg));
cl_git_pass(git_config_add_file_ondisk(cfg, "config9",
GIT_CONFIG_LEVEL_LOCAL, NULL, 0));
cl_git_pass(git_config_add_file_ondisk(cfg, "config15",
GIT_CONFIG_LEVEL_GLOBAL, NULL, 0));
cl_git_pass(git_config_open_level(&cfg_specific, cfg, GIT_CONFIG_LEVEL_GLOBAL));
cl_git_pass(git_config_set_int32(cfg_specific, "core.int32global", 28));
cl_git_pass(git_config_set_int64(cfg_specific, "core.int64global", expected));
cl_git_pass(git_config_set_bool(cfg_specific, "core.boolglobal", true));
cl_git_pass(git_config_set_string(cfg_specific, "core.stringglobal", "I'm a global config value!"));
git_config_free(cfg_specific);
git_config_free(cfg);
/* open config15 as local level config file */
cl_git_pass(git_config_open_ondisk(&cfg, "config15"));
cl_git_pass(git_config_get_int32(&i, cfg, "core.int32global"));
cl_assert_equal_i(28, i);
cl_git_pass(git_config_get_int64(&l, cfg, "core.int64global"));
cl_assert(l == expected);
cl_git_pass(git_config_get_bool(&i, cfg, "core.boolglobal"));
cl_assert_equal_b(true, i);
cl_git_pass(git_config_get_string_buf(&buf, cfg, "core.stringglobal"));
cl_assert_equal_s("I'm a global config value!", git_buf_cstr(&buf));
git_buf_dispose(&buf);
git_config_free(cfg);
}
void test_config_write__add_value_at_file_with_no_clrf_at_the_end(void)
{
git_config *cfg;
int i;
cl_git_pass(git_config_open_ondisk(&cfg, "config17"));
cl_git_pass(git_config_set_int32(cfg, "core.newline", 7));
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, "config17"));
cl_git_pass(git_config_get_int32(&i, cfg, "core.newline"));
cl_assert_equal_i(7, i);
git_config_free(cfg);
}
void test_config_write__add_section_at_file_with_no_clrf_at_the_end(void)
{
git_config *cfg;
int i;
cl_git_pass(git_config_open_ondisk(&cfg, "config17"));
cl_git_pass(git_config_set_int32(cfg, "diff.context", 10));
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, "config17"));
cl_git_pass(git_config_get_int32(&i, cfg, "diff.context"));
cl_assert_equal_i(10, i);
git_config_free(cfg);
}
void test_config_write__add_value_which_needs_quotes(void)
{
git_config *cfg, *base;
const char* str1;
const char* str2;
const char* str3;
const char* str4;
const char* str5;
cl_git_pass(git_config_open_ondisk(&cfg, "config17"));
cl_git_pass(git_config_set_string(cfg, "core.startwithspace", " Something"));
cl_git_pass(git_config_set_string(cfg, "core.endwithspace", "Something "));
cl_git_pass(git_config_set_string(cfg, "core.containscommentchar1", "some#thing"));
cl_git_pass(git_config_set_string(cfg, "core.containscommentchar2", "some;thing"));
cl_git_pass(git_config_set_string(cfg, "core.startwhithsapceandcontainsdoublequote", " some\"thing"));
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&base, "config17"));
cl_git_pass(git_config_snapshot(&cfg, base));
cl_git_pass(git_config_get_string(&str1, cfg, "core.startwithspace"));
cl_assert_equal_s(" Something", str1);
cl_git_pass(git_config_get_string(&str2, cfg, "core.endwithspace"));
cl_assert_equal_s("Something ", str2);
cl_git_pass(git_config_get_string(&str3, cfg, "core.containscommentchar1"));
cl_assert_equal_s("some#thing", str3);
cl_git_pass(git_config_get_string(&str4, cfg, "core.containscommentchar2"));
cl_assert_equal_s("some;thing", str4);
cl_git_pass(git_config_get_string(&str5, cfg, "core.startwhithsapceandcontainsdoublequote"));
cl_assert_equal_s(" some\"thing", str5);
git_config_free(cfg);
git_config_free(base);
}
void test_config_write__can_set_a_value_to_NULL(void)
{
git_repository *repository;
git_config *config;
repository = cl_git_sandbox_init("testrepo.git");
cl_git_pass(git_repository_config(&config, repository));
cl_git_fail(git_config_set_string(config, "a.b.c", NULL));
git_config_free(config);
cl_git_sandbox_cleanup();
}
void test_config_write__can_set_an_empty_value(void)
{
git_repository *repository;
git_config *config;
git_buf buf = {0};
repository = cl_git_sandbox_init("testrepo.git");
cl_git_pass(git_repository_config(&config, repository));
cl_git_pass(git_config_set_string(config, "core.somevar", ""));
cl_git_pass(git_config_get_string_buf(&buf, config, "core.somevar"));
cl_assert_equal_s("", buf.ptr);
git_buf_dispose(&buf);
git_config_free(config);
cl_git_sandbox_cleanup();
}
void test_config_write__updating_a_locked_config_file_returns_ELOCKED(void)
{
git_config *cfg;
cl_git_pass(git_config_open_ondisk(&cfg, "config9"));
cl_git_mkfile("config9.lock", "[core]\n");
cl_git_fail_with(git_config_set_string(cfg, "core.dump", "boom"), GIT_ELOCKED);
git_config_free(cfg);
}
void test_config_write__outside_change(void)
{
int32_t tmp;
git_config *cfg;
const char *filename = "config-ext-change";
cl_git_mkfile(filename, "[old]\nvalue = 5\n");
cl_git_pass(git_config_open_ondisk(&cfg, filename));
cl_git_pass(git_config_get_int32(&tmp, cfg, "old.value"));
/* Change the value on the file itself (simulate external process) */
cl_git_mkfile(filename, "[old]\nvalue = 6\n");
cl_git_pass(git_config_set_int32(cfg, "new.value", 7));
cl_git_pass(git_config_get_int32(&tmp, cfg, "old.value"));
cl_assert_equal_i(6, tmp);
git_config_free(cfg);
}
#define FOO_COMMENT \
"; another comment!\n"
#define SECTION_FOO \
"\n" \
" \n" \
" [section \"foo\"] \n" \
" # here's a comment\n" \
"\tname = \"value\"\n" \
" name2 = \"value2\"\n" \
#define SECTION_FOO_WITH_COMMENT SECTION_FOO FOO_COMMENT
#define SECTION_BAR \
"[section \"bar\"]\t\n" \
"\t \n" \
" barname=\"value\"\n"
void test_config_write__preserves_whitespace_and_comments(void)
{
const char *file_name = "config-duplicate-header";
const char *n;
git_config *cfg;
git_buf newfile = GIT_BUF_INIT;
/* This config can occur after removing and re-adding the origin remote */
const char *file_content = SECTION_FOO_WITH_COMMENT SECTION_BAR;
/* Write the test config and make sure the expected entry exists */
cl_git_mkfile(file_name, file_content);
cl_git_pass(git_config_open_ondisk(&cfg, file_name));
cl_git_pass(git_config_set_string(cfg, "section.foo.other", "otherval"));
cl_git_pass(git_config_set_string(cfg, "newsection.newname", "new_value"));
/* Ensure that we didn't needlessly mangle the config file */
cl_git_pass(git_futils_readbuffer(&newfile, file_name));
n = newfile.ptr;
cl_assert_equal_strn(SECTION_FOO, n, strlen(SECTION_FOO));
n += strlen(SECTION_FOO);
cl_assert_equal_strn("\tother = otherval\n", n, strlen("\tother = otherval\n"));
n += strlen("\tother = otherval\n");
cl_assert_equal_strn(FOO_COMMENT, n, strlen(FOO_COMMENT));
n += strlen(FOO_COMMENT);
cl_assert_equal_strn(SECTION_BAR, n, strlen(SECTION_BAR));
n += strlen(SECTION_BAR);
cl_assert_equal_s("[newsection]\n\tnewname = new_value\n", n);
git_buf_dispose(&newfile);
git_config_free(cfg);
}
void test_config_write__preserves_entry_with_name_only(void)
{
const char *file_name = "config-empty-value";
git_config *cfg;
git_buf newfile = GIT_BUF_INIT;
/* Write the test config and make sure the expected entry exists */
cl_git_mkfile(file_name, "[section \"foo\"]\n\tname\n");
cl_git_pass(git_config_open_ondisk(&cfg, file_name));
cl_git_pass(git_config_set_string(cfg, "newsection.newname", "new_value"));
cl_git_pass(git_config_set_string(cfg, "section.foo.other", "otherval"));
cl_git_pass(git_futils_readbuffer(&newfile, file_name));
cl_assert_equal_s("[section \"foo\"]\n\tname\n\tother = otherval\n[newsection]\n\tnewname = new_value\n", newfile.ptr);
git_buf_dispose(&newfile);
git_config_free(cfg);
}
void test_config_write__to_empty_file(void)
{
git_config *cfg;
const char *filename = "config-file";
git_buf result = GIT_BUF_INIT;
cl_git_mkfile(filename, "");
cl_git_pass(git_config_open_ondisk(&cfg, filename));
cl_git_pass(git_config_set_string(cfg, "section.name", "value"));
git_config_free(cfg);
cl_git_pass(git_futils_readbuffer(&result, "config-file"));
cl_assert_equal_s("[section]\n\tname = value\n", result.ptr);
git_buf_dispose(&result);
}
void test_config_write__to_file_with_only_comment(void)
{
git_config *cfg;
const char *filename = "config-file";
git_buf result = GIT_BUF_INIT;
cl_git_mkfile(filename, "\n\n");
cl_git_pass(git_config_open_ondisk(&cfg, filename));
cl_git_pass(git_config_set_string(cfg, "section.name", "value"));
git_config_free(cfg);
cl_git_pass(git_futils_readbuffer(&result, "config-file"));
cl_assert_equal_s("\n\n[section]\n\tname = value\n", result.ptr);
git_buf_dispose(&result);
}
void test_config_write__locking(void)
{
git_config *cfg, *cfg2;
git_config_entry *entry;
git_transaction *tx;
const char *filename = "locked-file";
/* Open the config and lock it */
cl_git_mkfile(filename, "[section]\n\tname = value\n");
cl_git_pass(git_config_open_ondisk(&cfg, filename));
cl_git_pass(git_config_get_entry(&entry, cfg, "section.name"));
cl_assert_equal_s("value", entry->value);
git_config_entry_free(entry);
cl_git_pass(git_config_lock(&tx, cfg));
/* Change entries in the locked backend */
cl_git_pass(git_config_set_string(cfg, "section.name", "other value"));
cl_git_pass(git_config_set_string(cfg, "section2.name3", "more value"));
/* We can see that the file we read from hasn't changed */
cl_git_pass(git_config_open_ondisk(&cfg2, filename));
cl_git_pass(git_config_get_entry(&entry, cfg2, "section.name"));
cl_assert_equal_s("value", entry->value);
git_config_entry_free(entry);
cl_git_fail_with(GIT_ENOTFOUND, git_config_get_entry(&entry, cfg2, "section2.name3"));
git_config_free(cfg2);
/* And we also get the old view when we read from the locked config */
cl_git_pass(git_config_get_entry(&entry, cfg, "section.name"));
cl_assert_equal_s("value", entry->value);
git_config_entry_free(entry);
cl_git_fail_with(GIT_ENOTFOUND, git_config_get_entry(&entry, cfg, "section2.name3"));
cl_git_pass(git_transaction_commit(tx));
git_transaction_free(tx);
/* Now that we've unlocked it, we should see both updates */
cl_git_pass(git_config_get_entry(&entry, cfg, "section.name"));
cl_assert_equal_s("other value", entry->value);
git_config_entry_free(entry);
cl_git_pass(git_config_get_entry(&entry, cfg, "section2.name3"));
cl_assert_equal_s("more value", entry->value);
git_config_entry_free(entry);
git_config_free(cfg);
/* We should also see the changes after reopening the config */
cl_git_pass(git_config_open_ondisk(&cfg, filename));
cl_git_pass(git_config_get_entry(&entry, cfg, "section.name"));
cl_assert_equal_s("other value", entry->value);
git_config_entry_free(entry);
cl_git_pass(git_config_get_entry(&entry, cfg, "section2.name3"));
cl_assert_equal_s("more value", entry->value);
git_config_entry_free(entry);
git_config_free(cfg);
}
void test_config_write__repeated(void)
{
const char *filename = "config-repeated";
git_config *cfg;
git_buf result = GIT_BUF_INIT;
const char *expected = "[sample \"prefix\"]\n\
\tsetting1 = someValue1\n\
\tsetting2 = someValue2\n\
\tsetting3 = someValue3\n\
\tsetting4 = someValue4\n\
";
cl_git_pass(git_config_open_ondisk(&cfg, filename));
cl_git_pass(git_config_set_string(cfg, "sample.prefix.setting1", "someValue1"));
cl_git_pass(git_config_set_string(cfg, "sample.prefix.setting2", "someValue2"));
cl_git_pass(git_config_set_string(cfg, "sample.prefix.setting3", "someValue3"));
cl_git_pass(git_config_set_string(cfg, "sample.prefix.setting4", "someValue4"));
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, filename));
cl_git_pass(git_futils_readbuffer(&result, filename));
cl_assert_equal_s(expected, result.ptr);
git_buf_dispose(&result);
git_config_free(cfg);
}
void test_config_write__preserve_case(void)
{
const char *filename = "config-preserve-case";
git_config *cfg;
git_buf result = GIT_BUF_INIT;
const char *expected = "[sOMe]\n" \
"\tThInG = foo\n" \
"\tOtheR = thing\n";
cl_git_pass(git_config_open_ondisk(&cfg, filename));
cl_git_pass(git_config_set_string(cfg, "sOMe.ThInG", "foo"));
cl_git_pass(git_config_set_string(cfg, "SomE.OtheR", "thing"));
git_config_free(cfg);
cl_git_pass(git_config_open_ondisk(&cfg, filename));
cl_git_pass(git_futils_readbuffer(&result, filename));
cl_assert_equal_s(expected, result.ptr);
git_buf_dispose(&result);
git_config_free(cfg);
}