cli args moved from Init() to Parse()

This commit is contained in:
Celestino Amoroso 2026-03-19 09:10:49 +01:00
parent 00b84278d8
commit 20b6b961fb
4 changed files with 41 additions and 49 deletions

View File

@ -60,6 +60,8 @@ func main() {
Refer to the unit test for a realistic example: [`cli_test.go`](cli_test.go). Refer to the unit test for a realistic example: [`cli_test.go`](cli_test.go).
## Usage
## API Reference ## API Reference
Key types and methods: Key types and methods:

7
cli.go
View File

@ -55,10 +55,9 @@ type CliParser struct {
flags int16 flags int16
} }
func (cli *CliParser) Init(argv []string, version string, description string, flags ...int16) { func (cli *CliParser) Init(version string, description string, flags ...int16) {
cli.version = version cli.version = version
cli.description = description cli.description = description
cli.cliArgs = argv
for _, flag := range flags { for _, flag := range flags {
cli.flags |= flag cli.flags |= flag
} }
@ -245,9 +244,11 @@ func (cli *CliParser) parseCommandArgs(commandArgs []string) (err error) {
return return
} }
func (cli *CliParser) Parse() (err error) { func (cli *CliParser) Parse(argv []string) (err error) {
var commandArgs []string var commandArgs []string
cli.cliArgs = argv
cli.addHelpAndVersion() cli.addHelpAndVersion()
// first parse options and collect command arguments in the args array // first parse options and collect command arguments in the args array

View File

@ -33,7 +33,7 @@ func TestVerbose(t *testing.T) {
t.Error(err) t.Error(err)
return return
} }
if err := cli.Parse(); err != nil { if err := cli.Parse(commonArgs()); err != nil {
t.Error(err) t.Error(err)
} else if gd.verbose != 3 { } else if gd.verbose != 3 {
t.Errorf("Expected verbose level 3, got %d", gd.verbose) t.Errorf("Expected verbose level 3, got %d", gd.verbose)
@ -134,7 +134,7 @@ Option: version, Type: n/a, Value: <nil>
return return
} }
tracer := NewSimpleOptionTracer(&sb) tracer := NewSimpleOptionTracer(&sb)
if err := cli.Parse(); err == nil { if err := cli.Parse(commonArgs()); err == nil {
cli.TraceOptions(tracer) cli.TraceOptions(tracer)
if sb.String() != expectedOutput { if sb.String() != expectedOutput {
t.Errorf("Parsed options do not match expected list.\nGot:\n%q\nExpected:\n%q", 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) { func commonArgs() []string {
args := []string{ return []string{
"ddt-ocr", "ddt-ocr",
"--log", "all", "--log", "all",
"-t", "-t",
@ -157,7 +157,10 @@ func initCli(cli *CliParser, gd *GlobalData) (err error) {
"--input-name=my-scan.pdf", "--input-name=my-scan.pdf",
"scan1.pdf", "scan2.pdf", "result.txt", "report.txt", "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) err = gd.addOptions(cli)
return return
} }
@ -168,8 +171,8 @@ func TestOptErrorUnknownOption(t *testing.T) {
var cli CliParser var cli CliParser
var gd GlobalData var gd GlobalData
if err := initCliUnknownOption(&cli, &gd, unknownOption); err == nil { if err := initCliUnknownOption(&cli, &gd); err == nil {
if err = cli.Parse(); err != nil { if err = cli.Parse(commonBadArgs(unknownOption)); err != nil {
if err.Error() != expectedErr.Error() { if err.Error() != expectedErr.Error() {
t.Errorf("Invalid error message.\nGot:\n%v\nExpected:\n%v", err, expectedErr) 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) { func commonBadArgs(option string) []string {
args := []string{ return []string{
"ddt-ocr", "ddt-ocr",
option, option,
"scan1.pdf", "scan2.pdf", "result.txt", "report.txt", "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) err = gd.addOptions(cli)
return return
} }
@ -199,8 +204,8 @@ func TestOptErrorMissingOptionValue(t *testing.T) {
var cli CliParser var cli CliParser
var gd GlobalData var gd GlobalData
if err := initCliMissingOptionValue(&cli, &gd, missingValueOption); err == nil { if err := initCliMissingOptionValue(&cli, &gd); err == nil {
if err = cli.Parse(); err != nil { if err = cli.Parse(commonBadArgs(missingValueOption)); err != nil {
if err.Error() != expectedErr.Error() { if err.Error() != expectedErr.Error() {
t.Errorf("Invalid error message.\nGot:\n%v\nExpected:\n%v", err, expectedErr) 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) { func initCliMissingOptionValue(cli *CliParser, gd *GlobalData) (err error) {
args := []string{ cli.Init(version, "cli-test")
"ddt-ocr",
option,
"scan1.pdf", "scan2.pdf", "result.txt", "report.txt",
}
cli.Init(args, version, "cli-test")
err = gd.addOptions(cli) err = gd.addOptions(cli)
return return
} }
func TestOptErrorInvalidOptionValue(t *testing.T) { func TestOptErrorInvalidOptionValue(t *testing.T) {
const missingInvalidValueOption = "--page" const missingInvalidValueOption = "--page"
var expectedErr = errInvalidOptionValue("page", "some", "num-array") var expectedErr = errInvalidOptionValue("page", "scan1.pdf", "num-array")
var cli CliParser var cli CliParser
var gd GlobalData var gd GlobalData
if err := initCliInvalidOptionValue(&cli, &gd, missingInvalidValueOption); err == nil { if err := initCliInvalidOptionValue(&cli, &gd); err == nil {
if err = cli.Parse(); err != nil { if err = cli.Parse(commonBadArgs(missingInvalidValueOption)); err != nil {
if err.Error() != expectedErr.Error() { if err.Error() != expectedErr.Error() {
t.Errorf("Invalid error message.\nGot:\n%v\nExpected:\n%v", err, expectedErr) 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) { func initCliInvalidOptionValue(cli *CliParser, gd *GlobalData) (err error) {
args := []string{ cli.Init(version, "cli-test")
"ddt-ocr",
option, "some",
"scan1.pdf", "scan2.pdf", "result.txt", "report.txt",
}
cli.Init(args, version, "cli-test")
err = gd.addOptions(cli) err = gd.addOptions(cli)
return return
} }
@ -262,7 +257,7 @@ func TestArgErrorMissingRequired(t *testing.T) {
var gd GlobalData var gd GlobalData
if err := initCliMissingRequiredArg(&cli, &gd); err == nil { 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() { if err.Error() != expectedErr.Error() {
t.Errorf("Invalid error message.\nGot:\n%v\nExpected:\n%v", err, expectedErr) 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) { func initCliMissingRequiredArg(cli *CliParser, gd *GlobalData) (err error) {
args := []string{ cli.Init(version, "cli-test")
"ddt-ocr",
}
cli.Init(args, version, "cli-test")
err = gd.addOptions(cli) err = gd.addOptions(cli)
return return
} }
func TestArgErrorRepeat(t *testing.T) { func TestArgErrorRepeatProperty(t *testing.T) {
var expectedErr = fmt.Errorf(`repeat property already set for arg <other>`) var expectedErr = fmt.Errorf(`repeat property already set for arg <other>`)
var cli CliParser var cli CliParser
var gd GlobalData var gd GlobalData
@ -299,17 +291,14 @@ func TestArgErrorRepeat(t *testing.T) {
} }
func initCliRepeatArg(cli *CliParser, gd *GlobalData) (err error) { func initCliRepeatArg(cli *CliParser, gd *GlobalData) (err error) {
args := []string{ cli.Init(version, "cli-test")
"ddt-ocr",
"scan1.pdf", "scan2.pdf", "result.txt", "report.txt",
}
cli.Init(args, version, "cli-test")
if err = gd.addOptions(cli); err == nil { if err = gd.addOptions(cli); err == nil {
defer func() { defer func() {
if r := recover(); r != nil { if r := recover(); r != nil {
err = r.(error) err = r.(error)
} }
}() }()
// This will raise error because we can't declare two args array
cli.AddStringArrayArg("other", true, nil, "other args") cli.AddStringArrayArg("other", true, nil, "other args")
cli.AddStringArrayArg("other2", true, nil, "other args 2") cli.AddStringArrayArg("other2", true, nil, "other args 2")
} }

View File

@ -26,8 +26,8 @@ func TestOneOptWithEqual(t *testing.T) {
"--color=blue", "--color=blue",
} }
cli.Init(args, "1.0.0", "TestOneOptWithEqual description") cli.Init("1.0.0", "TestOneOptWithEqual description")
if err := cli.Parse(); err != nil { if err := cli.Parse(args); err != nil {
t.Error(err) t.Error(err)
} else if color != "blue" { } else if color != "blue" {
t.Errorf("Expected color blue, got %q", color) t.Errorf("Expected color blue, got %q", color)
@ -54,8 +54,8 @@ func testIntArrayOptOk(t *testing.T, n int, args []string, flags ...int16) {
var cli CliParser var cli CliParser
t.Logf("Arg set n. %d", n) t.Logf("Arg set n. %d", n)
addBoxOption(&cli, &box) addBoxOption(&cli, &box)
cli.Init(args, "1.0.0", "TestIntArrayOpt description", flags...) cli.Init("1.0.0", "TestIntArrayOpt description", flags...)
if err := cli.Parse(); err != nil { if err := cli.Parse(args); err != nil {
t.Error(err) t.Error(err)
} else if len(box) != 4 { } else if len(box) != 4 {
t.Errorf(`Expected 4 items, got %d`, len(box)) t.Errorf(`Expected 4 items, got %d`, len(box))
@ -67,8 +67,8 @@ func testIntArrayOptKo(t *testing.T, n int, args []string, msg string, flags ...
var cli CliParser var cli CliParser
t.Logf("Arg set n. %d", n) t.Logf("Arg set n. %d", n)
addBoxOption(&cli, &box) addBoxOption(&cli, &box)
cli.Init(args, "1.0.0", "TestIntArrayOpt description", flags...) cli.Init("1.0.0", "TestIntArrayOpt description", flags...)
if err := cli.Parse(); err == nil { if err := cli.Parse(args); err == nil {
t.Errorf("Expected error, got nil") t.Errorf("Expected error, got nil")
} else if err.Error() != msg { } else if err.Error() != msg {
t.Errorf(`Invalid error: %q; expected: %q`, err.Error(), msg) t.Errorf(`Invalid error: %q; expected: %q`, err.Error(), msg)