+package main
+
+import (
+ "os"
+ "path/filepath"
+ "testing"
+
+ "github.com/stretchr/testify/require"
+)
+
+func TestLoadConfigGivesDefaultsWithoutAFile(t *testing.T) {
+ dir := t.TempDir()
+ config, err := loadConfig(dir)
+ require.NoError(t, err)
+ require.Equal(t, defaultConfig(), config)
+ require.NoFileExists(t, filepath.Join(dir, "config.json"))
+}
+
+func TestLoadConfigKeepsDefaultsForMissingFields(t *testing.T) {
+ dir := t.TempDir()
+ writeConfig(t, dir, `{"endpoint": "api", "compactor": {"effort": "xhigh"}}`)
+
+ config, err := loadConfig(dir)
+ require.NoError(t, err)
+ require.Equal(t, Config{
+ Endpoint: endpointAPI,
+ Compactor: ModelConfig{
+ Model: "gpt-6-luna",
+ Effort: "xhigh",
+ },
+ }, config)
+}
+
+func TestLoadConfigRejectsInvalidFiles(t *testing.T) {
+ testCases := []struct {
+ name string
+ text string
+ }{
+ {"unknown field", `{"endpont": "api"}`},
+ {"unknown nested field", `{"compactor": {"modle": "x"}}`},
+ {"endpoint URL", `{"endpoint": "https://example.com/v1/responses"}`},
+ {"empty model", `{"compactor": {"model": ""}}`},
+ {"second object", `{} {}`},
+ {"broken JSON", `{"endpoint": `},
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ dir := t.TempDir()
+ writeConfig(t, dir, tc.text)
+
+ _, err := loadConfig(dir)
+ require.Error(t, err)
+ })
+ }
+}
+
+func TestDataDirFollowsTheOrder(t *testing.T) {
+ root := t.TempDir()
+ testCases := []struct {
+ name string
+ dir string
+ xdg string
+ home string
+ want string
+ }{
+ {"ONECHAT_DIR first", filepath.Join(root, "a"), filepath.Join(root, "xdg"), root, filepath.Join(root, "a")},
+ {"absolute XDG_DATA_HOME", "", filepath.Join(root, "xdg"), root, filepath.Join(root, "xdg", "onechat")},
+ {"relative XDG_DATA_HOME ignored", "", "xdg", root, filepath.Join(root, ".local", "share", "onechat")},
+ {"home directory last", "", "", root, filepath.Join(root, ".local", "share", "onechat")},
+ }
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ t.Setenv("ONECHAT_DIR", tc.dir)
+ t.Setenv("XDG_DATA_HOME", tc.xdg)
+ t.Setenv("HOME", tc.home)
+
+ dir, err := dataDir()
+ require.NoError(t, err)
+ require.Equal(t, tc.want, dir)
+
+ info, err := os.Stat(dir)
+ require.NoError(t, err)
+ require.Equal(t, os.FileMode(0o700), info.Mode().Perm())
+ })
+ }
+}
+
+func TestDataDirFailsWithoutAHome(t *testing.T) {
+ t.Setenv("ONECHAT_DIR", "")
+ t.Setenv("XDG_DATA_HOME", "")
+ t.Setenv("HOME", "")
+
+ _, err := dataDir()
+ require.ErrorContains(t, err, "ONECHAT_DIR")
+}
+
+func writeConfig(t *testing.T, dir, text string) {
+ t.Helper()
+
+ err := os.WriteFile(filepath.Join(dir, "config.json"), []byte(text), 0o600)
+ require.NoError(t, err)
+}