All checks were successful
		
		
	
	Test / Create distribution (push) Successful in 25s
				
			Test / Hakurei (push) Successful in 44s
				
			Test / Sandbox (push) Successful in 41s
				
			Test / Hakurei (race detector) (push) Successful in 44s
				
			Test / Sandbox (race detector) (push) Successful in 41s
				
			Test / Hpkg (push) Successful in 41s
				
			Test / Flake checks (push) Successful in 1m24s
				
			Most tests already had no global state, however parallel was never enabled. This change enables it for all applicable tests. Signed-off-by: Ophestra <cat@gensokyo.uk>
		
			
				
	
	
		
			348 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			348 lines
		
	
	
		
			8.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
| package command_test
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"errors"
 | |
| 	"flag"
 | |
| 	"fmt"
 | |
| 	"io"
 | |
| 	"log"
 | |
| 	"strings"
 | |
| 	"testing"
 | |
| 
 | |
| 	"hakurei.app/command"
 | |
| )
 | |
| 
 | |
| func TestParse(t *testing.T) {
 | |
| 	t.Parallel()
 | |
| 
 | |
| 	testCases := []struct {
 | |
| 		name      string
 | |
| 		buildTree func(wout, wlog io.Writer) command.Command
 | |
| 		args      []string
 | |
| 		want      string
 | |
| 		wantLog   string
 | |
| 		wantErr   error
 | |
| 	}{
 | |
| 		{
 | |
| 			"d=0 empty sub",
 | |
| 			func(wout, wlog io.Writer) command.Command { return command.New(wout, newLogFunc(wlog), "root", nil) },
 | |
| 			[]string{""},
 | |
| 			"", "test: \"root\" has no subcommands\n", command.ErrEmptyTree,
 | |
| 		},
 | |
| 		{
 | |
| 			"d=0 empty sub garbage",
 | |
| 			func(wout, wlog io.Writer) command.Command { return command.New(wout, newLogFunc(wlog), "root", nil) },
 | |
| 			[]string{"a", "b", "c", "d"},
 | |
| 			"", "test: \"root\" has no subcommands\n", command.ErrEmptyTree,
 | |
| 		},
 | |
| 		{
 | |
| 			"d=0 no match",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"nonexistent"},
 | |
| 			"", "test: \"nonexistent\" is not a valid command\n", command.ErrNoMatch,
 | |
| 		},
 | |
| 		{
 | |
| 			"d=0 direct error",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"error"},
 | |
| 			"", "", errSuccess,
 | |
| 		},
 | |
| 		{
 | |
| 			"d=0 direct error garbage",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"error", "0", "1", "2"},
 | |
| 			"", "", errSuccess,
 | |
| 		},
 | |
| 		{
 | |
| 			"d=0 direct success out of order",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"succeed"},
 | |
| 			"", "", nil,
 | |
| 		},
 | |
| 		{
 | |
| 			"d=0 direct success output",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"print", "0", "1", "2"},
 | |
| 			"012", "", nil,
 | |
| 		},
 | |
| 		{
 | |
| 			"d=0 out of order string flag",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"string", "--string", "64d3b4b7b21788585845060e2199a78f"},
 | |
| 			"flag provided but not defined: -string\n\nUsage:\ttest string [-h | --help] COMMAND [OPTIONS]\n\n", "",
 | |
| 			errors.New("flag provided but not defined: -string"),
 | |
| 		},
 | |
| 		{
 | |
| 			"d=0 string flag",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"--string", "64d3b4b7b21788585845060e2199a78f", "string"},
 | |
| 			"64d3b4b7b21788585845060e2199a78f", "", nil,
 | |
| 		},
 | |
| 		{
 | |
| 			"d=0 int flag",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"--int", "2147483647", "int"},
 | |
| 			"2147483647", "", nil,
 | |
| 		},
 | |
| 		{
 | |
| 			"d=0 repeat flag",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"--repeat", "0", "--repeat", "1", "--repeat", "2", "--repeat", "3", "--repeat", "4", "repeat"},
 | |
| 			"[0 1 2 3 4]", "", nil,
 | |
| 		},
 | |
| 		{
 | |
| 			"d=0 bool flag",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"-v", "succeed"},
 | |
| 			"", "test: verbose\n", nil,
 | |
| 		},
 | |
| 		{
 | |
| 			"d=0 bool flag early error",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"--fail", "succeed"},
 | |
| 			"", "", errSuccess,
 | |
| 		},
 | |
| 
 | |
| 		{
 | |
| 			"d=1 empty sub",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"empty"},
 | |
| 			"", "test: \"empty\" has no subcommands\n", command.ErrEmptyTree,
 | |
| 		},
 | |
| 		{
 | |
| 			"d=1 empty sub garbage",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"empty", "a", "b", "c", "d"},
 | |
| 			"", "test: \"empty\" has no subcommands\n", command.ErrEmptyTree,
 | |
| 		},
 | |
