go/nyro_test.go
Rama master · réplica de lectura del repositorio original.
package main
import (
"bytes"
"strings"
"testing"
"unicode/utf8"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
)
func TestRootCmdSubcommands(t *testing.T) {
root := newRootCmd()
names := map[string]bool{}
aliases := map[string]bool{}
for _, c := range root.Commands() {
names[c.Name()] = true
for _, alias := range c.Aliases {
aliases[alias] = true
}
}
if names["completion"] {
t.Error("completion subcommand should be disabled")
}
if !names["tool"] {
t.Error("tool subcommand missing")
}
if !names["proxy"] {
t.Error("proxy subcommand missing")
}
if !names["serve"] {
t.Error("serve subcommand missing")
}
if names["server"] || aliases["server"] {
t.Error("server subcommand should have been renamed to serve without an alias")
}
// The pre-rename names must be fully gone: the rename ships without a
// compatibility period, so a lingering alias would be a bug, not a courtesy.
if names["gateway"] {
t.Error("gateway subcommand should have been renamed to proxy")
}
if names["admin"] {
t.Error("admin subcommand should have been renamed to serve")
}
if names["ca"] || aliases["ca"] {
t.Error("ca must be available only under tool")
}
if names["migrate"] || aliases["migrate"] {
t.Error("migrate must be available only under tool")
}
tool, _, err := root.Find([]string{"tool"})
if err != nil {
t.Fatalf("find tool command: %v", err)
}
toolNames := map[string]bool{}
for _, c := range tool.Commands() {
toolNames[c.Name()] = true
}
if !toolNames["ca"] {
t.Error("tool ca subcommand missing")
}
if !toolNames["migrate"] {
t.Error("tool migrate subcommand missing")
}
}
func TestRootCmdNoGlobalStorageFlags(t *testing.T) {
root := newRootCmd()
if f := root.PersistentFlags().Lookup("dsn"); f != nil {
t.Error("--dsn must not be a global/root flag (it belongs to serve only)")
}
}
func TestRootCmdToolCommandsExecuteOnlyUnderTool(t *testing.T) {
tests := []struct {
name string
args []string
wantErr bool
wantOutput string
}{
{
name: "direct ca is rejected",
args: []string{"ca"},
wantErr: true,
},
{
name: "direct migrate is rejected",
args: []string{"migrate"},
wantErr: true,
},
{
name: "tool ca help resolves",
args: []string{"tool", "ca", "--help"},
wantOutput: "Usage:\n nyro tool ca",
},
{
name: "tool migrate help resolves",
args: []string{"tool", "migrate", "--help"},
wantOutput: "Usage:\n nyro tool migrate",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
root := newRootCmd()
var output bytes.Buffer
root.SetOut(&output)
root.SetErr(&output)
root.SetArgs(tt.args)
root.SilenceUsage = true
root.SilenceErrors = true
err := root.Execute()
if (err != nil) != tt.wantErr {
t.Fatalf("Execute(%q) error = %v, wantErr %v", tt.args, err, tt.wantErr)
}
if tt.wantOutput != "" && !strings.Contains(output.String(), tt.wantOutput) {
t.Errorf("Execute(%q) output = %q, want substring %q", tt.args, output.String(), tt.wantOutput)
}
})
}
}
func TestPublicHelpCopyIsConcise(t *testing.T) {
root := newRootCmd()
var visit func(*cobra.Command)
visit = func(cmd *cobra.Command) {
if cmd.Hidden {
return
}
if strings.Contains(cmd.Short, "`") || strings.Contains(cmd.Long, "`") {
t.Errorf("%s command help contains backticks", cmd.CommandPath())
}
if utf8.RuneCountInString(cmd.Short) > 48 {
t.Errorf("%s short help is too long: %q", cmd.CommandPath(), cmd.Short)
}
if cmd.Long != "" {
t.Errorf("%s has long help; keep terminal help concise", cmd.CommandPath())
}
cmd.LocalNonPersistentFlags().VisitAll(func(flag *pflag.Flag) {
usage, _, _ := strings.Cut(flag.Usage, " (env ")
if strings.Contains(usage, "`") {
t.Errorf("%s --%s help contains backticks", cmd.CommandPath(), flag.Name)
}
if utf8.RuneCountInString(usage) > 64 {
t.Errorf("%s --%s help is too long: %q", cmd.CommandPath(), flag.Name, usage)
}
})
for _, child := range cmd.Commands() {
visit(child)
}
}
visit(root)
}
func TestHelpOutputUsesConciseDescriptions(t *testing.T) {
tests := []struct {
args []string
want string
}{
{args: []string{"--help"}, want: "serve Start Nyro with embedded services"},
{args: []string{"serve", "--help"}, want: "Create or update database tables on startup"},
{args: []string{"proxy", "--help"}, want: "Token used to join config sync"},
{args: []string{"tool", "ca", "--help"}, want: "Manage config sync certificates"},
{args: []string{"tool", "migrate", "diff", "--help"}, want: "Writable scratch database DSN"},
}
for _, tt := range tests {
root := newRootCmd()
var output bytes.Buffer
root.SetOut(&output)
root.SetErr(&output)
root.SetArgs(tt.args)
if err := root.Execute(); err != nil {
t.Fatalf("Execute(%q): %v", tt.args, err)
}
got := output.String()
if !strings.Contains(got, tt.want) {
t.Errorf("help for %q does not contain %q:\n%s", tt.args, tt.want, got)
}
for _, unwanted := range []string{
"--auto-migrate nyro tool migrate dump",
"--sync-listen nyro proxy",
"--sync-token nyro proxy",
"--sync-tls-ca nyro tool ca",
} {
if strings.Contains(got, unwanted) {
t.Errorf("help for %q contains invalid placeholder %q", tt.args, unwanted)
}
}
}
}