chore: initialize qiming workspace repository
This commit is contained in:
272
qimingcode/packages/opencode/test/format/format.test.ts
Normal file
272
qimingcode/packages/opencode/test/format/format.test.ts
Normal file
@@ -0,0 +1,272 @@
|
||||
import { NodeFileSystem } from "@effect/platform-node"
|
||||
import { describe, expect } from "bun:test"
|
||||
import { Effect, Layer } from "effect"
|
||||
import { provideTmpdirInstance } from "../fixture/fixture"
|
||||
import { testEffect } from "../lib/effect"
|
||||
import { CrossSpawnSpawner } from "@opencode-ai/core/cross-spawn-spawner"
|
||||
import { Format } from "../../src/format"
|
||||
import * as Formatter from "../../src/format/formatter"
|
||||
|
||||
const it = testEffect(Layer.mergeAll(Format.defaultLayer, CrossSpawnSpawner.defaultLayer, NodeFileSystem.layer))
|
||||
|
||||
describe("Format", () => {
|
||||
it.live("status() returns empty list when no formatters are configured", () =>
|
||||
provideTmpdirInstance(() =>
|
||||
Format.Service.use((fmt) =>
|
||||
Effect.gen(function* () {
|
||||
expect(yield* fmt.status()).toEqual([])
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
it.live("status() returns built-in formatters when formatter is true", () =>
|
||||
provideTmpdirInstance(
|
||||
() =>
|
||||
Format.Service.use((fmt) =>
|
||||
Effect.gen(function* () {
|
||||
const statuses = yield* fmt.status()
|
||||
const gofmt = statuses.find((item) => item.name === "gofmt")
|
||||
expect(gofmt).toBeDefined()
|
||||
expect(gofmt!.extensions).toContain(".go")
|
||||
}),
|
||||
),
|
||||
{
|
||||
config: {
|
||||
formatter: true,
|
||||
},
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
it.live("status() keeps built-in formatters when config object is provided", () =>
|
||||
provideTmpdirInstance(
|
||||
() =>
|
||||
Format.Service.use((fmt) =>
|
||||
Effect.gen(function* () {
|
||||
const statuses = yield* fmt.status()
|
||||
const gofmt = statuses.find((item) => item.name === "gofmt")
|
||||
const mix = statuses.find((item) => item.name === "mix")
|
||||
expect(gofmt).toBeDefined()
|
||||
expect(gofmt!.extensions).toContain(".go")
|
||||
expect(mix).toBeDefined()
|
||||
}),
|
||||
),
|
||||
{
|
||||
config: {
|
||||
formatter: {
|
||||
gofmt: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
it.live("status() excludes formatters marked as disabled in config", () =>
|
||||
provideTmpdirInstance(
|
||||
() =>
|
||||
Format.Service.use((fmt) =>
|
||||
Effect.gen(function* () {
|
||||
const statuses = yield* fmt.status()
|
||||
const gofmt = statuses.find((item) => item.name === "gofmt")
|
||||
const mix = statuses.find((item) => item.name === "mix")
|
||||
expect(gofmt).toBeUndefined()
|
||||
expect(mix).toBeDefined()
|
||||
}),
|
||||
),
|
||||
{
|
||||
config: {
|
||||
formatter: {
|
||||
gofmt: { disabled: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
it.live("status() excludes uv when ruff is disabled", () =>
|
||||
provideTmpdirInstance(
|
||||
() =>
|
||||
Format.Service.use((fmt) =>
|
||||
Effect.gen(function* () {
|
||||
const statuses = yield* fmt.status()
|
||||
expect(statuses.find((item) => item.name === "ruff")).toBeUndefined()
|
||||
expect(statuses.find((item) => item.name === "uv")).toBeUndefined()
|
||||
}),
|
||||
),
|
||||
{
|
||||
config: {
|
||||
formatter: {
|
||||
ruff: { disabled: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
it.live("status() excludes ruff when uv is disabled", () =>
|
||||
provideTmpdirInstance(
|
||||
() =>
|
||||
Format.Service.use((fmt) =>
|
||||
Effect.gen(function* () {
|
||||
const statuses = yield* fmt.status()
|
||||
expect(statuses.find((item) => item.name === "ruff")).toBeUndefined()
|
||||
expect(statuses.find((item) => item.name === "uv")).toBeUndefined()
|
||||
}),
|
||||
),
|
||||
{
|
||||
config: {
|
||||
formatter: {
|
||||
uv: { disabled: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
it.live("service initializes without error", () => provideTmpdirInstance(() => Format.Service.use(() => Effect.void)))
|
||||
|
||||
it.live("file() returns false when no formatter runs", () =>
|
||||
provideTmpdirInstance(
|
||||
(dir) =>
|
||||
Effect.gen(function* () {
|
||||
const file = `${dir}/test.txt`
|
||||
yield* Effect.promise(() => Bun.write(file, "x"))
|
||||
|
||||
const formatted = yield* Format.Service.use((fmt) => fmt.file(file))
|
||||
expect(formatted).toBe(false)
|
||||
}),
|
||||
{
|
||||
config: {
|
||||
formatter: false,
|
||||
},
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
it.live("status() initializes formatter state per directory", () =>
|
||||
Effect.gen(function* () {
|
||||
const a = yield* provideTmpdirInstance(() => Format.Service.use((fmt) => fmt.status()), {
|
||||
config: { formatter: false },
|
||||
})
|
||||
const b = yield* provideTmpdirInstance(() => Format.Service.use((fmt) => fmt.status()), {
|
||||
config: {
|
||||
formatter: true,
|
||||
},
|
||||
})
|
||||
|
||||
expect(a).toEqual([])
|
||||
expect(b.find((item) => item.name === "gofmt")).toBeDefined()
|
||||
}),
|
||||
)
|
||||
|
||||
it.live("runs enabled checks for matching formatters in parallel", () =>
|
||||
provideTmpdirInstance(
|
||||
(path) =>
|
||||
Effect.gen(function* () {
|
||||
const file = `${path}/test.parallel`
|
||||
yield* Effect.promise(() => Bun.write(file, "x"))
|
||||
|
||||
const one = {
|
||||
extensions: Formatter.gofmt.extensions,
|
||||
enabled: Formatter.gofmt.enabled,
|
||||
}
|
||||
const two = {
|
||||
extensions: Formatter.mix.extensions,
|
||||
enabled: Formatter.mix.enabled,
|
||||
}
|
||||
|
||||
let active = 0
|
||||
let max = 0
|
||||
|
||||
yield* Effect.acquireUseRelease(
|
||||
Effect.sync(() => {
|
||||
Formatter.gofmt.extensions = [".parallel"]
|
||||
Formatter.mix.extensions = [".parallel"]
|
||||
Formatter.gofmt.enabled = async () => {
|
||||
active++
|
||||
max = Math.max(max, active)
|
||||
await Bun.sleep(20)
|
||||
active--
|
||||
return ["sh", "-c", "true"]
|
||||
}
|
||||
Formatter.mix.enabled = async () => {
|
||||
active++
|
||||
max = Math.max(max, active)
|
||||
await Bun.sleep(20)
|
||||
active--
|
||||
return ["sh", "-c", "true"]
|
||||
}
|
||||
}),
|
||||
() =>
|
||||
Format.Service.use((fmt) =>
|
||||
Effect.gen(function* () {
|
||||
yield* fmt.init()
|
||||
yield* fmt.file(file)
|
||||
}),
|
||||
),
|
||||
() =>
|
||||
Effect.sync(() => {
|
||||
Formatter.gofmt.extensions = one.extensions
|
||||
Formatter.gofmt.enabled = one.enabled
|
||||
Formatter.mix.extensions = two.extensions
|
||||
Formatter.mix.enabled = two.enabled
|
||||
}),
|
||||
)
|
||||
|
||||
expect(max).toBe(2)
|
||||
}),
|
||||
{
|
||||
config: {
|
||||
formatter: {
|
||||
gofmt: {},
|
||||
mix: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
)
|
||||
|
||||
it.live("runs matching formatters sequentially for the same file", () =>
|
||||
provideTmpdirInstance(
|
||||
(path) =>
|
||||
Effect.gen(function* () {
|
||||
const file = `${path}/test.seq`
|
||||
yield* Effect.promise(() => Bun.write(file, "x"))
|
||||
|
||||
yield* Format.Service.use((fmt) =>
|
||||
Effect.gen(function* () {
|
||||
yield* fmt.init()
|
||||
expect(yield* fmt.file(file)).toBe(true)
|
||||
}),
|
||||
)
|
||||
|
||||
expect(yield* Effect.promise(() => Bun.file(file).text())).toBe("xAB")
|
||||
}),
|
||||
{
|
||||
config: {
|
||||
formatter: {
|
||||
first: {
|
||||
command: [
|
||||
"node",
|
||||
"-e",
|
||||
"const fs = require('fs'); const file = process.argv[1]; fs.writeFileSync(file, fs.readFileSync(file, 'utf8') + 'A')",
|
||||
"$FILE",
|
||||
],
|
||||
extensions: [".seq"],
|
||||
},
|
||||
second: {
|
||||
command: [
|
||||
"node",
|
||||
"-e",
|
||||
"const fs = require('fs'); const file = process.argv[1]; fs.writeFileSync(file, fs.readFileSync(file, 'utf8') + 'B')",
|
||||
"$FILE",
|
||||
],
|
||||
extensions: [".seq"],
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
),
|
||||
)
|
||||
})
|
||||
Reference in New Issue
Block a user