| 		{
 | |
| 			"d=1 empty sub help",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"empty", "-h"},
 | |
| 			"\nUsage:\ttest empty [-h | --help] COMMAND [OPTIONS]\n\n", "", flag.ErrHelp,
 | |
| 		},
 | |
| 		{
 | |
| 			"d=1 no match",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"join", "23aa3bb0", "34986782", "d8859355", "cd9ac317", ", "},
 | |
| 			"", "test: \"23aa3bb0\" is not a valid command\n", command.ErrNoMatch,
 | |
| 		},
 | |
| 		{
 | |
| 			"d=1 direct success out",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"join", "out", "23aa3bb0", "34986782", "d8859355", "cd9ac317", ", "},
 | |
| 			"23aa3bb0, 34986782, d8859355, cd9ac317", "", nil,
 | |
| 		},
 | |
| 		{
 | |
| 			"d=1 direct success log",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"join", "log", "23aa3bb0", "34986782", "d8859355", "cd9ac317", ", "},
 | |
| 			"", "test: 23aa3bb0, 34986782, d8859355, cd9ac317\n", nil,
 | |
| 		},
 | |
| 
 | |
| 		{
 | |
| 			"d=4 empty sub",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"deep", "d=2", "d=3", "d=4"},
 | |
| 			"", "test: \"d=4\" has no subcommands\n", command.ErrEmptyTree},
 | |
| 
 | |
| 		{
 | |
| 			"d=0 help",
 | |
| 			buildTestCommand,
 | |
| 			[]string{},
 | |
| 			`
 | |
| Usage:	test [-h | --help] [-v] [--fail] [--string <value>] [--int <int>] [--repeat <value>] COMMAND [OPTIONS]
 | |
| 
 | |
| Commands:
 | |
|     error      return an error
 | |
|     print      wraps Fprint
 | |
|     string     print string passed by flag
 | |
|     int        print int passed by flag
 | |
|     repeat     print repeated values passed by flag
 | |
|     empty      empty subcommand
 | |
|     join       wraps strings.Join
 | |
|     succeed    this command succeeds
 | |
|     deep       top level of command tree with various levels
 | |
| 
 | |
| `, "", command.ErrHelp,
 | |
| 		},
 | |
| 		{
 | |
| 			"d=0 help flag",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"-h"},
 | |
| 			`
 | |
| Usage:	test [-h | --help] [-v] [--fail] [--string <value>] [--int <int>] [--repeat <value>] COMMAND [OPTIONS]
 | |
| 
 | |
| Commands:
 | |
|     error      return an error
 | |
|     print      wraps Fprint
 | |
|     string     print string passed by flag
 | |
|     int        print int passed by flag
 | |
|     repeat     print repeated values passed by flag
 | |
|     empty      empty subcommand
 | |
|     join       wraps strings.Join
 | |
|     succeed    this command succeeds
 | |
|     deep       top level of command tree with various levels
 | |
| 
 | |
| Flags:
 | |
|   -fail
 | |
|     	fail early
 | |
|   -int int
 | |
|     	store value for the "int" command (default -1)
 | |
|   -repeat value
 | |
|     	store value for the "repeat" command
 | |
|   -string string
 | |
|     	store value for the "string" command (default "default")
 | |
|   -v	verbose output
 | |
| 
 | |
| `, "", flag.ErrHelp,
 | |
| 		},
 | |
| 
 | |
| 		{
 | |
| 			"d=1 help",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"join"},
 | |
| 			`
 | |
| Usage:	test join [-h | --help] COMMAND [OPTIONS]
 | |
| 
 | |
| Commands:
 | |
|     out    write result to wout
 | |
|     log    log result to wlog
 | |
| 
 | |
| `, "", command.ErrHelp,
 | |
| 		},
 | |
| 		{
 | |
| 			"d=1 help flag",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"join", "-h"},
 | |
| 			`
 | |
| Usage:	test join [-h | --help] COMMAND [OPTIONS]
 | |
| 
 | |
| Commands:
 | |
|     out    write result to wout
 | |
|     log    log result to wlog
 | |
| 
 | |
| `, "", flag.ErrHelp,
 | |
| 		},
 | |
| 
 | |
| 		{
 | |
| 			"d=2 help",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"deep", "d=2"},
 | |
| 			`
 | |
| Usage:	test deep d=2 [-h | --help] COMMAND [OPTIONS]
 | |
| 
 | |
| Commands:
 | |
|     d=3    relative third level
 | |
| 
 | |
| `, "", command.ErrHelp,
 | |
| 		},
 | |
| 		{
 | |
| 			"d=2 help flag",
 | |
| 			buildTestCommand,
 | |
| 			[]string{"deep", "d=2", "-h"},
 | |
| 			`
 | |
| Usage:	test deep d=2 [-h | --help] COMMAND [OPTIONS]
 | |
| 
 | |
| Commands:
 | |
|     d=3    relative third level
 | |
| 
 | |
| `, "", flag.ErrHelp,
 | |
| 		},
 | |
