Skip to content

Commit 9722382

Browse files
Cyberaxeparis
authored andcommitted
Added String-To-Int64 option parsing (#211)
1 parent 6d93a82 commit 9722382

File tree

2 files changed

+305
-0
lines changed

2 files changed

+305
-0
lines changed

string_to_int64.go

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
package pflag
2+
3+
import (
4+
"bytes"
5+
"fmt"
6+
"strconv"
7+
"strings"
8+
)
9+
10+
// -- stringToInt64 Value
11+
type stringToInt64Value struct {
12+
value *map[string]int64
13+
changed bool
14+
}
15+
16+
func newStringToInt64Value(val map[string]int64, p *map[string]int64) *stringToInt64Value {
17+
ssv := new(stringToInt64Value)
18+
ssv.value = p
19+
*ssv.value = val
20+
return ssv
21+
}
22+
23+
// Format: a=1,b=2
24+
func (s *stringToInt64Value) Set(val string) error {
25+
ss := strings.Split(val, ",")
26+
out := make(map[string]int64, len(ss))
27+
for _, pair := range ss {
28+
kv := strings.SplitN(pair, "=", 2)
29+
if len(kv) != 2 {
30+
return fmt.Errorf("%s must be formatted as key=value", pair)
31+
}
32+
var err error
33+
out[kv[0]], err = strconv.ParseInt(kv[1], 10, 64)
34+
if err != nil {
35+
return err
36+
}
37+
}
38+
if !s.changed {
39+
*s.value = out
40+
} else {
41+
for k, v := range out {
42+
(*s.value)[k] = v
43+
}
44+
}
45+
s.changed = true
46+
return nil
47+
}
48+
49+
func (s *stringToInt64Value) Type() string {
50+
return "stringToInt64"
51+
}
52+
53+
func (s *stringToInt64Value) String() string {
54+
var buf bytes.Buffer
55+
i := 0
56+
for k, v := range *s.value {
57+
if i > 0 {
58+
buf.WriteRune(',')
59+
}
60+
buf.WriteString(k)
61+
buf.WriteRune('=')
62+
buf.WriteString(strconv.FormatInt(v, 10))
63+
i++
64+
}
65+
return "[" + buf.String() + "]"
66+
}
67+
68+
func stringToInt64Conv(val string) (interface{}, error) {
69+
val = strings.Trim(val, "[]")
70+
// An empty string would cause an empty map
71+
if len(val) == 0 {
72+
return map[string]int64{}, nil
73+
}
74+
ss := strings.Split(val, ",")
75+
out := make(map[string]int64, len(ss))
76+
for _, pair := range ss {
77+
kv := strings.SplitN(pair, "=", 2)
78+
if len(kv) != 2 {
79+
return nil, fmt.Errorf("%s must be formatted as key=value", pair)
80+
}
81+
var err error
82+
out[kv[0]], err = strconv.ParseInt(kv[1], 10, 64)
83+
if err != nil {
84+
return nil, err
85+
}
86+
}
87+
return out, nil
88+
}
89+
90+
// GetStringToInt64 return the map[string]int64 value of a flag with the given name
91+
func (f *FlagSet) GetStringToInt64(name string) (map[string]int64, error) {
92+
val, err := f.getFlagType(name, "stringToInt64", stringToInt64Conv)
93+
if err != nil {
94+
return map[string]int64{}, err
95+
}
96+
return val.(map[string]int64), nil
97+
}
98+
99+
// StringToInt64Var defines a string flag with specified name, default value, and usage string.
100+
// The argument p point64s to a map[string]int64 variable in which to store the values of the multiple flags.
101+
// The value of each argument will not try to be separated by comma
102+
func (f *FlagSet) StringToInt64Var(p *map[string]int64, name string, value map[string]int64, usage string) {
103+
f.VarP(newStringToInt64Value(value, p), name, "", usage)
104+
}
105+
106+
// StringToInt64VarP is like StringToInt64Var, but accepts a shorthand letter that can be used after a single dash.
107+
func (f *FlagSet) StringToInt64VarP(p *map[string]int64, name, shorthand string, value map[string]int64, usage string) {
108+
f.VarP(newStringToInt64Value(value, p), name, shorthand, usage)
109+
}
110+
111+
// StringToInt64Var defines a string flag with specified name, default value, and usage string.
112+
// The argument p point64s to a map[string]int64 variable in which to store the value of the flag.
113+
// The value of each argument will not try to be separated by comma
114+
func StringToInt64Var(p *map[string]int64, name string, value map[string]int64, usage string) {
115+
CommandLine.VarP(newStringToInt64Value(value, p), name, "", usage)
116+
}
117+
118+
// StringToInt64VarP is like StringToInt64Var, but accepts a shorthand letter that can be used after a single dash.
119+
func StringToInt64VarP(p *map[string]int64, name, shorthand string, value map[string]int64, usage string) {
120+
CommandLine.VarP(newStringToInt64Value(value, p), name, shorthand, usage)
121+
}
122+
123+
// StringToInt64 defines a string flag with specified name, default value, and usage string.
124+
// The return value is the address of a map[string]int64 variable that stores the value of the flag.
125+
// The value of each argument will not try to be separated by comma
126+
func (f *FlagSet) StringToInt64(name string, value map[string]int64, usage string) *map[string]int64 {
127+
p := map[string]int64{}
128+
f.StringToInt64VarP(&p, name, "", value, usage)
129+
return &p
130+
}
131+
132+
// StringToInt64P is like StringToInt64, but accepts a shorthand letter that can be used after a single dash.
133+
func (f *FlagSet) StringToInt64P(name, shorthand string, value map[string]int64, usage string) *map[string]int64 {
134+
p := map[string]int64{}
135+
f.StringToInt64VarP(&p, name, shorthand, value, usage)
136+
return &p
137+
}
138+
139+
// StringToInt64 defines a string flag with specified name, default value, and usage string.
140+
// The return value is the address of a map[string]int64 variable that stores the value of the flag.
141+
// The value of each argument will not try to be separated by comma
142+
func StringToInt64(name string, value map[string]int64, usage string) *map[string]int64 {
143+
return CommandLine.StringToInt64P(name, "", value, usage)
144+
}
145+
146+
// StringToInt64P is like StringToInt64, but accepts a shorthand letter that can be used after a single dash.
147+
func StringToInt64P(name, shorthand string, value map[string]int64, usage string) *map[string]int64 {
148+
return CommandLine.StringToInt64P(name, shorthand, value, usage)
149+
}

string_to_int64_test.go

Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
// Copyright 2009 The Go Authors. All rights reserved.
2+
// Use of ths2i source code s2i governed by a BSD-style
3+
// license that can be found in the LICENSE file.
4+
5+
package pflag
6+
7+
import (
8+
"bytes"
9+
"fmt"
10+
"strconv"
11+
"testing"
12+
)
13+
14+
func setUpS2I64FlagSet(s2ip *map[string]int64) *FlagSet {
15+
f := NewFlagSet("test", ContinueOnError)
16+
f.StringToInt64Var(s2ip, "s2i", map[string]int64{}, "Command separated ls2it!")
17+
return f
18+
}
19+
20+
func setUpS2I64FlagSetWithDefault(s2ip *map[string]int64) *FlagSet {
21+
f := NewFlagSet("test", ContinueOnError)
22+
f.StringToInt64Var(s2ip, "s2i", map[string]int64{"a": 1, "b": 2}, "Command separated ls2it!")
23+
return f
24+
}
25+
26+
func createS2I64Flag(vals map[string]int64) string {
27+
var buf bytes.Buffer
28+
i := 0
29+
for k, v := range vals {
30+
if i > 0 {
31+
buf.WriteRune(',')
32+
}
33+
buf.WriteString(k)
34+
buf.WriteRune('=')
35+
buf.WriteString(strconv.FormatInt(v, 10))
36+
i++
37+
}
38+
return buf.String()
39+
}
40+
41+
func TestEmptyS2I64(t *testing.T) {
42+
var s2i map[string]int64
43+
f := setUpS2I64FlagSet(&s2i)
44+
err := f.Parse([]string{})
45+
if err != nil {
46+
t.Fatal("expected no error; got", err)
47+
}
48+
49+
getS2I, err := f.GetStringToInt64("s2i")
50+
if err != nil {
51+
t.Fatal("got an error from GetStringToInt64():", err)
52+
}
53+
if len(getS2I) != 0 {
54+
t.Fatalf("got s2i %v with len=%d but expected length=0", getS2I, len(getS2I))
55+
}
56+
}
57+
58+
func TestS2I64(t *testing.T) {
59+
var s2i map[string]int64
60+
f := setUpS2I64FlagSet(&s2i)
61+
62+
vals := map[string]int64{"a": 1, "b": 2, "d": 4, "c": 3}
63+
arg := fmt.Sprintf("--s2i=%s", createS2I64Flag(vals))
64+
err := f.Parse([]string{arg})
65+
if err != nil {
66+
t.Fatal("expected no error; got", err)
67+
}
68+
for k, v := range s2i {
69+
if vals[k] != v {
70+
t.Fatalf("expected s2i[%s] to be %d but got: %d", k, vals[k], v)
71+
}
72+
}
73+
getS2I, err := f.GetStringToInt64("s2i")
74+
if err != nil {
75+
t.Fatalf("got error: %v", err)
76+
}
77+
for k, v := range getS2I {
78+
if vals[k] != v {
79+
t.Fatalf("expected s2i[%s] to be %d but got: %d from GetStringToInt64", k, vals[k], v)
80+
}
81+
}
82+
}
83+
84+
func TestS2I64Default(t *testing.T) {
85+
var s2i map[string]int64
86+
f := setUpS2I64FlagSetWithDefault(&s2i)
87+
88+
vals := map[string]int64{"a": 1, "b": 2}
89+
90+
err := f.Parse([]string{})
91+
if err != nil {
92+
t.Fatal("expected no error; got", err)
93+
}
94+
for k, v := range s2i {
95+
if vals[k] != v {
96+
t.Fatalf("expected s2i[%s] to be %d but got: %d", k, vals[k], v)
97+
}
98+
}
99+
100+
getS2I, err := f.GetStringToInt64("s2i")
101+
if err != nil {
102+
t.Fatal("got an error from GetStringToInt64():", err)
103+
}
104+
for k, v := range getS2I {
105+
if vals[k] != v {
106+
t.Fatalf("expected s2i[%s] to be %d from GetStringToInt64 but got: %d", k, vals[k], v)
107+
}
108+
}
109+
}
110+
111+
func TestS2I64WithDefault(t *testing.T) {
112+
var s2i map[string]int64
113+
f := setUpS2I64FlagSetWithDefault(&s2i)
114+
115+
vals := map[string]int64{"a": 1, "b": 2}
116+
arg := fmt.Sprintf("--s2i=%s", createS2I64Flag(vals))
117+
err := f.Parse([]string{arg})
118+
if err != nil {
119+
t.Fatal("expected no error; got", err)
120+
}
121+
for k, v := range s2i {
122+
if vals[k] != v {
123+
t.Fatalf("expected s2i[%s] to be %d but got: %d", k, vals[k], v)
124+
}
125+
}
126+
127+
getS2I, err := f.GetStringToInt64("s2i")
128+
if err != nil {
129+
t.Fatal("got an error from GetStringToInt64():", err)
130+
}
131+
for k, v := range getS2I {
132+
if vals[k] != v {
133+
t.Fatalf("expected s2i[%s] to be %d from GetStringToInt64 but got: %d", k, vals[k], v)
134+
}
135+
}
136+
}
137+
138+
func TestS2I64CalledTwice(t *testing.T) {
139+
var s2i map[string]int64
140+
f := setUpS2I64FlagSet(&s2i)
141+
142+
in := []string{"a=1,b=2", "b=3"}
143+
expected := map[string]int64{"a": 1, "b": 3}
144+
argfmt := "--s2i=%s"
145+
arg1 := fmt.Sprintf(argfmt, in[0])
146+
arg2 := fmt.Sprintf(argfmt, in[1])
147+
err := f.Parse([]string{arg1, arg2})
148+
if err != nil {
149+
t.Fatal("expected no error; got", err)
150+
}
151+
for i, v := range s2i {
152+
if expected[i] != v {
153+
t.Fatalf("expected s2i[%s] to be %d but got: %d", i, expected[i], v)
154+
}
155+
}
156+
}

0 commit comments

Comments
 (0)