1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
package pythonlang
import (
"errors"
"os"
"strings"
"testing"
"rickub.com/turbo-editors/turbo-core/acp"
)
// The agents file Turbo Python writes. What the *feature* does is turbo-core's to
// test; what is checked here is the one part that belongs to this editor —
// that the starter file is filled in correctly, loads back as the agent it
// describes, and says enough for somebody to point it at their own.
// readAgentsFile returns the agents file a project was given.
func readAgentsFile(t *testing.T, dir string) string {
t.Helper()
data, err := os.ReadFile(acp.ProjectPath(Profile(), dir))
if err != nil {
t.Fatalf("reading the agents file: %v", err)
}
return string(data)
}
// createAgents writes the starter agents file into a fresh project.
func createAgents(t *testing.T) string {
t.Helper()
dir := t.TempDir()
if _, err := acp.Create(Profile(), dir); err != nil {
t.Fatalf("acp.Create() error = %v", err)
}
return dir
}
func TestTheCreatedAgentsFileFillsBothOfItsBlanks(t *testing.T) {
// Two different values — the project directory the example agent points
// into, and the user's own file that a comment names. Go writes
// %!s(MISSING) into the output rather than failing, so a miscounted verb
// produces a starter file that is written, opened, and wrong.
contents := readAgentsFile(t, createAgents(t))
if strings.Contains(contents, "%!") {
t.Errorf("the created file has an unfilled verb in it:\n%s", contents)
}
if want := Profile().ProjectDir() + "/agent.yaml"; !strings.Contains(contents, want) {
t.Errorf("the example agent does not point at %q:\n%s", want, contents)
}
if want := acp.UserPath(Profile()); want != "" && !strings.Contains(contents, want) {
t.Errorf("the created file never names the user's own file %q:\n%s", want, contents)
}
}
func TestTheCreatedAgentsFileLoadsBackAsOneAgent(t *testing.T) {
// The file is mostly comments, and a comment carrying an [[agent]] example
// that the loader read as real would put an agent nobody configured into
// the menu.
dir := createAgents(t)
list, err := acp.Load(Profile(), dir)
if err != nil {
t.Fatalf("acp.Load() error = %v", err)
}
if list.Len() != 1 {
t.Fatalf("the created file holds %d agents, want 1: %v", list.Len(), list.Agents())
}
agent := list.Agents()[0]
if agent.Command != "docker" {
t.Errorf("the example agent runs %q, want docker", agent.Command)
}
if want := "agent serve acp"; !strings.Contains(agent.CommandLine(), want) {
t.Errorf("the example command line is %q, want %q in it", agent.CommandLine(), want)
}
}
func TestTheCreatedAgentsFileExplainsItself(t *testing.T) {
// The keys, the window's keyboard and how to copy out of it are all
// invisible otherwise: this is the only document the editor hands a user.
contents := readAgentsFile(t, createAgents(t))
for _, want := range []string{
"[[agent]]", "name", "command", "args", "env", "cwd",
"agentclientprotocol.com",
"Alt-Enter", "Ctrl-W", "Esc", "Ctrl-C",
} {
if !strings.Contains(contents, want) {
t.Errorf("the created file never mentions %q:\n%s", want, contents)
}
}
}
func TestTheCreatedAgentsFileNamesThisEditorsOwnLanguage(t *testing.T) {
// The comment about coloured code blocks is the one line of this file that
// is about Turbo Python rather than about the protocol, and a copy left naming
// another editor's language would be the obvious way to get it wrong.
contents := readAgentsFile(t, createAgents(t))
if want := "```python"; !strings.Contains(contents, want) {
t.Errorf("the created file never mentions a %q fence:\n%s", want, contents)
}
if want := ".py files"; !strings.Contains(contents, want) {
t.Errorf("the created file never mentions %q:\n%s", want, contents)
}
}
func TestCreatingAgentsTwiceLeavesTheFirstAlone(t *testing.T) {
dir := createAgents(t)
path := acp.ProjectPath(Profile(), dir)
if err := os.WriteFile(path, []byte("# mine\n"), 0o644); err != nil {
t.Fatalf("writing over it: %v", err)
}
if _, err := acp.Create(Profile(), dir); !errors.Is(err, acp.ErrExists) {
t.Errorf("acp.Create() error = %v, want ErrExists", err)
}
data, err := os.ReadFile(path)
if err != nil {
t.Fatalf("reading it back: %v", err)
}
if string(data) != "# mine\n" {
t.Errorf("the file was overwritten: %q", data)
}
}
|