Files
golang-cli/validate_test.go
T
pim 9e0a98ed07 feat: Validate + keypress subpackage; RFC-style design.md (v1.2.0)
Validate(root): optional startup/test check for tree authoring faults —
>1 slot child per node, empty word, duplicate sibling words, dead-end
node — traversing circular slots without looping (#3).

keypress subpackage: WaitForKey(ctx, cancel) cancels a context on any
keystroke for watch-style streaming commands, with per-GOOS cbreak
(linux TCGETS/TCSETS, BSD TIOCGETA/TIOCSETA) and a non-tty/unsupported
fallback that just waits on ctx. Lifts the last OpenBSD-specific bit out
of evpnc/maglevc's watch.go (#6).

docs: replace PROPOSAL.md with an RFC-2119 design.md (FR/NFR for the
library). Example now dogfoods Validate (a unit test) and keypress (a
bounded `watch` command).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 22:11:13 +02:00

57 lines
1.5 KiB
Go

// SPDX-FileCopyrightText: (C) Copyright 2026 Pim van Pelt <pim@ipng.ch>
// SPDX-License-Identifier: Apache-2.0
package cli
import (
"context"
"strings"
"testing"
)
// TestValidateClean checks that a well-formed tree (the builder fixture, which
// includes a circular slot) validates without error.
func TestValidateClean(t *testing.T) {
if err := Validate(buildFixtureB()); err != nil {
t.Errorf("Validate(clean tree) = %v, want nil", err)
}
}
// TestValidateFaults checks each fault class is reported.
func TestValidateFaults(t *testing.T) {
dyn := func(context.Context, fakeClient, []string) []string { return nil }
root := &Node[fakeClient]{Children: []*Node[fakeClient]{
// two slot children under one node
{Word: "twoslots", Help: "", Children: []*Node[fakeClient]{
{Word: "<a>", Dynamic: dyn, Run: runNoop},
{Word: "<b>", Dynamic: dyn, Run: runNoop},
}},
// duplicate fixed words
{Word: "dup", Children: []*Node[fakeClient]{
{Word: "x", Run: runNoop},
{Word: "x", Run: runNoop},
}},
// dead end: neither runs nor has children
{Word: "deadend"},
// empty word
{Word: "", Run: runNoop},
}}
err := Validate(root)
if err == nil {
t.Fatal("Validate(broken tree) = nil, want errors")
}
msg := err.Error()
for _, want := range []string{
"only the first is reachable",
`duplicate child word "x"`,
"dead end",
"empty Word",
} {
if !strings.Contains(msg, want) {
t.Errorf("Validate missing %q in:\n%s", want, msg)
}
}
}