Skip to content

Commit

Permalink
feat: Add support of []time.Duration (#87)
Browse files Browse the repository at this point in the history
  • Loading branch information
obalunenko authored Mar 27, 2023
1 parent f2aba53 commit 01357aa
Show file tree
Hide file tree
Showing 8 changed files with 248 additions and 8 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
[![Go Reference](https://pkg.go.dev/badge/github.com/obalunenko/getenv.svg)](https://pkg.go.dev/github.com/obalunenko/getenv)
[![Go Report Card](https://goreportcard.com/badge/github.com/obalunenko/getenv)](https://goreportcard.com/report/github.com/obalunenko/getenv)
[![codecov](https://codecov.io/gh/obalunenko/getenv/branch/master/graph/badge.svg)](https://codecov.io/gh/obalunenko/getenv)
![coverbadger-tag-do-not-edit](https://img.shields.io/badge/coverage-98.11%25-brightgreen?longCache=true&style=flat)
![coverbadger-tag-do-not-edit](https://img.shields.io/badge/coverage-97.73%25-brightgreen?longCache=true&style=flat)
[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=obalunenko_getenv&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=obalunenko_getenv)

# getenv
Expand Down Expand Up @@ -39,6 +39,7 @@ Types supported:
- time.Time
- []time.Time
- time.Duration
- []time.Duration
- bool
- url.URL
- net.IP
Expand Down
1 change: 1 addition & 0 deletions getenv.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
// - time.Time
// - []time.Time
// - time.Duration
// - []time.Duration
// - bool
// - url.URL
// - net.IP
Expand Down
82 changes: 82 additions & 0 deletions getenv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1398,6 +1398,88 @@ func TestTimeSliceOrDefault(t *testing.T) {
}
}

func TestDurationSliceOrDefault(t *testing.T) {
type args struct {
key string
defaultVal []time.Duration
separator string
}

type expected struct {
val []time.Duration
}

var tests = []struct {
name string
precond precondition
args args
expected expected
}{
{
name: "env not set - default returned",
precond: precondition{
setenv: setenv{
isSet: false,
val: "2m,3h",
},
},
args: args{
key: testEnvKey,
defaultVal: []time.Duration{time.Second},
separator: ",",
},
expected: expected{
val: []time.Duration{time.Second},
},
},
{
name: "env set - env value returned",
precond: precondition{
setenv: setenv{
isSet: true,
val: "2m,3h",
},
},
args: args{
key: testEnvKey,
defaultVal: []time.Duration{time.Second},
separator: ",",
},
expected: expected{
val: []time.Duration{
2 * time.Minute, 3 * time.Hour,
},
},
},
{
name: "empty env value set - default returned",
precond: precondition{
setenv: setenv{
isSet: true,
val: "",
},
},
args: args{
key: testEnvKey,
defaultVal: []time.Duration{time.Second},
separator: ",",
},
expected: expected{
val: []time.Duration{time.Second},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.precond.maybeSetEnv(t, tt.args.key)

got := getenv.EnvOrDefault(tt.args.key, tt.args.defaultVal, option.WithSeparator(","))
assert.Equal(t, tt.expected.val, got)
})
}
}

func TestDurationOrDefault(t *testing.T) {
type args struct {
key string
Expand Down
2 changes: 1 addition & 1 deletion internal/constraint.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ type (

// Time is a constraint for time.Time and time.Duration.
Time interface {
time.Time | []time.Time | time.Duration
time.Time | []time.Time | time.Duration | []time.Duration
}
)
33 changes: 27 additions & 6 deletions internal/iface.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,8 @@ func NewEnvParser(v any) EnvParser {
p = boolParser(t)
case float32, []float32, float64, []float64:
p = newFloatParser(t)
case time.Time:
p = timeParser(t)
case []time.Time:
p = timeSliceParser(t)
case time.Duration:
p = durationParser(t)
case time.Time, []time.Time, time.Duration, []time.Duration:
p = newTimeParser(t)
case url.URL:
p = urlParser(t)
case net.IP:
Expand Down Expand Up @@ -124,6 +120,21 @@ func newFloatParser(v any) EnvParser {
}
}

func newTimeParser(v any) EnvParser {
switch t := v.(type) {
case time.Time:
return timeParser(t)
case []time.Time:
return timeSliceParser(t)
case time.Duration:
return durationParser(t)
case []time.Duration:
return durationSliceParser(t)
default:
return nil
}
}

// EnvParser interface for parsing environment variables.
type EnvParser interface {
ParseEnv(key string, defaltVal any, options Parameters) any
Expand Down Expand Up @@ -302,6 +313,16 @@ func (t timeSliceParser) ParseEnv(key string, defaltVal any, options Parameters)
return val
}

type durationSliceParser []time.Duration

func (t durationSliceParser) ParseEnv(key string, defaltVal any, options Parameters) any {
sep := options.Separator

val := durationSliceOrDefault(key, defaltVal.([]time.Duration), sep)

return val
}

type durationParser time.Duration

func (d durationParser) ParseEnv(key string, defaltVal any, _ Parameters) any {
Expand Down
29 changes: 29 additions & 0 deletions internal/iface_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,14 @@ func TestNewEnvParser(t *testing.T) {
want: timeSliceParser([]time.Time{}),
wantPanic: assert.NotPanics,
},
{
name: "[]time.Duration",
args: args{
v: []time.Duration{},
},
want: durationSliceParser([]time.Duration{}),
wantPanic: assert.NotPanics,
},
{
name: "time.Duration",
args: args{
Expand Down Expand Up @@ -882,6 +890,27 @@ func Test_ParseEnv(t *testing.T) {
time.Date(2023, time.March, 24, 0, 0, 0, 0, time.UTC),
},
},
{
name: "durationSliceParser",
s: durationSliceParser([]time.Duration{}),
precond: precondition{
setenv: setenv{
isSet: true,
val: "2m,3h",
},
},
args: args{
key: testEnvKey,
defaltVal: []time.Duration{},
in2: Parameters{
Separator: ",",
},
},
want: []time.Duration{
2 * time.Minute,
3 * time.Hour,
},
},
{
name: "urlParser",
s: urlParser(url.URL{}),
Expand Down
23 changes: 23 additions & 0 deletions internal/parsers.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,29 @@ func timeSliceOrDefault(key string, defaultVal []time.Time, layout, separator st
return val
}

// durationSliceOrDefault retrieves the []time.Duration value of the environment variable named
// by the key represented by layout.
// If variable not set or value is empty - defaultVal will be returned.
func durationSliceOrDefault(key string, defaultVal []time.Duration, separator string) []time.Duration {
valraw := stringSliceOrDefault(key, nil, separator)
if valraw == nil {
return defaultVal
}

val := make([]time.Duration, 0, len(valraw))

for _, s := range valraw {
v, err := time.ParseDuration(s)
if err != nil {
return defaultVal
}

val = append(val, v)
}

return val
}

// int64OrDefault retrieves the int64 value of the environment variable named
// by the key.
// If variable not set or value is empty - defaultVal will be returned.
Expand Down
83 changes: 83 additions & 0 deletions internal/parsers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2374,6 +2374,89 @@ func Test_timeSliceOrDefault(t *testing.T) {
}
}

func Test_durationSliceOrDefault(t *testing.T) {
type args struct {
key string
defaultVal []time.Duration
separator string
}

type expected struct {
val []time.Duration
}

var tests = []struct {
name string
precond precondition
args args
expected expected
}{
{
name: "env not set - default returned",
precond: precondition{
setenv: setenv{
isSet: false,
val: "2m,3h",
},
},
args: args{
key: testEnvKey,
defaultVal: []time.Duration{time.Second},
separator: ",",
},
expected: expected{
val: []time.Duration{time.Second},
},
},
{
name: "env set - env value returned",
precond: precondition{
setenv: setenv{
isSet: true,
val: "2m,3h",
},
},
args: args{
key: testEnvKey,
defaultVal: []time.Duration{time.Second},
separator: ",",
},
expected: expected{
val: []time.Duration{
2 * time.Minute, 3 * time.Hour,
},
},
},
{
name: "empty env value set - default returned",
precond: precondition{
setenv: setenv{
isSet: true,
val: "",
},
},
args: args{
key: testEnvKey,
defaultVal: []time.Duration{time.Second},
separator: ",",
},
expected: expected{
val: []time.Duration{time.Second},
},
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.precond.maybeSetEnv(t, tt.args.key)

got := durationSliceOrDefault(tt.args.key, tt.args.defaultVal, tt.args.separator)

assert.Equal(t, tt.expected.val, got)
})
}
}

func Test_durationOrDefault(t *testing.T) {
type args struct {
key string
Expand Down

0 comments on commit 01357aa

Please sign in to comment.