// 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 // // 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:" 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 #include #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 \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; }