From ee0a88dadb08320d88fab0e3ad2dd17ecfee8496 Mon Sep 17 00:00:00 2001 From: Seyi Kuforiji Date: Thu, 24 Jul 2025 15:28:34 +0100 Subject: t/unit-tests: convert reftable readwrite test to use clar Adapt reftable readwrite test file to use clar by using clar assertions where necessary. Signed-off-by: Seyi Kuforiji Signed-off-by: Junio C Hamano --- t/unit-tests/u-reftable-readwrite.c | 934 ++++++++++++++++++++++++++++++++++++ 1 file changed, 934 insertions(+) create mode 100644 t/unit-tests/u-reftable-readwrite.c (limited to 't/unit-tests/u-reftable-readwrite.c') diff --git a/t/unit-tests/u-reftable-readwrite.c b/t/unit-tests/u-reftable-readwrite.c new file mode 100644 index 0000000000..9aac74a011 --- /dev/null +++ b/t/unit-tests/u-reftable-readwrite.c @@ -0,0 +1,934 @@ +/* +Copyright 2020 Google LLC + +Use of this source code is governed by a BSD-style +license that can be found in the LICENSE file or at +https://developers.google.com/open-source/licenses/bsd +*/ + +#define DISABLE_SIGN_COMPARE_WARNINGS + +#include "unit-test.h" +#include "lib-reftable-clar.h" +#include "reftable/basics.h" +#include "reftable/blocksource.h" +#include "reftable/reftable-error.h" +#include "reftable/reftable-writer.h" +#include "reftable/table.h" +#include "strbuf.h" + +static const int update_index = 5; + +void test_reftable_readwrite__buffer(void) +{ + struct reftable_buf buf = REFTABLE_BUF_INIT; + struct reftable_block_source source = { 0 }; + struct reftable_block_data out = { 0 }; + int n; + uint8_t in[] = "hello"; + cl_assert_equal_i(reftable_buf_add(&buf, in, sizeof(in)), 0); + block_source_from_buf(&source, &buf); + cl_assert_equal_i(block_source_size(&source), 6); + n = block_source_read_data(&source, &out, 0, sizeof(in)); + cl_assert_equal_i(n, sizeof(in)); + cl_assert(!memcmp(in, out.data, n)); + block_source_release_data(&out); + + n = block_source_read_data(&source, &out, 1, 2); + cl_assert_equal_i(n, 2); + cl_assert(!memcmp(out.data, "el", 2)); + + block_source_release_data(&out); + block_source_close(&source); + reftable_buf_release(&buf); +} + +static void write_table(char ***names, struct reftable_buf *buf, int N, + int block_size, enum reftable_hash hash_id) +{ + struct reftable_write_options opts = { + .block_size = block_size, + .hash_id = hash_id, + }; + struct reftable_ref_record *refs; + struct reftable_log_record *logs; + int i; + + REFTABLE_CALLOC_ARRAY(*names, N + 1); + cl_assert(*names != NULL); + REFTABLE_CALLOC_ARRAY(refs, N); + cl_assert(refs != NULL); + REFTABLE_CALLOC_ARRAY(logs, N); + cl_assert(logs != NULL); + + for (i = 0; i < N; i++) { + refs[i].refname = (*names)[i] = xstrfmt("refs/heads/branch%02d", i); + refs[i].update_index = update_index; + refs[i].value_type = REFTABLE_REF_VAL1; + cl_reftable_set_hash(refs[i].value.val1, i, + REFTABLE_HASH_SHA1); + } + + for (i = 0; i < N; i++) { + logs[i].refname = (*names)[i]; + logs[i].update_index = update_index; + logs[i].value_type = REFTABLE_LOG_UPDATE; + cl_reftable_set_hash(logs[i].value.update.new_hash, i, + REFTABLE_HASH_SHA1); + logs[i].value.update.message = (char *) "message"; + } + + cl_reftable_write_to_buf(buf, refs, N, logs, N, &opts); + + reftable_free(refs); + reftable_free(logs); +} + +void test_reftable_readwrite__log_buffer_size(void) +{ + struct reftable_buf buf = REFTABLE_BUF_INIT; + struct reftable_write_options opts = { + .block_size = 4096, + }; + int i; + struct reftable_log_record + log = { .refname = (char *) "refs/heads/master", + .update_index = update_index, + .value_type = REFTABLE_LOG_UPDATE, + .value = { .update = { + .name = (char *) "Han-Wen Nienhuys", + .email = (char *) "hanwen@google.com", + .tz_offset = 100, + .time = 0x5e430672, + .message = (char *) "commit: 9\n", + } } }; + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, + &opts); + + /* This tests buffer extension for log compression. Must use a random + hash, to ensure that the compressed part is larger than the original. + */ + for (i = 0; i < REFTABLE_HASH_SIZE_SHA1; i++) { + log.value.update.old_hash[i] = (uint8_t)(git_rand(0) % 256); + log.value.update.new_hash[i] = (uint8_t)(git_rand(0) % 256); + } + reftable_writer_set_limits(w, update_index, update_index); + cl_assert_equal_i(reftable_writer_add_log(w, &log), 0); + cl_assert_equal_i(reftable_writer_close(w), 0); + reftable_writer_free(w); + reftable_buf_release(&buf); +} + +void test_reftable_readwrite__log_overflow(void) +{ + struct reftable_buf buf = REFTABLE_BUF_INIT; + char msg[256] = { 0 }; + struct reftable_write_options opts = { + .block_size = ARRAY_SIZE(msg), + }; + struct reftable_log_record log = { + .refname = (char *) "refs/heads/master", + .update_index = update_index, + .value_type = REFTABLE_LOG_UPDATE, + .value = { + .update = { + .old_hash = { 1 }, + .new_hash = { 2 }, + .name = (char *) "Han-Wen Nienhuys", + .email = (char *) "hanwen@google.com", + .tz_offset = 100, + .time = 0x5e430672, + .message = msg, + }, + }, + }; + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, + &opts); + + memset(msg, 'x', sizeof(msg) - 1); + reftable_writer_set_limits(w, update_index, update_index); + cl_assert_equal_i(reftable_writer_add_log(w, &log), REFTABLE_ENTRY_TOO_BIG_ERROR); + reftable_writer_free(w); + reftable_buf_release(&buf); +} + +void test_reftable_readwrite__log_write_limits(void) +{ + struct reftable_write_options opts = { 0 }; + struct reftable_buf buf = REFTABLE_BUF_INIT; + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, + &opts); + struct reftable_log_record log = { + .refname = (char *)"refs/head/master", + .update_index = 0, + .value_type = REFTABLE_LOG_UPDATE, + .value = { + .update = { + .old_hash = { 1 }, + .new_hash = { 2 }, + .name = (char *)"Han-Wen Nienhuys", + .email = (char *)"hanwen@google.com", + .tz_offset = 100, + .time = 0x5e430672, + }, + }, + }; + + reftable_writer_set_limits(w, 1, 1); + + /* write with update_index (0) below set limits (1, 1) */ + cl_assert_equal_i(reftable_writer_add_log(w, &log), 0); + + /* write with update_index (1) in the set limits (1, 1) */ + log.update_index = 1; + cl_assert_equal_i(reftable_writer_add_log(w, &log), 0); + + /* write with update_index (3) above set limits (1, 1) */ + log.update_index = 3; + cl_assert_equal_i(reftable_writer_add_log(w, &log), REFTABLE_API_ERROR); + + reftable_writer_free(w); + reftable_buf_release(&buf); +} + +void test_reftable_readwrite__log_write_read(void) +{ + struct reftable_write_options opts = { + .block_size = 256, + }; + struct reftable_ref_record ref = { 0 }; + struct reftable_log_record log = { 0 }; + struct reftable_iterator it = { 0 }; + struct reftable_table *table; + struct reftable_block_source source = { 0 }; + struct reftable_buf buf = REFTABLE_BUF_INIT; + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, &opts); + const struct reftable_stats *stats = NULL; + int N = 2, i; + char **names; + int err; + + names = reftable_calloc(N + 1, sizeof(*names)); + cl_assert(names != NULL); + + reftable_writer_set_limits(w, 0, N); + + for (i = 0; i < N; i++) { + char name[256]; + struct reftable_ref_record ref = { 0 }; + snprintf(name, sizeof(name), "b%02d%0*d", i, 130, 7); + names[i] = xstrdup(name); + ref.refname = name; + ref.update_index = i; + + cl_assert_equal_i(reftable_writer_add_ref(w, &ref), 0); + } + + for (i = 0; i < N; i++) { + struct reftable_log_record log = { 0 }; + + log.refname = names[i]; + log.update_index = i; + log.value_type = REFTABLE_LOG_UPDATE; + cl_reftable_set_hash(log.value.update.old_hash, i, + REFTABLE_HASH_SHA1); + cl_reftable_set_hash(log.value.update.new_hash, i + 1, + REFTABLE_HASH_SHA1); + + cl_assert_equal_i(reftable_writer_add_log(w, &log), 0); + } + + cl_assert_equal_i(reftable_writer_close(w), 0); + + stats = reftable_writer_stats(w); + cl_assert(stats->log_stats.blocks > 0); + reftable_writer_free(w); + w = NULL; + + block_source_from_buf(&source, &buf); + + err = reftable_table_new(&table, &source, "file.log"); + cl_assert(!err); + + err = reftable_table_init_ref_iterator(table, &it); + cl_assert(!err); + + err = reftable_iterator_seek_ref(&it, names[N - 1]); + cl_assert(!err); + + err = reftable_iterator_next_ref(&it, &ref); + cl_assert(!err); + + /* end of iteration. */ + cl_assert(reftable_iterator_next_ref(&it, &ref) > 0); + + reftable_iterator_destroy(&it); + reftable_ref_record_release(&ref); + + err = reftable_table_init_log_iterator(table, &it); + cl_assert(!err); + err = reftable_iterator_seek_log(&it, ""); + cl_assert(!err); + + for (i = 0; ; i++) { + int err = reftable_iterator_next_log(&it, &log); + if (err > 0) + break; + cl_assert(!err); + cl_assert_equal_s(names[i], log.refname); + cl_assert_equal_i(i, log.update_index); + reftable_log_record_release(&log); + } + + cl_assert_equal_i(i, N); + reftable_iterator_destroy(&it); + + /* cleanup. */ + reftable_buf_release(&buf); + free_names(names); + reftable_table_decref(table); +} + +void test_reftable_readwrite__log_zlib_corruption(void) +{ + struct reftable_write_options opts = { + .block_size = 256, + }; + struct reftable_iterator it = { 0 }; + struct reftable_table *table; + struct reftable_block_source source = { 0 }; + struct reftable_buf buf = REFTABLE_BUF_INIT; + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, + &opts); + const struct reftable_stats *stats = NULL; + char message[100] = { 0 }; + int i; + int err; + struct reftable_log_record log = { + .refname = (char *) "refname", + .value_type = REFTABLE_LOG_UPDATE, + .value = { + .update = { + .new_hash = { 1 }, + .old_hash = { 2 }, + .name = (char *) "My Name", + .email = (char *) "myname@invalid", + .message = message, + }, + }, + }; + + for (i = 0; i < sizeof(message) - 1; i++) + message[i] = (uint8_t)(git_rand(0) % 64 + ' '); + + reftable_writer_set_limits(w, 1, 1); + + cl_assert_equal_i(reftable_writer_add_log(w, &log), 0); + cl_assert_equal_i(reftable_writer_close(w), 0); + + stats = reftable_writer_stats(w); + cl_assert(stats->log_stats.blocks > 0); + reftable_writer_free(w); + w = NULL; + + /* corrupt the data. */ + buf.buf[50] ^= 0x99; + + block_source_from_buf(&source, &buf); + + err = reftable_table_new(&table, &source, "file.log"); + cl_assert(!err); + + err = reftable_table_init_log_iterator(table, &it); + cl_assert(!err); + err = reftable_iterator_seek_log(&it, "refname"); + cl_assert_equal_i(err, REFTABLE_ZLIB_ERROR); + + reftable_iterator_destroy(&it); + + /* cleanup. */ + reftable_table_decref(table); + reftable_buf_release(&buf); +} + +void test_reftable_readwrite__table_read_write_sequential(void) +{ + char **names; + struct reftable_buf buf = REFTABLE_BUF_INIT; + int N = 50; + struct reftable_iterator it = { 0 }; + struct reftable_block_source source = { 0 }; + struct reftable_table *table; + int err = 0; + int j = 0; + + write_table(&names, &buf, N, 256, REFTABLE_HASH_SHA1); + + block_source_from_buf(&source, &buf); + + err = reftable_table_new(&table, &source, "file.ref"); + cl_assert(!err); + + err = reftable_table_init_ref_iterator(table, &it); + cl_assert(!err); + err = reftable_iterator_seek_ref(&it, ""); + cl_assert(!err); + + for (j = 0; ; j++) { + struct reftable_ref_record ref = { 0 }; + int r = reftable_iterator_next_ref(&it, &ref); + cl_assert(r >= 0); + if (r > 0) + break; + cl_assert_equal_s(names[j], ref.refname); + cl_assert_equal_i(update_index, ref.update_index); + reftable_ref_record_release(&ref); + } + cl_assert_equal_i(j, N); + + reftable_iterator_destroy(&it); + reftable_table_decref(table); + reftable_buf_release(&buf); + free_names(names); +} + +void test_reftable_readwrite__table_write_small_table(void) +{ + char **names; + struct reftable_buf buf = REFTABLE_BUF_INIT; + int N = 1; + write_table(&names, &buf, N, 4096, REFTABLE_HASH_SHA1); + cl_assert(buf.len < 200); + reftable_buf_release(&buf); + free_names(names); +} + +void test_reftable_readwrite__table_read_api(void) +{ + char **names; + struct reftable_buf buf = REFTABLE_BUF_INIT; + int N = 50; + struct reftable_table *table; + struct reftable_block_source source = { 0 }; + struct reftable_log_record log = { 0 }; + struct reftable_iterator it = { 0 }; + int err; + + write_table(&names, &buf, N, 256, REFTABLE_HASH_SHA1); + + block_source_from_buf(&source, &buf); + + err = reftable_table_new(&table, &source, "file.ref"); + cl_assert(!err); + + err = reftable_table_init_ref_iterator(table, &it); + cl_assert(!err); + err = reftable_iterator_seek_ref(&it, names[0]); + cl_assert(!err); + + err = reftable_iterator_next_log(&it, &log); + cl_assert_equal_i(err, REFTABLE_API_ERROR); + + reftable_buf_release(&buf); + free_names(names); + reftable_iterator_destroy(&it); + reftable_table_decref(table); + reftable_buf_release(&buf); +} + +static void t_table_read_write_seek(int index, enum reftable_hash hash_id) +{ + char **names; + struct reftable_buf buf = REFTABLE_BUF_INIT; + int N = 50; + struct reftable_table *table; + struct reftable_block_source source = { 0 }; + int err; + int i = 0; + + struct reftable_iterator it = { 0 }; + struct reftable_buf pastLast = REFTABLE_BUF_INIT; + struct reftable_ref_record ref = { 0 }; + + write_table(&names, &buf, N, 256, hash_id); + + block_source_from_buf(&source, &buf); + + err = reftable_table_new(&table, &source, "file.ref"); + cl_assert(!err); + cl_assert_equal_i(hash_id, reftable_table_hash_id(table)); + + if (!index) { + table->ref_offsets.index_offset = 0; + } else { + cl_assert(table->ref_offsets.index_offset > 0); + } + + for (i = 1; i < N; i++) { + err = reftable_table_init_ref_iterator(table, &it); + cl_assert(!err); + err = reftable_iterator_seek_ref(&it, names[i]); + cl_assert(!err); + err = reftable_iterator_next_ref(&it, &ref); + cl_assert(!err); + cl_assert_equal_s(names[i], ref.refname); + cl_assert_equal_i(REFTABLE_REF_VAL1, ref.value_type); + cl_assert_equal_i(i, ref.value.val1[0]); + + reftable_ref_record_release(&ref); + reftable_iterator_destroy(&it); + } + + cl_assert_equal_i(reftable_buf_addstr(&pastLast, names[N - 1]), + 0); + cl_assert_equal_i(reftable_buf_addstr(&pastLast, "/"), 0); + + err = reftable_table_init_ref_iterator(table, &it); + cl_assert(!err); + err = reftable_iterator_seek_ref(&it, pastLast.buf); + if (err == 0) { + struct reftable_ref_record ref = { 0 }; + int err = reftable_iterator_next_ref(&it, &ref); + cl_assert(err > 0); + } else { + cl_assert(err > 0); + } + + reftable_buf_release(&pastLast); + reftable_iterator_destroy(&it); + + reftable_buf_release(&buf); + free_names(names); + reftable_table_decref(table); +} + +void test_reftable_readwrite__table_read_write_seek_linear(void) +{ + t_table_read_write_seek(0, REFTABLE_HASH_SHA1); +} + +void test_reftable_readwrite__table_read_write_seek_linear_sha256(void) +{ + t_table_read_write_seek(0, REFTABLE_HASH_SHA256); +} + +void test_reftable_readwrite__table_read_write_seek_index(void) +{ + t_table_read_write_seek(1, REFTABLE_HASH_SHA1); +} + +static void t_table_refs_for(int indexed) +{ + char **want_names; + int want_names_len = 0; + uint8_t want_hash[REFTABLE_HASH_SIZE_SHA1]; + + struct reftable_write_options opts = { + .block_size = 256, + }; + struct reftable_ref_record ref = { 0 }; + struct reftable_table *table; + struct reftable_block_source source = { 0 }; + struct reftable_buf buf = REFTABLE_BUF_INIT; + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, + &opts); + struct reftable_iterator it = { 0 }; + int N = 50, j, i; + int err; + + want_names = reftable_calloc(N + 1, sizeof(*want_names)); + cl_assert(want_names != NULL); + + cl_reftable_set_hash(want_hash, 4, REFTABLE_HASH_SHA1); + + for (i = 0; i < N; i++) { + uint8_t hash[REFTABLE_HASH_SIZE_SHA1]; + char fill[51] = { 0 }; + char name[100]; + struct reftable_ref_record ref = { 0 }; + + memset(hash, i, sizeof(hash)); + memset(fill, 'x', 50); + /* Put the variable part in the start */ + snprintf(name, sizeof(name), "br%02d%s", i, fill); + name[40] = 0; + ref.refname = name; + + ref.value_type = REFTABLE_REF_VAL2; + cl_reftable_set_hash(ref.value.val2.value, i / 4, + REFTABLE_HASH_SHA1); + cl_reftable_set_hash(ref.value.val2.target_value, + 3 + i / 4, REFTABLE_HASH_SHA1); + + /* 80 bytes / entry, so 3 entries per block. Yields 17 + */ + /* blocks. */ + cl_assert_equal_i(reftable_writer_add_ref(w, &ref), 0); + + if (!memcmp(ref.value.val2.value, want_hash, REFTABLE_HASH_SIZE_SHA1) || + !memcmp(ref.value.val2.target_value, want_hash, REFTABLE_HASH_SIZE_SHA1)) + want_names[want_names_len++] = xstrdup(name); + } + + cl_assert_equal_i(reftable_writer_close(w), 0); + + reftable_writer_free(w); + w = NULL; + + block_source_from_buf(&source, &buf); + + err = reftable_table_new(&table, &source, "file.ref"); + cl_assert(!err); + if (!indexed) + table->obj_offsets.is_present = 0; + + err = reftable_table_init_ref_iterator(table, &it); + cl_assert(!err); + err = reftable_iterator_seek_ref(&it, ""); + cl_assert(!err); + reftable_iterator_destroy(&it); + + err = reftable_table_refs_for(table, &it, want_hash); + cl_assert(!err); + + for (j = 0; ; j++) { + int err = reftable_iterator_next_ref(&it, &ref); + cl_assert(err >= 0); + if (err > 0) + break; + cl_assert(j < want_names_len); + cl_assert_equal_s(ref.refname, want_names[j]); + reftable_ref_record_release(&ref); + } + cl_assert_equal_i(j, want_names_len); + + reftable_buf_release(&buf); + free_names(want_names); + reftable_iterator_destroy(&it); + reftable_table_decref(table); +} + +void test_reftable_readwrite__table_refs_for_no_index(void) +{ + t_table_refs_for(0); +} + +void test_reftable_readwrite__table_refs_for_obj_index(void) +{ + t_table_refs_for(1); +} + +void test_reftable_readwrite__write_empty_table(void) +{ + struct reftable_write_options opts = { 0 }; + struct reftable_buf buf = REFTABLE_BUF_INIT; + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, &opts); + struct reftable_block_source source = { 0 }; + struct reftable_table *table = NULL; + struct reftable_ref_record rec = { 0 }; + struct reftable_iterator it = { 0 }; + int err; + + reftable_writer_set_limits(w, 1, 1); + + cl_assert_equal_i(reftable_writer_close(w), REFTABLE_EMPTY_TABLE_ERROR); + reftable_writer_free(w); + + cl_assert_equal_i(buf.len, header_size(1) + footer_size(1)); + + block_source_from_buf(&source, &buf); + + err = reftable_table_new(&table, &source, "filename"); + cl_assert(!err); + + err = reftable_table_init_ref_iterator(table, &it); + cl_assert(!err); + err = reftable_iterator_seek_ref(&it, ""); + cl_assert(!err); + + err = reftable_iterator_next_ref(&it, &rec); + cl_assert(err > 0); + + reftable_iterator_destroy(&it); + reftable_table_decref(table); + reftable_buf_release(&buf); +} + +void test_reftable_readwrite__write_object_id_min_length(void) +{ + struct reftable_write_options opts = { + .block_size = 75, + }; + struct reftable_buf buf = REFTABLE_BUF_INIT; + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, &opts); + struct reftable_ref_record ref = { + .update_index = 1, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = {42}, + }; + int i; + + reftable_writer_set_limits(w, 1, 1); + + /* Write the same hash in many refs. If there is only 1 hash, the + * disambiguating prefix is length 0 */ + for (i = 0; i < 256; i++) { + char name[256]; + snprintf(name, sizeof(name), "ref%05d", i); + ref.refname = name; + cl_assert_equal_i(reftable_writer_add_ref(w, &ref), 0); + } + + cl_assert_equal_i(reftable_writer_close(w), 0); + cl_assert_equal_i(reftable_writer_stats(w)->object_id_len, 2); + reftable_writer_free(w); + reftable_buf_release(&buf); +} + +void test_reftable_readwrite__write_object_id_length(void) +{ + struct reftable_write_options opts = { + .block_size = 75, + }; + struct reftable_buf buf = REFTABLE_BUF_INIT; + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, &opts); + struct reftable_ref_record ref = { + .update_index = 1, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = {42}, + }; + int i; + + reftable_writer_set_limits(w, 1, 1); + + /* Write the same hash in many refs. If there is only 1 hash, the + * disambiguating prefix is length 0 */ + for (i = 0; i < 256; i++) { + char name[256]; + snprintf(name, sizeof(name), "ref%05d", i); + ref.refname = name; + ref.value.val1[15] = i; + cl_assert(reftable_writer_add_ref(w, &ref) == 0); + } + + cl_assert_equal_i(reftable_writer_close(w), 0); + cl_assert_equal_i(reftable_writer_stats(w)->object_id_len, 16); + reftable_writer_free(w); + reftable_buf_release(&buf); +} + +void test_reftable_readwrite__write_empty_key(void) +{ + struct reftable_write_options opts = { 0 }; + struct reftable_buf buf = REFTABLE_BUF_INIT; + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, &opts); + struct reftable_ref_record ref = { + .refname = (char *) "", + .update_index = 1, + .value_type = REFTABLE_REF_DELETION, + }; + + reftable_writer_set_limits(w, 1, 1); + cl_assert_equal_i(reftable_writer_add_ref(w, &ref), REFTABLE_API_ERROR); + cl_assert_equal_i(reftable_writer_close(w), + REFTABLE_EMPTY_TABLE_ERROR); + reftable_writer_free(w); + reftable_buf_release(&buf); +} + +void test_reftable_readwrite__write_key_order(void) +{ + struct reftable_write_options opts = { 0 }; + struct reftable_buf buf = REFTABLE_BUF_INIT; + struct reftable_writer *w = cl_reftable_strbuf_writer(&buf, &opts); + struct reftable_ref_record refs[2] = { + { + .refname = (char *) "b", + .update_index = 1, + .value_type = REFTABLE_REF_SYMREF, + .value = { + .symref = (char *) "target", + }, + }, { + .refname = (char *) "a", + .update_index = 1, + .value_type = REFTABLE_REF_SYMREF, + .value = { + .symref = (char *) "target", + }, + } + }; + + reftable_writer_set_limits(w, 1, 1); + cl_assert_equal_i(reftable_writer_add_ref(w, &refs[0]), 0); + cl_assert_equal_i(reftable_writer_add_ref(w, &refs[1]), + REFTABLE_API_ERROR); + + refs[0].update_index = 2; + cl_assert_equal_i(reftable_writer_add_ref(w, &refs[0]), REFTABLE_API_ERROR); + + reftable_writer_close(w); + reftable_writer_free(w); + reftable_buf_release(&buf); +} + +void test_reftable_readwrite__write_multiple_indices(void) +{ + struct reftable_write_options opts = { + .block_size = 100, + }; + struct reftable_buf writer_buf = REFTABLE_BUF_INIT; + struct reftable_block_source source = { 0 }; + struct reftable_iterator it = { 0 }; + const struct reftable_stats *stats; + struct reftable_writer *writer; + struct reftable_table *table; + char buf[128]; + int i; + int err; + + writer = cl_reftable_strbuf_writer(&writer_buf, &opts); + reftable_writer_set_limits(writer, 1, 1); + for (i = 0; i < 100; i++) { + struct reftable_ref_record ref = { + .update_index = 1, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = {i}, + }; + + snprintf(buf, sizeof(buf), "refs/heads/%04d", i); + ref.refname = buf; + + cl_assert_equal_i(reftable_writer_add_ref(writer, &ref), 0); + } + + for (i = 0; i < 100; i++) { + struct reftable_log_record log = { + .update_index = 1, + .value_type = REFTABLE_LOG_UPDATE, + .value.update = { + .old_hash = { i }, + .new_hash = { i }, + }, + }; + + snprintf(buf, sizeof(buf), "refs/heads/%04d", i); + log.refname = buf; + + cl_assert_equal_i(reftable_writer_add_log(writer, &log), 0); + } + + reftable_writer_close(writer); + + /* + * The written data should be sufficiently large to result in indices + * for each of the block types. + */ + stats = reftable_writer_stats(writer); + cl_assert(stats->ref_stats.index_offset > 0); + cl_assert(stats->obj_stats.index_offset > 0); + cl_assert(stats->log_stats.index_offset > 0); + + block_source_from_buf(&source, &writer_buf); + err = reftable_table_new(&table, &source, "filename"); + cl_assert(!err); + + /* + * Seeking the log uses the log index now. In case there is any + * confusion regarding indices we would notice here. + */ + err = reftable_table_init_log_iterator(table, &it); + cl_assert(!err); + err = reftable_iterator_seek_log(&it, ""); + cl_assert(!err); + + reftable_iterator_destroy(&it); + reftable_writer_free(writer); + reftable_table_decref(table); + reftable_buf_release(&writer_buf); +} + +void test_reftable_readwrite__write_multi_level_index(void) +{ + struct reftable_write_options opts = { + .block_size = 100, + }; + struct reftable_buf writer_buf = REFTABLE_BUF_INIT, buf = REFTABLE_BUF_INIT; + struct reftable_block_source source = { 0 }; + struct reftable_iterator it = { 0 }; + const struct reftable_stats *stats; + struct reftable_writer *writer; + struct reftable_table *table; + int err; + + writer = cl_reftable_strbuf_writer(&writer_buf, &opts); + reftable_writer_set_limits(writer, 1, 1); + for (size_t i = 0; i < 200; i++) { + struct reftable_ref_record ref = { + .update_index = 1, + .value_type = REFTABLE_REF_VAL1, + .value.val1 = {i}, + }; + char buf[128]; + + snprintf(buf, sizeof(buf), "refs/heads/%03" PRIuMAX, (uintmax_t)i); + ref.refname = buf; + + cl_assert_equal_i(reftable_writer_add_ref(writer, &ref), 0); + } + reftable_writer_close(writer); + + /* + * The written refs should be sufficiently large to result in a + * multi-level index. + */ + stats = reftable_writer_stats(writer); + cl_assert_equal_i(stats->ref_stats.max_index_level, 2); + + block_source_from_buf(&source, &writer_buf); + err = reftable_table_new(&table, &source, "filename"); + cl_assert(!err); + + /* + * Seeking the last ref should work as expected. + */ + err = reftable_table_init_ref_iterator(table, &it); + cl_assert(!err); + err = reftable_iterator_seek_ref(&it, "refs/heads/199"); + cl_assert(!err); + + reftable_iterator_destroy(&it); + reftable_writer_free(writer); + reftable_table_decref(table); + reftable_buf_release(&writer_buf); + reftable_buf_release(&buf); +} + +void test_reftable_readwrite__corrupt_table_empty(void) +{ + struct reftable_buf buf = REFTABLE_BUF_INIT; + struct reftable_block_source source = { 0 }; + struct reftable_table *table; + int err; + + block_source_from_buf(&source, &buf); + err = reftable_table_new(&table, &source, "file.log"); + cl_assert_equal_i(err, REFTABLE_FORMAT_ERROR); +} + +void test_reftable_readwrite__corrupt_table(void) +{ + uint8_t zeros[1024] = { 0 }; + struct reftable_buf buf = REFTABLE_BUF_INIT; + struct reftable_block_source source = { 0 }; + struct reftable_table *table; + int err; + + cl_assert(!reftable_buf_add(&buf, zeros, sizeof(zeros))); + + block_source_from_buf(&source, &buf); + err = reftable_table_new(&table, &source, "file.log"); + cl_assert_equal_i(err, REFTABLE_FORMAT_ERROR); + + reftable_buf_release(&buf); +} -- cgit v1.2.3 From 9bbc981c6f27e00d050d4f70b0293f56e39b019a Mon Sep 17 00:00:00 2001 From: Seyi Kuforiji Date: Thu, 24 Jul 2025 15:28:37 +0100 Subject: t/unit-tests: finalize migration of reftable-related tests The old `lib-reftable.{c,h}` implemented helper functions for our homegrown unit-testing framework. As part of migrating reftable-related tests to the Clar framework, Clar-specific versions of these functions in `lib-reftable-clar.{c,h}` were introduced. Now that all test files using these helpers have been converted to Clar, we can safely remove the original `lib-reftable.{c,h}` and rename the Clar- specific versions back to `lib-reftable.{c,h}`. This restores a clean and consistent naming scheme for shared test utilities. Finally, update our build system to reflect the changes made and remove redundant code related to the reftable tests and our old homegrown unit-testing setup. `test-lib.{c,h}` remains unchanged in our build system as some files particularly `t/helper/test-example-tap.c` depends on it in order to run, and removing that would be beyond the scope of this patch. Signed-off-by: Seyi Kuforiji Signed-off-by: Junio C Hamano --- Makefile | 6 +-- t/Makefile | 1 - t/meson.build | 21 +------- t/unit-tests/lib-reftable-clar.c | 101 ------------------------------------ t/unit-tests/lib-reftable-clar.h | 20 ------- t/unit-tests/lib-reftable.c | 35 +++++++------ t/unit-tests/lib-reftable.h | 15 +++--- t/unit-tests/u-reftable-basics.c | 2 +- t/unit-tests/u-reftable-block.c | 2 +- t/unit-tests/u-reftable-merged.c | 2 +- t/unit-tests/u-reftable-pq.c | 2 +- t/unit-tests/u-reftable-readwrite.c | 2 +- t/unit-tests/u-reftable-record.c | 2 +- t/unit-tests/u-reftable-stack.c | 4 +- t/unit-tests/u-reftable-table.c | 2 +- 15 files changed, 38 insertions(+), 179 deletions(-) delete mode 100644 t/unit-tests/lib-reftable-clar.c delete mode 100644 t/unit-tests/lib-reftable-clar.h (limited to 't/unit-tests/u-reftable-readwrite.c') diff --git a/Makefile b/Makefile index cbbb2ec05a..25e6558b7b 100644 --- a/Makefile +++ b/Makefile @@ -1380,13 +1380,11 @@ CLAR_TEST_SUITES += u-urlmatch-normalization CLAR_TEST_PROG = $(UNIT_TEST_BIN)/unit-tests$(X) CLAR_TEST_OBJS = $(patsubst %,$(UNIT_TEST_DIR)/%.o,$(CLAR_TEST_SUITES)) CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/clar/clar.o -CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/unit-test.o CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/lib-oid.o -CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/lib-reftable-clar.o +CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/lib-reftable.o +CLAR_TEST_OBJS += $(UNIT_TEST_DIR)/unit-test.o -UNIT_TEST_PROGS = $(patsubst %,$(UNIT_TEST_BIN)/%$X,$(UNIT_TEST_PROGRAMS)) UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/test-lib.o -UNIT_TEST_OBJS += $(UNIT_TEST_DIR)/lib-reftable.o # xdiff and reftable libs may in turn depend on what is in libgit.a GITLIBS = common-main.o $(LIB_FILE) $(XDIFF_LIB) $(REFTABLE_LIB) $(LIB_FILE) diff --git a/t/Makefile b/t/Makefile index 791e0a0978..757674e727 100644 --- a/t/Makefile +++ b/t/Makefile @@ -125,7 +125,6 @@ check-meson: @mkdir -p mesontmp && \ printf "%s\n" \ "integration_tests t[0-9][0-9][0-9][0-9]-*.sh" \ - "unit_test_programs unit-tests/t-*.c" \ "clar_test_suites unit-tests/u-*.c" | \ while read -r variable pattern; do \ awk "/^$$variable = \[\$$/ {flag=1 ; next } /^]$$/ { flag=0 } flag { gsub(/^ \047/, \"\"); gsub(/\047,\$$/, \"\"); print }" meson.build >mesontmp/meson.txt && \ diff --git a/t/meson.build b/t/meson.build index fcbb659263..be96a9639f 100644 --- a/t/meson.build +++ b/t/meson.build @@ -28,7 +28,7 @@ clar_sources = [ 'unit-tests/clar/clar.c', 'unit-tests/unit-test.c', 'unit-tests/lib-oid.c', - 'unit-tests/lib-reftable-clar.c' + 'unit-tests/lib-reftable.c' ] clar_decls_h = custom_target( @@ -62,25 +62,6 @@ clar_unit_tests = executable('unit-tests', ) test('unit-tests', clar_unit_tests) -unit_test_programs = [ -] - -foreach unit_test_program : unit_test_programs - unit_test_name = fs.stem(unit_test_program) - unit_test = executable(unit_test_name, - sources: [ - 'unit-tests/test-lib.c', - 'unit-tests/lib-reftable.c', - unit_test_program, - ], - dependencies: [libgit_commonmain], - ) - test(unit_test_name, unit_test, - workdir: meson.current_source_dir(), - timeout: 0, - ) -endforeach - subdir('helper') integration_tests = [ diff --git a/t/unit-tests/lib-reftable-clar.c b/t/unit-tests/lib-reftable-clar.c deleted file mode 100644 index 64e40a106e..0000000000 --- a/t/unit-tests/lib-reftable-clar.c +++ /dev/null @@ -1,101 +0,0 @@ -#include "unit-test.h" -#include "lib-reftable-clar.h" -#include "hex.h" -#include "parse-options.h" -#include "reftable/constants.h" -#include "reftable/writer.h" -#include "strbuf.h" -#include "string-list.h" -#include "strvec.h" - -void cl_reftable_set_hash(uint8_t *p, int i, enum reftable_hash id) -{ - memset(p, (uint8_t)i, hash_size(id)); -} - -static ssize_t strbuf_writer_write(void *b, const void *data, size_t sz) -{ - strbuf_add(b, data, sz); - return sz; -} - -static int strbuf_writer_flush(void *arg UNUSED) -{ - return 0; -} - -struct reftable_writer *cl_reftable_strbuf_writer(struct reftable_buf *buf, - struct reftable_write_options *opts) -{ - struct reftable_writer *writer; - int ret = reftable_writer_new(&writer, &strbuf_writer_write, &strbuf_writer_flush, - buf, opts); - cl_assert(!ret); - return writer; -} - -void cl_reftable_write_to_buf(struct reftable_buf *buf, - struct reftable_ref_record *refs, - size_t nrefs, - struct reftable_log_record *logs, - size_t nlogs, - struct reftable_write_options *_opts) -{ - struct reftable_write_options opts = { 0 }; - const struct reftable_stats *stats; - struct reftable_writer *writer; - uint64_t min = 0xffffffff; - uint64_t max = 0; - int ret; - - if (_opts) - opts = *_opts; - - for (size_t i = 0; i < nrefs; i++) { - uint64_t ui = refs[i].update_index; - if (ui > max) - max = ui; - if (ui < min) - min = ui; - } - for (size_t i = 0; i < nlogs; i++) { - uint64_t ui = logs[i].update_index; - if (ui > max) - max = ui; - if (ui < min) - min = ui; - } - - writer = cl_reftable_strbuf_writer(buf, &opts); - ret = reftable_writer_set_limits(writer, min, max); - cl_assert_equal_i(ret, 0); - - if (nrefs) { - ret = reftable_writer_add_refs(writer, refs, nrefs); - cl_assert_equal_i(ret, 0); - } - - if (nlogs) { - ret = reftable_writer_add_logs(writer, logs, nlogs); - cl_assert_equal_i(ret, 0); - } - - ret = reftable_writer_close(writer); - cl_assert_equal_i(ret, 0); - - stats = reftable_writer_stats(writer); - for (size_t i = 0; i < (size_t)stats->ref_stats.blocks; i++) { - size_t off = i * (opts.block_size ? opts.block_size - : DEFAULT_BLOCK_SIZE); - if (!off) - off = header_size(opts.hash_id == REFTABLE_HASH_SHA256 ? 2 : 1); - cl_assert(buf->buf[off] == 'r'); - } - - if (nrefs) - cl_assert(stats->ref_stats.blocks > 0); - if (nlogs) - cl_assert(stats->log_stats.blocks > 0); - - reftable_writer_free(writer); -} diff --git a/t/unit-tests/lib-reftable-clar.h b/t/unit-tests/lib-reftable-clar.h deleted file mode 100644 index b562648973..0000000000 --- a/t/unit-tests/lib-reftable-clar.h +++ /dev/null @@ -1,20 +0,0 @@ -#include "git-compat-util.h" -#include "clar/clar.h" -#include "clar-decls.h" -#include "git-compat-util.h" -#include "reftable/reftable-writer.h" -#include "strbuf.h" - -struct reftable_buf; - -void cl_reftable_set_hash(uint8_t *p, int i, enum reftable_hash id); - -struct reftable_writer *cl_reftable_strbuf_writer(struct reftable_buf *buf, - struct reftable_write_options *opts); - -void cl_reftable_write_to_buf(struct reftable_buf *buf, - struct reftable_ref_record *refs, - size_t nrecords, - struct reftable_log_record *logs, - size_t nlogs, - struct reftable_write_options *opts); diff --git a/t/unit-tests/lib-reftable.c b/t/unit-tests/lib-reftable.c index 8a69612266..fdb5b11a20 100644 --- a/t/unit-tests/lib-reftable.c +++ b/t/unit-tests/lib-reftable.c @@ -1,12 +1,14 @@ -#define DISABLE_SIGN_COMPARE_WARNINGS - +#include "unit-test.h" #include "lib-reftable.h" -#include "test-lib.h" +#include "hex.h" +#include "parse-options.h" #include "reftable/constants.h" #include "reftable/writer.h" #include "strbuf.h" +#include "string-list.h" +#include "strvec.h" -void t_reftable_set_hash(uint8_t *p, int i, enum reftable_hash id) +void cl_reftable_set_hash(uint8_t *p, int i, enum reftable_hash id) { memset(p, (uint8_t)i, hash_size(id)); } @@ -22,17 +24,17 @@ static int strbuf_writer_flush(void *arg UNUSED) return 0; } -struct reftable_writer *t_reftable_strbuf_writer(struct reftable_buf *buf, +struct reftable_writer *cl_reftable_strbuf_writer(struct reftable_buf *buf, struct reftable_write_options *opts) { struct reftable_writer *writer; int ret = reftable_writer_new(&writer, &strbuf_writer_write, &strbuf_writer_flush, buf, opts); - check(!ret); + cl_assert(!ret); return writer; } -void t_reftable_write_to_buf(struct reftable_buf *buf, +void cl_reftable_write_to_buf(struct reftable_buf *buf, struct reftable_ref_record *refs, size_t nrefs, struct reftable_log_record *logs, @@ -64,35 +66,36 @@ void t_reftable_write_to_buf(struct reftable_buf *buf, min = ui; } - writer = t_reftable_strbuf_writer(buf, &opts); - reftable_writer_set_limits(writer, min, max); + writer = cl_reftable_strbuf_writer(buf, &opts); + ret = reftable_writer_set_limits(writer, min, max); + cl_assert(!ret); if (nrefs) { ret = reftable_writer_add_refs(writer, refs, nrefs); - check_int(ret, ==, 0); + cl_assert_equal_i(ret, 0); } if (nlogs) { ret = reftable_writer_add_logs(writer, logs, nlogs); - check_int(ret, ==, 0); + cl_assert_equal_i(ret, 0); } ret = reftable_writer_close(writer); - check_int(ret, ==, 0); + cl_assert_equal_i(ret, 0); stats = reftable_writer_stats(writer); - for (size_t i = 0; i < stats->ref_stats.blocks; i++) { + for (size_t i = 0; i < (size_t)stats->ref_stats.blocks; i++) { size_t off = i * (opts.block_size ? opts.block_size : DEFAULT_BLOCK_SIZE); if (!off) off = header_size(opts.hash_id == REFTABLE_HASH_SHA256 ? 2 : 1); - check_char(buf->buf[off], ==, 'r'); + cl_assert(buf->buf[off] == 'r'); } if (nrefs) - check_int(stats->ref_stats.blocks, >, 0); + cl_assert(stats->ref_stats.blocks > 0); if (nlogs) - check_int(stats->log_stats.blocks, >, 0); + cl_assert(stats->log_stats.blocks > 0); reftable_writer_free(writer); } diff --git a/t/unit-tests/lib-reftable.h b/t/unit-tests/lib-reftable.h index e4c360fa7e..d7e6d3136f 100644 --- a/t/unit-tests/lib-reftable.h +++ b/t/unit-tests/lib-reftable.h @@ -1,21 +1,20 @@ -#ifndef LIB_REFTABLE_H -#define LIB_REFTABLE_H - +#include "git-compat-util.h" +#include "clar/clar.h" +#include "clar-decls.h" #include "git-compat-util.h" #include "reftable/reftable-writer.h" +#include "strbuf.h" struct reftable_buf; -void t_reftable_set_hash(uint8_t *p, int i, enum reftable_hash id); +void cl_reftable_set_hash(uint8_t *p, int i, enum reftable_hash id); -struct reftable_writer *t_reftable_strbuf_writer(struct reftable_buf *buf, +struct reftable_writer *cl_reftable_strbuf_writer(struct reftable_buf *buf, struct reftable_write_options *opts); -void t_reftable_write_to_buf(struct reftable_buf *buf, +void cl_reftable_write_to_buf(struct reftable_buf *buf, struct reftable_ref_record *refs, size_t nrecords, struct reftable_log_record *logs, size_t nlogs, struct reftable_write_options *opts); - -#endif diff --git a/t/unit-tests/u-reftable-basics.c b/t/unit-tests/u-reftable-basics.c index f105c22d15..a0471083e7 100644 --- a/t/unit-tests/u-reftable-basics.c +++ b/t/unit-tests/u-reftable-basics.c @@ -7,7 +7,7 @@ https://developers.google.com/open-source/licenses/bsd */ #include "unit-test.h" -#include "lib-reftable-clar.h" +#include "lib-reftable.h" #include "reftable/basics.h" struct integer_needle_lesseq_args { diff --git a/t/unit-tests/u-reftable-block.c b/t/unit-tests/u-reftable-block.c index 97a1348563..f4bded7d26 100644 --- a/t/unit-tests/u-reftable-block.c +++ b/t/unit-tests/u-reftable-block.c @@ -7,7 +7,7 @@ https://developers.google.com/open-source/licenses/bsd */ #include "unit-test.h" -#include "lib-reftable-clar.h" +#include "lib-reftable.h" #include "reftable/block.h" #include "reftable/blocksource.h" #include "reftable/constants.h" diff --git a/t/unit-tests/u-reftable-merged.c b/t/unit-tests/u-reftable-merged.c index 62b02baa14..54cb7fc2a7 100644 --- a/t/unit-tests/u-reftable-merged.c +++ b/t/unit-tests/u-reftable-merged.c @@ -7,7 +7,7 @@ https://developers.google.com/open-source/licenses/bsd */ #include "unit-test.h" -#include "lib-reftable-clar.h" +#include "lib-reftable.h" #include "reftable/blocksource.h" #include "reftable/constants.h" #include "reftable/merged.h" diff --git a/t/unit-tests/u-reftable-pq.c b/t/unit-tests/u-reftable-pq.c index d55792ca6f..f8a28f6e07 100644 --- a/t/unit-tests/u-reftable-pq.c +++ b/t/unit-tests/u-reftable-pq.c @@ -7,7 +7,7 @@ https://developers.google.com/open-source/licenses/bsd */ #include "unit-test.h" -#include "lib-reftable-clar.h" +#include "lib-reftable.h" #include "reftable/constants.h" #include "reftable/pq.h" #include "strbuf.h" diff --git a/t/unit-tests/u-reftable-readwrite.c b/t/unit-tests/u-reftable-readwrite.c index 9aac74a011..4d8c4be5f1 100644 --- a/t/unit-tests/u-reftable-readwrite.c +++ b/t/unit-tests/u-reftable-readwrite.c @@ -9,7 +9,7 @@ https://developers.google.com/open-source/licenses/bsd #define DISABLE_SIGN_COMPARE_WARNINGS #include "unit-test.h" -#include "lib-reftable-clar.h" +#include "lib-reftable.h" #include "reftable/basics.h" #include "reftable/blocksource.h" #include "reftable/reftable-error.h" diff --git a/t/unit-tests/u-reftable-record.c b/t/unit-tests/u-reftable-record.c index 650b0aa0d3..6c8c0d5374 100644 --- a/t/unit-tests/u-reftable-record.c +++ b/t/unit-tests/u-reftable-record.c @@ -7,7 +7,7 @@ */ #include "unit-test.h" -#include "lib-reftable-clar.h" +#include "lib-reftable.h" #include "reftable/basics.h" #include "reftable/constants.h" #include "reftable/record.h" diff --git a/t/unit-tests/u-reftable-stack.c b/t/unit-tests/u-reftable-stack.c index 0e3e3f4f4a..e4ea57138e 100644 --- a/t/unit-tests/u-reftable-stack.c +++ b/t/unit-tests/u-reftable-stack.c @@ -10,7 +10,7 @@ https://developers.google.com/open-source/licenses/bsd #include "unit-test.h" #include "dir.h" -#include "lib-reftable-clar.h" +#include "lib-reftable.h" #include "reftable/merged.h" #include "reftable/reftable-error.h" #include "reftable/stack.h" @@ -497,7 +497,7 @@ void test_reftable_stack__add(void) struct reftable_buf path = REFTABLE_BUF_INIT; struct stat stat_result; size_t i, N = ARRAY_SIZE(refs); - int err; + int err = 0; err = reftable_new_stack(&st, dir, &opts); cl_assert(!err); diff --git a/t/unit-tests/u-reftable-table.c b/t/unit-tests/u-reftable-table.c index 839107d8a4..14fae8b199 100644 --- a/t/unit-tests/u-reftable-table.c +++ b/t/unit-tests/u-reftable-table.c @@ -1,5 +1,5 @@ #include "unit-test.h" -#include "lib-reftable-clar.h" +#include "lib-reftable.h" #include "reftable/blocksource.h" #include "reftable/constants.h" #include "reftable/iter.h" -- cgit v1.2.3