'use strict'; const { test } = require('node:test'); const assert = require('node:assert'); const { runExclusive } = require('./async-guard'); // A controllable promise so a test can hold an operation "in flight". function deferred() { let resolve, reject; const promise = new Promise((res, rej) => { resolve = res; reject = rej; }); return { promise, resolve, reject }; } test('runs fn and returns its resolved value', async () => { const set = new Set(); const out = await runExclusive(set, 'a', async () => 42); assert.strictEqual(out, 42); assert.strictEqual(set.size, 0, 'key freed after success'); }); test('skips a second concurrent call for the same key (fn runs once)', async () => { const set = new Set(); let calls = 0; const d = deferred(); const first = runExclusive(set, 'k', async () => { calls++; await d.promise; return 'first'; }); // Second call while the first is still in flight — must be a no-op. const second = await runExclusive(set, 'k', async () => { calls++; return 'second'; }); assert.strictEqual(second, undefined, 'skipped call resolves to undefined'); assert.strictEqual(calls, 1, 'fn invoked only once'); d.resolve(); assert.strictEqual(await first, 'first'); }); test('different keys run in parallel', async () => { const set = new Set(); const dA = deferred(); const dB = deferred(); let aDone = false; const a = runExclusive(set, 'A', async () => { await dA.promise; aDone = true; return 'A'; }); const b = runExclusive(set, 'B', async () => { await dB.promise; return 'B'; }); assert.strictEqual(set.size, 2, 'both keys in flight at once'); // B can finish before A — proves they are not serialized. dB.resolve(); assert.strictEqual(await b, 'B'); assert.strictEqual(aDone, false, 'A still in flight while B completed'); dA.resolve(); assert.strictEqual(await a, 'A'); assert.strictEqual(set.size, 0); }); test('frees the key after failure so a retry is possible', async () => { const set = new Set(); await assert.rejects( runExclusive(set, 'x', async () => { throw new Error('boom'); }), /boom/, ); assert.strictEqual(set.has('x'), false, 'key freed even on throw'); // Retry now succeeds because the key was released. const out = await runExclusive(set, 'x', async () => 'ok'); assert.strictEqual(out, 'ok'); }); test('supports a synchronous fn', async () => { const set = new Set(); const out = await runExclusive(set, 's', () => 7); assert.strictEqual(out, 7); assert.strictEqual(set.size, 0); });