]> git.giacomolli.uk - onechat/blob - agent_test.go
Separate returns from longer statement blocks
[onechat] / agent_test.go
1 package main
2
3 import (
4         "encoding/json"
5         "os"
6         "path/filepath"
7         "testing"
8
9         "github.com/stretchr/testify/require"
10 )
11
12 func TestNewAgentKeepsItsIDAcrossOpens(t *testing.T) {
13         dir := filepath.Join(t.TempDir(), "agent")
14         agent, err := openAgent(dir)
15         require.NoError(t, err)
16         require.Len(t, agent.config.ID, 2*agentIDBytes)
17         require.Equal(t, "gpt-6.1-sol", agent.config.Model)
18         require.True(t, filepath.IsAbs(agent.config.Workdir))
19
20         again, err := openAgent(dir)
21         require.NoError(t, err)
22         require.Equal(t, agent.config, again.config)
23
24         info, err := os.Stat(dir)
25         require.NoError(t, err)
26         require.Equal(t, os.FileMode(0o700), info.Mode().Perm())
27 }
28
29 func TestNewAgentsGetDifferentIDs(t *testing.T) {
30         first, err := openAgent(t.TempDir())
31         require.NoError(t, err)
32
33         second, err := openAgent(t.TempDir())
34         require.NoError(t, err)
35         require.Equal(t, first.config.Name, second.config.Name)
36         require.NotEqual(t, first.CacheKey(), second.CacheKey())
37 }
38
39 func TestRenamedAgentKeepsItsCacheKey(t *testing.T) {
40         dir := t.TempDir()
41         agent, err := openAgent(dir)
42         require.NoError(t, err)
43
44         key := agent.CacheKey()
45         require.Equal(t, "onechat-"+agent.config.ID, key)
46
47         config := agent.config
48         config.Name = "Lena"
49         agentWriteTestConfig(t, dir, config)
50
51         renamed, err := openAgent(dir)
52         require.NoError(t, err)
53         require.Equal(t, "Lena", renamed.config.Name)
54         require.Equal(t, key, renamed.CacheKey())
55 }
56
57 func TestAgentConfigErrors(t *testing.T) {
58         testCases := []struct {
59                 name   string
60                 config string
61                 err    string
62         }{
63                 {
64                         name:   "unknown field",
65                         config: `{"id": "00112233445566778899aabbccddeeff", "nmae": "Lena"}`,
66                         err:    `unknown field "nmae"`,
67                 },
68                 {
69                         name:   "missing id",
70                         config: `{"name": "Lena"}`,
71                         err:    "id must be 32 hexadecimal digits",
72                 },
73                 {
74                         name:   "relative workdir",
75                         config: `{"id": "00112233445566778899aabbccddeeff", "workdir": "src"}`,
76                         err:    `workdir "src" is not an absolute path`,
77                 },
78                 {
79                         name:   "name of two lines",
80                         config: `{"id": "00112233445566778899aabbccddeeff", "name": "Le\nna"}`,
81                         err:    "name must be one line of text",
82                 },
83         }
84
85         for _, tc := range testCases {
86                 t.Run(tc.name, func(t *testing.T) {
87                         dir := t.TempDir()
88                         require.NoError(t, os.WriteFile(filepath.Join(dir, "config.json"), []byte(tc.config), 0o600))
89
90                         _, err := openAgent(dir)
91                         require.ErrorContains(t, err, tc.err)
92                 })
93         }
94 }
95
96 func TestAgentPromptReadsTheInstructionsEachTime(t *testing.T) {
97         dir := t.TempDir()
98         agent, err := openAgent(dir)
99         require.NoError(t, err)
100
101         text, err := agent.Prompt()
102         require.NoError(t, err)
103         require.Equal(t, prompt(agent.config.Name, filepath.Join(dir, agentInstructionsFileName), ""), text)
104
105         require.NoError(t, os.WriteFile(filepath.Join(dir, agentInstructionsFileName), []byte("I am Lena.\n"), 0o600))
106         text, err = agent.Prompt()
107         require.NoError(t, err)
108         require.Equal(t, prompt(agent.config.Name, filepath.Join(dir, agentInstructionsFileName), "I am Lena."), text)
109 }
110
111 func TestAgentPromptUsesAnAbsoluteInstructionsPath(t *testing.T) {
112         dir := t.TempDir()
113         workdir, err := os.Getwd()
114         require.NoError(t, err)
115
116         relative, err := filepath.Rel(workdir, dir)
117         require.NoError(t, err)
118         require.False(t, filepath.IsAbs(relative))
119
120         agent, err := openAgent(relative)
121         require.NoError(t, err)
122
123         text, err := agent.Prompt()
124         require.NoError(t, err)
125         require.Contains(t, text, "The user's instructions live in the file "+filepath.Join(dir, agentInstructionsFileName)+",")
126 }
127
128 // agentWriteTestConfig writes config as the config.json of the agent in dir.
129 func agentWriteTestConfig(t *testing.T, dir string, config AgentConfig) {
130         t.Helper()
131
132         data, err := json.Marshal(config)
133         require.NoError(t, err)
134         require.NoError(t, os.WriteFile(filepath.Join(dir, "config.json"), data, 0o600))
135 }