Skip to content

Commit

Permalink
merge master changes
Browse files Browse the repository at this point in the history
  • Loading branch information
integrii committed May 28, 2022
1 parent 74b6ee1 commit 0be8b6c
Show file tree
Hide file tree
Showing 8 changed files with 140 additions and 23 deletions.
6 changes: 6 additions & 0 deletions flaggy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,9 @@ func TestComplexNesting(t *testing.T) {
t.Log("testE", testE)
t.FailNow()
}
if subcommandName := flaggy.DefaultParser.TrailingSubcommand().Name; subcommandName != "scD" {
t.Fatal("Used subcommand was incorrect:", subcommandName)
}

}

Expand Down Expand Up @@ -206,5 +209,8 @@ func TestParsePositionalsA(t *testing.T) {
if parser.TrailingArguments[1] != "trailingB" {
t.Fatal("Trailing argumentB was incorrect:", parser.TrailingArguments[1])
}
if subcommandName := parser.TrailingSubcommand().Name; subcommandName != "subcommand" {
t.Fatal("Used subcommand was incorrect:", subcommandName)
}

}
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
module github.com/integrii/flaggy

go 1.12

require github.com/google/go-cmp v0.5.6 // for tests only
4 changes: 4 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
3 changes: 0 additions & 3 deletions helpValues.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@ type HelpFlag struct {
// parser. The parser is required in order to detect default flag settings
// for help and version output.
func (h *Help) ExtractValues(p *Parser, message string) {

// accept message string for output
h.Message = message

Expand Down Expand Up @@ -187,13 +186,11 @@ func (h *Help) ExtractValues(p *Parser, message string) {
}

h.UsageString = usageString

}

// parseFlagsToHelpFlags parses the specified slice of flags into
// help flags on the the calling help command
func (h *Help) parseFlagsToHelpFlags(flags []*Flag, maxLength int) {

for _, f := range flags {
if f.Hidden {
continue
Expand Down
82 changes: 79 additions & 3 deletions helpValues_blackbox_test.go
Original file line number Diff line number Diff line change
@@ -1,22 +1,59 @@
package flaggy_test

import (
"os"
"strings"
"testing"
"time"

"github.com/google/go-cmp/cmp"
"github.com/integrii/flaggy"
)

func TestMinimalHelpOutput(t *testing.T) {
p := flaggy.NewParser("TestMinimalHelpOutput")

rd, wr, err := os.Pipe()
if err != nil {
t.Fatalf("pipe: error: %s", err)
}
savedStderr := os.Stderr
os.Stderr = wr

defer func() {
os.Stderr = savedStderr
}()

p.ShowHelp()

buf := make([]byte, 1024)
n, err := rd.Read(buf)
if err != nil {
t.Fatalf("read: error: %s", err)
}
got := strings.Split(string(buf[:n]), "\n")
want := []string{
"",
"",
" Flags: ",
" --version Displays the program version string.",
" -h --help Displays help with available flag, subcommand, and positional value parameters.",
"",
"",
}

if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("help mismatch (-want +got):\n%s", diff)
}
}

func TestHelpWithMissingSCName(t *testing.T) {
defer func() {
r := recover()
if r == nil {
t.Fatal("Expected panic with subcommand avilability at position, but did not get one")
gotMsg := r.(string)
wantMsg := "Panic instead of exit with code: 2"
if gotMsg != wantMsg {
t.Fatalf("error: got: %s; want: %s", gotMsg, wantMsg)
}
}()
flaggy.ResetParser()
Expand Down Expand Up @@ -62,6 +99,45 @@ func TestHelpOutput(t *testing.T) {
p.Duration(&durationFlag, "d", "durationFlag", "This is a test duration flag that does some untimely stuff.")
p.AdditionalHelpPrepend = "This is a prepend for help"
p.AdditionalHelpAppend = "This is an append for help"
p.ParseArgs([]string{"subcommandA", "subcommandB", "hiddenPositional1"})

rd, wr, err := os.Pipe()
if err != nil {
t.Fatalf("pipe: error: %s", err)
}
savedStderr := os.Stderr
os.Stderr = wr

defer func() {
os.Stderr = savedStderr
}()

if err := p.ParseArgs([]string{"subcommandA", "subcommandB", "hiddenPositional1"}); err != nil {
t.Fatalf("got: %s; want: no error", err)
}
p.ShowHelpWithMessage("This is a help message on exit")

buf := make([]byte, 1024)
n, err := rd.Read(buf)
if err != nil {
t.Fatalf("read: error: %s", err)
}
got := strings.Split(string(buf[:n]), "\n")
want := []string{
"subcommandB - Subcommand B is a command that does other stuff",
"",
" Flags: ",
" --version Displays the program version string.",
" -h --help Displays help with available flag, subcommand, and positional value parameters.",
" -s --stringFlag This is a test string flag that does some stringy string stuff. (default: defaultStringHere)",
" -i --intFlg This is a test int flag that does some interesting int stuff. (default: 0)",
" -b --boolFlag This is a test bool flag that does some booly bool stuff.",
" -d --durationFlag This is a test duration flag that does some untimely stuff. (default: 0s)",
"",
"This is a help message on exit",
"",
}

if diff := cmp.Diff(want, got); diff != "" {
t.Errorf("help mismatch (-want +got):\n%s", diff)
}
}
5 changes: 5 additions & 0 deletions parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ type Parser struct {
subcommandContext *Subcommand // points to the most specific subcommand being used
}

// TrailingSubcommand returns the last and most specific subcommand invoked.
func (p *Parser) TrailingSubcommand() *Subcommand {
return p.subcommandContext
}

// NewParser creates a new ArgumentParser ready to parse inputs
func NewParser(name string) *Parser {
// this can not be done inline because of struct embedding
Expand Down
8 changes: 5 additions & 3 deletions subCommand.go
Original file line number Diff line number Diff line change
Expand Up @@ -666,14 +666,14 @@ func (sc *Subcommand) AddPositionalValue(assignmentVar *string, name string, rel
// ensure no other positionals are at this depth
for _, other := range sc.PositionalFlags {
if relativePosition == other.Position {
log.Panicln("Unable to add positional value because one already exists at position: " + strconv.Itoa(relativePosition))
log.Panicln("Unable to add positional value " + name + " because " + other.Name + " already exists at position: " + strconv.Itoa(relativePosition))
}
}

// ensure no subcommands at this depth
for _, other := range sc.Subcommands {
if relativePosition == other.Position {
log.Panicln("Unable to add positional value a subcommand already exists at position: " + strconv.Itoa(relativePosition))
log.Panicln("Unable to add positional value " + name + "because a subcommand, " + other.Name + ", already exists at position: " + strconv.Itoa(relativePosition))
}
}

Expand All @@ -699,7 +699,9 @@ func (sc *Subcommand) SetValueForKey(key string, value string) (bool, error) {
// debugPrint("Evaluating string flag", f.ShortName, "==", key, "||", f.LongName, "==", key)
if f.ShortName == key || f.LongName == key {
// debugPrint("Setting string value for", key, "to", value)
f.identifyAndAssignValue(value)
if err := f.identifyAndAssignValue(value); err != nil {
return false, err
}
return true, nil
}
}
Expand Down
53 changes: 39 additions & 14 deletions subcommand_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ func TestSCNameExists(t *testing.T) {
scB := flaggy.NewSubcommand("test")
flaggy.AttachSubcommand(scA, 1)
flaggy.AttachSubcommand(scB, 1)

}

func TestFlagExists(t *testing.T) {
Expand All @@ -37,7 +36,6 @@ func TestFlagExists(t *testing.T) {
if e == false {
t.Fatal("Flag does not exist on a subcommand that should")
}

}

// TestExitOnUnknownFlag tests that when an unknown flag is supplied and the
Expand Down Expand Up @@ -157,7 +155,9 @@ func TestTypoSubcommand(t *testing.T) {
newSCB := flaggy.NewSubcommand("TestTypoSubcommandB")
p.AttachSubcommand(newSCA, 1)
p.AttachSubcommand(newSCB, 1)
p.ParseArgs(args)
if err := p.ParseArgs(args); err != nil {
t.Fatalf("got: %s; want: no error", err)
}
}

// TestIgnoreUnexpected tests what happens when an invalid subcommand is passed but should be ignored
Expand All @@ -167,7 +167,9 @@ func TestIgnoreUnexpected(t *testing.T) {
args := []string{"unexpectedArg"}
newSCA := flaggy.NewSubcommand("TestTypoSubcommandA")
p.AttachSubcommand(newSCA, 1)
p.ParseArgs(args)
if err := p.ParseArgs(args); err != nil {
t.Fatalf("got: %s; want: no error", err)
}
}

// TestSubcommandHelp tests displaying of help on unspecified commands
Expand All @@ -181,7 +183,9 @@ func TestSubcommandHelp(t *testing.T) {
p := flaggy.NewParser("TestSubcommandHelp")
p.ShowHelpOnUnexpected = true
args := []string{"unexpectedArg"}
p.ParseArgs(args)
if err := p.ParseArgs(args); err != nil {
t.Fatalf("got: %s; want: no error", err)
}
}

func TestHelpWithHFlagA(t *testing.T) {
Expand All @@ -194,7 +198,9 @@ func TestHelpWithHFlagA(t *testing.T) {
p := flaggy.NewParser("TestHelpWithHFlag")
p.ShowHelpWithHFlag = true
args := []string{"-h"}
p.ParseArgs(args)
if err := p.ParseArgs(args); err != nil {
t.Fatalf("got: %s; want: no error", err)
}
}

func TestHelpWithHFlagB(t *testing.T) {
Expand All @@ -207,7 +213,9 @@ func TestHelpWithHFlagB(t *testing.T) {
p := flaggy.NewParser("TestHelpWithHFlag")
p.ShowHelpWithHFlag = true
args := []string{"--help"}
p.ParseArgs(args)
if err := p.ParseArgs(args); err != nil {
t.Fatalf("got: %s; want: no error", err)
}
}

func TestVersionWithVFlagB(t *testing.T) {
Expand All @@ -221,7 +229,9 @@ func TestVersionWithVFlagB(t *testing.T) {
p.ShowVersionWithVersionFlag = true
p.Version = "TestVersionWithVFlagB 0.0.0a"
args := []string{"--version"}
p.ParseArgs(args)
if err := p.ParseArgs(args); err != nil {
t.Fatalf("got: %s; want: no error", err)
}
}

// TestSubcommandParse tests paring of a single subcommand
Expand All @@ -243,7 +253,9 @@ func TestSubcommandParse(t *testing.T) {

// override os args and parse them
os.Args = []string{"binaryName", "testSubcommand", "testPositional"}
p.Parse()
if err := p.Parse(); err != nil {
t.Fatalf("got: %s; want: no error", err)
}

// ensure subcommand and positional used
if !newSC.Used {
Expand All @@ -255,7 +267,6 @@ func TestSubcommandParse(t *testing.T) {
}

func TestBadSubcommand(t *testing.T) {

// create the argument parser
p := flaggy.NewParser("TestBadSubcommand")

Expand All @@ -265,11 +276,12 @@ func TestBadSubcommand(t *testing.T) {

// test what happens if you add a bad subcommand
os.Args = []string{"test"}
p.Parse()
if err := p.Parse(); err != nil {
t.Fatalf("got: %s; want: no error", err)
}
}

func TestBadPositional(t *testing.T) {

// create the argument parser
p := flaggy.NewParser("TestBadPositional")

Expand Down Expand Up @@ -310,7 +322,6 @@ func debugOff() {
// BenchmarkSubcommandParse benchmarks the creation and parsing of
// a basic subcommand
func BenchmarkSubcommandParse(b *testing.B) {

// catch errors that may occur
defer func(b *testing.B) {
err := recover()
Expand Down Expand Up @@ -342,7 +353,6 @@ func BenchmarkSubcommandParse(b *testing.B) {
b.Fatal("Error parsing args: " + err.Error())
}
}

}

// TestSCInputParsing tests all flag types on subcommands
Expand Down Expand Up @@ -804,3 +814,18 @@ func TestNestedSCBoolFlag(t *testing.T) {
t.Fatal("Error parsing args: " + err.Error())
}
}

func TestParseErrorsAreReportedRegression(t *testing.T) {
defer func() {
r := recover()
if r == nil {
t.Fatal("Expected crash on invalid syntax")
}
}()

flaggy.ResetParser()
intFlag := 42
flaggy.Int(&intFlag, "i", "int", "dummy")
os.Args = []string{"prog", "--int", "abc"}
flaggy.Parse()
}

0 comments on commit 0be8b6c

Please sign in to comment.