1package kvconf
2
3import (
4 "errors"
5 "io/fs"
6 "os"
7 "path/filepath"
8 "runtime"
9 "testing"
10)
11
12func TestReadFile(t *testing.T) {
13 dir := t.TempDir()
14 tests := []struct {
15 name string
16 setup func(t *testing.T) string
17 opts Options
18 want string
19 err error
20 }{
21 {name: "regular", setup: func(t *testing.T) string { return writeTemp(t, dir, "ok", "a = 1\n") }, want: "a = 1\n"},
22 {name: "missing", setup: func(t *testing.T) string { return filepath.Join(dir, "none") }, err: fs.ErrNotExist},
23 {name: "directory", setup: func(t *testing.T) string { return dir }, err: ErrNotRegular},
24 {
25 name: "too large",
26 setup: func(t *testing.T) string { return writeTemp(t, dir, "big", "0123456789") },
27 opts: Options{MaxBytes: 4},
28 err: ErrTooLarge,
29 },
30 {
31 name: "at the limit",
32 setup: func(t *testing.T) string { return writeTemp(t, dir, "limit", "0123") },
33 opts: Options{MaxBytes: 4},
34 want: "0123",
35 },
36 }
37 for _, tt := range tests {
38 t.Run(tt.name, func(t *testing.T) {
39 data, err := ReadFile(tt.setup(t), tt.opts)
40 if tt.err != nil {
41 if !errors.Is(err, tt.err) {
42 t.Fatalf("err = %v, want %v", err, tt.err)
43 }
44 return
45 }
46 must(t, err)
47 eq(t, string(data), tt.want)
48 })
49 }
50}
51
52func TestExpandPath(t *testing.T) {
53 home, err := os.UserHomeDir()
54 if err != nil {
55 t.Skip(err)
56 }
57 abs := filepath.Join(home, "x")
58 tests := []struct {
59 in, want string
60 err bool
61 }{
62 {in: "~/x", want: abs},
63 {in: "~", want: home},
64 {in: abs + string(filepath.Separator) + ".", want: abs},
65 {in: "", err: true},
66 {in: "rel", err: true},
67 {in: "~user/x", err: true},
68 {in: "/a\x00b", err: true},
69 }
70 for _, tt := range tests {
71 t.Run(tt.in, func(t *testing.T) {
72 got, err := ExpandPath(tt.in)
73 if (err != nil) != tt.err || got != tt.want {
74 t.Fatalf("ExpandPath(%q) = %q, %v", tt.in, got, err)
75 }
76 })
77 }
78}
79
80func TestDefaultPath(t *testing.T) {
81 home := t.TempDir()
82 xdg := filepath.Join(home, "xdg")
83 // The platform config dir, spelled out rather than recomputed.
84 native := filepath.Join(home, ".config")
85 switch runtime.GOOS {
86 case "darwin":
87 native = filepath.Join(home, "Library", "Application Support")
88 case "windows":
89 native = filepath.Join(home, "AppData")
90 }
91 tests := []struct{ name, xdg, want string }{
92 {name: "absolute XDG", xdg: xdg, want: filepath.Join(xdg, "app", "config")},
93 {name: "relative XDG is ignored", xdg: "relative", want: filepath.Join(native, "app", "config")},
94 {name: "no XDG", want: filepath.Join(native, "app", "config")},
95 }
96 for _, tt := range tests {
97 t.Run(tt.name, func(t *testing.T) {
98 t.Setenv("HOME", home)
99 t.Setenv("USERPROFILE", home)
100 t.Setenv("AppData", filepath.Join(home, "AppData"))
101 t.Setenv("XDG_CONFIG_HOME", tt.xdg)
102 got, err := DefaultPath("app", "config")
103 must(t, err)
104 eq(t, got, tt.want)
105 })
106 }
107}