7151e19432
Reverse S4 auto-select (empty=silence+empty state), add peak-thumbnail capture browser + bank filter + keyboard-strip drag machine, v3 component state (selection + zones), and the S-NAME-1 filename/display rename (UID locked). MSVC min/max macro collisions fixed post-implementation; 26/26 tests green.
204 lines
8.1 KiB
C++
204 lines
8.1 KiB
C++
// Standalone tests for reasampler::vst::capture_browser — no VST3, no REAPER, no framework.
|
|
// Same fast assert loop as the sibling pure tests (embed_strip / editor_geometry): assert
|
|
// the capture-first browser's card-grid + bank-filter-tab layout and hit-testing directly.
|
|
//
|
|
// Covers: layoutBrowser splitting an area into the tab strip + card grid and deriving the
|
|
// column count; a tiny/zero area (no inversion, columns >= 1); cardCellRect / cardContentRect
|
|
// / cardThumbnailRect / cardLabelRect tiling row-major across columns with the gutter inset
|
|
// and the thumbnail band above the label; cardHitTest landing on the card content (and MISSING
|
|
// in the inter-card gutter, past the last card, and on the tab strip); filterTabRect dividing
|
|
// the strip into equal segments with the last tab absorbing the remainder; filterTabHitTest
|
|
// hitting each tab and missing off-strip.
|
|
|
|
#include "../src/vst/capture_browser.h"
|
|
|
|
#include <cstdio>
|
|
|
|
using namespace reasampler::vst;
|
|
|
|
static int g_fail = 0;
|
|
#define CHECK(cond) do { if(!(cond)) { \
|
|
std::printf("FAIL line %d: %s\n", __LINE__, #cond); ++g_fail; } } while(0)
|
|
|
|
// --- layoutBrowser ------------------------------------------------------------
|
|
|
|
static void testLayoutNormalArea() {
|
|
// Wide enough for several columns of the fixed-width card.
|
|
const BrowserLayout L = layoutBrowser(560, 300);
|
|
CHECK(L.tabStrip.left == 0 && L.tabStrip.top == 0 && L.tabStrip.right == 560);
|
|
CHECK(L.tabStrip.height() == kBrowserTabHeight);
|
|
// The grid starts right below the tab strip and fills the rest, contiguous.
|
|
CHECK(L.grid.top == L.tabStrip.bottom);
|
|
CHECK(L.grid.bottom == 300 && L.grid.right == 560);
|
|
// columns = grid.width() / cardWidth (>= 1).
|
|
CHECK(L.columns == 560 / kBrowserCardWidth);
|
|
CHECK(L.columns >= 1);
|
|
}
|
|
|
|
static void testLayoutNarrowAreaSingleColumn() {
|
|
// Narrower than one card: still a single column, no inversion.
|
|
const BrowserLayout L = layoutBrowser(kBrowserCardWidth - 10, 200);
|
|
CHECK(L.columns == 1);
|
|
CHECK(L.grid.width() >= 0);
|
|
CHECK(L.tabStrip.height() == kBrowserTabHeight);
|
|
}
|
|
|
|
static void testLayoutZeroArea() {
|
|
const BrowserLayout L = layoutBrowser(0, 0);
|
|
CHECK(L.tabStrip.width() == 0 && L.tabStrip.height() == 0);
|
|
CHECK(L.grid.width() == 0);
|
|
CHECK(L.columns == 1); // never zero (avoids a divide-by-zero in card layout)
|
|
}
|
|
|
|
static void testLayoutTinyHeightClampsTabStrip() {
|
|
// A height below the tab band: the tab strip clamps to the area, the grid is empty.
|
|
const BrowserLayout L = layoutBrowser(560, kBrowserTabHeight - 6);
|
|
CHECK(L.tabStrip.height() == kBrowserTabHeight - 6);
|
|
CHECK(L.grid.height() <= 0); // no room left for cards
|
|
}
|
|
|
|
// --- card rects ---------------------------------------------------------------
|
|
|
|
static void testCardCellsTileRowMajor() {
|
|
const BrowserLayout L = layoutBrowser(560, 300);
|
|
const int cols = L.columns;
|
|
// Card 0 is top-left of the grid.
|
|
const Rect c0 = cardCellRect(L, 0);
|
|
CHECK(c0.left == L.grid.left && c0.top == L.grid.top);
|
|
CHECK(c0.width() == kBrowserCardWidth && c0.height() == kBrowserCardHeight);
|
|
// Card 1 is one card-width to the right, same row.
|
|
const Rect c1 = cardCellRect(L, 1);
|
|
CHECK(c1.left == L.grid.left + kBrowserCardWidth);
|
|
CHECK(c1.top == c0.top);
|
|
// The first card of the SECOND row wraps back to the left, one card-height down.
|
|
const Rect wrap = cardCellRect(L, cols);
|
|
CHECK(wrap.left == L.grid.left);
|
|
CHECK(wrap.top == L.grid.top + kBrowserCardHeight);
|
|
}
|
|
|
|
static void testCardCellNegativeIndex() {
|
|
const BrowserLayout L = layoutBrowser(560, 300);
|
|
const Rect r = cardCellRect(L, -1);
|
|
CHECK(r.left == 0 && r.top == 0 && r.right == 0 && r.bottom == 0);
|
|
}
|
|
|
|
static void testCardContentInsetByGutter() {
|
|
const BrowserLayout L = layoutBrowser(560, 300);
|
|
const Rect cell = cardCellRect(L, 0);
|
|
const Rect content = cardContentRect(L, 0);
|
|
CHECK(content.left == cell.left + kBrowserCardGutter);
|
|
CHECK(content.top == cell.top + kBrowserCardGutter);
|
|
CHECK(content.right == cell.right - kBrowserCardGutter);
|
|
CHECK(content.bottom == cell.bottom - kBrowserCardGutter);
|
|
}
|
|
|
|
static void testThumbnailAboveLabel() {
|
|
const BrowserLayout L = layoutBrowser(560, 300);
|
|
const Rect content = cardContentRect(L, 0);
|
|
const Rect thumb = cardThumbnailRect(L, 0);
|
|
const Rect label = cardLabelRect(L, 0);
|
|
// Thumbnail is the top band of the content; the label is the remainder below it, contiguous.
|
|
CHECK(thumb.left == content.left && thumb.right == content.right);
|
|
CHECK(thumb.top == content.top);
|
|
CHECK(thumb.height() == kBrowserThumbHeight);
|
|
CHECK(label.top == thumb.bottom);
|
|
CHECK(label.bottom == content.bottom);
|
|
CHECK(label.left == content.left && label.right == content.right);
|
|
}
|
|
|
|
// --- cardHitTest --------------------------------------------------------------
|
|
|
|
static void testCardHitCenterOfCard() {
|
|
const BrowserLayout L = layoutBrowser(560, 300);
|
|
const Rect content = cardContentRect(L, 3);
|
|
const int cx = content.left + content.width() / 2;
|
|
const int cy = content.top + content.height() / 2;
|
|
CHECK(cardHitTest(L, 12, cx, cy) == 3);
|
|
}
|
|
|
|
static void testCardHitMissesGutter() {
|
|
const BrowserLayout L = layoutBrowser(560, 300);
|
|
// A point in the gutter between the content and the cell edge (top-left corner of cell 0)
|
|
// is a miss — only the card CONTENT counts.
|
|
const Rect cell = cardCellRect(L, 0);
|
|
CHECK(cardHitTest(L, 12, cell.left, cell.top) == -1);
|
|
}
|
|
|
|
static void testCardHitMissesPastLastCard() {
|
|
const BrowserLayout L = layoutBrowser(560, 300);
|
|
// Only 2 cards exist; a point on where card 5 WOULD be is a miss.
|
|
const Rect content = cardContentRect(L, 5);
|
|
const int cx = content.left + content.width() / 2;
|
|
const int cy = content.top + content.height() / 2;
|
|
CHECK(cardHitTest(L, 2, cx, cy) == -1);
|
|
}
|
|
|
|
static void testCardHitMissesTabStrip() {
|
|
const BrowserLayout L = layoutBrowser(560, 300);
|
|
CHECK(cardHitTest(L, 12, 10, L.tabStrip.top + 2) == -1);
|
|
}
|
|
|
|
static void testCardHitZeroCards() {
|
|
const BrowserLayout L = layoutBrowser(560, 300);
|
|
CHECK(cardHitTest(L, 0, 20, 40) == -1);
|
|
}
|
|
|
|
// --- filter tabs --------------------------------------------------------------
|
|
|
|
static void testFilterTabsTileStrip() {
|
|
const BrowserLayout L = layoutBrowser(560, 300);
|
|
const int n = 4; // "All" + 3 banks
|
|
const Rect t0 = filterTabRect(L, n, 0);
|
|
const Rect tLast = filterTabRect(L, n, n - 1);
|
|
CHECK(t0.left == L.tabStrip.left);
|
|
// Adjacent tabs share an exact edge (no gap).
|
|
CHECK(filterTabRect(L, n, 0).right == filterTabRect(L, n, 1).left);
|
|
CHECK(filterTabRect(L, n, 1).right == filterTabRect(L, n, 2).left);
|
|
// The last tab reaches the strip's right edge exactly (absorbs the remainder).
|
|
CHECK(tLast.right == L.tabStrip.right);
|
|
// All tabs share the strip's height.
|
|
CHECK(t0.top == L.tabStrip.top && t0.bottom == L.tabStrip.bottom);
|
|
}
|
|
|
|
static void testFilterTabOutOfRange() {
|
|
const BrowserLayout L = layoutBrowser(560, 300);
|
|
CHECK(filterTabRect(L, 3, -1).width() == 0);
|
|
CHECK(filterTabRect(L, 3, 3).width() == 0);
|
|
CHECK(filterTabRect(L, 0, 0).width() == 0);
|
|
}
|
|
|
|
static void testFilterTabHit() {
|
|
const BrowserLayout L = layoutBrowser(560, 300);
|
|
const int n = 3;
|
|
for (int i = 0; i < n; ++i) {
|
|
const Rect t = filterTabRect(L, n, i);
|
|
const int cx = t.left + t.width() / 2;
|
|
const int cy = t.top + t.height() / 2;
|
|
CHECK(filterTabHitTest(L, n, cx, cy) == i);
|
|
}
|
|
// Below the strip (in the grid) -> no tab.
|
|
CHECK(filterTabHitTest(L, n, 20, L.grid.top + 4) == -1);
|
|
}
|
|
|
|
int main() {
|
|
testLayoutNormalArea();
|
|
testLayoutNarrowAreaSingleColumn();
|
|
testLayoutZeroArea();
|
|
testLayoutTinyHeightClampsTabStrip();
|
|
testCardCellsTileRowMajor();
|
|
testCardCellNegativeIndex();
|
|
testCardContentInsetByGutter();
|
|
testThumbnailAboveLabel();
|
|
testCardHitCenterOfCard();
|
|
testCardHitMissesGutter();
|
|
testCardHitMissesPastLastCard();
|
|
testCardHitMissesTabStrip();
|
|
testCardHitZeroCards();
|
|
testFilterTabsTileStrip();
|
|
testFilterTabOutOfRange();
|
|
testFilterTabHit();
|
|
|
|
if (g_fail == 0) std::printf("capture_browser: all tests passed\n");
|
|
return g_fail != 0;
|
|
}
|