diff options
| author | Edward Thomson <ethomson@edwardthomson.com> | 2021-11-16 23:29:22 -0500 |
|---|---|---|
| committer | Edward Thomson <ethomson@edwardthomson.com> | 2022-02-22 22:07:45 -0500 |
| commit | 3344fddc97bbdea9c1b6ebb6f7fb6dbd70b41dfb (patch) | |
| tree | fd6368a72944571c51627b40c592e7d58e0036e1 /tests/libgit2/network | |
| parent | 91ba089663f5efc3bd4ba14a5099372cf5ce57a6 (diff) | |
| download | libgit2-3344fddc97bbdea9c1b6ebb6f7fb6dbd70b41dfb.tar.gz | |
refactor: `tests` is now `tests/libgit2`
Like we want to separate libgit2 and utility source code, we want to
separate libgit2 and utility tests. Start by moving all the tests into
libgit2.
Diffstat (limited to 'tests/libgit2/network')
| -rw-r--r-- | tests/libgit2/network/cred.c | 46 | ||||
| -rw-r--r-- | tests/libgit2/network/fetchlocal.c | 552 | ||||
| -rw-r--r-- | tests/libgit2/network/matchhost.c | 13 | ||||
| -rw-r--r-- | tests/libgit2/network/refspecs.c | 191 | ||||
| -rw-r--r-- | tests/libgit2/network/remote/defaultbranch.c | 107 | ||||
| -rw-r--r-- | tests/libgit2/network/remote/delete.c | 46 | ||||
| -rw-r--r-- | tests/libgit2/network/remote/isvalidname.c | 24 | ||||
| -rw-r--r-- | tests/libgit2/network/remote/local.c | 483 | ||||
| -rw-r--r-- | tests/libgit2/network/remote/push.c | 114 | ||||
| -rw-r--r-- | tests/libgit2/network/remote/remotes.c | 575 | ||||
| -rw-r--r-- | tests/libgit2/network/remote/rename.c | 245 | ||||
| -rw-r--r-- | tests/libgit2/network/url/joinpath.c | 194 | ||||
| -rw-r--r-- | tests/libgit2/network/url/parse.c | 557 | ||||
| -rw-r--r-- | tests/libgit2/network/url/pattern.c | 103 | ||||
| -rw-r--r-- | tests/libgit2/network/url/redirect.c | 147 | ||||
| -rw-r--r-- | tests/libgit2/network/url/scp.c | 321 | ||||
| -rw-r--r-- | tests/libgit2/network/url/valid.c | 17 |
17 files changed, 3735 insertions, 0 deletions
diff --git a/tests/libgit2/network/cred.c b/tests/libgit2/network/cred.c new file mode 100644 index 000000000..5e4db7599 --- /dev/null +++ b/tests/libgit2/network/cred.c @@ -0,0 +1,46 @@ +#include "clar_libgit2.h" + +#include "git2/cred_helpers.h" + +void test_network_cred__stock_userpass_validates_args(void) +{ + git_credential_userpass_payload payload = {0}; + + cl_git_fail(git_credential_userpass(NULL, NULL, NULL, 0, NULL)); + + payload.username = "user"; + cl_git_fail(git_credential_userpass(NULL, NULL, NULL, 0, &payload)); + + payload.username = NULL; + payload.username = "pass"; + cl_git_fail(git_credential_userpass(NULL, NULL, NULL, 0, &payload)); +} + +void test_network_cred__stock_userpass_validates_that_method_is_allowed(void) +{ + git_credential *cred; + git_credential_userpass_payload payload = {"user", "pass"}; + + cl_git_fail(git_credential_userpass(&cred, NULL, NULL, 0, &payload)); + cl_git_pass(git_credential_userpass(&cred, NULL, NULL, GIT_CREDENTIAL_USERPASS_PLAINTEXT, &payload)); + git_credential_free(cred); +} + +void test_network_cred__stock_userpass_properly_handles_username_in_url(void) +{ + git_credential *cred; + git_credential_userpass_payload payload = {"alice", "password"}; + + cl_git_pass(git_credential_userpass(&cred, NULL, NULL, GIT_CREDENTIAL_USERPASS_PLAINTEXT, &payload)); + cl_assert_equal_s("alice", git_credential_get_username(cred)); + git_credential_free(cred); + + cl_git_pass(git_credential_userpass(&cred, NULL, "bob", GIT_CREDENTIAL_USERPASS_PLAINTEXT, &payload)); + cl_assert_equal_s("alice", git_credential_get_username(cred)); + git_credential_free(cred); + + payload.username = NULL; + cl_git_pass(git_credential_userpass(&cred, NULL, "bob", GIT_CREDENTIAL_USERPASS_PLAINTEXT, &payload)); + cl_assert_equal_s("bob", git_credential_get_username(cred)); + git_credential_free(cred); +} diff --git a/tests/libgit2/network/fetchlocal.c b/tests/libgit2/network/fetchlocal.c new file mode 100644 index 000000000..dc37c38ab --- /dev/null +++ b/tests/libgit2/network/fetchlocal.c @@ -0,0 +1,552 @@ +#include "clar_libgit2.h" + +#include "path.h" +#include "remote.h" + +static const char* tagger_name = "Vicent Marti"; +static const char* tagger_email = "vicent@github.com"; +static const char* tagger_message = "This is my tag.\n\nThere are many tags, but this one is mine\n"; + +static int transfer_cb(const git_indexer_progress *stats, void *payload) +{ + int *callcount = (int*)payload; + GIT_UNUSED(stats); + (*callcount)++; + return 0; +} + +static void cleanup_local_repo(void *path) +{ + cl_fixture_cleanup((char *)path); +} + +void test_network_fetchlocal__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_network_fetchlocal__complete(void) +{ + git_repository *repo; + git_remote *origin; + int callcount = 0; + git_strarray refnames = {0}; + + const char *url = cl_git_fixture_url("testrepo.git"); + git_fetch_options options = GIT_FETCH_OPTIONS_INIT; + + options.callbacks.transfer_progress = transfer_cb; + options.callbacks.payload = &callcount; + + cl_set_cleanup(&cleanup_local_repo, "foo"); + cl_git_pass(git_repository_init(&repo, "foo", true)); + + cl_git_pass(git_remote_create(&origin, repo, GIT_REMOTE_ORIGIN, url)); + cl_git_pass(git_remote_fetch(origin, NULL, &options, NULL)); + + cl_git_pass(git_reference_list(&refnames, repo)); + cl_assert_equal_i(20, (int)refnames.count); + cl_assert(callcount > 0); + + git_strarray_dispose(&refnames); + git_remote_free(origin); + git_repository_free(repo); +} + +void test_network_fetchlocal__prune(void) +{ + git_repository *repo; + git_remote *origin; + int callcount = 0; + git_strarray refnames = {0}; + git_reference *ref; + git_repository *remote_repo = cl_git_sandbox_init("testrepo.git"); + const char *url = cl_git_path_url(git_repository_path(remote_repo)); + git_fetch_options options = GIT_FETCH_OPTIONS_INIT; + + options.callbacks.transfer_progress = transfer_cb; + options.callbacks.payload = &callcount; + + cl_set_cleanup(&cleanup_local_repo, "foo"); + cl_git_pass(git_repository_init(&repo, "foo", true)); + + cl_git_pass(git_remote_create(&origin, repo, GIT_REMOTE_ORIGIN, url)); + cl_git_pass(git_remote_fetch(origin, NULL, &options, NULL)); + + cl_git_pass(git_reference_list(&refnames, repo)); + cl_assert_equal_i(20, (int)refnames.count); + cl_assert(callcount > 0); + git_strarray_dispose(&refnames); + git_remote_free(origin); + + cl_git_pass(git_reference_lookup(&ref, remote_repo, "refs/heads/br2")); + cl_git_pass(git_reference_delete(ref)); + git_reference_free(ref); + + cl_git_pass(git_remote_lookup(&origin, repo, GIT_REMOTE_ORIGIN)); + cl_git_pass(git_remote_fetch(origin, NULL, &options, NULL)); + cl_git_pass(git_remote_prune(origin, &options.callbacks)); + + cl_git_pass(git_reference_list(&refnames, repo)); + cl_assert_equal_i(19, (int)refnames.count); + git_strarray_dispose(&refnames); + git_remote_free(origin); + + cl_git_pass(git_reference_lookup(&ref, remote_repo, "refs/heads/packed")); + cl_git_pass(git_reference_delete(ref)); + git_reference_free(ref); + + cl_git_pass(git_remote_lookup(&origin, repo, GIT_REMOTE_ORIGIN)); + cl_git_pass(git_remote_fetch(origin, NULL, &options, NULL)); + cl_git_pass(git_remote_prune(origin, &options.callbacks)); + + cl_git_pass(git_reference_list(&refnames, repo)); + cl_assert_equal_i(18, (int)refnames.count); + git_strarray_dispose(&refnames); + git_remote_free(origin); + + git_repository_free(repo); +} + +static int update_tips_fail_on_call(const char *ref, const git_oid *old, const git_oid *new, void *data) +{ + GIT_UNUSED(ref); + GIT_UNUSED(old); + GIT_UNUSED(new); + GIT_UNUSED(data); + + cl_fail("update tips called"); + return 0; +} + +static void assert_ref_exists(git_repository *repo, const char *name) +{ + git_reference *ref; + + cl_git_pass(git_reference_lookup(&ref, repo, name)); + git_reference_free(ref); +} + +void test_network_fetchlocal__prune_overlapping(void) +{ + git_repository *repo; + git_remote *origin; + int callcount = 0; + git_strarray refnames = {0}; + git_reference *ref; + git_config *config; + git_oid target; + + git_repository *remote_repo = cl_git_sandbox_init("testrepo.git"); + const char *url = cl_git_path_url(git_repository_path(remote_repo)); + + git_fetch_options options = GIT_FETCH_OPTIONS_INIT; + options.callbacks.transfer_progress = transfer_cb; + options.callbacks.payload = &callcount; + + cl_git_pass(git_reference_lookup(&ref, remote_repo, "refs/heads/master")); + git_oid_cpy(&target, git_reference_target(ref)); + git_reference_free(ref); + cl_git_pass(git_reference_create(&ref, remote_repo, "refs/pull/42/head", &target, 1, NULL)); + git_reference_free(ref); + + cl_set_cleanup(&cleanup_local_repo, "foo"); + cl_git_pass(git_repository_init(&repo, "foo", true)); + + cl_git_pass(git_remote_create(&origin, repo, GIT_REMOTE_ORIGIN, url)); + + cl_git_pass(git_repository_config(&config, repo)); + cl_git_pass(git_config_set_bool(config, "remote.origin.prune", true)); + cl_git_pass(git_config_set_multivar(config, "remote.origin.fetch", "^$", "refs/pull/*/head:refs/remotes/origin/pr/*")); + + git_remote_free(origin); + cl_git_pass(git_remote_lookup(&origin, repo, GIT_REMOTE_ORIGIN)); + cl_git_pass(git_remote_fetch(origin, NULL, &options, NULL)); + + assert_ref_exists(repo, "refs/remotes/origin/master"); + assert_ref_exists(repo, "refs/remotes/origin/pr/42"); + cl_git_pass(git_reference_list(&refnames, repo)); + cl_assert_equal_i(21, (int)refnames.count); + git_strarray_dispose(&refnames); + + cl_git_pass(git_config_delete_multivar(config, "remote.origin.fetch", "refs")); + cl_git_pass(git_config_set_multivar(config, "remote.origin.fetch", "^$", "refs/pull/*/head:refs/remotes/origin/pr/*")); + cl_git_pass(git_config_set_multivar(config, "remote.origin.fetch", "^$", "refs/heads/*:refs/remotes/origin/*")); + + git_remote_free(origin); + cl_git_pass(git_remote_lookup(&origin, repo, GIT_REMOTE_ORIGIN)); + options.callbacks.update_tips = update_tips_fail_on_call; + cl_git_pass(git_remote_fetch(origin, NULL, &options, NULL)); + + assert_ref_exists(repo, "refs/remotes/origin/master"); + assert_ref_exists(repo, "refs/remotes/origin/pr/42"); + cl_git_pass(git_reference_list(&refnames, repo)); + cl_assert_equal_i(21, (int)refnames.count); + git_strarray_dispose(&refnames); + + cl_git_pass(git_config_delete_multivar(config, "remote.origin.fetch", "refs")); + cl_git_pass(git_config_set_multivar(config, "remote.origin.fetch", "^$", "refs/heads/*:refs/remotes/origin/*")); + cl_git_pass(git_config_set_multivar(config, "remote.origin.fetch", "^$", "refs/pull/*/head:refs/remotes/origin/pr/*")); + + git_remote_free(origin); + cl_git_pass(git_remote_lookup(&origin, repo, GIT_REMOTE_ORIGIN)); + options.callbacks.update_tips = update_tips_fail_on_call; + cl_git_pass(git_remote_fetch(origin, NULL, &options, NULL)); + + git_config_free(config); + git_strarray_dispose(&refnames); + git_remote_free(origin); + git_repository_free(repo); +} + +void test_network_fetchlocal__fetchprune(void) +{ + git_repository *repo; + git_remote *origin; + int callcount = 0; + git_strarray refnames = {0}; + git_reference *ref; + git_config *config; + git_repository *remote_repo = cl_git_sandbox_init("testrepo.git"); + const char *url = cl_git_path_url(git_repository_path(remote_repo)); + git_fetch_options options = GIT_FETCH_OPTIONS_INIT; + + options.callbacks.transfer_progress = transfer_cb; + options.callbacks.payload = &callcount; + + cl_set_cleanup(&cleanup_local_repo, "foo"); + cl_git_pass(git_repository_init(&repo, "foo", true)); + + cl_git_pass(git_remote_create(&origin, repo, GIT_REMOTE_ORIGIN, url)); + cl_git_pass(git_remote_fetch(origin, NULL, &options, NULL)); + + cl_git_pass(git_reference_list(&refnames, repo)); + cl_assert_equal_i(20, (int)refnames.count); + cl_assert(callcount > 0); + git_strarray_dispose(&refnames); + git_remote_free(origin); + + cl_git_pass(git_reference_lookup(&ref, remote_repo, "refs/heads/br2")); + cl_git_pass(git_reference_delete(ref)); + git_reference_free(ref); + + cl_git_pass(git_remote_lookup(&origin, repo, GIT_REMOTE_ORIGIN)); + cl_git_pass(git_remote_fetch(origin, NULL, &options, NULL)); + cl_git_pass(git_remote_prune(origin, &options.callbacks)); + + cl_git_pass(git_reference_list(&refnames, repo)); + cl_assert_equal_i(19, (int)refnames.count); + git_strarray_dispose(&refnames); + git_remote_free(origin); + + cl_git_pass(git_reference_lookup(&ref, remote_repo, "refs/heads/packed")); + cl_git_pass(git_reference_delete(ref)); + git_reference_free(ref); + + cl_git_pass(git_repository_config(&config, repo)); + cl_git_pass(git_config_set_bool(config, "remote.origin.prune", 1)); + git_config_free(config); + cl_git_pass(git_remote_lookup(&origin, repo, GIT_REMOTE_ORIGIN)); + cl_assert_equal_i(1, git_remote_prune_refs(origin)); + cl_git_pass(git_remote_fetch(origin, NULL, &options, NULL)); + + cl_git_pass(git_reference_list(&refnames, repo)); + cl_assert_equal_i(18, (int)refnames.count); + git_strarray_dispose(&refnames); + git_remote_free(origin); + + git_repository_free(repo); +} + +void test_network_fetchlocal__prune_tag(void) +{ + git_repository *repo; + git_remote *origin; + int callcount = 0; + git_reference *ref; + git_config *config; + git_oid tag_id; + git_signature *tagger; + git_object *obj; + + git_repository *remote_repo = cl_git_sandbox_init("testrepo.git"); + const char *url = cl_git_path_url(git_repository_path(remote_repo)); + git_fetch_options options = GIT_FETCH_OPTIONS_INIT; + + options.callbacks.transfer_progress = transfer_cb; + options.callbacks.payload = &callcount; + + cl_set_cleanup(&cleanup_local_repo, "foo"); + cl_git_pass(git_repository_init(&repo, "foo", true)); + + cl_git_pass(git_remote_create(&origin, repo, GIT_REMOTE_ORIGIN, url)); + cl_git_pass(git_remote_fetch(origin, NULL, &options, NULL)); + git_remote_free(origin); + + cl_git_pass(git_revparse_single(&obj, repo, "origin/master")); + + cl_git_pass(git_reference_create(&ref, repo, "refs/remotes/origin/fake-remote", git_object_id(obj), 1, NULL)); + git_reference_free(ref); + + /* create signature */ + cl_git_pass(git_signature_new(&tagger, tagger_name, tagger_email, 123456789, 60)); + + cl_git_pass( + git_tag_create(&tag_id, repo, + "some-tag", obj, tagger, tagger_message, 0) + ); + git_signature_free(tagger); + + cl_git_pass(git_repository_config(&config, repo)); + cl_git_pass(git_config_set_bool(config, "remote.origin.prune", 1)); + git_config_free(config); + cl_git_pass(git_remote_lookup(&origin, repo, GIT_REMOTE_ORIGIN)); + cl_assert_equal_i(1, git_remote_prune_refs(origin)); + cl_git_pass(git_remote_fetch(origin, NULL, &options, NULL)); + + assert_ref_exists(repo, "refs/tags/some-tag"); + cl_git_fail_with(GIT_ENOTFOUND, git_reference_lookup(&ref, repo, "refs/remotes/origin/fake-remote")); + + git_object_free(obj); + git_remote_free(origin); + + git_repository_free(repo); +} + +void test_network_fetchlocal__partial(void) +{ + git_repository *repo = cl_git_sandbox_init("partial-testrepo"); + git_remote *origin; + int callcount = 0; + git_strarray refnames = {0}; + const char *url; + git_fetch_options options = GIT_FETCH_OPTIONS_INIT; + + options.callbacks.transfer_progress = transfer_cb; + options.callbacks.payload = &callcount; + + cl_git_pass(git_reference_list(&refnames, repo)); + cl_assert_equal_i(1, (int)refnames.count); + + url = cl_git_fixture_url("testrepo.git"); + cl_git_pass(git_remote_create(&origin, repo, GIT_REMOTE_ORIGIN, url)); + cl_git_pass(git_remote_fetch(origin, NULL, &options, NULL)); + + git_strarray_dispose(&refnames); + + cl_git_pass(git_reference_list(&refnames, repo)); + cl_assert_equal_i(21, (int)refnames.count); /* 18 remote + 1 local */ + cl_assert(callcount > 0); + + git_strarray_dispose(&refnames); + git_remote_free(origin); +} + +static int remote_mirror_cb(git_remote **out, git_repository *repo, + const char *name, const char *url, void *payload) +{ + int error; + git_remote *remote; + + GIT_UNUSED(payload); + + if ((error = git_remote_create_with_fetchspec(&remote, repo, name, url, "+refs/*:refs/*")) < 0) + return error; + + *out = remote; + return 0; +} + +void test_network_fetchlocal__clone_into_mirror(void) +{ + git_clone_options opts = GIT_CLONE_OPTIONS_INIT; + git_repository *repo; + git_reference *ref; + + opts.bare = true; + opts.remote_cb = remote_mirror_cb; + cl_git_pass(git_clone(&repo, cl_git_fixture_url("testrepo.git"), "./foo.git", &opts)); + + cl_git_pass(git_reference_lookup(&ref, repo, "HEAD")); + cl_assert_equal_i(GIT_REFERENCE_SYMBOLIC, git_reference_type(ref)); + cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(ref)); + + git_reference_free(ref); + cl_git_pass(git_reference_lookup(&ref, repo, "refs/remotes/test/master")); + + git_reference_free(ref); + git_repository_free(repo); + cl_fixture_cleanup("./foo.git"); +} + +void test_network_fetchlocal__all_refs(void) +{ + git_repository *repo; + git_remote *remote; + git_reference *ref; + char *allrefs = "+refs/*:refs/*"; + git_strarray refspecs = { + &allrefs, + 1, + }; + + cl_git_pass(git_repository_init(&repo, "./foo.git", true)); + cl_git_pass(git_remote_create_anonymous(&remote, repo, cl_git_fixture_url("testrepo.git"))); + cl_git_pass(git_remote_fetch(remote, &refspecs, NULL, NULL)); + + cl_git_pass(git_reference_lookup(&ref, repo, "refs/remotes/test/master")); + git_reference_free(ref); + + cl_git_pass(git_reference_lookup(&ref, repo, "refs/tags/test")); + git_reference_free(ref); + + git_remote_free(remote); + git_repository_free(repo); + cl_fixture_cleanup("./foo.git"); +} + +void test_network_fetchlocal__multi_remotes(void) +{ + git_repository *repo = cl_git_sandbox_init("testrepo.git"); + git_remote *test, *test2; + git_strarray refnames = {0}; + git_fetch_options options = GIT_FETCH_OPTIONS_INIT; + + options.callbacks.transfer_progress = transfer_cb; + cl_git_pass(git_remote_set_url(repo, "test", cl_git_fixture_url("testrepo.git"))); + cl_git_pass(git_remote_lookup(&test, repo, "test")); + cl_git_pass(git_remote_fetch(test, NULL, &options, NULL)); + + cl_git_pass(git_reference_list(&refnames, repo)); + cl_assert_equal_i(35, (int)refnames.count); + git_strarray_dispose(&refnames); + + cl_git_pass(git_remote_set_url(repo, "test_with_pushurl", cl_git_fixture_url("testrepo.git"))); + cl_git_pass(git_remote_lookup(&test2, repo, "test_with_pushurl")); + cl_git_pass(git_remote_fetch(test2, NULL, &options, NULL)); + + cl_git_pass(git_reference_list(&refnames, repo)); + cl_assert_equal_i(48, (int)refnames.count); + + git_strarray_dispose(&refnames); + git_remote_free(test); + git_remote_free(test2); +} + +static int sideband_cb(const char *str, int len, void *payload) +{ + int *count = (int *) payload; + + GIT_UNUSED(str); + GIT_UNUSED(len); + + (*count)++; + return 0; +} + +void test_network_fetchlocal__call_progress(void) +{ + git_repository *repo; + git_remote *remote; + git_fetch_options options = GIT_FETCH_OPTIONS_INIT; + int callcount = 0; + + cl_git_pass(git_repository_init(&repo, "foo.git", true)); + cl_set_cleanup(cleanup_local_repo, "foo.git"); + + cl_git_pass(git_remote_create_with_fetchspec(&remote, repo, "origin", cl_git_fixture_url("testrepo.git"), "+refs/heads/*:refs/heads/*")); + + options.callbacks.sideband_progress = sideband_cb; + options.callbacks.payload = &callcount; + + cl_git_pass(git_remote_fetch(remote, NULL, &options, NULL)); + cl_assert(callcount != 0); + + git_remote_free(remote); + git_repository_free(repo); +} + +void test_network_fetchlocal__prune_load_remote_prune_config(void) +{ + git_repository *repo; + git_remote *origin; + git_config *config; + git_repository *remote_repo = cl_git_sandbox_init("testrepo.git"); + const char *url = cl_git_path_url(git_repository_path(remote_repo)); + + cl_set_cleanup(&cleanup_local_repo, "foo"); + cl_git_pass(git_repository_init(&repo, "foo", true)); + + cl_git_pass(git_repository_config(&config, repo)); + cl_git_pass(git_config_set_bool(config, "remote.origin.prune", 1)); + + cl_git_pass(git_remote_create(&origin, repo, GIT_REMOTE_ORIGIN, url)); + cl_assert_equal_i(1, git_remote_prune_refs(origin)); + + git_config_free(config); + git_remote_free(origin); + git_repository_free(repo); +} + +void test_network_fetchlocal__prune_load_fetch_prune_config(void) +{ + git_repository *repo; + git_remote *origin; + git_config *config; + git_repository *remote_repo = cl_git_sandbox_init("testrepo.git"); + const char *url = cl_git_path_url(git_repository_path(remote_repo)); + + cl_set_cleanup(&cleanup_local_repo, "foo"); + cl_git_pass(git_repository_init(&repo, "foo", true)); + + cl_git_pass(git_repository_config(&config, repo)); + cl_git_pass(git_config_set_bool(config, "fetch.prune", 1)); + + cl_git_pass(git_remote_create(&origin, repo, GIT_REMOTE_ORIGIN, url)); + cl_assert_equal_i(1, git_remote_prune_refs(origin)); + + git_config_free(config); + git_remote_free(origin); + git_repository_free(repo); +} + +static int update_tips_error(const char *ref, const git_oid *old, const git_oid *new, void *data) +{ + int *callcount = (int *) data; + + GIT_UNUSED(ref); + GIT_UNUSED(old); + GIT_UNUSED(new); + + (*callcount)++; + + return -1; +} + +void test_network_fetchlocal__update_tips_error_is_propagated(void) +{ + git_repository *repo; + git_reference_iterator *iterator; + git_reference *ref; + git_remote *remote; + git_fetch_options options = GIT_FETCH_OPTIONS_INIT; + int callcount = 0; + + cl_git_pass(git_repository_init(&repo, "foo.git", true)); + cl_set_cleanup(cleanup_local_repo, "foo.git"); + + cl_git_pass(git_remote_create_with_fetchspec(&remote, repo, "origin", cl_git_fixture_url("testrepo.git"), "+refs/heads/*:refs/remotes/update-tips/*")); + + options.callbacks.update_tips = update_tips_error; + options.callbacks.payload = &callcount; + + cl_git_fail(git_remote_fetch(remote, NULL, &options, NULL)); + cl_assert_equal_i(1, callcount); + + cl_git_pass(git_reference_iterator_glob_new(&iterator, repo, "refs/remotes/update-tips/**/")); + cl_assert_equal_i(GIT_ITEROVER, git_reference_next(&ref, iterator)); + + git_reference_iterator_free(iterator); + git_remote_free(remote); + git_repository_free(repo); +} diff --git a/tests/libgit2/network/matchhost.c b/tests/libgit2/network/matchhost.c new file mode 100644 index 000000000..3100dc21d --- /dev/null +++ b/tests/libgit2/network/matchhost.c @@ -0,0 +1,13 @@ +#include "clar_libgit2.h" +#include "netops.h" + +void test_network_matchhost__match(void) +{ + cl_git_pass(gitno__match_host("*.example.org", "www.example.org")); + cl_git_pass(gitno__match_host("*.foo.example.org", "www.foo.example.org")); + cl_git_fail(gitno__match_host("*.foo.example.org", "foo.example.org")); + cl_git_fail(gitno__match_host("*.foo.example.org", "www.example.org")); + cl_git_fail(gitno__match_host("*.example.org", "example.org")); + cl_git_fail(gitno__match_host("*.example.org", "www.foo.example.org")); + cl_git_fail(gitno__match_host("*.example.org", "blah.www.www.example.org")); +} diff --git a/tests/libgit2/network/refspecs.c b/tests/libgit2/network/refspecs.c new file mode 100644 index 000000000..d9e0d9e8d --- /dev/null +++ b/tests/libgit2/network/refspecs.c @@ -0,0 +1,191 @@ +#include "clar_libgit2.h" +#include "refspec.h" +#include "remote.h" + +static void assert_refspec(unsigned int direction, const char *input, bool is_expected_to_be_valid) +{ + git_refspec refspec; + int error; + + error = git_refspec__parse(&refspec, input, direction == GIT_DIRECTION_FETCH); + git_refspec__dispose(&refspec); + + if (is_expected_to_be_valid) + cl_assert_equal_i(0, error); + else + cl_assert_equal_i(GIT_EINVALIDSPEC, error); +} + +void test_network_refspecs__parsing(void) +{ + /* Ported from https://github.com/git/git/blob/abd2bde78bd994166900290434a2048e660dabed/t/t5511-refspec.sh */ + + assert_refspec(GIT_DIRECTION_PUSH, "", false); + assert_refspec(GIT_DIRECTION_PUSH, ":", true); + assert_refspec(GIT_DIRECTION_PUSH, "::", false); + assert_refspec(GIT_DIRECTION_PUSH, "+:", true); + + assert_refspec(GIT_DIRECTION_FETCH, "", true); + assert_refspec(GIT_DIRECTION_PUSH, ":", true); + assert_refspec(GIT_DIRECTION_FETCH, "::", false); + + assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*:refs/remotes/frotz/*", true); + assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*:refs/remotes/frotz", false); + assert_refspec(GIT_DIRECTION_PUSH, "refs/heads:refs/remotes/frotz/*", false); + assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/master:refs/remotes/frotz/xyzzy", true); + + /* + * These have invalid LHS, but we do not have a formal "valid sha-1 + * expression syntax checker" so they are not checked with the current + * code. They will be caught downstream anyway, but we may want to + * have tighter check later... + */ + /*assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/master::refs/remotes/frotz/xyzzy", false); */ + /*assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/maste :refs/remotes/frotz/xyzzy", false); */ + + assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*:refs/remotes/frotz/*", true); + assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*:refs/remotes/frotz", false); + assert_refspec(GIT_DIRECTION_FETCH, "refs/heads:refs/remotes/frotz/*", false); + assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/master:refs/remotes/frotz/xyzzy", true); + assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/master::refs/remotes/frotz/xyzzy", false); + assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/maste :refs/remotes/frotz/xyzzy", false); + + assert_refspec(GIT_DIRECTION_PUSH, "master~1:refs/remotes/frotz/backup", true); + assert_refspec(GIT_DIRECTION_FETCH, "master~1:refs/remotes/frotz/backup", false); + assert_refspec(GIT_DIRECTION_PUSH, "HEAD~4:refs/remotes/frotz/new", true); + assert_refspec(GIT_DIRECTION_FETCH, "HEAD~4:refs/remotes/frotz/new", false); + + assert_refspec(GIT_DIRECTION_PUSH, "HEAD", true); + assert_refspec(GIT_DIRECTION_FETCH, "HEAD", true); + assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/ nitfol", false); + assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/ nitfol", false); + + assert_refspec(GIT_DIRECTION_PUSH, "HEAD:", false); + assert_refspec(GIT_DIRECTION_FETCH, "HEAD:", true); + assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/ nitfol:", false); + assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/ nitfol:", false); + + assert_refspec(GIT_DIRECTION_PUSH, ":refs/remotes/frotz/deleteme", true); + assert_refspec(GIT_DIRECTION_FETCH, ":refs/remotes/frotz/HEAD-to-me", true); + assert_refspec(GIT_DIRECTION_PUSH, ":refs/remotes/frotz/delete me", false); + assert_refspec(GIT_DIRECTION_FETCH, ":refs/remotes/frotz/HEAD to me", false); + + assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*/for-linus:refs/remotes/mine/*-blah", true); + assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*/for-linus:refs/remotes/mine/*-blah", true); + + assert_refspec(GIT_DIRECTION_FETCH, "refs/heads*/for-linus:refs/remotes/mine/*", true); + assert_refspec(GIT_DIRECTION_PUSH, "refs/heads*/for-linus:refs/remotes/mine/*", true); + + assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*/*/for-linus:refs/remotes/mine/*", false); + assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*/*/for-linus:refs/remotes/mine/*", false); + + assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*g*/for-linus:refs/remotes/mine/*", false); + assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*g*/for-linus:refs/remotes/mine/*", false); + + assert_refspec(GIT_DIRECTION_FETCH, "refs/heads/*/for-linus:refs/remotes/mine/*", true); + assert_refspec(GIT_DIRECTION_PUSH, "refs/heads/*/for-linus:refs/remotes/mine/*", true); + + assert_refspec(GIT_DIRECTION_FETCH, "master", true); + assert_refspec(GIT_DIRECTION_PUSH, "master", true); + + assert_refspec(GIT_DIRECTION_FETCH, "refs/pull/*/head:refs/remotes/origin/pr/*", true); +} + +static void assert_valid_transform(const char *refspec, const char *name, const char *result) +{ + git_refspec spec; + git_buf buf = GIT_BUF_INIT; + + cl_git_pass(git_refspec__parse(&spec, refspec, true)); + cl_git_pass(git_refspec_transform(&buf, &spec, name)); + cl_assert_equal_s(result, buf.ptr); + + git_buf_dispose(&buf); + git_refspec__dispose(&spec); +} + +void test_network_refspecs__transform_mid_star(void) +{ + assert_valid_transform("refs/pull/*/head:refs/remotes/origin/pr/*", "refs/pull/23/head", "refs/remotes/origin/pr/23"); + assert_valid_transform("refs/heads/*:refs/remotes/origin/*", "refs/heads/master", "refs/remotes/origin/master"); + assert_valid_transform("refs/heads/*:refs/remotes/origin/*", "refs/heads/user/feature", "refs/remotes/origin/user/feature"); + assert_valid_transform("refs/heads/*:refs/heads/*", "refs/heads/master", "refs/heads/master"); + assert_valid_transform("refs/heads/*:refs/heads/*", "refs/heads/user/feature", "refs/heads/user/feature"); + assert_valid_transform("refs/*:refs/*", "refs/heads/master", "refs/heads/master"); +} + +void test_network_refspecs__transform_loosened_star(void) +{ + assert_valid_transform("refs/heads/branch-*:refs/remotes/origin/branch-*", "refs/heads/branch-a", "refs/remotes/origin/branch-a"); + assert_valid_transform("refs/heads/branch-*/head:refs/remotes/origin/branch-*/head", "refs/heads/branch-a/head", "refs/remotes/origin/branch-a/head"); +} + +void test_network_refspecs__transform_nested_star(void) +{ + assert_valid_transform("refs/heads/x*x/for-linus:refs/remotes/mine/*", "refs/heads/xbranchx/for-linus", "refs/remotes/mine/branch"); +} + +void test_network_refspecs__no_dst(void) +{ + assert_valid_transform("refs/heads/master:", "refs/heads/master", ""); +} + +static void assert_invalid_transform(const char *refspec, const char *name) +{ + git_refspec spec; + git_buf buf = GIT_BUF_INIT; + + git_refspec__parse(&spec, refspec, true); + cl_git_fail(git_refspec_transform(&buf, &spec, name)); + + git_buf_dispose(&buf); + git_refspec__dispose(&spec); +} + +void test_network_refspecs__invalid(void) +{ + assert_invalid_transform("refs/heads/*:refs/remotes/origin/*", "master"); + assert_invalid_transform("refs/heads/*:refs/remotes/origin/*", "refs/headz/master"); +} + +static void assert_invalid_rtransform(const char *refspec, const char *name) +{ + git_refspec spec; + git_buf buf = GIT_BUF_INIT; + + cl_git_pass(git_refspec__parse(&spec, refspec, true)); + cl_git_fail(git_refspec_rtransform(&buf, &spec, name)); + + git_buf_dispose(&buf); + git_refspec__dispose(&spec); +} + +void test_network_refspecs__invalid_reverse(void) +{ + assert_invalid_rtransform("refs/heads/*:refs/remotes/origin/*", "master"); + assert_invalid_rtransform("refs/heads/*:refs/remotes/origin/*", "refs/remotes/o/master"); +} + +void test_network_refspecs__matching(void) +{ + git_refspec spec; + + cl_git_pass(git_refspec__parse(&spec, ":", false)); + cl_assert_equal_s(":", spec.string); + cl_assert_equal_s("", spec.src); + cl_assert_equal_s("", spec.dst); + + git_refspec__dispose(&spec); +} + +void test_network_refspecs__parse_free(void) +{ + git_refspec *spec = NULL; + + cl_git_fail(git_refspec_parse(&spec, "", 0)); + cl_git_fail(git_refspec_parse(&spec, ":::", 0)); + cl_git_pass(git_refspec_parse(&spec, "HEAD:", 1)); + + cl_assert(spec != NULL); + git_refspec_free(spec); +} diff --git a/tests/libgit2/network/remote/defaultbranch.c b/tests/libgit2/network/remote/defaultbranch.c new file mode 100644 index 000000000..a7c0d81f6 --- /dev/null +++ b/tests/libgit2/network/remote/defaultbranch.c @@ -0,0 +1,107 @@ +#include "clar_libgit2.h" +#include "refspec.h" +#include "remote.h" + +static git_remote *g_remote; +static git_repository *g_repo_a, *g_repo_b; + +void test_network_remote_defaultbranch__initialize(void) +{ + g_repo_a = cl_git_sandbox_init("testrepo.git"); + cl_git_pass(git_repository_init(&g_repo_b, "repo-b.git", true)); + cl_git_pass(git_remote_create(&g_remote, g_repo_b, "origin", git_repository_path(g_repo_a))); +} + +void test_network_remote_defaultbranch__cleanup(void) +{ + git_remote_free(g_remote); + git_repository_free(g_repo_b); + + cl_git_sandbox_cleanup(); + cl_fixture_cleanup("repo-b.git"); +} + +static void assert_default_branch(const char *should) +{ + git_buf name = GIT_BUF_INIT; + + cl_git_pass(git_remote_connect(g_remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL)); + cl_git_pass(git_remote_default_branch(&name, g_remote)); + cl_assert_equal_s(should, name.ptr); + git_buf_dispose(&name); +} + +void test_network_remote_defaultbranch__master(void) +{ + assert_default_branch("refs/heads/master"); +} + +void test_network_remote_defaultbranch__master_does_not_win(void) +{ + cl_git_pass(git_repository_set_head(g_repo_a, "refs/heads/not-good")); + assert_default_branch("refs/heads/not-good"); +} + +void test_network_remote_defaultbranch__master_on_detached(void) +{ + cl_git_pass(git_repository_detach_head(g_repo_a)); + assert_default_branch("refs/heads/master"); +} + +void test_network_remote_defaultbranch__no_default_branch(void) +{ + git_remote *remote_b; + const git_remote_head **heads; + size_t len; + git_buf buf = GIT_BUF_INIT; + + cl_git_pass(git_remote_create(&remote_b, g_repo_b, "self", git_repository_path(g_repo_b))); + cl_git_pass(git_remote_connect(remote_b, GIT_DIRECTION_FETCH, NULL, NULL, NULL)); + cl_git_pass(git_remote_ls(&heads, &len, remote_b)); + cl_assert_equal_i(0, len); + + cl_git_fail_with(GIT_ENOTFOUND, git_remote_default_branch(&buf, remote_b)); + + git_remote_free(remote_b); +} + +void test_network_remote_defaultbranch__detached_sharing_nonbranch_id(void) +{ + git_oid id, id_cloned; + git_reference *ref; + git_buf buf = GIT_BUF_INIT; + git_repository *cloned_repo; + + cl_git_pass(git_reference_name_to_id(&id, g_repo_a, "HEAD")); + cl_git_pass(git_repository_detach_head(g_repo_a)); + cl_git_pass(git_reference_remove(g_repo_a, "refs/heads/master")); + cl_git_pass(git_reference_remove(g_repo_a, "refs/heads/not-good")); + cl_git_pass(git_reference_create(&ref, g_repo_a, "refs/foo/bar", &id, 1, NULL)); + git_reference_free(ref); + + cl_git_pass(git_remote_connect(g_remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL)); + cl_git_fail_with(GIT_ENOTFOUND, git_remote_default_branch(&buf, g_remote)); + + cl_git_pass(git_clone(&cloned_repo, git_repository_path(g_repo_a), "./local-detached", NULL)); + + cl_assert(git_repository_head_detached(cloned_repo)); + cl_git_pass(git_reference_name_to_id(&id_cloned, g_repo_a, "HEAD")); + cl_assert(git_oid_equal(&id, &id_cloned)); + + git_repository_free(cloned_repo); +} + +void test_network_remote_defaultbranch__unborn_HEAD_with_branches(void) +{ + git_reference *ref; + git_repository *cloned_repo; + + cl_git_pass(git_reference_symbolic_create(&ref, g_repo_a, "HEAD", "refs/heads/i-dont-exist", 1, NULL)); + git_reference_free(ref); + + cl_git_pass(git_clone(&cloned_repo, git_repository_path(g_repo_a), "./semi-empty", NULL)); + + cl_assert(git_repository_head_unborn(cloned_repo)); + + git_repository_free(cloned_repo); +} diff --git a/tests/libgit2/network/remote/delete.c b/tests/libgit2/network/remote/delete.c new file mode 100644 index 000000000..f23a638aa --- /dev/null +++ b/tests/libgit2/network/remote/delete.c @@ -0,0 +1,46 @@ +#include "clar_libgit2.h" +#include "config/config_helpers.h" + +#include "repository.h" + +static git_repository *_repo; + +void test_network_remote_delete__initialize(void) +{ + _repo = cl_git_sandbox_init("testrepo.git"); +} + +void test_network_remote_delete__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_network_remote_delete__remove_remote_tracking_branches(void) +{ + git_reference *ref; + + cl_git_pass(git_remote_delete(_repo, "test")); + cl_git_fail_with(GIT_ENOTFOUND, git_reference_lookup(&ref, _repo, "refs/remotes/test/master")); +} + +void test_network_remote_delete__remove_remote_configuration_settings(void) +{ + cl_assert(count_config_entries_match(_repo, "remote\\.test\\.+") > 0); + + cl_git_pass(git_remote_delete(_repo, "test")); + + cl_assert_equal_i(0, count_config_entries_match(_repo, "remote\\.test\\.+")); +} + +void test_network_remote_delete__remove_branch_upstream_configuration_settings(void) +{ + assert_config_entry_existence(_repo, "branch.mergeless.remote", true); + assert_config_entry_existence(_repo, "branch.master.remote", true); + + cl_git_pass(git_remote_delete(_repo, "test")); + + assert_config_entry_existence(_repo, "branch.mergeless.remote", false); + assert_config_entry_existence(_repo, "branch.mergeless.merge", false); + assert_config_entry_existence(_repo, "branch.master.remote", false); + assert_config_entry_existence(_repo, "branch.master.merge", false); +} diff --git a/tests/libgit2/network/remote/isvalidname.c b/tests/libgit2/network/remote/isvalidname.c new file mode 100644 index 000000000..a3080f67c --- /dev/null +++ b/tests/libgit2/network/remote/isvalidname.c @@ -0,0 +1,24 @@ +#include "clar_libgit2.h" + +static int is_valid_name(const char *name) +{ + int valid = 0; + cl_git_pass(git_remote_name_is_valid(&valid, name)); + return valid; +} + +void test_network_remote_isvalidname__can_detect_invalid_formats(void) +{ + cl_assert_equal_i(false, is_valid_name("/")); + cl_assert_equal_i(false, is_valid_name("//")); + cl_assert_equal_i(false, is_valid_name(".lock")); + cl_assert_equal_i(false, is_valid_name("a.lock")); + cl_assert_equal_i(false, is_valid_name("/no/leading/slash")); + cl_assert_equal_i(false, is_valid_name("no/trailing/slash/")); +} + +void test_network_remote_isvalidname__wont_hopefully_choke_on_valid_formats(void) +{ + cl_assert_equal_i(true, is_valid_name("webmatrix")); + cl_assert_equal_i(true, is_valid_name("yishaigalatzer/rules")); +} diff --git a/tests/libgit2/network/remote/local.c b/tests/libgit2/network/remote/local.c new file mode 100644 index 000000000..2007f3776 --- /dev/null +++ b/tests/libgit2/network/remote/local.c @@ -0,0 +1,483 @@ +#include "clar_libgit2.h" +#include "path.h" +#include "posix.h" +#include "git2/sys/repository.h" + +static git_repository *repo; +static git_str file_path_buf = GIT_STR_INIT; +static git_remote *remote; + +static char *push_refspec_strings[] = { + "refs/heads/master", +}; +static git_strarray push_array = { + push_refspec_strings, + 1, +}; + +void test_network_remote_local__initialize(void) +{ + cl_git_pass(git_repository_init(&repo, "remotelocal/", 0)); + cl_git_pass(git_repository_set_ident(repo, "Foo Bar", "foo@example.com")); + cl_assert(repo != NULL); +} + +void test_network_remote_local__cleanup(void) +{ + git_str_dispose(&file_path_buf); + + git_remote_free(remote); + remote = NULL; + + git_repository_free(repo); + repo = NULL; + + cl_fixture_cleanup("remotelocal"); +} + +static void connect_to_local_repository(const char *local_repository) +{ + git_str_sets(&file_path_buf, cl_git_path_url(local_repository)); + + cl_git_pass(git_remote_create_anonymous(&remote, repo, git_str_cstr(&file_path_buf))); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL)); +} + +void test_network_remote_local__connected(void) +{ + connect_to_local_repository(cl_fixture("testrepo.git")); + cl_assert(git_remote_connected(remote)); + + git_remote_disconnect(remote); + cl_assert(!git_remote_connected(remote)); +} + +void test_network_remote_local__retrieve_advertised_references(void) +{ + const git_remote_head **refs; + size_t refs_len; + + connect_to_local_repository(cl_fixture("testrepo.git")); + + cl_git_pass(git_remote_ls(&refs, &refs_len, remote)); + + cl_assert_equal_i(refs_len, 30); +} + +void test_network_remote_local__retrieve_advertised_before_connect(void) +{ + const git_remote_head **refs; + size_t refs_len = 0; + + git_str_sets(&file_path_buf, cl_git_path_url(cl_fixture("testrepo.git"))); + + cl_git_pass(git_remote_create_anonymous(&remote, repo, git_str_cstr(&file_path_buf))); + cl_git_fail(git_remote_ls(&refs, &refs_len, remote)); +} + +void test_network_remote_local__retrieve_advertised_references_after_disconnect(void) +{ + const git_remote_head **refs; + size_t refs_len; + + connect_to_local_repository(cl_fixture("testrepo.git")); + git_remote_disconnect(remote); + + cl_git_pass(git_remote_ls(&refs, &refs_len, remote)); + + cl_assert_equal_i(refs_len, 30); +} + +void test_network_remote_local__retrieve_advertised_references_from_spaced_repository(void) +{ + const git_remote_head **refs; + size_t refs_len; + + cl_fixture_sandbox("testrepo.git"); + cl_git_pass(p_rename("testrepo.git", "spaced testrepo.git")); + + connect_to_local_repository("spaced testrepo.git"); + + cl_git_pass(git_remote_ls(&refs, &refs_len, remote)); + + cl_assert_equal_i(refs_len, 30); + + git_remote_free(remote); /* Disconnect from the "spaced repo" before the cleanup */ + remote = NULL; + + cl_fixture_cleanup("spaced testrepo.git"); +} + +void test_network_remote_local__nested_tags_are_completely_peeled(void) +{ + const git_remote_head **refs; + size_t refs_len, i; + + connect_to_local_repository(cl_fixture("testrepo.git")); + + cl_git_pass(git_remote_ls(&refs, &refs_len, remote)); + + for (i = 0; i < refs_len; i++) { + if (!strcmp(refs[i]->name, "refs/tags/test^{}")) + cl_git_pass(git_oid_streq(&refs[i]->oid, "e90810b8df3e80c413d903f631643c716887138d")); + } +} + +void test_network_remote_local__shorthand_fetch_refspec0(void) +{ + char *refspec_strings[] = { + "master:remotes/sloppy/master", + "master:boh/sloppy/master", + }; + git_strarray array = { + refspec_strings, + 2, + }; + + git_reference *ref; + + connect_to_local_repository(cl_fixture("testrepo.git")); + + cl_git_pass(git_remote_fetch(remote, &array, NULL, NULL)); + + cl_git_pass(git_reference_lookup(&ref, repo, "refs/remotes/sloppy/master")); + git_reference_free(ref); + + cl_git_pass(git_reference_lookup(&ref, repo, "refs/heads/boh/sloppy/master")); + git_reference_free(ref); +} + +void test_network_remote_local__shorthand_fetch_refspec1(void) +{ + char *refspec_strings[] = { + "master", + "hard_tag", + }; + git_strarray array = { + refspec_strings, + 2, + }; + + git_reference *ref; + + connect_to_local_repository(cl_fixture("testrepo.git")); + + cl_git_pass(git_remote_fetch(remote, &array, NULL, NULL)); + + cl_git_fail(git_reference_lookup(&ref, repo, "refs/remotes/origin/master")); + cl_git_fail(git_reference_lookup(&ref, repo, "refs/tags/hard_tag")); +} + +void test_network_remote_local__tagopt(void) +{ + git_reference *ref; + git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT; + + cl_git_pass(git_remote_create(&remote, repo, "tagopt", cl_git_path_url(cl_fixture("testrepo.git")))); + fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL; + cl_git_pass(git_remote_fetch(remote, NULL, &fetch_opts, NULL)); + + cl_git_pass(git_reference_lookup(&ref, repo, "refs/remotes/tagopt/master")); + git_reference_free(ref); + cl_git_pass(git_reference_lookup(&ref, repo, "refs/tags/hard_tag")); + git_reference_free(ref); + + fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_AUTO; + cl_git_pass(git_remote_fetch(remote, NULL, &fetch_opts, NULL)); + cl_git_pass(git_reference_lookup(&ref, repo, "refs/remotes/tagopt/master")); + git_reference_free(ref); +} + +void test_network_remote_local__push_to_bare_remote(void) +{ + char *refspec_strings[] = { + "master:master", + }; + git_strarray array = { + refspec_strings, + 1, + }; + + /* Should be able to push to a bare remote */ + git_remote *localremote; + + /* Get some commits */ + connect_to_local_repository(cl_fixture("testrepo.git")); + cl_git_pass(git_remote_fetch(remote, &array, NULL, NULL)); + + /* Set up an empty bare repo to push into */ + { + git_repository *localbarerepo; + cl_git_pass(git_repository_init(&localbarerepo, "./localbare.git", 1)); + git_repository_free(localbarerepo); + } + + /* Connect to the bare repo */ + cl_git_pass(git_remote_create_anonymous(&localremote, repo, "./localbare.git")); + cl_git_pass(git_remote_connect(localremote, GIT_DIRECTION_PUSH, NULL, NULL, NULL)); + + /* Try to push */ + cl_git_pass(git_remote_upload(localremote, &push_array, NULL)); + + /* Clean up */ + git_remote_free(localremote); + cl_fixture_cleanup("localbare.git"); +} + +void test_network_remote_local__push_to_bare_remote_with_file_url(void) +{ + char *refspec_strings[] = { + "master:master", + }; + git_strarray array = { + refspec_strings, + 1, + }; + /* Should be able to push to a bare remote */ + git_remote *localremote; + const char *url; + + /* Get some commits */ + connect_to_local_repository(cl_fixture("testrepo.git")); + cl_git_pass(git_remote_fetch(remote, &array, NULL, NULL)); + + /* Set up an empty bare repo to push into */ + { + git_repository *localbarerepo; + cl_git_pass(git_repository_init(&localbarerepo, "./localbare.git", 1)); + git_repository_free(localbarerepo); + } + + /* Create a file URL */ + url = cl_git_path_url("./localbare.git"); + + /* Connect to the bare repo */ + cl_git_pass(git_remote_create_anonymous(&localremote, repo, url)); + cl_git_pass(git_remote_connect(localremote, GIT_DIRECTION_PUSH, NULL, NULL, NULL)); + + /* Try to push */ + cl_git_pass(git_remote_upload(localremote, &push_array, NULL)); + + /* Clean up */ + git_remote_free(localremote); + cl_fixture_cleanup("localbare.git"); +} + + +void test_network_remote_local__push_to_non_bare_remote(void) +{ + char *refspec_strings[] = { + "master:master", + }; + git_strarray array = { + refspec_strings, + 1, + }; + /* Shouldn't be able to push to a non-bare remote */ + git_remote *localremote; + git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT; + + /* Get some commits */ + connect_to_local_repository(cl_fixture("testrepo.git")); + cl_git_pass(git_remote_fetch(remote, &array, &fetch_opts, NULL)); + + /* Set up an empty non-bare repo to push into */ + { + git_repository *remoterepo = NULL; + cl_git_pass(git_repository_init(&remoterepo, "localnonbare", 0)); + git_repository_free(remoterepo); + } + + /* Connect to the bare repo */ + cl_git_pass(git_remote_create_anonymous(&localremote, repo, "./localnonbare")); + cl_git_pass(git_remote_connect(localremote, GIT_DIRECTION_PUSH, NULL, NULL, NULL)); + + /* Try to push */ + cl_git_fail_with(GIT_EBAREREPO, git_remote_upload(localremote, &push_array, NULL)); + + /* Clean up */ + git_remote_free(localremote); + cl_fixture_cleanup("localbare.git"); +} + +void test_network_remote_local__fetch(void) +{ + char *refspec_strings[] = { + "master:remotes/sloppy/master", + }; + git_strarray array = { + refspec_strings, + 1, + }; + + git_reflog *log; + const git_reflog_entry *entry; + git_reference *ref; + + connect_to_local_repository(cl_fixture("testrepo.git")); + + cl_git_pass(git_remote_fetch(remote, &array, NULL, "UPDAAAAAATE!!")); + + cl_git_pass(git_reference_lookup(&ref, repo, "refs/remotes/sloppy/master")); + git_reference_free(ref); + + cl_git_pass(git_reflog_read(&log, repo, "refs/remotes/sloppy/master")); + cl_assert_equal_i(1, git_reflog_entrycount(log)); + entry = git_reflog_entry_byindex(log, 0); + cl_assert_equal_s("foo@example.com", git_reflog_entry_committer(entry)->email); + cl_assert_equal_s("UPDAAAAAATE!!", git_reflog_entry_message(entry)); + + git_reflog_free(log); +} + +void test_network_remote_local__reflog(void) +{ + char *refspec_strings[] = { + "master:remotes/sloppy/master", + }; + git_strarray array = { + refspec_strings, + 1, + }; + + git_reflog *log; + const git_reflog_entry *entry; + + connect_to_local_repository(cl_fixture("testrepo.git")); + + cl_git_pass(git_remote_fetch(remote, &array, NULL, "UPDAAAAAATE!!")); + + cl_git_pass(git_reflog_read(&log, repo, "refs/remotes/sloppy/master")); + cl_assert_equal_i(1, git_reflog_entrycount(log)); + entry = git_reflog_entry_byindex(log, 0); + cl_assert_equal_s("foo@example.com", git_reflog_entry_committer(entry)->email); + cl_assert_equal_s("UPDAAAAAATE!!", git_reflog_entry_message(entry)); + + git_reflog_free(log); +} + +void test_network_remote_local__fetch_default_reflog_message(void) +{ + char *refspec_strings[] = { + "master:remotes/sloppy/master", + }; + git_strarray array = { + refspec_strings, + 1, + }; + + git_reflog *log; + const git_reflog_entry *entry; + char expected_reflog_msg[1024]; + + connect_to_local_repository(cl_fixture("testrepo.git")); + + cl_git_pass(git_remote_fetch(remote, &array, NULL, NULL)); + + cl_git_pass(git_reflog_read(&log, repo, "refs/remotes/sloppy/master")); + cl_assert_equal_i(1, git_reflog_entrycount(log)); + entry = git_reflog_entry_byindex(log, 0); + cl_assert_equal_s("foo@example.com", git_reflog_entry_committer(entry)->email); + + sprintf(expected_reflog_msg, "fetch %s", git_remote_url(remote)); + cl_assert_equal_s(expected_reflog_msg, git_reflog_entry_message(entry)); + + git_reflog_free(log); +} + +void test_network_remote_local__opportunistic_update(void) +{ + git_reference *ref; + char *refspec_strings[] = { + "master", + }; + git_strarray array = { + refspec_strings, + 1, + }; + + /* this remote has a passive refspec of "refs/heads/<star>:refs/remotes/origin/<star>" */ + cl_git_pass(git_remote_create(&remote, repo, "origin", cl_git_fixture_url("testrepo.git"))); + /* and we pass the active refspec "master" */ + cl_git_pass(git_remote_fetch(remote, &array, NULL, NULL)); + + /* and we expect that to update our copy of origin's master */ + cl_git_pass(git_reference_lookup(&ref, repo, "refs/remotes/origin/master")); + git_reference_free(ref); +} + +void test_network_remote_local__update_tips_for_new_remote(void) { + git_repository *src_repo; + git_repository *dst_repo; + git_remote *new_remote; + git_reference* branch; + + /* Copy test repo */ + cl_fixture_sandbox("testrepo.git"); + cl_git_pass(git_repository_open(&src_repo, "testrepo.git")); + + /* Set up an empty bare repo to push into */ + cl_git_pass(git_repository_init(&dst_repo, "./localbare.git", 1)); + + /* Push to bare repo */ + cl_git_pass(git_remote_create(&new_remote, src_repo, "bare", "./localbare.git")); + cl_git_pass(git_remote_push(new_remote, &push_array, NULL)); + /* Make sure remote branch has been created */ + cl_git_pass(git_branch_lookup(&branch, src_repo, "bare/master", GIT_BRANCH_REMOTE)); + + git_reference_free(branch); + git_remote_free(new_remote); + git_repository_free(dst_repo); + cl_fixture_cleanup("localbare.git"); + git_repository_free(src_repo); + cl_fixture_cleanup("testrepo.git"); +} + +void test_network_remote_local__push_delete(void) +{ + git_repository *src_repo; + git_repository *dst_repo; + git_remote *remote; + git_reference *ref; + char *spec_push[] = { "refs/heads/master" }; + char *spec_delete[] = { ":refs/heads/master" }; + git_strarray specs = { + spec_push, + 1, + }; + + src_repo = cl_git_sandbox_init("testrepo.git"); + cl_git_pass(git_repository_init(&dst_repo, "target.git", 1)); + + cl_git_pass(git_remote_create(&remote, src_repo, "origin", "./target.git")); + + /* Push the master branch and verify it's there */ + cl_git_pass(git_remote_push(remote, &specs, NULL)); + cl_git_pass(git_reference_lookup(&ref, dst_repo, "refs/heads/master")); + git_reference_free(ref); + + specs.strings = spec_delete; + cl_git_pass(git_remote_push(remote, &specs, NULL)); + cl_git_fail(git_reference_lookup(&ref, dst_repo, "refs/heads/master")); + + git_remote_free(remote); + git_repository_free(dst_repo); + cl_fixture_cleanup("target.git"); + cl_git_sandbox_cleanup(); +} + +void test_network_remote_local__anonymous_remote_inmemory_repo(void) +{ + git_repository *inmemory; + git_remote *remote; + + git_str_sets(&file_path_buf, cl_git_path_url(cl_fixture("testrepo.git"))); + + cl_git_pass(git_repository_new(&inmemory)); + cl_git_pass(git_remote_create_anonymous(&remote, inmemory, git_str_cstr(&file_path_buf))); + cl_git_pass(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL)); + cl_assert(git_remote_connected(remote)); + git_remote_disconnect(remote); + git_remote_free(remote); + git_repository_free(inmemory); +} diff --git a/tests/libgit2/network/remote/push.c b/tests/libgit2/network/remote/push.c new file mode 100644 index 000000000..3905debdf --- /dev/null +++ b/tests/libgit2/network/remote/push.c @@ -0,0 +1,114 @@ +#include "clar_libgit2.h" +#include "git2/sys/commit.h" + +static git_remote *_remote; +static git_repository *_repo, *_dummy; + +void test_network_remote_push__initialize(void) +{ + cl_fixture_sandbox("testrepo.git"); + git_repository_open(&_repo, "testrepo.git"); + + /* We need a repository to have a remote */ + cl_git_pass(git_repository_init(&_dummy, "dummy.git", true)); + cl_git_pass(git_remote_create(&_remote, _dummy, "origin", cl_git_path_url("testrepo.git"))); +} + +void test_network_remote_push__cleanup(void) +{ + git_remote_free(_remote); + _remote = NULL; + + git_repository_free(_repo); + _repo = NULL; + + git_repository_free(_dummy); + _dummy = NULL; + + cl_fixture_cleanup("testrepo.git"); + cl_fixture_cleanup("dummy.git"); +} + +static int negotiation_cb(const git_push_update **updates, size_t len, void *payload) +{ + const git_push_update *expected = payload; + + cl_assert_equal_i(1, len); + cl_assert_equal_s(expected->src_refname, updates[0]->src_refname); + cl_assert_equal_s(expected->dst_refname, updates[0]->dst_refname); + cl_assert_equal_oid(&expected->src, &updates[0]->src); + cl_assert_equal_oid(&expected->dst, &updates[0]->dst); + + return 0; +} + +void test_network_remote_push__delete_notification(void) +{ + git_push_options opts = GIT_PUSH_OPTIONS_INIT; + git_reference *ref; + git_push_update expected; + char *refspec = ":refs/heads/master"; + const git_strarray refspecs = { + &refspec, + 1, + }; + + cl_git_pass(git_reference_lookup(&ref, _repo, "refs/heads/master")); + + expected.src_refname = ""; + expected.dst_refname = "refs/heads/master"; + memset(&expected.dst, 0, sizeof(git_oid)); + git_oid_cpy(&expected.src, git_reference_target(ref)); + + opts.callbacks.push_negotiation = negotiation_cb; + opts.callbacks.payload = &expected; + cl_git_pass(git_remote_push(_remote, &refspecs, &opts)); + + git_reference_free(ref); + cl_git_fail_with(GIT_ENOTFOUND, git_reference_lookup(&ref, _repo, "refs/heads/master")); + +} + +static void create_dummy_commit(git_reference **out, git_repository *repo) +{ + git_index *index; + git_oid tree_id, commit_id; + git_signature *sig; + + cl_git_pass(git_repository_index(&index, repo)); + cl_git_pass(git_index_write_tree(&tree_id, index)); + git_index_free(index); + + cl_git_pass(git_signature_now(&sig, "Pusher Joe", "pjoe")); + cl_git_pass(git_commit_create_from_ids(&commit_id, repo, NULL, sig, sig, + NULL, "Empty tree\n", &tree_id, 0, NULL)); + cl_git_pass(git_reference_create(out, repo, "refs/heads/empty-tree", &commit_id, true, "commit yo")); + git_signature_free(sig); +} + +void test_network_remote_push__create_notification(void) +{ + git_push_options opts = GIT_PUSH_OPTIONS_INIT; + git_reference *ref; + git_push_update expected; + char *refspec = "refs/heads/empty-tree"; + const git_strarray refspecs = { + &refspec, + 1, + }; + + create_dummy_commit(&ref, _dummy); + + expected.src_refname = "refs/heads/empty-tree"; + expected.dst_refname = "refs/heads/empty-tree"; + git_oid_cpy(&expected.dst, git_reference_target(ref)); + memset(&expected.src, 0, sizeof(git_oid)); + + opts.callbacks.push_negotiation = negotiation_cb; + opts.callbacks.payload = &expected; + cl_git_pass(git_remote_push(_remote, &refspecs, &opts)); + + git_reference_free(ref); + cl_git_pass(git_reference_lookup(&ref, _repo, "refs/heads/empty-tree")); + git_reference_free(ref); +} diff --git a/tests/libgit2/network/remote/remotes.c b/tests/libgit2/network/remote/remotes.c new file mode 100644 index 000000000..79c4f39fa --- /dev/null +++ b/tests/libgit2/network/remote/remotes.c @@ -0,0 +1,575 @@ +#include "clar_libgit2.h" +#include "config/config_helpers.h" +#include "refspec.h" +#include "remote.h" + +static git_remote *_remote; +static git_repository *_repo; +static const git_refspec *_refspec; + +void test_network_remote_remotes__initialize(void) +{ + _repo = cl_git_sandbox_init("testrepo.git"); + + cl_git_pass(git_remote_lookup(&_remote, _repo, "test")); + + _refspec = git_remote_get_refspec(_remote, 0); + cl_assert(_refspec != NULL); +} + +void test_network_remote_remotes__cleanup(void) +{ + git_remote_free(_remote); + _remote = NULL; + + cl_git_sandbox_cleanup(); +} + +void test_network_remote_remotes__parsing(void) +{ + git_str url = GIT_STR_INIT; + git_remote *_remote2 = NULL; + + cl_assert_equal_s(git_remote_name(_remote), "test"); + cl_assert_equal_s(git_remote_url(_remote), "git://github.com/libgit2/libgit2"); + cl_assert(git_remote_pushurl(_remote) == NULL); + + cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, NULL)); + cl_assert_equal_s(url.ptr, "git://github.com/libgit2/libgit2"); + + cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, NULL)); + cl_assert_equal_s(url.ptr, "git://github.com/libgit2/libgit2"); + + cl_git_pass(git_remote_lookup(&_remote2, _repo, "test_with_pushurl")); + cl_assert_equal_s(git_remote_name(_remote2), "test_with_pushurl"); + cl_assert_equal_s(git_remote_url(_remote2), "git://github.com/libgit2/fetchlibgit2"); + cl_assert_equal_s(git_remote_pushurl(_remote2), "git://github.com/libgit2/pushlibgit2"); + + cl_git_pass(git_remote__urlfordirection(&url, _remote2, GIT_DIRECTION_FETCH, NULL)); + cl_assert_equal_s(url.ptr, "git://github.com/libgit2/fetchlibgit2"); + + cl_git_pass(git_remote__urlfordirection(&url, _remote2, GIT_DIRECTION_PUSH, NULL)); + cl_assert_equal_s(url.ptr, "git://github.com/libgit2/pushlibgit2"); + + git_remote_free(_remote2); + git_str_dispose(&url); +} + +static int remote_ready_callback(git_remote *remote, int direction, void *payload) +{ + if (direction == GIT_DIRECTION_PUSH) { + const char *url = git_remote_pushurl(remote); + + cl_assert_equal_p(url, NULL);; + cl_assert_equal_s(payload, "payload"); + return git_remote_set_instance_pushurl(remote, "push_url"); + } + + if (direction == GIT_DIRECTION_FETCH) { + const char *url = git_remote_url(remote); + + cl_assert_equal_s(url, "git://github.com/libgit2/libgit2"); + cl_assert_equal_s(payload, "payload"); + return git_remote_set_instance_url(remote, "fetch_url"); + } + + return -1; +} + +void test_network_remote_remotes__remote_ready(void) +{ + git_str url = GIT_STR_INIT; + + git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT; + callbacks.remote_ready = remote_ready_callback; + callbacks.payload = "payload"; + + cl_assert_equal_s(git_remote_name(_remote), "test"); + cl_assert_equal_s(git_remote_url(_remote), "git://github.com/libgit2/libgit2"); + cl_assert(git_remote_pushurl(_remote) == NULL); + + cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, &callbacks)); + cl_assert_equal_s(url.ptr, "fetch_url"); + + cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, &callbacks)); + cl_assert_equal_s(url.ptr, "push_url"); + + git_str_dispose(&url); +} + +#ifndef GIT_DEPRECATE_HARD +static int urlresolve_callback(git_buf *url_resolved, const char *url, int direction, void *payload) +{ + int error = -1; + + cl_assert(strcmp(url, "git://github.com/libgit2/libgit2") == 0); + cl_assert(strcmp(payload, "payload") == 0); + cl_assert(url_resolved->size == 0); + + if (direction == GIT_DIRECTION_PUSH) + error = git_buf_set(url_resolved, "pushresolve", strlen("pushresolve") + 1); + if (direction == GIT_DIRECTION_FETCH) + error = git_buf_set(url_resolved, "fetchresolve", strlen("fetchresolve") + 1); + + return error; +} +#endif + +void test_network_remote_remotes__urlresolve(void) +{ +#ifndef GIT_DEPRECATE_HARD + git_str url = GIT_STR_INIT; + + git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT; + callbacks.resolve_url = urlresolve_callback; + callbacks.payload = "payload"; + + cl_assert_equal_s(git_remote_name(_remote), "test"); + cl_assert_equal_s(git_remote_url(_remote), "git://github.com/libgit2/libgit2"); + cl_assert(git_remote_pushurl(_remote) == NULL); + + cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, &callbacks)); + cl_assert_equal_s(url.ptr, "fetchresolve"); + + cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, &callbacks)); + cl_assert_equal_s(url.ptr, "pushresolve"); + + git_str_dispose(&url); +#endif +} + +#ifndef GIT_DEPRECATE_HARD +static int urlresolve_passthrough_callback(git_buf *url_resolved, const char *url, int direction, void *payload) +{ + GIT_UNUSED(url_resolved); + GIT_UNUSED(url); + GIT_UNUSED(direction); + GIT_UNUSED(payload); + return GIT_PASSTHROUGH; +} +#endif + +void test_network_remote_remotes__urlresolve_passthrough(void) +{ +#ifndef GIT_DEPRECATE_HARD + git_str url = GIT_STR_INIT; + const char *orig_url = "git://github.com/libgit2/libgit2"; + + git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT; + callbacks.resolve_url = urlresolve_passthrough_callback; + + cl_assert_equal_s(git_remote_name(_remote), "test"); + cl_assert_equal_s(git_remote_url(_remote), orig_url); + cl_assert(git_remote_pushurl(_remote) == NULL); + + cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, &callbacks)); + cl_assert_equal_s(url.ptr, orig_url); + + cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, &callbacks)); + cl_assert_equal_s(url.ptr, orig_url); + + git_str_dispose(&url); +#endif +} + +void test_network_remote_remotes__instance_url(void) +{ + git_str url = GIT_STR_INIT; + const char *orig_url = "git://github.com/libgit2/libgit2"; + + cl_assert_equal_s(git_remote_name(_remote), "test"); + cl_assert_equal_s(git_remote_url(_remote), orig_url); + + cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, NULL)); + cl_assert_equal_s(url.ptr, orig_url); + git_str_clear(&url); + + cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, NULL)); + cl_assert_equal_s(url.ptr, orig_url); + git_str_clear(&url); + + /* Setting the instance url updates the fetch and push URLs */ + git_remote_set_instance_url(_remote, "https://github.com/new/remote/url"); + cl_assert_equal_s(git_remote_url(_remote), "https://github.com/new/remote/url"); + cl_assert_equal_p(git_remote_pushurl(_remote), NULL); + + cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, NULL)); + cl_assert_equal_s(url.ptr, "https://github.com/new/remote/url"); + git_str_clear(&url); + + cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, NULL)); + cl_assert_equal_s(url.ptr, "https://github.com/new/remote/url"); + git_str_clear(&url); + + /* Setting the instance push url updates only the push URL */ + git_remote_set_instance_pushurl(_remote, "https://github.com/new/push/url"); + cl_assert_equal_s(git_remote_url(_remote), "https://github.com/new/remote/url"); + cl_assert_equal_s(git_remote_pushurl(_remote), "https://github.com/new/push/url"); + + cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_FETCH, NULL)); + cl_assert_equal_s(url.ptr, "https://github.com/new/remote/url"); + git_str_clear(&url); + + cl_git_pass(git_remote__urlfordirection(&url, _remote, GIT_DIRECTION_PUSH, NULL)); + cl_assert_equal_s(url.ptr, "https://github.com/new/push/url"); + git_str_clear(&url); + + git_str_dispose(&url); +} + +void test_network_remote_remotes__pushurl(void) +{ + const char *name = git_remote_name(_remote); + git_remote *mod; + + cl_git_pass(git_remote_set_pushurl(_repo, name, "git://github.com/libgit2/notlibgit2")); + cl_git_pass(git_remote_lookup(&mod, _repo, name)); + cl_assert_equal_s(git_remote_pushurl(mod), "git://github.com/libgit2/notlibgit2"); + git_remote_free(mod); + + cl_git_pass(git_remote_set_pushurl(_repo, name, NULL)); + cl_git_pass(git_remote_lookup(&mod, _repo, name)); + cl_assert(git_remote_pushurl(mod) == NULL); + git_remote_free(mod); +} + +void test_network_remote_remotes__error_when_not_found(void) +{ + git_remote *r; + cl_git_fail_with(git_remote_lookup(&r, _repo, "does-not-exist"), GIT_ENOTFOUND); + + cl_assert(git_error_last() != NULL); + cl_assert(git_error_last()->klass == GIT_ERROR_CONFIG); +} + +void test_network_remote_remotes__error_when_no_push_available(void) +{ + git_remote *r; + git_remote_callbacks callbacks = GIT_REMOTE_CALLBACKS_INIT; + char *specs = { + "refs/heads/master", + }; + git_strarray arr = { + &specs, + 1, + }; + + + cl_git_pass(git_remote_create_anonymous(&r, _repo, cl_fixture("testrepo.git"))); + + callbacks.transport = git_transport_local; + cl_git_pass(git_remote_connect(r, GIT_DIRECTION_PUSH, &callbacks, NULL, NULL)); + + /* Make sure that push is really not available */ + r->transport->push = NULL; + + cl_git_fail_with(-1, git_remote_upload(r, &arr, NULL)); + + git_remote_free(r); +} + +void test_network_remote_remotes__refspec_parsing(void) +{ + cl_assert_equal_s(git_refspec_src(_refspec), "refs/heads/*"); + cl_assert_equal_s(git_refspec_dst(_refspec), "refs/remotes/test/*"); +} + +void test_network_remote_remotes__add_fetchspec(void) +{ + size_t size; + + size = git_remote_refspec_count(_remote); + + cl_git_pass(git_remote_add_fetch(_repo, "test", "refs/*:refs/*")); + size++; + + git_remote_free(_remote); + cl_git_pass(git_remote_lookup(&_remote, _repo, "test")); + + cl_assert_equal_i((int)size, (int)git_remote_refspec_count(_remote)); + + _refspec = git_remote_get_refspec(_remote, size - 1); + cl_assert_equal_s(git_refspec_src(_refspec), "refs/*"); + cl_assert_equal_s(git_refspec_dst(_refspec), "refs/*"); + cl_assert_equal_s(git_refspec_string(_refspec), "refs/*:refs/*"); + cl_assert_equal_b(_refspec->push, false); + + cl_git_fail_with(GIT_EINVALIDSPEC, git_remote_add_fetch(_repo, "test", "refs/*/foo/*:refs/*")); +} + +void test_network_remote_remotes__dup(void) +{ + git_strarray array; + git_remote *dup; + + cl_git_pass(git_remote_dup(&dup, _remote)); + + cl_assert_equal_s(git_remote_name(dup), git_remote_name(_remote)); + cl_assert_equal_s(git_remote_url(dup), git_remote_url(_remote)); + cl_assert_equal_s(git_remote_pushurl(dup), git_remote_pushurl(_remote)); + + cl_git_pass(git_remote_get_fetch_refspecs(&array, _remote)); + cl_assert_equal_i(1, (int)array.count); + cl_assert_equal_s("+refs/heads/*:refs/remotes/test/*", array.strings[0]); + git_strarray_dispose(&array); + + cl_git_pass(git_remote_get_push_refspecs(&array, _remote)); + cl_assert_equal_i(0, (int)array.count); + git_strarray_dispose(&array); + + git_remote_free(dup); +} + +void test_network_remote_remotes__add_pushspec(void) +{ + size_t size; + + size = git_remote_refspec_count(_remote); + + cl_git_pass(git_remote_add_push(_repo, "test", "refs/*:refs/*")); + size++; + + git_remote_free(_remote); + cl_git_pass(git_remote_lookup(&_remote, _repo, "test")); + + cl_assert_equal_i((int)size, (int)git_remote_refspec_count(_remote)); + + _refspec = git_remote_get_refspec(_remote, size - 1); + cl_assert_equal_s(git_refspec_src(_refspec), "refs/*"); + cl_assert_equal_s(git_refspec_dst(_refspec), "refs/*"); + cl_assert_equal_s(git_refspec_string(_refspec), "refs/*:refs/*"); + + cl_assert_equal_b(_refspec->push, true); +} + +void test_network_remote_remotes__fnmatch(void) +{ + cl_assert(git_refspec_src_matches(_refspec, "refs/heads/master")); + cl_assert(git_refspec_src_matches(_refspec, "refs/heads/multi/level/branch")); +} + +void test_network_remote_remotes__transform(void) +{ + git_buf ref = GIT_BUF_INIT; + + cl_git_pass(git_refspec_transform(&ref, _refspec, "refs/heads/master")); + cl_assert_equal_s(ref.ptr, "refs/remotes/test/master"); + git_buf_dispose(&ref); +} + +void test_network_remote_remotes__transform_destination_to_source(void) +{ + git_buf ref = GIT_BUF_INIT; + + cl_git_pass(git_refspec_rtransform(&ref, _refspec, "refs/remotes/test/master")); + cl_assert_equal_s(ref.ptr, "refs/heads/master"); + git_buf_dispose(&ref); +} + +void test_network_remote_remotes__missing_refspecs(void) +{ + git_config *cfg; + + git_remote_free(_remote); + _remote = NULL; + + cl_git_pass(git_repository_config(&cfg, _repo)); + cl_git_pass(git_config_set_string(cfg, "remote.specless.url", "http://example.com")); + cl_git_pass(git_remote_lookup(&_remote, _repo, "specless")); + + git_config_free(cfg); +} + +void test_network_remote_remotes__nonmatch_upstream_refspec(void) +{ + git_config *config; + git_remote *remote; + char *specstr[] = { + "refs/tags/*:refs/tags/*", + }; + git_strarray specs = { + specstr, + 1, + }; + + cl_git_pass(git_remote_create(&remote, _repo, "taggy", git_repository_path(_repo))); + + /* + * Set the current branch's upstream remote to a dummy ref so we call into the code + * which tries to check for the current branch's upstream in the refspecs + */ + cl_git_pass(git_repository_config(&config, _repo)); + cl_git_pass(git_config_set_string(config, "branch.master.remote", "taggy")); + cl_git_pass(git_config_set_string(config, "branch.master.merge", "refs/heads/foo")); + + cl_git_pass(git_remote_fetch(remote, &specs, NULL, NULL)); + + git_remote_free(remote); +} + +void test_network_remote_remotes__list(void) +{ + git_strarray list; + git_config *cfg; + + cl_git_pass(git_remote_list(&list, _repo)); + cl_assert(list.count == 5); + git_strarray_dispose(&list); + + cl_git_pass(git_repository_config(&cfg, _repo)); + + /* Create a new remote */ + cl_git_pass(git_config_set_string(cfg, "remote.specless.url", "http://example.com")); + + /* Update a remote (previously without any url/pushurl entry) */ + cl_git_pass(git_config_set_string(cfg, "remote.no-remote-url.pushurl", "http://example.com")); + + cl_git_pass(git_remote_list(&list, _repo)); + cl_assert(list.count == 7); + git_strarray_dispose(&list); + + git_config_free(cfg); +} + +void test_network_remote_remotes__loading_a_missing_remote_returns_ENOTFOUND(void) +{ + git_remote_free(_remote); + _remote = NULL; + + cl_assert_equal_i(GIT_ENOTFOUND, git_remote_lookup(&_remote, _repo, "just-left-few-minutes-ago")); +} + +void test_network_remote_remotes__loading_with_an_invalid_name_returns_EINVALIDSPEC(void) +{ + git_remote_free(_remote); + _remote = NULL; + + cl_assert_equal_i(GIT_EINVALIDSPEC, git_remote_lookup(&_remote, _repo, "Inv@{id")); +} + +/* + * $ git remote add addtest http://github.com/libgit2/libgit2 + * + * $ cat .git/config + * [...] + * [remote "addtest"] + * url = http://github.com/libgit2/libgit2 + * fetch = +refs/heads/\*:refs/remotes/addtest/\* + */ +void test_network_remote_remotes__add(void) +{ + git_remote_free(_remote); + _remote = NULL; + + cl_git_pass(git_remote_create(&_remote, _repo, "addtest", "http://github.com/libgit2/libgit2")); + cl_assert_equal_i(GIT_REMOTE_DOWNLOAD_TAGS_AUTO, git_remote_autotag(_remote)); + + git_remote_free(_remote); + _remote = NULL; + + cl_git_pass(git_remote_lookup(&_remote, _repo, "addtest")); + cl_assert_equal_i(GIT_REMOTE_DOWNLOAD_TAGS_AUTO, git_remote_autotag(_remote)); + + _refspec = git_vector_get(&_remote->refspecs, 0); + cl_assert_equal_s("refs/heads/*", git_refspec_src(_refspec)); + cl_assert(git_refspec_force(_refspec) == 1); + cl_assert_equal_s("refs/remotes/addtest/*", git_refspec_dst(_refspec)); + cl_assert_equal_s(git_remote_url(_remote), "http://github.com/libgit2/libgit2"); +} + +void test_network_remote_remotes__tagopt(void) +{ + const char *name = git_remote_name(_remote); + + git_remote_set_autotag(_repo, name, GIT_REMOTE_DOWNLOAD_TAGS_ALL); + assert_config_entry_value(_repo, "remote.test.tagopt", "--tags"); + + git_remote_set_autotag(_repo, name, GIT_REMOTE_DOWNLOAD_TAGS_NONE); + assert_config_entry_value(_repo, "remote.test.tagopt", "--no-tags"); + + git_remote_set_autotag(_repo, name, GIT_REMOTE_DOWNLOAD_TAGS_AUTO); + assert_config_entry_existence(_repo, "remote.test.tagopt", false); +} + +void test_network_remote_remotes__can_load_with_an_empty_url(void) +{ + git_remote *remote = NULL; + + cl_git_pass(git_remote_lookup(&remote, _repo, "empty-remote-url")); + + cl_assert(remote->url == NULL); + cl_assert(remote->pushurl == NULL); + + cl_git_fail(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL)); + + cl_assert(git_error_last() != NULL); + cl_assert(git_error_last()->klass == GIT_ERROR_INVALID); + + git_remote_free(remote); +} + +void test_network_remote_remotes__can_load_with_only_an_empty_pushurl(void) +{ + git_remote *remote = NULL; + + cl_git_pass(git_remote_lookup(&remote, _repo, "empty-remote-pushurl")); + + cl_assert(remote->url == NULL); + cl_assert(remote->pushurl == NULL); + + cl_git_fail(git_remote_connect(remote, GIT_DIRECTION_FETCH, NULL, NULL, NULL)); + + git_remote_free(remote); +} + +void test_network_remote_remotes__returns_ENOTFOUND_when_neither_url_nor_pushurl(void) +{ + git_remote *remote = NULL; + + cl_git_fail_with( + git_remote_lookup(&remote, _repo, "no-remote-url"), GIT_ENOTFOUND); +} + +static const char *fetch_refspecs[] = { + "+refs/heads/*:refs/remotes/origin/*", + "refs/tags/*:refs/tags/*", + "+refs/pull/*:refs/pull/*", +}; + +static const char *push_refspecs[] = { + "refs/heads/*:refs/heads/*", + "refs/tags/*:refs/tags/*", + "refs/notes/*:refs/notes/*", +}; + +void test_network_remote_remotes__query_refspecs(void) +{ + git_remote *remote; + git_strarray array; + int i; + + cl_git_pass(git_remote_create_with_fetchspec(&remote, _repo, "query", "git://github.com/libgit2/libgit2", NULL)); + git_remote_free(remote); + + for (i = 0; i < 3; i++) { + cl_git_pass(git_remote_add_fetch(_repo, "query", fetch_refspecs[i])); + cl_git_pass(git_remote_add_push(_repo, "query", push_refspecs[i])); + } + + cl_git_pass(git_remote_lookup(&remote, _repo, "query")); + + cl_git_pass(git_remote_get_fetch_refspecs(&array, remote)); + for (i = 0; i < 3; i++) { + cl_assert_equal_s(fetch_refspecs[i], array.strings[i]); + } + git_strarray_dispose(&array); + + cl_git_pass(git_remote_get_push_refspecs(&array, remote)); + for (i = 0; i < 3; i++) { + cl_assert_equal_s(push_refspecs[i], array.strings[i]); + } + git_strarray_dispose(&array); + + git_remote_free(remote); + git_remote_delete(_repo, "test"); +} diff --git a/tests/libgit2/network/remote/rename.c b/tests/libgit2/network/remote/rename.c new file mode 100644 index 000000000..1fd2affba --- /dev/null +++ b/tests/libgit2/network/remote/rename.c @@ -0,0 +1,245 @@ +#include "clar_libgit2.h" +#include "config/config_helpers.h" + +#include "repository.h" + +static git_repository *_repo; +static const char *_remote_name = "test"; + +void test_network_remote_rename__initialize(void) +{ + _repo = cl_git_sandbox_init("testrepo.git"); +} + +void test_network_remote_rename__cleanup(void) +{ + cl_git_sandbox_cleanup(); +} + +void test_network_remote_rename__renaming_a_remote_moves_related_configuration_section(void) +{ + git_strarray problems = {0}; + + assert_config_entry_existence(_repo, "remote.test.fetch", true); + assert_config_entry_existence(_repo, "remote.just/renamed.fetch", false); + + cl_git_pass(git_remote_rename(&problems, _repo, _remote_name, "just/renamed")); + cl_assert_equal_i(0, problems.count); + git_strarray_dispose(&problems); + + assert_config_entry_existence(_repo, "remote.test.fetch", false); + assert_config_entry_existence(_repo, "remote.just/renamed.fetch", true); +} + +void test_network_remote_rename__renaming_a_remote_updates_branch_related_configuration_entries(void) +{ + git_strarray problems = {0}; + + assert_config_entry_value(_repo, "branch.master.remote", "test"); + + cl_git_pass(git_remote_rename(&problems, _repo, _remote_name, "just/renamed")); + cl_assert_equal_i(0, problems.count); + git_strarray_dispose(&problems); + + assert_config_entry_value(_repo, "branch.master.remote", "just/renamed"); +} + +void test_network_remote_rename__renaming_a_remote_updates_default_fetchrefspec(void) +{ + git_strarray problems = {0}; + + cl_git_pass(git_remote_rename(&problems, _repo, _remote_name, "just/renamed")); + cl_assert_equal_i(0, problems.count); + git_strarray_dispose(&problems); + + assert_config_entry_value(_repo, "remote.just/renamed.fetch", "+refs/heads/*:refs/remotes/just/renamed/*"); +} + +void test_network_remote_rename__renaming_a_remote_without_a_fetchrefspec_doesnt_create_one(void) +{ + git_config *config; + git_remote *remote; + git_strarray problems = {0}; + + cl_git_pass(git_repository_config__weakptr(&config, _repo)); + cl_git_pass(git_config_delete_entry(config, "remote.test.fetch")); + + cl_git_pass(git_remote_lookup(&remote, _repo, "test")); + git_remote_free(remote); + + assert_config_entry_existence(_repo, "remote.test.fetch", false); + + cl_git_pass(git_remote_rename(&problems, _repo, _remote_name, "just/renamed")); + cl_assert_equal_i(0, problems.count); + git_strarray_dispose(&problems); + + assert_config_entry_existence(_repo, "remote.just/renamed.fetch", false); +} + +void test_network_remote_rename__renaming_a_remote_notifies_of_non_default_fetchrefspec(void) +{ + git_config *config; + git_remote *remote; + git_strarray problems = {0}; + + cl_git_pass(git_repository_config__weakptr(&config, _repo)); + cl_git_pass(git_config_set_string(config, "remote.test.fetch", "+refs/*:refs/*")); + cl_git_pass(git_remote_lookup(&remote, _repo, "test")); + git_remote_free(remote); + + cl_git_pass(git_remote_rename(&problems, _repo, _remote_name, "just/renamed")); + cl_assert_equal_i(1, problems.count); + cl_assert_equal_s("+refs/*:refs/*", problems.strings[0]); + git_strarray_dispose(&problems); + + assert_config_entry_value(_repo, "remote.just/renamed.fetch", "+refs/*:refs/*"); + + git_strarray_dispose(&problems); +} + +void test_network_remote_rename__new_name_can_contain_dots(void) +{ + git_strarray problems = {0}; + + cl_git_pass(git_remote_rename(&problems, _repo, _remote_name, "just.renamed")); + cl_assert_equal_i(0, problems.count); + git_strarray_dispose(&problems); + assert_config_entry_existence(_repo, "remote.just.renamed.fetch", true); +} + +void test_network_remote_rename__new_name_must_conform_to_reference_naming_conventions(void) +{ + git_strarray problems = {0}; + + cl_assert_equal_i( + GIT_EINVALIDSPEC, + git_remote_rename(&problems, _repo, _remote_name, "new@{name")); +} + +void test_network_remote_rename__renamed_name_is_persisted(void) +{ + git_remote *renamed; + git_repository *another_repo; + git_strarray problems = {0}; + + cl_git_fail(git_remote_lookup(&renamed, _repo, "just/renamed")); + + cl_git_pass(git_remote_rename(&problems, _repo, _remote_name, "just/renamed")); + cl_assert_equal_i(0, problems.count); + git_strarray_dispose(&problems); + + cl_git_pass(git_repository_open(&another_repo, "testrepo.git")); + cl_git_pass(git_remote_lookup(&renamed, _repo, "just/renamed")); + + git_remote_free(renamed); + git_repository_free(another_repo); +} + +void test_network_remote_rename__cannot_overwrite_an_existing_remote(void) +{ + git_strarray problems = {0}; + + cl_assert_equal_i(GIT_EEXISTS, git_remote_rename(&problems, _repo, _remote_name, "test")); + cl_assert_equal_i(GIT_EEXISTS, git_remote_rename(&problems, _repo, _remote_name, "test_with_pushurl")); +} + +void test_network_remote_rename__renaming_a_remote_moves_the_underlying_reference(void) +{ + git_reference *underlying; + git_strarray problems = {0}; + + cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&underlying, _repo, "refs/remotes/just/renamed")); + cl_git_pass(git_reference_lookup(&underlying, _repo, "refs/remotes/test/master")); + git_reference_free(underlying); + + cl_git_pass(git_remote_rename(&problems, _repo, _remote_name, "just/renamed")); + cl_assert_equal_i(0, problems.count); + git_strarray_dispose(&problems); + + cl_assert_equal_i(GIT_ENOTFOUND, git_reference_lookup(&underlying, _repo, "refs/remotes/test/master")); + cl_git_pass(git_reference_lookup(&underlying, _repo, "refs/remotes/just/renamed/master")); + git_reference_free(underlying); +} + +void test_network_remote_rename__overwrite_ref_in_target(void) +{ + git_oid id; + char idstr[GIT_OID_HEXSZ + 1] = {0}; + git_reference *ref; + git_branch_t btype; + git_branch_iterator *iter; + git_strarray problems = {0}; + + cl_git_pass(git_oid_fromstr(&id, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750")); + cl_git_pass(git_reference_create(&ref, _repo, "refs/remotes/renamed/master", &id, 1, NULL)); + git_reference_free(ref); + + cl_git_pass(git_remote_rename(&problems, _repo, _remote_name, "renamed")); + cl_assert_equal_i(0, problems.count); + git_strarray_dispose(&problems); + + /* make sure there's only one remote-tracking branch */ + cl_git_pass(git_branch_iterator_new(&iter, _repo, GIT_BRANCH_REMOTE)); + cl_git_pass(git_branch_next(&ref, &btype, iter)); + cl_assert_equal_s("refs/remotes/renamed/master", git_reference_name(ref)); + git_oid_fmt(idstr, git_reference_target(ref)); + cl_assert_equal_s("be3563ae3f795b2b4353bcce3a527ad0a4f7f644", idstr); + git_reference_free(ref); + + cl_git_fail_with(GIT_ITEROVER, git_branch_next(&ref, &btype, iter)); + git_branch_iterator_free(iter); +} + +void test_network_remote_rename__nonexistent_returns_enotfound(void) +{ + git_strarray problems = {0}; + + int err = git_remote_rename(&problems, _repo, "nonexistent", "renamed"); + + cl_assert_equal_i(GIT_ENOTFOUND, err); +} + +void test_network_remote_rename__symref_head(void) +{ + int error; + git_reference *ref; + git_branch_t btype; + git_branch_iterator *iter; + git_strarray problems = {0}; + char idstr[GIT_OID_HEXSZ + 1] = {0}; + git_vector refs; + + cl_git_pass(git_reference_symbolic_create(&ref, _repo, "refs/remotes/test/HEAD", "refs/remotes/test/master", 0, NULL)); + git_reference_free(ref); + + cl_git_pass(git_remote_rename(&problems, _repo, _remote_name, "renamed")); + cl_assert_equal_i(0, problems.count); + git_strarray_dispose(&problems); + + cl_git_pass(git_vector_init(&refs, 2, (git_vector_cmp) git_reference_cmp)); + cl_git_pass(git_branch_iterator_new(&iter, _repo, GIT_BRANCH_REMOTE)); + + while ((error = git_branch_next(&ref, &btype, iter)) == 0) { + cl_git_pass(git_vector_insert(&refs, ref)); + } + cl_assert_equal_i(GIT_ITEROVER, error); + git_vector_sort(&refs); + + cl_assert_equal_i(2, refs.length); + + ref = git_vector_get(&refs, 0); + cl_assert_equal_s("refs/remotes/renamed/HEAD", git_reference_name(ref)); + cl_assert_equal_s("refs/remotes/renamed/master", git_reference_symbolic_target(ref)); + git_reference_free(ref); + + ref = git_vector_get(&refs, 1); + cl_assert_equal_s("refs/remotes/renamed/master", git_reference_name(ref)); + git_oid_fmt(idstr, git_reference_target(ref)); + cl_assert_equal_s("be3563ae3f795b2b4353bcce3a527ad0a4f7f644", idstr); + git_reference_free(ref); + + git_vector_free(&refs); + + cl_git_fail_with(GIT_ITEROVER, git_branch_next(&ref, &btype, iter)); + git_branch_iterator_free(iter); +} diff --git a/tests/libgit2/network/url/joinpath.c b/tests/libgit2/network/url/joinpath.c new file mode 100644 index 000000000..bf4557138 --- /dev/null +++ b/tests/libgit2/network/url/joinpath.c @@ -0,0 +1,194 @@ +#include "clar_libgit2.h" +#include "net.h" +#include "netops.h" + +static git_net_url source, target; + +void test_network_url_joinpath__initialize(void) +{ + memset(&source, 0, sizeof(source)); + memset(&target, 0, sizeof(target)); +} + +void test_network_url_joinpath__cleanup(void) +{ + git_net_url_dispose(&source); + git_net_url_dispose(&target); +} + +void test_network_url_joinpath__target_paths_and_queries(void) +{ + cl_git_pass(git_net_url_parse(&source, "http://example.com/a/b")); + + cl_git_pass(git_net_url_joinpath(&target, &source, "/c/d")); + cl_assert_equal_s(target.path, "/a/b/c/d"); + cl_assert_equal_p(target.query, NULL); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "/c/d?foo")); + cl_assert_equal_s(target.path, "/a/b/c/d"); + cl_assert_equal_s(target.query, "foo"); + git_net_url_dispose(&target); +} + +void test_network_url_joinpath__source_query_removed(void) +{ + cl_git_pass(git_net_url_parse(&source, "http://example.com/a/b?query&one&two")); + + cl_git_pass(git_net_url_joinpath(&target, &source, "/c/d")); + cl_assert_equal_s(target.path, "/a/b/c/d"); + cl_assert_equal_p(target.query, NULL); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "/c/d?foo")); + cl_assert_equal_s(target.path, "/a/b/c/d"); + cl_assert_equal_s(target.query, "foo"); + git_net_url_dispose(&target); +} + +void test_network_url_joinpath__source_lacks_path(void) +{ + cl_git_pass(git_net_url_parse(&source, "http://example.com")); + + cl_git_pass(git_net_url_joinpath(&target, &source, "/")); + cl_assert_equal_s(target.path, "/"); + cl_assert_equal_p(target.query, NULL); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "")); + cl_assert_equal_s(target.path, "/"); + cl_assert_equal_p(target.query, NULL); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "asdf")); + cl_assert_equal_s(target.path, "/asdf"); + cl_assert_equal_p(target.query, NULL); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf")); + cl_assert_equal_s(target.path, "/asdf"); + cl_assert_equal_p(target.query, NULL); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar")); + cl_assert_equal_s(target.path, "/foo/bar"); + cl_assert_equal_p(target.query, NULL); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "asdf?hello")); + cl_assert_equal_s(target.path, "/asdf"); + cl_assert_equal_s(target.query, "hello"); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf?hello")); + cl_assert_equal_s(target.path, "/asdf"); + cl_assert_equal_s(target.query, "hello"); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar?hello")); + cl_assert_equal_s(target.path, "/foo/bar"); + cl_assert_equal_s(target.query, "hello"); + git_net_url_dispose(&target); +} + +void test_network_url_joinpath__source_is_slash(void) +{ + cl_git_pass(git_net_url_parse(&source, "http://example.com/")); + + cl_git_pass(git_net_url_joinpath(&target, &source, "/")); + cl_assert_equal_s(target.path, "/"); + cl_assert_equal_p(target.query, NULL); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "")); + cl_assert_equal_s(target.path, "/"); + cl_assert_equal_p(target.query, NULL); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "asdf")); + cl_assert_equal_s(target.path, "/asdf"); + cl_assert_equal_p(target.query, NULL); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf")); + cl_assert_equal_s(target.path, "/asdf"); + cl_assert_equal_p(target.query, NULL); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar")); + cl_assert_equal_s(target.path, "/foo/bar"); + cl_assert_equal_p(target.query, NULL); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "asdf?hello")); + cl_assert_equal_s(target.path, "/asdf"); + cl_assert_equal_s(target.query, "hello"); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf?hello")); + cl_assert_equal_s(target.path, "/asdf"); + cl_assert_equal_s(target.query, "hello"); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar?hello")); + cl_assert_equal_s(target.path, "/foo/bar"); + cl_assert_equal_s(target.query, "hello"); + git_net_url_dispose(&target); +} + + +void test_network_url_joinpath__source_has_query(void) +{ + cl_git_pass(git_net_url_parse(&source, "http://example.com?query")); + + cl_git_pass(git_net_url_joinpath(&target, &source, "/")); + cl_assert_equal_s(target.path, "/"); + cl_assert_equal_p(target.query, NULL); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "")); + cl_assert_equal_s(target.path, "/"); + cl_assert_equal_p(target.query, NULL); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "asdf")); + cl_assert_equal_s(target.path, "/asdf"); + cl_assert_equal_p(target.query, NULL); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf")); + cl_assert_equal_s(target.path, "/asdf"); + cl_assert_equal_p(target.query, NULL); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar")); + cl_assert_equal_s(target.path, "/foo/bar"); + cl_assert_equal_p(target.query, NULL); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "asdf?hello")); + cl_assert_equal_s(target.path, "/asdf"); + cl_assert_equal_s(target.query, "hello"); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "/asdf?hello")); + cl_assert_equal_s(target.path, "/asdf"); + cl_assert_equal_s(target.query, "hello"); + git_net_url_dispose(&target); + + cl_git_pass(git_net_url_joinpath(&target, &source, "/foo/bar?hello")); + cl_assert_equal_s(target.path, "/foo/bar"); + cl_assert_equal_s(target.query, "hello"); + git_net_url_dispose(&target); +} + + +void test_network_url_joinpath__empty_query_ignored(void) +{ + cl_git_pass(git_net_url_parse(&source, "http://example.com/foo")); + + cl_git_pass(git_net_url_joinpath(&target, &source, "/bar/baz?")); + cl_assert_equal_s(target.path, "/foo/bar/baz"); + cl_assert_equal_p(target.query, NULL); + git_net_url_dispose(&target); +} diff --git a/tests/libgit2/network/url/parse.c b/tests/libgit2/network/url/parse.c new file mode 100644 index 000000000..8149ba52c --- /dev/null +++ b/tests/libgit2/network/url/parse.c @@ -0,0 +1,557 @@ +#include "clar_libgit2.h" +#include "net.h" + +static git_net_url conndata; + +void test_network_url_parse__initialize(void) +{ + memset(&conndata, 0, sizeof(conndata)); +} + +void test_network_url_parse__cleanup(void) +{ + git_net_url_dispose(&conndata); +} + +/* Hostname */ + +void test_network_url_parse__hostname_trivial(void) +{ + cl_git_pass(git_net_url_parse(&conndata, "http://example.com/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_parse__hostname_root(void) +{ + cl_git_pass(git_net_url_parse(&conndata, "http://example.com/")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_parse__hostname_implied_root(void) +{ + cl_git_pass(git_net_url_parse(&conndata, "http://example.com")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_parse__hostname_implied_root_custom_port(void) +{ + cl_git_pass(git_net_url_parse(&conndata, "http://example.com:42")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "42"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_network_url_parse__hostname_implied_root_empty_port(void) +{ + cl_git_pass(git_net_url_parse(&conndata, "http://example.com:")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_parse__hostname_encoded_password(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://user:pass%2fis%40bad@hostname.com:1234/")); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "hostname.com"); + cl_assert_equal_s(conndata.port, "1234"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass/is@bad"); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_network_url_parse__hostname_user(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://user@example.com/resource")); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "443"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_parse__hostname_user_pass(void) +{ + /* user:pass@hostname.tld/resource */ + cl_git_pass(git_net_url_parse(&conndata, + "https://user:pass@example.com/resource")); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "443"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass"); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_parse__hostname_port(void) +{ + /* hostname.tld:port/resource */ + cl_git_pass(git_net_url_parse(&conndata, + "https://example.com:9191/resource")); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_network_url_parse__hostname_empty_port(void) +{ + cl_git_pass(git_net_url_parse(&conndata, "http://example.com:/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_parse__hostname_user_port(void) +{ + /* user@hostname.tld:port/resource */ + cl_git_pass(git_net_url_parse(&conndata, + "https://user@example.com:9191/resource")); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_network_url_parse__hostname_user_pass_port(void) +{ + /* user:pass@hostname.tld:port/resource */ + cl_git_pass(git_net_url_parse(&conndata, + "https://user:pass@example.com:9191/resource")); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass"); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +/* IPv4 addresses */ + +void test_network_url_parse__ipv4_trivial(void) +{ + cl_git_pass(git_net_url_parse(&conndata, "http://192.168.1.1/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_parse__ipv4_root(void) +{ + cl_git_pass(git_net_url_parse(&conndata, "http://192.168.1.1/")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_parse__ipv4_implied_root(void) +{ + cl_git_pass(git_net_url_parse(&conndata, "http://192.168.1.1")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_parse__ipv4_implied_root_custom_port(void) +{ + cl_git_pass(git_net_url_parse(&conndata, "http://192.168.1.1:42")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "42"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_network_url_parse__ipv4_implied_root_empty_port(void) +{ + cl_git_pass(git_net_url_parse(&conndata, "http://192.168.1.1:")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_parse__ipv4_encoded_password(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://user:pass%2fis%40bad@192.168.1.1:1234/")); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "1234"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass/is@bad"); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_network_url_parse__ipv4_user(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://user@192.168.1.1/resource")); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "443"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_parse__ipv4_user_pass(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://user:pass@192.168.1.1/resource")); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "443"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass"); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_parse__ipv4_port(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://192.168.1.1:9191/resource")); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_network_url_parse__ipv4_empty_port(void) +{ + cl_git_pass(git_net_url_parse(&conndata, "http://192.168.1.1:/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_parse__ipv4_user_port(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://user@192.168.1.1:9191/resource")); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_network_url_parse__ipv4_user_pass_port(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://user:pass@192.168.1.1:9191/resource")); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "192.168.1.1"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass"); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +/* IPv6 addresses */ + +void test_network_url_parse__ipv6_trivial(void) +{ + cl_git_pass(git_net_url_parse(&conndata, "http://[fe80::dcad:beff:fe00:0001]/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_parse__ipv6_root(void) +{ + cl_git_pass(git_net_url_parse(&conndata, "http://[fe80::dcad:beff:fe00:0001]/")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_parse__ipv6_implied_root(void) +{ + cl_git_pass(git_net_url_parse(&conndata, "http://[fe80::dcad:beff:fe00:0001]")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_parse__ipv6_implied_root_custom_port(void) +{ + cl_git_pass(git_net_url_parse(&conndata, "http://[fe80::dcad:beff:fe00:0001]:42")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "42"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_network_url_parse__ipv6_implied_root_empty_port(void) +{ + cl_git_pass(git_net_url_parse(&conndata, "http://[fe80::dcad:beff:fe00:0001]:")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_parse__ipv6_encoded_password(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://user:pass%2fis%40bad@[fe80::dcad:beff:fe00:0001]:1234/")); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "1234"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass/is@bad"); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_network_url_parse__ipv6_user(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://user@[fe80::dcad:beff:fe00:0001]/resource")); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "443"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_parse__ipv6_user_pass(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://user:pass@[fe80::dcad:beff:fe00:0001]/resource")); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "443"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass"); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_parse__ipv6_port(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://[fe80::dcad:beff:fe00:0001]:9191/resource")); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_network_url_parse__ipv6_empty_port(void) +{ + cl_git_pass(git_net_url_parse(&conndata, "http://[fe80::dcad:beff:fe00:0001]:/resource")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_parse__ipv6_user_port(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://user@[fe80::dcad:beff:fe00:0001]:9191/resource")); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_network_url_parse__ipv6_user_pass_port(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://user:pass@[fe80::dcad:beff:fe00:0001]:9191/resource")); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "fe80::dcad:beff:fe00:0001"); + cl_assert_equal_s(conndata.port, "9191"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "user"); + cl_assert_equal_s(conndata.password, "pass"); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_network_url_parse__ipv6_invalid_addresses(void) +{ + /* Opening bracket missing */ + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "http://fe80::dcad:beff:fe00:0001]/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "http://fe80::dcad:beff:fe00:0001]/")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "http://fe80::dcad:beff:fe00:0001]")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "http://fe80::dcad:beff:fe00:0001]:42")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "http://fe80::dcad:beff:fe00:0001]:")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "https://user:pass%2fis%40bad@fe80::dcad:beff:fe00:0001]:1234/")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "https://user@fe80::dcad:beff:fe00:0001]/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "https://user:pass@fe80::dcad:beff:fe00:0001]/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "https://fe80::dcad:beff:fe00:0001]:9191/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "http://fe80::dcad:beff:fe00:0001]:/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "https://user@fe80::dcad:beff:fe00:0001]:9191/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "https://user:pass@fe80::dcad:beff:fe00:0001]:9191/resource")); + + /* Closing bracket missing */ + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "http://[fe80::dcad:beff:fe00:0001/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "http://[fe80::dcad:beff:fe00:0001/")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "http://[fe80::dcad:beff:fe00:0001")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "http://[fe80::dcad:beff:fe00:0001:42")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "http://[fe80::dcad:beff:fe00:0001:")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "https://user:pass%2fis%40bad@[fe80::dcad:beff:fe00:0001:1234/")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "https://user@[fe80::dcad:beff:fe00:0001/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "https://user:pass@[fe80::dcad:beff:fe00:0001/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "https://[fe80::dcad:beff:fe00:0001:9191/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "http://[fe80::dcad:beff:fe00:0001:/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "https://user@[fe80::dcad:beff:fe00:0001:9191/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "https://user:pass@[fe80::dcad:beff:fe00:0001:9191/resource")); + /* Both brackets missing */ + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "http://fe80::dcad:beff:fe00:0001/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "http://fe80::dcad:beff:fe00:0001/")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "http://fe80::dcad:beff:fe00:0001")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "http://fe80::dcad:beff:fe00:0001:42")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "http://fe80::dcad:beff:fe00:0001:")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "https://user:pass%2fis%40bad@fe80::dcad:beff:fe00:0001:1234/")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "https://user@fe80::dcad:beff:fe00:0001/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "https://user:pass@fe80::dcad:beff:fe00:0001/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "https://fe80::dcad:beff:fe00:0001:9191/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "http://fe80::dcad:beff:fe00:0001:/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "https://user@fe80::dcad:beff:fe00:0001:9191/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "https://user:pass@fe80::dcad:beff:fe00:0001:9191/resource")); + + /* Invalid character inside address */ + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, "http://[fe8o::dcad:beff:fe00:0001]/resource")); +} diff --git a/tests/libgit2/network/url/pattern.c b/tests/libgit2/network/url/pattern.c new file mode 100644 index 000000000..5e4495f70 --- /dev/null +++ b/tests/libgit2/network/url/pattern.c @@ -0,0 +1,103 @@ +#include "clar_libgit2.h" +#include "net.h" + +struct url_pattern { + const char *url; + const char *pattern; + bool matches; +}; + +void test_network_url_pattern__single(void) +{ + git_net_url url; + size_t i; + + struct url_pattern url_patterns[] = { + /* Wildcard matches */ + { "https://example.com/", "", false }, + { "https://example.com/", "*", true }, + + /* Literal and wildcard matches */ + { "https://example.com/", "example.com", true }, + { "https://example.com/", ".example.com", true }, + { "https://example.com/", "*.example.com", true }, + { "https://www.example.com/", "www.example.com", true }, + { "https://www.example.com/", ".example.com", true }, + { "https://www.example.com/", "*.example.com", true }, + + /* Literal and wildcard failures */ + { "https://example.com/", "example.org", false }, + { "https://example.com/", ".example.org", false }, + { "https://example.com/", "*.example.org", false }, + { "https://foo.example.com/", "www.example.com", false }, + + /* + * A port in the pattern is optional; if no port is + * present, it matches *all* ports. + */ + { "https://example.com/", "example.com:443", true }, + { "https://example.com/", "example.com:80", false }, + { "https://example.com:1443/", "example.com", true }, + + /* Failures with similar prefix/suffix */ + { "https://texample.com/", "example.com", false }, + { "https://example.com/", "mexample.com", false }, + { "https://example.com:44/", "example.com:443", false }, + { "https://example.com:443/", "example.com:44", false }, + }; + + for (i = 0; i < ARRAY_SIZE(url_patterns); i++) { + cl_git_pass(git_net_url_parse(&url, url_patterns[i].url)); + cl_assert_(git_net_url_matches_pattern(&url, url_patterns[i].pattern) == url_patterns[i].matches, url_patterns[i].pattern); + git_net_url_dispose(&url); + } +} + +void test_network_url_pattern__list(void) +{ + git_net_url url; + size_t i; + + struct url_pattern url_patterns[] = { + /* Wildcard matches */ + { "https://example.com/", "", false }, + { "https://example.com/", "*", true }, + { "https://example.com/", ",example.com,", true }, + { "https://example.com/", "foo,,example.com,,bar", true }, + { "https://example.com/", "foo,,zzz,,*,,bar", true }, + + /* Literals */ + { "https://example.com/", "example.com", true }, + { "https://example.com/", "foo.bar,example.com", true }, + { "https://example.com/", "foo.bar", false }, + { "https://example.com/", "foo.bar,example.org", false }, + { "https://www.example.com/", "foo.example.com,www.example.com,bar.example.com", true }, + { "https://www.example.com/", "foo.example.com,baz.example.com,bar.example.com", false }, + { "https://foo.example.com/", "www.example.com", false }, + { "https://foo.example.com/", "bar.example.com,www.example.com,", false }, + + /* Wildcards */ + { "https://example.com/", ".example.com", true }, + { "https://example.com/", "*.example.com", true }, + { "https://example.com/", "foo.com,bar.com,.example.com", true }, + { "https://example.com/", ".foo.com,.bar.com,.example.com", true }, + { "https://example.com/", ".foo.com,.bar.com,asdf.com", false }, + { "https://example.com/", "*.foo,*.bar,*.example.com,*.asdf", true }, + { "https://example.com/", "*.foo,*.bar,*.asdf", false }, + + + /* Ports! */ + { "https://example.com/", "example.com:443", true }, + { "https://example.com/", "example.com:42,example.com:443,example.com:99", true }, + { "https://example.com/", "example.com:42,example.com:80,example.org:443", false }, + { "https://example.com:1443/", "example.com", true }, + { "https://example.com:44/", "example.com:443", false }, + { "https://example.com:443/", "example.com:44", false }, + }; + + for (i = 0; i < ARRAY_SIZE(url_patterns); i++) { + cl_git_pass(git_net_url_parse(&url, url_patterns[i].url)); + cl_assert_(git_net_url_matches_pattern_list(&url, url_patterns[i].pattern) == url_patterns[i].matches, url_patterns[i].pattern); + git_net_url_dispose(&url); + } +} diff --git a/tests/libgit2/network/url/redirect.c b/tests/libgit2/network/url/redirect.c new file mode 100644 index 000000000..a94db7daf --- /dev/null +++ b/tests/libgit2/network/url/redirect.c @@ -0,0 +1,147 @@ +#include "clar_libgit2.h" +#include "net.h" +#include "netops.h" + +static git_net_url conndata; + +void test_network_url_redirect__initialize(void) +{ + memset(&conndata, 0, sizeof(conndata)); +} + +void test_network_url_redirect__cleanup(void) +{ + git_net_url_dispose(&conndata); +} + +void test_network_url_redirect__redirect_http(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "http://example.com/foo/bar/baz")); + cl_git_pass(git_net_url_apply_redirect(&conndata, + "http://example.com/foo/bar/baz", false, "bar/baz")); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/foo/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); +} + +void test_network_url_redirect__redirect_ssl(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://example.com/foo/bar/baz")); + cl_git_pass(git_net_url_apply_redirect(&conndata, + "https://example.com/foo/bar/baz", false, "bar/baz")); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "443"); + cl_assert_equal_s(conndata.path, "/foo/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); +} + +void test_network_url_redirect__redirect_leaves_root_path(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://example.com/foo/bar/baz")); + cl_git_pass(git_net_url_apply_redirect(&conndata, + "https://example.com/foo/bar/baz", false, "/foo/bar/baz")); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "443"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); +} + +void test_network_url_redirect__redirect_encoded_username_password(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz")); + cl_git_pass(git_net_url_apply_redirect(&conndata, + "https://user%2fname:pass%40word%zyx%v@example.com/foo/bar/baz", false, "bar/baz")); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "443"); + cl_assert_equal_s(conndata.path, "/foo/"); + cl_assert_equal_s(conndata.username, "user/name"); + cl_assert_equal_s(conndata.password, "pass@word%zyx%v"); +} + +void test_network_url_redirect__redirect_cross_host_allowed(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://bar.com/bar/baz")); + cl_git_pass(git_net_url_apply_redirect(&conndata, + "https://foo.com/bar/baz", true, NULL)); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "foo.com"); + cl_assert_equal_s(conndata.port, "443"); + cl_assert_equal_s(conndata.path, "/bar/baz"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); +} + +void test_network_url_redirect__redirect_cross_host_denied(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://bar.com/bar/baz")); + cl_git_fail_with(git_net_url_apply_redirect(&conndata, + "https://foo.com/bar/baz", false, NULL), -1); +} + +void test_network_url_redirect__redirect_http_downgrade_denied(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://foo.com/bar/baz")); + cl_git_fail_with(git_net_url_apply_redirect(&conndata, + "http://foo.com/bar/baz", true, NULL), -1); +} + +void test_network_url_redirect__redirect_relative(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "http://foo.com/bar/baz/biff")); + cl_git_pass(git_net_url_apply_redirect(&conndata, + "/zap/baz/biff?bam", true, NULL)); + cl_assert_equal_s(conndata.scheme, "http"); + cl_assert_equal_s(conndata.host, "foo.com"); + cl_assert_equal_s(conndata.port, "80"); + cl_assert_equal_s(conndata.path, "/zap/baz/biff?bam"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); +} + +void test_network_url_redirect__redirect_relative_ssl(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://foo.com/bar/baz/biff")); + cl_git_pass(git_net_url_apply_redirect(&conndata, + "/zap/baz/biff?bam", true, NULL)); + cl_assert_equal_s(conndata.scheme, "https"); + cl_assert_equal_s(conndata.host, "foo.com"); + cl_assert_equal_s(conndata.port, "443"); + cl_assert_equal_s(conndata.path, "/zap/baz/biff?bam"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); +} + +void test_network_url_redirect__service_query_no_query_params_in_location(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://foo.com/bar/info/refs?service=git-upload-pack")); + cl_git_pass(git_net_url_apply_redirect(&conndata, + "/baz/info/refs", true, "/info/refs?service=git-upload-pack")); + cl_assert_equal_s(conndata.path, "/baz"); +} + +void test_network_url_redirect__service_query_with_query_params_in_location(void) +{ + cl_git_pass(git_net_url_parse(&conndata, + "https://foo.com/bar/info/refs?service=git-upload-pack")); + cl_git_pass(git_net_url_apply_redirect(&conndata, + "/baz/info/refs?service=git-upload-pack", true, "/info/refs?service=git-upload-pack")); + cl_assert_equal_s(conndata.path, "/baz"); +} diff --git a/tests/libgit2/network/url/scp.c b/tests/libgit2/network/url/scp.c new file mode 100644 index 000000000..8cdc832ae --- /dev/null +++ b/tests/libgit2/network/url/scp.c @@ -0,0 +1,321 @@ +#include "clar_libgit2.h" +#include "net.h" + +static git_net_url conndata; + +void test_network_url_scp__initialize(void) +{ + memset(&conndata, 0, sizeof(conndata)); +} + +void test_network_url_scp__cleanup(void) +{ + git_net_url_dispose(&conndata); +} + +/* Hostname */ + +void test_network_url_scp__hostname_trivial(void) +{ + cl_git_pass(git_net_url_parse_scp(&conndata, "example.com:/resource")); + cl_assert_equal_s(conndata.scheme, "ssh"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "22"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_scp__hostname_bracketed(void) +{ + cl_git_pass(git_net_url_parse_scp(&conndata, "[example.com]:/resource")); + cl_assert_equal_s(conndata.scheme, "ssh"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "22"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_scp__hostname_root(void) +{ + cl_git_pass(git_net_url_parse_scp(&conndata, "example.com:/")); + cl_assert_equal_s(conndata.scheme, "ssh"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "22"); + cl_assert_equal_s(conndata.path, "/"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_scp__hostname_user(void) +{ + cl_git_pass(git_net_url_parse_scp(&conndata, "git@example.com:/resource")); + cl_assert_equal_s(conndata.scheme, "ssh"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "22"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "git"); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_scp__hostname_user_bracketed(void) +{ + cl_git_pass(git_net_url_parse_scp(&conndata, "[git@example.com]:/resource")); + cl_assert_equal_s(conndata.scheme, "ssh"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "22"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "git"); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_scp__hostname_port(void) +{ + cl_git_pass(git_net_url_parse_scp(&conndata, "[example.com:42]:/resource")); + cl_assert_equal_s(conndata.scheme, "ssh"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "42"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_network_url_scp__hostname_user_port(void) +{ + cl_git_pass(git_net_url_parse_scp(&conndata, "[git@example.com:42]:/resource")); + cl_assert_equal_s(conndata.scheme, "ssh"); + cl_assert_equal_s(conndata.host, "example.com"); + cl_assert_equal_s(conndata.port, "42"); + cl_assert_equal_s(conndata.path, "/resource"); + cl_assert_equal_s(conndata.username, "git"); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_network_url_scp__ipv4_trivial(void) +{ + cl_git_pass(git_net_url_parse_scp(&conndata, "192.168.99.88:/resource/a/b/c")); + cl_assert_equal_s(conndata.scheme, "ssh"); + cl_assert_equal_s(conndata.host, "192.168.99.88"); + cl_assert_equal_s(conndata.port, "22"); + cl_assert_equal_s(conndata.path, "/resource/a/b/c"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_scp__ipv4_bracketed(void) +{ + cl_git_pass(git_net_url_parse_scp(&conndata, "[192.168.99.88]:/resource/a/b/c")); + cl_assert_equal_s(conndata.scheme, "ssh"); + cl_assert_equal_s(conndata.host, "192.168.99.88"); + cl_assert_equal_s(conndata.port, "22"); + cl_assert_equal_s(conndata.path, "/resource/a/b/c"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_scp__ipv4_user(void) +{ + cl_git_pass(git_net_url_parse_scp(&conndata, "git@192.168.99.88:/resource/a/b/c")); + cl_assert_equal_s(conndata.scheme, "ssh"); + cl_assert_equal_s(conndata.host, "192.168.99.88"); + cl_assert_equal_s(conndata.port, "22"); + cl_assert_equal_s(conndata.path, "/resource/a/b/c"); + cl_assert_equal_s(conndata.username, "git"); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_scp__ipv4_port(void) +{ + cl_git_pass(git_net_url_parse_scp(&conndata, "[192.168.99.88:1111]:/resource/a/b/c")); + cl_assert_equal_s(conndata.scheme, "ssh"); + cl_assert_equal_s(conndata.host, "192.168.99.88"); + cl_assert_equal_s(conndata.port, "1111"); + cl_assert_equal_s(conndata.path, "/resource/a/b/c"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_network_url_scp__ipv4_user_port(void) +{ + cl_git_pass(git_net_url_parse_scp(&conndata, "[git@192.168.99.88:1111]:/resource/a/b/c")); + cl_assert_equal_s(conndata.scheme, "ssh"); + cl_assert_equal_s(conndata.host, "192.168.99.88"); + cl_assert_equal_s(conndata.port, "1111"); + cl_assert_equal_s(conndata.path, "/resource/a/b/c"); + cl_assert_equal_s(conndata.username, "git"); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_network_url_scp__ipv6_trivial(void) +{ + cl_git_pass(git_net_url_parse_scp(&conndata, "[fe80::dcad:beff:fe00:0001]:/resource/foo")); + cl_assert_equal_s(conndata.scheme, "ssh"); + cl_assert_equal_s(conndata.host, "[fe80::dcad:beff:fe00:0001]"); + cl_assert_equal_s(conndata.port, "22"); + cl_assert_equal_s(conndata.path, "/resource/foo"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_scp__ipv6_user(void) +{ + cl_git_pass(git_net_url_parse_scp(&conndata, "git@[fe80::dcad:beff:fe00:0001]:/resource/foo")); + cl_assert_equal_s(conndata.scheme, "ssh"); + cl_assert_equal_s(conndata.host, "[fe80::dcad:beff:fe00:0001]"); + cl_assert_equal_s(conndata.port, "22"); + cl_assert_equal_s(conndata.path, "/resource/foo"); + cl_assert_equal_s(conndata.username, "git"); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_scp__ipv6_port(void) +{ + cl_git_pass(git_net_url_parse_scp(&conndata, "[[fe80::dcad:beff:fe00:0001]:99]:/resource/foo")); + cl_assert_equal_s(conndata.scheme, "ssh"); + cl_assert_equal_s(conndata.host, "[fe80::dcad:beff:fe00:0001]"); + cl_assert_equal_s(conndata.port, "99"); + cl_assert_equal_s(conndata.path, "/resource/foo"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_network_url_scp__ipv6_user_port(void) +{ + cl_git_pass(git_net_url_parse_scp(&conndata, "[git@[fe80::dcad:beff:fe00:0001]:99]:/resource/foo")); + cl_assert_equal_s(conndata.scheme, "ssh"); + cl_assert_equal_s(conndata.host, "[fe80::dcad:beff:fe00:0001]"); + cl_assert_equal_s(conndata.port, "99"); + cl_assert_equal_s(conndata.path, "/resource/foo"); + cl_assert_equal_s(conndata.username, "git"); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 0); +} + +void test_network_url_scp__hexhost_and_port(void) +{ + cl_git_pass(git_net_url_parse_scp(&conndata, "[fe:22]:/resource/foo")); + cl_assert_equal_s(conndata.scheme, "ssh"); + cl_assert_equal_s(conndata.host, "fe"); + cl_assert_equal_s(conndata.port, "22"); + cl_assert_equal_s(conndata.path, "/resource/foo"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_scp__malformed_ipv6_one(void) +{ + cl_git_pass(git_net_url_parse_scp(&conndata, "fe80::dcad:beff:fe00:0001]:/resource")); + cl_assert_equal_s(conndata.scheme, "ssh"); + cl_assert_equal_s(conndata.host, "fe80"); + cl_assert_equal_s(conndata.port, "22"); + cl_assert_equal_s(conndata.path, ":dcad:beff:fe00:0001]:/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_scp__malformed_ipv6_two(void) +{ + cl_git_pass(git_net_url_parse_scp(&conndata, "[fe80::dcad:beff:fe00:0001]:42]:/resource")); + cl_assert_equal_s(conndata.scheme, "ssh"); + cl_assert_equal_s(conndata.host, "[fe80::dcad:beff:fe00:0001]"); + cl_assert_equal_s(conndata.port, "22"); + cl_assert_equal_s(conndata.path, "42]:/resource"); + cl_assert_equal_p(conndata.username, NULL); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_scp__malformed_ipv6_with_user(void) +{ + cl_git_pass(git_net_url_parse_scp(&conndata, "git@[fe80::dcad:beff:fe00:0001]:42]:/resource")); + cl_assert_equal_s(conndata.scheme, "ssh"); + cl_assert_equal_s(conndata.host, "[fe80::dcad:beff:fe00:0001]"); + cl_assert_equal_s(conndata.port, "22"); + cl_assert_equal_s(conndata.path, "42]:/resource"); + cl_assert_equal_s(conndata.username, "git"); + cl_assert_equal_p(conndata.password, NULL); + cl_assert_equal_i(git_net_url_is_default_port(&conndata), 1); +} + +void test_network_url_scp__invalid_addresses(void) +{ + /* Path is required */ + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + "example.com")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + "example.com:")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + "[example.com:42]:")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + "[git@example.com:42]:")); + + /* Host is required */ + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + ":")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + ":foo")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + "git@:foo")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + "[]:")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + "git@[]:")); + + /* User is required if specified */ + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + "@example.com:foo")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + "@:foo")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + "[@localhost:22]:foo")); + + /* Port is required in brackets */ + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + "[example.com:]:foo")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + "[git@example.com:]:foo")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + "[fe:]:foo")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + "[@localhost]:foo")); + + /* Extra brackets are disallowed */ + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + "[git@[[fe80::dcad:beff:fe00:0001]]:42]:foo")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + "[[git@[fe80::dcad:beff:fe00:0001]]:42]:foo")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + "[[git@[fe80::dcad:beff:fe00:0001]:42]]:foo")); + + /* Closing bracket missing */ + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + "[fe80::dcad:beff:fe00:0001:/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + "[[fe80::dcad:beff:fe00:0001]:42:/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + "[git@[fe80::dcad:beff:fe00:0001]:42:/resource")); + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse_scp(&conndata, + "[git@[fe80::dcad:beff:fe00:0001:42]:/resource")); + + /* Invalid character inside address */ + cl_git_fail_with(GIT_EINVALIDSPEC, git_net_url_parse(&conndata, + "[fe8o::dcad:beff:fe00:0001]:/resource")); +} diff --git a/tests/libgit2/network/url/valid.c b/tests/libgit2/network/url/valid.c new file mode 100644 index 000000000..2b2cb7ba4 --- /dev/null +++ b/tests/libgit2/network/url/valid.c @@ -0,0 +1,17 @@ +#include "clar_libgit2.h" +#include "net.h" + +void test_network_url_valid__test(void) +{ + cl_assert(git_net_str_is_url("http://example.com/")); + cl_assert(git_net_str_is_url("file://localhost/tmp/foo/")); + cl_assert(git_net_str_is_url("ssh://user@host:42/tmp")); + cl_assert(git_net_str_is_url("git+ssh://user@host:42/tmp")); + cl_assert(git_net_str_is_url("ssh+git://user@host:42/tmp")); + cl_assert(git_net_str_is_url("https://user:pass@example.com/foo/bar")); + + cl_assert(!git_net_str_is_url("host:foo.git")); + cl_assert(!git_net_str_is_url("host:/foo.git")); + cl_assert(!git_net_str_is_url("[host:42]:/foo.git")); + cl_assert(!git_net_str_is_url("[user@host:42]:/foo.git")); +} |
