import { suite, test, timeout } from '@testdeck/mocha';
import { assert } from 'chai';
import * as Moq from 'typemoq';
import { Deferred } from '../../src/domain/deferred';

@suite
class DeferredTest {

	protected testInstanceMock: Moq.IMock<Deferred>;
	private get testInstance(): Deferred { return this.testInstanceMock.object; }

	public before(): void {

		this.testInstanceMock = Moq.Mock.ofType(Deferred);
		this.testInstanceMock.callBase = true;
	}

	@test
	public async untilOpen_ok_resolvingPromise(): Promise<void> {

		assert.instanceOf(this.testInstance.untilOpen(), Promise);
	}

	@test
	public async untilOpen_ok_resolvingSamePromise(): Promise<void> {

		assert.equal(this.testInstance.untilOpen(), this.testInstance.untilOpen());
	}

	@test
	@timeout(100)
	public async untilOpen_ok_resolveIfAlreadyOpen(): Promise<void> {

		this.testInstanceMock
			.setup((x) => x['isOpen'])
			.returns(() => true);
		await this.testInstance.untilOpen();
	}

	@test
	public untilOpen_ok_dontResolveIfClosed(done: any): void {

		let isOk = true;
		this.testInstanceMock
			.setup((x) => x['isOpen'])
			.returns(() => false);
		setTimeout(() => {

			if (isOk) {

				done();
			} else {

				done(new Error('Request answered while closed'));
			}
		}, 20);
		this.testInstance.untilOpen().then(() => isOk = false);
	}

	@test
	public untilOpen_ok_setResolverFunction(done: any): void {

		let isOk = true;
		this.testInstanceMock
			.setup((x) => x['isOpen'])
			.returns(() => false);
		setTimeout(() => {

			assert.typeOf(this.testInstance['isReadyCallback'], 'function');
			done();
		}, 20);
		this.testInstance.untilOpen().then(() => isOk = false);
	}

	@test
	public open_ok_setInternalState(): void {

		this.testInstance.open();
		this.testInstanceMock.verify((x) => x['isReadyCallback'](), Moq.Times.once());
		this.testInstanceMock.verify((x) => x['reset'](), Moq.Times.once());
		assert.isTrue(this.testInstance['isOpen']);
	}

	@test
	public close_ok_setInternalState(): void {

		this.testInstance.close();
		this.testInstanceMock.verify((x) => x['reset'](), Moq.Times.once());
		assert.isFalse(this.testInstance['isOpen']);
	}

	@test
	public reset_ok_setInternalState(): void {

		this.testInstance['reset']();
		assert.isFalse(this.testInstance['isOpeningPromisePresent']);
	}

}
