kit

kit
git clone https://git.ryansepassi.com/git/kit.git
Log | Files | Refs | README

commit 4c700b68454e1122cf38722505389124ca167189
parent ed311622bb71bccb5e5e98fe9c6dfff8f058c999
Author: Ryan Sepassi <rsepassi@gmail.com>
Date:   Tue,  2 Jun 2026 11:17:53 -0700

test: cover the new byte-utility tools + hash API

- test/api/hash_test.c (test-hash): cfree_hash against known vectors
  (SHA-256 empty/abc, CRC-32 0xcbf43926, BLAKE2b-256 abc) plus streaming/
  one-shot equivalence for all three algos. 24 checks.
- test/tools/run.sh (test-driver-tools): self-checking CLI harness for
  xxd (round-trips + -p/-i), cmp (identical/differ/-s + message), hash,
  disas (aa64/x64 + bad-hex), and mc (encoding + mc -p|disas round-trip +
  reloc). 16 checks.
Both added to the default gate and the test-driver aggregate.

Diffstat:
Atest/api/hash_test.c | 87+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mtest/lib/unit.mk | 3++-
Mtest/test.mk | 11++++++++++-
Atest/tools/run.sh | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 181 insertions(+), 2 deletions(-)

diff --git a/test/api/hash_test.c b/test/api/hash_test.c @@ -0,0 +1,87 @@ +/* hash_test — public <cfree/hash.h> surface: one-shot cfree_hash against known + * vectors (SHA-256 empty/"abc", CRC-32 of "123456789", BLAKE2b-256 "abc") and + * streaming/one-shot equivalence (two cfree_hasher_update chunks == one shot) + * for all three algorithms. + * + * Run by: make test-hash + */ + +#include <cfree/core.h> +#include <cfree/hash.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#include "lib/cfree_unit.h" + +static CfreeUnit g_u; +#define EXPECT(c, ...) CU_EXPECT(&g_u, c, __VA_ARGS__) + +static int hexval(char c) { + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return c - 'a' + 10; + if (c >= 'A' && c <= 'F') return c - 'A' + 10; + return -1; +} + +static void parse_hex(const char* hex, uint8_t* out, size_t n) { + size_t i; + for (i = 0; i < n; ++i) + out[i] = (uint8_t)((hexval(hex[2 * i]) << 4) | hexval(hex[2 * i + 1])); +} + +static void check_oneshot(CfreeHashAlgo algo, const char* name, const char* msg, + size_t len, const char* exphex) { + uint8_t digest[CFREE_HASH_MAX_LEN]; + uint8_t want[CFREE_HASH_MAX_LEN]; + size_t dlen = 0; + size_t wn = strlen(exphex) / 2; + EXPECT(cfree_hash(algo, (const uint8_t*)msg, len, digest, &dlen) == CFREE_OK, + "%s: cfree_hash returned OK", name); + EXPECT(dlen == cfree_hash_len(algo) && dlen == wn, + "%s: digest length %zu == %zu", name, dlen, wn); + parse_hex(exphex, want, wn); + EXPECT(memcmp(digest, want, wn) == 0, "%s: digest matches %s", name, exphex); +} + +/* Hashing "abc"+"def" in two streamed chunks must equal a one-shot of + * "abcdef". */ +static void check_stream_equiv(CfreeHashAlgo algo, const char* name) { + uint8_t one[CFREE_HASH_MAX_LEN]; + uint8_t two[CFREE_HASH_MAX_LEN]; + size_t l1 = 0, l2 = 0; + CfreeHasher* h = NULL; + EXPECT(cfree_hash(algo, (const uint8_t*)"abcdef", 6, one, &l1) == CFREE_OK, + "%s: one-shot OK", name); + EXPECT(cfree_hasher_new(&g_u.ctx, algo, &h) == CFREE_OK, "%s: hasher_new", + name); + cfree_hasher_update(h, (const uint8_t*)"abc", 3); + cfree_hasher_update(h, (const uint8_t*)"def", 3); + EXPECT(cfree_hasher_final(h, two, &l2) == CFREE_OK, "%s: hasher_final", name); + cfree_hasher_free(h); + EXPECT(l1 == l2 && memcmp(one, two, l1) == 0, + "%s: streamed digest == one-shot", name); +} + +int main(void) { + cfree_unit_init(&g_u); + + check_oneshot( + CFREE_HASH_SHA256, "sha256(\"\")", "", 0, + "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"); + check_oneshot( + CFREE_HASH_SHA256, "sha256(\"abc\")", "abc", 3, + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"); + check_oneshot(CFREE_HASH_CRC32, "crc32(\"123456789\")", "123456789", 9, + "cbf43926"); + check_oneshot( + CFREE_HASH_BLAKE2B, "blake2b(\"abc\")", "abc", 3, + "bddd813c634239723171ef3fee98579b94964e3bb1cb3e427262c8c068d52319"); + + check_stream_equiv(CFREE_HASH_SHA256, "sha256"); + check_stream_equiv(CFREE_HASH_BLAKE2B, "blake2b"); + check_stream_equiv(CFREE_HASH_CRC32, "crc32"); + + cfree_unit_summary(&g_u, "hash_test"); + return cfree_unit_status(&g_u); +} diff --git a/test/lib/unit.mk b/test/lib/unit.mk @@ -30,9 +30,10 @@ UNIT_CFLAGS_INTERNAL = $(HOST_CFLAGS) -Iinclude -Isrc -Itest # ---- registrations: stem lists + per-stem source --------------------------- UNIT_TESTS_PUBLIC := \ - ar_test cg_api_test cg_switch_test cg_fp_cmp_test rv64_jit_test \ + ar_test cg_api_test cg_switch_test cg_fp_cmp_test hash_test rv64_jit_test \ aa64_inline_test rv64_inline_test x64_inline_test ar_test_SRC := test/ar/ar_test.c +hash_test_SRC := test/api/hash_test.c cg_api_test_SRC := test/api/cg_type_test.c cg_switch_test_SRC := test/api/cg_switch_test.c cg_fp_cmp_test_SRC := test/api/cg_fp_cmp_test.c diff --git a/test/test.mk b/test/test.mk @@ -67,6 +67,8 @@ TEST_TARGETS = \ test-driver-objdump \ test-driver-pkg \ test-driver-strings \ + test-driver-tools \ + test-hash \ test-driver-strip \ test-dwarf \ test-elf \ @@ -183,7 +185,7 @@ test-images: test-cf-corpus-selftest: @bash test/lib/cf_corpus_selftest.sh -test-driver: test-driver-cc test-driver-ar test-driver-cas test-driver-strip test-driver-objcopy test-driver-objdump test-driver-pkg test-driver-strings +test-driver: test-driver-cc test-driver-ar test-driver-cas test-driver-strip test-driver-objcopy test-driver-objdump test-driver-pkg test-driver-strings test-driver-tools test-driver-cc: bin @CFREE=$(abspath $(BIN)) sh test/driver/run.sh @@ -263,6 +265,9 @@ test-driver-pkg: bin test-driver-strings: bin @CFREE=$(abspath $(BIN)) sh test/strings/run.sh +test-driver-tools: bin + @CFREE=$(abspath $(BIN)) sh test/tools/run.sh + # DWARF consumer unit test: builds a hand-crafted DWARF-bearing ELF in # memory and exercises every cfree_dwarf_* entry. It reaches into the # internal object builder to synthesize the fixture, so link individual @@ -374,6 +379,7 @@ test-interp-toy: bin CG_API_TEST_BIN = build/test/cg_api_test CG_SWITCH_TEST_BIN = build/test/cg_switch_test CG_FP_CMP_TEST_BIN = build/test/cg_fp_cmp_test +HASH_TEST_BIN = build/test/hash_test ABI_CLASSIFY_TEST_BIN = build/test/abi_classify_test IR_RECORDER_TEST_BIN = build/test/ir_recorder_test NATIVE_DIRECT_TARGET_TEST_BIN = build/test/native_direct_target_test @@ -383,6 +389,9 @@ test-cg-api: $(CG_API_TEST_BIN) $(CG_SWITCH_TEST_BIN) $(CG_FP_CMP_TEST_BIN) $(CG_SWITCH_TEST_BIN) $(CG_FP_CMP_TEST_BIN) +test-hash: $(HASH_TEST_BIN) + $(HASH_TEST_BIN) + test-abi-classify: $(ABI_CLASSIFY_TEST_BIN) $(ABI_CLASSIFY_TEST_BIN) diff --git a/test/tools/run.sh b/test/tools/run.sh @@ -0,0 +1,82 @@ +#!/bin/sh +# Driver-level checks for the byte-utility tools: xxd, cmp, hash, disas, mc. +# Self-checking (no golden files): round-trips and known encodings/digests are +# asserted inline via the shared cf_* verbs (ok/run_ok/run_fail/contains/ +# same_file) recorded over $work. + +set -u + +script_dir=$(cd "$(dirname "$0")" && pwd) +repo_root=$(cd "$script_dir/../.." && pwd) + +CFREE="${CFREE:-$repo_root/build/cfree}" + +if [ ! -x "$CFREE" ]; then + echo "tools: cfree binary not found at $CFREE" >&2 + exit 2 +fi + +work=$(mktemp -d "${TMPDIR:-/tmp}/cfree-tools-test.XXXXXX") +trap 'rm -rf "$work"' EXIT + +CF_KIT_DIR="$repo_root/test/lib" +. "$repo_root/test/lib/cfree_sh_kit.sh" +cf_report_init + +# A fixture with text, newlines, NUL and high bytes — exercises the ASCII +# column and binary round-tripping. +printf 'Hello, cfree!\nLine two.\n\000\001\377\376' > "$work/data.bin" + +# ---- xxd ------------------------------------------------------------------- +"$CFREE" xxd "$work/data.bin" > "$work/dump.txt" 2> "$work/xxd.err" +"$CFREE" xxd -r "$work/dump.txt" > "$work/rt.bin" 2>> "$work/xxd.err" +same_file xxd-roundtrip "$work/data.bin" "$work/rt.bin" + +"$CFREE" xxd -p "$work/data.bin" > "$work/p.txt" 2>> "$work/xxd.err" +"$CFREE" xxd -r -p "$work/p.txt" > "$work/rtp.bin" 2>> "$work/xxd.err" +same_file xxd-plain-roundtrip "$work/data.bin" "$work/rtp.bin" + +"$CFREE" xxd -i "$work/data.bin" > "$work/inc.txt" 2>> "$work/xxd.err" +contains xxd-include-array "$work/inc.txt" "unsigned char" +contains xxd-include-len "$work/inc.txt" "_len = 28" + +# ---- cmp ------------------------------------------------------------------- +cp "$work/data.bin" "$work/data2.bin" +run_ok cmp-identical "$CFREE" cmp "$work/data.bin" "$work/data2.bin" + +printf 'Hello, cfree!\nLine TWO.\n\000\001\377\376' > "$work/diff.bin" +run_fail cmp-differ-exit "$CFREE" cmp "$work/data.bin" "$work/diff.bin" +"$CFREE" cmp "$work/data.bin" "$work/diff.bin" > "$work/cmp.out" 2>&1 +contains cmp-differ-message "$work/cmp.out" "differ: char" +run_fail cmp-silent-exit "$CFREE" cmp -s "$work/data.bin" "$work/diff.bin" + +# ---- hash (CLI smoke; vectors covered by the test-hash unit test) ---------- +printf '123456789' > "$work/crc.in" +"$CFREE" hash -a crc32 "$work/crc.in" > "$work/crc.out" 2>&1 +contains hash-crc32 "$work/crc.out" "cbf43926" +printf 'abc' | "$CFREE" hash -a sha256 > "$work/sha.out" 2>&1 +contains hash-sha256 "$work/sha.out" \ + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" + +# ---- disas ----------------------------------------------------------------- +"$CFREE" disas -target aarch64 -x "1f 20 03 d5" > "$work/d-aa64.out" 2>&1 +contains disas-aa64-nop "$work/d-aa64.out" "nop" +"$CFREE" disas -target x86_64 -x "c3" > "$work/d-x64.out" 2>&1 +contains disas-x64-ret "$work/d-x64.out" "ret" +run_fail disas-bad-hex "$CFREE" disas -target aarch64 -x "zz" + +# ---- mc -------------------------------------------------------------------- +"$CFREE" mc -target aarch64 "add x0, x1, x2" > "$work/mc.out" 2>&1 +contains mc-aa64-encoding "$work/mc.out" "encoding: [0x20,0x00,0x02,0x8b]" + +# mc -p (raw hex) piped back through disas must recover the mnemonic. +"$CFREE" mc -target aarch64 -p "add x0, x1, x2" > "$work/mc.hex" 2>&1 +"$CFREE" disas -target aarch64 -x "$(cat "$work/mc.hex")" > "$work/mc-rt.out" 2>&1 +contains mc-disas-roundtrip "$work/mc-rt.out" "add x0, x1, x2" + +# A branch to an undefined symbol should surface a relocation, not an error. +"$CFREE" mc -target aarch64 "b somewhere" > "$work/mc-rel.out" 2>&1 +contains mc-reloc "$work/mc-rel.out" "reloc" + +cf_summary tools-driver +cf_exit