...

Source file src/github.com/spf13/viper/overrides_test.go

Documentation: github.com/spf13/viper

     1  package viper
     2  
     3  import (
     4  	"strings"
     5  	"testing"
     6  
     7  	"github.com/spf13/cast"
     8  	"github.com/stretchr/testify/assert"
     9  )
    10  
    11  type layer int
    12  
    13  const (
    14  	defaultLayer layer = iota + 1
    15  	overrideLayer
    16  )
    17  
    18  func TestNestedOverrides(t *testing.T) {
    19  	assert := assert.New(t)
    20  	var v *Viper
    21  
    22  	// Case 0: value overridden by a value
    23  	overrideDefault(assert, "tom", 10, "tom", 20) // "tom" is first given 10 as default value, then overridden by 20
    24  	override(assert, "tom", 10, "tom", 20)        // "tom" is first given value 10, then overridden by 20
    25  	overrideDefault(assert, "tom.age", 10, "tom.age", 20)
    26  	override(assert, "tom.age", 10, "tom.age", 20)
    27  	overrideDefault(assert, "sawyer.tom.age", 10, "sawyer.tom.age", 20)
    28  	override(assert, "sawyer.tom.age", 10, "sawyer.tom.age", 20)
    29  
    30  	// Case 1: key:value overridden by a value
    31  	v = overrideDefault(assert, "tom.age", 10, "tom", "boy") // "tom.age" is first given 10 as default value, then "tom" is overridden by "boy"
    32  	assert.Nil(v.Get("tom.age"))                             // "tom.age" should not exist anymore
    33  	v = override(assert, "tom.age", 10, "tom", "boy")
    34  	assert.Nil(v.Get("tom.age"))
    35  
    36  	// Case 2: value overridden by a key:value
    37  	overrideDefault(assert, "tom", "boy", "tom.age", 10) // "tom" is first given "boy" as default value, then "tom" is overridden by map{"age":10}
    38  	override(assert, "tom.age", 10, "tom", "boy")
    39  
    40  	// Case 3: key:value overridden by a key:value
    41  	v = overrideDefault(assert, "tom.size", 4, "tom.age", 10)
    42  	assert.Equal(4, v.Get("tom.size")) // value should still be reachable
    43  	v = override(assert, "tom.size", 4, "tom.age", 10)
    44  	assert.Equal(4, v.Get("tom.size"))
    45  	deepCheckValue(assert, v, overrideLayer, []string{"tom", "size"}, 4)
    46  
    47  	// Case 4: key:value overridden by a map
    48  	v = overrideDefault(assert, "tom.size", 4, "tom", map[string]any{"age": 10}) // "tom.size" is first given "4" as default value, then "tom" is overridden by map{"age":10}
    49  	assert.Equal(4, v.Get("tom.size"))                                           // "tom.size" should still be reachable
    50  	assert.Equal(10, v.Get("tom.age"))                                           // new value should be there
    51  	deepCheckValue(assert, v, overrideLayer, []string{"tom", "age"}, 10)         // new value should be there
    52  	v = override(assert, "tom.size", 4, "tom", map[string]any{"age": 10})
    53  	assert.Nil(v.Get("tom.size"))
    54  	assert.Equal(10, v.Get("tom.age"))
    55  	deepCheckValue(assert, v, overrideLayer, []string{"tom", "age"}, 10)
    56  
    57  	// Case 5: array overridden by a value
    58  	overrideDefault(assert, "tom", []int{10, 20}, "tom", 30)
    59  	override(assert, "tom", []int{10, 20}, "tom", 30)
    60  	overrideDefault(assert, "tom.age", []int{10, 20}, "tom.age", 30)
    61  	override(assert, "tom.age", []int{10, 20}, "tom.age", 30)
    62  
    63  	// Case 6: array overridden by an array
    64  	overrideDefault(assert, "tom", []int{10, 20}, "tom", []int{30, 40})
    65  	override(assert, "tom", []int{10, 20}, "tom", []int{30, 40})
    66  	overrideDefault(assert, "tom.age", []int{10, 20}, "tom.age", []int{30, 40})
    67  	v = override(assert, "tom.age", []int{10, 20}, "tom.age", []int{30, 40})
    68  	// explicit array merge:
    69  	s, ok := v.Get("tom.age").([]int)
    70  	if assert.True(ok, "tom[\"age\"] is not a slice") {
    71  		v.Set("tom.age", append(s, []int{50, 60}...))
    72  		assert.Equal([]int{30, 40, 50, 60}, v.Get("tom.age"))
    73  		deepCheckValue(assert, v, overrideLayer, []string{"tom", "age"}, []int{30, 40, 50, 60})
    74  	}
    75  }
    76  
    77  func overrideDefault(assert *assert.Assertions, firstPath string, firstValue any, secondPath string, secondValue any) *Viper {
    78  	return overrideFromLayer(defaultLayer, assert, firstPath, firstValue, secondPath, secondValue)
    79  }
    80  
    81  func override(assert *assert.Assertions, firstPath string, firstValue any, secondPath string, secondValue any) *Viper {
    82  	return overrideFromLayer(overrideLayer, assert, firstPath, firstValue, secondPath, secondValue)
    83  }
    84  
    85  // overrideFromLayer performs the sequential override and low-level checks.
    86  //
    87  // First assignment is made on layer l for path firstPath with value firstValue,
    88  // the second one on the override layer (i.e., with the Set() function)
    89  // for path secondPath with value secondValue.
    90  //
    91  // firstPath and secondPath can include an arbitrary number of dots to indicate
    92  // a nested element.
    93  //
    94  // After each assignment, the value is checked, retrieved both by its full path
    95  // and by its key sequence (successive maps).
    96  func overrideFromLayer(l layer, assert *assert.Assertions, firstPath string, firstValue any, secondPath string, secondValue any) *Viper {
    97  	v := New()
    98  	firstKeys := strings.Split(firstPath, v.keyDelim)
    99  	if assert == nil ||
   100  		len(firstKeys) == 0 || firstKeys[0] == "" {
   101  		return v
   102  	}
   103  
   104  	// Set and check first value
   105  	switch l {
   106  	case defaultLayer:
   107  		v.SetDefault(firstPath, firstValue)
   108  	case overrideLayer:
   109  		v.Set(firstPath, firstValue)
   110  	default:
   111  		return v
   112  	}
   113  	assert.Equal(firstValue, v.Get(firstPath))
   114  	deepCheckValue(assert, v, l, firstKeys, firstValue)
   115  
   116  	// Override and check new value
   117  	secondKeys := strings.Split(secondPath, v.keyDelim)
   118  	if len(secondKeys) == 0 || secondKeys[0] == "" {
   119  		return v
   120  	}
   121  	v.Set(secondPath, secondValue)
   122  	assert.Equal(secondValue, v.Get(secondPath))
   123  	deepCheckValue(assert, v, overrideLayer, secondKeys, secondValue)
   124  
   125  	return v
   126  }
   127  
   128  // deepCheckValue checks that all given keys correspond to a valid path in the
   129  // configuration map of the given layer, and that the final value equals the one given.
   130  func deepCheckValue(assert *assert.Assertions, v *Viper, l layer, keys []string, value any) {
   131  	if assert == nil || v == nil ||
   132  		len(keys) == 0 || keys[0] == "" {
   133  		return
   134  	}
   135  
   136  	// init
   137  	var val any
   138  	var ms string
   139  	switch l {
   140  	case defaultLayer:
   141  		val = v.defaults
   142  		ms = "v.defaults"
   143  	case overrideLayer:
   144  		val = v.override
   145  		ms = "v.override"
   146  	}
   147  
   148  	// loop through map
   149  	var m map[string]any
   150  	for _, k := range keys {
   151  		if val == nil {
   152  			assert.Failf("%s is not a map[string]any", ms)
   153  			return
   154  		}
   155  
   156  		// deep scan of the map to get the final value
   157  		switch val := val.(type) {
   158  		case map[any]any:
   159  			m = cast.ToStringMap(val)
   160  		case map[string]any:
   161  			m = val
   162  		default:
   163  			assert.Failf("%s is not a map[string]any", ms)
   164  			return
   165  		}
   166  		ms = ms + "[\"" + k + "\"]"
   167  		val = m[k]
   168  	}
   169  	assert.Equal(value, val)
   170  }
   171  

View as plain text