import { describe, expect, it } from 'vitest';
import { AsyncMutex } from './async-mutex.js';

const tick = () => new Promise((r) => setTimeout(r, 5));

describe('AsyncMutex', () => {
  it('runs exclusive sections serially, never overlapping', async () => {
    const m = new AsyncMutex();
    const log: string[] = [];
    const section = (name: string) => m.runExclusive(async () => {
      log.push(`${name}:enter`);
      await tick();
      log.push(`${name}:exit`);
    });
    await Promise.all([section('A'), section('B'), section('C')]);
    // every enter is immediately followed by its own exit (no interleave)
    expect(log).toEqual(['A:enter', 'A:exit', 'B:enter', 'B:exit', 'C:enter', 'C:exit']);
  });

  it('continues the chain after a rejection', async () => {
    const m = new AsyncMutex();
    const a = m.runExclusive(async () => { throw new Error('boom'); });
    await expect(a).rejects.toThrow('boom');
    const b = await m.runExclusive(async () => 42);
    expect(b).toBe(42);
  });

  it('returns the section result', async () => {
    const m = new AsyncMutex();
    expect(await m.runExclusive(async () => 'ok')).toBe('ok');
  });
});
