Files
ZacharyZhang-NY 0e21870b64 Add media components 346-365; input.SlideBase, guarded Pad
An audio player with transport, scrubber and volume; an equalizer and
a visualizer; a playlist; a cassette, cartridge and record that turn
while they play and hold where they stop; piano keys, a step sequencer
and a tracker you can type into; a waveform, a 16:9 video frame, an
image compare, a gallery, a filmstrip, a record button and an FM tuner.

input exports SlideBase, the undrawn rail its sliders share; the
gallery treats exported Bases as building blocks, not components.
pixel's micro font gains '#' for notes like C#4. pixel.Pad and the
slide rail read input only while their base is enabled, so Inert or a
fresh Disabled stops a drag or a key already sent. AGENTS records why
a drawn container keeps the DISABLED description: MyGo paints a
disabled subtree at half opacity.
2026-10-12 06:17:12 -04:00

75 lines
2.0 KiB
Go

package gallery
import (
"go/ast"
"go/parser"
"go/token"
"os"
"path/filepath"
"strings"
"testing"
)
func TestRegistry(t *testing.T) {
slugs, ids := map[string]bool{}, map[int]bool{}
known := map[string]bool{}
for _, c := range Categories {
known[c.Key] = true
}
for _, e := range Entries() {
if e.Name == "" || e.Zh == "" || e.Summary == "" || e.Demo == nil {
t.Fatalf("entry %+v is incomplete", e)
}
if !known[e.Category] {
t.Fatalf("%s: unknown category %q", e.Name, e.Category)
}
if (e.ID == 0) != (e.Category == "foundations") || e.ID < 0 || e.ID > 500 {
t.Fatalf("%s: id %d in %s", e.Name, e.ID, e.Category)
}
if slugs[e.Slug()] || e.ID > 0 && ids[e.ID] {
t.Fatalf("%s: duplicate slug or id", e.Slug())
}
slugs[e.Slug()], ids[e.ID] = true, true
if !strings.HasPrefix(e.Code(), "func "+funcName(e.Demo)+"(") {
t.Fatalf("%s: code snippet %q", e.Slug(), e.Code()[:min(40, len(e.Code()))])
}
}
}
// Every exported component has a demo; Bases are not components.
func TestEveryComponentHasADemo(t *testing.T) {
var demos strings.Builder
for _, e := range Entries() {
demos.WriteString(e.Code())
}
for _, cat := range Categories[1:] {
files, _ := filepath.Glob(filepath.Join("..", cat.Key, "*.go"))
for _, f := range files {
if strings.HasSuffix(f, "_test.go") {
continue
}
src, err := os.ReadFile(f)
if err != nil {
t.Fatal(err)
}
file, err := parser.ParseFile(token.NewFileSet(), f, src, 0)
if err != nil {
t.Fatal(err)
}
for _, d := range file.Decls {
fn, ok := d.(*ast.FuncDecl)
if !ok || fn.Recv != nil || !fn.Name.IsExported() || strings.HasSuffix(fn.Name.Name, "Base") || fn.Type.Params.NumFields() == 0 {
continue
}
if p, ok := fn.Type.Params.List[0].Type.(*ast.StarExpr); ok {
if sel, ok := p.X.(*ast.SelectorExpr); ok && sel.Sel.Name == "Context" {
if call := cat.Key + "." + fn.Name.Name + "("; !strings.Contains(demos.String(), call) {
t.Errorf("%s has no demo", call)
}
}
}
}
}
}
}