diff options
Diffstat (limited to 't')
47 files changed, 995 insertions, 463 deletions
diff --git a/t/Makefile b/t/Makefile index daa5fcae86..2994eb5fa9 100644 --- a/t/Makefile +++ b/t/Makefile @@ -177,3 +177,18 @@ perf: .PHONY: pre-clean $(T) aggregate-results clean valgrind perf \ check-chainlint clean-chainlint test-chainlint $(UNIT_TESTS) + +.PHONY: libgit-sys-test libgit-rs-test +libgit-sys-test: + $(QUIET)(\ + cd ../contrib/libgit-sys && \ + cargo test \ + ) +libgit-rs-test: + $(QUIET)(\ + cd ../contrib/libgit-rs && \ + cargo test \ + ) +ifdef INCLUDE_LIBGIT_RS +all:: libgit-sys-test libgit-rs-test +endif @@ -471,6 +471,10 @@ a test and then fails then the whole test run will abort. This can help to make sure the expected tests are executed and not silently skipped when their dependency breaks or is simply not present in a new environment. +GIT_TEST_NAME_HASH_VERSION=<int>, when set, causes 'git pack-objects' to +assume '--name-hash-version=<n>'. + + Naming Tests ------------ diff --git a/t/helper/meson.build b/t/helper/meson.build index f502d1aaa3..1d6154ce97 100644 --- a/t/helper/meson.build +++ b/t/helper/meson.build @@ -34,6 +34,7 @@ test_tool_sources = [ 'test-match-trees.c', 'test-mergesort.c', 'test-mktemp.c', + 'test-name-hash.c', 'test-online-cpus.c', 'test-pack-mtimes.c', 'test-parse-options.c', diff --git a/t/helper/test-hash-speed.c b/t/helper/test-hash-speed.c index 80df1aae66..fbf67fe6bd 100644 --- a/t/helper/test-hash-speed.c +++ b/t/helper/test-hash-speed.c @@ -3,16 +3,16 @@ #define NUM_SECONDS 3 -static inline void compute_hash(const struct git_hash_algo *algo, git_hash_ctx *ctx, uint8_t *final, const void *p, size_t len) +static inline void compute_hash(const struct git_hash_algo *algo, struct git_hash_ctx *ctx, uint8_t *final, const void *p, size_t len) { algo->init_fn(ctx); - algo->update_fn(ctx, p, len); - algo->final_fn(final, ctx); + git_hash_update(ctx, p, len); + git_hash_final(final, ctx); } int cmd__hash_speed(int ac, const char **av) { - git_hash_ctx ctx; + struct git_hash_ctx ctx; unsigned char hash[GIT_MAX_RAWSZ]; clock_t initial, start, end; unsigned bufsizes[] = { 64, 256, 1024, 8192, 16384 }; diff --git a/t/helper/test-hash.c b/t/helper/test-hash.c index 45d829c908..f0ee61c8b4 100644 --- a/t/helper/test-hash.c +++ b/t/helper/test-hash.c @@ -1,14 +1,16 @@ #include "test-tool.h" #include "hex.h" -int cmd_hash_impl(int ac, const char **av, int algo) +int cmd_hash_impl(int ac, const char **av, int algo, int unsafe) { - git_hash_ctx ctx; + struct git_hash_ctx ctx; unsigned char hash[GIT_MAX_HEXSZ]; unsigned bufsz = 8192; int binary = 0; char *buffer; const struct git_hash_algo *algop = &hash_algos[algo]; + if (unsafe) + algop = unsafe_hash_algo(algop); if (ac == 2) { if (!strcmp(av[1], "-b")) @@ -46,9 +48,9 @@ int cmd_hash_impl(int ac, const char **av, int algo) } if (this_sz == 0) break; - algop->update_fn(&ctx, buffer, this_sz); + git_hash_update(&ctx, buffer, this_sz); } - algop->final_fn(hash, &ctx); + git_hash_final(hash, &ctx); if (binary) fwrite(hash, 1, algop->rawsz, stdout); diff --git a/t/helper/test-name-hash.c b/t/helper/test-name-hash.c new file mode 100644 index 0000000000..af1d52de10 --- /dev/null +++ b/t/helper/test-name-hash.c @@ -0,0 +1,23 @@ +/* + * test-name-hash.c: Read a list of paths over stdin and report on their + * name-hash and full name-hash. + */ + +#include "test-tool.h" +#include "git-compat-util.h" +#include "pack-objects.h" +#include "strbuf.h" + +int cmd__name_hash(int argc UNUSED, const char **argv UNUSED) +{ + struct strbuf line = STRBUF_INIT; + + while (!strbuf_getline(&line, stdin)) { + printf("%10u ", pack_name_hash(line.buf)); + printf("%10u ", pack_name_hash_v2((unsigned const char *)line.buf)); + printf("%s\n", line.buf); + } + + strbuf_release(&line); + return 0; +} diff --git a/t/helper/test-sha1.c b/t/helper/test-sha1.c index e60d000c03..349540c4df 100644 --- a/t/helper/test-sha1.c +++ b/t/helper/test-sha1.c @@ -3,7 +3,7 @@ int cmd__sha1(int ac, const char **av) { - return cmd_hash_impl(ac, av, GIT_HASH_SHA1); + return cmd_hash_impl(ac, av, GIT_HASH_SHA1, 0); } int cmd__sha1_is_sha1dc(int argc UNUSED, const char **argv UNUSED) @@ -13,3 +13,8 @@ int cmd__sha1_is_sha1dc(int argc UNUSED, const char **argv UNUSED) #endif return 1; } + +int cmd__sha1_unsafe(int ac, const char **av) +{ + return cmd_hash_impl(ac, av, GIT_HASH_SHA1, 1); +} diff --git a/t/helper/test-sha1.sh b/t/helper/test-sha1.sh index 84594885c7..bf387d3db1 100755 --- a/t/helper/test-sha1.sh +++ b/t/helper/test-sha1.sh @@ -3,25 +3,31 @@ dd if=/dev/zero bs=1048576 count=100 2>/dev/null | /usr/bin/time t/helper/test-tool sha1 >/dev/null +dd if=/dev/zero bs=1048576 count=100 2>/dev/null | +/usr/bin/time t/helper/test-tool sha1-unsafe >/dev/null + while read expect cnt pfx do case "$expect" in '#'*) continue ;; esac - actual=$( - { - test -z "$pfx" || echo "$pfx" - dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null | - perl -pe 'y/\000/g/' - } | ./t/helper/test-tool sha1 $cnt - ) - if test "$expect" = "$actual" - then - echo "OK: $expect $cnt $pfx" - else - echo >&2 "OOPS: $cnt" - echo >&2 "expect: $expect" - echo >&2 "actual: $actual" - exit 1 - fi + for sha1 in sha1 sha1-unsafe + do + actual=$( + { + test -z "$pfx" || echo "$pfx" + dd if=/dev/zero bs=1048576 count=$cnt 2>/dev/null | + perl -pe 'y/\000/g/' + } | ./t/helper/test-tool $sha1 $cnt + ) + if test "$expect" = "$actual" + then + echo "OK ($sha1): $expect $cnt $pfx" + else + echo >&2 "OOPS ($sha1): $cnt" + echo >&2 "expect ($sha1): $expect" + echo >&2 "actual ($sha1): $actual" + exit 1 + fi + done done <<EOF da39a3ee5e6b4b0d3255bfef95601890afd80709 0 3f786850e387550fdab836ed7e6dc881de23001b 0 a diff --git a/t/helper/test-sha256.c b/t/helper/test-sha256.c index 2fb20438f3..7fd0aa1fcd 100644 --- a/t/helper/test-sha256.c +++ b/t/helper/test-sha256.c @@ -3,5 +3,5 @@ int cmd__sha256(int ac, const char **av) { - return cmd_hash_impl(ac, av, GIT_HASH_SHA256); + return cmd_hash_impl(ac, av, GIT_HASH_SHA256, 0); } diff --git a/t/helper/test-tool.c b/t/helper/test-tool.c index 69a9ffa1eb..50dc4dac4e 100644 --- a/t/helper/test-tool.c +++ b/t/helper/test-tool.c @@ -44,6 +44,7 @@ static struct test_cmd cmds[] = { { "match-trees", cmd__match_trees }, { "mergesort", cmd__mergesort }, { "mktemp", cmd__mktemp }, + { "name-hash", cmd__name_hash }, { "online-cpus", cmd__online_cpus }, { "pack-mtimes", cmd__pack_mtimes }, { "parse-options", cmd__parse_options }, @@ -71,6 +72,7 @@ static struct test_cmd cmds[] = { { "serve-v2", cmd__serve_v2 }, { "sha1", cmd__sha1 }, { "sha1-is-sha1dc", cmd__sha1_is_sha1dc }, + { "sha1-unsafe", cmd__sha1_unsafe }, { "sha256", cmd__sha256 }, { "sigchain", cmd__sigchain }, { "simple-ipc", cmd__simple_ipc }, diff --git a/t/helper/test-tool.h b/t/helper/test-tool.h index 9cfc5da6e5..6d62a5b53d 100644 --- a/t/helper/test-tool.h +++ b/t/helper/test-tool.h @@ -37,6 +37,7 @@ int cmd__lazy_init_name_hash(int argc, const char **argv); int cmd__match_trees(int argc, const char **argv); int cmd__mergesort(int argc, const char **argv); int cmd__mktemp(int argc, const char **argv); +int cmd__name_hash(int argc, const char **argv); int cmd__online_cpus(int argc, const char **argv); int cmd__pack_mtimes(int argc, const char **argv); int cmd__parse_options(int argc, const char **argv); @@ -64,6 +65,7 @@ int cmd__scrap_cache_tree(int argc, const char **argv); int cmd__serve_v2(int argc, const char **argv); int cmd__sha1(int argc, const char **argv); int cmd__sha1_is_sha1dc(int argc, const char **argv); +int cmd__sha1_unsafe(int argc, const char **argv); int cmd__sha256(int argc, const char **argv); int cmd__sigchain(int argc, const char **argv); int cmd__simple_ipc(int argc, const char **argv); @@ -82,6 +84,6 @@ int cmd__windows_named_pipe(int argc, const char **argv); #endif int cmd__write_cache(int argc, const char **argv); -int cmd_hash_impl(int ac, const char **av, int algo); +int cmd_hash_impl(int ac, const char **av, int algo, int unsafe); #endif diff --git a/t/meson.build b/t/meson.build index 35f25ca4a1..a03ebc81fd 100644 --- a/t/meson.build +++ b/t/meson.build @@ -1,9 +1,13 @@ clar_test_suites = [ 'unit-tests/u-ctype.c', + 'unit-tests/u-example-decorate.c', 'unit-tests/u-hash.c', + 'unit-tests/u-hashmap.c', 'unit-tests/u-mem-pool.c', 'unit-tests/u-prio-queue.c', 'unit-tests/u-reftable-tree.c', + 'unit-tests/u-strbuf.c', + 'unit-tests/u-strcmp-offset.c', 'unit-tests/u-strvec.c', ] @@ -44,8 +48,6 @@ clar_unit_tests = executable('unit-tests', test('unit-tests', clar_unit_tests) unit_test_programs = [ - 'unit-tests/t-example-decorate.c', - 'unit-tests/t-hashmap.c', 'unit-tests/t-oid-array.c', 'unit-tests/t-oidmap.c', 'unit-tests/t-oidtree.c', @@ -57,8 +59,6 @@ unit_test_programs = [ 'unit-tests/t-reftable-readwrite.c', 'unit-tests/t-reftable-record.c', 'unit-tests/t-reftable-stack.c', - 'unit-tests/t-strbuf.c', - 'unit-tests/t-strcmp-offset.c', 'unit-tests/t-trailer.c', 'unit-tests/t-urlmatch-normalization.c', ] @@ -721,6 +721,7 @@ integration_tests = [ 't5617-clone-submodules-remote.sh', 't5618-alternate-refs.sh', 't5619-clone-local-ambiguous-transport.sh', + 't5621-clone-revision.sh', 't5700-protocol-v1.sh', 't5701-git-serve.sh', 't5702-protocol-v2.sh', diff --git a/t/perf/p5313-pack-objects.sh b/t/perf/p5313-pack-objects.sh new file mode 100755 index 0000000000..be5229a0ec --- /dev/null +++ b/t/perf/p5313-pack-objects.sh @@ -0,0 +1,70 @@ +#!/bin/sh + +test_description='Tests pack performance using bitmaps' +. ./perf-lib.sh + +GIT_TEST_PASSING_SANITIZE_LEAK=0 +export GIT_TEST_PASSING_SANITIZE_LEAK + +test_perf_large_repo + +test_expect_success 'create rev input' ' + cat >in-thin <<-EOF && + $(git rev-parse HEAD) + ^$(git rev-parse HEAD~1) + EOF + + cat >in-big <<-EOF && + $(git rev-parse HEAD) + ^$(git rev-parse HEAD~1000) + EOF + + cat >in-shallow <<-EOF + $(git rev-parse HEAD) + --shallow $(git rev-parse HEAD) + EOF +' + +for version in 1 2 +do + export version + + test_perf "thin pack with version $version" ' + git pack-objects --thin --stdout --revs --sparse \ + --name-hash-version=$version <in-thin >out + ' + + test_size "thin pack size with version $version" ' + test_file_size out + ' + + test_perf "big pack with version $version" ' + git pack-objects --stdout --revs --sparse \ + --name-hash-version=$version <in-big >out + ' + + test_size "big pack size with version $version" ' + test_file_size out + ' + + test_perf "shallow fetch pack with version $version" ' + git pack-objects --stdout --revs --sparse --shallow \ + --name-hash-version=$version <in-shallow >out + ' + + test_size "shallow pack size with version $version" ' + test_file_size out + ' + + test_perf "repack with version $version" ' + git repack -adf --name-hash-version=$version + ' + + test_size "repack size with version $version" ' + gitdir=$(git rev-parse --git-dir) && + pack=$(ls $gitdir/objects/pack/pack-*.pack) && + test_file_size "$pack" + ' +done + +test_done diff --git a/t/perf/p5314-name-hash.sh b/t/perf/p5314-name-hash.sh new file mode 100755 index 0000000000..4ef0ba7711 --- /dev/null +++ b/t/perf/p5314-name-hash.sh @@ -0,0 +1,31 @@ +#!/bin/sh + +test_description='Tests pack performance using bitmaps' +. ./perf-lib.sh + +GIT_TEST_PASSING_SANITIZE_LEAK=0 +export GIT_TEST_PASSING_SANITIZE_LEAK + +test_perf_large_repo + +test_size 'paths at head' ' + git ls-tree -r --name-only HEAD >path-list && + wc -l <path-list && + test-tool name-hash <path-list >name-hashes +' + +for version in 1 2 +do + test_size "distinct hash value: v$version" ' + awk "{ print \$$version; }" <name-hashes | sort | \ + uniq -c >name-hash-count && + wc -l <name-hash-count + ' + + test_size "maximum multiplicity: v$version" ' + sort -nr <name-hash-count | head -n 1 | \ + awk "{ print \$1; }" + ' +done + +test_done diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 72a0c2e7d4..c49d9e0d38 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -586,6 +586,18 @@ test_expect_success 'GIT_DEFAULT_HASH overrides init.defaultObjectFormat' ' echo sha256 >expected ' +for hash in sha1 sha256 +do + test_expect_success "reinit repository with GIT_DEFAULT_HASH=$hash does not change format" ' + test_when_finished "rm -rf repo" && + git init repo && + git -C repo rev-parse --show-object-format >expect && + GIT_DEFAULT_HASH=$hash git init repo && + git -C repo rev-parse --show-object-format >actual && + test_cmp expect actual + ' +done + test_expect_success 'extensions.objectFormat is not allowed with repo version 0' ' test_when_finished "rm -rf explicit-v0" && git init --object-format=sha256 explicit-v0 && @@ -697,6 +709,15 @@ do git -C refformat rev-parse --show-ref-format >actual && test_cmp expect actual ' + + test_expect_success "reinit repository with GIT_DEFAULT_REF_FORMAT=$format does not change format" ' + test_when_finished "rm -rf refformat" && + git init refformat && + git -C refformat rev-parse --show-ref-format >expect && + GIT_DEFAULT_REF_FORMAT=$format git init refformat && + git -C refformat rev-parse --show-ref-format >actual && + test_cmp expect actual + ' done test_expect_success "--ref-format= overrides GIT_DEFAULT_REF_FORMAT" ' @@ -861,15 +882,6 @@ test_expect_success 're-init with includeIf.onbranch condition' ' test_cmp expect actual ' -test_expect_success 're-init with includeIf.onbranch condition' ' - test_when_finished "rm -rf repo" && - git init repo && - git -c includeIf.onbranch:nonexistent.path=/does/not/exist init repo && - echo $GIT_DEFAULT_REF_FORMAT >expect && - git -C repo rev-parse --show-ref-format >actual && - test_cmp expect actual -' - test_expect_success 're-init skips non-matching includeIf.onbranch' ' test_when_finished "rm -rf repo config" && cat >config <<-EOF && diff --git a/t/t0060-path-utils.sh b/t/t0060-path-utils.sh index dbb2e73bcd..8545cdfab5 100755 --- a/t/t0060-path-utils.sh +++ b/t/t0060-path-utils.sh @@ -592,17 +592,19 @@ test_lazy_prereq CAN_EXEC_IN_PWD ' ./git rev-parse ' +test_expect_success !VALGRIND,RUNTIME_PREFIX,CAN_EXEC_IN_PWD 'setup runtime prefix' ' + mkdir -p pretend/bin && + cp "$GIT_EXEC_PATH"/git$X pretend/bin/ +' + test_expect_success !VALGRIND,RUNTIME_PREFIX,CAN_EXEC_IN_PWD 'RUNTIME_PREFIX works' ' - mkdir -p pretend/bin pretend/libexec/git-core && + mkdir -p pretend/libexec/git-core && echo "echo HERE" | write_script pretend/libexec/git-core/git-here && - cp "$GIT_EXEC_PATH"/git$X pretend/bin/ && GIT_EXEC_PATH= ./pretend/bin/git here >actual && echo HERE >expect && test_cmp expect actual' test_expect_success !VALGRIND,RUNTIME_PREFIX,CAN_EXEC_IN_PWD '%(prefix)/ works' ' - mkdir -p pretend/bin && - cp "$GIT_EXEC_PATH"/git$X pretend/bin/ && git config yes.path "%(prefix)/yes" && GIT_EXEC_PATH= ./pretend/bin/git config --path yes.path >actual && echo "$(pwd)/pretend/yes" >expect && diff --git a/t/t0450/txt-help-mismatches b/t/t0450/txt-help-mismatches index 28003f18c9..c4a15fd0cb 100644 --- a/t/t0450/txt-help-mismatches +++ b/t/t0450/txt-help-mismatches @@ -45,7 +45,6 @@ rebase remote remote-ext remote-fd -repack reset restore rev-parse diff --git a/t/t1460-refs-migrate.sh b/t/t1460-refs-migrate.sh index ceb0c4977d..a6d9b35a46 100755 --- a/t/t1460-refs-migrate.sh +++ b/t/t1460-refs-migrate.sh @@ -244,6 +244,18 @@ do done done +test_expect_success 'multiple reftable blocks with multiple entries' ' + test_when_finished "rm -rf repo" && + git init --ref-format=files repo && + test_commit -C repo first && + printf "create refs/heads/ref-%d HEAD\n" $(test_seq 5000) >stdin && + git -C repo update-ref --stdin <stdin && + test_commit -C repo second && + printf "update refs/heads/ref-%d HEAD\n" $(test_seq 3000) >stdin && + git -C repo update-ref --stdin <stdin && + test_migration repo reftable +' + test_expect_success 'migrating from files format deletes backend files' ' test_when_finished "rm -rf repo" && git init --ref-format=files repo && diff --git a/t/t4100-apply-stat.sh b/t/t4100-apply-stat.sh index 146e73d8f5..a5664f3eb3 100755 --- a/t/t4100-apply-stat.sh +++ b/t/t4100-apply-stat.sh @@ -38,4 +38,17 @@ incomplete (1) incomplete (2) EOF +test_expect_success 'applying a hunk header which overflows fails' ' + cat >patch <<-\EOF && + diff -u a/file b/file + --- a/file + +++ b/file + @@ -98765432109876543210 +98765432109876543210 @@ + -a + +b + EOF + test_must_fail git apply patch 2>err && + echo "error: corrupt patch at line 4" >expect && + test_cmp expect err +' test_done diff --git a/t/t5300-pack-object.sh b/t/t5300-pack-object.sh index d1d6248558..5ac8d39094 100755 --- a/t/t5300-pack-object.sh +++ b/t/t5300-pack-object.sh @@ -689,4 +689,38 @@ do ' done +test_expect_success 'valid and invalid --name-hash-versions' ' + sane_unset GIT_TEST_NAME_HASH_VERSION && + + # Valid values are hard to verify other than "do not fail". + # Performance tests will be more valuable to validate these versions. + # Negative values are converted to version 1. + for value in -1 1 2 + do + git pack-objects base --all --name-hash-version=$value || return 1 + done && + + # Invalid values have clear post-conditions. + for value in 0 3 + do + test_must_fail git pack-objects base --all --name-hash-version=$value 2>err && + test_grep "invalid --name-hash-version option" err || return 1 + done +' + +# The following test is not necessarily a permanent choice, but since we do not +# have a "name hash version" bit in the .bitmap file format, we cannot write the +# hash values into the .bitmap file without risking breakage later. +# +# TODO: Make these compatible in the future and replace this test with the +# expected behavior when both are specified. +test_expect_success '--name-hash-version=2 and --write-bitmap-index are incompatible' ' + git pack-objects base --all --name-hash-version=2 --write-bitmap-index 2>err && + test_grep "currently, --write-bitmap-index requires --name-hash-version=1" err && + + # --stdout option silently removes --write-bitmap-index + git pack-objects --stdout --all --name-hash-version=2 --write-bitmap-index >out 2>err && + ! test_grep "currently, --write-bitmap-index requires --name-hash-version=1" err +' + test_done diff --git a/t/t5310-pack-bitmaps.sh b/t/t5310-pack-bitmaps.sh index eabfcd7ff6..621bbbdd26 100755 --- a/t/t5310-pack-bitmaps.sh +++ b/t/t5310-pack-bitmaps.sh @@ -26,6 +26,36 @@ has_any () { grep -Ff "$1" "$2" } +# Since name-hash values are stored in the .bitmap files, add a test +# that checks that the name-hash calculations are stable across versions. +# Not exhaustive, but these hashing algorithms would be hard to change +# without causing deviations here. +test_expect_success 'name-hash value stability' ' + cat >names <<-\EOF && + first + second + third + a/one-long-enough-for-collisions + b/two-long-enough-for-collisions + many/parts/to/this/path/enough/to/collide/in/v2 + enough/parts/to/this/path/enough/to/collide/in/v2 + EOF + + test-tool name-hash <names >out && + + cat >expect <<-\EOF && + 2582249472 1763573760 first + 2289942528 1188134912 second + 2300837888 1130758144 third + 2544516325 3963087891 a/one-long-enough-for-collisions + 2544516325 4013419539 b/two-long-enough-for-collisions + 1420111091 1709547268 many/parts/to/this/path/enough/to/collide/in/v2 + 1420111091 1709547268 enough/parts/to/this/path/enough/to/collide/in/v2 + EOF + + test_cmp expect out +' + test_bitmap_cases () { writeLookupTable=false for i in "$@" @@ -419,7 +449,10 @@ test_bitmap_cases () { cat >expect <<-\EOF && error: missing value for '\''pack.preferbitmaptips'\'' EOF - git repack -adb 2>actual && + + # Disable name hash version adjustment due to stderr comparison. + GIT_TEST_NAME_HASH_VERSION=1 \ + git repack -adb 2>actual && test_cmp expect actual ) ' diff --git a/t/t5323-pack-redundant.sh b/t/t5323-pack-redundant.sh index 8dbbcc5e51..688cd9706c 100755 --- a/t/t5323-pack-redundant.sh +++ b/t/t5323-pack-redundant.sh @@ -36,6 +36,12 @@ relationship between packs and objects is as follows: . ./test-lib.sh +if ! test_have_prereq WITHOUT_BREAKING_CHANGES +then + skip_all='skipping git-pack-redundant tests; built with breaking changes' + test_done +fi + main_repo=main.git shared_repo=shared.git diff --git a/t/t5333-pseudo-merge-bitmaps.sh b/t/t5333-pseudo-merge-bitmaps.sh index 1dd6284756..3905cb6e4f 100755 --- a/t/t5333-pseudo-merge-bitmaps.sh +++ b/t/t5333-pseudo-merge-bitmaps.sh @@ -208,7 +208,8 @@ test_expect_success 'bitmapPseudoMerge.stableThreshold creates stable groups' ' ' test_expect_success 'out of order thresholds are rejected' ' - test_must_fail git \ + # Disable the test var to remove a stderr message. + test_must_fail env GIT_TEST_NAME_HASH_VERSION=1 git \ -c bitmapPseudoMerge.test.pattern="refs/*" \ -c bitmapPseudoMerge.test.threshold=1.month.ago \ -c bitmapPseudoMerge.test.stableThreshold=1.week.ago \ diff --git a/t/t5401-update-hooks.sh b/t/t5401-update-hooks.sh index 723d1e17ec..17a46fd3ba 100755 --- a/t/t5401-update-hooks.sh +++ b/t/t5401-update-hooks.sh @@ -64,14 +64,14 @@ test_expect_success 'updated as expected' ' ' test_expect_success 'hooks ran' ' - test -f victim.git/pre-receive.args && - test -f victim.git/pre-receive.stdin && - test -f victim.git/update.args && - test -f victim.git/update.stdin && - test -f victim.git/post-receive.args && - test -f victim.git/post-receive.stdin && - test -f victim.git/post-update.args && - test -f victim.git/post-update.stdin + test_path_is_file victim.git/pre-receive.args && + test_path_is_file victim.git/pre-receive.stdin && + test_path_is_file victim.git/update.args && + test_path_is_file victim.git/update.stdin && + test_path_is_file victim.git/post-receive.args && + test_path_is_file victim.git/post-receive.stdin && + test_path_is_file victim.git/post-update.args && + test_path_is_file victim.git/post-update.stdin ' test_expect_success 'pre-receive hook input' ' diff --git a/t/t5505-remote.sh b/t/t5505-remote.sh index 519f7973e3..93a6662df7 100755 --- a/t/t5505-remote.sh +++ b/t/t5505-remote.sh @@ -1113,7 +1113,7 @@ Pull: refs/heads/main:refs/heads/origin Pull: refs/heads/next:refs/heads/origin2 EOF -test_expect_success 'migrate a remote from named file in $GIT_DIR/remotes' ' +test_expect_success WITHOUT_BREAKING_CHANGES 'migrate a remote from named file in $GIT_DIR/remotes' ' git clone one five && origin_url=$(pwd)/one && ( @@ -1139,7 +1139,7 @@ test_expect_success 'migrate a remote from named file in $GIT_DIR/remotes' ' ) ' -test_expect_success 'migrate a remote from named file in $GIT_DIR/branches' ' +test_expect_success WITHOUT_BREAKING_CHANGES 'migrate a remote from named file in $GIT_DIR/branches' ' git clone --template= one six && origin_url=$(pwd)/one && ( @@ -1155,7 +1155,7 @@ test_expect_success 'migrate a remote from named file in $GIT_DIR/branches' ' ) ' -test_expect_success 'migrate a remote from named file in $GIT_DIR/branches (2)' ' +test_expect_success WITHOUT_BREAKING_CHANGES 'migrate a remote from named file in $GIT_DIR/branches (2)' ' git clone --template= one seven && ( cd seven && diff --git a/t/t5510-fetch.sh b/t/t5510-fetch.sh index 2d9587059f..4680e0f644 100755 --- a/t/t5510-fetch.sh +++ b/t/t5510-fetch.sh @@ -34,14 +34,11 @@ test_expect_success "clone and setup child repos" ' git clone . three && ( cd three && - git config branch.main.remote two && - git config branch.main.merge refs/heads/one && - mkdir -p .git/remotes && - cat >.git/remotes/two <<-\EOF - URL: ../two/.git/ - Pull: refs/heads/main:refs/heads/two - Pull: refs/heads/one:refs/heads/one - EOF + git config set remote.two.url ../two/.git/ && + git config set remote.two.fetch refs/heads/main:refs/heads/two && + git config set --append remote.two.fetch refs/heads/one:refs/heads/one && + git config set branch.main.remote two && + git config set branch.main.merge refs/heads/one ) && git clone . bundle && git clone . seven @@ -1240,7 +1237,12 @@ test_expect_success 'all boundary commits are excluded' ' test_tick && git merge otherside && ad=$(git log --no-walk --format=%ad HEAD) && - git bundle create twoside-boundary.bdl main --since="$ad" && + + # If the a different name hash function is used here, then no delta + # pair is found and the bundle does not expand to three objects + # when fixing the thin object. + GIT_TEST_NAME_HASH_VERSION=1 \ + git bundle create twoside-boundary.bdl main --since="$ad" && test_bundle_object_count --thin twoside-boundary.bdl 3 ' diff --git a/t/t5515-fetch-merge-logic.sh b/t/t5515-fetch-merge-logic.sh index 320d26796d..4e6026c611 100755 --- a/t/t5515-fetch-merge-logic.sh +++ b/t/t5515-fetch-merge-logic.sh @@ -104,28 +104,31 @@ test_expect_success setup ' git config remote.config-glob.fetch refs/heads/*:refs/remotes/rem/* && remotes="$remotes config-glob" && - mkdir -p .git/remotes && - cat >.git/remotes/remote-explicit <<-\EOF && - URL: ../.git/ - Pull: refs/heads/main:remotes/rem/main - Pull: refs/heads/one:remotes/rem/one - Pull: two:remotes/rem/two - Pull: refs/heads/three:remotes/rem/three - EOF - remotes="$remotes remote-explicit" && - - cat >.git/remotes/remote-glob <<-\EOF && - URL: ../.git/ - Pull: refs/heads/*:refs/remotes/rem/* - EOF - remotes="$remotes remote-glob" && - - mkdir -p .git/branches && - echo "../.git" > .git/branches/branches-default && - remotes="$remotes branches-default" && - - echo "../.git#one" > .git/branches/branches-one && - remotes="$remotes branches-one" && + if test_have_prereq WITHOUT_BREAKING_CHANGES + then + mkdir -p .git/remotes && + cat >.git/remotes/remote-explicit <<-\EOF && + URL: ../.git/ + Pull: refs/heads/main:remotes/rem/main + Pull: refs/heads/one:remotes/rem/one + Pull: two:remotes/rem/two + Pull: refs/heads/three:remotes/rem/three + EOF + remotes="$remotes remote-explicit" && + + cat >.git/remotes/remote-glob <<-\EOF && + URL: ../.git/ + Pull: refs/heads/*:refs/remotes/rem/* + EOF + remotes="$remotes remote-glob" && + + mkdir -p .git/branches && + echo "../.git" > .git/branches/branches-default && + remotes="$remotes branches-default" && + + echo "../.git#one" > .git/branches/branches-one && + remotes="$remotes branches-one" + fi && for remote in $remotes ; do git config branch.br-$remote.remote $remote && diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh index 041d7d806f..85ed049627 100755 --- a/t/t5516-fetch-push.sh +++ b/t/t5516-fetch-push.sh @@ -975,7 +975,7 @@ test_expect_success 'allow push to HEAD of non-bare repository (config)' ' ! grep "warning: updating the current branch" stderr ' -test_expect_success 'fetch with branches' ' +test_expect_success WITHOUT_BREAKING_CHANGES 'fetch with branches' ' mk_empty testrepo && git branch second $the_first_commit && git checkout second && @@ -991,7 +991,7 @@ test_expect_success 'fetch with branches' ' git checkout main ' -test_expect_success 'fetch with branches containing #' ' +test_expect_success WITHOUT_BREAKING_CHANGES 'fetch with branches containing #' ' mk_empty testrepo && mkdir testrepo/.git/branches && echo "..#second" > testrepo/.git/branches/branch2 && @@ -1005,7 +1005,7 @@ test_expect_success 'fetch with branches containing #' ' git checkout main ' -test_expect_success 'push with branches' ' +test_expect_success WITHOUT_BREAKING_CHANGES 'push with branches' ' mk_empty testrepo && git checkout second && @@ -1022,7 +1022,7 @@ test_expect_success 'push with branches' ' ) ' -test_expect_success 'push with branches containing #' ' +test_expect_success WITHOUT_BREAKING_CHANGES 'push with branches containing #' ' mk_empty testrepo && test_when_finished "rm -rf .git/branches" && @@ -1211,18 +1211,16 @@ test_expect_success 'push --porcelain --dry-run rejected' ' ' test_expect_success 'push --prune' ' - mk_test testrepo heads/main heads/second heads/foo heads/bar && + mk_test testrepo heads/main heads/foo heads/bar && git push --prune testrepo : && check_push_result testrepo $the_commit heads/main && - check_push_result testrepo $the_first_commit heads/second && ! check_push_result testrepo $the_first_commit heads/foo heads/bar ' test_expect_success 'push --prune refspec' ' - mk_test testrepo tmp/main tmp/second tmp/foo tmp/bar && + mk_test testrepo tmp/main tmp/foo tmp/bar && git push --prune testrepo "refs/heads/*:refs/tmp/*" && check_push_result testrepo $the_commit tmp/main && - check_push_result testrepo $the_first_commit tmp/second && ! check_push_result testrepo $the_first_commit tmp/foo tmp/bar ' diff --git a/t/t5621-clone-revision.sh b/t/t5621-clone-revision.sh new file mode 100755 index 0000000000..db3b8cff55 --- /dev/null +++ b/t/t5621-clone-revision.sh @@ -0,0 +1,122 @@ +#!/bin/sh + +test_description='tests for git clone --revision' +GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main +export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME + +. ./test-lib.sh + +test_expect_success 'setup' ' + test_commit --no-tag "initial commit" README "Hello" && + test_commit --annotate "second commit" README "Hello world" v1.0 && + test_commit --no-tag "third commit" README "Hello world!" && + git switch -c feature v1.0 && + test_commit --no-tag "feature commit" README "Hello world!" && + git switch main +' + +test_expect_success 'clone with --revision being a branch' ' + test_when_finished "rm -rf dst" && + git clone --revision=refs/heads/feature . dst && + git rev-parse refs/heads/feature >expect && + git -C dst rev-parse HEAD >actual && + test_must_fail git -C dst symbolic-ref -q HEAD >/dev/null && + test_cmp expect actual && + git -C dst for-each-ref refs >expect && + test_must_be_empty expect && + test_must_fail git -C dst config remote.origin.fetch +' + +test_expect_success 'clone with --depth and --revision being a branch' ' + test_when_finished "rm -rf dst" && + git clone --no-local --depth=1 --revision=refs/heads/feature . dst && + git rev-parse refs/heads/feature >expect && + git -C dst rev-parse HEAD >actual && + test_must_fail git -C dst symbolic-ref -q HEAD >/dev/null && + test_cmp expect actual && + git -C dst for-each-ref refs >expect && + test_must_be_empty expect && + test_must_fail git -C dst config remote.origin.fetch && + git -C dst rev-list HEAD >actual && + test_line_count = 1 actual +' + +test_expect_success 'clone with --revision being a tag' ' + test_when_finished "rm -rf dst" && + git clone --revision=refs/tags/v1.0 . dst && + git rev-parse refs/tags/v1.0^{} >expect && + git -C dst rev-parse HEAD >actual && + test_must_fail git -C dst symbolic-ref -q HEAD >/dev/null && + test_cmp expect actual && + git -C dst for-each-ref refs >expect && + test_must_be_empty expect && + test_must_fail git -C dst config remote.origin.fetch +' + +test_expect_success 'clone with --revision being HEAD' ' + test_when_finished "rm -rf dst" && + git clone --revision=HEAD . dst && + git rev-parse HEAD >expect && + git -C dst rev-parse HEAD >actual && + test_must_fail git -C dst symbolic-ref -q HEAD >/dev/null && + test_cmp expect actual && + git -C dst for-each-ref refs >expect && + test_must_be_empty expect && + test_must_fail git -C dst config remote.origin.fetch +' + +test_expect_success 'clone with --revision being a raw commit hash' ' + test_when_finished "rm -rf dst" && + oid=$(git rev-parse refs/heads/feature) && + git clone --revision=$oid . dst && + echo $oid >expect && + git -C dst rev-parse HEAD >actual && + test_must_fail git -C dst symbolic-ref -q HEAD >/dev/null && + test_cmp expect actual && + git -C dst for-each-ref refs >expect && + test_must_be_empty expect && + test_must_fail git -C dst config remote.origin.fetch +' + +test_expect_success 'clone with --revision and --bare' ' + test_when_finished "rm -rf dst" && + git clone --revision=refs/heads/main --bare . dst && + oid=$(git rev-parse refs/heads/main) && + git -C dst cat-file -t $oid >actual && + echo "commit" >expect && + test_cmp expect actual && + git -C dst for-each-ref refs >expect && + test_must_be_empty expect && + test_must_fail git -C dst config remote.origin.fetch +' + +test_expect_success 'clone with --revision being a short raw commit hash' ' + test_when_finished "rm -rf dst" && + oid=$(git rev-parse --short refs/heads/feature) && + test_must_fail git clone --revision=$oid . dst 2>err && + test_grep "fatal: Remote revision $oid not found in upstream origin" err +' + +test_expect_success 'clone with --revision being a tree hash' ' + test_when_finished "rm -rf dst" && + oid=$(git rev-parse refs/heads/feature^{tree}) && + test_must_fail git clone --revision=$oid . dst 2>err && + test_grep "error: object $oid is a tree, not a commit" err +' + +test_expect_success 'clone with --revision being the parent of a ref fails' ' + test_when_finished "rm -rf dst" && + test_must_fail git clone --revision=refs/heads/main^ . dst +' + +test_expect_success 'clone with --revision and --branch fails' ' + test_when_finished "rm -rf dst" && + test_must_fail git clone --revision=refs/heads/main --branch=main . dst +' + +test_expect_success 'clone with --revision and --mirror fails' ' + test_when_finished "rm -rf dst" && + test_must_fail git clone --revision=refs/heads/main --mirror . dst +' + +test_done diff --git a/t/t6020-bundle-misc.sh b/t/t6020-bundle-misc.sh index 4ce62feaa2..b3807e8f35 100755 --- a/t/t6020-bundle-misc.sh +++ b/t/t6020-bundle-misc.sh @@ -246,7 +246,11 @@ test_expect_success 'create bundle with --since option' ' EOF test_cmp expect actual && - git bundle create since.bdl \ + # If a different name hash function is used, then one fewer + # delta base is found and this counts a different number + # of objects after performing --fix-thin. + GIT_TEST_NAME_HASH_VERSION=1 \ + git bundle create since.bdl \ --since "Thu Apr 7 15:27:00 2005 -0700" \ --all && diff --git a/t/t6423-merge-rename-directories.sh b/t/t6423-merge-rename-directories.sh index 88d1cf2cde..94080c65d1 100755 --- a/t/t6423-merge-rename-directories.sh +++ b/t/t6423-merge-rename-directories.sh @@ -5071,7 +5071,8 @@ test_expect_success '12i: Directory rename causes rename-to-self' ' test_path_is_file source/bar && test_path_is_file source/baz && - git ls-files | uniq >tracked && + git ls-files >actual && + uniq <actual >tracked && test_line_count = 3 tracked && git status --porcelain -uno >actual && @@ -5129,7 +5130,8 @@ test_expect_success '12j: Directory rename to root causes rename-to-self' ' test_path_is_file bar && test_path_is_file baz && - git ls-files | uniq >tracked && + git ls-files >actual && + uniq <actual >tracked && test_line_count = 3 tracked && git status --porcelain -uno >actual && @@ -5187,7 +5189,8 @@ test_expect_success '12k: Directory rename with sibling causes rename-to-self' ' test_path_is_file dirA/bar && test_path_is_file dirA/baz && - git ls-files | uniq >tracked && + git ls-files >actual && + uniq <actual >tracked && test_line_count = 3 tracked && git status --porcelain -uno >actual && diff --git a/t/t6500-gc.sh b/t/t6500-gc.sh index 5378455968..bef472cb8d 100755 --- a/t/t6500-gc.sh +++ b/t/t6500-gc.sh @@ -338,6 +338,39 @@ test_expect_success 'gc.maxCruftSize sets appropriate repack options' ' test_subcommand $cruft_max_size_opts --max-cruft-size=3145728 <trace2.txt ' +test_expect_success '--expire-to sets repack --expire-to' ' + rm -rf expired && + mkdir expired && + expire_to="$(pwd)/expired/pack" && + GIT_TRACE2_EVENT=$(pwd)/trace2.txt git -C cruft--max-size gc --cruft --expire-to="$expire_to" && + test_subcommand $cruft_max_size_opts --expire-to="$expire_to" <trace2.txt +' + +test_expect_success '--expire-to with --prune=now sets repack --expire-to' ' + rm -rf expired && + mkdir expired && + expire_to="$(pwd)/expired/pack" && + GIT_TRACE2_EVENT=$(pwd)/trace2.txt git -C cruft--max-size gc --cruft --prune=now --expire-to="$expire_to" && + test_subcommand git repack -d -l --cruft --cruft-expiration=now --expire-to="$expire_to" <trace2.txt +' + + +test_expect_success '--expire-to with --no-cruft sets repack -A' ' + rm -rf expired && + mkdir expired && + expire_to="$(pwd)/expired/pack" && + GIT_TRACE2_EVENT=$(pwd)/trace2.txt git -C cruft--max-size gc --no-cruft --expire-to="$expire_to" && + test_subcommand git repack -d -l -A --unpack-unreachable=2.weeks.ago <trace2.txt +' + +test_expect_success '--expire-to with --no-cruft sets repack -a' ' + rm -rf expired && + mkdir expired && + expire_to="$(pwd)/expired/pack" && + GIT_TRACE2_EVENT=$(pwd)/trace2.txt git -C cruft--max-size gc --no-cruft --prune=now --expire-to="$expire_to" && + test_subcommand git repack -d -l -a <trace2.txt +' + run_and_wait_for_gc () { # We read stdout from gc for the side effect of waiting until the # background gc process exits, closing its fd 9. Furthermore, the diff --git a/t/t7406-submodule-update.sh b/t/t7406-submodule-update.sh index 297c6c3b5c..c562bad042 100755 --- a/t/t7406-submodule-update.sh +++ b/t/t7406-submodule-update.sh @@ -1093,7 +1093,9 @@ test_expect_success 'submodule update --quiet passes quietness to fetch with a s ) && git clone super4 super5 && (cd super5 && - git submodule update --quiet --init --depth=1 submodule3 >out 2>err && + # This test var can mess with the stderr output checked in this test. + GIT_TEST_NAME_HASH_VERSION=1 \ + git submodule update --quiet --init --depth=1 submodule3 >out 2>err && test_must_be_empty out && test_must_be_empty err ) && diff --git a/t/t7422-submodule-output.sh b/t/t7422-submodule-output.sh index f21e920367..023a5cbdc4 100755 --- a/t/t7422-submodule-output.sh +++ b/t/t7422-submodule-output.sh @@ -167,10 +167,45 @@ do done test_expect_success !MINGW 'git submodule status --recursive propagates SIGPIPE' ' - { git submodule status --recursive 2>err; echo $?>status; } | - grep -q X/S && - test_must_be_empty err && - test_match_signal 13 "$(cat status)" + # The test setup is somewhat involved because triggering a SIGPIPE is + # racy with buffered pipes. To avoid the raciness we thus need to make + # sure that the subprocess in question fills the buffers completely, + # which requires a couple thousand submodules in total. + test_when_finished "rm -rf submodule repo" && + git init submodule && + ( + cd submodule && + test_commit initial && + + COMMIT=$(git rev-parse HEAD) && + for i in $(test_seq 2000) + do + printf "[submodule \"sm-$i\"]\npath = recursive-submodule-path-$i\n" "$i" || + return 1 + done >gitmodules && + BLOB=$(git hash-object -w --stdin <gitmodules) && + + printf "100644 blob $BLOB\t.gitmodules\n" >tree && + for i in $(test_seq 2000) + do + printf "160000 commit $COMMIT\trecursive-submodule-path-%d\n" "$i" || + return 1 + done >>tree && + TREE=$(git mktree <tree) && + + COMMIT=$(git commit-tree "$TREE") && + git reset --hard "$COMMIT" + ) && + + git init repo && + ( + cd repo && + GIT_ALLOW_PROTOCOL=file git submodule add "$(pwd)"/../submodule && + { git submodule status --recursive 2>err; echo $?>status; } | + grep -q recursive-submodule-path-1 && + test_must_be_empty err && + test_match_signal 13 "$(cat status)" + ) ' test_done diff --git a/t/t7700-repack.sh b/t/t7700-repack.sh index be1188e736..611755cc13 100755 --- a/t/t7700-repack.sh +++ b/t/t7700-repack.sh @@ -308,7 +308,10 @@ test_expect_success 'no bitmaps created if .keep files present' ' keep=${pack%.pack}.keep && test_when_finished "rm -f \"\$keep\"" && >"$keep" && - git -C bare.git repack -ad 2>stderr && + + # Disable --name-hash-version test due to stderr comparison. + GIT_TEST_NAME_HASH_VERSION=1 \ + git -C bare.git repack -ad 2>stderr && test_must_be_empty stderr && find bare.git/objects/pack/ -type f -name "*.bitmap" >actual && test_must_be_empty actual @@ -319,7 +322,10 @@ test_expect_success 'auto-bitmaps do not complain if unavailable' ' blob=$(test-tool genrandom big $((1024*1024)) | git -C bare.git hash-object -w --stdin) && git -C bare.git update-ref refs/tags/big $blob && - git -C bare.git repack -ad 2>stderr && + + # Disable --name-hash-version test due to stderr comparison. + GIT_TEST_NAME_HASH_VERSION=1 \ + git -C bare.git repack -ad 2>stderr && test_must_be_empty stderr && find bare.git/objects/pack -type f -name "*.bitmap" >actual && test_must_be_empty actual @@ -776,6 +782,12 @@ test_expect_success 'repack -ad cleans up old .tmp-* packs' ' test_must_be_empty tmpfiles ' +test_expect_success '--name-hash-version option passes through to pack-objects' ' + GIT_TRACE2_EVENT="$(pwd)/hash-trace.txt" \ + git repack -a --name-hash-version=2 && + test_subcommand_flex git pack-objects --name-hash-version=2 <hash-trace.txt +' + test_expect_success 'setup for update-server-info' ' git init update-server-info && test_commit -C update-server-info message diff --git a/t/t7701-repack-unpack-unreachable.sh b/t/t7701-repack-unpack-unreachable.sh index 5715f4d69a..5559d4ccb4 100755 --- a/t/t7701-repack-unpack-unreachable.sh +++ b/t/t7701-repack-unpack-unreachable.sh @@ -195,4 +195,20 @@ test_expect_success 'repack -k packs unreachable loose objects' ' git cat-file -p $sha1 ' +test_expect_success 'repack -k packs unreachable loose objects without existing packfiles' ' + test_when_finished "rm -rf repo" && + git init repo && + ( + cd repo && + + oid=$(echo would-be-deleted-loose | git hash-object -w --stdin) && + objpath=.git/objects/$(echo $sha1 | sed "s,..,&/,") && + test_path_is_file $objpath && + + git repack -ad --keep-unreachable && + test_path_is_missing $objpath && + git cat-file -p $oid + ) +' + test_done diff --git a/t/t9003-help-autocorrect.sh b/t/t9003-help-autocorrect.sh index 85a5074b5e..8da318d2b5 100755 --- a/t/t9003-help-autocorrect.sh +++ b/t/t9003-help-autocorrect.sh @@ -28,15 +28,18 @@ test_expect_success 'setup' ' test_cmp expect actual ' -test_expect_success 'autocorrect showing candidates' ' - git config help.autocorrect 0 && +for show in false no off 0 show +do + test_expect_success 'autocorrect showing candidates' ' + git config help.autocorrect $show && - test_must_fail git lfg 2>actual && - grep "^ lgf" actual && + test_must_fail git lfg 2>actual && + grep "^ lgf" actual && - test_must_fail git distimdist 2>actual && - grep "^ distimdistim" actual -' + test_must_fail git distimdist 2>actual && + grep "^ distimdistim" actual + ' +done for immediate in -1 immediate do diff --git a/t/test-lib-functions.sh b/t/test-lib-functions.sh index 14d511f509..b93736e0d5 100644 --- a/t/test-lib-functions.sh +++ b/t/test-lib-functions.sh @@ -1896,6 +1896,32 @@ test_subcommand () { fi } +# Check that the given subcommand was run with the given set of +# arguments in order (but with possible extra arguments). +# +# test_subcommand_flex [!] <command> <args>... < <trace> +# +# If the first parameter passed is !, this instead checks that +# the given command was not called. +# +test_subcommand_flex () { + local negate= + if test "$1" = "!" + then + negate=t + shift + fi + + local expr="$(printf '"%s".*' "$@")" + + if test -n "$negate" + then + ! grep "\[$expr\]" + else + grep "\[$expr\]" + fi +} + # Check that the given command was invoked as part of the # trace2-format trace on stdin. # diff --git a/t/test-lib.sh b/t/test-lib.sh index 9f27a49995..9001ed3a64 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -1862,6 +1862,10 @@ test_lazy_prereq CURL ' curl --version ' +test_lazy_prereq WITHOUT_BREAKING_CHANGES ' + test -z "$WITH_BREAKING_CHANGES" +' + # SHA1 is a test if the hash algorithm in use is SHA-1. This is both for tests # which will not work with other hash algorithms and tests that work but don't # test anything meaningful (e.g. special values which cause short collisions). diff --git a/t/unit-tests/t-example-decorate.c b/t/unit-tests/t-example-decorate.c deleted file mode 100644 index bfc776e223..0000000000 --- a/t/unit-tests/t-example-decorate.c +++ /dev/null @@ -1,74 +0,0 @@ -#define USE_THE_REPOSITORY_VARIABLE - -#include "test-lib.h" -#include "object.h" -#include "decorate.h" -#include "repository.h" - -struct test_vars { - struct object *one, *two, *three; - struct decoration n; - int decoration_a, decoration_b; -}; - -static void t_add(struct test_vars *vars) -{ - void *ret = add_decoration(&vars->n, vars->one, &vars->decoration_a); - - check(ret == NULL); - ret = add_decoration(&vars->n, vars->two, NULL); - check(ret == NULL); -} - -static void t_readd(struct test_vars *vars) -{ - void *ret = add_decoration(&vars->n, vars->one, NULL); - - check(ret == &vars->decoration_a); - ret = add_decoration(&vars->n, vars->two, &vars->decoration_b); - check(ret == NULL); -} - -static void t_lookup(struct test_vars *vars) -{ - void *ret = lookup_decoration(&vars->n, vars->one); - - check(ret == NULL); - ret = lookup_decoration(&vars->n, vars->two); - check(ret == &vars->decoration_b); - ret = lookup_decoration(&vars->n, vars->three); - check(ret == NULL); -} - -static void t_loop(struct test_vars *vars) -{ - int objects_noticed = 0; - - for (size_t i = 0; i < vars->n.size; i++) { - if (vars->n.entries[i].base) - objects_noticed++; - } - check_int(objects_noticed, ==, 2); -} - -int cmd_main(int argc UNUSED, const char **argv UNUSED) -{ - struct object_id one_oid = { { 1 } }, two_oid = { { 2 } }, three_oid = { { 3 } }; - struct test_vars vars = { 0 }; - - vars.one = lookup_unknown_object(the_repository, &one_oid); - vars.two = lookup_unknown_object(the_repository, &two_oid); - vars.three = lookup_unknown_object(the_repository, &three_oid); - - TEST(t_add(&vars), - "Add 2 objects, one with a non-NULL decoration and one with a NULL decoration."); - TEST(t_readd(&vars), - "When re-adding an already existing object, the old decoration is returned."); - TEST(t_lookup(&vars), - "Lookup returns the added declarations, or NULL if the object was never added."); - TEST(t_loop(&vars), "The user can also loop through all entries."); - - clear_decoration(&vars.n, NULL); - - return test_done(); -} diff --git a/t/unit-tests/t-strbuf.c b/t/unit-tests/t-strbuf.c deleted file mode 100644 index 3f4044d697..0000000000 --- a/t/unit-tests/t-strbuf.c +++ /dev/null @@ -1,122 +0,0 @@ -#include "test-lib.h" -#include "strbuf.h" - -/* wrapper that supplies tests with an empty, initialized strbuf */ -static void setup(void (*f)(struct strbuf*, const void*), - const void *data) -{ - struct strbuf buf = STRBUF_INIT; - - f(&buf, data); - strbuf_release(&buf); - check_uint(buf.len, ==, 0); - check_uint(buf.alloc, ==, 0); -} - -/* wrapper that supplies tests with a populated, initialized strbuf */ -static void setup_populated(void (*f)(struct strbuf*, const void*), - const char *init_str, const void *data) -{ - struct strbuf buf = STRBUF_INIT; - - strbuf_addstr(&buf, init_str); - check_uint(buf.len, ==, strlen(init_str)); - f(&buf, data); - strbuf_release(&buf); - check_uint(buf.len, ==, 0); - check_uint(buf.alloc, ==, 0); -} - -static int assert_sane_strbuf(struct strbuf *buf) -{ - /* Initialized strbufs should always have a non-NULL buffer */ - if (!check(!!buf->buf)) - return 0; - /* Buffers should always be NUL-terminated */ - if (!check_char(buf->buf[buf->len], ==, '\0')) - return 0; - /* - * Freshly-initialized strbufs may not have a dynamically allocated - * buffer - */ - if (buf->len == 0 && buf->alloc == 0) - return 1; - /* alloc must be at least one byte larger than len */ - return check_uint(buf->len, <, buf->alloc); -} - -static void t_static_init(void) -{ - struct strbuf buf = STRBUF_INIT; - - check_uint(buf.len, ==, 0); - check_uint(buf.alloc, ==, 0); - check_char(buf.buf[0], ==, '\0'); -} - -static void t_dynamic_init(void) -{ - struct strbuf buf; - - strbuf_init(&buf, 1024); - check(assert_sane_strbuf(&buf)); - check_uint(buf.len, ==, 0); - check_uint(buf.alloc, >=, 1024); - check_char(buf.buf[0], ==, '\0'); - strbuf_release(&buf); -} - -static void t_addch(struct strbuf *buf, const void *data) -{ - const char *p_ch = data; - const char ch = *p_ch; - size_t orig_alloc = buf->alloc; - size_t orig_len = buf->len; - - if (!check(assert_sane_strbuf(buf))) - return; - strbuf_addch(buf, ch); - if (!check(assert_sane_strbuf(buf))) - return; - if (!(check_uint(buf->len, ==, orig_len + 1) && - check_uint(buf->alloc, >=, orig_alloc))) - return; /* avoid de-referencing buf->buf */ - check_char(buf->buf[buf->len - 1], ==, ch); - check_char(buf->buf[buf->len], ==, '\0'); -} - -static void t_addstr(struct strbuf *buf, const void *data) -{ - const char *text = data; - size_t len = strlen(text); - size_t orig_alloc = buf->alloc; - size_t orig_len = buf->len; - - if (!check(assert_sane_strbuf(buf))) - return; - strbuf_addstr(buf, text); - if (!check(assert_sane_strbuf(buf))) - return; - if (!(check_uint(buf->len, ==, orig_len + len) && - check_uint(buf->alloc, >=, orig_alloc) && - check_uint(buf->alloc, >, orig_len + len) && - check_char(buf->buf[orig_len + len], ==, '\0'))) - return; - check_str(buf->buf + orig_len, text); -} - -int cmd_main(int argc UNUSED, const char **argv UNUSED) -{ - if (!TEST(t_static_init(), "static initialization works")) - test_skip_all("STRBUF_INIT is broken"); - TEST(t_dynamic_init(), "dynamic initialization works"); - TEST(setup(t_addch, "a"), "strbuf_addch adds char"); - TEST(setup(t_addch, ""), "strbuf_addch adds NUL char"); - TEST(setup_populated(t_addch, "initial value", "a"), - "strbuf_addch appends to initial value"); - TEST(setup(t_addstr, "hello there"), "strbuf_addstr adds string"); - TEST(setup_populated(t_addstr, "initial value", "hello there"), - "strbuf_addstr appends string to initial value"); - - return test_done(); -} diff --git a/t/unit-tests/t-strcmp-offset.c b/t/unit-tests/t-strcmp-offset.c deleted file mode 100644 index 6880f21161..0000000000 --- a/t/unit-tests/t-strcmp-offset.c +++ /dev/null @@ -1,35 +0,0 @@ -#include "test-lib.h" -#include "read-cache-ll.h" - -static void check_strcmp_offset(const char *string1, const char *string2, - int expect_result, uintmax_t expect_offset) -{ - size_t offset; - int result = strcmp_offset(string1, string2, &offset); - - /* - * Because different CRTs behave differently, only rely on signs of the - * result values. - */ - result = (result < 0 ? -1 : - result > 0 ? 1 : - 0); - - check_int(result, ==, expect_result); - check_uint((uintmax_t)offset, ==, expect_offset); -} - -#define TEST_STRCMP_OFFSET(string1, string2, expect_result, expect_offset) \ - TEST(check_strcmp_offset(string1, string2, expect_result, \ - expect_offset), \ - "strcmp_offset(%s, %s) works", #string1, #string2) - -int cmd_main(int argc UNUSED, const char **argv UNUSED) -{ - TEST_STRCMP_OFFSET("abc", "abc", 0, 3); - TEST_STRCMP_OFFSET("abc", "def", -1, 0); - TEST_STRCMP_OFFSET("abc", "abz", -1, 2); - TEST_STRCMP_OFFSET("abc", "abcdef", -1, 3); - - return test_done(); -} diff --git a/t/unit-tests/u-example-decorate.c b/t/unit-tests/u-example-decorate.c new file mode 100644 index 0000000000..9b1d1ce753 --- /dev/null +++ b/t/unit-tests/u-example-decorate.c @@ -0,0 +1,64 @@ +#define USE_THE_REPOSITORY_VARIABLE + +#include "unit-test.h" +#include "object.h" +#include "decorate.h" +#include "repository.h" + +struct test_vars { + struct object *one, *two, *three; + struct decoration n; + int decoration_a, decoration_b; +}; + +static struct test_vars vars; + +void test_example_decorate__initialize(void) +{ + struct object_id one_oid = { { 1 } }, two_oid = { { 2 } }, three_oid = { { 3 } }; + + vars.one = lookup_unknown_object(the_repository, &one_oid); + vars.two = lookup_unknown_object(the_repository, &two_oid); + vars.three = lookup_unknown_object(the_repository, &three_oid); +} + +void test_example_decorate__cleanup(void) +{ + clear_decoration(&vars.n, NULL); +} + +void test_example_decorate__add(void) +{ + cl_assert_equal_p(add_decoration(&vars.n, vars.one, &vars.decoration_a), NULL); + cl_assert_equal_p(add_decoration(&vars.n, vars.two, NULL), NULL); +} + +void test_example_decorate__readd(void) +{ + cl_assert_equal_p(add_decoration(&vars.n, vars.one, &vars.decoration_a), NULL); + cl_assert_equal_p(add_decoration(&vars.n, vars.two, NULL), NULL); + cl_assert_equal_p(add_decoration(&vars.n, vars.one, NULL), &vars.decoration_a); + cl_assert_equal_p(add_decoration(&vars.n, vars.two, &vars.decoration_b), NULL); +} + +void test_example_decorate__lookup(void) +{ + cl_assert_equal_p(add_decoration(&vars.n, vars.two, &vars.decoration_b), NULL); + cl_assert_equal_p(add_decoration(&vars.n, vars.one, NULL), NULL); + cl_assert_equal_p(lookup_decoration(&vars.n, vars.two), &vars.decoration_b); + cl_assert_equal_p(lookup_decoration(&vars.n, vars.one), NULL); +} + +void test_example_decorate__loop(void) +{ + int objects_noticed = 0; + + cl_assert_equal_p(add_decoration(&vars.n, vars.one, &vars.decoration_a), NULL); + cl_assert_equal_p(add_decoration(&vars.n, vars.two, &vars.decoration_b), NULL); + + for (size_t i = 0; i < vars.n.size; i++) + if (vars.n.entries[i].base) + objects_noticed++; + + cl_assert_equal_i(objects_noticed, 2); +} diff --git a/t/unit-tests/u-hash.c b/t/unit-tests/u-hash.c index a0320efe4b..bd4ac6a6e1 100644 --- a/t/unit-tests/u-hash.c +++ b/t/unit-tests/u-hash.c @@ -8,13 +8,13 @@ static void check_hash_data(const void *data, size_t data_length, cl_assert(data != NULL); for (size_t i = 1; i < ARRAY_SIZE(hash_algos); i++) { - git_hash_ctx ctx; + struct git_hash_ctx ctx; unsigned char hash[GIT_MAX_HEXSZ]; const struct git_hash_algo *algop = &hash_algos[i]; algop->init_fn(&ctx); - algop->update_fn(&ctx, data, data_length); - algop->final_fn(hash, &ctx); + git_hash_update(&ctx, data, data_length); + git_hash_final(hash, &ctx); cl_assert_equal_s(hash_to_hex_algop(hash,algop), expected_hashes[i - 1]); } diff --git a/t/unit-tests/t-hashmap.c b/t/unit-tests/u-hashmap.c index 83b79dff39..eb80aa1348 100644 --- a/t/unit-tests/t-hashmap.c +++ b/t/unit-tests/u-hashmap.c @@ -1,4 +1,4 @@ -#include "test-lib.h" +#include "unit-test.h" #include "hashmap.h" #include "strbuf.h" @@ -83,23 +83,23 @@ static void t_replace(struct hashmap *map, unsigned int ignore_case) struct test_entry *entry; entry = alloc_test_entry("key1", "value1", ignore_case); - check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL); + cl_assert_equal_p(hashmap_put_entry(map, entry, ent), NULL); entry = alloc_test_entry(ignore_case ? "Key1" : "key1", "value2", ignore_case); entry = hashmap_put_entry(map, entry, ent); - if (check(entry != NULL)) - check_str(get_value(entry), "value1"); + cl_assert(entry != NULL); + cl_assert_equal_s(get_value(entry), "value1"); free(entry); entry = alloc_test_entry("fooBarFrotz", "value3", ignore_case); - check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL); + cl_assert_equal_p(hashmap_put_entry(map, entry, ent), NULL); entry = alloc_test_entry(ignore_case ? "FOObarFrotz" : "fooBarFrotz", "value4", ignore_case); entry = hashmap_put_entry(map, entry, ent); - if (check(entry != NULL)) - check_str(get_value(entry), "value3"); + cl_assert(entry != NULL); + cl_assert_equal_s(get_value(entry), "value3"); free(entry); } @@ -122,20 +122,18 @@ static void t_get(struct hashmap *map, unsigned int ignore_case) for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) { entry = alloc_test_entry(key_val[i][0], key_val[i][1], ignore_case); - check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL); + cl_assert_equal_p(hashmap_put_entry(map, entry, ent), NULL); } for (size_t i = 0; i < ARRAY_SIZE(query); i++) { entry = get_test_entry(map, query[i][0], ignore_case); - if (check(entry != NULL)) - check_str(get_value(entry), query[i][1]); - else - test_msg("query key: %s", query[i][0]); + cl_assert(entry != NULL); + cl_assert_equal_s(get_value(entry), query[i][1]); } - check_pointer_eq(get_test_entry(map, "notInMap", ignore_case), NULL); - check_int(map->tablesize, ==, 64); - check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val)); + cl_assert_equal_p(get_test_entry(map, "notInMap", ignore_case), NULL); + cl_assert_equal_i(map->tablesize, 64); + cl_assert_equal_i(hashmap_get_size(map), ARRAY_SIZE(key_val)); } static void t_add(struct hashmap *map, unsigned int ignore_case) @@ -165,39 +163,19 @@ static void t_add(struct hashmap *map, unsigned int ignore_case) hashmap_for_each_entry_from(map, entry, ent) { - int ret; - if (!check_int((ret = key_val_contains( - key_val, seen, - ARRAY_SIZE(key_val), entry)), - ==, 0)) { - switch (ret) { - case 1: - test_msg("found entry was not given in the input\n" - " key: %s\n value: %s", - entry->key, get_value(entry)); - break; - case 2: - test_msg("duplicate entry detected\n" - " key: %s\n value: %s", - entry->key, get_value(entry)); - break; - } - } else { - count++; - } + int ret = key_val_contains(key_val, seen, + ARRAY_SIZE(key_val), entry); + cl_assert_equal_i(ret, 0); + count++; } - check_int(count, ==, 2); + cl_assert_equal_i(count, 2); } - for (size_t i = 0; i < ARRAY_SIZE(seen); i++) { - if (!check_int(seen[i], ==, 1)) - test_msg("following key-val pair was not iterated over:\n" - " key: %s\n value: %s", - key_val[i][0], key_val[i][1]); - } + for (size_t i = 0; i < ARRAY_SIZE(seen); i++) + cl_assert_equal_i(seen[i], 1); - check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val)); - check_pointer_eq(get_test_entry(map, "notInMap", ignore_case), NULL); + cl_assert_equal_i(hashmap_get_size(map), ARRAY_SIZE(key_val)); + cl_assert_equal_p(get_test_entry(map, "notInMap", ignore_case), NULL); } static void t_remove(struct hashmap *map, unsigned int ignore_case) @@ -211,24 +189,25 @@ static void t_remove(struct hashmap *map, unsigned int ignore_case) for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) { entry = alloc_test_entry(key_val[i][0], key_val[i][1], ignore_case); - check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL); + cl_assert_equal_p(hashmap_put_entry(map, entry, ent), NULL); } for (size_t i = 0; i < ARRAY_SIZE(remove); i++) { entry = alloc_test_entry(remove[i][0], "", ignore_case); removed = hashmap_remove_entry(map, entry, ent, remove[i][0]); - if (check(removed != NULL)) - check_str(get_value(removed), remove[i][1]); + cl_assert(removed != NULL); + cl_assert_equal_s(get_value(removed), remove[i][1]); free(entry); free(removed); } entry = alloc_test_entry("notInMap", "", ignore_case); - check_pointer_eq(hashmap_remove_entry(map, entry, ent, "notInMap"), NULL); + cl_assert_equal_p(hashmap_remove_entry(map, entry, ent, "notInMap"), NULL); free(entry); - check_int(map->tablesize, ==, 64); - check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val) - ARRAY_SIZE(remove)); + cl_assert_equal_i(map->tablesize, 64); + cl_assert_equal_i(hashmap_get_size(map), + ARRAY_SIZE(key_val) - ARRAY_SIZE(remove)); } static void t_iterate(struct hashmap *map, unsigned int ignore_case) @@ -242,38 +221,21 @@ static void t_iterate(struct hashmap *map, unsigned int ignore_case) for (size_t i = 0; i < ARRAY_SIZE(key_val); i++) { entry = alloc_test_entry(key_val[i][0], key_val[i][1], ignore_case); - check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL); + cl_assert_equal_p(hashmap_put_entry(map, entry, ent), NULL); } hashmap_for_each_entry(map, &iter, entry, ent /* member name */) { - int ret; - if (!check_int((ret = key_val_contains(key_val, seen, - ARRAY_SIZE(key_val), - entry)), ==, 0)) { - switch (ret) { - case 1: - test_msg("found entry was not given in the input\n" - " key: %s\n value: %s", - entry->key, get_value(entry)); - break; - case 2: - test_msg("duplicate entry detected\n" - " key: %s\n value: %s", - entry->key, get_value(entry)); - break; - } - } + int ret = key_val_contains(key_val, seen, + ARRAY_SIZE(key_val), + entry); + cl_assert(ret == 0); } - for (size_t i = 0; i < ARRAY_SIZE(seen); i++) { - if (!check_int(seen[i], ==, 1)) - test_msg("following key-val pair was not iterated over:\n" - " key: %s\n value: %s", - key_val[i][0], key_val[i][1]); - } + for (size_t i = 0; i < ARRAY_SIZE(seen); i++) + cl_assert_equal_i(seen[i], 1); - check_int(hashmap_get_size(map), ==, ARRAY_SIZE(key_val)); + cl_assert_equal_i(hashmap_get_size(map), ARRAY_SIZE(key_val)); } static void t_alloc(struct hashmap *map, unsigned int ignore_case) @@ -284,17 +246,17 @@ static void t_alloc(struct hashmap *map, unsigned int ignore_case) char *key = xstrfmt("key%d", i); char *value = xstrfmt("value%d", i); entry = alloc_test_entry(key, value, ignore_case); - check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL); + cl_assert_equal_p(hashmap_put_entry(map, entry, ent), NULL); free(key); free(value); } - check_int(map->tablesize, ==, 64); - check_int(hashmap_get_size(map), ==, 51); + cl_assert_equal_i(map->tablesize, 64); + cl_assert_equal_i(hashmap_get_size(map), 51); entry = alloc_test_entry("key52", "value52", ignore_case); - check_pointer_eq(hashmap_put_entry(map, entry, ent), NULL); - check_int(map->tablesize, ==, 256); - check_int(hashmap_get_size(map), ==, 52); + cl_assert_equal_p(hashmap_put_entry(map, entry, ent), NULL); + cl_assert_equal_i(map->tablesize, 256); + cl_assert_equal_i(hashmap_get_size(map), 52); for (int i = 1; i <= 12; i++) { char *key = xstrfmt("key%d", i); @@ -302,27 +264,27 @@ static void t_alloc(struct hashmap *map, unsigned int ignore_case) entry = alloc_test_entry(key, "", ignore_case); removed = hashmap_remove_entry(map, entry, ent, key); - if (check(removed != NULL)) - check_str(value, get_value(removed)); + cl_assert(removed != NULL); + cl_assert_equal_s(value, get_value(removed)); free(key); free(value); free(entry); free(removed); } - check_int(map->tablesize, ==, 256); - check_int(hashmap_get_size(map), ==, 40); + cl_assert_equal_i(map->tablesize, 256); + cl_assert_equal_i(hashmap_get_size(map), 40); entry = alloc_test_entry("key40", "", ignore_case); removed = hashmap_remove_entry(map, entry, ent, "key40"); - if (check(removed != NULL)) - check_str("value40", get_value(removed)); - check_int(map->tablesize, ==, 64); - check_int(hashmap_get_size(map), ==, 39); + cl_assert(removed != NULL); + cl_assert_equal_s("value40", get_value(removed)); + cl_assert_equal_i(map->tablesize, 64); + cl_assert_equal_i(hashmap_get_size(map), 39); free(entry); free(removed); } -static void t_intern(void) +void test_hashmap__intern(void) { const char *values[] = { "value1", "Value1", "value2", "value2" }; @@ -330,32 +292,68 @@ static void t_intern(void) const char *i1 = strintern(values[i]); const char *i2 = strintern(values[i]); - if (!check(!strcmp(i1, values[i]))) - test_msg("strintern(%s) returns %s\n", values[i], i1); - else if (!check(i1 != values[i])) - test_msg("strintern(%s) returns input pointer\n", - values[i]); - else if (!check_pointer_eq(i1, i2)) - test_msg("address('%s') != address('%s'), so strintern('%s') != strintern('%s')", - i1, i2, values[i], values[i]); - else - check_str(i1, values[i]); + cl_assert_equal_s(i1, values[i]); + cl_assert(i1 != values[i]); + cl_assert_equal_p(i1, i2); } } -int cmd_main(int argc UNUSED, const char **argv UNUSED) +void test_hashmap__replace_case_sensitive(void) +{ + setup(t_replace, 0); +} + +void test_hashmap__replace_case_insensitive(void) +{ + setup(t_replace, 1); +} + +void test_hashmap__get_case_sensitive(void) +{ + setup(t_get, 0); +} + +void test_hashmap__get_case_insensitive(void) +{ + setup(t_get, 1); +} + +void test_hashmap__add_case_sensitive(void) +{ + setup(t_add, 0); +} + +void test_hashmap__add_case_insensitive(void) +{ + setup(t_add, 1); +} + +void test_hashmap__remove_case_sensitive(void) +{ + setup(t_remove, 0); +} + +void test_hashmap__remove_case_insensitive(void) +{ + setup(t_remove, 1); +} + +void test_hashmap__iterate_case_sensitive(void) +{ + setup(t_iterate, 0); +} + +void test_hashmap__iterate_case_insensitive(void) +{ + setup(t_iterate, 1); +} + +void test_hashmap__alloc_case_sensitive(void) +{ + setup(t_alloc, 0); +} + +void test_hashmap__alloc_case_insensitive(void) { - TEST(setup(t_replace, 0), "replace works"); - TEST(setup(t_replace, 1), "replace (case insensitive) works"); - TEST(setup(t_get, 0), "get works"); - TEST(setup(t_get, 1), "get (case insensitive) works"); - TEST(setup(t_add, 0), "add works"); - TEST(setup(t_add, 1), "add (case insensitive) works"); - TEST(setup(t_remove, 0), "remove works"); - TEST(setup(t_remove, 1), "remove (case insensitive) works"); - TEST(setup(t_iterate, 0), "iterate works"); - TEST(setup(t_iterate, 1), "iterate (case insensitive) works"); - TEST(setup(t_alloc, 0), "grow / shrink works"); - TEST(t_intern(), "string interning works"); - return test_done(); + setup(t_alloc, 1); } diff --git a/t/unit-tests/u-strbuf.c b/t/unit-tests/u-strbuf.c new file mode 100644 index 0000000000..caa5d78aa3 --- /dev/null +++ b/t/unit-tests/u-strbuf.c @@ -0,0 +1,119 @@ +#include "unit-test.h" +#include "strbuf.h" + +/* wrapper that supplies tests with an empty, initialized strbuf */ +static void setup(void (*f)(struct strbuf*, const void*), + const void *data) +{ + struct strbuf buf = STRBUF_INIT; + + f(&buf, data); + strbuf_release(&buf); + cl_assert_equal_i(buf.len, 0); + cl_assert_equal_i(buf.alloc, 0); +} + +/* wrapper that supplies tests with a populated, initialized strbuf */ +static void setup_populated(void (*f)(struct strbuf*, const void*), + const char *init_str, const void *data) +{ + struct strbuf buf = STRBUF_INIT; + + strbuf_addstr(&buf, init_str); + cl_assert_equal_i(buf.len, strlen(init_str)); + f(&buf, data); + strbuf_release(&buf); + cl_assert_equal_i(buf.len, 0); + cl_assert_equal_i(buf.alloc, 0); +} + +static void assert_sane_strbuf(struct strbuf *buf) +{ + /* Initialized strbufs should always have a non-NULL buffer */ + cl_assert(buf->buf != NULL); + /* Buffers should always be NUL-terminated */ + cl_assert(buf->buf[buf->len] == '\0'); + /* + * In case the buffer contains anything, `alloc` must alloc must + * be at least one byte larger than `len`. + */ + if (buf->len) + cl_assert(buf->len < buf->alloc); +} + +void test_strbuf__static_init(void) +{ + struct strbuf buf = STRBUF_INIT; + + cl_assert_equal_i(buf.len, 0); + cl_assert_equal_i(buf.alloc, 0); + cl_assert(buf.buf[0] == '\0'); +} + +void test_strbuf__dynamic_init(void) +{ + struct strbuf buf; + + strbuf_init(&buf, 1024); + assert_sane_strbuf(&buf); + cl_assert_equal_i(buf.len, 0); + cl_assert(buf.alloc >= 1024); + cl_assert(buf.buf[0] == '\0'); + strbuf_release(&buf); +} + +static void t_addch(struct strbuf *buf, const void *data) +{ + const char *p_ch = data; + const char ch = *p_ch; + size_t orig_alloc = buf->alloc; + size_t orig_len = buf->len; + + assert_sane_strbuf(buf); + strbuf_addch(buf, ch); + assert_sane_strbuf(buf); + cl_assert_equal_i(buf->len, orig_len + 1); + cl_assert(buf->alloc >= orig_alloc); + cl_assert(buf->buf[buf->len] == '\0'); +} + +static void t_addstr(struct strbuf *buf, const void *data) +{ + const char *text = data; + size_t len = strlen(text); + size_t orig_alloc = buf->alloc; + size_t orig_len = buf->len; + + assert_sane_strbuf(buf); + strbuf_addstr(buf, text); + assert_sane_strbuf(buf); + cl_assert_equal_i(buf->len, orig_len + len); + cl_assert(buf->alloc >= orig_alloc); + cl_assert(buf->buf[buf->len] == '\0'); + cl_assert_equal_s(buf->buf + orig_len, text); +} + +void test_strbuf__add_single_char(void) +{ + setup(t_addch, "a"); +} + +void test_strbuf__add_empty_char(void) +{ + setup(t_addch, ""); +} + +void test_strbuf__add_append_char(void) +{ + setup_populated(t_addch, "initial value", "a"); +} + +void test_strbuf__add_single_str(void) +{ + setup(t_addstr, "hello there"); +} + +void test_strbuf__add_append_str(void) +{ + setup_populated(t_addstr, "initial value", "hello there"); +} diff --git a/t/unit-tests/u-strcmp-offset.c b/t/unit-tests/u-strcmp-offset.c new file mode 100644 index 0000000000..7e8e9acf3c --- /dev/null +++ b/t/unit-tests/u-strcmp-offset.c @@ -0,0 +1,45 @@ +#include "unit-test.h" +#include "read-cache-ll.h" + +static void check_strcmp_offset(const char *string1, const char *string2, + int expect_result, uintmax_t expect_offset) +{ + size_t offset; + int result = strcmp_offset(string1, string2, &offset); + + /* + * Because different CRTs behave differently, only rely on signs of the + * result values. + */ + result = (result < 0 ? -1 : + result > 0 ? 1 : + 0); + + cl_assert_equal_i(result, expect_result); + cl_assert_equal_i((uintmax_t)offset, expect_offset); +} + +void test_strcmp_offset__empty(void) +{ + check_strcmp_offset("", "", 0, 0); +} + +void test_strcmp_offset__equal(void) +{ + check_strcmp_offset("abc", "abc", 0, 3); +} + +void test_strcmp_offset__different(void) +{ + check_strcmp_offset("abc", "def", -1, 0); +} + +void test_strcmp_offset__mismatch(void) +{ + check_strcmp_offset("abc", "abz", -1, 2); +} + +void test_strcmp_offset__different_length(void) +{ + check_strcmp_offset("abc", "abcdef", -1, 3); +} |
