| 1 | import assert from "node:assert/strict"; |
| 2 | import { createSubscriptionScope } from "../lib/subscriptionScope"; |
| 3 | |
| 4 | const effects: string[] = []; |
| 5 | const queued: Array<() => void> = []; |
| 6 | let subscriptions = 0; |
| 7 | const scope = createSubscriptionScope((delta) => { subscriptions += delta; }); |
| 8 | scope.listen((listener: () => void) => { |
| 9 | queued.push(listener); |
| 10 | return () => { queued[1](); throw new Error("first unsubscribe failed"); }; |
| 11 | }, () => { effects.push("old-first"); }); |
| 12 | scope.listen((listener: () => void) => { |
| 13 | queued.push(listener); |
| 14 | return () => { effects.push("second-released"); }; |
| 15 | }, () => { effects.push("old-second"); }); |
| 16 | assert.equal(subscriptions, 2); |
| 17 | assert.throws(() => scope.dispose(), /first unsubscribe failed/); |
| 18 | assert.equal(scope.size, 0); |
| 19 | assert.equal(subscriptions, 0, "all subscriptions release even if one source cleanup fails"); |
| 20 | assert.deepEqual(effects, ["second-released"], "cleanup revokes all listeners before touching the source"); |
| 21 | const replacement = createSubscriptionScope(); |
| 22 | replacement.listen((listener: () => void) => { queued.push(listener); return () => {}; }, () => { effects.push("new"); }); |
| 23 | for (const listener of queued) listener(); |
| 24 | assert.deepEqual(effects, ["second-released", "new"], "queued old notifications cannot acquire replacement rights"); |
| 25 | scope.dispose(); |
| 26 | assert.equal(subscriptions, 0, "repeated disposal cannot decrement accounting twice"); |
| 27 | replacement.dispose(); |
| 28 | const synchronous = createSubscriptionScope((delta) => { subscriptions += delta; }); |
| 29 | synchronous.listen((listener: () => void) => { listener(); return () => {}; }, () => synchronous.dispose()); |
| 30 | assert.equal(synchronous.size, 0); |
| 31 | assert.equal(subscriptions, 0, "disposal during synchronous registration cannot leak a lease"); |
| 32 | console.log("PASS subscription scopes fence queued notifications and release all resources"); |
| 33 |