diff --git a/README.md b/README.md index df7f0a0..1f938d0 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,8 @@ type AppConfig struct { Float32Field float32 `env:"FLOAT32_FIELD"` Float64Field float64 `env:"FLOAT64_FIELD"` TimeDurationField time.Duration `env:"TIME_DURATION_FIELD"` + ByteSliceField []byte `env:"BYTE_SLICE_FIELD"` + StringSliceField []string `env:"STRING_SLICE_FIELD" default:"string1,string2,string3"` EmptyField string `env:"EMPTY_FIELD,omitempty"` WithDefaultField string `env:"WITH_DEFAULT_FIELD" default:"ave"` } @@ -104,6 +106,7 @@ func main() { - int, int8, int16, int32, int64 - uint, uint8, uint16, uint32, uint64 - float32, float64 +- slices: bytes, strings ### .env file diff --git a/config.go b/config.go index 581bacd..a0e2b8e 100644 --- a/config.go +++ b/config.go @@ -133,6 +133,8 @@ func (c *ConfigManager) UseCustomKeyTag(tag string) *ConfigManager { // Float32Field float32 `env:"FLOAT32_FIELD"` // Float64Field float64 `env:"FLOAT64_FIELD"` // TimeDurationField time.Duration `env:"TIME_DURATION_FIELD"` +// ByteSliceField []byte `env:"BYTE_SLICE_FIELD"` +// StringSliceField []string `env:"STRING_SLICE_FIELD"` // EmptyField string `env:"EMPTY_FIELD,omitempty"` // WithDefaultField string `env:"WITH_DEFAULT_FIELD" default:"ave"` // } diff --git a/config_test.go b/config_test.go index 4324161..9d139cd 100644 --- a/config_test.go +++ b/config_test.go @@ -32,6 +32,9 @@ func Test_UnmarshalFromEnv(t *testing.T) { TimeField time.Duration `env:"TIME_FIELD"` + ByteSliceField []byte `env:"BYTE_SLICE_FIELD"` + StringSliceField []string `env:"STRING_SLICE_FIELD"` + EmptyField string `env:"EMPTY_FIELD,omitempty"` } @@ -55,6 +58,8 @@ func Test_UnmarshalFromEnv(t *testing.T) { _ = os.Setenv("FLOAT64_FIELD", "3.14159265359") _ = os.Setenv("TIME_FIELD", "5s") + _ = os.Setenv("BYTE_SLICE_FIELD", "test") + _ = os.Setenv("STRING_SLICE_FIELD", "test1,test2,test3") cfg := new(TestConfig) cfgManager := NewDefault() @@ -76,6 +81,8 @@ func Test_UnmarshalFromEnv(t *testing.T) { assert.Equal(t, float32(3.14), cfg.Float32Field) assert.Equal(t, float64(3.14159265359), cfg.Float64Field) assert.Equal(t, 5*time.Second, cfg.TimeField) + assert.Equal(t, []byte("test"), cfg.ByteSliceField) + assert.Equal(t, []string{"test1", "test2", "test3"}, cfg.StringSliceField) } func Test_UnmarshalFromDotEnv(t *testing.T) { @@ -94,17 +101,20 @@ UINT32_FIELD=4294967295 UINT64_FIELD=18446744073709551615 FLOAT32_FIELD=3.14 FLOAT64_FIELD=3.14159265359 -TIME_FIELD=5s` +TIME_FIELD=5s +BYTE_SLICE_FIELD=test +STRING_SLICE_FIELD=test1,test2,test3` ) tmpFile, _ := os.CreateTemp(".", "test_env_*.env") - defer func() { _ = tmpFile.Close() }() + envFilePath := tmpFile.Name() + defer func() { + _ = tmpFile.Close() + _ = os.Remove(envFilePath) + }() _, _ = tmpFile.WriteString(envContent) - envFilePath := tmpFile.Name() - defer func() { _ = os.Remove(envFilePath) }() - type TestConfig struct { BoolField bool `env:"BOOL_FIELD"` StringField string `env:"STRING_FIELD"` @@ -121,6 +131,8 @@ TIME_FIELD=5s` Float32Field float32 `env:"FLOAT32_FIELD"` Float64Field float64 `env:"FLOAT64_FIELD"` TimeDurationField time.Duration `env:"TIME_FIELD"` + ByteSliceField []byte `env:"BYTE_SLICE_FIELD"` + StringSliceField []string `env:"STRING_SLICE_FIELD"` } dotEnvProvider, err := values.NewDotEnvProvider(envFilePath) @@ -148,6 +160,8 @@ TIME_FIELD=5s` assert.Equal(t, float32(3.14), cfg.Float32Field) assert.Equal(t, float64(3.14159265359), cfg.Float64Field) assert.Equal(t, 5*time.Second, cfg.TimeDurationField) + assert.Equal(t, []byte("test"), cfg.ByteSliceField) + assert.Equal(t, []string{"test1", "test2", "test3"}, cfg.StringSliceField) } func Test_EmptyField(t *testing.T) { @@ -218,6 +232,8 @@ func Test_OmitEmpty(t *testing.T) { Float32Field float32 `env:"FLOAT32_FIELD,omitempty"` Float64Field float64 `env:"FLOAT64_FIELD,omitempty"` TimeDurationField time.Duration `env:"TIME_FIELD,omitempty"` + ByteSliceField []byte `env:"BYTE_SLICE_FIELD,omitempty"` + StringSliceField []string `env:"STRING_SLICE_FIELD,omitempty"` } _ = os.Setenv("BOOL_FIELD", "") @@ -235,6 +251,8 @@ func Test_OmitEmpty(t *testing.T) { _ = os.Setenv("FLOAT32_FIELD", "") _ = os.Setenv("FLOAT64_FIELD", "") _ = os.Setenv("TIME_FIELD", "") + _ = os.Setenv("BYTE_SLICE_FIELD", "") + _ = os.Setenv("STRING_SLICE_FIELD", "") cfg := new(TestConfig) cfgManager := NewDefault() @@ -256,6 +274,8 @@ func Test_OmitEmpty(t *testing.T) { assert.Equal(t, float32(0), cfg.Float32Field) assert.Equal(t, float64(0), cfg.Float64Field) assert.Equal(t, time.Duration(0), cfg.TimeDurationField) + assert.Equal(t, []byte(nil), cfg.ByteSliceField) + assert.Equal(t, []string(nil), cfg.StringSliceField) } func Test_DefaultValues(t *testing.T) { diff --git a/pkg/parsers/default.go b/pkg/parsers/default.go index a64390d..325849a 100644 --- a/pkg/parsers/default.go +++ b/pkg/parsers/default.go @@ -3,6 +3,7 @@ package parsers import ( "reflect" "strconv" + "strings" "time" ) @@ -11,6 +12,12 @@ var ( reflect.TypeOf(time.Duration(83)): func(v string) (interface{}, error) { return time.ParseDuration(v) }, + reflect.TypeOf([]byte{}): func(v string) (interface{}, error) { + return []byte(v), nil + }, + reflect.TypeOf([]string{}): func(v string) (interface{}, error) { + return strings.Split(v, ","), nil + }, } defaultKindParsers = map[reflect.Kind]func(v string) (interface{}, error){