105 lines
3.0 KiB
Go
105 lines
3.0 KiB
Go
package menu
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
"reflect"
|
|
"regexp"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
var sample = []Item{
|
|
{Label: "module build", Desc: "build the .mod", Args: []string{"module", "build"}},
|
|
{Label: "topdata validate-topdata", Desc: "validate topdata", Args: []string{"topdata", "validate-topdata"}},
|
|
}
|
|
|
|
func TestSelectReturnsChosenArgs(t *testing.T) {
|
|
got, err := Select(io.Discard, strings.NewReader("1\n\n"), sample)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
if want := []string{"module", "build"}; !reflect.DeepEqual(got, want) {
|
|
t.Fatalf("got %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestSelectAppendsExtraArgs(t *testing.T) {
|
|
got, err := Select(io.Discard, strings.NewReader("2\n--dry-run foo\n"), sample)
|
|
if err != nil {
|
|
t.Fatalf("unexpected error: %v", err)
|
|
}
|
|
want := []string{"topdata", "validate-topdata", "--dry-run", "foo"}
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Fatalf("got %v, want %v", got, want)
|
|
}
|
|
}
|
|
|
|
func TestSelectQuitReturnsNil(t *testing.T) {
|
|
got, err := Select(io.Discard, strings.NewReader("q\n"), sample)
|
|
if err != nil || got != nil {
|
|
t.Fatalf("quit should return (nil,nil); got (%v,%v)", got, err)
|
|
}
|
|
}
|
|
|
|
func TestSelectInvalidErrors(t *testing.T) {
|
|
if _, err := Select(io.Discard, strings.NewReader("99\n"), sample); err == nil {
|
|
t.Fatal("out-of-range selection should error")
|
|
}
|
|
}
|
|
|
|
func TestSelectAlignsDescriptionsAfterLongestLabel(t *testing.T) {
|
|
items := []Item{
|
|
{Label: "hak build", Desc: "build haks", Args: []string{"hak", "build"}},
|
|
{Label: "topdata exceptionally-long-command", Desc: "long command", Args: []string{"topdata", "long"}},
|
|
}
|
|
var out bytes.Buffer
|
|
if _, err := Select(&out, strings.NewReader("q\n"), items); err != nil {
|
|
t.Fatalf("select: %v", err)
|
|
}
|
|
text := stripANSI(out.String())
|
|
var positions []int
|
|
for _, line := range strings.Split(text, "\n") {
|
|
for _, desc := range []string{"build haks", "long command"} {
|
|
if index := strings.Index(line, desc); index >= 0 {
|
|
positions = append(positions, index)
|
|
}
|
|
}
|
|
}
|
|
if len(positions) != 2 {
|
|
t.Fatalf("expected two menu descriptions, got %d:\n%s", len(positions), text)
|
|
}
|
|
if positions[0] != positions[1] {
|
|
t.Fatalf("descriptions are not aligned: columns %v\n%s", positions, text)
|
|
}
|
|
}
|
|
|
|
func TestSelectShowsCommandGuidanceBeforeArgumentsPrompt(t *testing.T) {
|
|
items := []Item{{
|
|
Label: "topdata build",
|
|
Desc: "compile topdata",
|
|
Args: []string{"topdata", "build"},
|
|
Usage: "crucible topdata build [--force]",
|
|
Options: []string{"--force rebuild outputs"},
|
|
}}
|
|
var out bytes.Buffer
|
|
if _, err := Select(&out, strings.NewReader("1\n\n"), items); err != nil {
|
|
t.Fatalf("select: %v", err)
|
|
}
|
|
text := stripANSI(out.String())
|
|
for _, want := range []string{
|
|
"usage: crucible topdata build [--force]",
|
|
"options:",
|
|
"--force rebuild outputs",
|
|
"arguments (press Enter to use defaults):",
|
|
} {
|
|
if !strings.Contains(text, want) {
|
|
t.Errorf("selected command guidance missing %q:\n%s", want, text)
|
|
}
|
|
}
|
|
}
|
|
|
|
func stripANSI(value string) string {
|
|
return regexp.MustCompile(`\x1b\[[0-9;]*m`).ReplaceAllString(value, "")
|
|
}
|