151 lines
4.4 KiB
Go
151 lines
4.4 KiB
Go
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
|||
|
|
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
|
||
|
|
|
||
|
|
package templates
|
||
|
|
|
||
|
|
import (
|
||
|
|
"errors"
|
||
|
|
"os"
|
||
|
|
"path/filepath"
|
||
|
|
"testing"
|
||
|
|
)
|
||
|
|
|
||
|
|
// addTemplate fails the test when a template cannot be created, which is
|
||
|
|
// not what is under test in the cases that use it.
|
||
|
|
func addTemplate(t *testing.T, s *Store, tpl PostTemplate) *PostTemplate {
|
||
|
|
t.Helper()
|
||
|
|
created, err := s.Add(tpl)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("Add(%q): %v", tpl.Name, err)
|
||
|
|
}
|
||
|
|
return created
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestAddAndList(t *testing.T) {
|
||
|
|
path := filepath.Join(t.TempDir(), "templates.toml")
|
||
|
|
s := New(path)
|
||
|
|
tpl, err := s.Add(PostTemplate{
|
||
|
|
Name: "Review",
|
||
|
|
Tags: []string{"review"},
|
||
|
|
Body: "## Summary\n",
|
||
|
|
Title: "Review: ",
|
||
|
|
Slug: "review",
|
||
|
|
})
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("Add: %v", err)
|
||
|
|
}
|
||
|
|
if tpl.Name != "Review" {
|
||
|
|
t.Fatalf("tpl = %+v", tpl)
|
||
|
|
}
|
||
|
|
all := s.All()
|
||
|
|
if len(all) != 1 || all[0].Name != "Review" || len(all[0].Tags) != 1 {
|
||
|
|
t.Fatalf("templates = %v", all)
|
||
|
|
}
|
||
|
|
if all[0].Body != "## Summary\n" || all[0].Title != "Review: " || all[0].Slug != "review" {
|
||
|
|
t.Fatalf("template fields = %+v", all[0])
|
||
|
|
}
|
||
|
|
if _, err := s.Add(PostTemplate{Name: "Review"}); !errors.Is(err, ErrNameTaken) {
|
||
|
|
t.Fatalf("duplicate accepted: %v", err)
|
||
|
|
}
|
||
|
|
if _, err := s.Add(PostTemplate{}); !errors.Is(err, ErrEmptyName) {
|
||
|
|
t.Fatalf("empty name accepted: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
info, err := os.Stat(path)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("stat: %v", err)
|
||
|
|
}
|
||
|
|
if info.Mode().Perm() != 0o600 {
|
||
|
|
t.Fatalf("mode = %v", info.Mode().Perm())
|
||
|
|
}
|
||
|
|
|
||
|
|
reopened := New(path)
|
||
|
|
if len(reopened.All()) != 1 {
|
||
|
|
t.Fatalf("reopened = %v", reopened.All())
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// The extra fields survive the round trip through the file, which is
|
||
|
|
// what lets a scientific template pre-fill a DOI, a series or an ORCID.
|
||
|
|
func TestFieldsRoundTrip(t *testing.T) {
|
||
|
|
path := filepath.Join(t.TempDir(), "templates.toml")
|
||
|
|
s := New(path)
|
||
|
|
addTemplate(t, s, PostTemplate{
|
||
|
|
Name: "Paper",
|
||
|
|
Fields: map[string]string{
|
||
|
|
"doi": "10.5555/",
|
||
|
|
"orcid": "0000-0002-1825-0097",
|
||
|
|
"series": "tds",
|
||
|
|
"series_order": "2",
|
||
|
|
},
|
||
|
|
})
|
||
|
|
reopened := New(path)
|
||
|
|
all := reopened.All()
|
||
|
|
if len(all) != 1 {
|
||
|
|
t.Fatalf("templates = %v", all)
|
||
|
|
}
|
||
|
|
fields := all[0].Fields
|
||
|
|
if fields["doi"] != "10.5555/" || fields["orcid"] != "0000-0002-1825-0097" ||
|
||
|
|
fields["series"] != "tds" || fields["series_order"] != "2" {
|
||
|
|
t.Fatalf("fields = %v", fields)
|
||
|
|
}
|
||
|
|
// A template without extra fields reads back with none.
|
||
|
|
addTemplate(t, s, PostTemplate{Name: "Bare"})
|
||
|
|
for _, tpl := range New(path).All() {
|
||
|
|
if tpl.Name == "Bare" && tpl.Fields != nil {
|
||
|
|
t.Fatalf("bare template has fields: %v", tpl.Fields)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestDelete(t *testing.T) {
|
||
|
|
s := New(filepath.Join(t.TempDir(), "templates.toml"))
|
||
|
|
addTemplate(t, s, PostTemplate{Name: "A"})
|
||
|
|
if err := s.Delete("A"); err != nil {
|
||
|
|
t.Fatalf("Delete: %v", err)
|
||
|
|
}
|
||
|
|
if err := s.Delete("A"); !errors.Is(err, ErrNoSuchTemplate) {
|
||
|
|
t.Fatalf("second Delete = %v, want ErrNoSuchTemplate", err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestMissingAndBrokenFiles(t *testing.T) {
|
||
|
|
if got := New(filepath.Join(t.TempDir(), "nope.toml")).All(); got != nil {
|
||
|
|
t.Fatalf("templates = %v, want none", got)
|
||
|
|
}
|
||
|
|
path := filepath.Join(t.TempDir(), "templates.toml")
|
||
|
|
if err := os.WriteFile(path, []byte("broken = = ="), 0o600); err != nil {
|
||
|
|
t.Fatalf("write: %v", err)
|
||
|
|
}
|
||
|
|
if got := New(path).All(); got != nil {
|
||
|
|
t.Fatalf("templates = %v, want none", got)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestEntriesWithoutNameSkipped(t *testing.T) {
|
||
|
|
path := filepath.Join(t.TempDir(), "templates.toml")
|
||
|
|
body := "[[templates]]\nbody = \"no name\"\n\n[[templates]]\nname = \"ok\"\n"
|
||
|
|
if err := os.WriteFile(path, []byte(body), 0o600); err != nil {
|
||
|
|
t.Fatalf("write: %v", err)
|
||
|
|
}
|
||
|
|
all := New(path).All()
|
||
|
|
if len(all) != 1 || all[0].Name != "ok" {
|
||
|
|
t.Fatalf("templates = %v", all)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// A hand-written fields table with a scalar of any TOML type arrives as
|
||
|
|
// its text, so a series order written bare as a number still fills the
|
||
|
|
// form.
|
||
|
|
func TestFieldsHandWrittenTable(t *testing.T) {
|
||
|
|
path := filepath.Join(t.TempDir(), "templates.toml")
|
||
|
|
body := "[[templates]]\nname = \"paper\"\n[templates.fields]\nseries_order = 3\ndoi = \"10.1/x\"\n"
|
||
|
|
if err := os.WriteFile(path, []byte(body), 0o600); err != nil {
|
||
|
|
t.Fatalf("write: %v", err)
|
||
|
|
}
|
||
|
|
all := New(path).All()
|
||
|
|
if len(all) != 1 || all[0].Fields["series_order"] != "3" || all[0].Fields["doi"] != "10.1/x" {
|
||
|
|
t.Fatalf("templates = %+v", all)
|
||
|
|
}
|
||
|
|
}
|