| 	}
 | |
| 	for _, tc := range testCases {
 | |
| 		t.Run(tc.name, func(t *testing.T) {
 | |
| 			t.Parallel()
 | |
| 			wout, wlog := new(bytes.Buffer), new(bytes.Buffer)
 | |
| 			c := tc.buildTree(wout, wlog)
 | |
| 
 | |
| 			if err := c.Parse(tc.args); !errors.Is(err, tc.wantErr) {
 | |
| 				t.Errorf("Parse: error = %v; wantErr %v", err, tc.wantErr)
 | |
| 			}
 | |
| 			if got := wout.String(); got != tc.want {
 | |
| 				t.Errorf("Parse: %s want %s", got, tc.want)
 | |
| 			}
 | |
| 			if gotLog := wlog.String(); gotLog != tc.wantLog {
 | |
| 				t.Errorf("Parse: log = %s wantLog %s", gotLog, tc.wantLog)
 | |
| 			}
 | |
| 		})
 | |
| 	}
 | |
| }
 | |
| 
 | |
| var (
 | |
| 	errJoinLen = errors.New("not enough arguments to join")
 | |
| 	errSuccess = errors.New("success")
 | |
| )
 | |
| 
 | |
| func buildTestCommand(wout, wlog io.Writer) (c command.Command) {
 | |
| 	var (
 | |
| 		flagVerbose bool
 | |
| 		flagFail    bool
 | |
| 
 | |
| 		flagString string
 | |
| 		flagInt    int
 | |
| 		flagRepeat command.RepeatableFlag
 | |
| 	)
 | |
| 
 | |
| 	logf := newLogFunc(wlog)
 | |
| 	c = command.New(wout, logf, "test", func([]string) error {
 | |
| 		if flagVerbose {
 | |
| 			logf("verbose")
 | |
| 		}
 | |
| 		if flagFail {
 | |
| 			return errSuccess
 | |
| 		}
 | |
| 		return nil
 | |
| 	}).
 | |
| 		Flag(&flagVerbose, "v", command.BoolFlag(false), "verbose output").
 | |
| 		Flag(&flagFail, "fail", command.BoolFlag(false), "fail early").
 | |
| 		Command("error", "return an error", func([]string) error {
 | |
| 			return errSuccess
 | |
| 		}).
 | |
| 		Command("print", "wraps Fprint", func(args []string) error {
 | |
| 			a := make([]any, len(args))
 | |
| 			for i, v := range args {
 | |
| 				a[i] = v
 | |
| 			}
 | |
| 			_, err := fmt.Fprint(wout, a...)
 | |
| 			return err
 | |
| 		}).
 | |
| 		Flag(&flagString, "string", command.StringFlag("default"), "store value for the \"string\" command").
 | |
| 		Command("string", "print string passed by flag", func(args []string) error { _, err := fmt.Fprint(wout, flagString); return err }).
 | |
| 		Flag(&flagInt, "int", command.IntFlag(-1), "store value for the \"int\" command").
 | |
| 		Command("int", "print int passed by flag", func(args []string) error { _, err := fmt.Fprint(wout, flagInt); return err }).
 | |
| 		Flag(nil, "repeat", &flagRepeat, "store value for the \"repeat\" command").
 | |
| 		Command("repeat", "print repeated values passed by flag", func(args []string) error { _, err := fmt.Fprint(wout, flagRepeat); return err })
 | |
| 
 | |
| 	c.New("empty", "empty subcommand")
 | |
| 	c.New("hidden", command.UsageInternal)
 | |
| 
 | |
| 	c.New("join", "wraps strings.Join").
 | |
| 		Command("out", "write result to wout", func(args []string) error {
 | |
| 			if len(args) == 0 {
 | |
| 				return errJoinLen
 | |
| 			}
 | |
| 			_, err := fmt.Fprint(wout, strings.Join(args[:len(args)-1], args[len(args)-1]))
 | |
| 			return err
 | |
| 		}).
 | |
| 		Command("log", "log result to wlog", func(args []string) error {
 | |
| 			if len(args) == 0 {
 | |
| 				return errJoinLen
 | |
| 			}
 | |
| 			logf("%s", strings.Join(args[:len(args)-1], args[len(args)-1]))
 | |
| 			return nil
 | |
| 		})
 | |
| 
 | |
| 	c.Command("succeed", "this command succeeds", func([]string) error { return nil })
 | |
| 
 | |
| 	c.New("deep", "top level of command tree with various levels").
 | |
| 		New("d=2", "relative second level").
 | |
| 		New("d=3", "relative third level").
 | |
| 		New("d=4", "relative fourth level")
 | |
| 
 | |
| 	return
 | |
| }
 | |
| 
 | |
| func newLogFunc(w io.Writer) command.LogFunc { return log.New(w, "test: ", 0).Printf }
 |