import { Signal } from '../../../../lib/experimental/core/Signal'; describe('experimental.core.Signal', () => { describe('constuctor', () => { it('can be created with new invokation', () => { const signal = new Signal(); expect(signal).toBeInstanceOf(Signal); expect(signal.constructor).toBe(Signal); expect(signal.slotCount()).toBe(0); }); it('can be created with function call invokation', () => { const signal = Signal(); expect(signal).toBeInstanceOf(Signal); expect(signal.constructor).toBe(Signal); expect(signal.slotCount()).toBe(0); }); }); describe('connect', () => { // // exceptions // it('should throw an exception if slot is not function', () => { const signal = Signal(); expect(() => { signal.connect('defently not a function'); }).toThrowError(TypeError); }); // // no slots // it('should not emit signals without slots', () => { const signal = Signal(); expect(signal.slotCount()).toBe(0); expect(signal()).toBeFalsy(); }); // // one slot // it('should emit signals with one slot without arguments', (done) => { const signal = Signal(); signal.connect(function (...args: any[]) { expect(args.length).toBe(0); done(); }); expect(signal.slotCount()).toBe(1); expect(signal()).toBeTruthy(); }); it('should emit signals with one slot with one argument', (done) => { const signal = Signal<(x: number) => void>(); signal.connect(function (x: number) { expect(x).toBe(1); done(); }); expect(signal.slotCount()).toBe(1); expect(signal(1)).toBeTruthy(); }); it('should emit signals with one slot with two arguments', (done) => { const signal = Signal<(x: number, y: number) => void>(); signal.connect(function (x: number, y: number) { expect(x).toBe(1); expect(y).toBe(2); done(); }); expect(signal.slotCount()).toBe(1); expect(signal(1, 2)).toBeTruthy(); }); it('should emit signals with one slot with three arguments', (done) => { const signal = Signal<(x: number, y: number, z: number) => void>(); signal.connect(function (x: number, y: number, z: number) { expect(x).toBe(1); expect(y).toBe(2); expect(z).toBe(3); done(); }); expect(signal.slotCount()).toBe(1); expect(signal(1, 2, 3)).toBeTruthy(); }); it('should emit signals with one slot with many arguments', (done) => { const signal = Signal<(a1: number, a2: number, a3: number, a4: number) => void>(); signal.connect(function (a1: number, a2: number, a3: number, a4: number) { expect(a1).toBe(1); expect(a2).toBe(2); expect(a3).toBe(3); expect(a4).toBe(4); done(); }); expect(signal.slotCount()).toBe(1); expect(signal(1, 2, 3, 4)).toBeTruthy(); }); // // two slots // it('should emit signals with two slots without arguments', () => { expect.assertions(2 + 2); const signal = Signal(); signal.connect(function (...args: any[]) { expect(args.length).toBe(0); }); signal.connect(function (...args: any[]) { expect(args.length).toBe(0); }); expect(signal.slotCount()).toBe(2); expect(signal()).toBeTruthy(); }); it('should emit signals with two slots with one argument', () => { expect.assertions(2 + 2); const signal = Signal<(x: number) => void>(); signal.connect(function (x: number) { expect(x).toBe(1); }); signal.connect(function (x: number) { expect(x).toBe(1); }); expect(signal.slotCount()).toBe(2); expect(signal(1)).toBeTruthy(); }); it('should emit signals with two slots with two arguments', () => { expect.assertions(2 * 2 + 2); const signal = Signal<(x: number, y: number) => void>(); signal.connect(function (x: number, y: number) { expect(x).toBe(1); expect(y).toBe(2); }); signal.connect(function (x: number, y: number) { expect(x).toBe(1); expect(y).toBe(2); }); expect(signal.slotCount()).toBe(2); expect(signal(1, 2)).toBeTruthy(); }); it('should emit signals with two slots with three arguments', () => { expect.assertions(2 * 3 + 2); const signal = Signal<(x: number, y: number, z: number) => void>(); signal.connect(function (x: number, y: number, z: number) { expect(x).toBe(1); expect(y).toBe(2); expect(z).toBe(3); }); signal.connect(function (x: number, y: number, z: number) { expect(x).toBe(1); expect(y).toBe(2); expect(z).toBe(3); }); expect(signal.slotCount()).toBe(2); expect(signal(1, 2, 3)).toBeTruthy(); }); it('should emit signals with two slots with many arguments', () => { expect.assertions(2 * 4 + 2); const signal = Signal<(a1: number, a2: number, a3: number, a4: number) => void>(); signal.connect(function (a1: number, a2: number, a3: number, a4: number) { expect(a1).toBe(1); expect(a2).toBe(2); expect(a3).toBe(3); expect(a4).toBe(4); }); signal.connect(function (a1: number, a2: number, a3: number, a4: number) { expect(a1).toBe(1); expect(a2).toBe(2); expect(a3).toBe(3); expect(a4).toBe(4); }); expect(signal.slotCount()).toBe(2); expect(signal(1, 2, 3, 4)).toBeTruthy(); }); // // many slots // it('should emit signals with many slots without arguments', () => { expect.assertions(3 + 2); const signal = Signal(); signal.connect(function (...args: any[]) { expect(args.length).toBe(0); }); signal.connect(function (...args: any[]) { expect(args.length).toBe(0); }); signal.connect(function (...args: any[]) { expect(args.length).toBe(0); }); expect(signal.slotCount()).toBe(3); expect(signal()).toBeTruthy(); }); it('should emit signals with many slots with one argument', () => { expect.assertions(3 + 2); const signal = Signal<(x: number) => void>(); signal.connect(function (x: number) { expect(x).toBe(1); }); signal.connect(function (x: number) { expect(x).toBe(1); }); signal.connect(function (x: number) { expect(x).toBe(1); }); expect(signal.slotCount()).toBe(3); expect(signal(1)).toBeTruthy(); }); it('should emit signals with many slots with two arguments', () => { expect.assertions(3 * 2 + 2); const signal = Signal<(x: number, y: number) => void>(); signal.connect(function (x: number, y: number) { expect(x).toBe(1); expect(y).toBe(2); }); signal.connect(function (x: number, y: number) { expect(x).toBe(1); expect(y).toBe(2); }); signal.connect(function (x: number, y: number) { expect(x).toBe(1); expect(y).toBe(2); }); expect(signal.slotCount()).toBe(3); expect(signal(1, 2)).toBeTruthy(); }); it('should emit signals with many slots with three arguments', () => { expect.assertions(3 * 3 + 2); const signal = Signal<(x: number, y: number, z: number) => void>(); signal.connect(function (x: number, y: number, z: number) { expect(x).toBe(1); expect(y).toBe(2); expect(z).toBe(3); }); signal.connect(function (x: number, y: number, z: number) { expect(x).toBe(1); expect(y).toBe(2); expect(z).toBe(3); }); signal.connect(function (x: number, y: number, z: number) { expect(x).toBe(1); expect(y).toBe(2); expect(z).toBe(3); }); expect(signal.slotCount()).toBe(3); expect(signal(1, 2, 3)).toBeTruthy(); }); it('should emit signals with many slots with many arguments', () => { expect.assertions(3 * 4 + 2); const signal = Signal<(a1: number, a2: number, a3: number, a4: number) => void>(); signal.connect(function (a1: number, a2: number, a3: number, a4: number) { expect(a1).toBe(1); expect(a2).toBe(2); expect(a3).toBe(3); expect(a4).toBe(4); }); signal.connect(function (a1: number, a2: number, a3: number, a4: number) { expect(a1).toBe(1); expect(a2).toBe(2); expect(a3).toBe(3); expect(a4).toBe(4); }); signal.connect(function (a1: number, a2: number, a3: number, a4: number) { expect(a1).toBe(1); expect(a2).toBe(2); expect(a3).toBe(3); expect(a4).toBe(4); }); expect(signal.slotCount()).toBe(3); expect(signal(1, 2, 3, 4)).toBeTruthy(); }); }); describe('disconnect', () => { // // exceptions // it('should throw an exception if slot is not function', () => { const signal = Signal(); expect(() => { signal.disconnect('defently not a function'); }).toThrowError(TypeError); }); // // empty case // it('should do nothing with zero slots', () => { const signal = Signal(); expect(signal.slotCount()).toBe(0); signal.disconnect(function () { }); expect(signal.slotCount()).toBe(0); }); // // one to zero case // it('should disconnect one connected slot', () => { expect.assertions(1 + 2); const signal = Signal<(x: number) => void>(); function f(x: number) { expect(x).toBe(1); } signal.connect(f); expect(signal.slotCount()).toBe(1); signal(1); signal.disconnect(f); expect(signal.slotCount()).toBe(0); signal(2); }); it('should not disconnect not connected slot', () => { expect.assertions(2 + 2); const signal = Signal<(x: number) => void>(); function f(x: number) { expect(x).toBe(1); } function g() { } signal.connect(f); expect(signal.slotCount()).toBe(1); signal(1); signal.disconnect(g); expect(signal.slotCount()).toBe(1); signal(1); }); // // many to any case // it('should disconnect many connected slots', () => { expect.assertions(3 + 3); const signal = Signal<(x: number) => void>(); function f(x: number) { expect(x).toBe(1); } function g(x: number) { expect(x).toBe(1); } signal.connect(f); signal.connect(g); expect(signal.slotCount()).toBe(2); signal(1); signal.disconnect(f); expect(signal.slotCount()).toBe(1); signal(1); signal.disconnect(g); expect(signal.slotCount()).toBe(0); signal(2); }); it('should not disconnect not connected slot', () => { expect.assertions(4 + 2); const signal = Signal<(x: number) => void>(); function f(x: number) { expect(x).toBe(1); } function g(x: number) { expect(x).toBe(1); } function h() { } signal.connect(f); signal.connect(g); expect(signal.slotCount()).toBe(2); signal(1); signal.disconnect(h); expect(signal.slotCount()).toBe(2); signal(1); }); it('should disconnect repeatedly connected one slot', () => { expect.assertions(2 + 2); const signal = Signal<(x: number) => void>(); function f(x: number) { expect(x).toBe(1); } signal.connect(f); signal.connect(f); expect(signal.slotCount()).toBe(2); signal(1); signal.disconnect(f); expect(signal.slotCount()).toBe(0); signal(2); }); }); describe('disconnectAll', () => { it('should disconnect all slots', () => { expect.assertions(2 + 2); const signal = Signal<(x: number) => void>(); function f(x: number) { expect(x).toBe(1); } function g(x: number) { expect(x).toBe(1); } signal.connect(f); signal.connect(g); expect(signal.slotCount()).toBe(2); signal(1); signal.disconnectAll(); signal(2); expect(signal.slotCount()).toBe(0); }); }); describe('once', () => { it('should throw an exception if slot is not function', () => { const signal = Signal(); expect(() => { signal.once('defently not a function'); }).toThrowError(TypeError); }); it('should be called once', () => { expect.assertions(1 + 2); const signal = Signal<(x: number) => void>(); signal.once(function (x: number) { expect(x).toBe(1); }); expect(signal.slotCount()).toBe(1); signal(1); expect(signal.slotCount()).toBe(0); signal(2); }); it('should be removable', () => { expect.assertions(2); const signal = Signal<(x: number) => void>(); function f(x: number) { expect(x).toBe(0); } signal.once(f); expect(signal.slotCount()).toBe(1); signal.disconnect(f); expect(signal.slotCount()).toBe(0); signal(1); }); it('should not fire from self', () => { expect.assertions(1 + 2); const signal = Signal<(x: number) => void>(); function f(x: number) { expect(x).toBe(1); signal(3); } signal.once(f); expect(signal.slotCount()).toBe(1); signal(1); expect(signal.slotCount()).toBe(0); signal(2); }); }); });