aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGrégoire Duchêne <gduchene@awhk.org>2022-12-10 14:27:00 +0000
committerGrégoire Duchêne <gduchene@awhk.org>2022-12-10 14:41:04 +0000
commitcf1bfb5f93c5c8f5b923e2ed84a7ef45f188876c (patch)
treefff4ba83a8a3025bcba053c7f0d833edd05dc3e3
parent3cc43119b40d3a556ae818b69bad5d977cc24014 (diff)
Add ParseProtobufEnumv0.5.0
-rw-r--r--flag.go24
-rw-r--r--flag_test.go36
2 files changed, 60 insertions, 0 deletions
diff --git a/flag.go b/flag.go
index 01e5f54..42f4537 100644
--- a/flag.go
+++ b/flag.go
@@ -145,6 +145,30 @@ func (f *Feature) String() string {
// value or an error.
type ParseFunc[T any] func(string) (T, error)
+// ParseProtobufEnum returns a ParseFunc that will return the
+// appropriate enum value or a UnknownEnumValueError if the string
+// passed did not match any of the values supplied.
+//
+// Strings are compared in uppercase only, so ‘FOO,’ ‘foo,’, and ‘fOo’
+// all refer to the same value.
+//
+// Callers should pass the protoc-generated *_value directly. See
+// https://developers.google.com/protocol-buffers/docs/reference/go-generated#enum
+// for more details.
+func ParseProtobufEnum[T ~int32](values map[string]int32) ParseFunc[T] {
+ valid := make([]string, 0, len(values))
+ for val := range values {
+ valid = append(valid, val)
+ }
+ return func(s string) (T, error) {
+ val, found := values[strings.ToUpper(s)]
+ if !found {
+ return 0, UnknownEnumValueError{s, valid}
+ }
+ return T(val), nil
+ }
+}
+
// ParseStringEnum returns a ParseFunc that will return the string
// passed if it matched any of the values supplied. If no such match is
// found, an UnknownEnumValueError is returned.
diff --git a/flag_test.go b/flag_test.go
index 0fb83c7..5b0df0e 100644
--- a/flag_test.go
+++ b/flag_test.go
@@ -143,6 +143,42 @@ func TestInitFlagSet(s *testing.T) {
})
}
+func TestParseProtobufEnum(s *testing.T) {
+ t := &core.T{T: s}
+
+ // That type and map emulate code generated by protoc.
+ type fakeEnum int32
+ values := map[string]int32{
+ "FAKE_UNKNOWN": 0,
+ "FOO": 1,
+ "BAR": 2,
+ }
+ parse := core.ParseProtobufEnum[fakeEnum](values)
+
+ t.Run("Match", func(t *core.T) {
+ val, err := parse("FOO")
+ t.AssertErrorIs(nil, err)
+ t.AssertEqual(fakeEnum(1), val)
+ })
+
+ t.Run("MatchCase", func(t *core.T) {
+ val, err := parse("Foo")
+ t.AssertErrorIs(nil, err)
+ t.AssertEqual(fakeEnum(1), val)
+ })
+
+ t.Run("UnknownValue", func(t *core.T) {
+ val, err := parse("BAZ")
+ var exp core.UnknownEnumValueError
+ if t.AssertErrorAs(&exp, err) {
+ t.AssertEqual("BAZ", exp.Actual)
+ sort.Strings(exp.Expected)
+ t.AssertEqual([]string{"BAR", "FAKE_UNKNOWN", "FOO"}, exp.Expected)
+ }
+ t.AssertEqual(fakeEnum(0), val)
+ })
+}
+
func TestParseStringEnum(s *testing.T) {
t := &core.T{T: s}
parse := core.ParseStringEnum("foo", "bar")