project-directories.test.ts 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. import { describe, expect } from "bun:test"
  2. import { Effect, Schema } from "effect"
  3. import { Database } from "@opencode-ai/core/database/database"
  4. import { LayerNode } from "@opencode-ai/core/effect/layer-node"
  5. import { AppNodeBuilder } from "@opencode-ai/core/effect/app-node-builder"
  6. import { Project } from "@opencode-ai/core/project"
  7. import { ProjectDirectories } from "@opencode-ai/core/project/directories"
  8. import { ProjectTable } from "@opencode-ai/core/project/sql"
  9. import { AbsolutePath } from "@opencode-ai/core/schema"
  10. import { testEffect } from "./lib/effect"
  11. const it = testEffect(AppNodeBuilder.build(LayerNode.group([Database.node, ProjectDirectories.node])))
  12. const projectID = Project.ID.make("project-directories")
  13. const directory = AbsolutePath.make("/tmp/project-directories")
  14. function setup() {
  15. return Database.Service.use(({ db }) =>
  16. db
  17. .insert(ProjectTable)
  18. .values({ id: projectID, worktree: directory, sandboxes: [], time_created: 1, time_updated: 1 })
  19. .onConflictDoNothing()
  20. .run()
  21. .pipe(Effect.orDie),
  22. )
  23. }
  24. describe("ProjectDirectories", () => {
  25. it.effect("decodes directory schemas", () =>
  26. Effect.sync(() => {
  27. expect(Schema.decodeUnknownSync(ProjectDirectories.ListInput)({ projectID })).toEqual({ projectID })
  28. expect(Schema.decodeUnknownSync(ProjectDirectories.ListOutput)([{ directory }])).toEqual([{ directory }])
  29. }),
  30. )
  31. it.effect("creates once and ignores conflicts", () =>
  32. Effect.gen(function* () {
  33. yield* setup()
  34. const service = yield* ProjectDirectories.Service
  35. expect(yield* service.create({ projectID, directory })).toBe(true)
  36. expect(yield* service.create({ projectID, directory, strategy: "git_worktree" })).toBe(false)
  37. expect(yield* service.list(projectID)).toEqual([{ directory, strategy: undefined }])
  38. }),
  39. )
  40. it.effect("returns an empty list for missing projects", () =>
  41. Effect.gen(function* () {
  42. const service = yield* ProjectDirectories.Service
  43. expect(yield* service.list(Project.ID.make("missing-project"))).toEqual([])
  44. }),
  45. )
  46. it.effect("replaces the strategy when requested", () =>
  47. Effect.gen(function* () {
  48. yield* setup()
  49. const service = yield* ProjectDirectories.Service
  50. yield* service.create({ projectID, directory, strategy: "old/strategy" })
  51. expect(yield* service.create({ projectID, directory, strategy: "new/strategy", behavior: "replace" })).toBe(true)
  52. expect(yield* service.create({ projectID, directory, strategy: "new/strategy", behavior: "replace" })).toBe(false)
  53. expect(yield* service.create({ projectID, directory, behavior: "replace" })).toBe(true)
  54. expect(yield* service.create({ projectID, directory, behavior: "replace" })).toBe(false)
  55. expect(yield* service.create({ projectID, directory, strategy: "new/strategy", behavior: "replace" })).toBe(true)
  56. expect(yield* service.list(projectID)).toEqual([{ directory, strategy: "new/strategy" }])
  57. }),
  58. )
  59. })