package tentacle import ( "bytes" "os" "path/filepath" "reflect" "strings" "testing" ) func TestRegistryEmptyRoundTripAndConflict(t *testing.T) { path := filepath.Join(t.TempDir(), "settings", "tentacles.toml") registry := &Registry{Path: path} entries, err := registry.Load() if err != nil || len(entries) != 0 { t.Fatalf("fresh registry: %v %v", entries, err) } if _, err := os.Stat(filepath.Dir(path)); !os.IsNotExist(err) { t.Fatal("reading defaults created files") } entries = []Entry{{ID: "example", Program: []string{"/usr/bin/example", "literal $(data)"}, Enabled: true, Presentation: true}} if err := registry.Save(entries); err != nil { t.Fatal(err) } info, _ := os.Stat(path) if info.Mode().Perm() != 0600 { t.Fatalf("permissions: %v", info.Mode()) } other := &Registry{Path: path} loaded, err := other.Load() if err != nil || !reflect.DeepEqual(entries, loaded) { t.Fatalf("round trip: %v %v", loaded, err) } entries[0].Enabled = false if err := registry.Save(entries); err != nil { t.Fatal(err) } before, _ := os.ReadFile(path) if err := other.Save(nil); err == nil { t.Fatal("stale writer replaced current registry") } after, _ := os.ReadFile(path) if !bytes.Equal(before, after) { t.Fatal("failed save changed file") } if err := registry.Save(nil); err != nil { t.Fatal(err) } loaded, err = other.Load() if err != nil || len(loaded) != 0 { t.Fatalf("remove all: %v %v", loaded, err) } } func TestRegistryRejectsInvalidWithoutReplacement(t *testing.T) { path := filepath.Join(t.TempDir(), "tentacles.toml") for _, data := range []string{ "", "version = 2\n", "version = 1\nunknown = true\n", "version = 1\n[[tentacles]]\nid = 'relative'\nprogram = ['relative']\n", "version = 1\n" + strings.Repeat("[[tentacles]]\nid = 'duplicate'\nprogram = ['/usr/bin/example']\n", 2), strings.Repeat("x", MaxFrameBytes+1), } { if err := os.WriteFile(path, []byte(data), 0600); err != nil { t.Fatal(err) } registry := &Registry{Path: path} if _, err := registry.Load(); err == nil { t.Fatalf("accepted invalid registry: %.80s", data) } if err := registry.Save(nil); err == nil { t.Fatal("saved after failed load") } after, _ := os.ReadFile(path) if string(after) != data { t.Fatal("invalid registry overwritten") } } link := path + ".link" if err := os.Symlink(path, link); err != nil { t.Fatal(err) } if _, err := (&Registry{Path: link}).Load(); err == nil { t.Fatal("accepted symlink") } } func TestRegistryInteractionGrantRoundTrip(t *testing.T) { registry := &Registry{Path: filepath.Join(t.TempDir(), "tentacles.toml")} if _, err := registry.Load(); err != nil { t.Fatal(err) } entry := Entry{ID: "wormhole", Program: []string{"/tmp/wormhole-tentacle"}, Enabled: true, Presentation: true, Interaction: true} if err := registry.Save([]Entry{entry}); err != nil { t.Fatal(err) } loaded, err := registry.Load() if err != nil || len(loaded) != 1 || !loaded[0].Spec().Interaction { t.Fatal(loaded, err) } entry.Presentation = false if err := registry.Save([]Entry{entry}); err == nil { t.Fatal("interaction without presentation accepted") } }