myxce/src/harness/snapdiff.c
Rongsong Shen cf55d691de
feat(xce-harness-component): relocate xce_test into standalone harness component
Move xce_test's 15 production sources + headers from src/controller/testsuite/
into a new src/harness/ component with its own meson.build, and strip every
now-dangling controller-side reference (11 controller_unit_test_src entries,
4 standalone test-binary blocks, 11 controller_test.c extern/RUN_TEST lines)
so the controller build is never left broken.

Fixes a broken relative-symlink bridge (xce_test_controller_link) added to
keep two controller-embedded tests (test_test_cli.c, test_xcetest_process_entry.c)
finding the relocated xce_test binary until task 2.1 moves them too.

Discovered and documented in design.md: four controller-domain regression
tests call functions directly from four of xce_test's own files, requiring
controller_unit_test to permanently recompile them from src/harness/ — a
real dependency neither the original discovery nor design audit caught.

controller_unit_test: 1228 Tests 0 Failures 0 Ignored (verified via the
Unity binary's own printed summary line, not just meson's aggregate count).

Task 1.1 of xce-harness-component.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RLSNJhNoULvVcUhXEFafQC
2026-09-14 05:08:15 +00:00

113 lines
3 KiB
C

#define _GNU_SOURCE
#include "snapdiff.h"
#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#define SNAPDIFF_BUF_SIZE 65536
int snapdiff_paths(const char* path1, const char* path2, FILE* out,
snapdiff_report_t* rep)
{
if (!path1 || !path2)
return -EINVAL;
snapdiff_report_t local;
memset(&local, 0, sizeof(local));
local.diff_offset = -1;
int fd1 = open(path1, O_RDONLY);
if (fd1 < 0) {
int saved = errno;
if (out)
fprintf(out, "snapdiff: %s: %s\n", path1, strerror(saved));
return -saved;
}
int fd2 = open(path2, O_RDONLY);
if (fd2 < 0) {
int saved = errno;
close(fd1);
if (out)
fprintf(out, "snapdiff: %s: %s\n", path2, strerror(saved));
return -saved;
}
struct stat st1, st2;
if (fstat(fd1, &st1) != 0 || fstat(fd2, &st2) != 0) {
int saved = errno;
close(fd1);
close(fd2);
if (out)
fprintf(out, "snapdiff: fstat failed: %s\n", strerror(saved));
return -saved;
}
local.size1 = st1.st_size;
local.size2 = st2.st_size;
if (st1.st_size != st2.st_size) {
local.size_mismatch = 1;
close(fd1);
close(fd2);
if (rep)
*rep = local;
if (out)
fprintf(out,
"snapdiff: %s (%jd bytes) vs %s (%jd bytes): SIZE MISMATCH\n",
path1, (intmax_t)local.size1, path2, (intmax_t)local.size2);
return 1;
}
uint8_t buf1[SNAPDIFF_BUF_SIZE];
uint8_t buf2[SNAPDIFF_BUF_SIZE];
off_t off = 0;
int found_diff = 0;
for (;;) {
ssize_t n1 = read(fd1, buf1, sizeof(buf1));
ssize_t n2 = read(fd2, buf2, sizeof(buf2));
if (n1 <= 0 || n2 <= 0)
break;
ssize_t n = (n1 < n2) ? n1 : n2;
for (ssize_t i = 0; i < n; i++) {
if (buf1[i] != buf2[i]) {
local.diff_offset = off + (off_t)i;
found_diff = 1;
break;
}
}
if (found_diff)
break;
off += (off_t)n;
}
close(fd1);
close(fd2);
if (!found_diff) {
local.identical = 1;
if (rep)
*rep = local;
if (out)
fprintf(out, "snapdiff: %s vs %s: IDENTICAL (%jd bytes)\n", path1,
path2, (intmax_t)local.size1);
return 0;
}
local.chunk_index = local.diff_offset / SNAPDIFF_CHUNK_SIZE;
local.at_chunk_boundary = (local.diff_offset % SNAPDIFF_CHUNK_SIZE == 0);
if (rep)
*rep = local;
if (out)
fprintf(out,
"snapdiff: %s vs %s: DIFFER at offset %jd (chunk %jd%s)\n",
path1, path2, (intmax_t)local.diff_offset,
(intmax_t)local.chunk_index,
local.at_chunk_boundary
? " -- exactly at a chunk boundary, first byte of chunk"
: " -- NOT at a chunk boundary, mid-chunk");
return 1;
}