Skip to content

Commit 5f8ef04

Browse files
committed
feat: support enum field validation
relates to #6
1 parent 66abc62 commit 5f8ef04

File tree

3 files changed

+56
-0
lines changed

3 files changed

+56
-0
lines changed

env.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ func setField(t reflect.StructField, v reflect.Value, value string) (err error)
107107
return setSlice(t, v, value)
108108
}
109109

110+
if err = checkEnum(t, value); err != nil {
111+
return fmt.Errorf("error setting %q: %v", t.Name, err)
112+
}
113+
110114
if err = setBuiltInField(v, value); err != nil {
111115
return fmt.Errorf("error setting %q: %v", t.Name, err)
112116
}

env_test.go

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,42 @@ func TestEnvPrefixed(t *testing.T) {
675675
Equals(t, "hello", config.Prop)
676676
}
677677

678+
func TestEnumUnmatched(t *testing.T) {
679+
os.Setenv("PROP", "foo")
680+
681+
config := struct {
682+
Prop string `env:"PROP" enum:"1,2,3"`
683+
}{}
684+
685+
err := Set(&config)
686+
ErrorNotNil(t, err)
687+
Assert(t, strings.HasPrefix(err.Error(), `error setting "Prop": "foo" is not a member of [1,2,3]`))
688+
}
689+
690+
func TestEnumMatchedString(t *testing.T) {
691+
os.Setenv("PROP", "foo")
692+
693+
config := struct {
694+
Prop string `env:"PROP" enum:"foo,bar,baz"`
695+
}{}
696+
697+
err := Set(&config)
698+
ErrorNil(t, err)
699+
Assert(t, config.Prop == "foo")
700+
}
701+
702+
func TestEnumMatchedInteger(t *testing.T) {
703+
os.Setenv("PROP", "1")
704+
705+
config := struct {
706+
Prop int `env:"PROP" enum:"1,2,3"`
707+
}{}
708+
709+
err := Set(&config)
710+
ErrorNil(t, err)
711+
Assert(t, config.Prop == 1)
712+
}
713+
678714
type configDuration struct {
679715
Duration time.Duration
680716
}

set.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package env
33
import (
44
"fmt"
55
"reflect"
6+
"slices"
67
"strconv"
78
"strings"
89
"time"
@@ -179,3 +180,18 @@ func getDelimiter(t reflect.StructField) string {
179180
}
180181
return ","
181182
}
183+
184+
func checkEnum(t reflect.StructField, value string) (err error) {
185+
rawChoices, ok := t.Tag.Lookup("enum")
186+
if !ok {
187+
return
188+
}
189+
190+
delimiter := getDelimiter(t)
191+
choices := split(rawChoices, delimiter)
192+
if !slices.Contains(choices, value) {
193+
return fmt.Errorf(`"%s" is not a member of [%s]`, value, strings.Join(choices, ","))
194+
}
195+
196+
return
197+
}

0 commit comments

Comments
 (0)