From cf419803bc61e5972e75ea99e6f3ad23374eb3bc Mon Sep 17 00:00:00 2001 From: Vivek R Date: Mon, 27 Jan 2020 15:49:46 +0530 Subject: [PATCH] feat: add must getters Add getters which panics if key is not found or value returned is default data type. For example: `kf.MustInt("abc")` If path "abc" is not found or its 0 then it panics else returnes value. --- getters.go | 535 ++++++++++++++++++++++++++++++++++++++++++++++++++ koanf.go | 358 --------------------------------- koanf_test.go | 88 +++++++++ 3 files changed, 623 insertions(+), 358 deletions(-) create mode 100644 getters.go diff --git a/getters.go b/getters.go new file mode 100644 index 00000000..167ebb70 --- /dev/null +++ b/getters.go @@ -0,0 +1,535 @@ +package koanf + +import ( + "fmt" + "time" +) + +// Int64 returns the int64 value of a given key path or 0 if the path +// does not exist or if the value is not a valid int64. +func (ko *Koanf) Int64(path string) int64 { + if v := ko.Get(path); v != nil { + i, _ := toInt64(v) + return i + } + return 0 +} + +// MustInt64 returns the int64 value of a given key path or panics +// if the value is not set or set to default value of 0. +func (ko *Koanf) MustInt64(path string) int64 { + val := ko.Int64(path) + if val == 0 { + panic(fmt.Sprintf("invalid value: %s=%v", path, val)) + } + return val +} + +// Int64s returns the []int64 slice value of a given key path or an +// empty []int64 slice if the path does not exist or if the value +// is not a valid int slice. +func (ko *Koanf) Int64s(path string) []int64 { + o := ko.Get(path) + if o == nil { + return []int64{} + } + + var out []int64 + switch v := o.(type) { + case []interface{}: + out = make([]int64, 0, len(v)) + for _, vi := range v { + i, err := toInt64(vi) + + // On error, return as it's not a valid + // int slice. + if err != nil { + return []int64{} + } + out = append(out, i) + } + return out + } + + return []int64{} +} + +// MustInt64s returns the []int64 slice value of a given key path or panics +// if the value is not set or its default value. +func (ko *Koanf) MustInt64s(path string) []int64 { + val := ko.Int64s(path) + if len(val) == 0 { + panic(fmt.Sprintf("invalid value: %s=%v", path, val)) + } + return val +} + +// Int64Map returns the map[string]int64 value of a given key path +// or an empty map[string]int64 if the path does not exist or if the +// value is not a valid int64 map. +func (ko *Koanf) Int64Map(path string) map[string]int64 { + var ( + out = map[string]int64{} + o = ko.Get(path) + ) + if o == nil { + return out + } + + mp, ok := o.(map[string]interface{}) + if !ok { + return out + } + + out = make(map[string]int64, len(mp)) + for k, v := range mp { + switch i := v.(type) { + case int64: + out[k] = i + default: + // Attempt a conversion. + iv, err := toInt64(i) + if err != nil { + return map[string]int64{} + } + out[k] = iv + } + } + return out +} + +// MustInt64Map returns the map[string]int64 value of a given key path +// or panics if its not set or set to default value. +func (ko *Koanf) MustInt64Map(path string) map[string]int64 { + val := ko.Int64Map(path) + if len(val) == 0 { + panic(fmt.Sprintf("invalid value: %s=%v", path, val)) + } + return val +} + +// Int returns the int value of a given key path or 0 if the path +// does not exist or if the value is not a valid int. +func (ko *Koanf) Int(path string) int { + return int(ko.Int64(path)) +} + +// MustInt returns the int value of a given key path or panics +// or panics if its not set or set to default value of 0. +func (ko *Koanf) MustInt(path string) int { + val := ko.Int(path) + if val == 0 { + panic(fmt.Sprintf("invalid value: %s=%v", path, val)) + } + return val +} + +// Ints returns the []int slice value of a given key path or an +// empty []int slice if the path does not exist or if the value +// is not a valid int slice. +func (ko *Koanf) Ints(path string) []int { + ints := ko.Int64s(path) + if len(ints) == 0 { + return []int{} + } + + out := make([]int, len(ints)) + for i, v := range ints { + out[i] = int(v) + } + return out +} + +// MustInts returns the []int slice value of a given key path or panics +// if the value is not set or set to default value. +func (ko *Koanf) MustInts(path string) []int { + val := ko.Ints(path) + if len(val) == 0 { + panic(fmt.Sprintf("invalid value: %s=%v", path, val)) + } + return val +} + +// IntMap returns the map[string]int value of a given key path +// or an empty map[string]int if the path does not exist or if the +// value is not a valid int map. +func (ko *Koanf) IntMap(path string) map[string]int { + var ( + mp = ko.Int64Map(path) + out = make(map[string]int, len(mp)) + ) + for k, v := range mp { + out[k] = int(v) + } + return out +} + +// MustIntMap returns the map[string]int value of a given key path or panics +// if the value is not set or set to default value. +func (ko *Koanf) MustIntMap(path string) map[string]int { + val := ko.IntMap(path) + if len(val) == 0 { + panic(fmt.Sprintf("invalid value: %s=%v", path, val)) + } + return val +} + +// Float64 returns the float64 value of a given key path or 0 if the path +// does not exist or if the value is not a valid float64. +func (ko *Koanf) Float64(path string) float64 { + if v := ko.Get(path); v != nil { + f, _ := toFloat64(v) + return f + } + return 0 +} + +// MustFloat64 returns the float64 value of a given key path or panics +// or panics if its not set or set to default value 0. +func (ko *Koanf) MustFloat64(path string) float64 { + val := ko.Float64(path) + if val == 0 { + panic(fmt.Sprintf("invalid value: %s=%v", path, val)) + } + return val +} + +// Float64s returns the []float64 slice value of a given key path or an +// empty []float64 slice if the path does not exist or if the value +// is not a valid float64 slice. +func (ko *Koanf) Float64s(path string) []float64 { + o := ko.Get(path) + if o == nil { + return []float64{} + } + + var out []float64 + switch v := o.(type) { + case []interface{}: + out = make([]float64, 0, len(v)) + for _, vi := range v { + i, err := toFloat64(vi) + + // On error, return as it's not a valid + // int slice. + if err != nil { + return []float64{} + } + out = append(out, float64(i)) + } + return out + } + + return []float64{} +} + +// MustFloat64s returns the []Float64 slice value of a given key path or panics +// if the value is not set or set to default value. +func (ko *Koanf) MustFloat64s(path string) []float64 { + val := ko.Float64s(path) + if len(val) == 0 { + panic(fmt.Sprintf("invalid value: %s=%v", path, val)) + } + return val +} + +// Float64Map returns the map[string]float64 value of a given key path +// or an empty map[string]float64 if the path does not exist or if the +// value is not a valid float64 map. +func (ko *Koanf) Float64Map(path string) map[string]float64 { + var ( + out = map[string]float64{} + o = ko.Get(path) + ) + if o == nil { + return out + } + + mp, ok := o.(map[string]interface{}) + if !ok { + return out + } + + out = make(map[string]float64, len(mp)) + for k, v := range mp { + switch i := v.(type) { + case float64: + out[k] = i + default: + // Attempt a conversion. + iv, err := toFloat64(i) + if err != nil { + return map[string]float64{} + } + out[k] = iv + } + } + return out +} + +// MustFloat64Map returns the map[string]float64 value of a given key path or panics +// if the value is not set or set to default value. +func (ko *Koanf) MustFloat64Map(path string) map[string]float64 { + val := ko.Float64Map(path) + if len(val) == 0 { + panic(fmt.Sprintf("invalid value: %s=%v", path, val)) + } + return val +} + +// Duration returns the time.Duration value of a given key path assuming +// that the key contains a valid numeric value. +func (ko *Koanf) Duration(path string) time.Duration { + return time.Duration(ko.Int64(path)) +} + +// MustDuration returns the time.Duration value of a given key path or panics +// if its not set or set to default value 0. +func (ko *Koanf) MustDuration(path string) time.Duration { + val := ko.Duration(path) + if val == 0 { + panic(fmt.Sprintf("invalid value: %s=%v", path, val)) + } + return val +} + +// Time attempts to parse the value of a given key path and return time.Time +// representation. If the value is numeric, it is treated as a UNIX timestamp +// and if it's string, a parse is attempted with the given layout. +func (ko *Koanf) Time(path, layout string) time.Time { + // Unix timestamp? + v := ko.Int64(path) + if v != 0 { + return time.Unix(v, 0) + } + + // String representation. + s := ko.String(path) + if s != "" { + t, _ := time.Parse(layout, s) + return t + } + + return time.Time{} +} + +// MustTime attempts to parse the value of a given key path and return time.Time +// representation. If the value is numeric, it is treated as a UNIX timestamp +// and if it's string, a parse is attempted with the given layout. It panics if +// the parsed time is zero. +func (ko *Koanf) MustTime(path, layout string) time.Time { + val := ko.Time(path, layout) + if val.IsZero() { + panic(fmt.Sprintf("invalid value: %s=%v", path, val)) + } + return val +} + +// String returns the string value of a given key path or "" if the path +// does not exist or if the value is not a valid string. +func (ko *Koanf) String(path string) string { + if v := ko.Get(path); v != nil { + if i, ok := v.(string); ok { + return i + } + return fmt.Sprintf("%v", v) + } + return "" +} + +// MustString returns the string value of a given key path +// or panics if its not set or set to default value "". +func (ko *Koanf) MustString(path string) string { + val := ko.String(path) + if val == "" { + panic(fmt.Sprintf("invalid value: %s=%v", path, val)) + } + return val +} + +// Strings returns the []string slice value of a given key path or an +// empty []string slice if the path does not exist or if the value +// is not a valid string slice. +func (ko *Koanf) Strings(path string) []string { + o := ko.Get(path) + if o == nil { + return []string{} + } + + var out []string + switch v := o.(type) { + case []interface{}: + out = make([]string, 0, len(v)) + for _, u := range v { + if s, ok := u.(string); ok { + out = append(out, s) + } else { + out = append(out, fmt.Sprintf("%v", u)) + } + } + return out + case []string: + out := make([]string, len(v)) + copy(out[:], v[:]) + return out + } + return []string{} +} + +// MustStrings returns the []string slice value of a given key path or panics +// if the value is not set or set to default value. +func (ko *Koanf) MustStrings(path string) []string { + val := ko.Strings(path) + if len(val) == 0 { + panic(fmt.Sprintf("invalid value: %s=%v", path, val)) + } + return val +} + +// StringMap returns the map[string]string value of a given key path +// or an empty map[string]string if the path does not exist or if the +// value is not a valid string map. +func (ko *Koanf) StringMap(path string) map[string]string { + var ( + out = map[string]string{} + o = ko.Get(path) + ) + if o == nil { + return out + } + + mp, ok := o.(map[string]interface{}) + if !ok { + return out + } + out = make(map[string]string, len(mp)) + for k, v := range mp { + switch s := v.(type) { + case string: + out[k] = s + default: + // There's a non string type. Return. + return map[string]string{} + } + } + + return out +} + +// MustStringMap returns the map[string]string value of a given key path or panics +// if the value is not set or set to default value. +func (ko *Koanf) MustStringMap(path string) map[string]string { + val := ko.StringMap(path) + if len(val) == 0 { + panic(fmt.Sprintf("invalid value: %s=%v", path, val)) + } + return val +} + +// Bytes returns the []byte value of a given key path or an empty +// []byte slice if the path does not exist or if the value is not a valid string. +func (ko *Koanf) Bytes(path string) []byte { + return []byte(ko.String(path)) +} + +// MustBytes returns the []byte value of a given key path or panics +// if the value is not set or set to default value. +func (ko *Koanf) MustBytes(path string) []byte { + val := ko.Bytes(path) + if len(val) == 0 { + panic(fmt.Sprintf("invalid value: %s=%v", path, val)) + } + return val +} + +// Bool returns the bool value of a given key path or false if the path +// does not exist or if the value is not a valid bool representation. +// Accepted string representations of bool are the ones supported by strconv.ParseBool. +func (ko *Koanf) Bool(path string) bool { + if v := ko.Get(path); v != nil { + b, _ := toBool(v) + return b + } + return false +} + +// Bools returns the []bool slice value of a given key path or an +// empty []bool slice if the path does not exist or if the value +// is not a valid bool slice. +func (ko *Koanf) Bools(path string) []bool { + o := ko.Get(path) + if o == nil { + return []bool{} + } + + var out []bool + switch v := o.(type) { + case []interface{}: + out = make([]bool, 0, len(v)) + for _, u := range v { + b, err := toBool(u) + if err != nil { + return nil + } + out = append(out, b) + } + return out + case []bool: + return out + } + return nil +} + +// MustBools returns the []bool value of a given key path or panics +// if the value is not set or set to default value. +func (ko *Koanf) MustBools(path string) []bool { + val := ko.Bools(path) + if len(val) == 0 { + panic(fmt.Sprintf("invalid value: %s=%v", path, val)) + } + return val +} + +// BoolMap returns the map[string]bool value of a given key path +// or an empty map[string]bool if the path does not exist or if the +// value is not a valid bool map. +func (ko *Koanf) BoolMap(path string) map[string]bool { + var ( + out = map[string]bool{} + o = ko.Get(path) + ) + if o == nil { + return out + } + + mp, ok := o.(map[string]interface{}) + if !ok { + return out + } + out = make(map[string]bool, len(mp)) + for k, v := range mp { + switch i := v.(type) { + case bool: + out[k] = i + default: + // Attempt a conversion. + b, err := toBool(i) + if err != nil { + return map[string]bool{} + } + out[k] = b + } + } + + return out +} + +// MustBoolMap returns the map[string]bool value of a given key path or panics +// if the value is not set or set to default value. +func (ko *Koanf) MustBoolMap(path string) map[string]bool { + val := ko.BoolMap(path) + if len(val) == 0 { + panic(fmt.Sprintf("invalid value: %s=%v", path, val)) + } + return val +} diff --git a/koanf.go b/koanf.go index c4cbf73c..8cf8f5c3 100644 --- a/koanf.go +++ b/koanf.go @@ -7,7 +7,6 @@ import ( "sort" "strconv" "strings" - "time" "github.com/knadh/koanf/maps" "github.com/mitchellh/mapstructure" @@ -259,363 +258,6 @@ func (ko *Koanf) Exists(path string) bool { return ok } -// Int64 returns the int64 value of a given key path or 0 if the path -// does not exist or if the value is not a valid int64. -func (ko *Koanf) Int64(path string) int64 { - if v := ko.Get(path); v != nil { - i, _ := toInt64(v) - return i - } - return 0 -} - -// Int64s returns the []int64 slice value of a given key path or an -// empty []int64 slice if the path does not exist or if the value -// is not a valid int slice. -func (ko *Koanf) Int64s(path string) []int64 { - o := ko.Get(path) - if o == nil { - return []int64{} - } - - var out []int64 - switch v := o.(type) { - case []interface{}: - out = make([]int64, 0, len(v)) - for _, vi := range v { - i, err := toInt64(vi) - - // On error, return as it's not a valid - // int slice. - if err != nil { - return []int64{} - } - out = append(out, i) - } - return out - } - - return []int64{} -} - -// Int64Map returns the map[string]int64 value of a given key path -// or an empty map[string]int64 if the path does not exist or if the -// value is not a valid int64 map. -func (ko *Koanf) Int64Map(path string) map[string]int64 { - var ( - out = map[string]int64{} - o = ko.Get(path) - ) - if o == nil { - return out - } - - mp, ok := o.(map[string]interface{}) - if !ok { - return out - } - - out = make(map[string]int64, len(mp)) - for k, v := range mp { - switch i := v.(type) { - case int64: - out[k] = i - default: - // Attempt a conversion. - iv, err := toInt64(i) - if err != nil { - return map[string]int64{} - } - out[k] = iv - } - } - return out -} - -// Int returns the int value of a given key path or 0 if the path -// does not exist or if the value is not a valid int. -func (ko *Koanf) Int(path string) int { - return int(ko.Int64(path)) -} - -// Ints returns the []int slice value of a given key path or an -// empty []int slice if the path does not exist or if the value -// is not a valid int slice. -func (ko *Koanf) Ints(path string) []int { - ints := ko.Int64s(path) - if len(ints) == 0 { - return []int{} - } - - out := make([]int, len(ints)) - for i, v := range ints { - out[i] = int(v) - } - return out -} - -// IntMap returns the map[string]int value of a given key path -// or an empty map[string]int if the path does not exist or if the -// value is not a valid int map. -func (ko *Koanf) IntMap(path string) map[string]int { - var ( - mp = ko.Int64Map(path) - out = make(map[string]int, len(mp)) - ) - for k, v := range mp { - out[k] = int(v) - } - return out -} - -// Float64 returns the float64 value of a given key path or 0 if the path -// does not exist or if the value is not a valid float64. -func (ko *Koanf) Float64(path string) float64 { - if v := ko.Get(path); v != nil { - f, _ := toFloat64(v) - return f - } - return 0.0 -} - -// Float64s returns the []float64 slice value of a given key path or an -// empty []float64 slice if the path does not exist or if the value -// is not a valid float64 slice. -func (ko *Koanf) Float64s(path string) []float64 { - o := ko.Get(path) - if o == nil { - return []float64{} - } - - var out []float64 - switch v := o.(type) { - case []interface{}: - out = make([]float64, 0, len(v)) - for _, vi := range v { - i, err := toFloat64(vi) - - // On error, return as it's not a valid - // int slice. - if err != nil { - return []float64{} - } - out = append(out, float64(i)) - } - return out - } - - return []float64{} -} - -// Float64Map returns the map[string]float64 value of a given key path -// or an empty map[string]float64 if the path does not exist or if the -// value is not a valid float64 map. -func (ko *Koanf) Float64Map(path string) map[string]float64 { - var ( - out = map[string]float64{} - o = ko.Get(path) - ) - if o == nil { - return out - } - - mp, ok := o.(map[string]interface{}) - if !ok { - return out - } - - out = make(map[string]float64, len(mp)) - for k, v := range mp { - switch i := v.(type) { - case float64: - out[k] = i - default: - // Attempt a conversion. - iv, err := toFloat64(i) - if err != nil { - return map[string]float64{} - } - out[k] = iv - } - } - return out -} - -// Duration returns the time.Duration value of a given key path assuming -// that the key contains a valid numeric value. -func (ko *Koanf) Duration(path string) time.Duration { - return time.Duration(ko.Int64(path)) -} - -// Time attempts to parse the value of a given key path and return time.Time -// representation. If the value is numeric, it is treated as a UNIX timestamp -// and if it's string, a parse is attempted with the given layout. -func (ko *Koanf) Time(path, layout string) time.Time { - // Unix timestamp? - v := ko.Int64(path) - if v != 0 { - return time.Unix(v, 0) - } - - // String representation. - s := ko.String(path) - if s != "" { - t, _ := time.Parse(layout, s) - return t - } - - return time.Time{} -} - -// String returns the string value of a given key path or "" if the path -// does not exist or if the value is not a valid string. -func (ko *Koanf) String(path string) string { - if v := ko.Get(path); v != nil { - if i, ok := v.(string); ok { - return i - } - return fmt.Sprintf("%v", v) - } - return "" -} - -// Strings returns the []string slice value of a given key path or an -// empty []string slice if the path does not exist or if the value -// is not a valid string slice. -func (ko *Koanf) Strings(path string) []string { - o := ko.Get(path) - if o == nil { - return []string{} - } - - var out []string - switch v := o.(type) { - case []interface{}: - out = make([]string, 0, len(v)) - for _, u := range v { - if s, ok := u.(string); ok { - out = append(out, s) - } else { - out = append(out, fmt.Sprintf("%v", u)) - } - } - return out - case []string: - out := make([]string, len(v)) - copy(out[:], v[:]) - return out - } - return []string{} -} - -// StringMap returns the map[string]string value of a given key path -// or an empty map[string]string if the path does not exist or if the -// value is not a valid string map. -func (ko *Koanf) StringMap(path string) map[string]string { - var ( - out = map[string]string{} - o = ko.Get(path) - ) - if o == nil { - return out - } - - mp, ok := o.(map[string]interface{}) - if !ok { - return out - } - out = make(map[string]string, len(mp)) - for k, v := range mp { - switch s := v.(type) { - case string: - out[k] = s - default: - // There's a non string type. Return. - return map[string]string{} - } - } - - return out -} - -// Bytes returns the []byte value of a given key path or an empty -// []byte slice if the path does not exist or if the value is not a valid string. -func (ko *Koanf) Bytes(path string) []byte { - return []byte(ko.String(path)) -} - -// Bool returns the bool value of a given key path or false if the path -// does not exist or if the value is not a valid bool representation. -// Accepted string representations of bool are the ones supported by strconv.ParseBool. -func (ko *Koanf) Bool(path string) bool { - if v := ko.Get(path); v != nil { - b, _ := toBool(v) - return b - } - return false -} - -// Bools returns the []bool slice value of a given key path or an -// empty []bool slice if the path does not exist or if the value -// is not a valid bool slice. -func (ko *Koanf) Bools(path string) []bool { - o := ko.Get(path) - if o == nil { - return []bool{} - } - - var out []bool - switch v := o.(type) { - case []interface{}: - out = make([]bool, 0, len(v)) - for _, u := range v { - b, err := toBool(u) - if err != nil { - return nil - } - out = append(out, b) - } - return out - case []bool: - return out - } - return nil -} - -// BoolMap returns the map[string]bool value of a given key path -// or an empty map[string]bool if the path does not exist or if the -// value is not a valid bool map. -func (ko *Koanf) BoolMap(path string) map[string]bool { - var ( - out = map[string]bool{} - o = ko.Get(path) - ) - if o == nil { - return out - } - - mp, ok := o.(map[string]interface{}) - if !ok { - return out - } - out = make(map[string]bool, len(mp)) - for k, v := range mp { - switch i := v.(type) { - case bool: - out[k] = i - default: - // Attempt a conversion. - b, err := toBool(i) - if err != nil { - return map[string]bool{} - } - out[k] = b - } - } - - return out -} - // MapKeys returns a sorted string list of keys in a map addressed by the // given path. If the path is not a map, an empty string slice is // returned. diff --git a/koanf_test.go b/koanf_test.go index b707e80b..50dc89b0 100644 --- a/koanf_test.go +++ b/koanf_test.go @@ -601,16 +601,21 @@ func TestGetTypes(t *testing.T) { // Int. assert.Equal(t, int64(0), c.koanf.Int64("xxxx"), "get value mismatch") assert.Equal(t, int64(1234), c.koanf.Int64("parent1.id"), "get value mismatch") + assert.Equal(t, int(0), c.koanf.Int("xxxx"), "get value mismatch") assert.Equal(t, int(1234), c.koanf.Int("parent1.id"), "get value mismatch") + assert.Equal(t, []int64{}, c.koanf.Int64s("xxxx"), "get value mismatch") assert.Equal(t, []int64{1, 2, 3}, c.koanf.Int64s("parent1.child1.grandchild1.ids"), "get value mismatch") + assert.Equal(t, map[string]int64{"key1": 1, "key2": 1, "key3": 1}, c.koanf.Int64Map("parent1.intmap"), "get value mismatch") assert.Equal(t, map[string]int64{}, c.koanf.Int64Map("parent1.boolmap"), "get value mismatch") assert.Equal(t, map[string]int64{}, c.koanf.Int64Map("xxxx"), "get value mismatch") assert.Equal(t, map[string]int64{"key1": 1, "key2": 1, "key3": 1}, c.koanf.Int64Map("parent1.floatmap"), "get value mismatch") + assert.Equal(t, []int{1, 2, 3}, c.koanf.Ints("parent1.child1.grandchild1.ids"), "get value mismatch") assert.Equal(t, []int{}, c.koanf.Ints("xxxx"), "get value mismatch") + assert.Equal(t, map[string]int{"key1": 1, "key2": 1, "key3": 1}, c.koanf.IntMap("parent1.intmap"), "get value mismatch") assert.Equal(t, map[string]int{}, c.koanf.IntMap("parent1.boolmap"), "get value mismatch") assert.Equal(t, map[string]int{}, c.koanf.IntMap("xxxx"), "get value mismatch") @@ -618,8 +623,10 @@ func TestGetTypes(t *testing.T) { // Float. assert.Equal(t, float64(0), c.koanf.Float64("xxx"), "get value mismatch") assert.Equal(t, float64(1234), c.koanf.Float64("parent1.id"), "get value mismatch") + assert.Equal(t, []float64{}, c.koanf.Float64s("xxxx"), "get value mismatch") assert.Equal(t, []float64{1, 2, 3}, c.koanf.Float64s("parent1.child1.grandchild1.ids"), "get value mismatch") + assert.Equal(t, map[string]float64{"key1": 1, "key2": 1, "key3": 1}, c.koanf.Float64Map("parent1.intmap"), "get value mismatch") assert.Equal(t, map[string]float64{"key1": 1.1, "key2": 1.2, "key3": 1.3}, c.koanf.Float64Map("parent1.floatmap"), "get value mismatch") assert.Equal(t, map[string]float64{}, c.koanf.Float64Map("parent1.boolmap"), "get value mismatch") @@ -628,10 +635,13 @@ func TestGetTypes(t *testing.T) { // String and bytes. assert.Equal(t, []byte{}, c.koanf.Bytes("xxxx"), "get value mismatch") assert.Equal(t, []byte("parent1"), c.koanf.Bytes("parent1.name"), "get value mismatch") + assert.Equal(t, "", c.koanf.String("xxxx"), "get value mismatch") assert.Equal(t, "parent1", c.koanf.String("parent1.name"), "get value mismatch") + assert.Equal(t, []string{}, c.koanf.Strings("xxxx"), "get value mismatch") assert.Equal(t, []string{"red", "blue", "orange"}, c.koanf.Strings("orphan"), "get value mismatch") + assert.Equal(t, map[string]string{"key1": "val1", "key2": "val2", "key3": "val3"}, c.koanf.StringMap("parent1.strmap"), "get value mismatch") assert.Equal(t, map[string]string{}, c.koanf.StringMap("xxxx"), "get value mismatch") assert.Equal(t, map[string]string{}, c.koanf.StringMap("parent1.intmap"), "get value mismatch") @@ -641,10 +651,12 @@ func TestGetTypes(t *testing.T) { assert.Equal(t, false, c.koanf.Bool("type"), "get value mismatch") assert.Equal(t, true, c.koanf.Bool("parent1.child1.grandchild1.on"), "get value mismatch") assert.Equal(t, true, c.koanf.Bool("strbool"), "get value mismatch") + assert.Equal(t, []bool{}, c.koanf.Bools("xxxx"), "get value mismatch") assert.Equal(t, []bool{true, false, true}, c.koanf.Bools("bools"), "get value mismatch") assert.Equal(t, []bool{true, false, true}, c.koanf.Bools("intbools"), "get value mismatch") assert.Equal(t, []bool{true, true, false}, c.koanf.Bools("strbools"), "get value mismatch") + assert.Equal(t, map[string]bool{"ok1": true, "ok2": true, "notok3": false}, c.koanf.BoolMap("parent1.boolmap"), "get value mismatch") assert.Equal(t, map[string]bool{"key1": true, "key2": true, "key3": true}, c.koanf.BoolMap("parent1.intmap"), "get value mismatch") assert.Equal(t, map[string]bool{}, c.koanf.BoolMap("xxxx"), "get value mismatch") @@ -652,8 +664,10 @@ func TestGetTypes(t *testing.T) { // Others. assert.Equal(t, time.Duration(1234), c.koanf.Duration("parent1.id"), "get value mismatch") assert.Equal(t, time.Duration(0), c.koanf.Duration("xxxx"), "get value mismatch") + assert.Equal(t, time.Time{}, c.koanf.Time("xxxx", "2006-01-02"), "get value mismatch") assert.Equal(t, time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC), c.koanf.Time("time", "2006-01-02"), "get value mismatch") + assert.Equal(t, []string{}, c.koanf.MapKeys("xxxx"), "map keys mismatch") assert.Equal(t, []string{"bools", "empty", "intbools", "orphan", "parent1", "parent2", "strbool", "strbools", "time", "type"}, c.koanf.MapKeys(""), "map keys mismatch") @@ -663,3 +677,77 @@ func TestGetTypes(t *testing.T) { assert.Equal(t, time.Date(1970, 1, 1, 0, 20, 34, 0, time.UTC), c.koanf.Time("parent1.id", "").UTC(), "get value mismatch") } } + +func TestMustGetTypes(t *testing.T) { + for _, c := range cases { + // Int. + assert.Panics(t, func() { c.koanf.MustInt64("xxxx") }) + assert.Equal(t, int64(1234), c.koanf.MustInt64("parent1.id"), "get value mismatch") + + assert.Panics(t, func() { c.koanf.MustInt("xxxx") }) + assert.Equal(t, int(1234), c.koanf.MustInt("parent1.id"), "get value mismatch") + + assert.Panics(t, func() { c.koanf.MustInt64s("xxxx") }) + assert.Equal(t, []int64{1, 2, 3}, c.koanf.MustInt64s("parent1.child1.grandchild1.ids"), "get value mismatch") + + assert.Panics(t, func() { c.koanf.MustInt64Map("xxxx") }) + assert.Equal(t, map[string]int64{"key1": 1, "key2": 1, "key3": 1}, c.koanf.MustInt64Map("parent1.intmap"), "get value mismatch") + + assert.Panics(t, func() { c.koanf.MustInt64Map("parent1.boolmap") }) + assert.Equal(t, map[string]int64{"key1": 1, "key2": 1, "key3": 1}, c.koanf.MustInt64Map("parent1.floatmap"), "get value mismatch") + + assert.Panics(t, func() { c.koanf.MustInts("xxxx") }) + assert.Equal(t, []int{1, 2, 3}, c.koanf.MustInts("parent1.child1.grandchild1.ids"), "get value mismatch") + + assert.Panics(t, func() { c.koanf.MustIntMap("xxxx") }) + assert.Panics(t, func() { c.koanf.MustIntMap("parent1.boolmap") }) + assert.Equal(t, map[string]int{"key1": 1, "key2": 1, "key3": 1}, c.koanf.MustIntMap("parent1.intmap"), "get value mismatch") + + // Float. + assert.Panics(t, func() { c.koanf.MustInts("xxxx") }) + assert.Equal(t, float64(1234), c.koanf.MustFloat64("parent1.id"), "get value mismatch") + + assert.Panics(t, func() { c.koanf.MustFloat64s("xxxx") }) + assert.Equal(t, []float64{1, 2, 3}, c.koanf.MustFloat64s("parent1.child1.grandchild1.ids"), "get value mismatch") + + assert.Panics(t, func() { c.koanf.MustFloat64Map("xxxx") }) + assert.Panics(t, func() { c.koanf.MustFloat64Map("parent1.boolmap") }) + assert.Equal(t, map[string]float64{"key1": 1.1, "key2": 1.2, "key3": 1.3}, c.koanf.MustFloat64Map("parent1.floatmap"), "get value mismatch") + assert.Equal(t, map[string]float64{"key1": 1, "key2": 1, "key3": 1}, c.koanf.MustFloat64Map("parent1.intmap"), "get value mismatch") + + // String and bytes. + assert.Panics(t, func() { c.koanf.MustBytes("xxxx") }) + assert.Equal(t, []byte("parent1"), c.koanf.MustBytes("parent1.name"), "get value mismatch") + + assert.Panics(t, func() { c.koanf.MustString("xxxx") }) + assert.Equal(t, "parent1", c.koanf.MustString("parent1.name"), "get value mismatch") + + assert.Panics(t, func() { c.koanf.MustStrings("xxxx") }) + assert.Equal(t, []string{"red", "blue", "orange"}, c.koanf.MustStrings("orphan"), "get value mismatch") + + assert.Panics(t, func() { c.koanf.MustStringMap("xxxx") }) + assert.Panics(t, func() { c.koanf.MustStringMap("parent1.intmap") }) + assert.Equal(t, map[string]string{"key1": "val1", "key2": "val2", "key3": "val3"}, c.koanf.MustStringMap("parent1.strmap"), "get value mismatch") + + // // Bools. + assert.Panics(t, func() { c.koanf.MustBools("xxxx") }) + assert.Equal(t, []bool{true, false, true}, c.koanf.MustBools("bools"), "get value mismatch") + assert.Equal(t, []bool{true, false, true}, c.koanf.MustBools("intbools"), "get value mismatch") + assert.Equal(t, []bool{true, true, false}, c.koanf.MustBools("strbools"), "get value mismatch") + + assert.Panics(t, func() { c.koanf.MustBoolMap("xxxx") }) + assert.Equal(t, map[string]bool{"ok1": true, "ok2": true, "notok3": false}, c.koanf.MustBoolMap("parent1.boolmap"), "get value mismatch") + assert.Equal(t, map[string]bool{"key1": true, "key2": true, "key3": true}, c.koanf.MustBoolMap("parent1.intmap"), "get value mismatch") + + // Others. + assert.Panics(t, func() { c.koanf.MustDuration("xxxx") }) + assert.Equal(t, time.Duration(1234), c.koanf.MustDuration("parent1.id"), "get value mismatch") + + assert.Panics(t, func() { c.koanf.MustTime("xxxx", "2006-01-02") }) + assert.Equal(t, time.Date(2019, 1, 1, 0, 0, 0, 0, time.UTC), c.koanf.MustTime("time", "2006-01-02"), "get value mismatch") + + // // Attempt to parse int=1234 as a Unix timestamp. + assert.Panics(t, func() { c.koanf.MustTime("time", "2006") }) + assert.Equal(t, time.Date(1970, 1, 1, 0, 20, 34, 0, time.UTC), c.koanf.MustTime("parent1.id", "").UTC(), "get value mismatch") + } +}