проектные команды и ссылки на источник
- заведён internal/source: уровни ссылаются друг на друга путём на диске или git-репозиторием, ревизия закрепляется хвостом #ref; клон делается заново и удаляется, кэша нет - добавлены init, add, pull, list, check в проекте — манифест .conventions.toml, сборка копий по разу на компонент, маркер локальной части, READING.md рядом - проверки формы развязаны с набором: принимают lang.Vocabulary, а язык копии узнаётся по строке о версии — манифеста рядом с ней нет
This commit is contained in:
@@ -0,0 +1,133 @@
|
||||
package project_test
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
"git.vakhrushev.me/av/convy/internal/doc"
|
||||
"git.vakhrushev.me/av/convy/internal/lang"
|
||||
"git.vakhrushev.me/av/convy/internal/project"
|
||||
)
|
||||
|
||||
const versionLine = `Ключевые слова ДОЛЖЕН, НЕ ДОЛЖЕН, СЛЕДУЕТ, НЕ СЛЕДУЕТ, ДОПУСКАЕТСЯ и метки
|
||||
ПОЧЕМУ, ПРИМЕРЫ, МЕХАНИЗИРОВАНО и СНЯТО толкуются как описано в языке
|
||||
конвенций версии 1 — тогда и только тогда, когда написаны заглавными.`
|
||||
|
||||
const baseLayer = `---
|
||||
topic: time
|
||||
prefix: TIME
|
||||
---
|
||||
|
||||
# Время
|
||||
|
||||
Как приложение записывает моменты.
|
||||
|
||||
` + versionLine + `
|
||||
|
||||
## Правила
|
||||
|
||||
### TIME-1. Момент записывается в UTC
|
||||
|
||||
**ДОЛЖЕН.** Момент времени записывается с суффиксом Z.
|
||||
|
||||
**ПОЧЕМУ.** Без явного смещения не видно, в какой зоне запись сделана.
|
||||
`
|
||||
|
||||
const goLayer = `---
|
||||
topic: time
|
||||
prefix: GTIM
|
||||
lang: go
|
||||
extends: arch/time.md
|
||||
---
|
||||
|
||||
# Время: реализация на Go
|
||||
|
||||
Как базовый слой выполняется в Go-коде.
|
||||
|
||||
` + versionLine + `
|
||||
|
||||
## Правила
|
||||
|
||||
### GTIM-1. «Сейчас» берётся у слоя хранилища
|
||||
|
||||
**ДОЛЖЕН.** Текущее время приходит из ` + "`store.Now()`" + `.
|
||||
|
||||
**ПОЧЕМУ.** Единая точка даёт гарантированный UTC.
|
||||
`
|
||||
|
||||
func layers(t *testing.T, bodies ...string) []*doc.Document {
|
||||
t.Helper()
|
||||
v, err := lang.Lookup(1, "ru")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var out []*doc.Document
|
||||
for i, body := range bodies {
|
||||
d, err := doc.Parse("layer.md", body)
|
||||
if err != nil {
|
||||
t.Fatalf("layer %d: %v", i, err)
|
||||
}
|
||||
d.Blocks(v)
|
||||
out = append(out, d)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func vocab(t *testing.T) lang.Vocabulary {
|
||||
t.Helper()
|
||||
v, err := lang.Lookup(1, "ru")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
// A copy is one document rather than three files glued together: the first
|
||||
// layer is the document, and every layer after it is a section of it.
|
||||
func TestRenderMakesTheLayersSectionsOfOneDocument(t *testing.T) {
|
||||
body := project.Render("time", layers(t, baseLayer, goLayer), vocab(t))
|
||||
|
||||
for _, want := range []string{
|
||||
"---\norigin: time\n---",
|
||||
"\n# Время\n",
|
||||
"\n## Правила\n",
|
||||
"\n### TIME-1. Момент записывается в UTC\n",
|
||||
"\n## Время: реализация на Go\n",
|
||||
"\n### Правила\n",
|
||||
"\n#### GTIM-1. «Сейчас» берётся у слоя хранилища\n",
|
||||
} {
|
||||
if !strings.Contains(body, want) {
|
||||
t.Errorf("the copy lacks %q:\n%s", want, body)
|
||||
}
|
||||
}
|
||||
if strings.Contains(body, "topic: time\nprefix:") {
|
||||
t.Errorf("the front matter of a layer travelled into the copy:\n%s", body)
|
||||
}
|
||||
if strings.Contains(body, "extends:") {
|
||||
t.Errorf("a path of the suite travelled into the copy:\n%s", body)
|
||||
}
|
||||
}
|
||||
|
||||
// The line about the language is what makes a copy readable on its own, and
|
||||
// saying it three times over says nothing more than saying it once.
|
||||
func TestRenderNamesTheLanguageOnce(t *testing.T) {
|
||||
body := project.Render("time", layers(t, baseLayer, goLayer), vocab(t))
|
||||
if n := strings.Count(body, "толкуются как описано"); n != 1 {
|
||||
t.Errorf("the language version line appears %d times:\n%s", n, body)
|
||||
}
|
||||
if !strings.Contains(body, "конвенций версии 1") {
|
||||
t.Errorf("the language version line is gone altogether:\n%s", body)
|
||||
}
|
||||
}
|
||||
|
||||
// A single layer is not a special case: assembly out of one layer is a copy of
|
||||
// it, with no section headings invented around it.
|
||||
func TestRenderOfOneLayerKeepsItsLevels(t *testing.T) {
|
||||
body := project.Render("time", layers(t, baseLayer), vocab(t))
|
||||
if !strings.Contains(body, "\n# Время\n") || !strings.Contains(body, "\n### TIME-1.") {
|
||||
t.Errorf("a single layer was restructured:\n%s", body)
|
||||
}
|
||||
if strings.Contains(body, "####") {
|
||||
t.Errorf("headings of a single layer were demoted:\n%s", body)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user