// Standalone tests for reasampler::tooltip — no REAPER, no test framework. Asserts the custom // hover-delay tooltip's placement geometry and the action display-prefix strip helper. // // Covers (L5 refinement 2 pure module): prefix strip (present / absent / empty prefix / exact // match); placement BELOW the anchor centred; horizontal clamp at both client edges; the // bottom-edge flip to ABOVE; the both-clip clamp for a tall tooltip; degenerate inputs -> empty. #include "../src/tooltip.h" #include #include using namespace reasampler; static int g_fail = 0; #define CHECK(cond) do { if(!(cond)) { \ std::printf("FAIL line %d: %s\n", __LINE__, #cond); ++g_fail; } } while(0) // --- Prefix strip ------------------------------------------------------------ static void testStripPresent() { CHECK(stripActionPrefix("ReaSampler: capture selected track(s)", "ReaSampler: ") == "capture selected track(s)"); } static void testStripAbsent() { // No prefix present -> returned unchanged (defensive: a name from an unexpected source shows). CHECK(stripActionPrefix("capture selected track(s)", "ReaSampler: ") == "capture selected track(s)"); } static void testStripEmptyPrefix() { CHECK(stripActionPrefix("anything", "") == "anything"); } static void testStripExactMatchLeavesEmpty() { // Name equals the prefix exactly -> the remainder is empty. CHECK(stripActionPrefix("ReaSampler: ", "ReaSampler: ").empty()); } static void testStripBetaPrefix() { CHECK(stripActionPrefix("ReaSampler beta: show version", "ReaSampler beta: ") == "show version"); } // --- Placement: below, centred ----------------------------------------------- // Anchor button at (100, 10) size 108x34 in a 400x300 client. Text 80x14, spec defaults // (gap 4, padX 6, padY 3, margin 2). boxW = 80+12 = 92, boxH = 14+6 = 20. // Centre x = 100 + (108-92)/2 = 100 + 8 = 108. Below y = 10 + 34 + 4 = 48. static void testBelowCentred() { const TooltipBox tb = computeTooltip(100, 10, 108, 34, 80, 14, 400, 300, TooltipSpec{}); CHECK(!tb.empty()); CHECK((tb == TooltipBox{108, 48, 92, 20})); } // --- Horizontal clamp -------------------------------------------------------- // A button near the RIGHT edge pushes the centred box past the client; it clamps to // clientW - margin - boxW. Client 400, boxW 92, margin 2 -> maxX = 400-2-92 = 306. static void testClampRight() { const TooltipBox tb = computeTooltip(360, 10, 108, 34, 80, 14, 400, 300, TooltipSpec{}); CHECK(!tb.empty()); CHECK(tb.x == 306); } // A button near the LEFT edge clamps x to the left margin (2). static void testClampLeft() { const TooltipBox tb = computeTooltip(0, 10, 20, 34, 80, 14, 400, 300, TooltipSpec{}); CHECK(!tb.empty()); CHECK(tb.x == 2); } // --- Vertical flip ----------------------------------------------------------- // A button near the BOTTOM edge: below would clip, so the box flips ABOVE the anchor. // Anchor at y=270 h=34 in a 300-tall client. Below y = 270+34+4 = 308, box bottom 308+20=328 > // 300-2 -> flip above: y = 270 - 4 - 20 = 246 (>= margin, so used). static void testFlipAbove() { const TooltipBox tb = computeTooltip(100, 270, 108, 34, 80, 14, 400, 300, TooltipSpec{}); CHECK(!tb.empty()); CHECK(tb.y == 246); } // A tall tooltip in a short client fits neither below nor above cleanly -> clamped to the // bottom margin (never negative). Client 40 tall, box 20 tall, anchor filling it. static void testBothClipClampsBottom() { // anchor 0..30 in a 40-tall client, text tall enough that above < margin too. const TooltipBox tb = computeTooltip(100, 5, 108, 30, 80, 30, 400, 40, TooltipSpec{}); CHECK(!tb.empty()); // boxH = 36; below y = 5+30+4=39 clips; above = 5-4-36 = -35 < margin; clamp to maxY = // 40-2-36 = 2 (>= margin). CHECK(tb.y == 2); } // --- Narrow client: box width clamped ---------------------------------------- // When the client is narrower than the box's natural width, the box is shrunk to fit and // the result satisfies x >= margin AND x + width <= clientW - margin. // Natural boxW = 80+12 = 92. Narrow client = 60. maxBoxW = 60-4 = 56. // Clamped boxW = 56. x = 2 + (108-56)/2 ... centred but clamped to [2, 60-2-56] = [2, 2]. static void testNarrowClientBoxClamped() { const TooltipSpec spec{}; // margin = 2 const TooltipBox tb = computeTooltip(2, 10, 108, 34, 80, 14, 60, 300, spec); CHECK(!tb.empty()); CHECK(tb.x >= spec.margin); CHECK(tb.x + tb.width <= 60 - spec.margin); } // --- Degenerate -------------------------------------------------------------- static void testDegenerateEmpty() { CHECK(computeTooltip(0, 0, 100, 30, 0, 14, 400, 300, TooltipSpec{}).empty()); // no text width CHECK(computeTooltip(0, 0, 100, 30, 80, 0, 400, 300, TooltipSpec{}).empty()); // no text height CHECK(computeTooltip(0, 0, 100, 30, 80, 14, 0, 300, TooltipSpec{}).empty()); // no client width CHECK(computeTooltip(0, 0, 100, 30, 80, 14, 400, 0, TooltipSpec{}).empty()); // no client height } int main() { testStripPresent(); testStripAbsent(); testStripEmptyPrefix(); testStripExactMatchLeavesEmpty(); testStripBetaPrefix(); testBelowCentred(); testClampRight(); testClampLeft(); testFlipAbove(); testBothClipClampsBottom(); testNarrowClientBoxClamped(); testDegenerateEmpty(); if (g_fail == 0) std::printf("tooltip: all tests passed\n"); else std::printf("tooltip: %d CHECK(s) FAILED\n", g_fail); return g_fail == 0 ? 0 : 1; }