aboutsummaryrefslogtreecommitdiff
path: root/internal/config/config_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/config/config_test.go')
-rw-r--r--internal/config/config_test.go158
1 files changed, 158 insertions, 0 deletions
diff --git a/internal/config/config_test.go b/internal/config/config_test.go
new file mode 100644
index 0000000..06c0234
--- /dev/null
+++ b/internal/config/config_test.go
@@ -0,0 +1,158 @@
+package config
+
+import (
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+func write(t *testing.T, body string) string {
+ t.Helper()
+ path := filepath.Join(t.TempDir(), "config")
+ if err := os.WriteFile(path, []byte(body), 0o644); err != nil {
+ t.Fatal(err)
+ }
+ return path
+}
+
+func TestLoadMissingFileKeepsDefaults(t *testing.T) {
+ cfg, err := Load(filepath.Join(t.TempDir(), "absent"))
+ if err != nil {
+ t.Fatalf("missing file should not be an error: %v", err)
+ }
+ if cfg.Hours != 12 || cfg.Icons != "nerd" {
+ t.Fatalf("defaults not returned: %+v", cfg)
+ }
+}
+
+func TestLoadOverridesOnlyWhatIsSet(t *testing.T) {
+ cfg, err := Load(write(t, "hours=24\nicons=emoji\n"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if cfg.Hours != 24 {
+ t.Errorf("hours = %d, want 24", cfg.Hours)
+ }
+ if cfg.Icons != "emoji" {
+ t.Errorf("icons = %q, want emoji", cfg.Icons)
+ }
+ // Untouched keys must keep their defaults.
+ if cfg.GraphHeight != 5 || !cfg.Graph {
+ t.Errorf("unset keys lost their defaults: %+v", cfg)
+ }
+}
+
+func TestLoadCommentsAndBlanks(t *testing.T) {
+ cfg, err := Load(write(t, "\n# a comment\n\nhours=6 # trailing comment\n"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if cfg.Hours != 6 {
+ t.Fatalf("hours = %d, want 6 (trailing comment must be stripped)", cfg.Hours)
+ }
+}
+
+func TestLoadErrors(t *testing.T) {
+ for name, body := range map[string]string{
+ "no equals": "hours 12\n",
+ "unknown key": "colour=always\n",
+ "not a number": "hours=soon\n",
+ "not a bool": "graph=maybe\n",
+ } {
+ t.Run(name, func(t *testing.T) {
+ if _, err := Load(write(t, body)); err == nil {
+ t.Fatalf("expected an error for %q", body)
+ }
+ })
+ }
+}
+
+func TestPollenAllAndNone(t *testing.T) {
+ cfg, _ := Load(write(t, "pollen=all\n"))
+ if len(cfg.Pollen) != len(AllSpecies) {
+ t.Errorf("pollen=all gave %v", cfg.Pollen)
+ }
+ cfg, _ = Load(write(t, "pollen=none\n"))
+ if len(cfg.Pollen) != 0 {
+ t.Errorf("pollen=none gave %v", cfg.Pollen)
+ }
+}
+
+func TestValidateNamesTheOffender(t *testing.T) {
+ cfg := Default()
+ cfg.Columns = []string{"hour", "tempature"}
+ err := cfg.Validate()
+ if err == nil {
+ t.Fatal("expected an error for an unknown column")
+ }
+ if !strings.Contains(err.Error(), "tempature") {
+ t.Errorf("error must name the offending column, got: %v", err)
+ }
+ if !strings.Contains(err.Error(), "conditions") {
+ t.Errorf("error must list valid columns, got: %v", err)
+ }
+}
+
+func TestValidateRejectsBadEnums(t *testing.T) {
+ for name, mutate := range map[string]func(*Config){
+ "icons": func(c *Config) { c.Icons = "pictures" },
+ "color": func(c *Config) { c.Color = "sometimes" },
+ "units": func(c *Config) { c.Units = "furlongs" },
+ "hours": func(c *Config) { c.Hours = 0 },
+ "graph_height": func(c *Config) { c.GraphHeight = 1 },
+ "pollen": func(c *Config) { c.Pollen = []string{"oak"} },
+ } {
+ t.Run(name, func(t *testing.T) {
+ cfg := Default()
+ mutate(&cfg)
+ if err := cfg.Validate(); err == nil {
+ t.Fatalf("expected %s to be rejected", name)
+ }
+ })
+ }
+}
+
+func TestDefaultIsValid(t *testing.T) {
+ if err := Default().Validate(); err != nil {
+ t.Fatalf("the built-in default must be valid: %v", err)
+ }
+}
+
+func TestFieldsRequestsOnlySelectedColumns(t *testing.T) {
+ cfg := Default()
+ cfg.Columns = []string{"hour", "temp", "wind"}
+ got := strings.Join(cfg.Fields(), ",")
+ want := "temperature_2m,wind_speed_10m"
+ if got != want {
+ t.Fatalf("Fields() = %q, want %q", got, want)
+ }
+}
+
+func TestFieldsDeduplicates(t *testing.T) {
+ cfg := Default()
+ // icon and conditions both come from weather_code.
+ cfg.Columns = []string{"icon", "conditions"}
+ if got := cfg.Fields(); len(got) != 1 || got[0] != "weather_code" {
+ t.Fatalf("Fields() = %v, want one weather_code", got)
+ }
+}
+
+func TestWriteDefaultRoundTrips(t *testing.T) {
+ path := filepath.Join(t.TempDir(), "sub", "config")
+ want := Default()
+ want.Location = "Krakow"
+ if err := WriteDefault(path, want); err != nil {
+ t.Fatal(err)
+ }
+ got, err := Load(path)
+ if err != nil {
+ t.Fatalf("the file we generate must parse: %v", err)
+ }
+ if got.Location != "Krakow" || got.Hours != want.Hours || got.Icons != want.Icons {
+ t.Fatalf("round trip changed values:\n got %+v\nwant %+v", got, want)
+ }
+ if err := got.Validate(); err != nil {
+ t.Fatalf("the file we generate must validate: %v", err)
+ }
+}