bump to 0.9.8; add padded-canary build (app_version_padding_tests)

Canary re-proven on this base: reconstruct-from-components trips the
fixture checks; an unpadded fixture trips the non-vacuity assertion.
De-literalizes stale version examples in comments.
This commit is contained in:
2026-07-27 22:51:16 -04:00
parent 0c06bbad2c
commit 3790677097
5 changed files with 180 additions and 27 deletions
+84
View File
@@ -0,0 +1,84 @@
// test_app_version_padding.cpp — the ALWAYS-ON anti-normalization guard for the version
// string threading (Phase V, V1 leading-zero fidelity). No REAPER, no framework.
//
// WHY THIS EXECUTABLE EXISTS: test_app_version.cpp pins stampVersion() relative to the
// live configure_file'd version string — but a live-version assertion can only DETECT a
// "reconstruct the string from numeric components" regression when the live version
// happens to be zero-padded. "0.9.01" reconstructed via integers renders "0.9.1" and
// trips it; "0.9.8" reconstructs to itself, so at an unpadded version the check passes
// whether or not the code regressed — the guard silently goes vacuous while green.
// Padded and unpadded versions are both legitimate (Daniel's ruling), so the guard must
// not depend on the shipped version's shape.
//
// MECHANISM: CMakeLists.txt runs the SAME src/version_generated.h.in template through
// configure_file a second time with a SYNTHETIC zero-padded version ("0.9.01") into
// generated_padding_canary/, and this executable compiles the SAME src/app_version.cpp
// against that header (include-dir substitution — this target never sees the live
// generated/ dir). The exact production derivation path — template substitution →
// REASAMPLER_VERSION_STRING → stampVersion()/appVersion() — is thereby exercised with an
// input whose normalized form provably differs from its verbatim form. If anyone
// reimplements the version string by reconstructing it from numeric components (a
// parse-and-reprint inside app_version.cpp, or project(VERSION) numeric macros added to
// the template), this binary renders "0.9.1" and the checks below fail — at ANY live
// version, which is exactly the property the live-version assertion cannot provide.
//
// The "0.9.01" literals below are the synthetic fixture and MUST match the canary
// configure_file input in CMakeLists.txt. They are NOT the shipped version: never bump
// them on release — their padded shape is the entire point.
#include "../src/app_version.h"
#include <cstdio>
#include <string>
using namespace reasampler;
static int g_fail = 0;
#define CHECK(cond) do { if(!(cond)) { \
std::printf("FAIL line %d: %s\n", __LINE__, #cond); ++g_fail; } } while(0)
static void testPaddedVersionSurvivesThreadingVerbatim() {
// The verbatim-threading invariant, exercised with an input where reconstruction and
// verbatim DIFFER: a normalized render would be "0.9.1" and fail both checks.
CHECK(stampVersion() == "0.9.01");
if (isBeta()) CHECK(appVersion() == "0.9.01-beta");
else CHECK(appVersion() == "0.9.01");
}
static void testPaddedStampStillClassifiesStamped() {
// A padded stamp stays classifiable on read-back: parse tolerates leading zeros
// (raw preserved verbatim, triple normalized to integers — {0,9,1}).
WritingVersion wv = classifyWritingVersion(stampVersion());
CHECK(wv.kind == WritingVersion::Kind::Stamped);
CHECK(wv.raw == "0.9.01");
CHECK(wv.parsed.major == 0 && wv.parsed.minor == 9 && wv.parsed.patch == 1);
}
static void testCanaryFixtureIsNonVacuous() {
// Self-check: the canary fixture must be zero-padded so that its verbatim string
// differs from what a parse-and-reprint of its numeric triple would produce.
// If the fixture is ever "fixed" to an unpadded form (e.g. "0.9.1"), the checks in
// testPaddedVersionSurvivesThreadingVerbatim become vacuous — a reconstructed
// string would match the fixture and the canary would pass even if the threading
// regressed. Parse stampVersion() and reprint the triple; they must NOT match.
WritingVersion wv = classifyWritingVersion(stampVersion());
CHECK(wv.kind == WritingVersion::Kind::Stamped); // fixture must be parseable
const std::string reprinted =
std::to_string(wv.parsed.major) + "." +
std::to_string(wv.parsed.minor) + "." +
std::to_string(wv.parsed.patch);
// If this fails, the fixture is unpadded and the canary guards nothing.
// Restore a zero-padded fixture (e.g. "0.9.01") in CMakeLists.txt and
// update the matching literals in this file.
CHECK(reprinted != stampVersion());
}
int main() {
testPaddedVersionSurvivesThreadingVerbatim();
testPaddedStampStillClassifiesStamped();
testCanaryFixtureIsNonVacuous();
if (g_fail == 0) std::printf("app_version_padding: all tests passed\n");
else std::printf("app_version_padding: %d CHECK(s) FAILED\n", g_fail);
return g_fail == 0 ? 0 : 1;
}