From 76945bf3c86e3d812b21efea8617bd546d91a63a Mon Sep 17 00:00:00 2001 From: Sisyphus Date: Sat, 18 Apr 2026 14:09:32 +0900 Subject: [PATCH] test(rules-injector): cover project-root-finder memoization Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus --- .../project-root-finder.test.ts | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 src/hooks/rules-injector/project-root-finder.test.ts diff --git a/src/hooks/rules-injector/project-root-finder.test.ts b/src/hooks/rules-injector/project-root-finder.test.ts new file mode 100644 index 000000000..35d442290 --- /dev/null +++ b/src/hooks/rules-injector/project-root-finder.test.ts @@ -0,0 +1,47 @@ +import { afterEach, describe, expect, it, mock } from "bun:test"; + +describe("findProjectRoot", () => { + afterEach(async () => { + const actualFileSystem = await import("node:fs"); + mock.module("node:fs", () => actualFileSystem); + }); + + it("memoizes repeated lookups for the same start path and resets on cache clear", async () => { + // given + const actualFileSystem = await import("node:fs"); + const projectRoot = "/workspace/project"; + const startPath = `${projectRoot}/src/file.ts`; + const packageJsonPath = `${projectRoot}/package.json`; + + const existsSyncSpy = mock((path: string) => path === packageJsonPath); + const statSyncSpy = mock(() => ({ isDirectory: () => false })); + + mock.module("node:fs", () => ({ + ...actualFileSystem, + existsSync: existsSyncSpy, + statSync: statSyncSpy, + })); + + const { clearProjectRootCache, findProjectRoot } = await import( + `./project-root-finder.ts?memoization=${Date.now()}` + ); + + // when + const firstResult = findProjectRoot(startPath); + const firstExistsSyncCallCount = existsSyncSpy.mock.calls.length; + + const secondResult = findProjectRoot(startPath); + const secondExistsSyncCallCount = existsSyncSpy.mock.calls.length; + + clearProjectRootCache(); + const thirdResult = findProjectRoot(startPath); + + // then + expect(firstResult).toBe(projectRoot); + expect(secondResult).toBe(projectRoot); + expect(thirdResult).toBe(projectRoot); + expect(firstExistsSyncCallCount).toBeGreaterThan(0); + expect(secondExistsSyncCallCount).toBe(firstExistsSyncCallCount); + expect(existsSyncSpy).toHaveBeenCalledTimes(firstExistsSyncCallCount * 2); + }); +});