3c2a7c45b2
Vendor Steinberg VST3 SDK (v3.7.9_build_61); add reasampler_vst.vst3 as a second, additive build artifact with pure editor-geometry + bridge-marshal helpers under CTest.
117 lines
4.2 KiB
C++
117 lines
4.2 KiB
C++
// Standalone tests for reasampler::vst::bridge_marshal — no VST3, no REAPER, no test
|
|
// framework. Same fast assert loop as the sibling pure tests: assert the REAPER
|
|
// bridge-read marshalling (GetProjExtState result decode + a small JSON string-field
|
|
// reader) directly, so the DAW-facing shell only has to invoke the API.
|
|
//
|
|
// Covers: decodeGetProjExtState hit/absent/zero-return/empty-buffer (the stale-buffer
|
|
// guard); extractJsonStringField present/absent/escapes/whitespace/value-vs-key
|
|
// disambiguation/non-string-value/malformed.
|
|
|
|
#include "../src/vst/bridge_marshal.h"
|
|
|
|
#include <cstdio>
|
|
|
|
using namespace reasampler::vst;
|
|
|
|
static int g_fail = 0;
|
|
#define CHECK(cond) do { if(!(cond)) { \
|
|
std::printf("FAIL line %d: %s\n", __LINE__, #cond); ++g_fail; } } while(0)
|
|
|
|
// --- decodeGetProjExtState ----------------------------------------------------
|
|
|
|
static void testDecodeHit() {
|
|
// REAPER reports a non-zero length and filled the buffer: that IS the value.
|
|
auto v = decodeGetProjExtState(5, "hello");
|
|
CHECK(v.has_value());
|
|
CHECK(v && *v == "hello");
|
|
}
|
|
|
|
static void testDecodeAbsentKey() {
|
|
// REAPER returns 0 for an absent key. Even if a caller passed a dirty buffer, the
|
|
// decoder must NOT surface it — the zero return means "no value".
|
|
auto v = decodeGetProjExtState(0, "stale-bytes-from-a-prior-read");
|
|
CHECK(!v.has_value());
|
|
}
|
|
|
|
static void testDecodeNegativeReturn() {
|
|
auto v = decodeGetProjExtState(-1, "whatever");
|
|
CHECK(!v.has_value());
|
|
}
|
|
|
|
static void testDecodeEmptyBuffer() {
|
|
// Positive return but empty buffer — treat as no value (defensive).
|
|
auto v = decodeGetProjExtState(3, "");
|
|
CHECK(!v.has_value());
|
|
}
|
|
|
|
// --- extractJsonStringField ---------------------------------------------------
|
|
|
|
static void testExtractPresent() {
|
|
const std::string json = R"({"guid":"ABC-123","name":"kick"})";
|
|
auto g = extractJsonStringField(json, "guid");
|
|
CHECK(g && *g == "ABC-123");
|
|
auto n = extractJsonStringField(json, "name");
|
|
CHECK(n && *n == "kick");
|
|
}
|
|
|
|
static void testExtractAbsent() {
|
|
const std::string json = R"({"guid":"ABC-123"})";
|
|
CHECK(!extractJsonStringField(json, "missing").has_value());
|
|
}
|
|
|
|
static void testExtractWhitespaceTolerant() {
|
|
const std::string json = "{ \"guid\" : \"X\" , \"n\":\"y\" }";
|
|
auto g = extractJsonStringField(json, "guid");
|
|
CHECK(g && *g == "X");
|
|
}
|
|
|
|
static void testExtractEscapes() {
|
|
// \" \\ \/ \n \t all decode.
|
|
const std::string json = R"({"path":"a\\b\/c\"d\ne"})";
|
|
auto p = extractJsonStringField(json, "path");
|
|
CHECK(p && *p == "a\\b/c\"d\ne");
|
|
}
|
|
|
|
static void testExtractValueContainingKeyText() {
|
|
// A VALUE that contains the key text must not be mistaken for the member. Here the
|
|
// first "guid" occurrence is inside another value; the real member comes later.
|
|
const std::string json = R"({"note":"the guid is here","guid":"REAL"})";
|
|
auto g = extractJsonStringField(json, "guid");
|
|
CHECK(g && *g == "REAL");
|
|
}
|
|
|
|
static void testExtractNonStringValue() {
|
|
// A numeric/object value is not a string — return nullopt rather than garbage.
|
|
const std::string json = R"({"count":42,"name":"ok"})";
|
|
CHECK(!extractJsonStringField(json, "count").has_value());
|
|
// The sibling string field still reads.
|
|
auto n = extractJsonStringField(json, "name");
|
|
CHECK(n && *n == "ok");
|
|
}
|
|
|
|
static void testExtractMalformed() {
|
|
CHECK(!extractJsonStringField(R"({"guid":"unterminated)", "guid").has_value());
|
|
CHECK(!extractJsonStringField(R"({"guid":)", "guid").has_value());
|
|
CHECK(!extractJsonStringField(R"({"guid")", "guid").has_value());
|
|
CHECK(!extractJsonStringField("", "guid").has_value());
|
|
// Dangling escape at end of string.
|
|
CHECK(!extractJsonStringField(R"({"guid":"abc\)", "guid").has_value());
|
|
}
|
|
|
|
int main() {
|
|
testDecodeHit();
|
|
testDecodeAbsentKey();
|
|
testDecodeNegativeReturn();
|
|
testDecodeEmptyBuffer();
|
|
testExtractPresent();
|
|
testExtractAbsent();
|
|
testExtractWhitespaceTolerant();
|
|
testExtractEscapes();
|
|
testExtractValueContainingKeyText();
|
|
testExtractNonStringValue();
|
|
testExtractMalformed();
|
|
|
|
if (g_fail == 0) std::printf("bridge_marshal: all tests passed\n");
|
|
return g_fail != 0;
|
|
}
|