aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Agafonov <[email protected]>2018-03-28 15:42:34 +0300
committerEric Paris <[email protected]>2018-03-28 05:42:34 -0700
commit45e82a3a9c6b20fe3159b3dc2eb28d80a3b2ee67 (patch)
tree1c2fc66aae710372b6bb42fbc30c373600fb7928
parentee5fd03fd6acfd43e44aea0b4135958546ed8e73 (diff)
Implement BytesHex type of argument (#115)
BytesHex is an []byte represented as HEX-string --bytes=010203040506070809 states for []bytes{1,2,3,4,5,6,7,8,9}
-rw-r--r--bytes.go105
-rw-r--r--bytes_test.go72
2 files changed, 177 insertions, 0 deletions
diff --git a/bytes.go b/bytes.go
new file mode 100644
index 0000000..12c58db
--- /dev/null
+++ b/bytes.go
@@ -0,0 +1,105 @@
+package pflag
+
+import (
+ "encoding/hex"
+ "fmt"
+ "strings"
+)
+
+// BytesHex adapts []byte for use as a flag. Value of flag is HEX encoded
+type bytesHexValue []byte
+
+func (bytesHex bytesHexValue) String() string {
+ return fmt.Sprintf("%X", []byte(bytesHex))
+}
+
+func (bytesHex *bytesHexValue) Set(value string) error {
+ bin, err := hex.DecodeString(strings.TrimSpace(value))
+
+ if err != nil {
+ return err
+ }
+
+ *bytesHex = bin
+
+ return nil
+}
+
+func (*bytesHexValue) Type() string {
+ return "bytesHex"
+}
+
+func newBytesHexValue(val []byte, p *[]byte) *bytesHexValue {
+ *p = val
+ return (*bytesHexValue)(p)
+}
+
+func bytesHexConv(sval string) (interface{}, error) {
+
+ bin, err := hex.DecodeString(sval)
+
+ if err == nil {
+ return bin, nil
+ }
+
+ return nil, fmt.Errorf("invalid string being converted to Bytes: %s %s", sval, err)
+}
+
+// GetBytesHex return the []byte value of a flag with the given name
+func (f *FlagSet) GetBytesHex(name string) ([]byte, error) {
+ val, err := f.getFlagType(name, "bytesHex", bytesHexConv)
+
+ if err != nil {
+ return []byte{}, err
+ }
+
+ return val.([]byte), nil
+}
+
+// BytesHexVar defines an []byte flag with specified name, default value, and usage string.
+// The argument p points to an []byte variable in which to store the value of the flag.
+func (f *FlagSet) BytesHexVar(p *[]byte, name string, value []byte, usage string) {
+ f.VarP(newBytesHexValue(value, p), name, "", usage)
+}
+
+// BytesHexVarP is like BytesHexVar, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) BytesHexVarP(p *[]byte, name, shorthand string, value []byte, usage string) {
+ f.VarP(newBytesHexValue(value, p), name, shorthand, usage)
+}
+
+// BytesHexVar defines an []byte flag with specified name, default value, and usage string.
+// The argument p points to an []byte variable in which to store the value of the flag.
+func BytesHexVar(p *[]byte, name string, value []byte, usage string) {
+ CommandLine.VarP(newBytesHexValue(value, p), name, "", usage)
+}
+
+// BytesHexVarP is like BytesHexVar, but accepts a shorthand letter that can be used after a single dash.
+func BytesHexVarP(p *[]byte, name, shorthand string, value []byte, usage string) {
+ CommandLine.VarP(newBytesHexValue(value, p), name, shorthand, usage)
+}
+
+// BytesHex defines an []byte flag with specified name, default value, and usage string.
+// The return value is the address of an []byte variable that stores the value of the flag.
+func (f *FlagSet) BytesHex(name string, value []byte, usage string) *[]byte {
+ p := new([]byte)
+ f.BytesHexVarP(p, name, "", value, usage)
+ return p
+}
+
+// BytesHexP is like BytesHex, but accepts a shorthand letter that can be used after a single dash.
+func (f *FlagSet) BytesHexP(name, shorthand string, value []byte, usage string) *[]byte {
+ p := new([]byte)
+ f.BytesHexVarP(p, name, shorthand, value, usage)
+ return p
+}
+
+// BytesHex defines an []byte flag with specified name, default value, and usage string.
+// The return value is the address of an []byte variable that stores the value of the flag.
+func BytesHex(name string, value []byte, usage string) *[]byte {
+ return CommandLine.BytesHexP(name, "", value, usage)
+}
+
+// BytesHexP is like BytesHex, but accepts a shorthand letter that can be used after a single dash.
+func BytesHexP(name, shorthand string, value []byte, usage string) *[]byte {
+ return CommandLine.BytesHexP(name, shorthand, value, usage)
+}
diff --git a/bytes_test.go b/bytes_test.go
new file mode 100644
index 0000000..cc4a769
--- /dev/null
+++ b/bytes_test.go
@@ -0,0 +1,72 @@
+package pflag
+
+import (
+ "fmt"
+ "os"
+ "testing"
+)
+
+func setUpBytesHex(bytesHex *[]byte) *FlagSet {
+ f := NewFlagSet("test", ContinueOnError)
+ f.BytesHexVar(bytesHex, "bytes", []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, "Some bytes in HEX")
+ f.BytesHexVarP(bytesHex, "bytes2", "B", []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}, "Some bytes in HEX")
+ return f
+}
+
+func TestBytesHex(t *testing.T) {
+ testCases := []struct {
+ input string
+ success bool
+ expected string
+ }{
+ /// Positive cases
+ {"", true, ""}, // Is empty string OK ?
+ {"01", true, "01"},
+ {"0101", true, "0101"},
+ {"1234567890abcdef", true, "1234567890ABCDEF"},
+ {"1234567890ABCDEF", true, "1234567890ABCDEF"},
+
+ // Negative cases
+ {"0", false, ""}, // Short string
+ {"000", false, ""}, /// Odd-length string
+ {"qq", false, ""}, /// non-hex character
+ }
+
+ devnull, _ := os.Open(os.DevNull)
+ os.Stderr = devnull
+
+ for i := range testCases {
+ var bytesHex []byte
+ f := setUpBytesHex(&bytesHex)
+
+ tc := &testCases[i]
+
+ // --bytes
+ args := []string{
+ fmt.Sprintf("--bytes=%s", tc.input),
+ fmt.Sprintf("-B %s", tc.input),
+ fmt.Sprintf("--bytes2=%s", tc.input),
+ }
+
+ for _, arg := range args {
+ err := f.Parse([]string{arg})
+
+ if err != nil && tc.success == true {
+ t.Errorf("expected success, got %q", err)
+ continue
+ } else if err == nil && tc.success == false {
+ // bytesHex, err := f.GetBytesHex("bytes")
+ t.Errorf("expected failure while processing %q", tc.input)
+ continue
+ } else if tc.success {
+ bytesHex, err := f.GetBytesHex("bytes")
+ if err != nil {
+ t.Errorf("Got error trying to fetch the IP flag: %v", err)
+ }
+ if fmt.Sprintf("%X", bytesHex) != tc.expected {
+ t.Errorf("expected %q, got '%X'", tc.expected, bytesHex)
+ }
+ }
+ }
+ }
+}