cb6b63cc88
REAPER may not expose the parent project pointer during plugin creation/setState, so the instrument would silently resolve no sample roots. Only that null-parent case now falls back to EnumProjects(-1); a resolved-but-unlisted or unsaved project still resolves nothing.
172 lines
5.7 KiB
C++
172 lines
5.7 KiB
C++
// Standalone tests for reasampler::instrument::map::sample_roots — no VST3, no REAPER, no
|
|
// test framework. The project identities are addresses of local objects standing in for
|
|
// ReaProject*; paths are lowercase forward-slash so normalizeSlashes is the identity on
|
|
// every platform.
|
|
|
|
#include "../src/core/instrument/map/sample_roots.h"
|
|
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <map>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
using namespace reasampler::instrument::map;
|
|
|
|
static int g_fail = 0;
|
|
#define CHECK(cond) do { if(!(cond)) { \
|
|
std::printf("FAIL line %d: %s\n", __LINE__, #cond); ++g_fail; } } while(0)
|
|
|
|
namespace {
|
|
|
|
int projA = 0, projB = 0, projC = 0, stranger = 0;
|
|
|
|
// Tab 0 (projA) plays the focused tab — the one the old EnumProjects(-1) lookup answered.
|
|
std::vector<ProjectTab> threeTabs() {
|
|
return {
|
|
{&projA, "c:/projects/a/song_a.rpp"},
|
|
{&projB, "c:/projects/b/song_b.rpp"},
|
|
{&projC, ""}, // never saved
|
|
};
|
|
}
|
|
|
|
std::vector<std::uint8_t> bytesOf(const std::string& s) {
|
|
return std::vector<std::uint8_t>(s.begin(), s.end());
|
|
}
|
|
|
|
} // namespace
|
|
|
|
// --- ownProjectDir ------------------------------------------------------------
|
|
|
|
static void testBackgroundInstanceResolvesItsOwnProjectNotTheFirstTab() {
|
|
CHECK(ownProjectDir(&projB, threeTabs()) == "c:/projects/b");
|
|
}
|
|
|
|
static void testEachOfTwoProjectsResolvesItsOwnDirectory() {
|
|
const auto tabs = threeTabs();
|
|
CHECK(ownProjectDir(&projA, tabs) == "c:/projects/a");
|
|
CHECK(ownProjectDir(&projB, tabs) == "c:/projects/b");
|
|
}
|
|
|
|
static void testNullIdentityResolvesNothing() {
|
|
CHECK(ownProjectDir(nullptr, threeTabs()).empty());
|
|
}
|
|
|
|
static void testUnlistedProjectResolvesNothingRatherThanAnotherTab() {
|
|
CHECK(ownProjectDir(&stranger, threeTabs()).empty());
|
|
}
|
|
|
|
static void testUnsavedOwnProjectResolvesNothingEvenBesideSavedTabs() {
|
|
CHECK(ownProjectDir(&projC, threeTabs()).empty());
|
|
}
|
|
|
|
static void testNoOpenProjectsResolvesNothing() {
|
|
CHECK(ownProjectDir(&projA, {}).empty());
|
|
}
|
|
|
|
static void testNullOwnFallsBackToTheActiveTab() {
|
|
CHECK(ownProjectDir(nullptr, threeTabs(), &projB) == "c:/projects/b");
|
|
}
|
|
|
|
static void testNullOwnAndNullFallbackResolvesNothing() {
|
|
CHECK(ownProjectDir(nullptr, threeTabs(), nullptr).empty());
|
|
}
|
|
|
|
static void testNonNullOwnIgnoresTheFallback() {
|
|
CHECK(ownProjectDir(&stranger, threeTabs(), &projB).empty());
|
|
}
|
|
|
|
// --- sampleRootCandidates -----------------------------------------------------
|
|
|
|
static void testProjectDirIsTheOnlyCandidate() {
|
|
const auto roots = sampleRootCandidates("c:/projects/b");
|
|
CHECK(roots.size() == 1);
|
|
CHECK(!roots.empty() && roots[0] == "c:/projects/b");
|
|
}
|
|
|
|
static void testNoProjectDirMeansNoCandidates() {
|
|
CHECK(sampleRootCandidates("").empty());
|
|
}
|
|
|
|
// --- readFromFirstRoot --------------------------------------------------------
|
|
|
|
static void testReadsUnderTheFirstRootThatHasTheFile() {
|
|
const std::map<std::string, std::string> disk = {
|
|
{"c:/second/reasampler_bank/x.wav", "SECOND"},
|
|
};
|
|
std::vector<std::string> asked;
|
|
const auto bytes = readFromFirstRoot(
|
|
{"c:/first", "c:/second"}, "reasampler_bank/x.wav", [&](const std::string& p) {
|
|
asked.push_back(p);
|
|
const auto it = disk.find(p);
|
|
return it == disk.end() ? std::vector<std::uint8_t>{} : bytesOf(it->second);
|
|
});
|
|
CHECK(bytes == bytesOf("SECOND"));
|
|
CHECK(asked.size() == 2);
|
|
CHECK(asked.size() == 2 && asked[0] == "c:/first/reasampler_bank/x.wav");
|
|
}
|
|
|
|
static void testEarlierRootWinsWhenBothHaveTheFile() {
|
|
std::vector<std::string> asked;
|
|
const auto bytes = readFromFirstRoot(
|
|
{"c:/first", "c:/second"}, "reasampler_bank/x.wav", [&](const std::string& p) {
|
|
asked.push_back(p);
|
|
return bytesOf(p);
|
|
});
|
|
CHECK(bytes == bytesOf("c:/first/reasampler_bank/x.wav"));
|
|
CHECK(asked.size() == 1);
|
|
}
|
|
|
|
static void testNoRootsReadsNothing() {
|
|
int calls = 0;
|
|
const auto bytes = readFromFirstRoot({}, "reasampler_bank/x.wav",
|
|
[&](const std::string&) {
|
|
++calls;
|
|
return bytesOf("never");
|
|
});
|
|
CHECK(bytes.empty());
|
|
CHECK(calls == 0);
|
|
}
|
|
|
|
static void testEmptyRelativePathReadsNothing() {
|
|
int calls = 0;
|
|
const auto bytes = readFromFirstRoot({"c:/first"}, "", [&](const std::string&) {
|
|
++calls;
|
|
return bytesOf("never");
|
|
});
|
|
CHECK(bytes.empty());
|
|
CHECK(calls == 0);
|
|
}
|
|
|
|
static void testNoRootHoldingTheFileYieldsEmpty() {
|
|
const auto bytes = readFromFirstRoot({"c:/first", "c:/second"}, "reasampler_bank/x.wav",
|
|
[](const std::string&) {
|
|
return std::vector<std::uint8_t>{};
|
|
});
|
|
CHECK(bytes.empty());
|
|
}
|
|
|
|
int main() {
|
|
testBackgroundInstanceResolvesItsOwnProjectNotTheFirstTab();
|
|
testEachOfTwoProjectsResolvesItsOwnDirectory();
|
|
testNullIdentityResolvesNothing();
|
|
testUnlistedProjectResolvesNothingRatherThanAnotherTab();
|
|
testUnsavedOwnProjectResolvesNothingEvenBesideSavedTabs();
|
|
testNoOpenProjectsResolvesNothing();
|
|
testNullOwnFallsBackToTheActiveTab();
|
|
testNullOwnAndNullFallbackResolvesNothing();
|
|
testNonNullOwnIgnoresTheFallback();
|
|
|
|
testProjectDirIsTheOnlyCandidate();
|
|
testNoProjectDirMeansNoCandidates();
|
|
|
|
testReadsUnderTheFirstRootThatHasTheFile();
|
|
testEarlierRootWinsWhenBothHaveTheFile();
|
|
testNoRootsReadsNothing();
|
|
testEmptyRelativePathReadsNothing();
|
|
testNoRootHoldingTheFileYieldsEmpty();
|
|
|
|
if (g_fail == 0) std::printf("sample_roots: all tests passed\n");
|
|
return g_fail != 0;
|
|
}
|