Implements the core design: a mount table published as an atomically- swapped snapshot; mem/dir/pack/overlay backends; copy-on-write overlay with copy-up and whiteout deletion; a checksummed append journal; compaction with exact-duplicate elimination; single-writer/wait-free- reader concurrency with a structural/content write split; openat2/ Landlock path containment for dir mounts; and load-time pack integrity validation. Zero required third-party dependencies. Sanitizer testing (ASan/UBSan) caught and led to fixing a genuine heap-use-after-free in the snapshot-reclamation path: the textbook "load pointer, then increment its refcount" pattern left a gap a concurrent writer could free through. Closed with a small reclaim_gate rwlock, documented in internal.h and CLAUDE.md since it's a pattern every refcounted structure in the codebase now follows. zip/tar import/export backends, recommended in concept.md Section 11, will not be built — a permanent project decision recorded in CLAUDE.md since concept.md itself is frozen and cannot be edited to reflect it. Includes a runnable demo (examples/demo.c, `make demo`) exercising the library end to end and proving cross-run persistence through the pack file, plus open-source scaffolding: MIT license, README, CONTRIBUTING, and a CI workflow running the test suite under ASan/UBSan/TSan. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UqJpkdJ6Njnt1pw3CbghzB
47 lines
1.3 KiB
C
47 lines
1.3 KiB
C
/*
|
|
* test_harness.h — minimal assertion-based test harness.
|
|
*
|
|
* No third-party test framework, consistent with the project's
|
|
* static-linking / zero-required-dependency constraint (Section 11.1).
|
|
*/
|
|
#ifndef PACKFS_TEST_HARNESS_H
|
|
#define PACKFS_TEST_HARNESS_H
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
static int pfs_test_failures = 0;
|
|
|
|
#define CHECK(cond) do { \
|
|
if (!(cond)) { \
|
|
fprintf(stderr, "FAIL %s:%d: %s\n", __FILE__, __LINE__, #cond); \
|
|
pfs_test_failures++; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define CHECK_EQ_INT(a, b) do { \
|
|
long long _a = (long long)(a), _b = (long long)(b); \
|
|
if (_a != _b) { \
|
|
fprintf(stderr, "FAIL %s:%d: %s (%lld) != %s (%lld)\n", __FILE__, __LINE__, #a, _a, #b, _b); \
|
|
pfs_test_failures++; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define CHECK_STR_EQ(a, b) do { \
|
|
const char *_a = (a), *_b = (b); \
|
|
if (strcmp(_a, _b) != 0) { \
|
|
fprintf(stderr, "FAIL %s:%d: %s (\"%s\") != %s (\"%s\")\n", __FILE__, __LINE__, #a, _a, #b, _b); \
|
|
pfs_test_failures++; \
|
|
} \
|
|
} while (0)
|
|
|
|
#define TEST_MAIN_END() \
|
|
do { \
|
|
if (pfs_test_failures) { fprintf(stderr, "%d check(s) failed\n", pfs_test_failures); return 1; } \
|
|
fprintf(stderr, "OK\n"); \
|
|
return 0; \
|
|
} while (0)
|
|
|
|
#endif
|