joeylib2/tools/diffUberHashes/diffUberHashes.c

101 lines
3.4 KiB
C

// Part of JoeyLib, Copyright (c) 2026 Scott Duensing, under the MIT License.
// See LICENSE.md for license information.
// SPDX-License-Identifier: MIT
//
// diffUberHashes.c - compare two UBER logs (joeylog.txt) op by op, by the
// surface hash each op left.
//
// diffUberHashes <reference-log> <test-log>
//
// The golden gates hold each port's UBER run to tests/goldens/uber with it
// (scripts/verify-all.sh), and a port's rewrite of a primitive is checked
// with it: it names every op whose pixels came out different, which "looks
// right" misses until the mismatch cascades into corruption that is hard
// to trace.
//
// Both the timed ops' hashes and the UBER-CHK correctness checks' count, a
// check's under "chk:<op>" so it can never meet a timed op's name; the last
// hash a log gives an op is the one compared (toolUberLog.h). Prints a line
// for each op MISSING from the test log, each MISMATCH, and each EXTRA op
// only the test log has, then the tally.
//
// Exit: 0 every hash matches, 1 at least one does not (or an op is missing
// or extra), 2 a usage error or a log that cannot be read or has no UBER
// hash lines.
#include <stdio.h>
#include <string.h>
#include "toolFile.h"
#include "toolUberLog.h"
#define TOOL_NAME "diffUberHashes"
#define ARG_COUNT 3
#define MATCH_EXIT 0
#define FAIL_EXIT 1
#define USAGE_EXIT 2
int main(int argc, char **argv) {
ToolUberLogT ref;
ToolUberLogT test;
const ToolUberOpT *op;
const ToolUberOpT *other;
size_t matches;
size_t mismatches;
size_t extras;
size_t i;
toolFileName(TOOL_NAME);
if (argc != ARG_COUNT) {
fprintf(stderr, "usage: %s <reference-log> <test-log>\n", TOOL_NAME);
return USAGE_EXIT;
}
if (!toolUberRead(TOOL_NAME, argv[1], TOOL_UBER_HASH, &ref) || !toolUberRead(TOOL_NAME, argv[2], TOOL_UBER_HASH, &test)) {
return USAGE_EXIT;
}
if (ref.count == 0u) {
fprintf(stderr, "%s: no UBER hash lines in %s\n", TOOL_NAME, argv[1]);
return USAGE_EXIT;
}
if (test.count == 0u) {
fprintf(stderr, "%s: no UBER hash lines in %s\n", TOOL_NAME, argv[2]);
return USAGE_EXIT;
}
matches = 0u;
mismatches = 0u;
extras = 0u;
for (i = 0; i < ref.count; i++) {
op = &ref.ops[i];
other = toolUberFind(&test, op->name, op->nameLen);
if (other == NULL) {
fputs(" MISSING in test: ", stdout);
toolUberNamePrint(stdout, op);
printf(" (ref=%s)\n", op->hash);
mismatches++;
} else if (strcmp(other->hash, op->hash) != 0) {
fputs(" MISMATCH ", stdout);
toolUberNamePrint(stdout, op);
printf(": ref=%s test=%s\n", op->hash, other->hash);
mismatches++;
} else {
matches++;
}
}
for (i = 0; i < test.count; i++) {
op = &test.ops[i];
if (toolUberFind(&ref, op->name, op->nameLen) == NULL) {
fputs(" EXTRA in test: ", stdout);
toolUberNamePrint(stdout, op);
printf(" (test=%s)\n", op->hash);
extras++;
}
}
putchar('\n');
if (mismatches == 0u && extras == 0u) {
printf("OK: %zu/%zu ops match\n", matches, ref.count + extras);
return MATCH_EXIT;
}
printf("FAIL: %zu match, %zu mismatch, %zu extras\n", matches, mismatches, extras);
return FAIL_EXIT;
}