// Standalone tests for reasampler::track_topology — no REAPER, no framework. // Covers the direct-child walk over a flat I_FOLDERDEPTH delta list: the set a // ranged item render must silence so a folder parent's children stay out of the // capture. #include "../src/core/capture/track_topology.h" #include #include using namespace reasampler::capture; 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 bool sameIndices(const std::vector& got, const std::vector& want) { return got == want; } static void testFlatProjectHasNoChildren() { // No track opens a folder, so no track has children — including the one asked // about. A flat project must produce an empty silence set, not a stray one. const std::vector depths{0, 0, 0}; CHECK(sameIndices(directChildIndices(depths, 0), {})); CHECK(sameIndices(directChildIndices(depths, 1), {})); } static void testFolderParentReturnsItsDirectChildren() { // 0: folder parent, 1: child, 2: last child (closes the folder), 3: unrelated. const std::vector depths{1, 0, -1, 0}; CHECK(sameIndices(directChildIndices(depths, 0), {1, 2})); // Track 3 sits outside the folder entirely and owns nothing. CHECK(sameIndices(directChildIndices(depths, 3), {})); } static void testGrandchildrenAreExcluded() { // 0: outer folder, 1: inner folder (a direct child), 2: grandchild closing the // inner folder, 3: second direct child closing the outer. The grandchild reaches // track 0 only through track 1, so silencing track 1's send covers it — listing // it too would be redundant, and the walk must not. const std::vector depths{1, 1, -1, -1}; CHECK(sameIndices(directChildIndices(depths, 0), {1, 3})); // Asked about the inner folder, the grandchild IS the direct child. CHECK(sameIndices(directChildIndices(depths, 1), {2})); } static void testMultiLevelCloseEndsTheOuterFolderToo() { // A -2 closes two folders at once (SDK: "last in the innermost and next-innermost // folders"), so track 3 is outside track 0's folder even though no track between // them closed it singly. const std::vector depths{1, 1, -2, 0}; CHECK(sameIndices(directChildIndices(depths, 0), {1})); CHECK(sameIndices(directChildIndices(depths, 1), {2})); } static void testNonFolderAndOutOfRangeReturnEmpty() { const std::vector depths{1, 0, -1}; CHECK(sameIndices(directChildIndices(depths, 1), {})); // a plain child CHECK(sameIndices(directChildIndices(depths, 2), {})); // the folder's last track CHECK(sameIndices(directChildIndices(depths, -1), {})); // no such track CHECK(sameIndices(directChildIndices(depths, 3), {})); // past the end CHECK(sameIndices(directChildIndices({}, 0), {})); // empty project } static void testUnterminatedFolderSwallowsTheRest() { // A folder that never closes owns every remaining track, which is how REAPER // reads the same list — the walk must not stop early and leave a child audible. const std::vector depths{1, 0, 0}; CHECK(sameIndices(directChildIndices(depths, 0), {1, 2})); } int main() { testFlatProjectHasNoChildren(); testFolderParentReturnsItsDirectChildren(); testGrandchildrenAreExcluded(); testMultiLevelCloseEndsTheOuterFolderToo(); testNonFolderAndOutOfRangeReturnEmpty(); testUnterminatedFolderSwallowsTheRest(); if (g_fail == 0) std::printf("track_topology: all tests passed\n"); return g_fail == 0 ? 0 : 1; }