aboutsummaryrefslogtreecommitdiff
path: root/internal/admin/api_colors_test.go
diff options
context:
space:
mode:
authorhistoria <[not public]>2026-07-15 05:10:40 -0400
committerhistoria <[not public]>2026-07-15 05:10:40 -0400
commit84dd8c7557d8b9d92cd8d339afc28a0fd9a3a896 (patch)
tree60c47059d6776e7b91fb516ebdb04a0932c9aa59 /internal/admin/api_colors_test.go
parentbeb188ce050fb76cdddc0bbeedee7ec608e47995 (diff)
downloadthehouseoficarus-84dd8c7557d8b9d92cd8d339afc28a0fd9a3a896.tar.gz
feat(admin): color scheme test page added
Diffstat (limited to 'internal/admin/api_colors_test.go')
-rw-r--r--internal/admin/api_colors_test.go159
1 files changed, 159 insertions, 0 deletions
diff --git a/internal/admin/api_colors_test.go b/internal/admin/api_colors_test.go
new file mode 100644
index 0000000..d1e5e9a
--- /dev/null
+++ b/internal/admin/api_colors_test.go
@@ -0,0 +1,159 @@
+package admin
+
+import (
+ "bytes"
+ "encoding/json"
+ "io"
+ "net/http"
+ "net/http/httptest"
+ "os"
+ "path/filepath"
+ "testing"
+
+ "thehouseoficarus/internal/config"
+)
+
+func newColorsTestServer(t *testing.T) (*AdminServer, string) {
+ t.Helper()
+ dir := t.TempDir()
+ path := filepath.Join(dir, "config.yaml")
+ if err := os.WriteFile(path, []byte("tick_length: 600\ndefault_colors:\n room_name: \"74 bold\"\n"), 0644); err != nil {
+ t.Fatal(err)
+ }
+ loaded, err := config.Load(path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return &AdminServer{cfg: loaded, configPath: path}, path
+}
+
+func TestColorsGet(t *testing.T) {
+ s, _ := newColorsTestServer(t)
+ req := httptest.NewRequest(http.MethodGet, "/api/colors", nil)
+ w := httptest.NewRecorder()
+ s.getColors(w, req)
+ if w.Code != http.StatusOK {
+ t.Fatalf("status %d", w.Code)
+ }
+ var out map[string]any
+ if err := json.Unmarshal(w.Body.Bytes(), &out); err != nil {
+ t.Fatal(err)
+ }
+ cats, _ := out["categories"].([]any)
+ if len(cats) != len(colorCategories) {
+ t.Fatalf("categories count: got %d want %d", len(cats), len(colorCategories))
+ }
+ preview, _ := out["preview"].([]any)
+ if len(preview) < 8 {
+ t.Fatalf("preview sections too few: %d", len(preview))
+ }
+}
+
+func TestColorsSaveAndPersist(t *testing.T) {
+ s, path := newColorsTestServer(t)
+ before := s.cfg.DefaultColors["room_name"]
+
+ body := map[string]any{"colors": map[string]string{"room_name": "FF bold"}}
+ b, _ := json.Marshal(body)
+ req := httptest.NewRequest(http.MethodPost, "/api/colors", bytes.NewReader(b))
+ req.Header.Set("Content-Type", "application/json")
+ w := httptest.NewRecorder()
+ s.saveColors(w, req)
+ if w.Code != http.StatusOK {
+ t.Fatalf("save status %d: %s", w.Code, w.Body.String())
+ }
+ if s.cfg.DefaultColors["room_name"] == before {
+ t.Fatalf("live map not updated")
+ }
+ if s.cfg.DefaultColors["room_name"] != "FF bold" {
+ t.Fatalf("live value = %q", s.cfg.DefaultColors["room_name"])
+ }
+ raw, err := os.ReadFile(path)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Contains(raw, []byte("FF bold")) {
+ t.Fatalf("config.yaml not persisted with new value; got:\n%s", string(raw))
+ }
+}
+
+func TestColorsSaveRejectsBadSpec(t *testing.T) {
+ s, _ := newColorsTestServer(t)
+ body := map[string]any{"colors": map[string]string{"room_name": "zzzzz"}}
+ b, _ := json.Marshal(body)
+ req := httptest.NewRequest(http.MethodPost, "/api/colors", bytes.NewReader(b))
+ req.Header.Set("Content-Type", "application/json")
+ w := httptest.NewRecorder()
+ s.saveColors(w, req)
+ if w.Code != http.StatusBadRequest {
+ t.Fatalf("expected 400, got %d: %s", w.Code, w.Body.String())
+ }
+}
+
+func TestColorsSaveRejectsUnknownKey(t *testing.T) {
+ s, _ := newColorsTestServer(t)
+ body := map[string]any{"colors": map[string]string{"nope": "FF"}}
+ b, _ := json.Marshal(body)
+ req := httptest.NewRequest(http.MethodPost, "/api/colors", bytes.NewReader(b))
+ req.Header.Set("Content-Type", "application/json")
+ w := httptest.NewRecorder()
+ s.saveColors(w, req)
+ if w.Code != http.StatusBadRequest {
+ t.Fatalf("expected 400, got %d", w.Code)
+ }
+}
+
+func TestColorsOffAllowed(t *testing.T) {
+ s, _ := newColorsTestServer(t)
+ body := map[string]any{"colors": map[string]string{"mob": "off"}}
+ b, _ := json.Marshal(body)
+ req := httptest.NewRequest(http.MethodPost, "/api/colors", bytes.NewReader(b))
+ req.Header.Set("Content-Type", "application/json")
+ w := httptest.NewRecorder()
+ s.saveColors(w, req)
+ if w.Code != http.StatusOK {
+ t.Fatalf("expected 200 for 'off', got %d: %s", w.Code, w.Body.String())
+ }
+}
+
+func TestColorsReset(t *testing.T) {
+ s, _ := newColorsTestServer(t)
+ s.cfg.DefaultColors["room_name"] = "FF"
+ req := httptest.NewRequest(http.MethodPost, "/api/colors/reset", nil)
+ w := httptest.NewRecorder()
+ s.handleColorsReset(w, req)
+ if w.Code != http.StatusOK {
+ t.Fatalf("status %d: %s", w.Code, w.Body.String())
+ }
+ if s.cfg.DefaultColors["room_name"] != "74 bold" {
+ t.Fatalf("reset did not restore builtin; got %q", s.cfg.DefaultColors["room_name"])
+ }
+}
+
+func TestColorsPreviewExhaustive(t *testing.T) {
+ s, _ := newColorsTestServer(t)
+ req := httptest.NewRequest(http.MethodGet, "/api/colors", nil)
+ w := httptest.NewRecorder()
+ s.getColors(w, req)
+ var out map[string]any
+ if err := json.Unmarshal(w.Body.Bytes(), &out); err != nil {
+ t.Fatal(err)
+ }
+ seen := map[string]bool{}
+ for _, sec := range out["preview"].([]any) {
+ for _, ln := range sec.(map[string]any)["lines"].([]any) {
+ for _, seg := range ln.(map[string]any)["segments"].([]any) {
+ c := seg.(map[string]any)["c"].(string)
+ if c != "" {
+ seen[c] = true
+ }
+ }
+ }
+ }
+ for _, cat := range colorCategories {
+ if !seen[cat.Name] {
+ t.Errorf("preview missing category: %s", cat.Name)
+ }
+ }
+ _ = io.Discard
+} \ No newline at end of file