Files
reasampler/tests/test_sample_bands.cpp
T

164 lines
7.0 KiB
C++

// Standalone tests for reasampler::instrument::ui::sample_bands — no VST3, no REAPER, no
// test framework. Same fast assert loop as the sibling pure tests.
//
// Covers: the shared Rect vocabulary (contains() half-open + degenerate rects); the
// three-band vertical inventory (chrome over waveform over decks, no overlap, no
// inversion) asserted as pure geometry with no paint call; the waveform band's two-lane
// floor and the bands-clip-rather-than-squeeze rule on a short window; the deck band's
// bottom anchor and its exact requested height; and the lane split (mono = one full-band
// lane, stereo = two lanes with the seam gap between them).
#include "../src/core/instrument/ui/sample_bands.h"
#include <cstdio>
using namespace reasampler;
using namespace reasampler::instrument::ui;
static int g_fail = 0;
#define CHECK(cond) do { if(!(cond)) { \
std::printf("FAIL line %d: %s\n", __LINE__, #cond); ++g_fail; } } while(0)
// --- the shared Rect vocabulary ----------------------------------------------
static void testContainsHalfOpen() {
Rect r = Rect::ltrb(10, 20, 50, 40); // [10,50) x [20,40)
CHECK(contains(r, 10, 20)); // top-left inclusive
CHECK(contains(r, 49, 39)); // bottom-right exclusive edge, inside
CHECK(!contains(r, 50, 30)); // right edge excluded
CHECK(!contains(r, 30, 40)); // bottom edge excluded
CHECK(!contains(r, 9, 30)); // left of rect
CHECK(!contains(r, 30, 19)); // above rect
}
static void testContainsDegenerate() {
CHECK(!contains(Rect::ltrb(10, 10, 10, 20), 10, 15)); // zero width
CHECK(!contains(Rect::ltrb(10, 10, 20, 10), 15, 10)); // zero height
CHECK(!contains(Rect::ltrb(20, 10, 10, 20), 15, 15)); // inverted (right < left)
}
// --- the vertical inventory ---------------------------------------------------
static void testBandsStackTopToBottomWithoutOverlap() {
const SampleBands b = computeSampleBands(840, 620, 120);
CHECK(b.chrome.y == 0);
CHECK(b.chrome.height == kTitleHeight + kChromeRowHeight);
// Strictly ordered, no overlap: each band starts at or after the previous one's bottom.
CHECK(b.waveform.y >= b.chrome.bottom());
CHECK(b.decks.y >= b.waveform.bottom());
// No inversion anywhere.
CHECK(b.chrome.height > 0 && b.waveform.height > 0 && b.decks.height > 0);
CHECK(b.chrome.width > 0 && b.waveform.width > 0 && b.decks.width > 0);
}
static void testChromeSpansFullWidthAndLowerBandsAreInset() {
const SampleBands b = computeSampleBands(840, 620, 120);
CHECK(b.chrome.x == 0 && b.chrome.right() == 840);
CHECK(b.waveform.x == kPad && b.waveform.right() == 840 - kPad);
CHECK(b.decks.x == kPad && b.decks.right() == 840 - kPad);
}
static void testDeckBandIsBottomAnchoredAtItsRequestedHeight() {
const int deckH = 96;
const SampleBands b = computeSampleBands(840, 620, deckH);
CHECK(b.decks.height == deckH);
CHECK(b.decks.bottom() == 620 - kPad); // bottom-anchored inside the pad
}
static void testWaveformAbsorbsSlackAsTheWindowGrows() {
const SampleBands small = computeSampleBands(840, 620, 120);
const SampleBands big = computeSampleBands(840, 900, 120);
CHECK(big.waveform.height == small.waveform.height + 280);
// The fixed bands do not grow with the window.
CHECK(big.chrome.height == small.chrome.height);
CHECK(big.decks.height == small.decks.height);
}
static void testWaveformNeverShrinksBelowTheTwoLaneFloor() {
// A window far too short for chrome + two lanes + deck: the floor wins and the deck band
// is pushed past the bottom (clipped) rather than squeezing the waveform.
const SampleBands b = computeSampleBands(840, 160, 120);
CHECK(b.waveform.height == kWaveformMinHeight);
CHECK(b.decks.y >= b.waveform.bottom());
CHECK(b.decks.bottom() > 160); // deliberately clipped below the window
}
static void testTwoLaneFloorHoldsTwoUsableLanes() {
// The floor is exactly what two minimum lanes plus their seam need — not an arbitrary
// number, so a lane can never be allocated below its own minimum.
CHECK(kWaveformMinHeight == 2 * kLaneMinHeight + kLaneGap);
const SampleBands b = computeSampleBands(840, 160, 120);
const WaveformLanes lanes = waveformLanes(b.waveform, /*stereo=*/true);
CHECK(lanes.upper.height >= kLaneMinHeight);
CHECK(lanes.lower.height >= kLaneMinHeight);
}
static void testDegenerateWindowYieldsNoInvertedRects() {
const SampleBands z = computeSampleBands(0, 0, 0);
CHECK(z.chrome.width == 0 && z.chrome.height == 0);
CHECK(z.waveform.width <= 0 || z.waveform.height >= 0);
CHECK(z.waveform.right() >= z.waveform.x);
CHECK(z.decks.right() >= z.decks.x);
const SampleBands tiny = computeSampleBands(20, 20, 4);
CHECK(tiny.waveform.right() >= tiny.waveform.x);
CHECK(tiny.decks.right() >= tiny.decks.x);
}
// --- the waveform band's lanes ------------------------------------------------
static void testMonoUsesOneFullBandLane() {
const Rect band = Rect::ltrb(8, 100, 832, 300);
const WaveformLanes lanes = waveformLanes(band, /*stereo=*/false);
CHECK(lanes.upper == band);
CHECK(lanes.lower.empty()); // no redundant duplicate lane in mono
}
static void testStereoSplitsIntoTwoLanesWithTheSeamGap() {
const Rect band = Rect::ltrb(8, 100, 832, 300); // height 200
const WaveformLanes lanes = waveformLanes(band, /*stereo=*/true);
CHECK(lanes.upper.y == band.y);
CHECK(lanes.lower.bottom() == band.bottom());
// Full width each, seam exactly kLaneGap, no overlap.
CHECK(lanes.upper.x == band.x && lanes.upper.right() == band.right());
CHECK(lanes.lower.x == band.x && lanes.lower.right() == band.right());
CHECK(lanes.lower.y - lanes.upper.bottom() == kLaneGap);
CHECK(lanes.upper.height + lanes.lower.height + kLaneGap == band.height);
}
static void testStereoOddRemainderGoesToTheUpperLane() {
const Rect band = Rect::ltrb(0, 0, 100, 201); // usable 199 -> 100 / 99
const WaveformLanes lanes = waveformLanes(band, /*stereo=*/true);
CHECK(lanes.upper.height == 100);
CHECK(lanes.lower.height == 99);
CHECK(lanes.lower.bottom() == band.bottom());
}
static void testEmptyBandYieldsEmptyLanes() {
const WaveformLanes lanes = waveformLanes(Rect{}, /*stereo=*/true);
CHECK(lanes.upper.empty());
CHECK(lanes.lower.empty());
}
int main() {
testContainsHalfOpen();
testContainsDegenerate();
testBandsStackTopToBottomWithoutOverlap();
testChromeSpansFullWidthAndLowerBandsAreInset();
testDeckBandIsBottomAnchoredAtItsRequestedHeight();
testWaveformAbsorbsSlackAsTheWindowGrows();
testWaveformNeverShrinksBelowTheTwoLaneFloor();
testTwoLaneFloorHoldsTwoUsableLanes();
testDegenerateWindowYieldsNoInvertedRects();
testMonoUsesOneFullBandLane();
testStereoSplitsIntoTwoLanesWithTheSeamGap();
testStereoOddRemainderGoesToTheUpperLane();
testEmptyBandYieldsEmptyLanes();
if (g_fail == 0) {
std::printf("sample_bands: all tests passed\n");
return 0;
}
std::printf("sample_bands: %d failure(s)\n", g_fail);
return 1;
}