feat(version): V4 beta-in-isolation channel via -DREASAMPLER_CHANNEL
Compile-time channel flag forks a fully isolated reaper_reasampler_beta (namespace, command-id prefix, action names, dock ident, -beta render) from one auditable app_version definition. Stable identity byte-unchanged.
This commit is contained in:
@@ -17,13 +17,94 @@ static int g_fail = 0;
|
||||
std::printf("FAIL line %d: %s\n", __LINE__, #cond); ++g_fail; } } while(0)
|
||||
|
||||
// --- appVersion: exact-string fidelity, leading zero preserved ----------------
|
||||
//
|
||||
// The channel is a COMPILE-TIME fact (REASAMPLER_CHANNEL_IS_BETA, threaded through the same
|
||||
// configure_file'd header): the stable `build` tree compiles these tests with the flag = 0,
|
||||
// the `build-beta` tree with = 1. So each config's ctest run validates ITS OWN channel's
|
||||
// derivation. The channel-dependent assertions below branch on isBeta() so the ONE test
|
||||
// source is correct in both configs — and each branch would fail if the derivation regressed
|
||||
// (a beta build rendering "0.9.01" without the suffix, or stable rendering "-beta", trips it).
|
||||
|
||||
static void testVersionConstantRendersExactString() {
|
||||
// The Daniel-fixed string: EXACTLY "0.9.01", two-digit zero-padded patch. This is
|
||||
// the whole point of sourcing the STRING (not reconstructing from numeric components):
|
||||
// a normalized "0.9.1" here would be a leading-zero-fidelity regression, and this
|
||||
// assertion fails against the actual CMake-configured value, not a re-derivation.
|
||||
CHECK(appVersion() == "0.9.01");
|
||||
// The Daniel-fixed base string: EXACTLY "0.9.01", two-digit zero-padded patch — the
|
||||
// numeric triple, IDENTICAL on both channels (it is also the stamp value). This is the
|
||||
// whole point of sourcing the STRING (not reconstructing from numeric components): a
|
||||
// normalized "0.9.1" here would be a leading-zero-fidelity regression. stampVersion()
|
||||
// is the pure numeric triple regardless of channel.
|
||||
CHECK(stampVersion() == "0.9.01");
|
||||
}
|
||||
|
||||
// --- channel-derived rendering (V4) -------------------------------------------
|
||||
|
||||
static void testChannelDerivedRendering() {
|
||||
// The DISPLAY render. Stable: exactly the numeric string. Beta: numeric + "-beta"
|
||||
// (a plain suffix, V2). This is the show-version + panel-readout value. Each branch is
|
||||
// the assertion the OTHER config's build would need to fail — i.e. a stable build that
|
||||
// wrongly rendered "-beta", or a beta build that dropped it, is caught here.
|
||||
if (isBeta()) {
|
||||
CHECK(channel() == Channel::Beta);
|
||||
CHECK(appVersion() == "0.9.01-beta");
|
||||
} else {
|
||||
CHECK(channel() == Channel::Stable);
|
||||
CHECK(appVersion() == "0.9.01");
|
||||
}
|
||||
// The STAMP value is the numeric triple on BOTH channels — never suffixed — so it stays
|
||||
// classifiable (see the stamp-classifiability test) and byte-identical to stable.
|
||||
CHECK(stampVersion() == "0.9.01");
|
||||
}
|
||||
|
||||
static void testChannelDerivedIdentityStrings() {
|
||||
// Namespace, command-id prefix, action-name prefix, binary + dock idents all fork from
|
||||
// the one channel bit. Stable values are BYTE-IDENTICAL to the pre-V4 build — any drift
|
||||
// in the stable branch is a shipped-identity defect.
|
||||
if (isBeta()) {
|
||||
CHECK(extStateNamespace() == "reasampler_beta");
|
||||
CHECK(commandIdPrefix() == "CEREBELLUM_REASAMPLER_BETA_");
|
||||
CHECK(actionDisplayPrefix() == "ReaSampler beta: ");
|
||||
CHECK(binaryName() == "reaper_reasampler_beta");
|
||||
CHECK(dockTitle() == "ReaSampler Bank beta");
|
||||
CHECK(dockIdent() == "reasampler_bank_panel_beta");
|
||||
} else {
|
||||
CHECK(extStateNamespace() == "reasampler");
|
||||
CHECK(commandIdPrefix() == "CEREBELLUM_REASAMPLER_");
|
||||
CHECK(actionDisplayPrefix() == "ReaSampler: ");
|
||||
CHECK(binaryName() == "reaper_reasampler");
|
||||
CHECK(dockTitle() == "ReaSampler Bank");
|
||||
CHECK(dockIdent() == "reasampler_bank_panel");
|
||||
}
|
||||
}
|
||||
|
||||
static void testChannelQualifiedIdAndNameComposition() {
|
||||
// The two composition helpers the shells funnel through. A representative shipped id
|
||||
// (CAPTURE_TRACK) and phrase must compose to the exact channel-qualified strings — this
|
||||
// is what guarantees stable rebuilds its shipped id and beta gets the isolated one.
|
||||
if (isBeta()) {
|
||||
CHECK(channelCommandId("CAPTURE_TRACK") == "CEREBELLUM_REASAMPLER_BETA_CAPTURE_TRACK");
|
||||
CHECK(channelActionName("capture selected track(s)") ==
|
||||
"ReaSampler beta: capture selected track(s)");
|
||||
} else {
|
||||
CHECK(channelCommandId("CAPTURE_TRACK") == "CEREBELLUM_REASAMPLER_CAPTURE_TRACK");
|
||||
CHECK(channelActionName("capture selected track(s)") ==
|
||||
"ReaSampler: capture selected track(s)");
|
||||
}
|
||||
}
|
||||
|
||||
static void testStampClassifiesAsStampedOnOwnChannel() {
|
||||
// The V4 stamp-classifiability requirement: the value a channel WRITES (stampVersion())
|
||||
// must classify as Stamped when that same channel reads it back — on BOTH channels. A
|
||||
// "-beta"-suffixed stamp would classify as Unknown, so this fails if a build ever stamped
|
||||
// appVersion() instead of stampVersion().
|
||||
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);
|
||||
|
||||
// The OTHER channel's raw stamp value is handled without throwing per the design: since
|
||||
// both channels stamp the identical numeric triple, the other channel's value is the same
|
||||
// "0.9.01" and also classifies Stamped. (The DISPLAY string "0.9.01-beta", by contrast,
|
||||
// is intentionally NOT the stamp value — confirm it classifies Unknown, proving why the
|
||||
// stamp must stay the numeric triple.)
|
||||
CHECK(classifyWritingVersion("0.9.01-beta").kind == WritingVersion::Kind::Unknown);
|
||||
}
|
||||
|
||||
// --- parseVersion: well-formed, leading zeros, and rejection ------------------
|
||||
@@ -122,6 +203,10 @@ static void testStampedStampIsOrderableAgainstCurrent() {
|
||||
|
||||
int main() {
|
||||
testVersionConstantRendersExactString();
|
||||
testChannelDerivedRendering();
|
||||
testChannelDerivedIdentityStrings();
|
||||
testChannelQualifiedIdAndNameComposition();
|
||||
testStampClassifiesAsStampedOnOwnChannel();
|
||||
testParseWellFormed();
|
||||
testParseRejectsMalformed();
|
||||
testOrderingByPatch();
|
||||
|
||||
@@ -252,11 +252,15 @@ static void testTableHasBothScopes() {
|
||||
std::set<std::string> ids;
|
||||
int item = 0, track = 0;
|
||||
for (const auto& def : table) {
|
||||
// Every id is a non-empty CEREBELLUM_REASAMPLER_ string and is UNIQUE
|
||||
// (duplicate ids would collide on registration).
|
||||
std::string id = def.commandString;
|
||||
CHECK(id.rfind("CEREBELLUM_REASAMPLER_", 0) == 0);
|
||||
CHECK(ids.insert(id).second); // false if duplicate
|
||||
// Every command SUFFIX (Phase V, V4 — the channel prefix is prepended by the shell)
|
||||
// is a non-empty, UNIQUE string (duplicate suffixes would collide once composed).
|
||||
std::string suffix = def.commandSuffix;
|
||||
CHECK(!suffix.empty());
|
||||
// The suffix is NOT prefixed with the channel family here — that is composed at
|
||||
// register time. A leftover "CEREBELLUM_REASAMPLER_" in the table would be a
|
||||
// double-prefix bug, so assert its ABSENCE.
|
||||
CHECK(suffix.rfind("CEREBELLUM_REASAMPLER_", 0) != 0);
|
||||
CHECK(ids.insert(suffix).second); // false if duplicate
|
||||
// Every scope resolves to a supported offline source.
|
||||
CHECK(renderSettingsFor(sourceModeForScope(def.scope), 1.0).supported);
|
||||
|
||||
@@ -269,16 +273,17 @@ static void testTableHasBothScopes() {
|
||||
}
|
||||
|
||||
static void testScopeActionIdsAreTheShippedStrings() {
|
||||
// Pin the shipped CAPTURE_ITEM / CAPTURE_TRACK ids so a future edit that silently
|
||||
// changes them (breaking user keybindings) fails the gate.
|
||||
// Pin the shipped CAPTURE_ITEM / CAPTURE_TRACK SUFFIXES so a future edit that silently
|
||||
// changes them (breaking user keybindings once composed with the channel prefix) fails
|
||||
// the gate. The full stable id is prefix + suffix ("CEREBELLUM_REASAMPLER_CAPTURE_ITEM").
|
||||
const auto& table = captureActionTable();
|
||||
std::string itemId, trackId;
|
||||
for (const auto& def : table) {
|
||||
if (def.scope == CaptureScope::Item) itemId = def.commandString;
|
||||
if (def.scope == CaptureScope::Track) trackId = def.commandString;
|
||||
if (def.scope == CaptureScope::Item) itemId = def.commandSuffix;
|
||||
if (def.scope == CaptureScope::Track) trackId = def.commandSuffix;
|
||||
}
|
||||
CHECK(itemId == "CEREBELLUM_REASAMPLER_CAPTURE_ITEM");
|
||||
CHECK(trackId == "CEREBELLUM_REASAMPLER_CAPTURE_TRACK");
|
||||
CHECK(itemId == "CAPTURE_ITEM");
|
||||
CHECK(trackId == "CAPTURE_TRACK");
|
||||
}
|
||||
|
||||
int main() {
|
||||
|
||||
Reference in New Issue
Block a user