import { Lock } from './lock.class';
import { expect } from 'chai';
import sinon from 'sinon';

/*
 * For this test one must imagine two independent actions happening
 * at the same time. This will be siginfied in comments as `A` and `B`.
 */
describe('Lock', () => {

    const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
    let lock;
    beforeEach(() => {
        lock = new Lock();
    });

    it('should not call subsequent methods when locked', async () => {
        const spy = sinon.spy();

        // Start critical section A.
        await lock.acquire();

        // B tries to acquire lock.
        (async () => {
            await lock.acquire();
            spy();
        })();

        await sleep(500);
        expect(spy.called).to.equal(false, 'Method should not have been called during outer critical section');

        // End critical section A.
        lock.release();
    });

    it('should call subsequent methods after lock was released', async () => {
        const spy = sinon.spy();

        // Start critical section A.
        await lock.acquire();

        // B tries to acquire lock.
        (async () => {
            await lock.acquire();
            spy();
        })();

        // End critical section A.
        expect(spy.called).to.equal(false, 'Method should not have been called during outer critical section');
        lock.release();

        await sleep(500);
        expect(spy.called).to.equal(true, 'Method should have been called after critical section');
    });

    it('should provide a convinient lock method', async () => {
        const spy = sinon.spy();

        // Start critical section A.
        await lock.acquire();

        // B tries to acquire the lock.
        lock.lock(spy);

        // End critical section A.
        expect(spy.called).to.equal(false, 'Method should not have been called during outer critical section');
        lock.release();

        await sleep(500);
        expect(spy.called).to.equal(true, 'Method should have been called after critical section');
    });

});
