summaryrefslogtreecommitdiffstats
path: root/config/defaultConfigProvider_test.go
diff options
context:
space:
mode:
authorBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2021-06-09 10:58:18 +0200
committerBjørn Erik Pedersen <bjorn.erik.pedersen@gmail.com>2021-06-14 17:00:32 +0200
commitd392893cd73dc00c927f342778f6dca9628d328e (patch)
treee2ea3eec09f36b7122ecdbc498c3c130e240e85c /config/defaultConfigProvider_test.go
parenta886dd53b80322e1edf924f2ede4d4ea037c5baf (diff)
Misc config loading fixes
The main motivation behind this is simplicity and correctnes, but the new small config library is also faster: ``` BenchmarkDefaultConfigProvider/Viper-16 252418 4546 ns/op 2720 B/op 30 allocs/op BenchmarkDefaultConfigProvider/Custom-16 450756 2651 ns/op 1008 B/op 6 allocs/op ``` Fixes #8633 Fixes #8618 Fixes #8630 Updates #8591 Closes #6680 Closes #5192
Diffstat (limited to 'config/defaultConfigProvider_test.go')
-rw-r--r--config/defaultConfigProvider_test.go315
1 files changed, 315 insertions, 0 deletions
diff --git a/config/defaultConfigProvider_test.go b/config/defaultConfigProvider_test.go
new file mode 100644
index 000000000..834165d96
--- /dev/null
+++ b/config/defaultConfigProvider_test.go
@@ -0,0 +1,315 @@
+// Copyright 2021 The Hugo Authors. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package config
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "strconv"
+ "strings"
+ "testing"
+
+ "github.com/spf13/viper"
+
+ "github.com/gohugoio/hugo/common/para"
+
+ "github.com/gohugoio/hugo/common/maps"
+
+ qt "github.com/frankban/quicktest"
+)
+
+func TestDefaultConfigProvider(t *testing.T) {
+ c := qt.New(t)
+
+ c.Run("Set and get", func(c *qt.C) {
+ cfg := New()
+ var k string
+ var v interface{}
+
+ k, v = "foo", "bar"
+ cfg.Set(k, v)
+ c.Assert(cfg.Get(k), qt.Equals, v)
+ c.Assert(cfg.Get(strings.ToUpper(k)), qt.Equals, v)
+ c.Assert(cfg.GetString(k), qt.Equals, v)
+
+ k, v = "foo", 42
+ cfg.Set(k, v)
+ c.Assert(cfg.Get(k), qt.Equals, v)
+ c.Assert(cfg.GetInt(k), qt.Equals, v)
+
+ c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
+ "foo": 42,
+ })
+ })
+
+ c.Run("Set and get map", func(c *qt.C) {
+ cfg := New()
+
+ cfg.Set("foo", map[string]interface{}{
+ "bar": "baz",
+ })
+
+ c.Assert(cfg.Get("foo"), qt.DeepEquals, maps.Params{
+ "bar": "baz",
+ })
+
+ c.Assert(cfg.GetStringMap("foo"), qt.DeepEquals, map[string]interface{}{"bar": string("baz")})
+ c.Assert(cfg.GetStringMapString("foo"), qt.DeepEquals, map[string]string{"bar": string("baz")})
+ })
+
+ c.Run("Set and get nested", func(c *qt.C) {
+ cfg := New()
+
+ cfg.Set("a", map[string]interface{}{
+ "B": "bv",
+ })
+ cfg.Set("a.c", "cv")
+
+ c.Assert(cfg.Get("a"), qt.DeepEquals, maps.Params{
+ "b": "bv",
+ "c": "cv",
+ })
+ c.Assert(cfg.Get("a.c"), qt.Equals, "cv")
+
+ cfg.Set("b.a", "av")
+ c.Assert(cfg.Get("b"), qt.DeepEquals, maps.Params{
+ "a": "av",
+ })
+
+ cfg.Set("b", map[string]interface{}{
+ "b": "bv",
+ })
+
+ c.Assert(cfg.Get("b"), qt.DeepEquals, maps.Params{
+ "a": "av",
+ "b": "bv",
+ })
+
+ cfg = New()
+
+ cfg.Set("a", "av")
+
+ cfg.Set("", map[string]interface{}{
+ "a": "av2",
+ "b": "bv2",
+ })
+
+ c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
+ "a": "av2",
+ "b": "bv2",
+ })
+
+ cfg = New()
+
+ cfg.Set("a", "av")
+
+ cfg.Set("", map[string]interface{}{
+ "b": "bv2",
+ })
+
+ c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
+ "a": "av",
+ "b": "bv2",
+ })
+
+ cfg = New()
+
+ cfg.Set("", map[string]interface{}{
+ "foo": map[string]interface{}{
+ "a": "av",
+ },
+ })
+
+ cfg.Set("", map[string]interface{}{
+ "foo": map[string]interface{}{
+ "b": "bv2",
+ },
+ })
+
+ c.Assert(cfg.Get("foo"), qt.DeepEquals, maps.Params{
+ "a": "av",
+ "b": "bv2",
+ })
+ })
+
+ c.Run("Merge default strategy", func(c *qt.C) {
+ cfg := New()
+
+ cfg.Set("a", map[string]interface{}{
+ "B": "bv",
+ })
+
+ cfg.Merge("a", map[string]interface{}{
+ "B": "bv2",
+ "c": "cv2",
+ })
+
+ c.Assert(cfg.Get("a"), qt.DeepEquals, maps.Params{
+ "b": "bv",
+ "c": "cv2",
+ })
+
+ cfg = New()
+
+ cfg.Set("a", "av")
+
+ cfg.Merge("", map[string]interface{}{
+ "a": "av2",
+ "b": "bv2",
+ })
+
+ c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
+ "a": "av",
+ "b": "bv2",
+ })
+ })
+
+ c.Run("Merge shallow", func(c *qt.C) {
+ cfg := New()
+
+ cfg.Set("a", map[string]interface{}{
+ "_merge": "shallow",
+ "B": "bv",
+ "c": map[string]interface{}{
+ "b": "bv",
+ },
+ })
+
+ cfg.Merge("a", map[string]interface{}{
+ "c": map[string]interface{}{
+ "d": "dv2",
+ },
+ "e": "ev2",
+ })
+
+ c.Assert(cfg.Get("a"), qt.DeepEquals, maps.Params{
+ "e": "ev2",
+ "_merge": maps.ParamsMergeStrategyShallow,
+ "b": "bv",
+ "c": maps.Params{
+ "b": "bv",
+ },
+ })
+ })
+
+ c.Run("IsSet", func(c *qt.C) {
+ cfg := New()
+
+ cfg.Set("a", map[string]interface{}{
+ "B": "bv",
+ })
+
+ c.Assert(cfg.IsSet("A"), qt.IsTrue)
+ c.Assert(cfg.IsSet("a.b"), qt.IsTrue)
+ c.Assert(cfg.IsSet("z"), qt.IsFalse)
+ })
+
+ c.Run("Para", func(c *qt.C) {
+ cfg := New()
+ p := para.New(4)
+ r, _ := p.Start(context.Background())
+
+ setAndGet := func(k string, v int) error {
+ vs := strconv.Itoa(v)
+ cfg.Set(k, v)
+ err := errors.New("get failed")
+ if cfg.Get(k) != v {
+ return err
+ }
+ if cfg.GetInt(k) != v {
+ return err
+ }
+ if cfg.GetString(k) != vs {
+ return err
+ }
+ if !cfg.IsSet(k) {
+ return err
+ }
+ return nil
+ }
+
+ for i := 0; i < 20; i++ {
+ i := i
+ r.Run(func() error {
+ const v = 42
+ k := fmt.Sprintf("k%d", i)
+ if err := setAndGet(k, v); err != nil {
+ return err
+ }
+
+ m := maps.Params{
+ "new": 42,
+ }
+
+ cfg.Merge("", m)
+
+ return nil
+ })
+ }
+
+ c.Assert(r.Wait(), qt.IsNil)
+ })
+}
+
+func BenchmarkDefaultConfigProvider(b *testing.B) {
+ type cfger interface {
+ Get(key string) interface{}
+ Set(key string, value interface{})
+ IsSet(key string) bool
+ }
+
+ newMap := func() map[string]interface{} {
+ return map[string]interface{}{
+ "a": map[string]interface{}{
+ "b": map[string]interface{}{
+ "c": 32,
+ "d": 43,
+ },
+ },
+ "b": 62,
+ }
+ }
+
+ runMethods := func(b *testing.B, cfg cfger) {
+ m := newMap()
+ cfg.Set("mymap", m)
+ cfg.Set("num", 32)
+ if !(cfg.IsSet("mymap") && cfg.IsSet("mymap.a") && cfg.IsSet("mymap.a.b") && cfg.IsSet("mymap.a.b.c")) {
+ b.Fatal("IsSet failed")
+ }
+
+ if cfg.Get("num") != 32 {
+ b.Fatal("Get failed")
+ }
+
+ if cfg.Get("mymap.a.b.c") != 32 {
+ b.Fatal("Get failed")
+ }
+ }
+
+ b.Run("Viper", func(b *testing.B) {
+ v := viper.New()
+ for i := 0; i < b.N; i++ {
+ runMethods(b, v)
+ }
+ })
+
+ b.Run("Custom", func(b *testing.B) {
+ cfg := New()
+ for i := 0; i < b.N; i++ {
+ runMethods(b, cfg)
+ }
+ })
+}