discordo/internal/config/config_test.go

172 lines
4.5 KiB
Go

package config
import (
"os"
"path/filepath"
"reflect"
"testing"
"github.com/BurntSushi/toml"
"github.com/ayn2op/discordo/internal/consts"
tviewkeybind "github.com/ayn2op/tview/keybind"
"github.com/gdamore/tcell/v3"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
)
func TestDefaultPath(t *testing.T) {
t.Run("user config dir fallback", func(t *testing.T) {
t.Setenv("AppData", "")
t.Setenv("HOME", "")
t.Setenv("home", "")
t.Setenv("XDG_CONFIG_HOME", "")
// filepath.Join strips the leading dot.
got := DefaultPath()
want := filepath.Join(".", consts.Name, fileName)
if got != want {
t.Fatalf("got = %v, want = %v", got, want)
}
})
}
func TestLoad(t *testing.T) {
t.Run("invalid default config returns error", func(t *testing.T) {
orig := defaultCfg
defaultCfg = []byte("invalid =")
t.Cleanup(func() { defaultCfg = orig })
if _, err := Load("does-not-matter.toml"); err == nil {
t.Fatal(err)
}
})
t.Run("invalid config returns error", func(t *testing.T) {
path := filepath.Join(t.TempDir(), "bad.toml")
if err := os.WriteFile(path, []byte("invalid ="), os.ModePerm); err != nil {
t.Fatal(err)
}
if _, err := Load(path); err == nil {
t.Fatal("expected error")
}
})
t.Run("valid config does not return error", func(t *testing.T) {
path := filepath.Join(t.TempDir(), "good.toml")
if err := os.WriteFile(path, []byte("mouse = false\n[help]\nenabled = true"), os.ModePerm); err != nil {
t.Fatal(err)
}
cfg, err := Load(path)
if err != nil {
t.Fatal(err)
}
if cfg.Mouse != false {
t.Fatalf("got = %v, want = false", cfg.Mouse)
}
if !cfg.Help.Enabled {
t.Fatal("help enabled = false, want true")
}
})
t.Run("invalid allowed MIME type returns error", func(t *testing.T) {
path := filepath.Join(t.TempDir(), "bad-mime.toml")
if err := os.WriteFile(path, []byte(`allowed_mime_types = ["image/"]`), os.ModePerm); err != nil {
t.Fatal(err)
}
if _, err := Load(path); err == nil {
t.Fatal("expected error")
}
})
// Keys live in config.toml, descriptions in defaultKeybinds(); fail if either is missing.
t.Run("default keybinds are fully populated", func(t *testing.T) {
cfg, err := Load(filepath.Join(t.TempDir(), "missing.toml"))
if err != nil {
t.Fatal(err)
}
var walk func(path string, v reflect.Value)
walk = func(path string, v reflect.Value) {
rt := v.Type()
for i := range rt.NumField() {
fv, name := v.Field(i), path+rt.Field(i).Name
if kb, ok := fv.Interface().(Keybind); ok {
if len(kb.Keys()) == 0 {
if rt.Field(i).Tag.Get("toml") != "delete" {
t.Errorf("%s: no keys (missing from config.toml?)", name)
}
continue
}
if kb.Help().Desc == "" {
t.Errorf("%s: no help description (missing from defaultKeybinds?)", name)
}
if kb.Help().Key == "" {
t.Errorf("%s: help key not populated from config.toml", name)
}
continue
}
if fv.Kind() == reflect.Struct {
walk(name+".", fv)
}
}
}
walk("Keybinds.", reflect.ValueOf(cfg.Keybinds))
})
t.Run("open with bad path returns error (!= ErrNotExist)", func(t *testing.T) {
if _, err := Load("bad\x00path"); err == nil {
t.Fatal("expected error")
}
})
t.Run("missing file uses defaults", func(t *testing.T) {
path := filepath.Join(t.TempDir(), "missing.toml")
cfg, err := Load(path)
if err != nil {
t.Fatal(err)
}
var defCfg Config
if err := toml.Unmarshal(defaultCfg, &defCfg); err != nil {
t.Fatal(err)
}
defCfg.applyDefaults()
if diff := cmp.Diff(
defCfg,
*cfg,
cmpopts.EquateComparable(tcell.Style{}),
cmpopts.IgnoreUnexported(tviewkeybind.Keybind{}),
); diff != "" {
t.Fatalf("got = -, want = +, diff=%s", diff)
}
})
}
func TestMIMETypesHas(t *testing.T) {
tests := []struct {
name string
allowed MIMETypes
mediaType string
wantAllowed bool
}{
{"exact", []string{"application/pdf"}, "application/pdf", true},
{"exact mismatch", []string{"application/pdf"}, "application/zip", false},
{"subtype wildcard", []string{"image/*"}, "image/png", true},
{"wildcard mismatch", []string{"image/*"}, "video/mp4", false},
{"all wildcard", []string{"*/*"}, "video/mp4", true},
{"case and parameters", []string{"image/*"}, "Image/PNG; charset=utf-8", true},
{"invalid content type", []string{"*/*"}, "not-a-mime-type", false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := tt.allowed.Has(tt.mediaType); got != tt.wantAllowed {
t.Fatalf("Has(%q) = %v, want %v", tt.mediaType, got, tt.wantAllowed)
}
})
}
}