Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 9abbe37e02 | |||
| 52ff844ce1 | |||
| 20b6b961fb | |||
| 00b84278d8 | |||
| 9e28ee6545 | |||
| 92267aec50 |
@@ -60,6 +60,8 @@ func main() {
|
||||
|
||||
Refer to the unit test for a realistic example: [`cli_test.go`](cli_test.go).
|
||||
|
||||
## Usage
|
||||
|
||||
## API Reference
|
||||
|
||||
Key types and methods:
|
||||
|
||||
@@ -14,6 +14,7 @@ type cliParser interface {
|
||||
getCliArgs(startIndex, endIndex int) (args []string)
|
||||
PrintVersion(specs []string)
|
||||
PrintUsage()
|
||||
FlagIsSet(flag int16) bool
|
||||
}
|
||||
|
||||
type cliOptionParser interface {
|
||||
@@ -25,7 +26,7 @@ type cliOptionParser interface {
|
||||
isSet() bool
|
||||
isHidden() bool
|
||||
requiresValue() bool
|
||||
finalCheck(cliValue string) (err error)
|
||||
finalCheck() (err error)
|
||||
}
|
||||
|
||||
type OptManager interface {
|
||||
@@ -33,7 +34,7 @@ type OptManager interface {
|
||||
}
|
||||
|
||||
type SpecialValueFunc func(manager OptManager, cliValue string, currentValue any) (value any, err error)
|
||||
type FinalCheckFunc func(cliValue string, currentValue any) (err error)
|
||||
type FinalCheckFunc func(currentValue any) (err error)
|
||||
|
||||
type OptReference interface {
|
||||
AddSpecialValue(cliValue string, specialFunc SpecialValueFunc)
|
||||
@@ -41,20 +42,30 @@ type OptReference interface {
|
||||
SetHidden(hidden bool)
|
||||
}
|
||||
|
||||
const (
|
||||
ResetOnEqualSign = int16(1 << iota) // for some option types, like arrays, the equal signs reset to empty the accumulator of values
|
||||
)
|
||||
|
||||
type CliParser struct {
|
||||
description string
|
||||
version string
|
||||
options []cliOptionParser
|
||||
argSpecs []argSpec
|
||||
cliArgs []string
|
||||
flags int16
|
||||
}
|
||||
|
||||
func (cli *CliParser) Init(argv []string, version string, description string) {
|
||||
func (cli *CliParser) Init(version string, description string, flags ...int16) {
|
||||
cli.version = version
|
||||
cli.description = description
|
||||
cli.cliArgs = argv
|
||||
for _, flag := range flags {
|
||||
cli.flags |= flag
|
||||
}
|
||||
}
|
||||
|
||||
func (cli *CliParser) FlagIsSet(flag int16) bool {
|
||||
return (cli.flags & flag) == flag
|
||||
}
|
||||
func (cli *CliParser) GetOption(name string) (ref OptReference) {
|
||||
var opt cliOptionParser
|
||||
if strings.HasPrefix(name, "-") {
|
||||
@@ -158,17 +169,12 @@ func (cli *CliParser) addHelpAndVersion() {
|
||||
|
||||
}
|
||||
|
||||
func (cli *CliParser) Parse() (err error) {
|
||||
var arg string
|
||||
var i int
|
||||
var args []string
|
||||
func (cli *CliParser) parseOptions() (commandArgs []string, err error) {
|
||||
// var commandArgs []string
|
||||
var optionsAllowed bool = true
|
||||
|
||||
cli.addHelpAndVersion()
|
||||
|
||||
// first parse options and collect argument in the args array
|
||||
skipNext := false
|
||||
for i, arg = range cli.cliArgs[1:] {
|
||||
for i, arg := range cli.cliArgs[1:] {
|
||||
if skipNext {
|
||||
skipNext = false
|
||||
} else {
|
||||
@@ -182,50 +188,81 @@ func (cli *CliParser) Parse() (err error) {
|
||||
break
|
||||
}
|
||||
} else {
|
||||
args = append(args, arg)
|
||||
commandArgs = append(commandArgs, arg)
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *CliParser) checkOptionValues() (err error) {
|
||||
for _, opt := range cli.options {
|
||||
if err = opt.finalCheck(); err != nil {
|
||||
break
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *CliParser) parseCommandArgs(commandArgs []string) (err error) {
|
||||
var n int
|
||||
|
||||
i := 0
|
||||
// acquire arguments as required by the argSpecs
|
||||
specIndex := -1
|
||||
for index, argSpec := range cli.argSpecs {
|
||||
specIndex = index
|
||||
if n, err = argSpec.parse(cli, specIndex, commandArgs, i); err != nil {
|
||||
break
|
||||
}
|
||||
i += n
|
||||
if i >= len(commandArgs) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// check if there are remaining arg-specs that require a value
|
||||
if err == nil {
|
||||
if i < len(commandArgs) {
|
||||
err = fmt.Errorf("too many arguments: %d allowed", i)
|
||||
} else {
|
||||
specIndex++
|
||||
if specIndex < len(cli.argSpecs) {
|
||||
// skip all non required args
|
||||
for _, spec := range cli.argSpecs[specIndex:] {
|
||||
if !spec.getBase().required {
|
||||
specIndex++
|
||||
}
|
||||
}
|
||||
}
|
||||
// return error if there are remaining arg-specs that require a value
|
||||
if specIndex < len(cli.argSpecs) {
|
||||
err = errTooFewArguments(len(cli.argSpecs))
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (cli *CliParser) Parse(argv []string) (err error) {
|
||||
var commandArgs []string
|
||||
|
||||
cli.cliArgs = argv
|
||||
|
||||
cli.addHelpAndVersion()
|
||||
|
||||
// first parse options and collect command arguments in the args array
|
||||
if commandArgs, err = cli.parseOptions(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// do final checks
|
||||
if err = cli.checkOptionValues(); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
// then parse collected arguments
|
||||
if err == nil {
|
||||
var n int
|
||||
i = 0
|
||||
|
||||
// acquire arguments as required by the argSpecs
|
||||
specIndex := -1
|
||||
for index, argSpec := range cli.argSpecs {
|
||||
specIndex = index
|
||||
if n, err = argSpec.parse(cli, specIndex, args, i); err != nil {
|
||||
break
|
||||
}
|
||||
i += n
|
||||
if i >= len(args) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// check if there are remaining arg-specs that require a value
|
||||
if err == nil {
|
||||
if i < len(args) {
|
||||
err = fmt.Errorf("too many arguments: %d allowed", i)
|
||||
} else {
|
||||
specIndex++
|
||||
if specIndex < len(cli.argSpecs) {
|
||||
// skip all non required args
|
||||
for _, spec := range cli.argSpecs[specIndex:] {
|
||||
if !spec.getBase().required {
|
||||
specIndex++
|
||||
}
|
||||
}
|
||||
}
|
||||
// return error if there are remaining arg-specs that require a value
|
||||
if specIndex < len(cli.argSpecs) {
|
||||
err = errTooFewArguments(len(cli.argSpecs))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
err = cli.parseCommandArgs(commandArgs)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
+30
-41
@@ -6,7 +6,7 @@ import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
const version = `$VER:ddt-ocr,1.0.1,2025-11-23,celestino.amoroso@gmail.com:$`
|
||||
const version = `$VER:ddt-ocr,2.0.0,2026-03-19,celestino.amoroso@gmail.com:$`
|
||||
|
||||
type GlobalData struct {
|
||||
config string
|
||||
@@ -33,7 +33,7 @@ func TestVerbose(t *testing.T) {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
if err := cli.Parse(); err != nil {
|
||||
if err := cli.Parse(commonArgs()); err != nil {
|
||||
t.Error(err)
|
||||
} else if gd.verbose != 3 {
|
||||
t.Errorf("Expected verbose level 3, got %d", gd.verbose)
|
||||
@@ -134,7 +134,7 @@ Option: version, Type: n/a, Value: <nil>
|
||||
return
|
||||
}
|
||||
tracer := NewSimpleOptionTracer(&sb)
|
||||
if err := cli.Parse(); err == nil {
|
||||
if err := cli.Parse(commonArgs()); err == nil {
|
||||
cli.TraceOptions(tracer)
|
||||
if sb.String() != expectedOutput {
|
||||
t.Errorf("Parsed options do not match expected list.\nGot:\n%q\nExpected:\n%q", sb.String(), expectedOutput)
|
||||
@@ -144,8 +144,8 @@ Option: version, Type: n/a, Value: <nil>
|
||||
}
|
||||
}
|
||||
|
||||
func initCli(cli *CliParser, gd *GlobalData) (err error) {
|
||||
args := []string{
|
||||
func commonArgs() []string {
|
||||
return []string{
|
||||
"ddt-ocr",
|
||||
"--log", "all",
|
||||
"-t",
|
||||
@@ -157,7 +157,10 @@ func initCli(cli *CliParser, gd *GlobalData) (err error) {
|
||||
"--input-name=my-scan.pdf",
|
||||
"scan1.pdf", "scan2.pdf", "result.txt", "report.txt",
|
||||
}
|
||||
cli.Init(args, version, "cli-test")
|
||||
}
|
||||
|
||||
func initCli(cli *CliParser, gd *GlobalData) (err error) {
|
||||
cli.Init(version, "cli-test")
|
||||
err = gd.addOptions(cli)
|
||||
return
|
||||
}
|
||||
@@ -168,8 +171,8 @@ func TestOptErrorUnknownOption(t *testing.T) {
|
||||
var cli CliParser
|
||||
var gd GlobalData
|
||||
|
||||
if err := initCliUnknownOption(&cli, &gd, unknownOption); err == nil {
|
||||
if err = cli.Parse(); err != nil {
|
||||
if err := initCliUnknownOption(&cli, &gd); err == nil {
|
||||
if err = cli.Parse(commonBadArgs(unknownOption)); err != nil {
|
||||
if err.Error() != expectedErr.Error() {
|
||||
t.Errorf("Invalid error message.\nGot:\n%v\nExpected:\n%v", err, expectedErr)
|
||||
}
|
||||
@@ -182,13 +185,15 @@ func TestOptErrorUnknownOption(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func initCliUnknownOption(cli *CliParser, gd *GlobalData, option string) (err error) {
|
||||
args := []string{
|
||||
func commonBadArgs(option string) []string {
|
||||
return []string{
|
||||
"ddt-ocr",
|
||||
option,
|
||||
"scan1.pdf", "scan2.pdf", "result.txt", "report.txt",
|
||||
}
|
||||
cli.Init(args, version, "cli-test")
|
||||
}
|
||||
func initCliUnknownOption(cli *CliParser, gd *GlobalData) (err error) {
|
||||
cli.Init(version, "cli-test")
|
||||
err = gd.addOptions(cli)
|
||||
return
|
||||
}
|
||||
@@ -199,8 +204,8 @@ func TestOptErrorMissingOptionValue(t *testing.T) {
|
||||
var cli CliParser
|
||||
var gd GlobalData
|
||||
|
||||
if err := initCliMissingOptionValue(&cli, &gd, missingValueOption); err == nil {
|
||||
if err = cli.Parse(); err != nil {
|
||||
if err := initCliMissingOptionValue(&cli, &gd); err == nil {
|
||||
if err = cli.Parse(commonBadArgs(missingValueOption)); err != nil {
|
||||
if err.Error() != expectedErr.Error() {
|
||||
t.Errorf("Invalid error message.\nGot:\n%v\nExpected:\n%v", err, expectedErr)
|
||||
}
|
||||
@@ -213,25 +218,20 @@ func TestOptErrorMissingOptionValue(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func initCliMissingOptionValue(cli *CliParser, gd *GlobalData, option string) (err error) {
|
||||
args := []string{
|
||||
"ddt-ocr",
|
||||
option,
|
||||
"scan1.pdf", "scan2.pdf", "result.txt", "report.txt",
|
||||
}
|
||||
cli.Init(args, version, "cli-test")
|
||||
func initCliMissingOptionValue(cli *CliParser, gd *GlobalData) (err error) {
|
||||
cli.Init(version, "cli-test")
|
||||
err = gd.addOptions(cli)
|
||||
return
|
||||
}
|
||||
|
||||
func TestOptErrorInvalidOptionValue(t *testing.T) {
|
||||
const missingInvalidValueOption = "--page"
|
||||
var expectedErr = errInvalidOptionValue("page", "some", "num-array")
|
||||
var expectedErr = errInvalidOptionValue("page", "scan1.pdf", "num-array")
|
||||
var cli CliParser
|
||||
var gd GlobalData
|
||||
|
||||
if err := initCliInvalidOptionValue(&cli, &gd, missingInvalidValueOption); err == nil {
|
||||
if err = cli.Parse(); err != nil {
|
||||
if err := initCliInvalidOptionValue(&cli, &gd); err == nil {
|
||||
if err = cli.Parse(commonBadArgs(missingInvalidValueOption)); err != nil {
|
||||
if err.Error() != expectedErr.Error() {
|
||||
t.Errorf("Invalid error message.\nGot:\n%v\nExpected:\n%v", err, expectedErr)
|
||||
}
|
||||
@@ -244,13 +244,8 @@ func TestOptErrorInvalidOptionValue(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func initCliInvalidOptionValue(cli *CliParser, gd *GlobalData, option string) (err error) {
|
||||
args := []string{
|
||||
"ddt-ocr",
|
||||
option, "some",
|
||||
"scan1.pdf", "scan2.pdf", "result.txt", "report.txt",
|
||||
}
|
||||
cli.Init(args, version, "cli-test")
|
||||
func initCliInvalidOptionValue(cli *CliParser, gd *GlobalData) (err error) {
|
||||
cli.Init(version, "cli-test")
|
||||
err = gd.addOptions(cli)
|
||||
return
|
||||
}
|
||||
@@ -262,7 +257,7 @@ func TestArgErrorMissingRequired(t *testing.T) {
|
||||
var gd GlobalData
|
||||
|
||||
if err := initCliMissingRequiredArg(&cli, &gd); err == nil {
|
||||
if err = cli.Parse(); err != nil {
|
||||
if err = cli.Parse([]string{"ddt-ocr"}); err != nil {
|
||||
if err.Error() != expectedErr.Error() {
|
||||
t.Errorf("Invalid error message.\nGot:\n%v\nExpected:\n%v", err, expectedErr)
|
||||
}
|
||||
@@ -276,15 +271,12 @@ func TestArgErrorMissingRequired(t *testing.T) {
|
||||
}
|
||||
|
||||
func initCliMissingRequiredArg(cli *CliParser, gd *GlobalData) (err error) {
|
||||
args := []string{
|
||||
"ddt-ocr",
|
||||
}
|
||||
cli.Init(args, version, "cli-test")
|
||||
cli.Init(version, "cli-test")
|
||||
err = gd.addOptions(cli)
|
||||
return
|
||||
}
|
||||
|
||||
func TestArgErrorRepeat(t *testing.T) {
|
||||
func TestArgErrorRepeatProperty(t *testing.T) {
|
||||
var expectedErr = fmt.Errorf(`repeat property already set for arg <other>`)
|
||||
var cli CliParser
|
||||
var gd GlobalData
|
||||
@@ -299,17 +291,14 @@ func TestArgErrorRepeat(t *testing.T) {
|
||||
}
|
||||
|
||||
func initCliRepeatArg(cli *CliParser, gd *GlobalData) (err error) {
|
||||
args := []string{
|
||||
"ddt-ocr",
|
||||
"scan1.pdf", "scan2.pdf", "result.txt", "report.txt",
|
||||
}
|
||||
cli.Init(args, version, "cli-test")
|
||||
cli.Init(version, "cli-test")
|
||||
if err = gd.addOptions(cli); err == nil {
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = r.(error)
|
||||
}
|
||||
}()
|
||||
// This will raise error because we can't declare two args array
|
||||
cli.AddStringArrayArg("other", true, nil, "other args")
|
||||
cli.AddStringArrayArg("other2", true, nil, "other args 2")
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
module git.portale-stac.it/go-pkg/cli
|
||||
module git.portale-stac.it/go-pkg/cli/v2
|
||||
|
||||
go 1.25.4
|
||||
|
||||
+3
-3
@@ -153,13 +153,13 @@ func (opt *cliOptionBase) fetchOptionValue(parser cliParser, argIndex int, value
|
||||
return
|
||||
}
|
||||
|
||||
func (opt *cliOptionBase) finalCheck(cliValue string) (err error) {
|
||||
func (opt *cliOptionBase) finalCheck() (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
func (opt *cliOptionBase) checkValue(cliValue string, value any) (err error) {
|
||||
func (opt *cliOptionBase) checkValue(value any) (err error) {
|
||||
if opt.finalCheckFunc != nil {
|
||||
err = opt.finalCheckFunc(cliValue, value)
|
||||
err = opt.finalCheckFunc(value)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
+2
-2
@@ -67,9 +67,9 @@ func (opt *cliOptionBool) parse(parser cliParser, argIndex int, valuePtr *string
|
||||
return
|
||||
}
|
||||
|
||||
func (opt *cliOptionBool) finalCheck(cliValue string) (err error) {
|
||||
func (opt *cliOptionBool) finalCheck() (err error) {
|
||||
currentValue, _ := opt.getTargetVar()
|
||||
return opt.getBase().checkValue(cliValue, currentValue)
|
||||
return opt.getBase().checkValue(currentValue)
|
||||
}
|
||||
|
||||
func (cli *CliParser) AddBoolOpt(name, short string, targetVar *bool, description string, aliases ...string) OptReference {
|
||||
|
||||
+3
-3
@@ -75,7 +75,7 @@ func (opt *cliOptionIntArray) parse(parser cliParser, argIndex int, valuePtr *st
|
||||
err = errInvalidOptionValue(opt.name, boxedValue, "num-array")
|
||||
}
|
||||
} else {
|
||||
if !opt.alreadySeen {
|
||||
if !opt.alreadySeen || (valuePtr != nil && parser.FlagIsSet(ResetOnEqualSign)) {
|
||||
*opt.targetVar = []int{}
|
||||
opt.alreadySeen = true
|
||||
}
|
||||
@@ -97,9 +97,9 @@ func (opt *cliOptionIntArray) parse(parser cliParser, argIndex int, valuePtr *st
|
||||
return
|
||||
}
|
||||
|
||||
func (opt *cliOptionIntArray) finalCheck(cliValue string) (err error) {
|
||||
func (opt *cliOptionIntArray) finalCheck() (err error) {
|
||||
currentValue, _ := opt.getTargetVar()
|
||||
return opt.getBase().checkValue(cliValue, currentValue)
|
||||
return opt.getBase().checkValue(currentValue)
|
||||
}
|
||||
|
||||
func (cli *CliParser) AddIntArrayOpt(name, short string, targetVar *[]int, defaultValue []int, description string, aliases ...string) OptReference {
|
||||
|
||||
+2
-2
@@ -57,9 +57,9 @@ func (opt *cliOptionInt) parse(parser cliParser, argIndex int, valuePtr *string)
|
||||
}
|
||||
return
|
||||
}
|
||||
func (opt *cliOptionInt) finalCheck(cliValue string) (err error) {
|
||||
func (opt *cliOptionInt) finalCheck() (err error) {
|
||||
currentValue, _ := opt.getTargetVar()
|
||||
return opt.getBase().checkValue(cliValue, currentValue)
|
||||
return opt.getBase().checkValue(currentValue)
|
||||
}
|
||||
|
||||
func (cli *CliParser) AddIntOpt(name, short string, targetVar *int, defaultValue int, description string, aliases ...string) OptReference {
|
||||
|
||||
+2
-2
@@ -53,9 +53,9 @@ func (opt *cliOptionMulti) parse(parser cliParser, argIndex int, valuePtr *strin
|
||||
value = "true"
|
||||
return
|
||||
}
|
||||
func (opt *cliOptionMulti) finalCheck(cliValue string) (err error) {
|
||||
func (opt *cliOptionMulti) finalCheck() (err error) {
|
||||
currentValue, _ := opt.getTargetVar()
|
||||
return opt.getBase().checkValue(cliValue, currentValue)
|
||||
return opt.getBase().checkValue(currentValue)
|
||||
}
|
||||
|
||||
func (cli *CliParser) AddMultiOpt(name, short string, targetVar *int, defaultValue int, description string, aliases ...string) OptReference {
|
||||
|
||||
+2
-2
@@ -85,7 +85,7 @@ func (cli *CliParser) AddStringArrayOpt(name, short string, targetVar *[]string,
|
||||
return opt
|
||||
}
|
||||
|
||||
func (opt *cliOptionStringArray) finalCheck(cliValue string) (err error) {
|
||||
func (opt *cliOptionStringArray) finalCheck() (err error) {
|
||||
currentValue, _ := opt.getTargetVar()
|
||||
return opt.getBase().checkValue(cliValue, currentValue)
|
||||
return opt.getBase().checkValue(currentValue)
|
||||
}
|
||||
|
||||
+2
-2
@@ -89,9 +89,9 @@ func (opt *cliOptionStringMap) parse(parser cliParser, argIndex int, valuePtr *s
|
||||
return
|
||||
}
|
||||
|
||||
func (opt *cliOptionStringMap) finalCheck(cliValue string) (err error) {
|
||||
func (opt *cliOptionStringMap) finalCheck() (err error) {
|
||||
currentValue, _ := opt.getTargetVar()
|
||||
return opt.getBase().checkValue(cliValue, currentValue)
|
||||
return opt.getBase().checkValue(currentValue)
|
||||
}
|
||||
|
||||
func (cli *CliParser) AddStringMapOpt(name, short string, targetVar *map[string]string, defaultValue map[string]string, description string, aliases ...string) OptReference {
|
||||
|
||||
+2
-2
@@ -55,9 +55,9 @@ func (opt *cliOptionString) parse(parser cliParser, argIndex int, valuePtr *stri
|
||||
}
|
||||
return
|
||||
}
|
||||
func (opt *cliOptionString) finalCheck(cliValue string) (err error) {
|
||||
func (opt *cliOptionString) finalCheck() (err error) {
|
||||
currentValue, _ := opt.getTargetVar()
|
||||
return opt.getBase().checkValue(cliValue, currentValue)
|
||||
return opt.getBase().checkValue(currentValue)
|
||||
}
|
||||
|
||||
func (cli *CliParser) AddStringOpt(name, short string, targetVar *string, defaultValue string, description string, aliases ...string) OptReference {
|
||||
|
||||
+67
-52
@@ -26,8 +26,8 @@ func TestOneOptWithEqual(t *testing.T) {
|
||||
"--color=blue",
|
||||
}
|
||||
|
||||
cli.Init(args, "1.0.0", "TestOneOptWithEqual description")
|
||||
if err := cli.Parse(); err != nil {
|
||||
cli.Init("1.0.0", "TestOneOptWithEqual description")
|
||||
if err := cli.Parse(args); err != nil {
|
||||
t.Error(err)
|
||||
} else if color != "blue" {
|
||||
t.Errorf("Expected color blue, got %q", color)
|
||||
@@ -37,7 +37,7 @@ func TestOneOptWithEqual(t *testing.T) {
|
||||
func addBoxOption(cli *CliParser, boxPtr *[]int) {
|
||||
// Define options
|
||||
optRef := cli.AddIntArrayOpt("box", "b", boxPtr, []int{1, 2, 3, 4}, "Box spec: Left,Width,Top,Height; provide 4 int values")
|
||||
optRef.OnFinalCheck(func(cliValue string, currentValue any) (err error) {
|
||||
optRef.OnFinalCheck(func(currentValue any) (err error) {
|
||||
if array, ok := currentValue.([]int); ok {
|
||||
if len(array) != 4 {
|
||||
err = fmt.Errorf("--box option requires exactly 4 items, %d provided", len(array))
|
||||
@@ -49,8 +49,34 @@ func addBoxOption(cli *CliParser, boxPtr *[]int) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestIntArrayOpt(t *testing.T) {
|
||||
func testIntArrayOptOk(t *testing.T, n int, args []string, flags ...int16) {
|
||||
var box []int
|
||||
var cli CliParser
|
||||
t.Logf("Arg set n. %d", n)
|
||||
addBoxOption(&cli, &box)
|
||||
cli.Init("1.0.0", "TestIntArrayOpt description", flags...)
|
||||
if err := cli.Parse(args); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(box) != 4 {
|
||||
t.Errorf(`Expected 4 items, got %d`, len(box))
|
||||
}
|
||||
}
|
||||
|
||||
func testIntArrayOptKo(t *testing.T, n int, args []string, msg string, flags ...int16) {
|
||||
var box []int
|
||||
var cli CliParser
|
||||
t.Logf("Arg set n. %d", n)
|
||||
addBoxOption(&cli, &box)
|
||||
cli.Init("1.0.0", "TestIntArrayOpt description", flags...)
|
||||
if err := cli.Parse(args); err == nil {
|
||||
t.Errorf("Expected error, got nil")
|
||||
} else if err.Error() != msg {
|
||||
t.Errorf(`Invalid error: %q; expected: %q`, err.Error(), msg)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIntArrayOpt(t *testing.T) {
|
||||
var args []string
|
||||
// Always recover from panic to return error before adding options
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
@@ -61,68 +87,57 @@ func TestIntArrayOpt(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
|
||||
args_1 := []string{
|
||||
n := 0
|
||||
|
||||
n++
|
||||
args = []string{
|
||||
"TestIntArrayOpt",
|
||||
"--box=100,200,150,450",
|
||||
}
|
||||
testIntArrayOptOk(t, n, args)
|
||||
|
||||
if true {
|
||||
var cli CliParser
|
||||
t.Logf("Arg set n. 1")
|
||||
addBoxOption(&cli, &box)
|
||||
cli.Init(args_1, "1.0.0", "TestIntArrayOpt description")
|
||||
if err := cli.Parse(); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(box) != 4 {
|
||||
t.Errorf(`Expected 4 items, got %d`, len(box))
|
||||
}
|
||||
}
|
||||
|
||||
args_2 := []string{
|
||||
n++
|
||||
args = []string{
|
||||
"TestIntArrayOpt",
|
||||
"--box=100,200,150",
|
||||
}
|
||||
if true {
|
||||
var cli CliParser
|
||||
t.Logf("Arg set n. 2")
|
||||
addBoxOption(&cli, &box)
|
||||
cli.Init(args_2, "1.0.0", "TestIntArrayOpt description")
|
||||
if err := cli.Parse(); err == nil {
|
||||
t.Errorf("Expected error, got nil")
|
||||
} else if err.Error() != "--box option requires exactly 4 items, 3 provided" {
|
||||
t.Errorf(`Invalid error: %q; expected: "--box option requires exactly 4 items, 3 provided"`, err.Error())
|
||||
}
|
||||
}
|
||||
testIntArrayOptKo(t, n, args, "--box option requires exactly 4 items, 3 provided")
|
||||
|
||||
args_3 := []string{
|
||||
n++
|
||||
args = []string{
|
||||
"TestIntArrayOpt",
|
||||
"--box", "100,200,150,450",
|
||||
}
|
||||
if true {
|
||||
var cli CliParser
|
||||
t.Logf("Arg set n. 3")
|
||||
addBoxOption(&cli, &box)
|
||||
cli.Init(args_3, "1.0.0", "TestIntArrayOpt description")
|
||||
if err := cli.Parse(); err != nil {
|
||||
t.Error(err)
|
||||
} else if len(box) != 4 {
|
||||
t.Errorf(`Expected 4 items, got %d`, len(box))
|
||||
}
|
||||
}
|
||||
testIntArrayOptOk(t, n, args)
|
||||
|
||||
args_4 := []string{
|
||||
n++
|
||||
args = []string{
|
||||
"TestIntArrayOpt",
|
||||
"--box",
|
||||
}
|
||||
if true {
|
||||
var cli CliParser
|
||||
t.Logf("Arg set n. 4")
|
||||
addBoxOption(&cli, &box)
|
||||
cli.Init(args_4, "1.0.0", "TestIntArrayOpt description")
|
||||
if err := cli.Parse(); err == nil {
|
||||
t.Errorf("Expected error, got nil")
|
||||
} else if err.Error() != `option "box" requires a value` {
|
||||
t.Errorf(`Invalid error - Expected: 'option "box" requires a value'; got '%s'`, err.Error())
|
||||
}
|
||||
testIntArrayOptKo(t, n, args, `option "box" requires a value`)
|
||||
|
||||
n++
|
||||
args = []string{
|
||||
"TestIntArrayOpt",
|
||||
"--box", "100,200,150",
|
||||
"--box", "450",
|
||||
}
|
||||
testIntArrayOptOk(t, n, args)
|
||||
|
||||
n++
|
||||
args = []string{
|
||||
"TestIntArrayOpt",
|
||||
"--box", "100,200,150",
|
||||
"--box", "450,12",
|
||||
}
|
||||
testIntArrayOptKo(t, n, args, "--box option requires exactly 4 items, 5 provided")
|
||||
|
||||
n++
|
||||
args = []string{
|
||||
"TestIntArrayOpt",
|
||||
"--box", "100,200,150",
|
||||
"--box=100,200,150,450",
|
||||
}
|
||||
testIntArrayOptOk(t, n, args, ResetOnEqualSign)
|
||||
}
|
||||
|
||||
@@ -104,16 +104,12 @@ func (cli *CliParser) parseArg(arg string, index int) (skipNextArg bool, err err
|
||||
}
|
||||
for i, optName := range opts {
|
||||
if opt := cli.findOptionByArg(dashes + optName); opt != nil {
|
||||
var optValue string
|
||||
if equalPresent && i == len(opts)-1 {
|
||||
_, optValue, err = opt.parse(cli, index, &value)
|
||||
_, _, err = opt.parse(cli, index, &value)
|
||||
} else if i < len(opts)-1 && opt.requiresValue() {
|
||||
err = errMissingOptionValue(dashes + optName)
|
||||
} else {
|
||||
skipNextArg, optValue, err = opt.parse(cli, index, nil)
|
||||
}
|
||||
if err == nil && i == len(opts)-1 {
|
||||
err = opt.finalCheck(optValue)
|
||||
skipNextArg, _, err = opt.parse(cli, index, nil)
|
||||
}
|
||||
} else {
|
||||
err = errUnknownOption(dashes + optName)
|
||||
|
||||
Reference in New Issue
Block a user