Files
settings/settings_test.go
2026-08-17 19:33:06 -04:00

283 lines
8.5 KiB
Go

package settings
import (
"bytes"
"crypto/rand"
"encoding/json"
"errors"
"fmt"
"io"
"log"
"maps"
"os"
"strings"
"testing"
"time"
)
var (
AdditionalKeyValuePairs = map[string]string{
"D": "d",
"E": "e",
"F": "f",
}
)
func TestSettings(t *testing.T) {
err := os.Remove(TheTestFilename)
if err != nil && !errors.Is(err, os.ErrNotExist) {
t.Fatalf("error cleaning up %s from previous run: %v\n", TheTestFilename, err)
}
var buffer bytes.Buffer
err = WriteMapToWriter(&buffer, KeyValuePairs)
if err != nil {
t.Fatalf("error writing test data to *bytes.Buffer: %v\n", err)
}
err = os.WriteFile(TheTestFilename, buffer.Bytes(), 0664)
if err != nil {
t.Fatalf("error writing %s: %v\n", TheTestFilename, err)
}
defer func() {
if err := os.Remove(TheTestFilename); err != nil {
t.Fatalf("error cleaning up %s from this run: %v\n", TheTestFilename, err)
}
}()
settings := TheSettings
err = settings.Update()
if err != nil {
t.Fatalf("error updating settings: %v\n", err)
} else if want, got := TheTestFilename, settings.GetFilename(); want != got {
t.Fatalf("error: wanted '%s'; got '%s'\n", want, got)
} else if got := settings.modtime; got.Equal(time.Time{}) {
t.Fatalf("error: modtime == (time.Time{}) - not updated when initialized")
} else {
for k, v := range KeyValuePairs {
if !settings.ContainsKey(k) {
t.Fatalf("error: key '%s' not found\n", k)
} else if want, got := v, settings.GetKeyValue(k); want != got {
t.Fatalf("error: wanted '%s' for key '%s'; got '%s'\n", want, k, got)
}
}
}
// change the filename
TheNewTestFilename := fmt.Sprintf("New%s", TheTestFilename)
buffer.Reset()
err = WriteMapToWriter(&buffer, AdditionalKeyValuePairs)
if err != nil {
t.Fatalf("error writing new map to *bytes.Buffer: %v\n", err)
}
err = os.WriteFile(TheNewTestFilename, buffer.Bytes(), 0664)
if err != nil {
t.Fatalf("error writing new test file %s: %v\n", TheNewTestFilename, err)
}
defer func() {
if err := os.Remove(TheNewTestFilename); err != nil {
t.Fatalf("error deleting %s: %v", TheNewTestFilename, err)
}
}()
if updated := settings.SetFilename(TheNewTestFilename); !updated {
t.Fatalf("error: SetFilename() indicated the filename was not updated...\n")
} else if updated := settings.SetFilename(settings.GetFilename()); updated {
t.Fatalf("error: setting filename to itself still resulted in updated=true\n")
}
for k, v := range AdditionalKeyValuePairs {
if !settings.ContainsKey(k) {
t.Fatalf("error: key '%s' not found\n", k)
} else if want, got := v, settings.GetKeyValue(k); want != got {
t.Fatalf("error: wanted '%s' for key '%s'; got '%s'\n", want, k, got)
}
}
// update the file, wait, then try again
newKeyValuePairs := make(map[string]string)
maps.Copy(newKeyValuePairs, KeyValuePairs)
maps.Copy(newKeyValuePairs, AdditionalKeyValuePairs)
newKeyValuePairs["G"] = "g"
buffer.Reset()
err = WriteMapToWriter(&buffer, newKeyValuePairs)
if err != nil {
t.Fatalf("error writing new key value pairs to *bytes.Buffer: %v\n", err)
}
err = os.WriteFile(TheNewTestFilename, buffer.Bytes(), 0664)
if err != nil {
t.Fatalf("error writing updates to %s: %v\n", TheNewTestFilename, err)
}
select {
case <-t.Context().Done():
t.Fatalf("error: timed out before finishing wait")
case <-time.After(time.Duration(float64(MaintenanceRoutinePace.Nanoseconds()) * 1.1)):
}
for k, v := range newKeyValuePairs {
if !settings.ContainsKey(k) {
t.Fatalf("error: key '%s' not found in settings\n", k)
} else if want, got := v, settings.GetKeyValue(k); want != got {
t.Fatalf("error: wanted '%s' for key '%s'; got '%s'\n", want, k, got)
}
}
buffer.Reset()
defaultLogWriter := log.Writer()
log.SetOutput(&buffer)
// set settings to a fake filename
WarnIfFileNotFound = true
if updated := settings.SetFilename("fakefilename.txt"); !updated {
t.Fatalf("failed to update filename to fake filename...\n")
}
defer settings.SetFilename(TheTestFilename)
log.SetOutput(defaultLogWriter)
WarnIfFileNotFound = false
if !strings.Contains(buffer.String(), "no such file or directory") {
t.Fatalf("error: wanted error indicating 'no such file or directory'; got %v\n", err)
}
}
func TestDump(t *testing.T) {
dump, err := TheSettings.Dump()
if err != nil {
t.Fatalf("error dumping settings: %v\n", err)
}
scanner := NewScanner(bytes.NewReader(dump))
var found int
loop:
for {
key, value, err := scanner.ReadNextLine()
if err != nil {
if !errors.Is(err, io.EOF) {
t.Fatalf("error reading next line: %v\n", err)
}
break loop
}
if want, got := TheSettings.GetKeyValue(key), value; want != got {
t.Fatalf("error: wanted key %q value %q; got %q\n", key, want, got)
}
found++
}
if want, got := len(TheSettings.contents), found; want != got {
t.Fatalf("error: wanted %d entries; got %d\n", want, got)
}
}
func TestDumpJson(t *testing.T) {
marshaled, err := TheSettings.DumpToJson()
if err != nil {
t.Fatalf("error dumping to json: %v\n", err)
}
var unmarshaled map[string]string
err = json.Unmarshal(marshaled, &unmarshaled)
if err != nil {
t.Fatalf("error unmarshaling json dump: %v\n", err)
}
if want, got := TheSettings.contents, unmarshaled; !maps.Equal(want, got) {
t.Fatalf("error: wanted %v; got %v\n", want, got)
}
}
func TestSetKeyValue(t *testing.T) {
key, value := rand.Text(), rand.Text()
if !TheSettings.SetKeyValue(key, value) {
t.Fatalf("SetKeyValue didn't update?\n")
}
if want, got := value, TheSettings.GetKeyValue(key); want != got {
t.Fatalf("error: wanted %q; got %q\n", want, got)
}
}
func TestParseBool(t *testing.T) {
TheTestItems := map[string]bool{
"yes": true,
"on": true,
"true": true,
"True": true,
"TRUE": true,
"no": false,
"off": false,
"false": false,
}
for boolString, want := range TheTestItems {
got, err := ParseBool(boolString)
if err != nil {
t.Fatalf("error: %v\n", err)
}
if want != got {
t.Fatalf("error: wanted %s=%v; got %v\n", boolString, want, got)
}
}
TheBadTestItems := []string{
"blue",
"cat",
"https://google.com",
}
for _, boolString := range TheBadTestItems {
got, err := ParseBool(boolString)
if err == nil {
t.Fatalf("error: successfully parsed %s as bool %v...\n", boolString, got)
}
}
}
func TestGetStringOrDefault(t *testing.T) {
dump, err := TheSettings.Dump()
if err != nil {
t.Fatalf("error getting dump: %v\n", err)
}
scanner := NewScanner(bytes.NewReader(dump))
loop:
for {
key, value, err := scanner.ReadNextLine()
if err != nil {
if !errors.Is(err, io.EOF) {
t.Fatalf("error reading from dump: %v\n", err)
}
break loop
}
if want, got := value, TheSettings.GetStringOrDefault(key, "SomeInvalidDefault"); want != got {
t.Fatalf("error: wanted key %q=%q; got %q\n", key, want, got)
}
}
badKey := "some new key"
badValue := "some invalid value"
if want, got := badValue, TheSettings.GetStringOrDefault(badKey, badValue); want != got {
t.Fatalf("error: wanted key %q=%q; got %q\n", badKey, want, got)
}
}
func TestGetBoolOrDefault(t *testing.T) {
key, value := "some bool value", "on"
TheSettings.SetKeyValue(key, value)
if want, got := true, TheSettings.GetBoolOrDefault(key, false); want != got {
t.Fatalf("error: wanted %q=%v; got %v\n", key, want, got)
}
value = "shark"
TheSettings.SetKeyValue(key, value)
if want, got := false, TheSettings.GetBoolOrDefault(key, false); want != got {
t.Fatalf("error: wanted %q=%v; got %v\n", key, want, got)
}
}
func TestGetDurationOrDefault(t *testing.T) {
key, value := "some duration value", "10s"
TheSettings.SetKeyValue(key, value)
if want, got := time.Second*10, TheSettings.GetDurationOrDefault(key, time.Minute*10); want != got {
t.Fatalf("error: wanted %q=%s; got %s\n", key, want, got)
}
value = "loud"
TheSettings.SetKeyValue(key, value)
if want, got := time.Minute*10, TheSettings.GetDurationOrDefault(key, time.Minute*10); want != got {
t.Fatalf("error: wanted %q=%s; got %s\n", key, want, got)
}
}
func TestGetIntOrDefault(t *testing.T) {
key, value := "some int value", "10"
TheSettings.SetKeyValue(key, value)
if want, got := 10, TheSettings.GetIntOrDefault(key, 200); want != got {
t.Fatalf("error: wanted %q=%d; got %d\n", key, want, got)
}
value = "cat"
TheSettings.SetKeyValue(key, value)
if want, got := 200, TheSettings.GetIntOrDefault(key, 200); want != got {
t.Fatalf("error: wanted default value %d for bad key; got %d\n", want, got)
}
if want, got := 200, TheSettings.GetIntOrDefault("some fake bad key", 200); want != got {
t.Fatalf("error: wanted default value %d for bad key; got %d\n", want, got)
}
}