Resolve ReaSampler 9000 samples against the instance's own project, not the focused tab
sampleRoots matches getReaperParent(3) among EnumProjects' open projects; every instrument sample read goes through an ordered root list (one root today) so a later temp-bank root slots in after it.
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
// 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());
|
||||
}
|
||||
|
||||
// --- 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();
|
||||
|
||||
testProjectDirIsTheOnlyCandidate();
|
||||
testNoProjectDirMeansNoCandidates();
|
||||
|
||||
testReadsUnderTheFirstRootThatHasTheFile();
|
||||
testEarlierRootWinsWhenBothHaveTheFile();
|
||||
testNoRootsReadsNothing();
|
||||
testEmptyRelativePathReadsNothing();
|
||||
testNoRootHoldingTheFileYieldsEmpty();
|
||||
|
||||
if (g_fail == 0) std::printf("sample_roots: all tests passed\n");
|
||||
return g_fail != 0;
|
||||
}
|
||||
Reference in New Issue
Block a user