// Copyright (c) 2026 Storm Dragon // SPDX-License-Identifier: GPL-3.0-or-later package tentacle import ( "git.stormux.org/storm/cthulhu/internal/interaction" "os" "path/filepath" "reflect" "testing" ) func TestPageStoreAtomicPersistenceAndExternalEdits(t *testing.T) { path := filepath.Join(t.TempDir(), "preferences.json") store := &PageStore{Path: path} values, err := store.Load() if err != nil || len(values) != 0 { t.Fatal(values, err) } if _, err := os.Stat(path); !os.IsNotExist(err) { t.Fatal("load created a file") } values["probe"] = map[string]map[string]interaction.Value{"page": {"name": {Text: "Example"}}} if err := store.Save(values); err != nil { t.Fatal(err) } info, _ := os.Stat(path) if info.Mode().Perm() != 0600 { t.Fatal(info.Mode()) } other := &PageStore{Path: path} loaded, err := other.Load() if err != nil || !reflect.DeepEqual(loaded, values) { t.Fatal(loaded, err) } loaded["probe"]["page"]["name"] = interaction.Value{Text: "Changed"} if err := other.Save(loaded); err != nil { t.Fatal(err) } if err := store.Save(values); err == nil { t.Fatal("overwrote another editor") } after, err := (&PageStore{Path: path}).Load() if err != nil || after["probe"]["page"]["name"].Text != "Changed" { t.Fatal(after, err) } } func TestPageStoreRejectsSymlinksMalformedAndUnloadedWrites(t *testing.T) { directory := t.TempDir() path := filepath.Join(directory, "preferences.json") store := &PageStore{Path: path} if store.Save(PageValues{}) == nil { t.Fatal("saved without loading") } for _, data := range []string{`null`, `{"probe":{},"probe":{}}`, `{"probe":`, `[]`} { if err := os.WriteFile(path, []byte(data), 0600); err != nil { t.Fatal(err) } if _, err := store.Load(); err == nil { t.Fatal("accepted", data) } if store.Save(PageValues{}) == nil { t.Fatal("saved after a failed load") } } link := filepath.Join(directory, "link") if err := os.Symlink(path, link); err != nil { t.Fatal(err) } if _, err := (&PageStore{Path: link}).Load(); err == nil { t.Fatal("followed a symlink") } }