Files
reasampler/tests/test_bake_wire.cpp
T

113 lines
4.4 KiB
C++

// Standalone tests for reasampler::wire::bake_wire — no VST3, no REAPER, no framework.
// Same fast assert loop as the sibling wire tests.
//
// Covers: request + outcome round-trips including bytes that would break a delimiter-based
// format; the refusals every house wire record shares (wrong tag, truncation, trailing
// garbage, a swapped record kind); an unrecognized status integer degrading to Failed
// rather than to Ok; and the action lookup name's leading underscore.
#include "../src/core/wire/bake_wire.h"
#include <cstdio>
#include <string>
using namespace reasampler::wire;
static int g_fail = 0;
#define CHECK(cond) do { if(!(cond)) { \
std::printf("FAIL line %d: %s\n", __LINE__, #cond); ++g_fail; } } while(0)
int main() {
// --- Request round-trip, with hostile field content -----------------------------
{
BakeRequest req;
req.instanceGuid = "0123abcd";
req.stagedFilePath = "C:/Temp/re:sampler 9000/bake 12:34.wav"; // colons + spaces
req.sourceSampleId = "cap-1";
req.sourceRelativePath = "reasampler_bank/kick.wav";
req.sourceDisplayName = "Kick r2";
req.ownUsageKey = "rsusage_0123abcd";
req.rootNote = 36;
req.generation = 1893456000;
const std::string encoded = encodeBakeRequest(req);
const auto decoded = decodeBakeRequest(encoded);
CHECK(decoded.has_value());
CHECK(*decoded == req);
// Empty strings and a zero generation survive too (a first, un-named source).
BakeRequest bare;
CHECK(decodeBakeRequest(encodeBakeRequest(bare)) == bare);
}
// --- Outcome round-trip -----------------------------------------------------------
{
BakeOutcome out;
out.status = BakeStatus::Ok;
out.sampleId = "bake-1893456000-kick_1893456000.wav";
out.relativePath = "reasampler_bank/kick_1893456000.wav";
out.displayName = "Kick r3";
out.rootNote = 36;
out.channelCount = 2;
out.replaced = true;
out.message = "replaced the bank entry";
out.generation = 1893456000;
const auto decoded = decodeBakeOutcome(encodeBakeOutcome(out));
CHECK(decoded.has_value());
CHECK(*decoded == out);
CHECK(decoded->replaced);
out.replaced = false;
CHECK(decodeBakeOutcome(encodeBakeOutcome(out))->replaced == false);
}
// --- Malformed input is refused, never half-parsed ---------------------------------
{
BakeRequest req;
req.instanceGuid = "abc";
req.rootNote = 60;
const std::string good = encodeBakeRequest(req);
CHECK(!decodeBakeRequest("").has_value());
CHECK(!decodeBakeRequest("rsbakereq0" + good.substr(10)).has_value()); // wrong tag
CHECK(!decodeBakeRequest(good.substr(0, good.size() - 3)).has_value()); // truncated
CHECK(!decodeBakeRequest(good + "junk").has_value()); // trailing
// The two records share a key; each must refuse the other's bytes outright.
CHECK(!decodeBakeOutcome(good).has_value());
CHECK(!decodeBakeRequest(encodeBakeOutcome(BakeOutcome{})).has_value());
}
// --- A status integer this build does not know reads as a FAILURE ------------------
{
// Hand-built with a future status value; every other field is well-formed, so only
// the vocabulary gap is under test.
BakeOutcome out;
out.status = BakeStatus::Ok;
out.generation = 7;
std::string wire = encodeBakeOutcome(out);
// The status field is the first after the tag: "<len>':'<digits>".
const std::string okField = "1:0";
const std::size_t at = wire.find(okField);
CHECK(at != std::string::npos);
wire.replace(at, okField.size(), "2:99");
const auto decoded = decodeBakeOutcome(wire);
CHECK(decoded.has_value());
CHECK(decoded->status == BakeStatus::Failed); // never Ok
CHECK(decoded->generation == 7);
}
// --- The lookup name carries the underscore the registration string does not -------
{
const std::string lookup = bakeActionLookupName();
CHECK(!lookup.empty());
CHECK(lookup[0] == '_');
CHECK(lookup.find(kBakeActionSuffix) != std::string::npos);
CHECK(lookup.find(kBakeActionSuffix) > 0u);
}
if (g_fail == 0) std::printf("bake_wire: all tests passed\n");
return g_fail ? 1 : 0;
}