134 lines
4.7 KiB
C++
134 lines
4.7 KiB
C++
// Standalone tests for reasampler::card_meta — no REAPER, no test framework. Asserts the
|
|
// L7 decorative overlay formatters: bars.beats.subdivisions (F1 tempo+meter stamp) and
|
|
// seconds.milliseconds.
|
|
//
|
|
// Covers: bar-1 origin (zero length), sub-bar, exact bar boundary rollover, multi-bar,
|
|
// long capture, non-4/4 meters (3/4 and 6/8), unstamped meter -> blank, unknown tempo ->
|
|
// blank (s.ms still derivable); s.ms zero / sub-second / multi-second / ms carry / negative.
|
|
|
|
#include "../src/core/ui/card_meta.h"
|
|
|
|
#include <cstdio>
|
|
#include <string>
|
|
|
|
using namespace reasampler;
|
|
using namespace reasampler::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)
|
|
|
|
// Beat length in 4/4 at 120 BPM: (60/120)*(4/4) = 0.5 s/beat, so a 4/4 bar = 2.0 s.
|
|
|
|
// --- bars.beats.subdivisions -------------------------------------------------
|
|
|
|
static void testZeroLengthIsBarOneOrigin() {
|
|
// Zero length -> the musical origin, "1.1.00".
|
|
CHECK(formatBarsBeats(MusicalLength{0.0, 120.0, 4, 4}) == "1.1.00");
|
|
}
|
|
|
|
static void testSubBeat() {
|
|
// 0.25 s at 120 BPM 4/4 = 0.5 beats -> bar 1, beat 1, .50.
|
|
CHECK(formatBarsBeats(MusicalLength{0.25, 120.0, 4, 4}) == "1.1.50");
|
|
}
|
|
|
|
static void testWholeBeatWithinBar() {
|
|
// 0.5 s = exactly 1 beat -> bar 1, beat 2, .00.
|
|
CHECK(formatBarsBeats(MusicalLength{0.5, 120.0, 4, 4}) == "1.2.00");
|
|
}
|
|
|
|
static void testExactBarBoundaryRollsOver() {
|
|
// 2.0 s = exactly 4 beats = 1 bar in 4/4 -> rolls to bar 2, beat 1 (NOT "1.5.00").
|
|
CHECK(formatBarsBeats(MusicalLength{2.0, 120.0, 4, 4}) == "2.1.00");
|
|
}
|
|
|
|
static void testMultiBar() {
|
|
// 5.0 s at 120 4/4 = 10 beats = 2 bars + 2 beats -> "3.3.00".
|
|
CHECK(formatBarsBeats(MusicalLength{5.0, 120.0, 4, 4}) == "3.3.00");
|
|
}
|
|
|
|
static void testLongCaptureNoBarCap() {
|
|
// 256 s at 120 4/4 = 512 beats = 128 bars exactly -> bar 129, beat 1.
|
|
CHECK(formatBarsBeats(MusicalLength{256.0, 120.0, 4, 4}) == "129.1.00");
|
|
}
|
|
|
|
static void testThreeFourMeter() {
|
|
// 3/4 at 120 BPM: beat = (60/120)*(4/4)=0.5 s, bar = 3 beats = 1.5 s. 1.5 s -> bar 2,1.
|
|
CHECK(formatBarsBeats(MusicalLength{1.5, 120.0, 3, 4}) == "2.1.00");
|
|
// 1.0 s = 2 beats -> bar 1, beat 3.
|
|
CHECK(formatBarsBeats(MusicalLength{1.0, 120.0, 3, 4}) == "1.3.00");
|
|
}
|
|
|
|
static void testSixEightMeter() {
|
|
// 6/8 at 120 BPM: an eighth-beat = (60/120)*(4/8) = 0.25 s; bar = 6 beats = 1.5 s.
|
|
// 1.5 s -> bar 2, beat 1.
|
|
CHECK(formatBarsBeats(MusicalLength{1.5, 120.0, 6, 8}) == "2.1.00");
|
|
// 0.25 s = exactly 1 eighth-beat -> bar 1, beat 2.
|
|
CHECK(formatBarsBeats(MusicalLength{0.25, 120.0, 6, 8}) == "1.2.00");
|
|
}
|
|
|
|
static void testUnstampedMeterIsBlank() {
|
|
// 0/0 (pre-L7 sample) -> no musical read-out.
|
|
CHECK(formatBarsBeats(MusicalLength{3.0, 120.0, 0, 0}).empty());
|
|
CHECK(formatBarsBeats(MusicalLength{3.0, 120.0, 4, 0}).empty()); // partial stamp also blank
|
|
CHECK(formatBarsBeats(MusicalLength{3.0, 120.0, 0, 4}).empty());
|
|
}
|
|
|
|
static void testUnknownTempoIsBlank() {
|
|
// Tempo 0 -> no musical read-out even with a meter (cannot derive beats).
|
|
CHECK(formatBarsBeats(MusicalLength{3.0, 0.0, 4, 4}).empty());
|
|
}
|
|
|
|
static void testNegativeLengthClampsToOrigin() {
|
|
// Defensive: a negative length reads as the origin, not garbage.
|
|
CHECK(formatBarsBeats(MusicalLength{-5.0, 120.0, 4, 4}) == "1.1.00");
|
|
}
|
|
|
|
// --- seconds.milliseconds ----------------------------------------------------
|
|
|
|
static void testSecondsMsZero() {
|
|
CHECK(formatSecondsMs(0.0) == "0.000");
|
|
}
|
|
|
|
static void testSecondsMsSubSecond() {
|
|
CHECK(formatSecondsMs(0.5) == "0.500");
|
|
}
|
|
|
|
static void testSecondsMsMultiSecond() {
|
|
CHECK(formatSecondsMs(1.5) == "1.500");
|
|
CHECK(formatSecondsMs(62.037) == "62.037");
|
|
}
|
|
|
|
static void testSecondsMsNegativeClamps() {
|
|
CHECK(formatSecondsMs(-1.0) == "0.000");
|
|
}
|
|
|
|
static void testSecondsMsNearWholeSecondCarry() {
|
|
// 0.9999 s: floor to ms could hit 999 or 1000; the carry keeps it well-formed.
|
|
const std::string r = formatSecondsMs(0.9999);
|
|
CHECK(r == "0.999" || r == "1.000");
|
|
}
|
|
|
|
int main() {
|
|
testZeroLengthIsBarOneOrigin();
|
|
testSubBeat();
|
|
testWholeBeatWithinBar();
|
|
testExactBarBoundaryRollsOver();
|
|
testMultiBar();
|
|
testLongCaptureNoBarCap();
|
|
testThreeFourMeter();
|
|
testSixEightMeter();
|
|
testUnstampedMeterIsBlank();
|
|
testUnknownTempoIsBlank();
|
|
testNegativeLengthClampsToOrigin();
|
|
testSecondsMsZero();
|
|
testSecondsMsSubSecond();
|
|
testSecondsMsMultiSecond();
|
|
testSecondsMsNegativeClamps();
|
|
testSecondsMsNearWholeSecondCarry();
|
|
|
|
if (g_fail == 0) std::printf("card_meta: all tests passed\n");
|
|
else std::printf("card_meta: %d CHECK(s) FAILED\n", g_fail);
|
|
return g_fail == 0 ? 0 : 1;
|
|
}
|