// 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 relative assertion (e.g. appVersion() == // stampVersion()) is version-shape-blind: it holds whether the string was threaded // verbatim or reconstructed from numeric components, at any version, padded or not. // The live suite therefore cannot detect a reconstruct-from-components regression at all. // 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 #include 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, one of two causes: (1) the fixture was changed to an unpadded form // (e.g. "0.9.1") — restore a zero-padded fixture (e.g. "0.9.01") in CMakeLists.txt // and update the matching literals in this file; or (2) the fixture is still padded // but app_version.cpp regressed to parse-and-reprint — in that case // testPaddedVersionSurvivesThreadingVerbatim also fails, pointing at the real cause. 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; }