diff --git a/packages/opencode/test/altimate/fingerprint-detect.test.ts b/packages/opencode/test/altimate/fingerprint-detect.test.ts index 70677147b..e61134018 100644 --- a/packages/opencode/test/altimate/fingerprint-detect.test.ts +++ b/packages/opencode/test/altimate/fingerprint-detect.test.ts @@ -107,4 +107,37 @@ describe("Fingerprint.detect: file-based project detection", () => { expect(result.tags).toContain("dbt") expect(result.tags).toContain("sql") }) + + test("detects dbt-packages from dbt_packages.yml", async () => { + await using tmp = await tmpdir() + await fs.writeFile(path.join(tmp.path, "dbt_packages.yml"), "packages:\n - package: dbt-labs/dbt_utils\n") + const result = await Fingerprint.detect(tmp.path) + expect(result.tags).toContain("dbt-packages") + }) + + test("combined project detects multiple technologies", async () => { + await using tmp = await tmpdir() + await fs.writeFile(path.join(tmp.path, "dbt_project.yml"), "name: test\n") + await fs.writeFile(path.join(tmp.path, "airflow.cfg"), "[core]\n") + await fs.writeFile(path.join(tmp.path, "databricks.yml"), "bundle:\n name: test\n") + const result = await Fingerprint.detect(tmp.path) + expect(result.tags).toContain("dbt") + expect(result.tags).toContain("airflow") + expect(result.tags).toContain("databricks") + expect(result.tags).toContain("data-engineering") + }) +}) + +describe("Fingerprint.refresh", () => { + test("invalidates cache and re-detects new files", async () => { + await using tmp = await tmpdir() + // Initial detect — no tags + const r1 = await Fingerprint.detect(tmp.path) + expect(r1.tags).toEqual([]) + // Add dbt_project.yml after initial detect + await fs.writeFile(path.join(tmp.path, "dbt_project.yml"), "name: test\n") + // refresh() should invalidate cache and pick up the new file + const r3 = await Fingerprint.refresh() + expect(r3.tags).toContain("dbt") + }) }) diff --git a/packages/opencode/test/util/context.test.ts b/packages/opencode/test/util/context.test.ts new file mode 100644 index 000000000..0d94dad85 --- /dev/null +++ b/packages/opencode/test/util/context.test.ts @@ -0,0 +1,45 @@ +import { describe, test, expect } from "bun:test" +import { Context } from "../../src/util/context" + +describe("Context: provide and use", () => { + test("use() returns provided value", () => { + const ctx = Context.create<{ id: number }>("test") + const result = ctx.provide({ id: 42 }, () => ctx.use()) + expect(result).toEqual({ id: 42 }) + }) + + test("use() throws NotFound outside provider", () => { + const ctx = Context.create<{ id: number }>("myctx") + expect(() => ctx.use()).toThrow(Context.NotFound) + expect(() => ctx.use()).toThrow("No context found for myctx") + }) + + test("nested provide uses innermost value", () => { + const ctx = Context.create<{ val: string }>("nest") + const result = ctx.provide({ val: "outer" }, () => + ctx.provide({ val: "inner" }, () => ctx.use().val), + ) + expect(result).toBe("inner") + }) + + test("provide passes through callback return value", () => { + const ctx = Context.create<{ val: string }>("passthrough") + const result = ctx.provide({ val: "x" }, () => 42) + expect(result).toBe(42) + }) + + test("concurrent contexts are isolated", async () => { + const ctx = Context.create<{ id: number }>("concurrent") + const results = await Promise.all([ + ctx.provide({ id: 1 }, async () => { + await new Promise((r) => setTimeout(r, 10)) + return ctx.use().id + }), + ctx.provide({ id: 2 }, async () => { + await new Promise((r) => setTimeout(r, 5)) + return ctx.use().id + }), + ]) + expect(results).toEqual([1, 2]) + }) +})