command and help ux pass
This commit is contained in:
@@ -148,28 +148,138 @@ func TestBuilderHelpIsOK(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Every legacy command named in command-surface.md must have exactly one
|
||||
// canonical home (Builder.Legacy), so the migrated surface has no gaps or
|
||||
// ambiguous homes.
|
||||
func TestLegacyCommandsHaveExactlyOneHome(t *testing.T) {
|
||||
legacy := []string{
|
||||
"build", "build-module", "extract", "validate", "compare",
|
||||
"build-haks", "apply-hak-manifest",
|
||||
"validate-topdata", "build-topdata", "build-top-package", "compare-topdata", "convert-topdata",
|
||||
"build-wiki", "deploy-wiki",
|
||||
func TestCanonicalCommandSurface(t *testing.T) {
|
||||
want := map[string][]string{
|
||||
"depot": nil,
|
||||
"hak": {"build", "manifest"},
|
||||
"module": {"build", "extract", "validate", "compare", "manifest"},
|
||||
"topdata": {"validate", "build", "package", "compare", "convert"},
|
||||
"wiki": {"build", "deploy"},
|
||||
}
|
||||
for _, cmd := range legacy {
|
||||
homes := 0
|
||||
for _, b := range Registry {
|
||||
for _, c := range b.Legacy {
|
||||
if c == cmd {
|
||||
homes++
|
||||
for _, builder := range Registry {
|
||||
got := builder.subcommands()
|
||||
expected, ok := want[builder.Name]
|
||||
if !ok {
|
||||
t.Fatalf("unexpected builder %q", builder.Name)
|
||||
}
|
||||
if strings.Join(got, ",") != strings.Join(expected, ",") {
|
||||
t.Errorf("%s commands = %v, want %v", builder.Name, got, expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRegistryCommandNamesAndAliasesAreUnambiguous(t *testing.T) {
|
||||
for _, builder := range Registry {
|
||||
seen := map[string]bool{}
|
||||
for _, command := range builder.Commands {
|
||||
if command.Name == "" || command.Summary == "" || command.AppCommand == "" || command.Usage == "" {
|
||||
t.Errorf("%s has incomplete command metadata: %#v", builder.Name, command)
|
||||
}
|
||||
if seen[command.Name] {
|
||||
t.Errorf("%s repeats command name %q", builder.Name, command.Name)
|
||||
}
|
||||
seen[command.Name] = true
|
||||
for _, alias := range command.Aliases {
|
||||
if alias.Name == "" {
|
||||
t.Errorf("%s %s has an empty alias", builder.Name, command.Name)
|
||||
continue
|
||||
}
|
||||
if seen[alias.Name] {
|
||||
t.Errorf("%s repeats command or alias %q", builder.Name, alias.Name)
|
||||
}
|
||||
seen[alias.Name] = true
|
||||
}
|
||||
}
|
||||
if homes != 1 {
|
||||
t.Errorf("legacy command %q has %d canonical homes, want 1", cmd, homes)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMusicCommandsAreNotAccepted(t *testing.T) {
|
||||
for _, builderName := range []string{"hak", "module"} {
|
||||
builder, ok := find(builderName)
|
||||
if !ok {
|
||||
t.Fatalf("missing builder %q", builderName)
|
||||
}
|
||||
if builder.accepts("music") {
|
||||
t.Errorf("%s must not accept the removed music command", builderName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestHiddenAliasesPreserveImplementationTargets(t *testing.T) {
|
||||
tests := []struct {
|
||||
builder string
|
||||
alias string
|
||||
target string
|
||||
}{
|
||||
{"hak", "build-haks", "build-haks"},
|
||||
{"hak", "apply-hak-manifest", "apply-hak-manifest"},
|
||||
{"module", "build-module", "build-module"},
|
||||
{"module", "apply-hak-manifest", "apply-hak-manifest"},
|
||||
{"topdata", "validate-topdata", "validate-topdata"},
|
||||
{"topdata", "build-topdata", "build-topdata"},
|
||||
{"topdata", "build-top-package", "build-top-package"},
|
||||
{"topdata", "compare-topdata", "compare-topdata"},
|
||||
{"topdata", "convert-topdata", "convert-topdata"},
|
||||
{"wiki", "build-wiki", "build-wiki"},
|
||||
{"wiki", "deploy-wiki", "deploy-wiki"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.builder+"/"+tt.alias, func(t *testing.T) {
|
||||
builder, ok := find(tt.builder)
|
||||
if !ok {
|
||||
t.Fatalf("missing builder %q", tt.builder)
|
||||
}
|
||||
command, target, ok := builder.command(tt.alias)
|
||||
if !ok {
|
||||
t.Fatalf("hidden alias %q is not accepted", tt.alias)
|
||||
}
|
||||
if target != tt.target {
|
||||
t.Fatalf("alias %q target = %q, want %q", tt.alias, target, tt.target)
|
||||
}
|
||||
if command.Name == tt.alias {
|
||||
t.Fatalf("alias %q must not be a visible command", tt.alias)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestBuilderHelpHidesCompatibilityAliases(t *testing.T) {
|
||||
aliases := map[string][]string{
|
||||
"hak": {"build-haks", "apply-hak-manifest"},
|
||||
"module": {"build-module", "apply-hak-manifest"},
|
||||
"topdata": {"validate-topdata", "build-topdata", "build-top-package", "compare-topdata", "convert-topdata"},
|
||||
"wiki": {"build-wiki", "deploy-wiki"},
|
||||
}
|
||||
for builderName, hidden := range aliases {
|
||||
var out, errw bytes.Buffer
|
||||
if code := runBuilder(builderName, []string{"--help"}, &out, &errw); code != exitOK {
|
||||
t.Fatalf("%s help exit = %d", builderName, code)
|
||||
}
|
||||
for _, alias := range hidden {
|
||||
if strings.Contains(out.String(), alias) {
|
||||
t.Errorf("%s help exposed hidden alias %q:\n%s", builderName, alias, out.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestCommandHelpUsesCanonicalGuidanceWithoutLoadingProject(t *testing.T) {
|
||||
var out, errw bytes.Buffer
|
||||
if code := runBuilder("topdata", []string{"build", "--help"}, &out, &errw); code != exitOK {
|
||||
t.Fatalf("command help exit = %d, stderr:\n%s", code, errw.String())
|
||||
}
|
||||
for _, want := range []string{
|
||||
"compile topdata",
|
||||
"usage: crucible topdata build",
|
||||
"--force",
|
||||
"--skip-lfs",
|
||||
} {
|
||||
if !strings.Contains(out.String(), want) {
|
||||
t.Errorf("command help missing %q:\n%s", want, out.String())
|
||||
}
|
||||
}
|
||||
if errw.Len() != 0 {
|
||||
t.Fatalf("command help must not load a project or emit errors:\n%s", errw.String())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user