test_ingest: portable temp paths for Windows CI

The test hardcoded /tmp, which does not exist on the Windows runner.
With NDEBUG compiling the asserts out, the NULL stream from the failed
fopen reached fclose() and tripped the UCRT invalid-parameter fail-fast
(0xc0000409). Temp files now go to %TEMP% on Windows; rm -rf and unlink
are replaced with ISO C remove(); file-handle acquisition failures now
exit loudly instead of relying on assert.
This commit is contained in:
Eremey Valetov
2026-06-11 17:01:29 -04:00
parent efd41dceb1
commit ac01b32273

View File

@@ -18,11 +18,41 @@ static int tests_run = 0, tests_passed = 0;
static char tmp_archive[256];
static void rmrf(const char *path)
/* Temp-file base: %TEMP% on Windows, /tmp elsewhere. */
static const char *tmpdir(void)
{
char cmd[768];
snprintf(cmd, sizeof cmd, "rm -rf '%s' '%s.blocks'", path, path);
system(cmd);
#ifdef _WIN32
const char *t = getenv("TEMP");
if (!t) t = getenv("TMP");
return t ? t : ".";
#else
return "/tmp";
#endif
}
/* Remove the archive and its derived files. v2 archives never create
* the .blocks sidecar, so plain remove() covers everything. */
static void cleanup(const char *path)
{
char buf[320];
remove(path);
snprintf(buf, sizeof buf, "%s.out", path);
remove(buf);
snprintf(buf, sizeof buf, "%s.blocks", path);
remove(buf);
}
/* fopen that fails the test loudly: assert() is compiled out in
* Release builds, and continuing with a NULL stream trips the MSVC
* CRT invalid-parameter fail-fast instead of a test failure. */
static FILE *xfopen(const char *path, const char *mode)
{
FILE *f = fopen(path, mode);
if (!f) {
fprintf(stderr, "FATAL: cannot open %s (mode %s)\n", path, mode);
exit(1);
}
return f;
}
static void fill_random(uint8_t *buf, size_t len, uint32_t seed)
@@ -37,7 +67,10 @@ static void fill_random(uint8_t *buf, size_t len, uint32_t seed)
static uint8_t *slurp(const char *path, size_t *out_len)
{
FILE *f = fopen(path, "rb");
if (!f) return NULL;
if (!f) {
fprintf(stderr, "FATAL: cannot slurp %s\n", path);
exit(1);
}
fseek(f, 0, SEEK_END);
long n = ftell(f);
fseek(f, 0, SEEK_SET);
@@ -50,7 +83,7 @@ static uint8_t *slurp(const char *path, size_t *out_len)
static void test_roundtrip_small(void)
{
rmrf(tmp_archive);
cleanup(tmp_archive);
const char *msg = "hello world";
struct uc2_ingest_stats st;
int rc = uc2_ingest_write(tmp_archive,
@@ -64,8 +97,7 @@ static void test_roundtrip_small(void)
char restored[320];
snprintf(restored, sizeof restored, "%s.out", tmp_archive);
FILE *out = fopen(restored, "wb");
assert(out);
FILE *out = xfopen(restored, "wb");
rc = uc2_ingest_restore(tmp_archive, out);
fclose(out);
assert(rc == 0);
@@ -75,13 +107,13 @@ static void test_roundtrip_small(void)
assert(got_len == strlen(msg));
assert(memcmp(got, msg, got_len) == 0);
free(got);
unlink(restored);
rmrf(tmp_archive);
remove(restored);
cleanup(tmp_archive);
}
static void test_roundtrip_multichunk(void)
{
rmrf(tmp_archive);
cleanup(tmp_archive);
const size_t N = 200000;
uint8_t *data = malloc(N);
fill_random(data, N, 0x12345678);
@@ -95,8 +127,7 @@ static void test_roundtrip_multichunk(void)
char restored[320];
snprintf(restored, sizeof restored, "%s.out", tmp_archive);
FILE *out = fopen(restored, "wb");
assert(out);
FILE *out = xfopen(restored, "wb");
rc = uc2_ingest_restore(tmp_archive, out);
fclose(out);
assert(rc == 0);
@@ -108,13 +139,13 @@ static void test_roundtrip_multichunk(void)
free(got);
free(data);
unlink(restored);
rmrf(tmp_archive);
remove(restored);
cleanup(tmp_archive);
}
static void test_intra_call_dedup(void)
{
rmrf(tmp_archive);
cleanup(tmp_archive);
/* Concatenate the same random buffer twice -- CDC produces the
* same chunk hashes for both halves, so half the chunks should
* dedup within a single ingest call. */
@@ -137,8 +168,7 @@ static void test_intra_call_dedup(void)
* structurally transparent. */
char restored[320];
snprintf(restored, sizeof restored, "%s.out", tmp_archive);
FILE *out = fopen(restored, "wb");
assert(out);
FILE *out = xfopen(restored, "wb");
rc = uc2_ingest_restore(tmp_archive, out);
fclose(out);
assert(rc == 0);
@@ -150,13 +180,13 @@ static void test_intra_call_dedup(void)
free(got);
free(data);
unlink(restored);
rmrf(tmp_archive);
remove(restored);
cleanup(tmp_archive);
}
static void test_v2_self_contained(void)
{
rmrf(tmp_archive);
cleanup(tmp_archive);
/* A v2 archive must restore correctly even if the legacy sidecar
* blockstore directory is absent. The chunk pool lives inside
* the archive file itself. */
@@ -179,8 +209,7 @@ static void test_v2_self_contained(void)
char restored[320];
snprintf(restored, sizeof restored, "%s.out", tmp_archive);
FILE *out = fopen(restored, "wb");
assert(out);
FILE *out = xfopen(restored, "wb");
rc = uc2_ingest_restore(tmp_archive, out);
fclose(out);
assert(rc == 0);
@@ -192,13 +221,13 @@ static void test_v2_self_contained(void)
free(got);
free(data);
unlink(restored);
rmrf(tmp_archive);
remove(restored);
cleanup(tmp_archive);
}
static void test_empty_stream(void)
{
rmrf(tmp_archive);
cleanup(tmp_archive);
struct uc2_ingest_stats st;
int rc = uc2_ingest_write(tmp_archive, NULL, 0, 0, &st);
assert(rc == 0);
@@ -208,8 +237,7 @@ static void test_empty_stream(void)
char restored[320];
snprintf(restored, sizeof restored, "%s.out", tmp_archive);
FILE *out = fopen(restored, "wb");
assert(out);
FILE *out = xfopen(restored, "wb");
rc = uc2_ingest_restore(tmp_archive, out);
fclose(out);
assert(rc == 0);
@@ -218,35 +246,35 @@ static void test_empty_stream(void)
uint8_t *got = slurp(restored, &got_len);
assert(got_len == 0);
free(got);
unlink(restored);
rmrf(tmp_archive);
remove(restored);
cleanup(tmp_archive);
}
static void test_bad_magic_rejected(void)
{
rmrf(tmp_archive);
FILE *f = fopen(tmp_archive, "wb");
assert(f);
cleanup(tmp_archive);
FILE *f = xfopen(tmp_archive, "wb");
const char garbage[16] = "not-a-uc2-ingest";
fwrite(garbage, 1, sizeof garbage, f);
fclose(f);
FILE *out = fopen("/dev/null", "wb");
#ifdef _MSC_VER
if (!out) out = fopen("NUL", "wb");
#endif
assert(out);
if (!out) {
fprintf(stderr, "FATAL: no null device\n");
exit(1);
}
int rc = uc2_ingest_restore(tmp_archive, out);
fclose(out);
assert(rc != 0);
(void)rc;
rmrf(tmp_archive);
cleanup(tmp_archive);
}
int main(void)
{
snprintf(tmp_archive, sizeof tmp_archive,
"/tmp/uc2_ingest_test_%d.uc2", (int)getpid());
"%s/uc2_ingest_test_%d.uc2", tmpdir(), (int)getpid());
printf("Running uc2_ingest tests...\n");
TEST(test_roundtrip_small);