Skip to content

Commit

Permalink
common way of composing shorthand arguments (#52)
Browse files Browse the repository at this point in the history
* common way of composing shortway argument. Tests, Tests correction of formatting

* unnamed return values
  • Loading branch information
goofinator authored and akamensky committed Dec 11, 2019
1 parent e731cac commit 543653f
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 41 deletions.
155 changes: 127 additions & 28 deletions argparse_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,98 +8,135 @@ import (
"testing"
)

func TestInternalFunction1(t *testing.T) {
func TestInternalFunctionParse(t *testing.T) {
var resultS string
//test string
a := &arg{
result: &resultS,
sname: "-f",
lname: "--flag",
sname: "f",
lname: "flag",
size: 2,
opts: nil,
unique: true,
}
args0 := []string{}
args2 := []string{"0", "1"}
failureMessageCommon := "[--f|----flag] followed by too many arguments"
failureMessage := "[--f|----flag] must be followed by a string"
failureMessageCommon := "[-f|--flag] followed by too many arguments"
failureMessage := "[-f|--flag] must be followed by a string"

if err := a.parse(args0, 1); err == nil || err.Error() != failureMessage {
t.Errorf("Test %s failed with error: \"%s\". error: \"%s\" expected", t.Name(), err, failureMessage)
t.Errorf("Test %s failed with error: \"%v\". error: %q expected", t.Name(), err, failureMessage)
}
a.parsed = false
if err := a.parse(args2, 1); err == nil || err.Error() != failureMessageCommon {
t.Errorf("Test %s failed with error: \"%s\". error: \"%s\" expected", t.Name(), err, failureMessageCommon)
t.Errorf("Test %s failed with error: \"%v\". error: %q expected", t.Name(), err, failureMessageCommon)
}
a.parsed = false
//test int
var resultI int
a.result = &resultI
failureMessage = "[--f|----flag] must be followed by an integer"
failureMessage = "[-f|--flag] must be followed by an integer"
if err := a.parse(args0, 1); err == nil || err.Error() != failureMessage {
t.Errorf("Test %s failed with error: \"%s\". error: \"%s\" expected", t.Name(), err, failureMessage)
t.Errorf("Test %s failed with error: \"%v\". error: %q expected", t.Name(), err, failureMessage)
}
a.parsed = false
if err := a.parse(args2, 1); err == nil || err.Error() != failureMessageCommon {
t.Errorf("Test %s failed with error: \"%s\". error: \"%s\" expected", t.Name(), err, failureMessageCommon)
t.Errorf("Test %s failed with error: \"%v\". error: %q expected", t.Name(), err, failureMessageCommon)
}
a.parsed = false
//test float
var resultF float64
a.result = &resultF
failureMessage = "[--f|----flag] must be followed by a floating point number"
failureMessage = "[-f|--flag] must be followed by a floating point number"
if err := a.parse(args0, 1); err == nil || err.Error() != failureMessage {
t.Errorf("Test %s failed with error: \"%s\". error: \"%s\" expected", t.Name(), err, failureMessage)
t.Errorf("Test %s failed with error: \"%v\". error: %q expected", t.Name(), err, failureMessage)
}
a.parsed = false
if err := a.parse(args2, 1); err == nil || err.Error() != failureMessageCommon {
t.Errorf("Test %s failed with error: \"%s\". error: \"%s\" expected", t.Name(), err, failureMessageCommon)
t.Errorf("Test %s failed with error: \"%v\". error: %q expected", t.Name(), err, failureMessageCommon)
}
a.parsed = false
//test os.File
var resultFile os.File
a.result = &resultFile
failureMessage = "[--f|----flag] must be followed by a path to file"
failureMessage = "[-f|--flag] must be followed by a path to file"
if err := a.parse(args0, 1); err == nil || err.Error() != failureMessage {
t.Errorf("Test %s failed with error: \"%s\". error: \"%s\" expected", t.Name(), err, failureMessage)
t.Errorf("Test %s failed with error: \"%v\". error: %q expected", t.Name(), err, failureMessage)
}
a.parsed = false
if err := a.parse(args2, 1); err == nil || err.Error() != failureMessageCommon {
t.Errorf("Test %s failed with error: \"%s\". error: \"%s\" expected", t.Name(), err, failureMessageCommon)
t.Errorf("Test %s failed with error: \"%v\". error: %q expected", t.Name(), err, failureMessageCommon)
}
a.parsed = false
//test []string
var resultSL []string
a.result = &resultSL
failureMessage = "[--f|----flag] must be followed by a string"
failureMessage = "[-f|--flag] must be followed by a string"
if err := a.parse(args0, 1); err == nil || err.Error() != failureMessage {
t.Errorf("Test %s failed with error: \"%s\". error: \"%s\" expected", t.Name(), err, failureMessage)
t.Errorf("Test %s failed with error: \"%v\". error: %q expected", t.Name(), err, failureMessage)
}
a.parsed = false
if err := a.parse(args2, 1); err == nil || err.Error() != failureMessageCommon {
t.Errorf("Test %s failed with error: \"%s\". error: \"%s\" expected", t.Name(), err, failureMessageCommon)
t.Errorf("Test %s failed with error: \"%v\". error: %q expected", t.Name(), err, failureMessageCommon)
}
a.parsed = false
//test []int
var resultIL []int
a.result = &resultIL
failureMessage = "[--f|----flag] must be followed by a string representation of integer"
failureMessage = "[-f|--flag] must be followed by a string representation of integer"
if err := a.parse(args0, 1); err == nil || err.Error() != failureMessage {
t.Errorf("Test %s failed with error: \"%s\". error: \"%s\" expected", t.Name(), err, failureMessage)
t.Errorf("Test %s failed with error: \"%v\". error: %q expected", t.Name(), err, failureMessage)
}
a.parsed = false
if err := a.parse(args2, 1); err == nil || err.Error() != failureMessageCommon {
t.Errorf("Test %s failed with error: \"%s\". error: \"%s\" expected", t.Name(), err, failureMessageCommon)
t.Errorf("Test %s failed with error: \"%v\". error: %q expected", t.Name(), err, failureMessageCommon)
}
a.parsed = false
//test []float
var resultFL []float64
a.result = &resultFL
failureMessage = "[--f|----flag] must be followed by a string representation of integer"
failureMessage = "[-f|--flag] must be followed by a string representation of integer"
if err := a.parse(args0, 1); err == nil || err.Error() != failureMessage {
t.Errorf("Test %s failed with error: \"%s\". error: \"%s\" expected", t.Name(), err, failureMessage)
t.Errorf("Test %s failed with error: \"%v\". error: %q expected", t.Name(), err, failureMessage)
}
a.parsed = false
if err := a.parse(args2, 1); err == nil || err.Error() != failureMessageCommon {
t.Errorf("Test %s failed with error: \"%s\". error: \"%s\" expected", t.Name(), err, failureMessageCommon)
t.Errorf("Test %s failed with error: \"%v\". error: %q expected", t.Name(), err, failureMessageCommon)
}
a.parsed = false
//test []os.File
var resultFileL []os.File
a.result = &resultFileL
failureMessage = "[--f|----flag] must be followed by a path to file"
failureMessage = "[-f|--flag] must be followed by a path to file"
if err := a.parse(args0, 1); err == nil || err.Error() != failureMessage {
t.Errorf("Test %s failed with error: \"%s\". error: \"%s\" expected", t.Name(), err, failureMessage)
t.Errorf("Test %s failed with error: \"%v\". error: %q expected", t.Name(), err, failureMessage)
}
a.parsed = false
if err := a.parse(args2, 1); err == nil || err.Error() != failureMessageCommon {
t.Errorf("Test %s failed with error: \"%s\". error: \"%s\" expected", t.Name(), err, failureMessageCommon)
t.Errorf("Test %s failed with error: \"%v\". error: %q expected", t.Name(), err, failureMessageCommon)
}
a.parsed = false
}

func TestInternalFunctionCheck(t *testing.T) {
var resultS string
//test string
a := &arg{
result: &resultS,
sname: "f",
lname: "flag",
size: 0,
opts: nil,
unique: true,
}

srgString := "-f"
failureMessage := "Argument's size < 1 is not allowed"

if _, err := a.check(srgString); err == nil || err.Error() != failureMessage {
t.Errorf("Test %s failed with error: \"%v\". error: %q expected", t.Name(), err, failureMessage)
}
a.parsed = false
}

func TestFlagSimple1(t *testing.T) {
Expand Down Expand Up @@ -181,6 +218,68 @@ func TestFlagSimple2(t *testing.T) {
}
}

func TestFlagMultiShorthandWithParam1(t *testing.T) {
testArgs := []string{"progname", "-ab", "10", "-c", "-de", "11", "--ee", "12"}

testList := []int{11, 12}

p := NewParser("", "description")
flag1 := p.Flag("a", "aa", nil)
int2 := p.Int("b", "bb", nil)
flag3 := p.Flag("c", "cc", nil)
flag4 := p.Flag("d", "dd", nil)
intList5 := p.IntList("e", "ee", nil)
flag6 := p.Flag("f", "ff", nil)

err := p.Parse(testArgs)
if err != nil {
t.Errorf("Test %s failed with error: %s", t.Name(), err.Error())
return
}

if *flag1 != true {
t.Errorf("Test %s failed with flag1 being false", t.Name())
}

if *int2 != 10 {
t.Errorf("Test %s failed with *int2=%v being false", t.Name(), *int2)
}

if *flag3 != true {
t.Errorf("Test %s failed with flag3 being false", t.Name())
}

if *flag4 != true {
t.Errorf("Test %s failed with flag4 being false", t.Name())
}

if !reflect.DeepEqual(*intList5, testList) {
t.Errorf("Test %s failed: expected [%v], got [%v]", t.Name(), testList, *intList5)
}

if *flag6 != false {
t.Errorf("Test %s failed with flag6 being true", t.Name())
}
}

func TestFlagMultiShorthandWithParamFail1(t *testing.T) {
testArgs := []string{"progname", "-bab", "10"}

p := NewParser("", "description")
_ = p.Flag("a", "aa", nil)
_ = p.Int("b", "bb", nil)

err := p.Parse(testArgs)
if err == nil {
t.Errorf("Test %s failed with no error", t.Name())
return
}
errExpectation := "[-b|--bb] argument: The parameter must follow"
if err.Error() != errExpectation {
t.Errorf("Test %s failed. error %q getted. %q expected", t.Name(), err.Error(), errExpectation)
}
}

func TestFlagMultiShorthand1(t *testing.T) {
testArgs := []string{"progname", "-abcd", "-e"}

Expand Down
34 changes: 22 additions & 12 deletions argument.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,11 @@ func (o arg) GetLname() string {
type help struct{}

//Check if argumet present.
//For args with size 1 (Flag,FlagCounter) multiple shorthand in one argument are allowed,
//so check - returns the number of occurrences.
//For other args check - returns 1 if occured or 0 in no
func (o *arg) check(argument string) int {
//Check - returns the argumet's number of occurrences and error.
//For long name return value is 0 or 1.
//For shorthand argument - 0 if there is no occurrences, or count of occurrences.
//Shorthand argument with parametr, mast be the only or last in the argument string.
func (o *arg) check(argument string) (int, error) {
// Shortcut to showing help
if argument == "-h" || argument == "--help" {
helpText := o.parent.Help(nil)
Expand All @@ -59,27 +60,36 @@ func (o *arg) check(argument string) int {
// If argument begins with "--" and next is not "-" then it is a long name
if len(argument) > 2 && strings.HasPrefix(argument, "--") && argument[2] != '-' {
if argument[2:] == o.lname {
return 1
return 1, nil
}
}
}

// Check for short name only if not empty
if o.sname != "" {
// If argument begins with "-" and next is not "-" then it is a short name
if len(argument) > 1 && strings.HasPrefix(argument, "-") && argument[1] != '-' {
count := strings.Count(argument[1:], o.sname)
switch {
// For args with size 1 (Flag,FlagCounter) multiple shorthand in one argument are allowed
if o.size == 1 {
return strings.Count(argument[1:], o.sname)
// For all other types it must be separate argument
} else {
if argument[1:] == o.sname {
return 1
case o.size == 1:
return count, nil
// For args with o.size > 1, shorthand argument is allowed only to complete the sequence of arguments combined into one
case o.size > 1:
if count > 1 {
return count, fmt.Errorf("[%s] argument: The parameter must follow", o.name())
}
if strings.HasSuffix(argument[1:], o.sname) {
return count, nil
}
//if o.size < 1 - it is an error
default:
return 0, fmt.Errorf("Argument's size < 1 is not allowed")
}
}
}

return 0
return 0, nil
}

func (o *arg) reduce(position int, args *[]string) {
Expand Down
4 changes: 3 additions & 1 deletion command.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,9 @@ func (o *Command) parse(args *[]string) error {
if arg == "" {
continue
}
if cnt := oarg.check(arg); cnt > 0 {
if cnt, err := oarg.check(arg); err != nil {
return err
} else if cnt > 0 {
if len(*args) < j+oarg.size {
return fmt.Errorf("not enough arguments for %s", oarg.name())
}
Expand Down

0 comments on commit 543653f

Please sign in to comment.