// Standalone tests for reasampler::sample_usage β€” no REAPER, no framework. // The pS-usage seam: instances publish held captures; the extension folds live // instances' holds into the prune's `referenced` set. Tested hard here because this is // the prune-protection guarantee β€” a SAFETY property: every failure, ambiguity, or // uncertainty must FAIL-SAFE toward PROTECT (over-protection acceptable; // under-protection = deleting a maybe-used file is a data-loss bug). // // Covers: wire round-trip (nonce + unioned flag, empty / adversarial bytes), // malformed -> nullopt, the publish plan's branches (fresh / clean replace + skip / // sibling union with the sticky poison flag / cross-track re-mint / undecodable remint), // the SAME-TRACK SIBLING repro (the review's πŸ”΄#1 β€” byte-identical wire convergence // must never let one sibling clean-replace the other's still-held paths, including one // write later via the poison flag), the liveness fold (live, dead-track, empty-guid // fallback, de-dup), the ZERO-IDENTIFIED protect-all net (πŸ”΄#2 β€” an identity-matcher // failure must protect everything, not nothing), the UNREADABLE-record abort // (foldUsageRecords.abortPrune β€” prune halts, deletes nothing), the UNDECODABLE-EXISTING // REMINT (corrupt key left in place β€” prune-side abort keeps firing while sibling holds // unprotected), the ABORTβ†’PROTECT-ALL belt-and-braces (foldUsageRecords.heldPaths is // the full protect-all set even when abortPrune is set), the TRUNCATED-WALKβ†’PROTECT-ALL // proof (FX walk misses a nested instance β†’ anyLive=false β†’ usageHeldPaths protects // every record β€” the pure side of the depth-cap + depth-exhaustion-is-container fix), // the pure identity matcher (UID hex / module filename base / display name, beta // over-protect), and the composed pruneOrphans exclusion proof. #include "../src/core/wire/sample_usage.h" #include #include #include #include #include #include "../src/core/reclaim/prune_reconcile.h" // mergeReferenced + pruneOrphans (composed proof) using namespace reasampler; using namespace reasampler::reclaim; using namespace reasampler::wire; 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 { UsageRecord makeRecord(const std::string& trackGuid, const std::string& nonce, std::vector holds, bool unioned = false) { UsageRecord r; r.trackGuid = trackGuid; r.ownerNonce = nonce; r.unioned = unioned; r.holds = std::move(holds); return r; } bool holdsContainPath(const std::vector& holds, const std::string& path) { for (const UsageHold& h : holds) if (h.relativePath == path) return true; return false; } } // namespace // --- wire round-trip ---------------------------------------------------------- static void testRoundTrip() { const UsageRecord rec = makeRecord( "{12345678-1234-1234-1234-1234567890AB}", "aabbccdd00112233", {UsageHold{"cap-1700-kick", "reasampler_bank/kick.wav"}, UsageHold{"cap-1701-snare", "reasampler_bank/snare.wav"}}, /*unioned=*/true); const std::string wire = encodeUsageRecord(rec); auto back = decodeUsageRecord(wire); CHECK(back.has_value()); CHECK(*back == rec); CHECK(back->unioned); CHECK(encodeUsageRecord(*back) == wire); // deterministic re-encode } static void testRoundTripEmptyHoldsAndEmptyGuid() { // An empty-holds record is LEGAL (an instance releasing everything it held), and an // empty trackGuid is legal (no track context at publish -> any-instance fallback). const UsageRecord rec = makeRecord("", "", {}); auto back = decodeUsageRecord(encodeUsageRecord(rec)); CHECK(back.has_value()); CHECK(back->trackGuid.empty()); CHECK(back->ownerNonce.empty()); CHECK(!back->unioned); CHECK(back->holds.empty()); } static void testRoundTripAdversarialBytes() { // Ids/paths carrying the wire's own metacharacters must survive whole (the whole // point of length-prefixing): ':' delimiters, digits, the magic tag itself. const UsageRecord rec = makeRecord( "12:34:guid-with-colons", "1:0", {UsageHold{"rsusage1-lookalike", "path with spaces/and:colons/7:x.wav"}}); auto back = decodeUsageRecord(encodeUsageRecord(rec)); CHECK(back.has_value()); CHECK(*back == rec); } static void testDecodeMalformed() { CHECK(!decodeUsageRecord("").has_value()); CHECK(!decodeUsageRecord("garbage").has_value()); CHECK(!decodeUsageRecord("rsusage1").has_value()); // truncated after magic CHECK(!decodeUsageRecord("rsusage2" "0:0:1:01:0").has_value()); // wrong magic // A non-"0"/"1" unioned field is corruption -> reject whole. Hand-built wire: // magic + trackGuid "" + nonce "" + unioned "2" + count 0. CHECK(!decodeUsageRecord("rsusage1" "0:" "0:" "1:2" "1:0").has_value()); // Truncated mid-holds: claims 2 holds, carries 1. The count field for one hold is // the "1:1" that FOLLOWS the unioned field "1:0" (nonce chosen digit-free so the // needle is unambiguous). UsageRecord one = makeRecord("{G}", "nonce", {UsageHold{"a", "p.wav"}}); std::string wire = encodeUsageRecord(one); const std::string needle = "1:0" "1:1"; // unioned=0 then count=1 const std::size_t pos = wire.find(needle); CHECK(pos != std::string::npos); wire[pos + 5] = '2'; // count "1:1" -> "1:2" CHECK(!decodeUsageRecord(wire).has_value()); // Trailing garbage after a complete record -> reject whole. CHECK(!decodeUsageRecord(encodeUsageRecord(one) + "x").has_value()); } // --- publish plan -------------------------------------------------------------- static void testPlanFreshKey() { const UsageRecord mine = makeRecord("{T1}", "NA", {UsageHold{"a", "p.wav"}}); const UsagePublishPlan plan = planUsagePublish(std::nullopt, mine); CHECK(!plan.remint); CHECK(!plan.skipWrite); auto back = decodeUsageRecord(plan.wire); CHECK(back.has_value()); CHECK(back->ownerNonce == "NA"); CHECK(!back->unioned); // sole known writer -> un-poisoned } static void testPlanCleanReplaceAndSkip() { // The key holds this incarnation's own un-poisoned write (nonce match, !unioned): // the sole-writer path. Clean replace; released holds drop. const UsageRecord prev = makeRecord("{T1}", "NA", {UsageHold{"a", "pa.wav"}, UsageHold{"b", "pb.wav"}}); const std::string prevWire = encodeUsageRecord(prev); const UsageRecord mine = makeRecord("{T1}", "NA", {UsageHold{"a", "pa.wav"}}); const UsagePublishPlan plan = planUsagePublish(prevWire, mine); CHECK(!plan.remint); CHECK(!plan.skipWrite); auto back = decodeUsageRecord(plan.wire); CHECK(back.has_value()); CHECK(back->holds.size() == 1); // 'b' genuinely released β€” NOT unioned back in CHECK(!back->unioned); // Unchanged play-set -> byte-identical write -> skip (idle reload tick). const UsagePublishPlan idle = planUsagePublish(prevWire, prev); CHECK(idle.skipWrite); CHECK(!idle.remint); } // The review's πŸ”΄#1 repro. Two same-track FX copies share a key and converge on // byte-identical hold sets; the OLD wire-equality discriminator let sibling A // clean-replace over B's still-held path. With the in-wire per-lifetime nonce + // sticky unioned poison, every same-track collision unions and NO write of A's can // ever drop B's holds β€” including A's SECOND write after it re-owns the key. static void testSiblingCollisionNeverDropsHolds() { // A (lifetime nonce NA) publishes {pa}. const UsageRecord aFirst = makeRecord("{T1}", "NA", {UsageHold{"a", "pa.wav"}}); const UsagePublishPlan planA1 = planUsagePublish(std::nullopt, aFirst); CHECK(!planA1.remint && !planA1.skipWrite); // B (lifetime nonce NB, same track, SAME hold set β€” the byte-identical // convergence) publishes {pa}: foreign nonce, same track -> UNION, and the // false->true poison flip is WRITTEN (never skipped), marking the key multi-writer. const UsageRecord bSame = makeRecord("{T1}", "NB", {UsageHold{"a", "pa.wav"}}); const UsagePublishPlan planB = planUsagePublish(planA1.wire, bSame); CHECK(!planB.remint); CHECK(!planB.skipWrite); // the poison flip must land in ext-state auto bBack = decodeUsageRecord(planB.wire); CHECK(bBack.has_value()); CHECK(bBack->unioned); CHECK(holdsContainPath(bBack->holds, "pa.wav")); // A changes its selection to {pc} (releases pa from ITS play-set β€” but B still // plays pa). Foreign nonce (NB) -> union: pa is RETAINED. Pre-fix this was the // clean-replace that dropped B's hold -> prune could delete B's playing file. const UsageRecord aSecond = makeRecord("{T1}", "NA", {UsageHold{"c", "pc.wav"}}); const UsagePublishPlan planA2 = planUsagePublish(planB.wire, aSecond); CHECK(!planA2.remint); auto a2Back = decodeUsageRecord(planA2.wire); CHECK(a2Back.has_value()); CHECK(holdsContainPath(a2Back->holds, "pa.wav")); // B's hold survives A's write CHECK(holdsContainPath(a2Back->holds, "pc.wav")); CHECK(a2Back->unioned); // A writes AGAIN (selection {pd}) β€” now the key carries A's OWN nonce (NA). A bare // nonce discriminator would clean-replace here and drop pa one step late; the // sticky unioned poison forces union forever. pa STILL survives. const UsageRecord aThird = makeRecord("{T1}", "NA", {UsageHold{"d", "pd.wav"}}); const UsagePublishPlan planA3 = planUsagePublish(planA2.wire, aThird); CHECK(!planA3.remint); auto a3Back = decodeUsageRecord(planA3.wire); CHECK(a3Back.has_value()); CHECK(holdsContainPath(a3Back->holds, "pa.wav")); // the poison-flag guarantee CHECK(a3Back->unioned); } static void testPlanUnionSkipOnlyWhenAlreadyPoisoned() { // Union over an ALREADY-unioned record that adds no holds -> skip (the write would // flip only the nonce β€” redundant churn; the protection is already in place). const UsageRecord poisoned = makeRecord("{T1}", "NA", {UsageHold{"a", "pa.wav"}}, /*unioned=*/true); const UsageRecord mineSubset = makeRecord("{T1}", "NB", {UsageHold{"a", "pa.wav"}}); const UsagePublishPlan plan = planUsagePublish(encodeUsageRecord(poisoned), mineSubset); CHECK(!plan.remint); CHECK(plan.skipWrite); // But a union that ADDS a hold must write even when already poisoned. const UsageRecord mineNew = makeRecord("{T1}", "NB", {UsageHold{"b", "pb.wav"}}); const UsagePublishPlan plan2 = planUsagePublish(encodeUsageRecord(poisoned), mineNew); CHECK(!plan2.skipWrite); auto back = decodeUsageRecord(plan2.wire); CHECK(back.has_value()); CHECK(back->holds.size() == 2); CHECK(back->unioned); } static void testPlanEmptyNonceNeverClaimsOwnership() { // A record written with an empty nonce (defensive: publisher failed to mint) can // never be claimed via empty==empty β€” the same-track path must UNION, not replace. const UsageRecord theirs = makeRecord("{T1}", "", {UsageHold{"a", "pa.wav"}}); const UsageRecord mine = makeRecord("{T1}", "", {UsageHold{"b", "pb.wav"}}); const UsagePublishPlan plan = planUsagePublish(encodeUsageRecord(theirs), mine); CHECK(!plan.remint); auto back = decodeUsageRecord(plan.wire); CHECK(back.has_value()); CHECK(holdsContainPath(back->holds, "pa.wav")); // never dropped CHECK(back->unioned); } static void testPlanCrossTrackRemint() { // The key holds a foreign record from ANOTHER track: this state was cloned there // (FX copy / track duplication) β€” take a fresh identity, leave theirs untouched. const UsageRecord theirs = makeRecord("{T1}", "NA", {UsageHold{"a", "pa.wav"}}); const UsageRecord mine = makeRecord("{T2}", "NB", {UsageHold{"a", "pa.wav"}}); const UsagePublishPlan plan = planUsagePublish(encodeUsageRecord(theirs), mine); CHECK(plan.remint); auto back = decodeUsageRecord(plan.wire); CHECK(back.has_value()); CHECK(!back->unioned); // written under the NEW key β€” fresh, un-poisoned } static void testPlanOwnRecordAfterTrackMove() { // My own un-poisoned record, but the instance moved tracks THIS lifetime (nonce // matches, track differs): still mine β€” clean replace with the new track guid, NOT // a remint (the key stays stable; no record proliferation on a track move). const UsageRecord prev = makeRecord("{T1}", "NA", {UsageHold{"a", "pa.wav"}}); const UsageRecord mine = makeRecord("{T2}", "NA", {UsageHold{"a", "pa.wav"}}); const UsagePublishPlan plan = planUsagePublish(encodeUsageRecord(prev), mine); CHECK(!plan.remint); auto back = decodeUsageRecord(plan.wire); CHECK(back.has_value()); CHECK(back->trackGuid == "{T2}"); } static void testPlanUndecodableExistingRemints() { // An undecodable existing value under MY key must REMINT (not overwrite). Overwriting // would clear the prune-side abort while a same-key sibling B's holds are unprotected // until B republishes. Leaving the corrupt key in place keeps the prune-side abort // (foldUsageRecords.abortPrune) firing so no delete-ward window opens. const UsageRecord mine = makeRecord("{T1}", "NA", {UsageHold{"a", "pa.wav"}}); const UsagePublishPlan plan = planUsagePublish(std::string("corrupt"), mine); CHECK(plan.remint); // fresh key β€” leave the corrupt key untouched CHECK(!plan.skipWrite); // wire carries mine (to be written under the NEW key by the caller) auto back = decodeUsageRecord(plan.wire); CHECK(back.has_value()); CHECK(back->holds.size() == 1); CHECK(!back->unioned); // fresh key, sole writer β€” un-poisoned } // --- liveness fold --------------------------------------------------------------- static void testHeldPathsLiveness() { const std::vector records = { makeRecord("{LIVE}", "N1", {UsageHold{"a", "pa.wav"}}), makeRecord("{DEAD}", "N2", {UsageHold{"b", "pb.wav"}}), // deleted track makeRecord("", "N3", {UsageHold{"c", "pc.wav"}}), // no track context }; const std::unordered_set live = {"{LIVE}"}; // Live-track record counts; dead-track record is EXCLUDED (stale-record cleanup β€” // possible ONLY because at least one instance was positively identified, so the // matcher demonstrably works in this project); empty-guid record counts while ANY // instance lives (fail-safe fallback). const std::vector withAny = usageHeldPaths(records, live, true); CHECK(withAny.size() == 2); CHECK(withAny[0] == "pa.wav"); CHECK(withAny[1] == "pc.wav"); } // The review's πŸ”΄#2 repro: records exist but ZERO instances were identified live // (either every instance was genuinely deleted, or β€” indistinguishable β€” the identity // matcher failed on every FX). The old fold dropped every record -> all held captures // became prunable. The fail-safe net protects ALL records' paths instead. static void testZeroIdentifiedProtectsAll() { const std::vector records = { makeRecord("{T1}", "N1", {UsageHold{"a", "pa.wav"}}), makeRecord("{T2}", "N2", {UsageHold{"b", "pb.wav"}}), makeRecord("", "N3", {UsageHold{"c", "pc.wav"}}), }; const std::vector all = usageHeldPaths(records, std::unordered_set{}, false); CHECK(all.size() == 3); // EVERY path protected β€” never zero CHECK(all[0] == "pa.wav"); CHECK(all[1] == "pb.wav"); CHECK(all[2] == "pc.wav"); // No records at all -> nothing to protect (the common no-instances case). CHECK(usageHeldPaths({}, std::unordered_set{}, false).empty()); } static void testHeldPathsDedupAndEmptyPathSkip() { const std::vector records = { makeRecord("{T}", "N1", {UsageHold{"a", "shared.wav"}, UsageHold{"x", ""}}), makeRecord("{T}", "N2", {UsageHold{"b", "shared.wav"}, UsageHold{"c", "own.wav"}}), }; const std::unordered_set live = {"{T}"}; const std::vector paths = usageHeldPaths(records, live, true); CHECK(paths.size() == 2); // shared.wav de-duped across records; empty path skipped CHECK(paths[0] == "shared.wav"); CHECK(paths[1] == "own.wav"); } // A take-FX-hosted instance: the shell attributes it to the ITEM'S OWNING TRACK (the // same guid the VST-side getReaperParent(1) publishes), so at the pure layer its record // folds exactly like a track-FX one. This is the pure half of the take-FX guarantee; // the enumeration itself (TakeFX_* walk, fx_ident + original_name) is shell code. static void testTakeFxAttributedRecordIsProtected() { const std::vector records = { makeRecord("{ITEM-TRACK}", "N1", {UsageHold{"a", "take-held.wav"}}), }; const std::unordered_set live = {"{ITEM-TRACK}"}; // set via item scan const std::vector paths = usageHeldPaths(records, live, true); CHECK(paths.size() == 1); CHECK(paths[0] == "take-held.wav"); } // --- the unreadable-record abort (foldUsageRecords) -------------------------------- // A present-but-unreadable/undecodable rsusage_* record must ABORT the prune (halt, // delete nothing) β€” silently reduced protection is the delete direction. static void testUnreadableRecordAbortsPrune() { std::vector> decoded; decoded.push_back(makeRecord("{T1}", "N1", {UsageHold{"a", "pa.wav"}})); decoded.push_back(std::nullopt); // one unreadable record among readable ones const UsageFoldResult fold = foldUsageRecords(decoded, std::unordered_set{"{T1}"}, true); CHECK(fold.abortPrune); // All readable -> no abort, normal liveness fold. std::vector> ok; ok.push_back(makeRecord("{T1}", "N1", {UsageHold{"a", "pa.wav"}})); const UsageFoldResult okFold = foldUsageRecords(ok, std::unordered_set{"{T1}"}, true); CHECK(!okFold.abortPrune); CHECK(okFold.heldPaths.size() == 1); CHECK(okFold.heldPaths[0] == "pa.wav"); // Empty input (no records enumerated) -> empty, no abort. const UsageFoldResult empty = foldUsageRecords({}, std::unordered_set{}, false); CHECK(!empty.abortPrune); CHECK(empty.heldPaths.empty()); // Readable records + zero identified -> the protect-all net applies through the // fold too (belt and braces with the abort). std::vector> unmatched; unmatched.push_back(makeRecord("{T9}", "N1", {UsageHold{"a", "pa.wav"}})); const UsageFoldResult net = foldUsageRecords(unmatched, std::unordered_set{}, false); CHECK(!net.abortPrune); CHECK(net.heldPaths.size() == 1); } // --- abort returns the protect-all set (belt-and-braces) --------------------------- // foldUsageRecords must return heldPaths = EVERY readable record's paths when // abortPrune is set, so a future caller that forgets to check the flag before using // heldPaths still gets maximum protection rather than an empty set (which would be // delete-ward). static void testAbortFoldReturnsProtectAllSet() { // Two readable records + one unreadable (nullopt) in between. std::vector> decoded; decoded.push_back(makeRecord("{T1}", "N1", {UsageHold{"a", "pa.wav"}})); decoded.push_back(std::nullopt); // triggers abort decoded.push_back(makeRecord("{T2}", "N2", {UsageHold{"b", "pb.wav"}})); // Live: only {T1} β€” so without protect-all, T2's path would be excluded. const UsageFoldResult fold = foldUsageRecords(decoded, std::unordered_set{"{T1}"}, true); CHECK(fold.abortPrune); // heldPaths must contain BOTH paths (protect-all over all readable records), // not just {T1}'s path. CHECK(fold.heldPaths.size() == 2); bool hasPA = false, hasPB = false; for (const std::string& p : fold.heldPaths) { if (p == "pa.wav") hasPA = true; if (p == "pb.wav") hasPB = true; } CHECK(hasPA); CHECK(hasPB); // All nullopt (every key unreadable): abort + empty heldPaths (nothing readable). std::vector> allNull; allNull.push_back(std::nullopt); const UsageFoldResult allNullFold = foldUsageRecords(allNull, std::unordered_set{}, false); CHECK(allNullFold.abortPrune); CHECK(allNullFold.heldPaths.empty()); // no readable records to protect } // --- truncated enumeration β†’ protect-all ------------------------------------------- // The FX walk may truncate at kMaxContainerDepth, leaving a deeply-nested live instance // missed. At the PURE layer this is indistinguishable from a genuine identity-matcher // failure: anyInstanceLive stays false while records exist. The protect-all net in // usageHeldPaths guarantees this resolves toward PROTECT, never toward delete β€” the same // test shape as testZeroIdentifiedProtectsAll, stated here explicitly for the truncation // failure mode. static void testTruncatedWalkProtectsAll() { // Records from two tracks that host instances; the FX walk (shell side) failed to // identify ANY instance (e.g. truncated at depth, or a future matcher gap). const std::vector records = { makeRecord("{TRACK-A}", "N1", {UsageHold{"x", "nested-a.wav"}}), makeRecord("{TRACK-B}", "N2", {UsageHold{"y", "nested-b.wav"}}), }; // Shell reported anyLive=false (it couldn't identify any instance β€” truncated walk). const std::vector paths = usageHeldPaths(records, std::unordered_set{}, /*anyInstanceLive=*/false); // Both paths must be protected β€” the protect-all net fires. CHECK(paths.size() == 2); bool hasA = false, hasB = false; for (const std::string& p : paths) { if (p == "nested-a.wav") hasA = true; if (p == "nested-b.wav") hasB = true; } CHECK(hasA); CHECK(hasB); // Belt-and-braces: the same scenario through foldUsageRecords also protects all. std::vector> decoded; for (const UsageRecord& r : records) decoded.push_back(r); const UsageFoldResult fold = foldUsageRecords(decoded, std::unordered_set{}, false); CHECK(!fold.abortPrune); CHECK(fold.heldPaths.size() == 2); } // --- the identity matcher ---------------------------------------------------------- // The common-case shapes: REAPER's fx_ident carries the .vst3 MODULE PATH (matched by // the output-name needle "REASAMPLER_9000" β€” the display name, space-separated, can // never match it); original_name carries the display name. UID hex matches when the // rendering embeds it. All substring, case-insensitive. static void testIdentityMatcher() { const std::string uid = "ABCD1234ABCD1234ABCD1234ABCD1234"; const std::string name = "REASAMPLER 9000"; const std::string output = "REASAMPLER_9000"; // The module-path fx_ident shape: ONLY the output-name needle can catch this (the // review's πŸ”΄#2b β€” the display name alone silently failed the common case). const std::string modulePath = "C:\\Program Files\\Common Files\\VST3\\reasampler_9000.vst3"; CHECK(identityMatches(modulePath, uid, name, output)); CHECK(!identityMatches(modulePath, uid, name, "")); // display name can't match it // The display-name shape (original_name / renamed renderings). CHECK(identityMatches("VST3: ReaSampler 9000", uid, name, output)); // The UID-hex shape (case-insensitive). CHECK(identityMatches("vst3", uid, name, output)); // Beta over-protect (deliberate): stable needles are substrings of beta renderings // β€” a stable extension protects beta instances' holds too (wider set only). CHECK(identityMatches("...\\reasampler_9000_beta.vst3", uid, name, output)); CHECK(identityMatches("ReaSampler 9000 beta", uid, name, output)); // Non-matches stay non-matches. CHECK(!identityMatches("", uid, name, output)); CHECK(!identityMatches("ReaComp", uid, name, output)); CHECK(!identityMatches("some_other_sampler.vst3", uid, name, output)); } // --- the composed prune-protection proof ----------------------------------------- // The definition-of-done property at the pure layer: a capture held by a live instance // lands in the referenced union, and pruneOrphans can NEVER emit it β€” even when the // bank no longer references it (deleted from the bank while the instance kept its ref) // and it is owned + present (the exact preconditions under which it WOULD be reclaimed). static void testInstanceHoldMakesPathUnprunable() { const std::vector present = {"held.wav", "orphan.wav"}; const std::vector owned = {"held.wav", "orphan.wav"}; const std::vector bankRefs = {}; // bank does NOT reference either // Without instance usage both are orphans (the pre-pS-usage behavior). CHECK(pruneOrphans(present, bankRefs, owned).size() == 2); // A live instance holds held.wav -> the union protects it; orphan.wav still reclaims. const std::vector records = { makeRecord("{T}", "N1", {UsageHold{"id-held", "held.wav"}})}; const std::unordered_set live = {"{T}"}; const std::vector referenced = mergeReferenced(bankRefs, usageHeldPaths(records, live, true)); const std::vector orphans = pruneOrphans(present, referenced, owned); CHECK(orphans.size() == 1); CHECK(orphans[0] == "orphan.wav"); // Zero instances identified anywhere -> the protect-all net keeps held.wav // un-prunable THROUGH the composed pipeline too (matcher failure must never // resolve toward delete; the accepted residual is that leftover records keep // protecting until an instance is identified again). const std::vector refsNoneIdentified = mergeReferenced( bankRefs, usageHeldPaths(records, std::unordered_set{}, false)); const std::vector orphansNone = pruneOrphans(present, refsNoneIdentified, owned); CHECK(orphansNone.size() == 1); CHECK(orphansNone[0] == "orphan.wav"); // Stale-record cleanup still works when the matcher is demonstrably alive: another // instance is identified on a different track, the record's own track is gone -> // the record no longer counts -> held.wav is reclaimable again. const std::vector refsAfterDelete = mergeReferenced( bankRefs, usageHeldPaths(records, std::unordered_set{"{OTHER}"}, true)); CHECK(pruneOrphans(present, refsAfterDelete, owned).size() == 2); } static void testMergeReferencedOrderAndDedup() { const std::vector a = {"p1.wav", "p2.wav"}; const std::vector b = {"p2.wav", "p3.wav", "p1.wav"}; const std::vector merged = mergeReferenced(a, b); CHECK(merged.size() == 3); CHECK(merged[0] == "p1.wav"); CHECK(merged[1] == "p2.wav"); CHECK(merged[2] == "p3.wav"); CHECK(mergeReferenced({}, {}).empty()); } int main() { testRoundTrip(); testRoundTripEmptyHoldsAndEmptyGuid(); testRoundTripAdversarialBytes(); testDecodeMalformed(); testPlanFreshKey(); testPlanCleanReplaceAndSkip(); testSiblingCollisionNeverDropsHolds(); testPlanUnionSkipOnlyWhenAlreadyPoisoned(); testPlanEmptyNonceNeverClaimsOwnership(); testPlanCrossTrackRemint(); testPlanOwnRecordAfterTrackMove(); testPlanUndecodableExistingRemints(); testHeldPathsLiveness(); testZeroIdentifiedProtectsAll(); testHeldPathsDedupAndEmptyPathSkip(); testTakeFxAttributedRecordIsProtected(); testUnreadableRecordAbortsPrune(); testAbortFoldReturnsProtectAllSet(); testTruncatedWalkProtectsAll(); testIdentityMatcher(); testInstanceHoldMakesPathUnprunable(); testMergeReferencedOrderAndDedup(); if (g_fail == 0) { std::printf("sample_usage_tests: all tests passed\n"); return 0; } std::printf("sample_usage_tests: %d FAILURES\n", g_fail); return 1; }