diff --git a/Makefile b/Makefile index 62188f5e8f..46468b02b8 100644 --- a/Makefile +++ b/Makefile @@ -1334,6 +1334,7 @@ THIRD_PARTY_SOURCES += sha1collisiondetection/% THIRD_PARTY_SOURCES += sha1dc/% UNIT_TEST_PROGRAMS += t-ctype +UNIT_TEST_PROGRAMS += t-hash UNIT_TEST_PROGRAMS += t-mem-pool UNIT_TEST_PROGRAMS += t-prio-queue UNIT_TEST_PROGRAMS += t-reftable-basics diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index 897f19868e..880ab4456e 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -256,11 +256,9 @@ static void module_list_active(struct module_list *list) static char *get_up_path(const char *path) { - int i; struct strbuf sb = STRBUF_INIT; - for (i = count_slashes(path); i; i--) - strbuf_addstr(&sb, "../"); + strbuf_addstrings(&sb, "../", count_slashes(path)); /* * Check if 'path' ends with slash or not diff --git a/json-writer.c b/json-writer.c index 005c820aa4..25b9201f9c 100644 --- a/json-writer.c +++ b/json-writer.c @@ -46,10 +46,7 @@ static void append_quoted_string(struct strbuf *out, const char *in) static void indent_pretty(struct json_writer *jw) { - int k; - - for (k = 0; k < jw->open_stack.len; k++) - strbuf_addstr(&jw->json, " "); + strbuf_addstrings(&jw->json, " ", jw->open_stack.len); } /* diff --git a/strbuf.c b/strbuf.c index e1076c9891..3d2189a7f6 100644 --- a/strbuf.c +++ b/strbuf.c @@ -313,6 +313,15 @@ void strbuf_add(struct strbuf *sb, const void *data, size_t len) strbuf_setlen(sb, sb->len + len); } +void strbuf_addstrings(struct strbuf *sb, const char *s, size_t n) +{ + size_t len = strlen(s); + + strbuf_grow(sb, st_mult(len, n)); + for (size_t i = 0; i < n; i++) + strbuf_add(sb, s, len); +} + void strbuf_addbuf(struct strbuf *sb, const struct strbuf *sb2) { strbuf_grow(sb, sb2->len); diff --git a/strbuf.h b/strbuf.h index 97fa4a3d01..003f880ff7 100644 --- a/strbuf.h +++ b/strbuf.h @@ -310,6 +310,11 @@ static inline void strbuf_addstr(struct strbuf *sb, const char *s) strbuf_add(sb, s, strlen(s)); } +/** + * Add a NUL-terminated string the specified number of times to the buffer. + */ +void strbuf_addstrings(struct strbuf *sb, const char *s, size_t n); + /** * Copy the contents of another buffer at the end of the current one. */ diff --git a/t/t0015-hash.sh b/t/t0015-hash.sh deleted file mode 100755 index 0a087a1983..0000000000 --- a/t/t0015-hash.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/sh - -test_description='test basic hash implementation' - -TEST_PASSES_SANITIZE_LEAK=true -. ./test-lib.sh - -test_expect_success 'test basic SHA-1 hash values' ' - test-tool sha1 actual && - grep da39a3ee5e6b4b0d3255bfef95601890afd80709 actual && - printf "a" | test-tool sha1 >actual && - grep 86f7e437faa5a7fce15d1ddcb9eaeaea377667b8 actual && - printf "abc" | test-tool sha1 >actual && - grep a9993e364706816aba3e25717850c26c9cd0d89d actual && - printf "message digest" | test-tool sha1 >actual && - grep c12252ceda8be8994d5fa0290a47231c1d16aae3 actual && - printf "abcdefghijklmnopqrstuvwxyz" | test-tool sha1 >actual && - grep 32d10c7b8cf96570ca04ce37f2a19d84240d3a89 actual && - perl -e "$| = 1; print q{aaaaaaaaaa} for 1..100000;" | - test-tool sha1 >actual && - grep 34aa973cd4c4daa4f61eeb2bdbad27316534016f actual && - printf "blob 0\0" | test-tool sha1 >actual && - grep e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 actual && - printf "blob 3\0abc" | test-tool sha1 >actual && - grep f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f actual && - printf "tree 0\0" | test-tool sha1 >actual && - grep 4b825dc642cb6eb9a060e54bf8d69288fbee4904 actual -' - -test_expect_success 'test basic SHA-256 hash values' ' - test-tool sha256 actual && - grep e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 actual && - printf "a" | test-tool sha256 >actual && - grep ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb actual && - printf "abc" | test-tool sha256 >actual && - grep ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad actual && - printf "message digest" | test-tool sha256 >actual && - grep f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650 actual && - printf "abcdefghijklmnopqrstuvwxyz" | test-tool sha256 >actual && - grep 71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73 actual && - # Try to exercise the chunking code by turning autoflush on. - perl -e "$| = 1; print q{aaaaaaaaaa} for 1..100000;" | - test-tool sha256 >actual && - grep cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0 actual && - perl -e "$| = 1; print q{abcdefghijklmnopqrstuvwxyz} for 1..100000;" | - test-tool sha256 >actual && - grep e406ba321ca712ad35a698bf0af8d61fc4dc40eca6bdcea4697962724ccbde35 actual && - printf "blob 0\0" | test-tool sha256 >actual && - grep 473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813 actual && - printf "blob 3\0abc" | test-tool sha256 >actual && - grep c1cf6e465077930e88dc5136641d402f72a229ddd996f627d60e9639eaba35a6 actual && - printf "tree 0\0" | test-tool sha256 >actual && - grep 6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321 actual -' - -test_done diff --git a/t/unit-tests/t-hash.c b/t/unit-tests/t-hash.c new file mode 100644 index 0000000000..e9a78bf2c0 --- /dev/null +++ b/t/unit-tests/t-hash.c @@ -0,0 +1,84 @@ +#include "test-lib.h" +#include "hex.h" +#include "strbuf.h" + +static void check_hash_data(const void *data, size_t data_length, + const char *expected_hashes[]) +{ + if (!check(data != NULL)) { + test_msg("BUG: NULL data pointer provided"); + return; + } + + for (size_t i = 1; i < ARRAY_SIZE(hash_algos); i++) { + 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); + + if (!check_str(hash_to_hex_algop(hash, algop), expected_hashes[i - 1])) + test_msg("result does not match with the expected for %s\n", hash_algos[i].name); + } +} + +/* Works with a NUL terminated string. Doesn't work if it should contain a NUL character. */ +#define TEST_HASH_STR(data, expected_sha1, expected_sha256) do { \ + const char *expected_hashes[] = { expected_sha1, expected_sha256 }; \ + TEST(check_hash_data(data, strlen(data), expected_hashes), \ + "SHA1 and SHA256 (%s) works", #data); \ + } while (0) + +/* Only works with a literal string, useful when it contains a NUL character. */ +#define TEST_HASH_LITERAL(literal, expected_sha1, expected_sha256) do { \ + const char *expected_hashes[] = { expected_sha1, expected_sha256 }; \ + TEST(check_hash_data(literal, (sizeof(literal) - 1), expected_hashes), \ + "SHA1 and SHA256 (%s) works", #literal); \ + } while (0) + +int cmd_main(int argc, const char **argv) +{ + struct strbuf aaaaaaaaaa_100000 = STRBUF_INIT; + struct strbuf alphabet_100000 = STRBUF_INIT; + + strbuf_addstrings(&aaaaaaaaaa_100000, "aaaaaaaaaa", 100000); + strbuf_addstrings(&alphabet_100000, "abcdefghijklmnopqrstuvwxyz", 100000); + + TEST_HASH_STR("", + "da39a3ee5e6b4b0d3255bfef95601890afd80709", + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + TEST_HASH_STR("a", + "86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", + "ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb"); + TEST_HASH_STR("abc", + "a9993e364706816aba3e25717850c26c9cd0d89d", + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); + TEST_HASH_STR("message digest", + "c12252ceda8be8994d5fa0290a47231c1d16aae3", + "f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650"); + TEST_HASH_STR("abcdefghijklmnopqrstuvwxyz", + "32d10c7b8cf96570ca04ce37f2a19d84240d3a89", + "71c480df93d6ae2f1efad1447c66c9525e316218cf51fc8d9ed832f2daf18b73"); + TEST_HASH_STR(aaaaaaaaaa_100000.buf, + "34aa973cd4c4daa4f61eeb2bdbad27316534016f", + "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0"); + TEST_HASH_STR(alphabet_100000.buf, + "e7da7c55b3484fdf52aebec9cbe7b85a98f02fd4", + "e406ba321ca712ad35a698bf0af8d61fc4dc40eca6bdcea4697962724ccbde35"); + TEST_HASH_LITERAL("blob 0\0", + "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391", + "473a0f4c3be8a93681a267e3b1e9a7dcda1185436fe141f7749120a303721813"); + TEST_HASH_LITERAL("blob 3\0abc", + "f2ba8f84ab5c1bce84a7b441cb1959cfc7093b7f", + "c1cf6e465077930e88dc5136641d402f72a229ddd996f627d60e9639eaba35a6"); + TEST_HASH_LITERAL("tree 0\0", + "4b825dc642cb6eb9a060e54bf8d69288fbee4904", + "6ef19b41225c5369f1c104d45d8d85efa9b057b53b14b4b9b939dd74decc5321"); + + strbuf_release(&aaaaaaaaaa_100000); + strbuf_release(&alphabet_100000); + + return test_done(); +}