110 lines
2.6 KiB
Go
110 lines
2.6 KiB
Go
package mujica
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
var (
|
|
docsGoBlock = regexp.MustCompile("(?s)```go\n(.*?)```")
|
|
docsSpace = regexp.MustCompile(`\s+`)
|
|
docsPageID = regexp.MustCompile(`ID: "(\d{3})"`)
|
|
)
|
|
|
|
// docsLines normalizes code into its non-empty, non-comment lines without whitespace.
|
|
func docsLines(code string) []string {
|
|
var out []string
|
|
for _, l := range strings.Split(code, "\n") {
|
|
s := strings.TrimSpace(l)
|
|
if s != "" && !strings.HasPrefix(s, "//") {
|
|
out = append(out, docsSpace.ReplaceAllString(s, ""))
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// docsContains reports whether want appears in order inside have.
|
|
func docsContains(have, want []string) bool {
|
|
i := 0
|
|
for _, h := range have {
|
|
if i < len(want) && h == want[i] {
|
|
i++
|
|
}
|
|
}
|
|
return i == len(want)
|
|
}
|
|
|
|
func readGlob(t *testing.T, pattern string) map[string]string {
|
|
t.Helper()
|
|
files, err := filepath.Glob(pattern)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
out := map[string]string{}
|
|
for _, f := range files {
|
|
b, err := os.ReadFile(f)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
out[f] = string(b)
|
|
}
|
|
return out
|
|
}
|
|
|
|
// TestDocSnippetsAreCompiledExamples keeps each doc's first Go block, in order, inside one Example.
|
|
func TestDocSnippetsAreCompiledExamples(t *testing.T) {
|
|
var examples [][]string
|
|
for _, src := range readGlob(t, "example_*_test.go") {
|
|
for _, fn := range strings.Split(src, "\nfunc Example")[1:] {
|
|
examples = append(examples, docsLines(fn))
|
|
}
|
|
}
|
|
for d, src := range readGlob(t, "docs/components/*.md") {
|
|
m := docsGoBlock.FindStringSubmatch(src)
|
|
if m == nil {
|
|
t.Errorf("%s has no Go example", d)
|
|
continue
|
|
}
|
|
want, found := docsLines(m[1]), false
|
|
for _, ex := range examples {
|
|
if docsContains(ex, want) {
|
|
found = true
|
|
break
|
|
}
|
|
}
|
|
if !found {
|
|
t.Errorf("%s: its Go block is not, in order, inside any compiled Example", d)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestDocsMatchGalleryPages wants exactly one doc and one gallery page per component ID.
|
|
func TestDocsMatchGalleryPages(t *testing.T) {
|
|
if n := len(readGlob(t, "docs/components/*.md")); n != 318 {
|
|
t.Fatalf("component docs = %d, want 318", n)
|
|
}
|
|
pages := map[string]int{}
|
|
for _, src := range readGlob(t, "examples/gallery/pages_*.go") {
|
|
for _, m := range docsPageID.FindAllStringSubmatch(src, -1) {
|
|
pages[m[1]]++
|
|
}
|
|
}
|
|
docs := map[string]int{}
|
|
for d := range readGlob(t, "docs/components/*.md") {
|
|
docs[filepath.Base(d)[:3]]++
|
|
}
|
|
for id, n := range pages {
|
|
if n != 1 || docs[id] != 1 {
|
|
t.Errorf("component %s: %d gallery pages, %d docs; want 1 and 1", id, n, docs[id])
|
|
}
|
|
}
|
|
for id, n := range docs {
|
|
if pages[id] == 0 {
|
|
t.Errorf("doc %s (%d files) has no gallery page", id, n)
|
|
}
|
|
}
|
|
}
|