test: added NAME section to the help output

This commit is contained in:
Celestino Amoroso 2026-01-23 11:20:27 +01:00
parent b9f5f92948
commit f830851e58

View File

@ -6,76 +6,370 @@ import (
"testing" "testing"
) )
type GlobaData struct { const version = `$VER:ddt-ocr,1.0.1,2025-11-23,celestino.amoroso@gmail.com:$`
type GlobalData struct {
config string config string
log []string log []string
printOcr bool printOcr bool
saveClips bool saveClips bool
trace bool trace bool
page []int page []int
cliVars map[string]string
inputName string
workDir string
attempts int
sources []string sources []string
dest string dest string
facoltativo string report string
} }
func (gd *GlobaData) String() string { func TestVersion(t *testing.T) {
var sb strings.Builder
fmt.Fprintf(&sb, "Options:\n")
fmt.Fprintf(&sb, " Config.....: %q\n", gd.config)
fmt.Fprintf(&sb, " Log........: %v\n", gd.log)
fmt.Fprintf(&sb, " Print-Ocr..: %v\n", gd.printOcr)
fmt.Fprintf(&sb, " Save-Clips.: %v\n", gd.saveClips)
fmt.Fprintf(&sb, " Page.......: %v\n", gd.page)
fmt.Fprintf(&sb, " Trace......: %v\n", gd.trace)
fmt.Fprintf(&sb, "Argumentes:\n")
fmt.Fprintf(&sb, " Sources....: %s\n", strings.Join(gd.sources, ", "))
fmt.Fprintf(&sb, " Destination: %s\n", gd.dest)
fmt.Fprintf(&sb, " Facoltativo: %s\n", gd.facoltativo)
return sb.String()
}
func TestUsage(t *testing.T) {
var cli CliParser var cli CliParser
var version = `$VER:mini-ddt-ocr,1.0.1,2025-11-23,celestino.amoroso@gmail.com:$` var gd GlobalData
var gd GlobaData
args := []string{ if err := initCli(&cli, &gd); err != nil {
"mini-ddt-ocr",
"--log", "all",
"--config", "devel-config.yaml",
// "--var", "deploy_env=devel",
"--print-ocr",
"--pages", "17,18",
"../../dev-stuff/ocis-upload.log", "ciccio", "bello", "pippo",
}
cli.Init(args, version)
if err := gd.addOptions(&cli); err != nil {
t.Error(err) t.Error(err)
return return
} }
usage := cli.Usage() if v, err := cli.GetVersionSection("all"); err == nil {
fmt.Println(usage) if v != version[5:len(version)-2] {
if err := cli.Parse(); err == nil { t.Errorf("Version string does not match expected.\nGot:\n%q\nExpected:\n%q", v, version)
fmt.Println(&gd) }
} else { } else {
t.Error(err) t.Error(err)
} }
} }
func (gd *GlobaData) addOptions(cli *CliParser) (err error) { func TestVersionNumber(t *testing.T) {
var cli CliParser
var gd GlobalData
if err := initCli(&cli, &gd); err != nil {
t.Error(err)
return
}
secValues := []string{"ddt-ocr", "1.0.1", "2025-11-23", "celestino.amoroso@gmail.com"}
for i, sec := range []string{"program", "version", "date", "email"} {
if v, err := cli.GetVersionSection(sec); err == nil {
if v != secValues[i] {
t.Errorf("Version section %q does not match expected value.\nGot:\n%q\nExpected:\n%q", sec, v, version)
}
} else {
t.Error(err)
}
}
}
func TestUsage(t *testing.T) {
const expectedUsage = `NAME ddt-ocr - cli-test
USAGE: ddt-ocr [<options>] <image-sources> ... <dest> [<report>]
where:
<image-sources> Source image files
<dest> Output destination file
<report> Optional report file
<options>
-o, --print-ocr Print the OCR output to stderr
-s, --save-clip Save the image clips as PNG files (alias: save-clips)
-t, --trace Enable trace mode for detailed logging
-p, --page(s) <num>["," ...] Process only the specified pages (comma-separated list)
-c, --config <file> Alternate configuration file
-l, --log(s) <string>["," ...] Logging options (comma-separated list)
-V, --var(s) <key=value>["," ...] Define one or more comma separated variables for the actions context (multiple allowed)
-n, --input-name <string> Input file name when source comes from stdin
-d, --work-dir <dir> Work directory
--attempts <num> Attempts for retrying failed operations (default: "1")
`
var cli CliParser
var gd GlobalData
if err := initCli(&cli, &gd); err != nil {
t.Error(err)
return
}
usage := cli.Usage()
if usage != expectedUsage {
t.Errorf("Usage output does not match expected.\nGot:\n%s\nExpected:\n%s", usage, expectedUsage)
}
}
func TestParser(t *testing.T) {
const expectedOutput = `Option: print-ocr, Type: bool, Value: true
Option: save-clip, Type: bool, Value: false
Option: trace, Type: bool, Value: true
Option: page, Type: num-array, Value: [17 18]
Option: config, Type: string, Value: devel-config.yaml
Option: log, Type: string-array, Value: [all]
Option: var, Type: map-string, Value: map[deploy_env:devel]
Option: input-name, Type: string, Value: my-scan.pdf
Option: work-dir, Type: string, Value:
Option: attempts, Type: num, Value: 1
Option: help, Type: n/a, Value: <nil>
Option: version, Type: n/a, Value: <nil>
`
var cli CliParser
var gd GlobalData
var sb strings.Builder
if err := initCli(&cli, &gd); err != nil {
t.Error(err)
return
}
tracer := NewSimpleOptionTracer(&sb)
if err := cli.Parse(); err == nil {
cli.TraceOptions(tracer)
if sb.String() != expectedOutput {
t.Errorf("Parsed options do not match expected.\nGot:\n%q\nExpected:\n%q", sb.String(), expectedOutput)
}
} else {
t.Error(err)
}
}
func initCli(cli *CliParser, gd *GlobalData) (err error) {
args := []string{
"ddt-ocr",
"--log", "all",
"-t",
"--config", "devel-config.yaml",
"--var", "deploy_env=devel",
"--print-ocr",
"--pages", "17,18",
"--input-name=my-scan.pdf",
"scan1.pdf", "scan2.pdf", "result.txt", "report.txt",
}
cli.Init(args, version, "cli-test")
err = gd.addOptions(cli)
return
}
func TestOptErrorUnknownOption(t *testing.T) {
const unknownOption = "--logging"
var expectedErr = errUnknownOption(unknownOption)
var cli CliParser
var gd GlobalData
if err := initCliUnknownOption(&cli, &gd, unknownOption); err == nil {
if err = cli.Parse(); err != nil {
if err.Error() != expectedErr.Error() {
t.Errorf("Invalid error message.\nGot:\n%v\nExpected:\n%v", err, expectedErr)
}
} else {
t.Errorf("Expected error for unknown option %q, but got none", unknownOption)
}
} else {
t.Error(err)
return
}
}
func initCliUnknownOption(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")
err = gd.addOptions(cli)
return
}
func TestOptErrorMissingOptionValue(t *testing.T) {
const missingValueOption = "--page"
var expectedErr = fmt.Errorf(`invalid value scan1.pdf (string) for option "page" (num-array)`)
var cli CliParser
var gd GlobalData
if err := initCliMissingOptionValue(&cli, &gd, missingValueOption); err == nil {
if err = cli.Parse(); err != nil {
if err.Error() != expectedErr.Error() {
t.Errorf("Invalid error message.\nGot:\n%v\nExpected:\n%v", err, expectedErr)
}
} else {
t.Errorf("Expected error for unknown option %q, but got none", missingValueOption)
}
} else {
t.Error(err)
return
}
}
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")
err = gd.addOptions(cli)
return
}
func TestOptErrorInvalidOptionValue(t *testing.T) {
const missingInvalidValueOption = "--page"
var expectedErr = errInvalidOptionValue("page", "some", "num-array")
var cli CliParser
var gd GlobalData
if err := initCliInvalidOptionValue(&cli, &gd, missingInvalidValueOption); err == nil {
if err = cli.Parse(); err != nil {
if err.Error() != expectedErr.Error() {
t.Errorf("Invalid error message.\nGot:\n%v\nExpected:\n%v", err, expectedErr)
}
} else {
t.Errorf("Expected error for unknown option %q, but got none", missingInvalidValueOption)
}
} else {
t.Error(err)
return
}
}
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")
err = gd.addOptions(cli)
return
}
func TestArgErrorMissingRequired(t *testing.T) {
const missingRequiredArg = "--page"
var expectedErr = fmt.Errorf(`missing required arg <image-sources>`)
var cli CliParser
var gd GlobalData
if err := initCliMissingRequiredArg(&cli, &gd); err == nil {
if err = cli.Parse(); err != nil {
if err.Error() != expectedErr.Error() {
t.Errorf("Invalid error message.\nGot:\n%v\nExpected:\n%v", err, expectedErr)
}
} else {
t.Errorf("Expected error for unknown option %q, but got none", missingRequiredArg)
}
} else {
t.Error(err)
return
}
}
func initCliMissingRequiredArg(cli *CliParser, gd *GlobalData) (err error) {
args := []string{
"ddt-ocr",
}
cli.Init(args, version, "cli-test")
err = gd.addOptions(cli)
return
}
func TestArgErrorReapet(t *testing.T) {
var expectedErr = fmt.Errorf(`repeat property already set for arg <other>`)
var cli CliParser
var gd GlobalData
if err := initCliReapetArg(&cli, &gd); err != nil {
if err.Error() != expectedErr.Error() {
t.Errorf("Invalid error message.\nGot:\n%v\nExpected:\n%v", err, expectedErr)
}
} else {
t.Errorf("Expected error, but got none")
}
}
func initCliReapetArg(cli *CliParser, gd *GlobalData) (err error) {
args := []string{
"ddt-ocr",
"scan1.pdf", "scan2.pdf", "result.txt", "report.txt",
}
cli.Init(args, version, "cli-test")
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)
} }
}() }()
cli.AddBoolOpt("print-ocr", "o", &gd.printOcr, "Stampa l'output del programma OCR") cli.AddStringArrayArg("other", true, nil, "other args")
cli.AddBoolOpt("save-clip", "s", &gd.saveClips, "Registra le immagini delle aree ritagliata", "save-clips") cli.AddStringArrayArg("other2", true, nil, "other args 2")
cli.AddBoolOpt("trace", "t", &gd.trace, "Attiva la modalità di tracciamento delle operazioni") }
cli.AddIntArrayOpt("page", "p", &gd.page, gd.page, "Elabora la pagina specificata") return
cli.AddStringOpt("config", "c", &gd.config, gd.config, "Specifica un percorso alternativo per il file di configurazione") }
cli.AddStringArrayOpt("log", "l", &gd.log, gd.log, "Maschera di livelli di log")
func TestOptHidden(t *testing.T) {
cli.AddStringArrayArg("sorgenti", true, &gd.sources, "file da elaborare") const expectedUsage = `NAME ddt-ocr - cli-test
cli.AddStringArg("dest", true, &gd.dest, "file di outout") USAGE: ddt-ocr [<options>] <image-sources> ... <dest> [<report>]
cli.AddStringArg("facoltativo", false, &gd.facoltativo, "file facoltativo") where:
<image-sources> Source image files
<dest> Output destination file
<report> Optional report file
<options>
-o, --print-ocr Print the OCR output to stderr
-t, --trace Enable trace mode for detailed logging
-p, --page(s) <num>["," ...] Process only the specified pages (comma-separated list)
-c, --config <file> Alternate configuration file
-l, --log(s) <string>["," ...] Logging options (comma-separated list)
-V, --var(s) <key=value>["," ...] Define one or more comma separated variables for the actions context (multiple allowed)
-n, --input-name <string> Input file name when source comes from stdin
-d, --work-dir <dir> Work directory
--attempts <num> Attempts for retrying failed operations (default: "1")
`
var cli CliParser
var gd GlobalData
if err := initCliHiddenOpt(&cli, &gd); err != nil {
t.Error(err)
return
}
usage := cli.Usage()
if usage != expectedUsage {
t.Errorf("Usage output does not match expected.\nGot:\n%s\nExpected:\n%s", usage, expectedUsage)
}
}
func initCliHiddenOpt(cli *CliParser, gd *GlobalData) (err error) {
if err = initCli(cli, gd); err == nil {
if ref := cli.GetOption("save-clip"); ref != nil {
ref.SetHidden(true)
} else {
err = fmt.Errorf("option save-clip not found")
}
}
return
}
func (gd *GlobalData) addOptions(cli *CliParser) (err error) {
// Always recover from panic to return error before adding options
defer func() {
if r := recover(); r != nil {
err = r.(error)
}
}()
// Define options
cli.AddBoolOpt("print-ocr", "o", &gd.printOcr, "Print the OCR output to stderr")
cli.AddBoolOpt("save-clip", "s", &gd.saveClips, "Save the image clips as PNG files", "save-clips")
cli.AddBoolOpt("trace", "t", &gd.trace, "Enable trace mode for detailed logging")
cli.AddIntArrayOpt("page", "p", &gd.page, gd.page, "Process only the specified pages (comma-separated list)")
cli.AddFileOpt("config", "c", &gd.config, gd.config, "Alternate configuration file")
cli.AddStringArrayOpt("log", "l", &gd.log, gd.log, "Logging options (comma-separated list)")
cli.AddStringMapOpt("var", "V", &gd.cliVars, nil, "Define one or more comma separated variables for the actions context (multiple allowed)")
cli.AddStringOpt("input-name", "n", &gd.inputName, "", "Input file name when source comes from stdin")
cli.AddDirOpt("work-dir", "d", &gd.workDir, "", "Work directory")
if ref := cli.AddIntOpt("attempts", "", &gd.attempts, 1, "Attempts for retrying failed operations"); ref != nil {
ref.AddSpecialValue("many", func(manager OptManager, cliValue string, currentValue any) (any, error) {
return 1000, nil
})
ref.AddSpecialValue("few", func(manager OptManager, cliValue string, currentValue any) (any, error) {
manager.SetOptionValue("page", "1")
return nil, nil
})
}
// Define arguments
cli.AddStringArrayArg("image-sources", true, &gd.sources, "Source image files")
cli.AddStringArg("dest", true, &gd.dest, "Output destination file")
cli.AddStringArg("report", false, &gd.report, "Optional report file")
return return
} }