Re-derive the floor-size test fixtures from the constants and move the ceiling to sample_bands.h
This commit is contained in:
@@ -8,7 +8,8 @@
|
||||
// octave boundaries and the 0..127 extremes; keyRect tiling and black-over-white overlap;
|
||||
// keyAtPoint resolving black-over-white by zone and missing off-band; the root affordance's
|
||||
// hit-to-marker round trip; resolveDragNote clamping a wandering pointer; noteName under the
|
||||
// C4 (MIDI 60) DAW convention; and the gutter pinned at the shipped default window size.
|
||||
// C4 (MIDI 60) DAW convention; the gutter at the sawtooth's maximum residue; and the gutter
|
||||
// pinned at the shipped default window size (derived from kEditorMinWidth/kEditorMinHeight).
|
||||
//
|
||||
// Client-pixel-only guarantee: every width swept below is a CLIENT-pixel width. Nothing in
|
||||
// the instrument implements IPlugViewContentScaleSupport, so if a host scales the plugin
|
||||
@@ -280,28 +281,18 @@ static void testNoteNamesFollowTheC4Convention() {
|
||||
CHECK(noteName(500) == "G9");
|
||||
}
|
||||
|
||||
// --- the gutter at the shipped default window size -----------------------------
|
||||
// --- the gutter at the sawtooth's maximum residue -------------------------------
|
||||
|
||||
// The rule-based sweep above pins `margins == w % 75` and `leftMargin == margins/2` at every
|
||||
// width, but pins no concrete number — Daniel is making a visual call on the specific gutter
|
||||
// at the shipped default, and neither kPad nor the 840 default is covered by another test
|
||||
// firing if either ever changes. The strip is a sawtooth with period kStripWhiteKeyCount (75)
|
||||
// px of window width, and the shipped 840 default lands on residue 74 — the cycle's maximum:
|
||||
// one pixel of resize (840->841) collapses both gutters to zero and grows every white key
|
||||
// from 10px to 11px.
|
||||
static void testGutterAtTheShippedDefaultWindowSize() {
|
||||
constexpr int kShippedDefaultWindowW = 840; // editor_session.cpp's ViewRect default
|
||||
constexpr int kShippedDefaultWindowH = 620; // editor_session.cpp's ViewRect default
|
||||
// Derive rootStrip's width the same way the shell does, through the real allocator +
|
||||
// chrome layout, rather than re-deriving the inset formula — so a change to either one
|
||||
// fails this test instead of silently moving the shipped gutter out from under it.
|
||||
const SampleBands bands =
|
||||
computeSampleBands(kShippedDefaultWindowW, kShippedDefaultWindowH, 0);
|
||||
const ChromeRects chrome = chromeRects(bands.chrome, /*knobSize=*/24);
|
||||
const int stripW = chrome.rootStrip.width;
|
||||
CHECK(stripW == 824);
|
||||
|
||||
const StripLayout L = layoutStrip(stripW, 30);
|
||||
// width, but pins no concrete number. The strip is a sawtooth with period kStripWhiteKeyCount
|
||||
// (75) px of window width; 840 is an arbitrary but independently useful sample because it
|
||||
// lands on residue 74 — the cycle's maximum: one pixel of resize (840->841) collapses both
|
||||
// gutters to zero and grows every white key from 10px to 11px. Kept as a synthetic worst-case
|
||||
// sample; NOT tied to any shipped window size (see testGutterAtTheShippedDefaultWindowSize
|
||||
// below for that).
|
||||
static void testGutterAtTheSawtoothMaximumResidueWidth() {
|
||||
constexpr int kSawtoothMaxResidueStripW = 824; // an arbitrary width landing on residue 74
|
||||
const StripLayout L = layoutStrip(kSawtoothMaxResidueStripW, 30);
|
||||
CHECK(L.whiteWidth == 10);
|
||||
const int margins = L.band.width - L.keys.width;
|
||||
CHECK(margins == 74);
|
||||
@@ -309,6 +300,31 @@ static void testGutterAtTheShippedDefaultWindowSize() {
|
||||
CHECK(leftMargin == 37);
|
||||
}
|
||||
|
||||
// --- the gutter at the shipped default window size -----------------------------
|
||||
|
||||
// Daniel is making a visual call on the specific gutter at the shipped default; neither kPad
|
||||
// nor the floor is covered by another test firing if either ever changes. Derived from
|
||||
// kEditorMinWidth/kEditorMinHeight (editor_session.cpp's ViewRect default IS the floor) rather
|
||||
// than a hardcoded window size, so a floor change fails HERE instead of silently moving the
|
||||
// shipped gutter out from under it. The numbers below are today's floor (1190x680); re-derive
|
||||
// them by hand if the floor ever moves.
|
||||
static void testGutterAtTheShippedDefaultWindowSize() {
|
||||
// Derive rootStrip's width the same way the shell does, through the real allocator +
|
||||
// chrome layout, rather than re-deriving the inset formula.
|
||||
const SampleBands bands = computeSampleBands(kEditorMinWidth, kEditorMinHeight, 0);
|
||||
const ChromeRects chrome = chromeRects(bands.chrome, /*knobSize=*/24);
|
||||
const int stripW = chrome.rootStrip.width;
|
||||
CHECK(stripW == kEditorMinWidth - 2 * kPad);
|
||||
CHECK(stripW == 1174);
|
||||
|
||||
const StripLayout L = layoutStrip(stripW, 30);
|
||||
CHECK(L.whiteWidth == 15);
|
||||
const int margins = L.band.width - L.keys.width;
|
||||
CHECK(margins == 49);
|
||||
const int leftMargin = L.keys.x - L.band.x;
|
||||
CHECK(leftMargin == 24);
|
||||
}
|
||||
|
||||
int main() {
|
||||
testLayoutFillsTheBandAndCentresTheKeys();
|
||||
testDegenerateSizesYieldNoKeys();
|
||||
@@ -325,6 +341,7 @@ int main() {
|
||||
testHitTestingAKeyMarksThatSameKey();
|
||||
testDragTracksThePointerAndClampsWhenItWanders();
|
||||
testNoteNamesFollowTheC4Convention();
|
||||
testGutterAtTheSawtoothMaximumResidueWidth();
|
||||
testGutterAtTheShippedDefaultWindowSize();
|
||||
|
||||
if (g_fail == 0) {
|
||||
|
||||
@@ -5,8 +5,10 @@
|
||||
// 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).
|
||||
// bottom anchor and its exact requested height; the same stack/anchor/degrade properties
|
||||
// re-anchored AT the allocator's own kEditorMinWidth/kEditorMinHeight floor rather than only
|
||||
// below it; 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"
|
||||
|
||||
@@ -104,6 +106,56 @@ static void testDegenerateWindowYieldsNoInvertedRects() {
|
||||
CHECK(tiny.decks.right() >= tiny.decks.x);
|
||||
}
|
||||
|
||||
// --- the allocator at its own floor (kEditorMinWidth x kEditorMinHeight) -------
|
||||
|
||||
// The allocator's own client-area floor is a fact IT owns (kEditorMinWidth/kEditorMinHeight
|
||||
// above); the fixtures above validate the general shape entirely below that floor (840x620,
|
||||
// 840x160). These anchor the same properties AT the floor itself, so a floor move that broke
|
||||
// the stack there would have nothing else in this file to catch it.
|
||||
|
||||
static void testBandsStackWithoutOverlapAtTheEditorFloor() {
|
||||
const SampleBands b = computeSampleBands(kEditorMinWidth, kEditorMinHeight, 120);
|
||||
CHECK(b.chrome.y == 0);
|
||||
CHECK(b.chrome.width == kEditorMinWidth);
|
||||
CHECK(b.chrome.height == kTitleHeight + kChromeRowHeight);
|
||||
CHECK(b.waveform.y >= b.chrome.bottom());
|
||||
CHECK(b.decks.y >= b.waveform.bottom());
|
||||
CHECK(b.waveform.x == kPad && b.waveform.right() == kEditorMinWidth - kPad);
|
||||
CHECK(b.decks.x == kPad && b.decks.right() == kEditorMinWidth - kPad);
|
||||
}
|
||||
|
||||
static void testDeckBandIsBottomAnchoredAtTheEditorFloor() {
|
||||
constexpr int deckH = 120;
|
||||
const SampleBands b = computeSampleBands(kEditorMinWidth, kEditorMinHeight, deckH);
|
||||
CHECK(b.decks.height == deckH);
|
||||
CHECK(b.decks.bottom() == kEditorMinHeight - kPad);
|
||||
}
|
||||
|
||||
// At a representative two-row deck height (216px — the ceiling test_deck_groups.cpp bounds
|
||||
// the wrapped deck to), the waveform gets exactly what the floor's own height leaves it: an
|
||||
// equality, not a bound, so a floor-height change that quietly ate into the waveform's slack
|
||||
// would fail here rather than only widen/narrow a `>=`.
|
||||
static void testWaveformGetsExactlyTheFloorsRemainingHeightAtATwoRowDeck() {
|
||||
constexpr int twoRowDeckH = 216;
|
||||
const SampleBands b = computeSampleBands(kEditorMinWidth, kEditorMinHeight, twoRowDeckH);
|
||||
const int expected = kEditorMinHeight - kPad - twoRowDeckH - 2 * kBandGap -
|
||||
(kTitleHeight + kChromeRowHeight);
|
||||
CHECK(b.waveform.height == expected);
|
||||
CHECK(b.waveform.height == 358);
|
||||
CHECK(b.waveform.height >= kWaveformMinHeight);
|
||||
}
|
||||
|
||||
// The floor is not immune to the degrade path: a deck grown too tall for the floor's OWN
|
||||
// height still hits the floor-wins rule instead of squeezing the waveform below its usable
|
||||
// minimum — the sub-floor fixtures above cover the general rule; this is the same rule
|
||||
// exercised at the allocator's own minimum width.
|
||||
static void testAnOversizedDeckAtTheFloorStillDegradesGracefully() {
|
||||
const SampleBands b = computeSampleBands(kEditorMinWidth, kEditorMinHeight, 500);
|
||||
CHECK(b.waveform.height == kWaveformMinHeight);
|
||||
CHECK(b.decks.y >= b.waveform.bottom());
|
||||
CHECK(b.decks.bottom() > kEditorMinHeight); // clipped below the floor's own window
|
||||
}
|
||||
|
||||
// --- the waveform band's lanes ------------------------------------------------
|
||||
|
||||
static void testMonoUsesOneFullBandLane() {
|
||||
@@ -149,6 +201,10 @@ int main() {
|
||||
testWaveformNeverShrinksBelowTheTwoLaneFloor();
|
||||
testTwoLaneFloorHoldsTwoUsableLanes();
|
||||
testDegenerateWindowYieldsNoInvertedRects();
|
||||
testBandsStackWithoutOverlapAtTheEditorFloor();
|
||||
testDeckBandIsBottomAnchoredAtTheEditorFloor();
|
||||
testWaveformGetsExactlyTheFloorsRemainingHeightAtATwoRowDeck();
|
||||
testAnOversizedDeckAtTheFloorStillDegradesGracefully();
|
||||
testMonoUsesOneFullBandLane();
|
||||
testStereoSplitsIntoTwoLanesWithTheSeamGap();
|
||||
testStereoOddRemainderGoesToTheUpperLane();
|
||||
|
||||
Reference in New Issue
Block a user