- suite init создаёт директорию и манифест со скелетом таблиц; suite add пишет файл конвенции и вправляет запись в suite.toml, сохраняя комментарии - без аргументов команды спрашивают поля с подсказками, с флагами берут всё сразу и не спрашивают ничего; без терминала пустой вызов отказывает - строка о версии языка генерируется из словаря набора, поэтому созданный файл проходит suite check без правок - починено разрешение extends: короткая форма бралась по суффиксу и могла указать на сам файл; теперь неоднозначность либо избегается при записи, либо сообщается ошибкой
131 lines
3.7 KiB
Go
131 lines
3.7 KiB
Go
package manifest_test
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.vakhrushev.me/av/convy/internal/manifest"
|
|
)
|
|
|
|
func TestAddEntryKeepsComments(t *testing.T) {
|
|
source := `# The suite manifest.
|
|
|
|
[language]
|
|
version = 1
|
|
|
|
# ─── Topics ───
|
|
#
|
|
# A topic is a set of rules about one focus of development.
|
|
|
|
[topics.live]
|
|
config = "configuration"
|
|
time = "time"
|
|
|
|
[topics.retired]
|
|
# Empty. Retired names land here together with a reason and a date.
|
|
`
|
|
got, err := manifest.AddEntry([]byte(source), "topics.live", "logging", "logging: levels, structure")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
out := string(got)
|
|
|
|
for _, want := range []string{
|
|
"# ─── Topics ───",
|
|
"# A topic is a set of rules about one focus of development.",
|
|
"# Empty. Retired names land here together with a reason and a date.",
|
|
`logging = "logging: levels, structure"`,
|
|
} {
|
|
if !strings.Contains(out, want) {
|
|
t.Errorf("the result lost %q:\n%s", want, out)
|
|
}
|
|
}
|
|
}
|
|
|
|
// A table whose keys are already sorted keeps its order; one ordered by hand
|
|
// gets the entry appended, so that a grouping by directory survives.
|
|
func TestAddEntryRespectsExistingOrder(t *testing.T) {
|
|
sorted := `[topics.live]
|
|
config = "c"
|
|
time = "t"
|
|
`
|
|
got, err := manifest.AddEntry([]byte(sorted), "topics.live", "logging", "l")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
wantSorted := "[topics.live]\nconfig = \"c\"\nlogging = \"l\"\ntime = \"t\"\n"
|
|
if string(got) != wantSorted {
|
|
t.Errorf("a sorted table was not kept sorted:\n%s", got)
|
|
}
|
|
|
|
grouped := `[prefixes.live]
|
|
TIME = "conventions/arch/time.md"
|
|
CONF = "conventions/arch/config.md"
|
|
GTIM = "conventions/lang/go/time.md"
|
|
`
|
|
got, err = manifest.AddEntry([]byte(grouped), "prefixes.live", "GCFG", "conventions/lang/go/config.md")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.HasSuffix(strings.TrimRight(string(got), "\n"), `GCFG = "conventions/lang/go/config.md"`) {
|
|
t.Errorf("a hand-ordered table did not get the entry appended:\n%s", got)
|
|
}
|
|
}
|
|
|
|
func TestAddEntryIntoEmptyTable(t *testing.T) {
|
|
source := `[topics.live]
|
|
# Nothing yet.
|
|
|
|
[topics.retired]
|
|
`
|
|
got, err := manifest.AddEntry([]byte(source), "topics.live", "time", "time")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := "[topics.live]\n# Nothing yet.\ntime = \"time\"\n\n[topics.retired]\n"
|
|
if string(got) != want {
|
|
t.Errorf("insertion into an empty table went wrong:\n%q", got)
|
|
}
|
|
}
|
|
|
|
// A comment block separated from an empty table by a blank line explains the
|
|
// table header standing below it, not the one above. Filing an entry after such
|
|
// a block puts it under the wrong explanation.
|
|
func TestAddEntryIntoEmptyTableStopsBeforeTheNextComment(t *testing.T) {
|
|
source := `[topics.live]
|
|
|
|
# Retired names land here together with a reason and a date.
|
|
|
|
[topics.retired]
|
|
`
|
|
got, err := manifest.AddEntry([]byte(source), "topics.live", "time", "time")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
want := "[topics.live]\ntime = \"time\"\n\n# Retired names land here together with a reason and a date.\n\n[topics.retired]\n"
|
|
if string(got) != want {
|
|
t.Errorf("the entry was filed under the wrong comment:\n%q", got)
|
|
}
|
|
}
|
|
|
|
func TestAddEntryRejectsDuplicateAndMissingTable(t *testing.T) {
|
|
source := "[topics.live]\ntime = \"t\"\n"
|
|
if _, err := manifest.AddEntry([]byte(source), "topics.live", "time", "t"); err == nil {
|
|
t.Error("a duplicate key was accepted")
|
|
}
|
|
if _, err := manifest.AddEntry([]byte(source), "prefixes.live", "TIME", "x.md"); err == nil {
|
|
t.Error("a missing table was accepted")
|
|
}
|
|
}
|
|
|
|
func TestAddEntryQuotesWhatIsNotBare(t *testing.T) {
|
|
source := "[topics.live]\n"
|
|
got, err := manifest.AddEntry([]byte(source), "topics.live", "web ui", `a "quoted" thing`)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(string(got), `"web ui" = "a \"quoted\" thing"`) {
|
|
t.Errorf("key or value was not escaped:\n%s", got)
|
|
}
|
|
}
|