- Inject bonfire.Output from stdin/stdout/stderr with stdlib widgets and x/term - Degrade spinner, progress, table and prompts without a TTY or color - Reject plugin command names that are not namespace:verb
158 lines
4.2 KiB
Go
158 lines
4.2 KiB
Go
package bonfire
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestNonTTYSpinner(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
out := NewOutput(strings.NewReader(""), &buf, &buf)
|
|
if err := out.Spinner("building", func() error { return nil }); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if got := buf.String(); got != "[...] building\n" {
|
|
t.Fatalf("spinner = %q", got)
|
|
}
|
|
}
|
|
|
|
func TestNonTTYProgress(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
out := NewOutput(strings.NewReader(""), &buf, &buf)
|
|
if err := out.Progress(10, func(p Progress) error {
|
|
for i := 0; i < 10; i++ {
|
|
p.Advance(1)
|
|
}
|
|
return nil
|
|
}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got := buf.String()
|
|
for _, want := range []string{"[1/10] 10%", "[5/10] 50%", "[10/10] 100%"} {
|
|
if !strings.Contains(got, want) {
|
|
t.Fatalf("missing %q in %q", want, got)
|
|
}
|
|
}
|
|
if strings.Contains(got, "\x1b[") {
|
|
t.Fatalf("non-tty progress has ansi: %q", got)
|
|
}
|
|
}
|
|
|
|
func TestNonTTYTable(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
out := NewOutput(strings.NewReader(""), &buf, &buf)
|
|
out.Table([]string{"plugin", "status"}, [][]string{{"golem15.blog", "active"}})
|
|
got := buf.String()
|
|
if got != "plugin\tstatus\ngolem15.blog\tactive\n" {
|
|
t.Fatalf("table = %q", got)
|
|
}
|
|
}
|
|
|
|
func TestColorPolicy(t *testing.T) {
|
|
t.Run("NO_COLOR", func(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
out := newConsole(strings.NewReader(""), &buf, &buf, func(k string) string {
|
|
if k == "NO_COLOR" {
|
|
return "1"
|
|
}
|
|
if k == "FORCE_COLOR" {
|
|
return "1"
|
|
}
|
|
return ""
|
|
}, boolPtr(true), boolPtr(true))
|
|
out.Success("ok")
|
|
if strings.Contains(buf.String(), "\x1b[") {
|
|
t.Fatalf("NO_COLOR leaked ansi: %q", buf.String())
|
|
}
|
|
})
|
|
t.Run("TERM=dumb", func(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
out := newConsole(strings.NewReader(""), &buf, &buf, func(k string) string {
|
|
if k == "TERM" {
|
|
return "dumb"
|
|
}
|
|
if k == "FORCE_COLOR" {
|
|
return "1"
|
|
}
|
|
return ""
|
|
}, boolPtr(true), boolPtr(true))
|
|
out.Info("hi")
|
|
if strings.Contains(buf.String(), "\x1b[") {
|
|
t.Fatalf("TERM=dumb leaked ansi: %q", buf.String())
|
|
}
|
|
})
|
|
t.Run("FORCE_COLOR", func(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
out := newConsole(strings.NewReader(""), &buf, &buf, func(k string) string {
|
|
if k == "FORCE_COLOR" {
|
|
return "1"
|
|
}
|
|
return ""
|
|
}, boolPtr(false), boolPtr(false))
|
|
out.Success("ok")
|
|
if !strings.Contains(buf.String(), "\x1b[") {
|
|
t.Fatalf("FORCE_COLOR did not enable ansi: %q", buf.String())
|
|
}
|
|
})
|
|
t.Run("default non-tty", func(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
out := NewOutput(strings.NewReader(""), &buf, &buf)
|
|
out.Success("ok")
|
|
if strings.Contains(buf.String(), "\x1b[") {
|
|
t.Fatalf("non-tty default has ansi: %q", buf.String())
|
|
}
|
|
})
|
|
}
|
|
|
|
func TestPluginCommandRequiresColon(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
_, err := NewRoot("app", []Command{{Name: "hello", Description: "bad"}}, &buf)
|
|
if err == nil || !errors.Is(err, ErrCommandName) {
|
|
t.Fatalf("want ErrCommandName, got %v", err)
|
|
}
|
|
if !strings.Contains(err.Error(), "hello") {
|
|
t.Fatalf("error should name the command: %v", err)
|
|
}
|
|
}
|
|
|
|
func TestKernelAndNamespacedCommands(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
root, err := NewRoot("summer", []Command{
|
|
{Name: "build", Description: "Build the app"},
|
|
{Name: "dev", Description: "Watch and rebuild"},
|
|
{Name: "make:plugin", Description: "Scaffold a plugin from a vendor.plugin id"},
|
|
{Name: "greeter:hello", Description: "Say hello"},
|
|
}, &buf)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
root.SetArgs([]string{"make:plugin", "--help"})
|
|
if err := root.Execute(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(buf.String(), "vendor.plugin") && !strings.Contains(buf.String(), "make:plugin") {
|
|
t.Fatalf("help = %q", buf.String())
|
|
}
|
|
}
|
|
|
|
func TestHelpUsesSharedAdapter(t *testing.T) {
|
|
var buf bytes.Buffer
|
|
root, err := NewRoot("hello", []Command{{
|
|
Name: "greeter:hello",
|
|
Description: "Print the configured application name",
|
|
}}, &buf)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
root.SetArgs([]string{"greeter:hello", "--help"})
|
|
if err := root.Execute(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got := buf.String()
|
|
if !strings.Contains(got, "greeter:hello") || !strings.Contains(got, "Print the configured application name") {
|
|
t.Fatalf("help = %q", got)
|
|
}
|
|
}
|