]> git.giacomolli.uk - onechat/blob - config_test.go
Convert reply Markdown to Telegram entities
[onechat] / config_test.go
1 package main
2
3 import (
4         "os"
5         "path/filepath"
6         "testing"
7
8         "github.com/stretchr/testify/require"
9 )
10
11 func TestLoadConfigGivesDefaultsWithoutAFile(t *testing.T) {
12         dir := t.TempDir()
13         config, err := loadConfig(dir)
14         require.NoError(t, err)
15         require.Equal(t, defaultConfig(), config)
16         require.NoFileExists(t, filepath.Join(dir, "config.json"))
17 }
18
19 func TestLoadConfigKeepsDefaultsForMissingFields(t *testing.T) {
20         dir := t.TempDir()
21         writeConfig(t, dir, `{"endpoint": "api", "compactor": {"effort": "xhigh"}}`)
22
23         config, err := loadConfig(dir)
24         require.NoError(t, err)
25         require.Equal(t, Config{
26                 Endpoint: endpointAPI,
27                 Compactor: ModelConfig{
28                         Model:  "gpt-6.1-sol",
29                         Effort: "xhigh",
30                 },
31         }, config)
32 }
33
34 func TestLoadConfigRejectsInvalidFiles(t *testing.T) {
35         testCases := []struct {
36                 name string
37                 text string
38         }{
39                 {
40                         name: "unknown field",
41                         text: `{"endpont": "api"}`,
42                 },
43                 {
44                         name: "unknown nested field",
45                         text: `{"compactor": {"modle": "x"}}`,
46                 },
47                 {
48                         name: "endpoint URL",
49                         text: `{"endpoint": "https://example.com/v1/responses"}`,
50                 },
51                 {
52                         name: "empty model",
53                         text: `{"compactor": {"model": ""}}`,
54                 },
55                 {
56                         name: "second object",
57                         text: `{} {}`,
58                 },
59                 {
60                         name: "broken JSON",
61                         text: `{"endpoint": `,
62                 },
63         }
64
65         for _, tc := range testCases {
66                 t.Run(tc.name, func(t *testing.T) {
67                         dir := t.TempDir()
68                         writeConfig(t, dir, tc.text)
69
70                         _, err := loadConfig(dir)
71                         require.Error(t, err)
72                 })
73         }
74 }
75
76 func TestDataDirFollowsTheOrder(t *testing.T) {
77         root := t.TempDir()
78         testCases := []struct {
79                 name string
80                 dir  string
81                 xdg  string
82                 home string
83                 want string
84         }{
85                 {
86                         name: "ONECHAT_DIR first",
87                         dir:  filepath.Join(root, "a"),
88                         xdg:  filepath.Join(root, "xdg"),
89                         home: root,
90                         want: filepath.Join(root, "a"),
91                 },
92                 {
93                         name: "absolute XDG_DATA_HOME",
94                         dir:  "",
95                         xdg:  filepath.Join(root, "xdg"),
96                         home: root,
97                         want: filepath.Join(root, "xdg", "onechat"),
98                 },
99                 {
100                         name: "relative XDG_DATA_HOME ignored",
101                         dir:  "",
102                         xdg:  "xdg",
103                         home: root,
104                         want: filepath.Join(root, ".local", "share", "onechat"),
105                 },
106                 {
107                         name: "home directory last",
108                         dir:  "",
109                         xdg:  "",
110                         home: root,
111                         want: filepath.Join(root, ".local", "share", "onechat"),
112                 },
113         }
114
115         for _, tc := range testCases {
116                 t.Run(tc.name, func(t *testing.T) {
117                         t.Setenv("ONECHAT_DIR", tc.dir)
118                         t.Setenv("XDG_DATA_HOME", tc.xdg)
119                         t.Setenv("HOME", tc.home)
120
121                         dir, err := dataDir()
122                         require.NoError(t, err)
123                         require.Equal(t, tc.want, dir)
124
125                         info, err := os.Stat(dir)
126                         require.NoError(t, err)
127                         require.Equal(t, os.FileMode(0o700), info.Mode().Perm())
128                 })
129         }
130 }
131
132 func TestDataDirFailsWithoutAHome(t *testing.T) {
133         t.Setenv("ONECHAT_DIR", "")
134         t.Setenv("XDG_DATA_HOME", "")
135         t.Setenv("HOME", "")
136
137         _, err := dataDir()
138         require.ErrorContains(t, err, "ONECHAT_DIR")
139 }
140
141 func writeConfig(t *testing.T, dir, text string) {
142         t.Helper()
143
144         err := os.WriteFile(filepath.Join(dir, "config.json"), []byte(text), 0o600)
145         require.NoError(t, err)
146 }