From 791dd222c5a093dea560d76c87e3d35b220e750c Mon Sep 17 00:00:00 2001 From: Jay Date: Wed, 12 Feb 2020 09:39:46 +0000 Subject: [PATCH] add first version --- .drone.yml | 18 ++ argparse.go | 168 ++++++++++++ argparse_test.go | 541 ++++++++++++++++++++++++++++++++++++ argument.go | 174 ++++++++++++ argument_test.go | 700 +++++++++++++++++++++++++++++++++++++++++++++++ example/main.go | 37 +++ go.mod | 3 + go.sum | 0 8 files changed, 1641 insertions(+) create mode 100644 .drone.yml create mode 100644 argparse.go create mode 100644 argparse_test.go create mode 100644 argument.go create mode 100644 argument_test.go create mode 100644 example/main.go create mode 100644 go.mod create mode 100644 go.sum diff --git a/.drone.yml b/.drone.yml new file mode 100644 index 0000000..0f8493b --- /dev/null +++ b/.drone.yml @@ -0,0 +1,18 @@ +kind: pipeline +name: test-stable-version + +steps: + - name: test + image: golang:1 + commands: + - go test + +--- +kind: pipeline +name: test-rc-version + +steps: + - name: test + image: golang:rc + commands: + - go test diff --git a/argparse.go b/argparse.go new file mode 100644 index 0000000..eb8751d --- /dev/null +++ b/argparse.go @@ -0,0 +1,168 @@ +package argparse + +import ( + "errors" + "fmt" + "reflect" +) + +type Parser struct { + args []*arg + parsed bool +} + +type arg struct { + sname string + lname string + // value number count + size int + value interface{} + unique bool + parsed bool +} + +func New() *Parser { + return &Parser{ + args: make([]*arg, 0), + } +} + +func (p *Parser) addArg(a *arg) error { + for _, v := range p.args { + if (v.sname == a.sname || v.lname == a.lname) && (a.unique || v.unique) { + return errors.New("option name dup") + } + } + p.args = append(p.args, a) + + return nil +} + +func (p *Parser) typeVar(i interface{}, short, long string, size int, unique bool) { + t := reflect.ValueOf(i) + if t.Kind() != reflect.Ptr { + panic(errors.New("var type not ptr")) + } + + a := &arg{ + sname: short, + lname: long, + value: i, + size: size, + unique: unique, + } + + if err := p.addArg(a); err != nil { + panic(fmt.Errorf("unable to add String: %s\n", err)) + } +} + +func (p *Parser) Parse(a []string) error { + copyArg := make([]string, len(a)) + copy(copyArg, a) + + err := p.parse(©Arg) + if err != nil { + return err + } + + return nil +} + +// in loop func +func (p *Parser) parse(args *[]string) error { + if p.parsed { + return nil + } + if len(*args) < 1 { + return nil + } + + err := p.parseArguemtns(args) + if err != nil { + return err + } + + p.parsed = true + return nil +} + +func (p *Parser) parseArguemtns(args *[]string) error { + n := len(p.args) + + for i := 0; i < n; i++ { + nn := len(*args) + oarg := p.args[i] + + for j := 0; j < nn; j++ { + s := (*args)[j] + if s == "" { + continue + } + ct, err := oarg.check(s) + if err != nil { + return err + } + if ct > 0 { + valpos := j + 1 + if len(*args) < valpos+oarg.size { + return fmt.Errorf("no enough arguments for %s", oarg.name()) + } + err := oarg.parse((*args)[valpos : valpos+oarg.size]) + if err != nil { + return err + } + + oarg.reduce(j, args) + continue + } + } + + } + + return nil +} + +func (p *Parser) String(short, long string) *string { + var result string + + p.typeVar(&result, short, long, 1, true) + + return &result +} +func (p *Parser) StringVar(i *string, short, long string) { + p.typeVar(i, short, long, 1, true) +} + +func (p *Parser) Int(short, long string) *int { + var result int + + p.typeVar(&result, short, long, 1, true) + + return &result +} +func (p *Parser) IntVar(i *int, short, long string) { + p.typeVar(i, short, long, 1, true) +} + +func (p *Parser) Bool(short, long string) *bool { + var result bool + + p.typeVar(&result, short, long, 0, true) + + return &result +} +func (p *Parser) BoolVar(i *bool, short, long string) { + p.typeVar(i, short, long, 0, true) +} + +func (p *Parser) Float(short, long string) *float64 { + var result float64 + + p.typeVar(&result, short, long, 1, true) + + return &result +} +func (p *Parser) FloatVar(i *float64, short, long string) { + p.typeVar(i, short, long, 1, true) +} diff --git a/argparse_test.go b/argparse_test.go new file mode 100644 index 0000000..ce77691 --- /dev/null +++ b/argparse_test.go @@ -0,0 +1,541 @@ +package argparse + +import ( + "reflect" + "testing" +) + +func TestNew(t *testing.T) { + tests := []struct { + name string + want *Parser + }{ + { + name: "test new parser", + want: &Parser{args: make([]*arg, 0)}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := New(); !reflect.DeepEqual(got, tt.want) { + t.Errorf("New() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestParser_addArg(t *testing.T) { + type fields struct { + args []*arg + parsed bool + } + type args struct { + a *arg + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + name: "test addArg to parser", + fields: fields{ + args: nil, + parsed: false, + }, + args: args{ + a: &arg{sname: "a"}, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &Parser{ + args: tt.fields.args, + parsed: tt.fields.parsed, + } + if err := p.addArg(tt.args.a); (err != nil) != tt.wantErr { + t.Errorf("Parser.addArg() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestParser_typeVar(t *testing.T) { + var s string + type fields struct { + args []*arg + parsed bool + } + type args struct { + i interface{} + short string + long string + size int + unique bool + } + tests := []struct { + name string + fields fields + args args + }{ + { + name: "test parser typeVar func", + fields: fields{}, + args: args{ + i: &s, + short: "s", + long: "string", + size: 1, + unique: true, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &Parser{ + args: tt.fields.args, + parsed: tt.fields.parsed, + } + p.typeVar(tt.args.i, tt.args.short, tt.args.long, tt.args.size, tt.args.unique) + }) + } +} + +func TestParser_Parse(t *testing.T) { + var conf string + var port int + type fields struct { + args []*arg + parsed bool + } + type args struct { + a []string + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + name: "test parser run Parse", + fields: fields{ + args: []*arg{ + &arg{ + sname: "c", + size: 1, + unique: true, + value: &conf, + }, + &arg{ + sname: "p", + size: 1, + unique: true, + value: &port, + }, + }, + }, + args: args{ + a: []string{ + "-c", "/root/config.ini", + "-p", "3000", + }, + }, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &Parser{ + args: tt.fields.args, + parsed: tt.fields.parsed, + } + if err := p.Parse(tt.args.a); (err != nil) != tt.wantErr { + t.Errorf("Parser.Parse() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestParser_parse(t *testing.T) { + var conf string + type fields struct { + args []*arg + parsed bool + } + type args struct { + args *[]string + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + name: "test parser parse func", + fields: fields{ + args: []*arg{ + &arg{ + sname: "c", + size: 1, + unique: true, + value: &conf, + }, + }, + }, + args: args{args: &[]string{"-c", "/config.yml"}}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &Parser{ + args: tt.fields.args, + parsed: tt.fields.parsed, + } + if err := p.parse(tt.args.args); (err != nil) != tt.wantErr { + t.Errorf("Parser.parse() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestParser_parseArguemtns(t *testing.T) { + var conf string + type fields struct { + args []*arg + parsed bool + } + type args struct { + args *[]string + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + name: "test parser parseArguments", + fields: fields{ + args: []*arg{ + &arg{ + sname: "c", + size: 1, + unique: true, + value: &conf, + }, + }, + }, + args: args{args: &[]string{"-vv"}}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &Parser{ + args: tt.fields.args, + parsed: tt.fields.parsed, + } + if err := p.parseArguemtns(tt.args.args); (err != nil) != tt.wantErr { + t.Errorf("Parser.parseArguemtns() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestParser_String(t *testing.T) { + type fields struct { + args []*arg + parsed bool + } + type args struct { + short string + long string + } + tests := []struct { + name string + fields fields + args args + }{ + { + name: "test add string flag to parser", + fields: fields{}, + args: args{ + short: "c", + long: "", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &Parser{ + args: tt.fields.args, + parsed: tt.fields.parsed, + } + if got := p.String(tt.args.short, tt.args.long); got == nil { + t.Errorf("Parser.String() = %v", got) + } + }) + } +} + +func TestParser_StringVar(t *testing.T) { + var s string + type fields struct { + args []*arg + parsed bool + } + type args struct { + i *string + short string + long string + } + tests := []struct { + name string + fields fields + args args + }{ + { + name: "test add string flag to parser with ptr", + fields: fields{}, + args: args{ + i: &s, + short: "s", + long: "", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &Parser{ + args: tt.fields.args, + parsed: tt.fields.parsed, + } + p.StringVar(tt.args.i, tt.args.short, tt.args.long) + }) + } +} + +func TestParser_Int(t *testing.T) { + type fields struct { + args []*arg + parsed bool + } + type args struct { + short string + long string + } + tests := []struct { + name string + fields fields + args args + }{ + { + name: "test add int flag to parser", + fields: fields{}, + args: args{ + short: "i", + long: "", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &Parser{ + args: tt.fields.args, + parsed: tt.fields.parsed, + } + if got := p.Int(tt.args.short, tt.args.long); got == nil { + t.Errorf("Parser.Int() = %v", got) + } + }) + } +} + +func TestParser_IntVar(t *testing.T) { + var i int + type fields struct { + args []*arg + parsed bool + } + type args struct { + i *int + short string + long string + } + tests := []struct { + name string + fields fields + args args + }{ + { + name: "test add int flag to parser (ptr)", + fields: fields{}, + args: args{ + i: &i, + short: "i", + long: "", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &Parser{ + args: tt.fields.args, + parsed: tt.fields.parsed, + } + p.IntVar(tt.args.i, tt.args.short, tt.args.long) + }) + } +} + +func TestParser_Bool(t *testing.T) { + type fields struct { + args []*arg + parsed bool + } + type args struct { + short string + long string + } + tests := []struct { + name string + fields fields + args args + }{ + { + name: "test add bool flag to parser", + fields: fields{}, + args: args{ + short: "b", + long: "", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &Parser{ + args: tt.fields.args, + parsed: tt.fields.parsed, + } + if got := p.Bool(tt.args.short, tt.args.long); got == nil { + t.Errorf("Parser.Bool() = %v", got) + } + }) + } +} + +func TestParser_BoolVar(t *testing.T) { + var b bool + type fields struct { + args []*arg + parsed bool + } + type args struct { + i *bool + short string + long string + } + tests := []struct { + name string + fields fields + args args + }{ + { + name: "test add bool flag to parser (ptr)", + fields: fields{}, + args: args{ + i: &b, + short: "b", + long: "", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &Parser{ + args: tt.fields.args, + parsed: tt.fields.parsed, + } + p.BoolVar(tt.args.i, tt.args.short, tt.args.long) + }) + } +} + +func TestParser_Float(t *testing.T) { + type fields struct { + args []*arg + parsed bool + } + type args struct { + short string + long string + } + tests := []struct { + name string + fields fields + args args + }{ + { + name: "test add float flag to parser", + fields: fields{}, + args: args{ + short: "f", + long: "", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &Parser{ + args: tt.fields.args, + parsed: tt.fields.parsed, + } + if got := p.Float(tt.args.short, tt.args.long); got == nil { + t.Errorf("Parser.Float() = %v", got) + } + }) + } +} + +func TestParser_FloatVar(t *testing.T) { + var f float64 + type fields struct { + args []*arg + parsed bool + } + type args struct { + i *float64 + short string + long string + } + tests := []struct { + name string + fields fields + args args + }{ + { + name: "test add float flag to parser (ptr)", + fields: fields{}, + args: args{ + i: &f, + short: "f", + long: "", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + p := &Parser{ + args: tt.fields.args, + parsed: tt.fields.parsed, + } + p.FloatVar(tt.args.i, tt.args.short, tt.args.long) + }) + } +} diff --git a/argument.go b/argument.go new file mode 100644 index 0000000..2c9ea18 --- /dev/null +++ b/argument.go @@ -0,0 +1,174 @@ +package argparse + +import ( + "errors" + "fmt" + "strconv" + "strings" +) + +var ( + ErrArgTooMany = errors.New("arg too manu") + ErrNoArg = errors.New("no arg") +) + +func (a *arg) check(s string) (count int, err error) { + res := a.checkLongName(s) + if res > 0 { + return res, nil + } + return a.checkShortName(s) +} + +func (a *arg) checkLongName(s string) int { + if a.lname != "" { + if len(s) > 2 && strings.HasPrefix(s, "--") && s[2] != '-' { + if s[2:] == a.lname { + return 1 + } + } + } + return 0 +} + +func (a *arg) checkShortName(s string) (int, error) { + if a.sname != "" { + if len(s) > 1 && strings.HasPrefix(s, "-") && s[1] != '-' { + if s[1:] == a.sname { + return 1, nil + } + } + } + return 0, nil +} + +func (a *arg) reduce(pos int, args *[]string) { + a.reduceLongName(pos, args) + a.reduceShortName(pos, args) +} + +func (a *arg) reduceLongName(pos int, args *[]string) { + s := (*args)[pos] + if a.lname == "" { + return + } + + if res := a.checkLongName(s); res == 0 { + return + } + + for i := pos; i <= pos+a.size; i++ { + (*args)[i] = "" + } +} + +func (a *arg) reduceShortName(pos int, args *[]string) { + s := (*args)[pos] + if a.sname == "" { + return + } + + if res, err := a.checkShortName(s); res == 0 || err != nil { + return + } + + for i := pos; i <= pos+a.size; i++ { + (*args)[i] = "" + } +} + +func (a *arg) name() string { + if a.sname == "" { + return fmt.Sprintf("--%s", a.lname) + } else if a.lname == "" { + return fmt.Sprintf("-%s", a.sname) + } else { + return fmt.Sprintf("-%s|--%s", a.sname, a.lname) + } +} + +func (a *arg) parse(args []string) error { + if a.unique && a.parsed { + return fmt.Errorf("[%s] can only parsent once\n", a.name()) + } + return a.parseType(args) +} + +func (a *arg) parseType(args []string) error { + var err error + switch a.value.(type) { + case *string: + return a.parseString(args) + case *int: + return a.parseInt(args) + case *bool: + return a.parseBool(args) + case *float64: + return a.parseFloat(args) + case *[]string: + case *[]int: + case *[]float64: + default: + err = fmt.Errorf("unsupport type [%t]", a.value) + } + return err +} + +func (a *arg) parseString(args []string) error { + var err error + + if len(args) > 1 { + return ErrArgTooMany + } + if len(args) == 0 { + return ErrNoArg + } + + *((a.value).(*string)) = args[0] + a.parsed = true + + return err +} + +func (a *arg) parseInt(args []string) error { + var err error + + if len(args) > 1 { + return ErrArgTooMany + } + if len(args) == 0 { + return ErrNoArg + } + + if i, err := strconv.Atoi(args[0]); err == nil { + *((a.value).(*int)) = i + a.parsed = true + } else { + return fmt.Errorf("[%s] bad int value", a.name()) + } + + return err +} + +func (a *arg) parseBool(args []string) error { + *a.value.(*bool) = true + a.parsed = true + return nil +} + +func (a *arg) parseFloat(args []string) (err error) { + if len(args) > 1 { + return ErrArgTooMany + } + if len(args) == 0 { + return ErrNoArg + } + + if f, err := strconv.ParseFloat(args[0], 64); err == nil { + *a.value.(*float64) = f + a.parsed = true + } else { + return fmt.Errorf("[%s] bad float value", a.name()) + } + return +} diff --git a/argument_test.go b/argument_test.go new file mode 100644 index 0000000..3129712 --- /dev/null +++ b/argument_test.go @@ -0,0 +1,700 @@ +package argparse + +import "testing" + +func Test_arg_check(t *testing.T) { + type fields struct { + sname string + lname string + size int + value interface{} + unique bool + parsed bool + } + type args struct { + s string + } + tests := []struct { + name string + fields fields + args args + wantCount int + wantErr bool + }{ + { + name: "test argument check arg with short name", + fields: fields{sname: "d", size: 1}, + args: args{s: "-d"}, + wantCount: 1, + wantErr: false, + }, + { + name: "test argument check arg with long name", + fields: fields{lname: "dir", size: 1}, + args: args{s: "--dir"}, + wantCount: 1, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &arg{ + sname: tt.fields.sname, + lname: tt.fields.lname, + size: tt.fields.size, + value: tt.fields.value, + unique: tt.fields.unique, + parsed: tt.fields.parsed, + } + gotCount, err := a.check(tt.args.s) + if (err != nil) != tt.wantErr { + t.Errorf("arg.check() error = %v, wantErr %v", err, tt.wantErr) + return + } + if gotCount != tt.wantCount { + t.Errorf("arg.check() = %v, want %v", gotCount, tt.wantCount) + } + }) + } +} + +func Test_arg_checkLongName(t *testing.T) { + type fields struct { + sname string + lname string + size int + value interface{} + unique bool + parsed bool + } + type args struct { + s string + } + tests := []struct { + name string + fields fields + args args + want int + }{ + { + name: "test argument check long name", + fields: fields{ + lname: "dir", + size: 1, + }, + args: args{ + s: "--dir", + }, + want: 1, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &arg{ + sname: tt.fields.sname, + lname: tt.fields.lname, + size: tt.fields.size, + value: tt.fields.value, + unique: tt.fields.unique, + parsed: tt.fields.parsed, + } + if got := a.checkLongName(tt.args.s); got != tt.want { + t.Errorf("arg.checkLongName() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_arg_checkShortName(t *testing.T) { + type fields struct { + sname string + lname string + size int + value interface{} + unique bool + parsed bool + } + type args struct { + s string + } + tests := []struct { + name string + fields fields + args args + want int + wantErr bool + }{ + { + name: "test argument check short name", + fields: fields{ + sname: "d", + size: 1, + }, + args: args{s: "-d"}, + want: 1, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &arg{ + sname: tt.fields.sname, + lname: tt.fields.lname, + size: tt.fields.size, + value: tt.fields.value, + unique: tt.fields.unique, + parsed: tt.fields.parsed, + } + got, err := a.checkShortName(tt.args.s) + if (err != nil) != tt.wantErr { + t.Errorf("arg.checkShortName() error = %v, wantErr %v", err, tt.wantErr) + return + } + if got != tt.want { + t.Errorf("arg.checkShortName() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_arg_reduce(t *testing.T) { + a0 := []string{"-d"} + a1 := []string{"--dir"} + type fields struct { + sname string + lname string + size int + value interface{} + unique bool + parsed bool + } + type args struct { + pos int + args *[]string + } + tests := []struct { + name string + fields fields + args args + }{ + { + name: "test argument reduce with short name", + fields: fields{ + sname: "d", + size: 0, + unique: true, + }, + args: args{ + pos: 0, + args: &a0, + }, + }, + { + name: "test argument reduce with long name", + fields: fields{ + lname: "dir", + size: 0, + unique: true, + }, + args: args{ + pos: 0, + args: &a1, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &arg{ + sname: tt.fields.sname, + lname: tt.fields.lname, + size: tt.fields.size, + value: tt.fields.value, + unique: tt.fields.unique, + parsed: tt.fields.parsed, + } + a.reduce(tt.args.pos, tt.args.args) + if (*tt.args.args)[0] != "" { + t.Errorf("arg reduce failed") + } + }) + } +} + +func Test_arg_reduceLongName(t *testing.T) { + a0 := []string{"--dir"} + a1 := []string{"--file", "/config.yml"} + type fields struct { + sname string + lname string + size int + value interface{} + unique bool + parsed bool + } + type args struct { + pos int + args *[]string + } + tests := []struct { + name string + fields fields + args args + }{ + { + name: "test argument reduce long name 1", + fields: fields{ + lname: "dir", + size: 0, + }, + args: args{ + pos: 0, + args: &a0, + }, + }, + { + name: "test argument redue long name 2", + fields: fields{ + lname: "file", + size: 1, + }, + args: args{ + pos: 0, + args: &a1, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &arg{ + sname: tt.fields.sname, + lname: tt.fields.lname, + size: tt.fields.size, + value: tt.fields.value, + unique: tt.fields.unique, + parsed: tt.fields.parsed, + } + a.reduceLongName(tt.args.pos, tt.args.args) + for i := tt.args.pos; i < tt.args.pos+tt.fields.size; i++ { + if (*tt.args.args)[i] != "" { + t.Errorf("arg reduce fail") + } + } + }) + } +} + +func Test_arg_reduceShortName(t *testing.T) { + a0 := []string{"-d"} + a1 := []string{"-f", "/config.yml"} + type fields struct { + sname string + lname string + size int + value interface{} + unique bool + parsed bool + } + type args struct { + pos int + args *[]string + } + tests := []struct { + name string + fields fields + args args + }{ + { + name: "test argument reduce short name 1", + fields: fields{ + sname: "d", + size: 0, + }, + args: args{ + pos: 0, + args: &a0, + }, + }, + { + name: "test argument reduce short name 2", + fields: fields{ + sname: "f", + size: 1, + }, + args: args{ + pos: 0, + args: &a1, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &arg{ + sname: tt.fields.sname, + lname: tt.fields.lname, + size: tt.fields.size, + value: tt.fields.value, + unique: tt.fields.unique, + parsed: tt.fields.parsed, + } + a.reduceShortName(tt.args.pos, tt.args.args) + for i := tt.args.pos; i < tt.args.pos+tt.fields.size; i++ { + if (*tt.args.args)[i] != "" { + t.Errorf("arg reduce fail") + } + } + }) + } +} + +func Test_arg_name(t *testing.T) { + type fields struct { + sname string + lname string + size int + value interface{} + unique bool + parsed bool + } + tests := []struct { + name string + fields fields + want string + }{ + { + name: "test argument get name 1", + fields: fields{ + sname: "d", + }, + want: "-d", + }, + { + name: "test argument get name 2", + fields: fields{ + lname: "dir", + }, + want: "--dir", + }, + { + name: "test argument get name 3", + fields: fields{ + sname: "d", + lname: "dir", + }, + want: "-d|--dir", + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &arg{ + sname: tt.fields.sname, + lname: tt.fields.lname, + size: tt.fields.size, + value: tt.fields.value, + unique: tt.fields.unique, + parsed: tt.fields.parsed, + } + if got := a.name(); got != tt.want { + t.Errorf("arg.name() = %v, want %v", got, tt.want) + } + }) + } +} + +func Test_arg_parse(t *testing.T) { + var b bool + var s string + type fields struct { + sname string + lname string + size int + value interface{} + unique bool + parsed bool + } + type args struct { + args []string + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + name: "test argument parse 1", + fields: fields{ + sname: "d", + size: 0, + value: &b, + unique: true, + }, + args: args{ + args: []string{}, + }, + wantErr: false, + }, + { + name: "test argument parse 2", + fields: fields{ + sname: "f", + size: 1, + unique: true, + value: &s, + }, + args: args{args: []string{"/config.yml"}}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &arg{ + sname: tt.fields.sname, + lname: tt.fields.lname, + size: tt.fields.size, + value: tt.fields.value, + unique: tt.fields.unique, + parsed: tt.fields.parsed, + } + if err := a.parse(tt.args.args); (err != nil) != tt.wantErr { + t.Errorf("arg.parse() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func Test_arg_parseType(t *testing.T) { + var s string + type fields struct { + sname string + lname string + size int + value interface{} + unique bool + parsed bool + } + type args struct { + args []string + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + name: "test argument parseType 1", + fields: fields{ + sname: "f", + value: &s, + size: 1, + unique: true, + }, + args: args{args: []string{"/config.yml"}}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &arg{ + sname: tt.fields.sname, + lname: tt.fields.lname, + size: tt.fields.size, + value: tt.fields.value, + unique: tt.fields.unique, + parsed: tt.fields.parsed, + } + if err := a.parseType(tt.args.args); (err != nil) != tt.wantErr { + t.Errorf("arg.parseType() error = %v, wantErr %v", err, tt.wantErr) + } + if s != (tt.args.args)[0] { + t.Errorf("arg.parseType() string = %s, wantErr %s", s, (tt.args.args)[0]) + } + }) + } +} + +func Test_arg_parseString(t *testing.T) { + var s string + type fields struct { + sname string + lname string + size int + value interface{} + unique bool + parsed bool + } + type args struct { + args []string + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + name: "test argument parseString", + fields: fields{ + value: &s, + unique: true, + size: 1, + }, + args: args{args: []string{"value"}}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &arg{ + sname: tt.fields.sname, + lname: tt.fields.lname, + size: tt.fields.size, + value: tt.fields.value, + unique: tt.fields.unique, + parsed: tt.fields.parsed, + } + if err := a.parseString(tt.args.args); (err != nil) != tt.wantErr { + t.Errorf("arg.parseString() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func Test_arg_parseInt(t *testing.T) { + var i int + type fields struct { + sname string + lname string + size int + value interface{} + unique bool + parsed bool + } + type args struct { + args []string + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + name: "test argument parseInt", + fields: fields{ + value: &i, + size: 1, + unique: true, + }, + args: args{args: []string{"123"}}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &arg{ + sname: tt.fields.sname, + lname: tt.fields.lname, + size: tt.fields.size, + value: tt.fields.value, + unique: tt.fields.unique, + parsed: tt.fields.parsed, + } + if err := a.parseInt(tt.args.args); (err != nil) != tt.wantErr { + t.Errorf("arg.parseInt() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func Test_arg_parseBool(t *testing.T) { + var b bool + type fields struct { + sname string + lname string + size int + value interface{} + unique bool + parsed bool + } + type args struct { + args []string + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + name: "test argument parseBool", + fields: fields{ + value: &b, + unique: true, + }, + args: args{}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &arg{ + sname: tt.fields.sname, + lname: tt.fields.lname, + size: tt.fields.size, + value: tt.fields.value, + unique: tt.fields.unique, + parsed: tt.fields.parsed, + } + if err := a.parseBool(tt.args.args); (err != nil) != tt.wantErr { + t.Errorf("arg.parseBool() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func Test_arg_parseFloat(t *testing.T) { + var f float64 + type fields struct { + sname string + lname string + size int + value interface{} + unique bool + parsed bool + } + type args struct { + args []string + } + tests := []struct { + name string + fields fields + args args + wantErr bool + }{ + { + name: "test argument parseFloat", + fields: fields{ + value: &f, + unique: true, + }, + args: args{args: []string{"1.23"}}, + wantErr: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + a := &arg{ + sname: tt.fields.sname, + lname: tt.fields.lname, + size: tt.fields.size, + value: tt.fields.value, + unique: tt.fields.unique, + parsed: tt.fields.parsed, + } + if err := a.parseFloat(tt.args.args); (err != nil) != tt.wantErr { + t.Errorf("arg.parseFloat() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/example/main.go b/example/main.go new file mode 100644 index 0000000..834df6b --- /dev/null +++ b/example/main.go @@ -0,0 +1,37 @@ +package main + +import ( + "fmt" + + "git.trj.tw/golang/argparse" +) + +func main() { + fmt.Println("argparse example") + opts := []string{ + "-f", "/config.yml", + "-v", + "--port", "3000", + "--float", "1.23", + "-n", "name!!", + } + + p := argparse.New() + + var configPath string + var versionFlag bool + var port int + var floatVal float64 + var name *string + + p.BoolVar(&versionFlag, "v", "version") + p.StringVar(&configPath, "f", "config") + p.IntVar(&port, "p", "port") + p.FloatVar(&floatVal, "ff", "float") + + name = p.String("n", "name") + + p.Parse(opts) + + fmt.Printf("Config: %s\nVersionFlag: %v\nPort: %d\nFloatVal: %f\nName: %s\n", configPath, versionFlag, port, floatVal, *name) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..cd955b1 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module git.trj.tw/golang/argparse + +go 1.13 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..e69de29