diff --git a/src/common/utils/get-startable-stoppable.test.ts b/src/common/utils/get-startable-stoppable.test.ts new file mode 100644 index 0000000000..8ed213c265 --- /dev/null +++ b/src/common/utils/get-startable-stoppable.test.ts @@ -0,0 +1,68 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getStartableStoppable } from "./get-startable-stoppable"; + +describe("getStartableStoppable", () => { + let stopMock: jest.Mock<() => void>; + let startMock: jest.Mock<() => () => void>; + let actual: { stop: () => void; start: () => void }; + + beforeEach(() => { + stopMock = jest.fn(); + startMock = jest.fn(() => stopMock); + + actual = getStartableStoppable(startMock); + }); + + it("does not start yet", () => { + expect(startMock).not.toHaveBeenCalled(); + }); + + it("does not stop yet", () => { + expect(stopMock).not.toHaveBeenCalled(); + }); + + it("when stopping before ever starting, throws", () => { + expect(() => { + actual.stop(); + }).toThrow("Tried to stop something that has not started yet."); + }); + + describe("when started", () => { + beforeEach(() => { + actual.start(); + }); + + it("starts", () => { + expect(startMock).toHaveBeenCalled(); + }); + + it("does not stop yet", () => { + expect(stopMock).not.toHaveBeenCalled(); + }); + + describe("when stopped", () => { + beforeEach(() => { + actual.stop(); + }); + + it("stops", () => { + expect(stopMock).toHaveBeenCalled(); + }); + + it("when stopped again, throws", () => { + expect(() => { + actual.stop(); + }).toThrow("Tried to stop something that has already stopped."); + }); + + it("when started again, throws for restart being YAGNI with logical blind spots", () => { + expect(() => { + actual.start(); + }).toThrow("Tried to restart something that has stopped."); + }); + }); + }); +}); diff --git a/src/common/utils/get-startable-stoppable.ts b/src/common/utils/get-startable-stoppable.ts new file mode 100644 index 0000000000..a28897fb27 --- /dev/null +++ b/src/common/utils/get-startable-stoppable.ts @@ -0,0 +1,37 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +export const getStartableStoppable = ( + startAndGetStopCallback: () => () => void, +) => { + let dispose: () => void; + let stopped = false; + let started = false; + + return { + start: () => { + if (started) { + throw new Error("Tried to restart something that has stopped."); + } + + dispose = startAndGetStopCallback(); + + started = true; + }, + + stop: () => { + if (!started) { + throw new Error("Tried to stop something that has not started yet."); + } + + if (stopped) { + throw new Error("Tried to stop something that has already stopped."); + } + + dispose(); + + stopped = true; + }, + }; +};