Files
reasampler/tests/test_view_tree.cpp
T

121 lines
4.6 KiB
C++

// Standalone tests for reasampler::buildFolderTree — no REAPER, no framework.
// The D2 view shell is DAW-bound and only verifiable in REAPER; this covers the
// one genuinely pure piece: the I_FOLDERDEPTH walk that turns REAPER's linear
// track stream into the parent<->child FolderTree the pure model consumes.
#include "../src/core/view/view_tree.h"
#include <cstdio>
#include <string>
using namespace reasampler;
using namespace reasampler::view;
static int g_fail = 0;
#define CHECK(cond) do { if(!(cond)) { \
std::printf("FAIL line %d: %s\n", __LINE__, #cond); ++g_fail; } } while(0)
// Find a node by guid; returns nullptr if absent.
static const FolderNode* nodeOf(const FolderTree& t, const std::string& guid) {
for (const auto& n : t.nodes)
if (n.guid == guid) return &n;
return nullptr;
}
// All top-level leaves: three depth-0 tracks, no folders. Every parentGuid empty,
// nothing is a parent, order preserved.
static void testFlatLeaves() {
FolderTree t = buildFolderTree({{"a", 0}, {"b", 0}, {"c", 0}});
CHECK(t.nodes.size() == 3);
CHECK(t.nodes[0].guid == "a" && t.nodes[1].guid == "b" && t.nodes[2].guid == "c");
for (const auto& n : t.nodes) {
CHECK(n.parentGuid.empty());
CHECK(!n.isParent);
}
}
// One folder: parent P (depth 1) contains child C, which closes the folder (-1).
// P is a parent and is itself top-level; C's parent is P.
static void testSingleFolder() {
FolderTree t = buildFolderTree({{"P", 1}, {"C", -1}});
const FolderNode* p = nodeOf(t, "P");
const FolderNode* c = nodeOf(t, "C");
CHECK(p && c);
CHECK(p->isParent);
CHECK(p->parentGuid.empty()); // the folder parent is itself top-level
CHECK(!c->isParent);
CHECK(c->parentGuid == "P"); // child sits under the folder
}
// Folder with two children; a following top-level leaf must land back at the root,
// proving the close (-1) popped the folder off the stack.
static void testFolderThenSibling() {
FolderTree t = buildFolderTree({{"P", 1}, {"C1", 0}, {"C2", -1}, {"S", 0}});
CHECK(nodeOf(t, "C1")->parentGuid == "P");
CHECK(nodeOf(t, "C2")->parentGuid == "P");
CHECK(nodeOf(t, "S")->parentGuid.empty()); // popped back to root
}
// Nested folders: P > Q > leaf. The inner leaf closes BOTH folders at once (-2).
// A sibling after it returns to the root.
static void testNestedDeepClose() {
FolderTree t = buildFolderTree({{"P", 1}, {"Q", 1}, {"L", -2}, {"S", 0}});
CHECK(nodeOf(t, "P")->isParent && nodeOf(t, "P")->parentGuid.empty());
CHECK(nodeOf(t, "Q")->isParent && nodeOf(t, "Q")->parentGuid == "P");
CHECK(nodeOf(t, "L")->parentGuid == "Q"); // deepest leaf under Q
CHECK(!nodeOf(t, "L")->isParent);
CHECK(nodeOf(t, "S")->parentGuid.empty()); // both levels popped
}
// Nested with a stepwise close: inner folder closes (-1), then a sibling at the
// OUTER level, then that folder closes (-1). Proves partial pops track correctly.
static void testNestedStepwiseClose() {
FolderTree t = buildFolderTree(
{{"P", 1}, {"Q", 1}, {"L", -1}, {"M", -1}});
CHECK(nodeOf(t, "Q")->parentGuid == "P");
CHECK(nodeOf(t, "L")->parentGuid == "Q"); // L inside inner folder Q
CHECK(nodeOf(t, "M")->parentGuid == "P"); // after Q closed, M is under P
}
// Malformed stream: a close deeper than the open stack must clamp to empty, never
// underflow. A following leaf is still top-level and the walk stays total.
static void testMalformedCloseClamps() {
FolderTree t = buildFolderTree({{"P", 1}, {"C", -5}, {"S", 0}});
CHECK(nodeOf(t, "C")->parentGuid == "P");
CHECK(nodeOf(t, "S")->parentGuid.empty()); // clamped, not underflowed
CHECK(t.nodes.size() == 3);
}
// Empty input yields an empty tree (no fault).
static void testEmpty() {
FolderTree t = buildFolderTree({});
CHECK(t.nodes.empty());
}
// An empty folder (parent immediately closes itself, depth accounting P=1 then a
// child that both belongs to and closes it). Here P opens and the sole child
// closes; verifies a folder with exactly one leaf child.
static void testSingleChildFolder() {
FolderTree t = buildFolderTree({{"P", 1}, {"only", -1}});
CHECK(nodeOf(t, "only")->parentGuid == "P");
CHECK(nodeOf(t, "P")->isParent);
}
int main() {
testFlatLeaves();
testSingleFolder();
testFolderThenSibling();
testNestedDeepClose();
testNestedStepwiseClose();
testMalformedCloseClamps();
testEmpty();
testSingleChildFolder();
if (g_fail == 0) {
std::printf("view_tree: all tests passed\n");
return 0;
}
std::printf("view_tree: %d checks FAILED\n", g_fail);
return 1;
}