// Standalone tests for the Design View repair pass's pure decision — no REAPER, no // test framework. // // The two properties the pass exists for: it drives a flag ONLY where a park record // names the track (so a track the tool never parked can never have its main send // re-enabled under it), and it fires on applied-output drift rather than on "an undo // happened". Both AppliedStates are produced by the real fingerprint // (view::appliedState) over real models, so a change to what the fingerprint carries // shows up here rather than being papered over by hand-built fixtures. #include "../src/shell/view/view_reconcile.h" #include #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) namespace { TrackSnapshot captured(int showInTcp, int showInMixer, int mainSend, int fxEnable) { TrackSnapshot snap; snap.showInTcp = showInTcp; snap.showInMixer = showInMixer; snap.mainSend = mainSend; snap.fxEnable = fxEnable; return snap; } bool hasOp(const std::vector& ops, const std::string& guid, Flag flag, int value) { for (const TrackFlagOp& op : ops) if (op.guid == guid && op.flag == flag && op.value == value) return true; return false; } bool namesTrack(const std::vector& ops, const std::string& guid) { for (const TrackFlagOp& op : ops) if (op.guid == guid) return true; return false; } } // namespace // -- the trigger: applied-output drift, not "an undo happened" ----------------- static void testAnUndoThatLeftOurAppliedOutputAloneRepairsNothing() { // The rejected trigger is "did an undo occur" — an undo that touched nothing we // drive still answers yes, and repairing on it rewrites state the user owns. ViewModeModel model; model.setActiveMode(kDesignModeId); model.storeSnapshot("{A}", captured(1, 1, 1, 1)); const view::AppliedState state = view::appliedState(model); CHECK(planReconcile(state, state).empty()); } static void testADriftedActiveModeAloneIsNotAReasonToDriveATrack() { // Drift is the gate, not the instruction: the record still has an owner, so the // reapply that follows this pass is what drives it. ViewModeModel applied; applied.setActiveMode(kDesignModeId); applied.storeSnapshot("{A}", captured(1, 1, 1, 1)); ViewModeModel reloaded; // active mode Arrange — the fingerprint differs reloaded.storeSnapshot("{A}", captured(1, 1, 1, 1)); CHECK(view::appliedState(applied) != view::appliedState(reloaded)); CHECK(planReconcile(view::appliedState(applied), view::appliedState(reloaded)).empty()); } // -- the scope rule: a record names the track, or nothing is written ----------- static void testARecordTheReloadedModelLostIsHandedBackItsCapturedValues() { // The undo case: REAPER rolled view_state back to before the switch, so the model // no longer records the park — but the flags are still driven on the track, and // this memo is the only surviving account of what they were. ViewModeModel applied; applied.setActiveMode(kDesignModeId); applied.storeSnapshot("{A}", captured(1, 1, 1, 1)); const ViewModeModel reloaded; // Arrange, no records at all const std::vector ops = planReconcile(view::appliedState(applied), view::appliedState(reloaded)); CHECK(ops.size() == 4); CHECK(hasOp(ops, "{A}", Flag::ShowInTcp, 1)); CHECK(hasOp(ops, "{A}", Flag::ShowInMixer, 1)); CHECK(hasOp(ops, "{A}", Flag::MainSend, 1)); CHECK(hasOp(ops, "{A}", Flag::FxEnable, 1)); } static void testARepairedFlagReturnsToItsCapturedValueNeverToOn() { // A track the user had OUT of the master mix and FX-bypassed before we parked it: // the repair must hand back exactly that, not a hardcoded "on". ViewModeModel applied; applied.setActiveMode(kDesignModeId); applied.storeSnapshot("{A}", captured(1, 0, 0, 0)); const ViewModeModel reloaded; const std::vector ops = planReconcile(view::appliedState(applied), view::appliedState(reloaded)); CHECK(hasOp(ops, "{A}", Flag::MainSend, 0)); CHECK(hasOp(ops, "{A}", Flag::ShowInMixer, 0)); CHECK(hasOp(ops, "{A}", Flag::FxEnable, 0)); CHECK(!hasOp(ops, "{A}", Flag::MainSend, 1)); } static void testATrackNeitherStateRecordsIsNeverDrivenAtAll() { // The regression this rule is built against: a track the model merely calls // active is NOT a track the tool parked. It holds no captured value, so asserting // B_MAINSEND=1 on it would silently re-enable a send the user disabled by hand. ViewModeModel applied; applied.setActiveMode(kDesignModeId); applied.storeSnapshot("{A}", captured(1, 1, 1, 1)); ViewModeModel reloaded; reloaded.membership().tag("{B}", kArrangeModeId); // active, never parked, no record const std::vector ops = planReconcile(view::appliedState(applied), view::appliedState(reloaded)); CHECK(namesTrack(ops, "{A}")); CHECK(!namesTrack(ops, "{B}")); } static void testASpentFlagHalfIsNotARecordToRepairFrom() { // A restore already handed the flags back and zeroed them on the record; the FX // half outlives that. Repairing from the spent half would drive those zeros — // i.e. re-park the track — so the fingerprint must not carry it. ViewModeModel applied; applied.setActiveMode(kDesignModeId); applied.storeSnapshot("{A}", captured(1, 1, 1, 1)); applied.releaseSnapshotFlags("{A}"); const ViewModeModel reloaded; CHECK(planReconcile(view::appliedState(applied), view::appliedState(reloaded)).empty()); } int main() { testAnUndoThatLeftOurAppliedOutputAloneRepairsNothing(); testADriftedActiveModeAloneIsNotAReasonToDriveATrack(); testARecordTheReloadedModelLostIsHandedBackItsCapturedValues(); testARepairedFlagReturnsToItsCapturedValueNeverToOn(); testATrackNeitherStateRecordsIsNeverDrivenAtAll(); testASpentFlagHalfIsNotARecordToRepairFrom(); if (g_fail == 0) std::printf("All tests passed.\n"); return g_fail ? 1 : 0; }