test(git): migrate git tests to Effect runner (#27121)
This commit is contained in:
@@ -1,71 +1,70 @@
|
|||||||
import { $ } from "bun"
|
import { $ } from "bun"
|
||||||
import { describe, expect, test } from "bun:test"
|
import { describe, expect } from "bun:test"
|
||||||
import fs from "fs/promises"
|
import fs from "fs/promises"
|
||||||
import path from "path"
|
import path from "path"
|
||||||
import { ManagedRuntime } from "effect"
|
import { Effect } from "effect"
|
||||||
import { Git } from "../../src/git"
|
import { Git } from "../../src/git"
|
||||||
import { tmpdir } from "../fixture/fixture"
|
import { tmpdir } from "../fixture/fixture"
|
||||||
|
import { testEffect } from "../lib/effect"
|
||||||
|
|
||||||
const weird = process.platform === "win32" ? "space file.txt" : "tab\tfile.txt"
|
const weird = process.platform === "win32" ? "space file.txt" : "tab\tfile.txt"
|
||||||
|
const it = testEffect(Git.defaultLayer)
|
||||||
|
|
||||||
async function withGit<T>(body: (rt: ManagedRuntime.ManagedRuntime<Git.Service, never>) => Promise<T>) {
|
const scopedTmpdir = (options?: Parameters<typeof tmpdir>[0]) =>
|
||||||
const rt = ManagedRuntime.make(Git.defaultLayer)
|
Effect.acquireRelease(
|
||||||
try {
|
Effect.promise(() => tmpdir(options)),
|
||||||
return await body(rt)
|
(tmp) => Effect.promise(() => tmp[Symbol.asyncDispose]()),
|
||||||
} finally {
|
)
|
||||||
await rt.dispose()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
describe("Git", () => {
|
describe("Git", () => {
|
||||||
test("branch() returns current branch name", async () => {
|
it.live("branch() returns current branch name", () =>
|
||||||
await using tmp = await tmpdir({ git: true })
|
Effect.gen(function* () {
|
||||||
|
const tmp = yield* scopedTmpdir({ git: true })
|
||||||
await withGit(async (rt) => {
|
const git = yield* Git.Service
|
||||||
const branch = await rt.runPromise(Git.Service.use((git) => git.branch(tmp.path)))
|
const branch = yield* git.branch(tmp.path)
|
||||||
expect(branch).toBeDefined()
|
expect(branch).toBeDefined()
|
||||||
expect(typeof branch).toBe("string")
|
expect(typeof branch).toBe("string")
|
||||||
})
|
}),
|
||||||
})
|
)
|
||||||
|
|
||||||
test("branch() returns undefined for non-git directories", async () => {
|
it.live("branch() returns undefined for non-git directories", () =>
|
||||||
await using tmp = await tmpdir()
|
Effect.gen(function* () {
|
||||||
|
const tmp = yield* scopedTmpdir()
|
||||||
await withGit(async (rt) => {
|
const git = yield* Git.Service
|
||||||
const branch = await rt.runPromise(Git.Service.use((git) => git.branch(tmp.path)))
|
const branch = yield* git.branch(tmp.path)
|
||||||
expect(branch).toBeUndefined()
|
expect(branch).toBeUndefined()
|
||||||
})
|
}),
|
||||||
})
|
)
|
||||||
|
|
||||||
test("branch() returns undefined for detached HEAD", async () => {
|
it.live("branch() returns undefined for detached HEAD", () =>
|
||||||
await using tmp = await tmpdir({ git: true })
|
Effect.gen(function* () {
|
||||||
const hash = (await $`git rev-parse HEAD`.cwd(tmp.path).quiet().text()).trim()
|
const tmp = yield* scopedTmpdir({ git: true })
|
||||||
await $`git checkout --detach ${hash}`.cwd(tmp.path).quiet()
|
const hash = (yield* Effect.promise(() => $`git rev-parse HEAD`.cwd(tmp.path).quiet().text())).trim()
|
||||||
|
yield* Effect.promise(() => $`git checkout --detach ${hash}`.cwd(tmp.path).quiet())
|
||||||
await withGit(async (rt) => {
|
const git = yield* Git.Service
|
||||||
const branch = await rt.runPromise(Git.Service.use((git) => git.branch(tmp.path)))
|
const branch = yield* git.branch(tmp.path)
|
||||||
expect(branch).toBeUndefined()
|
expect(branch).toBeUndefined()
|
||||||
})
|
}),
|
||||||
})
|
)
|
||||||
|
|
||||||
test("defaultBranch() uses init.defaultBranch when available", async () => {
|
it.live("defaultBranch() uses init.defaultBranch when available", () =>
|
||||||
await using tmp = await tmpdir({ git: true })
|
Effect.gen(function* () {
|
||||||
await $`git branch -M trunk`.cwd(tmp.path).quiet()
|
const tmp = yield* scopedTmpdir({ git: true })
|
||||||
await $`git config init.defaultBranch trunk`.cwd(tmp.path).quiet()
|
yield* Effect.promise(() => $`git branch -M trunk`.cwd(tmp.path).quiet())
|
||||||
|
yield* Effect.promise(() => $`git config init.defaultBranch trunk`.cwd(tmp.path).quiet())
|
||||||
await withGit(async (rt) => {
|
const git = yield* Git.Service
|
||||||
const branch = await rt.runPromise(Git.Service.use((git) => git.defaultBranch(tmp.path)))
|
const branch = yield* git.defaultBranch(tmp.path)
|
||||||
expect(branch?.name).toBe("trunk")
|
expect(branch?.name).toBe("trunk")
|
||||||
expect(branch?.ref).toBe("trunk")
|
expect(branch?.ref).toBe("trunk")
|
||||||
})
|
}),
|
||||||
})
|
)
|
||||||
|
|
||||||
test("status() handles special filenames", async () => {
|
it.live("status() handles special filenames", () =>
|
||||||
await using tmp = await tmpdir({ git: true })
|
Effect.gen(function* () {
|
||||||
await fs.writeFile(path.join(tmp.path, weird), "hello\n", "utf-8")
|
const tmp = yield* scopedTmpdir({ git: true })
|
||||||
|
yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, weird), "hello\n", "utf-8"))
|
||||||
await withGit(async (rt) => {
|
const git = yield* Git.Service
|
||||||
const status = await rt.runPromise(Git.Service.use((git) => git.status(tmp.path)))
|
const status = yield* git.status(tmp.path)
|
||||||
expect(status).toEqual(
|
expect(status).toEqual(
|
||||||
expect.arrayContaining([
|
expect.arrayContaining([
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
@@ -74,23 +73,24 @@ describe("Git", () => {
|
|||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
)
|
)
|
||||||
})
|
}),
|
||||||
})
|
)
|
||||||
|
|
||||||
test("diff(), stats(), and mergeBase() parse tracked changes", async () => {
|
it.live("diff(), stats(), and mergeBase() parse tracked changes", () =>
|
||||||
await using tmp = await tmpdir({ git: true })
|
Effect.gen(function* () {
|
||||||
await $`git branch -M main`.cwd(tmp.path).quiet()
|
const tmp = yield* scopedTmpdir({ git: true })
|
||||||
await fs.writeFile(path.join(tmp.path, weird), "before\n", "utf-8")
|
yield* Effect.promise(() => $`git branch -M main`.cwd(tmp.path).quiet())
|
||||||
await $`git add .`.cwd(tmp.path).quiet()
|
yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, weird), "before\n", "utf-8"))
|
||||||
await $`git commit --no-gpg-sign -m "add file"`.cwd(tmp.path).quiet()
|
yield* Effect.promise(() => $`git add .`.cwd(tmp.path).quiet())
|
||||||
await $`git checkout -b feature/test`.cwd(tmp.path).quiet()
|
yield* Effect.promise(() => $`git commit --no-gpg-sign -m "add file"`.cwd(tmp.path).quiet())
|
||||||
await fs.writeFile(path.join(tmp.path, weird), "after\n", "utf-8")
|
yield* Effect.promise(() => $`git checkout -b feature/test`.cwd(tmp.path).quiet())
|
||||||
|
yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, weird), "after\n", "utf-8"))
|
||||||
|
|
||||||
await withGit(async (rt) => {
|
const git = yield* Git.Service
|
||||||
const [base, diff, stats] = await Promise.all([
|
const [base, diff, stats] = yield* Effect.all([
|
||||||
rt.runPromise(Git.Service.use((git) => git.mergeBase(tmp.path, "main"))),
|
git.mergeBase(tmp.path, "main"),
|
||||||
rt.runPromise(Git.Service.use((git) => git.diff(tmp.path, "HEAD"))),
|
git.diff(tmp.path, "HEAD"),
|
||||||
rt.runPromise(Git.Service.use((git) => git.stats(tmp.path, "HEAD"))),
|
git.stats(tmp.path, "HEAD"),
|
||||||
])
|
])
|
||||||
|
|
||||||
expect(base).toBeTruthy()
|
expect(base).toBeTruthy()
|
||||||
@@ -111,23 +111,24 @@ describe("Git", () => {
|
|||||||
}),
|
}),
|
||||||
]),
|
]),
|
||||||
)
|
)
|
||||||
})
|
}),
|
||||||
})
|
)
|
||||||
|
|
||||||
test("patch() returns capped native patch output", async () => {
|
it.live("patch() returns capped native patch output", () =>
|
||||||
await using tmp = await tmpdir({ git: true })
|
Effect.gen(function* () {
|
||||||
await fs.writeFile(path.join(tmp.path, weird), "before\n", "utf-8")
|
const tmp = yield* scopedTmpdir({ git: true })
|
||||||
await fs.writeFile(path.join(tmp.path, "other.txt"), "old\n", "utf-8")
|
yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, weird), "before\n", "utf-8"))
|
||||||
await $`git add .`.cwd(tmp.path).quiet()
|
yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, "other.txt"), "old\n", "utf-8"))
|
||||||
await $`git commit --no-gpg-sign -m "add file"`.cwd(tmp.path).quiet()
|
yield* Effect.promise(() => $`git add .`.cwd(tmp.path).quiet())
|
||||||
await fs.writeFile(path.join(tmp.path, weird), "after\n", "utf-8")
|
yield* Effect.promise(() => $`git commit --no-gpg-sign -m "add file"`.cwd(tmp.path).quiet())
|
||||||
await fs.writeFile(path.join(tmp.path, "other.txt"), "new\n", "utf-8")
|
yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, weird), "after\n", "utf-8"))
|
||||||
|
yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, "other.txt"), "new\n", "utf-8"))
|
||||||
|
|
||||||
await withGit(async (rt) => {
|
const git = yield* Git.Service
|
||||||
const [patch, all, capped] = await Promise.all([
|
const [patch, all, capped] = yield* Effect.all([
|
||||||
rt.runPromise(Git.Service.use((git) => git.patch(tmp.path, "HEAD", weird, { context: 2_147_483_647 }))),
|
git.patch(tmp.path, "HEAD", weird, { context: 2_147_483_647 }),
|
||||||
rt.runPromise(Git.Service.use((git) => git.patchAll(tmp.path, "HEAD", { context: 2_147_483_647 }))),
|
git.patchAll(tmp.path, "HEAD", { context: 2_147_483_647 }),
|
||||||
rt.runPromise(Git.Service.use((git) => git.patch(tmp.path, "HEAD", weird, { maxOutputBytes: 1 }))),
|
git.patch(tmp.path, "HEAD", weird, { maxOutputBytes: 1 }),
|
||||||
])
|
])
|
||||||
|
|
||||||
expect(patch.truncated).toBe(false)
|
expect(patch.truncated).toBe(false)
|
||||||
@@ -140,17 +141,18 @@ describe("Git", () => {
|
|||||||
expect(all.text).toContain("+new")
|
expect(all.text).toContain("+new")
|
||||||
expect(capped.truncated).toBe(true)
|
expect(capped.truncated).toBe(true)
|
||||||
expect(capped.text).toBe("")
|
expect(capped.text).toBe("")
|
||||||
})
|
}),
|
||||||
})
|
)
|
||||||
|
|
||||||
test("patchUntracked() and statUntracked() handle added files", async () => {
|
it.live("patchUntracked() and statUntracked() handle added files", () =>
|
||||||
await using tmp = await tmpdir({ git: true })
|
Effect.gen(function* () {
|
||||||
await fs.writeFile(path.join(tmp.path, weird), "one\ntwo\n", "utf-8")
|
const tmp = yield* scopedTmpdir({ git: true })
|
||||||
|
yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, weird), "one\ntwo\n", "utf-8"))
|
||||||
|
|
||||||
await withGit(async (rt) => {
|
const git = yield* Git.Service
|
||||||
const [patch, stat] = await Promise.all([
|
const [patch, stat] = yield* Effect.all([
|
||||||
rt.runPromise(Git.Service.use((git) => git.patchUntracked(tmp.path, weird, { context: 2_147_483_647 }))),
|
git.patchUntracked(tmp.path, weird, { context: 2_147_483_647 }),
|
||||||
rt.runPromise(Git.Service.use((git) => git.statUntracked(tmp.path, weird))),
|
git.statUntracked(tmp.path, weird),
|
||||||
])
|
])
|
||||||
|
|
||||||
expect(patch.truncated).toBe(false)
|
expect(patch.truncated).toBe(false)
|
||||||
@@ -158,18 +160,19 @@ describe("Git", () => {
|
|||||||
expect(patch.text).toContain("+one")
|
expect(patch.text).toContain("+one")
|
||||||
expect(patch.text).toContain("+two")
|
expect(patch.text).toContain("+two")
|
||||||
expect(stat).toEqual(expect.objectContaining({ file: weird, additions: 2, deletions: 0 }))
|
expect(stat).toEqual(expect.objectContaining({ file: weird, additions: 2, deletions: 0 }))
|
||||||
})
|
}),
|
||||||
})
|
)
|
||||||
|
|
||||||
test("show() returns empty text for binary blobs", async () => {
|
it.live("show() returns empty text for binary blobs", () =>
|
||||||
await using tmp = await tmpdir({ git: true })
|
Effect.gen(function* () {
|
||||||
await fs.writeFile(path.join(tmp.path, "bin.dat"), new Uint8Array([0, 1, 2, 3]))
|
const tmp = yield* scopedTmpdir({ git: true })
|
||||||
await $`git add .`.cwd(tmp.path).quiet()
|
yield* Effect.promise(() => fs.writeFile(path.join(tmp.path, "bin.dat"), new Uint8Array([0, 1, 2, 3])))
|
||||||
await $`git commit --no-gpg-sign -m "add binary"`.cwd(tmp.path).quiet()
|
yield* Effect.promise(() => $`git add .`.cwd(tmp.path).quiet())
|
||||||
|
yield* Effect.promise(() => $`git commit --no-gpg-sign -m "add binary"`.cwd(tmp.path).quiet())
|
||||||
|
|
||||||
await withGit(async (rt) => {
|
const git = yield* Git.Service
|
||||||
const text = await rt.runPromise(Git.Service.use((git) => git.show(tmp.path, "HEAD", "bin.dat")))
|
const text = yield* git.show(tmp.path, "HEAD", "bin.dat")
|
||||||
expect(text).toBe("")
|
expect(text).toBe("")
|
||||||
})
|
}),
|
||||||
})
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user