164 lines
6.1 KiB
C++
164 lines
6.1 KiB
C++
// Standalone tests for reasampler::batch_capture — no REAPER, no test framework.
|
|
// Same fast loop as the sibling pure tests (render_settings et al.): assert the batch
|
|
// planning (selected-set -> ordered capture units) and result aggregation directly.
|
|
//
|
|
// Covers (M11 brief §test cases):
|
|
// * selected-set -> capture-request-list planning: items; razor areas; empty set;
|
|
// multiple razor areas across tracks (order preserved, ordinals contiguous);
|
|
// invalid (empty/inverted) ranges dropped.
|
|
// * batch result aggregation: all-success; partial-failure ORDERING (failed
|
|
// ordinals reported in unit order); all-failed; single-unit noun singular.
|
|
|
|
#include "../src/core/capture/batch_capture.h"
|
|
|
|
#include <cstdio>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
using namespace reasampler;
|
|
using namespace reasampler::capture;
|
|
|
|
static int g_fail = 0;
|
|
#define CHECK(cond) do { if(!(cond)) { \
|
|
std::printf("FAIL line %d: %s\n", __LINE__, #cond); ++g_fail; } } while(0)
|
|
|
|
// --- planCaptureUnits: items -------------------------------------------------
|
|
|
|
// Three selected items -> three units, order preserved, ordinals 1,2,3, bounds exact.
|
|
static void testPlanItemsPreservesOrderAndBounds() {
|
|
std::vector<BatchRange> in = {{0.0, 1.5}, {2.0, 2.25}, {10.0, 12.0}};
|
|
auto units = planCaptureUnits(in);
|
|
CHECK(units.size() == 3);
|
|
CHECK(units[0].ordinal == 1 && units[0].startSeconds == 0.0 && units[0].endSeconds == 1.5);
|
|
CHECK(units[1].ordinal == 2 && units[1].startSeconds == 2.0 && units[1].endSeconds == 2.25);
|
|
CHECK(units[2].ordinal == 3 && units[2].startSeconds == 10.0 && units[2].endSeconds == 12.0);
|
|
}
|
|
|
|
// --- planCaptureUnits: empty set ---------------------------------------------
|
|
|
|
// No selected item / no razor area -> empty plan (shell reports nothing-to-batch).
|
|
static void testPlanEmptySet() {
|
|
CHECK(planCaptureUnits({}).empty());
|
|
}
|
|
|
|
// --- planCaptureUnits: invalid ranges dropped, ordinals stay contiguous ------
|
|
|
|
// An empty (end==start) and an inverted (end<start) range are DROPPED; the kept
|
|
// units are renumbered 1..k with no gap, so a dropped neighbor never leaves a hole
|
|
// in the reported ordinals.
|
|
static void testPlanDropsInvalidAndRenumbers() {
|
|
std::vector<BatchRange> in = {
|
|
{0.0, 1.0}, // kept -> #1
|
|
{5.0, 5.0}, // empty -> dropped
|
|
{3.0, 2.0}, // inverted -> dropped
|
|
{8.0, 9.0}, // kept -> #2
|
|
};
|
|
auto units = planCaptureUnits(in);
|
|
CHECK(units.size() == 2);
|
|
CHECK(units[0].ordinal == 1 && units[0].startSeconds == 0.0 && units[0].endSeconds == 1.0);
|
|
CHECK(units[1].ordinal == 2 && units[1].startSeconds == 8.0 && units[1].endSeconds == 9.0);
|
|
}
|
|
|
|
// --- planCaptureUnits: multiple razor areas across tracks --------------------
|
|
|
|
// The shell concatenates every track's parsed razor areas in track order; planning
|
|
// preserves that concatenation order and assigns contiguous ordinals. Two areas on
|
|
// track A followed by one on track B -> ordinals 1,2,3 in that exact order.
|
|
static void testPlanRazorAreasAcrossTracksOrdered() {
|
|
std::vector<BatchRange> in = {
|
|
{0.0, 0.5}, // track A, area 1
|
|
{1.0, 1.5}, // track A, area 2
|
|
{4.0, 6.0}, // track B, area 1
|
|
};
|
|
auto units = planCaptureUnits(in);
|
|
CHECK(units.size() == 3);
|
|
CHECK(units[0].startSeconds == 0.0 && units[0].endSeconds == 0.5);
|
|
CHECK(units[1].startSeconds == 1.0 && units[1].endSeconds == 1.5);
|
|
CHECK(units[2].startSeconds == 4.0 && units[2].endSeconds == 6.0);
|
|
CHECK(units[0].ordinal == 1 && units[1].ordinal == 2 && units[2].ordinal == 3);
|
|
}
|
|
|
|
// --- BatchOutcome: all-success -----------------------------------------------
|
|
|
|
static void testOutcomeAllSuccess() {
|
|
BatchOutcome o;
|
|
o.record(1, true);
|
|
o.record(2, true);
|
|
o.record(3, true);
|
|
CHECK(o.total() == 3);
|
|
CHECK(o.succeeded() == 3);
|
|
CHECK(o.failed() == 0);
|
|
CHECK(o.failures().empty());
|
|
CHECK(o.summaryLine("item") == "ReaSampler batch capture: 3 items captured.");
|
|
}
|
|
|
|
// --- BatchOutcome: partial-failure ordering ----------------------------------
|
|
|
|
// Failures are reported in UNIT ORDER (#2, #4), not record-count order or sorted —
|
|
// the summary must let the user retry exactly the right units. This assertion fails
|
|
// if the aggregation reordered, deduped, or dropped a failure.
|
|
static void testOutcomePartialFailureOrdering() {
|
|
BatchOutcome o;
|
|
o.record(1, true);
|
|
o.record(2, false, "render produced no output file");
|
|
o.record(3, true);
|
|
o.record(4, false, "capture range is empty");
|
|
o.record(5, true);
|
|
CHECK(o.total() == 5);
|
|
CHECK(o.succeeded() == 3);
|
|
CHECK(o.failed() == 2);
|
|
|
|
auto fails = o.failures();
|
|
CHECK(fails.size() == 2);
|
|
CHECK(fails[0].ordinal == 2 && !fails[0].ok);
|
|
CHECK(fails[0].detail == "render produced no output file");
|
|
CHECK(fails[1].ordinal == 4);
|
|
|
|
CHECK(o.summaryLine("item") ==
|
|
"ReaSampler batch capture: 3 of 5 items captured (2 failed: #2, #4).");
|
|
}
|
|
|
|
// --- BatchOutcome: all-failed ------------------------------------------------
|
|
|
|
static void testOutcomeAllFailed() {
|
|
BatchOutcome o;
|
|
o.record(1, false, "x");
|
|
o.record(2, false, "y");
|
|
CHECK(o.succeeded() == 0);
|
|
CHECK(o.failed() == 2);
|
|
CHECK(o.summaryLine("razor area") ==
|
|
"ReaSampler batch capture: 0 of 2 razor areas captured (2 failed: #1, #2).");
|
|
}
|
|
|
|
// --- BatchOutcome: single unit uses singular noun ----------------------------
|
|
|
|
static void testOutcomeSingularNoun() {
|
|
BatchOutcome o;
|
|
o.record(1, true);
|
|
CHECK(o.summaryLine("item") == "ReaSampler batch capture: 1 item captured.");
|
|
}
|
|
|
|
// --- BatchOutcome: empty (no units planned) ----------------------------------
|
|
|
|
static void testOutcomeEmpty() {
|
|
BatchOutcome o;
|
|
CHECK(o.total() == 0);
|
|
CHECK(o.summaryLine("item") == "ReaSampler batch capture: nothing to capture.");
|
|
}
|
|
|
|
int main() {
|
|
testPlanItemsPreservesOrderAndBounds();
|
|
testPlanEmptySet();
|
|
testPlanDropsInvalidAndRenumbers();
|
|
testPlanRazorAreasAcrossTracksOrdered();
|
|
|
|
testOutcomeAllSuccess();
|
|
testOutcomePartialFailureOrdering();
|
|
testOutcomeAllFailed();
|
|
testOutcomeSingularNoun();
|
|
testOutcomeEmpty();
|
|
|
|
if (g_fail == 0) std::printf("All tests passed.\n");
|
|
return g_fail ? 1 : 0;
|
|
}
|