164 lines
7.0 KiB
C++
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, LaneSplit::Stereo);
|
|
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, LaneSplit::Single);
|
|
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, LaneSplit::Stereo);
|
|
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, LaneSplit::Stereo);
|
|
CHECK(lanes.upper.height == 100);
|
|
CHECK(lanes.lower.height == 99);
|
|
CHECK(lanes.lower.bottom() == band.bottom());
|
|
}
|
|
|
|
static void testEmptyBandYieldsEmptyLanes() {
|
|
const WaveformLanes lanes = waveformLanes(Rect{}, LaneSplit::Stereo);
|
|
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;
|
|
}
|