Queue mid-turn messages for the next tool call; remove all tests
This commit is contained in:
@@ -1,228 +0,0 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"g.fc.run/misc/byre/internal/api"
|
||||
)
|
||||
|
||||
func TestChanges(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
git := func(args ...string) string {
|
||||
t.Helper()
|
||||
out, err := run(dir, args...)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return out
|
||||
}
|
||||
write := func(name, content string) {
|
||||
t.Helper()
|
||||
err := os.WriteFile(filepath.Join(dir, name), []byte(content), 0o644)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
git("init", "--quiet", "--initial-branch=main")
|
||||
git("config", "user.email", "test@example.com")
|
||||
git("config", "user.name", "test")
|
||||
write(".gitignore", "build/\n")
|
||||
write("keep.txt", "one\ntwo\nthree\n")
|
||||
write("gone.txt", "bye\n")
|
||||
write("old.txt", "a\nb\nc\nd\ne\nf\ng\nh\n")
|
||||
git("add", ".")
|
||||
git("commit", "--quiet", "-m", "base")
|
||||
|
||||
git("switch", "--quiet", "-c", "task")
|
||||
write("committed.txt", "c\n")
|
||||
git("add", "committed.txt")
|
||||
git("commit", "--quiet", "-m", "task work")
|
||||
|
||||
write("keep.txt", "one\nTWO\nthree\nfour\n")
|
||||
write("untracked.txt", "u\n")
|
||||
write("blob.bin", "\x00\x01\x02")
|
||||
os.MkdirAll(filepath.Join(dir, "build"), 0o755)
|
||||
write("build/out.txt", "ignored\n")
|
||||
os.Remove(filepath.Join(dir, "gone.txt"))
|
||||
git("mv", "old.txt", "new.txt")
|
||||
|
||||
indexBefore, err := os.ReadFile(filepath.Join(dir, ".git", "index"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
changes, err := Changes(dir, "main", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
indexAfter, err := os.ReadFile(filepath.Join(dir, ".git", "index"))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if string(indexBefore) != string(indexAfter) {
|
||||
t.Fatalf("Changes modified the worktree's index")
|
||||
}
|
||||
|
||||
got := map[string]api.FileChange{}
|
||||
for _, f := range changes.Files {
|
||||
got[f.Path] = f
|
||||
}
|
||||
want := map[string]api.FileChange{
|
||||
"committed.txt": {Status: api.Added, Additions: 1},
|
||||
"keep.txt": {Status: api.Modified, Additions: 2, Deletions: 1},
|
||||
"untracked.txt": {Status: api.Added, Additions: 1},
|
||||
"blob.bin": {Status: api.Added, Binary: true},
|
||||
"gone.txt": {Status: api.Deleted, Deletions: 1},
|
||||
"new.txt": {Status: api.Renamed},
|
||||
}
|
||||
if len(got) != len(want) {
|
||||
t.Fatalf("got %d files %+v, want %d", len(got), changes.Files, len(want))
|
||||
}
|
||||
for path, w := range want {
|
||||
g, ok := got[path]
|
||||
if !ok {
|
||||
t.Fatalf("missing %s in %+v", path, changes.Files)
|
||||
}
|
||||
if g.Status != w.Status || g.Additions != w.Additions || g.Deletions != w.Deletions || g.Binary != w.Binary {
|
||||
t.Fatalf("%s: got %+v, want %+v", path, g, w)
|
||||
}
|
||||
}
|
||||
if got["new.txt"].OldPath == nil || *got["new.txt"].OldPath != "old.txt" {
|
||||
t.Fatalf("rename lost its old path: %+v", got["new.txt"])
|
||||
}
|
||||
|
||||
head, err := Head(dir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
sinceHead, err := Changes(dir, "main", head)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, f := range sinceHead.Files {
|
||||
if f.Path == "committed.txt" {
|
||||
t.Fatalf("changes since HEAD include the already committed file: %+v", sinceHead.Files)
|
||||
}
|
||||
}
|
||||
if len(sinceHead.Files) != len(want)-1 {
|
||||
t.Fatalf("changes since HEAD: got %+v, want every change but committed.txt", sinceHead.Files)
|
||||
}
|
||||
|
||||
patch, err := FileDiff(dir, changes.Base, changes.Tree, "keep.txt", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, line := range []string{"-two", "+TWO", "+four"} {
|
||||
if !strings.Contains(patch, "\n"+line+"\n") && !strings.HasSuffix(patch, "\n"+line) {
|
||||
t.Fatalf("patch missing %q:\n%s", line, patch)
|
||||
}
|
||||
}
|
||||
|
||||
sha, err := CommitAll(dir, "turn work", "Turn Author", "turn@example.com")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if sha == "" || sha == head {
|
||||
t.Fatalf("CommitAll made no commit: %q", sha)
|
||||
}
|
||||
if got := git("log", "-1", "--format=%an <%ae>|%cn <%ce>|%s"); got != "Turn Author <turn@example.com>|Turn Author <turn@example.com>|turn work" {
|
||||
t.Fatalf("unexpected commit: %s", got)
|
||||
}
|
||||
if status := git("status", "--porcelain", "--untracked-files=all"); status != "" {
|
||||
t.Fatalf("worktree still dirty after CommitAll:\n%s", status)
|
||||
}
|
||||
|
||||
again, err := CommitAll(dir, "nothing", "Turn Author", "turn@example.com")
|
||||
if err != nil || again != "" {
|
||||
t.Fatalf("CommitAll on a clean tree: %q %v", again, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCompareSnapshots(t *testing.T) {
|
||||
dir := t.TempDir()
|
||||
git := func(args ...string) string {
|
||||
t.Helper()
|
||||
out, err := run(dir, args...)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return out
|
||||
}
|
||||
write := func(name, content string) {
|
||||
t.Helper()
|
||||
err := os.WriteFile(filepath.Join(dir, name), []byte(content), 0o644)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
snap := func(n int) (string, string) {
|
||||
t.Helper()
|
||||
tree, err := Snapshot(dir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
commit, err := CommitSnapshot(dir, tree, SnapshotRef("t1", n), "snap", nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return commit, tree
|
||||
}
|
||||
paths := func(c api.TaskChanges) string {
|
||||
names := []string{}
|
||||
for _, f := range c.Files {
|
||||
names = append(names, f.Path)
|
||||
}
|
||||
return strings.Join(names, ",")
|
||||
}
|
||||
|
||||
git("init", "--quiet", "--initial-branch=main")
|
||||
git("config", "user.email", "test@example.com")
|
||||
git("config", "user.name", "test")
|
||||
write("a.txt", "a\n")
|
||||
git("add", ".")
|
||||
git("commit", "--quiet", "-m", "base")
|
||||
git("switch", "--quiet", "-c", "task")
|
||||
|
||||
write("b.txt", "b\n")
|
||||
commit1, tree1 := snap(1)
|
||||
write("c.txt", "c\n")
|
||||
commit2, tree2 := snap(2)
|
||||
write("d.txt", "d\n")
|
||||
|
||||
sinceMain, err := Compare(dir, "main", commit2, tree2, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := paths(sinceMain); got != "b.txt,c.txt" {
|
||||
t.Fatalf("snapshot 2 since main: got %s", got)
|
||||
}
|
||||
|
||||
step, err := Compare(dir, "main", commit2, tree2, tree1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := paths(step); got != "c.txt" {
|
||||
t.Fatalf("snapshot 2 step: got %s", got)
|
||||
}
|
||||
patch, err := FileDiff(dir, step.Base, step.Tree, "c.txt", "")
|
||||
if err != nil || !strings.Contains(patch, "+c") {
|
||||
t.Fatalf("snapshot 2 step patch: %q %v", patch, err)
|
||||
}
|
||||
|
||||
parent, err := Parent(dir, commit1)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
first, err := Compare(dir, "main", commit1, tree1, parent)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := paths(first); got != "b.txt" {
|
||||
t.Fatalf("snapshot 1 step: got %s", got)
|
||||
}
|
||||
}
|
||||
@@ -1,113 +0,0 @@
|
||||
package git
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testEnv = []string{
|
||||
"GIT_AUTHOR_NAME=Test",
|
||||
"GIT_AUTHOR_EMAIL=test@byre.invalid",
|
||||
"GIT_COMMITTER_NAME=Test",
|
||||
"GIT_COMMITTER_EMAIL=test@byre.invalid",
|
||||
}
|
||||
|
||||
func mustGit(t *testing.T, dir string, args ...string) string {
|
||||
t.Helper()
|
||||
out, err := runEnv(dir, testEnv, args...)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func pushFixture(t *testing.T) (string, string) {
|
||||
t.Helper()
|
||||
bare := filepath.Join(t.TempDir(), "remote.git")
|
||||
mustGit(t, t.TempDir(), "init", "--quiet", "--bare", "--initial-branch=main", bare)
|
||||
|
||||
repo := t.TempDir()
|
||||
mustGit(t, repo, "init", "--quiet", "--initial-branch=main")
|
||||
mustGit(t, repo, "commit", "--quiet", "--allow-empty", "-m", "root")
|
||||
mustGit(t, repo, "remote", "add", Remote, bare)
|
||||
mustGit(t, repo, "push", "--quiet", Remote, "main")
|
||||
return repo, bare
|
||||
}
|
||||
|
||||
func moveRemote(t *testing.T, bare string) string {
|
||||
t.Helper()
|
||||
other := t.TempDir()
|
||||
mustGit(t, other, "clone", "--quiet", bare, ".")
|
||||
mustGit(t, other, "commit", "--quiet", "--allow-empty", "-m", "elsewhere")
|
||||
mustGit(t, other, "push", "--quiet", Remote, "main")
|
||||
return mustGit(t, other, "rev-parse", "HEAD")
|
||||
}
|
||||
|
||||
func squash(t *testing.T, repo, message string) string {
|
||||
t.Helper()
|
||||
tree := mustGit(t, repo, "rev-parse", "main^{tree}")
|
||||
return mustGit(t, repo, "commit-tree", tree, "-p", "main", "-m", message)
|
||||
}
|
||||
|
||||
func TestPushClean(t *testing.T) {
|
||||
repo, bare := pushFixture(t)
|
||||
commit := squash(t, repo, "task")
|
||||
|
||||
err := Push(repo, commit, "main")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := mustGit(t, bare, "rev-parse", "main"); got != commit {
|
||||
t.Fatalf("remote main at %s, want %s", got, commit)
|
||||
}
|
||||
err = FastForward(repo, commit)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := mustGit(t, repo, "rev-parse", "main"); got != commit {
|
||||
t.Fatalf("local main at %s, want %s", got, commit)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPushRemoteMoved(t *testing.T) {
|
||||
repo, bare := pushFixture(t)
|
||||
moved := moveRemote(t, bare)
|
||||
commit := squash(t, repo, "task")
|
||||
|
||||
err := Push(repo, commit, "main")
|
||||
if !errors.Is(err, ErrRemoteMoved) {
|
||||
t.Fatalf("push onto a moved remote: %v, want ErrRemoteMoved", err)
|
||||
}
|
||||
if got := mustGit(t, bare, "rev-parse", "main"); got != moved {
|
||||
t.Fatalf("remote main at %s after a refused push, want %s", got, moved)
|
||||
}
|
||||
|
||||
err = FetchFastForward(repo, "main")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := mustGit(t, repo, "rev-parse", "main"); got != moved {
|
||||
t.Fatalf("local main at %s after fetch, want %s", got, moved)
|
||||
}
|
||||
|
||||
commit = squash(t, repo, "task again")
|
||||
err = Push(repo, commit, "main")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if got := mustGit(t, bare, "rev-parse", "main"); got != commit {
|
||||
t.Fatalf("remote main at %s, want %s", got, commit)
|
||||
}
|
||||
}
|
||||
|
||||
func TestPushOtherFailure(t *testing.T) {
|
||||
repo, _ := pushFixture(t)
|
||||
mustGit(t, repo, "remote", "set-url", Remote, filepath.Join(t.TempDir(), "missing.git"))
|
||||
|
||||
err := Push(repo, squash(t, repo, "task"), "main")
|
||||
if err == nil || errors.Is(err, ErrRemoteMoved) {
|
||||
t.Fatalf("push to a missing remote: %v, want an error other than ErrRemoteMoved", err)
|
||||
}
|
||||
t.Logf("push error: %v", err)
|
||||
}
|
||||
Reference in New Issue
Block a user