github.com/gohugoio/hugo@v0.88.1/config/defaultConfigProvider_test.go (about)

     1  // Copyright 2021 The Hugo Authors. All rights reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  // http://www.apache.org/licenses/LICENSE-2.0
     7  //
     8  // Unless required by applicable law or agreed to in writing, software
     9  // distributed under the License is distributed on an "AS IS" BASIS,
    10  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package config
    15  
    16  import (
    17  	"context"
    18  	"errors"
    19  	"fmt"
    20  	"strconv"
    21  	"strings"
    22  	"testing"
    23  
    24  	"github.com/spf13/viper"
    25  
    26  	"github.com/gohugoio/hugo/common/para"
    27  
    28  	"github.com/gohugoio/hugo/common/maps"
    29  
    30  	qt "github.com/frankban/quicktest"
    31  )
    32  
    33  func TestDefaultConfigProvider(t *testing.T) {
    34  	c := qt.New(t)
    35  
    36  	c.Run("Set and get", func(c *qt.C) {
    37  		cfg := New()
    38  		var k string
    39  		var v interface{}
    40  
    41  		k, v = "foo", "bar"
    42  		cfg.Set(k, v)
    43  		c.Assert(cfg.Get(k), qt.Equals, v)
    44  		c.Assert(cfg.Get(strings.ToUpper(k)), qt.Equals, v)
    45  		c.Assert(cfg.GetString(k), qt.Equals, v)
    46  
    47  		k, v = "foo", 42
    48  		cfg.Set(k, v)
    49  		c.Assert(cfg.Get(k), qt.Equals, v)
    50  		c.Assert(cfg.GetInt(k), qt.Equals, v)
    51  
    52  		c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
    53  			"foo": 42,
    54  		})
    55  	})
    56  
    57  	c.Run("Set and get map", func(c *qt.C) {
    58  		cfg := New()
    59  
    60  		cfg.Set("foo", map[string]interface{}{
    61  			"bar": "baz",
    62  		})
    63  
    64  		c.Assert(cfg.Get("foo"), qt.DeepEquals, maps.Params{
    65  			"bar": "baz",
    66  		})
    67  
    68  		c.Assert(cfg.GetStringMap("foo"), qt.DeepEquals, map[string]interface{}{"bar": string("baz")})
    69  		c.Assert(cfg.GetStringMapString("foo"), qt.DeepEquals, map[string]string{"bar": string("baz")})
    70  	})
    71  
    72  	c.Run("Set and get nested", func(c *qt.C) {
    73  		cfg := New()
    74  
    75  		cfg.Set("a", map[string]interface{}{
    76  			"B": "bv",
    77  		})
    78  		cfg.Set("a.c", "cv")
    79  
    80  		c.Assert(cfg.Get("a"), qt.DeepEquals, maps.Params{
    81  			"b": "bv",
    82  			"c": "cv",
    83  		})
    84  		c.Assert(cfg.Get("a.c"), qt.Equals, "cv")
    85  
    86  		cfg.Set("b.a", "av")
    87  		c.Assert(cfg.Get("b"), qt.DeepEquals, maps.Params{
    88  			"a": "av",
    89  		})
    90  
    91  		cfg.Set("b", map[string]interface{}{
    92  			"b": "bv",
    93  		})
    94  
    95  		c.Assert(cfg.Get("b"), qt.DeepEquals, maps.Params{
    96  			"a": "av",
    97  			"b": "bv",
    98  		})
    99  
   100  		cfg = New()
   101  
   102  		cfg.Set("a", "av")
   103  
   104  		cfg.Set("", map[string]interface{}{
   105  			"a": "av2",
   106  			"b": "bv2",
   107  		})
   108  
   109  		c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
   110  			"a": "av2",
   111  			"b": "bv2",
   112  		})
   113  
   114  		cfg = New()
   115  
   116  		cfg.Set("a", "av")
   117  
   118  		cfg.Set("", map[string]interface{}{
   119  			"b": "bv2",
   120  		})
   121  
   122  		c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
   123  			"a": "av",
   124  			"b": "bv2",
   125  		})
   126  
   127  		cfg = New()
   128  
   129  		cfg.Set("", map[string]interface{}{
   130  			"foo": map[string]interface{}{
   131  				"a": "av",
   132  			},
   133  		})
   134  
   135  		cfg.Set("", map[string]interface{}{
   136  			"foo": map[string]interface{}{
   137  				"b": "bv2",
   138  			},
   139  		})
   140  
   141  		c.Assert(cfg.Get("foo"), qt.DeepEquals, maps.Params{
   142  			"a": "av",
   143  			"b": "bv2",
   144  		})
   145  	})
   146  
   147  	c.Run("Merge default strategy", func(c *qt.C) {
   148  		cfg := New()
   149  
   150  		cfg.Set("a", map[string]interface{}{
   151  			"B": "bv",
   152  		})
   153  
   154  		cfg.Merge("a", map[string]interface{}{
   155  			"B": "bv2",
   156  			"c": "cv2",
   157  		})
   158  
   159  		c.Assert(cfg.Get("a"), qt.DeepEquals, maps.Params{
   160  			"b": "bv",
   161  			"c": "cv2",
   162  		})
   163  
   164  		cfg = New()
   165  
   166  		cfg.Set("a", "av")
   167  
   168  		cfg.Merge("", map[string]interface{}{
   169  			"a": "av2",
   170  			"b": "bv2",
   171  		})
   172  
   173  		c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
   174  			"a": "av",
   175  		})
   176  	})
   177  
   178  	c.Run("Merge shallow", func(c *qt.C) {
   179  		cfg := New()
   180  
   181  		cfg.Set("a", map[string]interface{}{
   182  			"_merge": "shallow",
   183  			"B":      "bv",
   184  			"c": map[string]interface{}{
   185  				"b": "bv",
   186  			},
   187  		})
   188  
   189  		cfg.Merge("a", map[string]interface{}{
   190  			"c": map[string]interface{}{
   191  				"d": "dv2",
   192  			},
   193  			"e": "ev2",
   194  		})
   195  
   196  		c.Assert(cfg.Get("a"), qt.DeepEquals, maps.Params{
   197  			"e":      "ev2",
   198  			"_merge": maps.ParamsMergeStrategyShallow,
   199  			"b":      "bv",
   200  			"c": maps.Params{
   201  				"b": "bv",
   202  			},
   203  		})
   204  	})
   205  
   206  	// Issue #8679
   207  	c.Run("Merge typed maps", func(c *qt.C) {
   208  
   209  		for _, left := range []interface{}{
   210  			map[string]string{
   211  				"c": "cv1",
   212  			},
   213  			map[string]interface{}{
   214  				"c": "cv1",
   215  			},
   216  			map[interface{}]interface{}{
   217  				"c": "cv1",
   218  			},
   219  		} {
   220  			cfg := New()
   221  
   222  			cfg.Set("", map[string]interface{}{
   223  				"b": left,
   224  			})
   225  
   226  			cfg.Merge("", maps.Params{
   227  				"b": maps.Params{
   228  					"c": "cv2",
   229  					"d": "dv2",
   230  				},
   231  			})
   232  
   233  			c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
   234  				"b": maps.Params{
   235  					"c": "cv1",
   236  					"d": "dv2",
   237  				},
   238  			})
   239  		}
   240  
   241  		for _, left := range []interface{}{
   242  			map[string]string{
   243  				"b": "bv1",
   244  			},
   245  			map[string]interface{}{
   246  				"b": "bv1",
   247  			},
   248  			map[interface{}]interface{}{
   249  				"b": "bv1",
   250  			},
   251  		} {
   252  
   253  			for _, right := range []interface{}{
   254  				map[string]string{
   255  					"b": "bv2",
   256  					"c": "cv2",
   257  				},
   258  				map[string]interface{}{
   259  					"b": "bv2",
   260  					"c": "cv2",
   261  				},
   262  				map[interface{}]interface{}{
   263  					"b": "bv2",
   264  					"c": "cv2",
   265  				},
   266  			} {
   267  				cfg := New()
   268  
   269  				cfg.Set("a", left)
   270  
   271  				cfg.Merge("a", right)
   272  
   273  				c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
   274  					"a": maps.Params{
   275  						"b": "bv1",
   276  						"c": "cv2",
   277  					},
   278  				})
   279  			}
   280  
   281  		}
   282  
   283  	})
   284  
   285  	// Issue #8701
   286  	c.Run("Prevent _merge only maps", func(c *qt.C) {
   287  		cfg := New()
   288  
   289  		cfg.Set("", map[string]interface{}{
   290  			"B": "bv",
   291  		})
   292  
   293  		cfg.Merge("", map[string]interface{}{
   294  			"c": map[string]interface{}{
   295  				"_merge": "shallow",
   296  				"d":      "dv2",
   297  			},
   298  		})
   299  
   300  		c.Assert(cfg.Get(""), qt.DeepEquals, maps.Params{
   301  			"b": "bv",
   302  		})
   303  	})
   304  
   305  	c.Run("IsSet", func(c *qt.C) {
   306  		cfg := New()
   307  
   308  		cfg.Set("a", map[string]interface{}{
   309  			"B": "bv",
   310  		})
   311  
   312  		c.Assert(cfg.IsSet("A"), qt.IsTrue)
   313  		c.Assert(cfg.IsSet("a.b"), qt.IsTrue)
   314  		c.Assert(cfg.IsSet("z"), qt.IsFalse)
   315  	})
   316  
   317  	c.Run("Para", func(c *qt.C) {
   318  		cfg := New()
   319  		p := para.New(4)
   320  		r, _ := p.Start(context.Background())
   321  
   322  		setAndGet := func(k string, v int) error {
   323  			vs := strconv.Itoa(v)
   324  			cfg.Set(k, v)
   325  			err := errors.New("get failed")
   326  			if cfg.Get(k) != v {
   327  				return err
   328  			}
   329  			if cfg.GetInt(k) != v {
   330  				return err
   331  			}
   332  			if cfg.GetString(k) != vs {
   333  				return err
   334  			}
   335  			if !cfg.IsSet(k) {
   336  				return err
   337  			}
   338  			return nil
   339  		}
   340  
   341  		for i := 0; i < 20; i++ {
   342  			i := i
   343  			r.Run(func() error {
   344  				const v = 42
   345  				k := fmt.Sprintf("k%d", i)
   346  				if err := setAndGet(k, v); err != nil {
   347  					return err
   348  				}
   349  
   350  				m := maps.Params{
   351  					"new": 42,
   352  				}
   353  
   354  				cfg.Merge("", m)
   355  
   356  				return nil
   357  			})
   358  		}
   359  
   360  		c.Assert(r.Wait(), qt.IsNil)
   361  	})
   362  }
   363  
   364  func BenchmarkDefaultConfigProvider(b *testing.B) {
   365  	type cfger interface {
   366  		Get(key string) interface{}
   367  		Set(key string, value interface{})
   368  		IsSet(key string) bool
   369  	}
   370  
   371  	newMap := func() map[string]interface{} {
   372  		return map[string]interface{}{
   373  			"a": map[string]interface{}{
   374  				"b": map[string]interface{}{
   375  					"c": 32,
   376  					"d": 43,
   377  				},
   378  			},
   379  			"b": 62,
   380  		}
   381  	}
   382  
   383  	runMethods := func(b *testing.B, cfg cfger) {
   384  		m := newMap()
   385  		cfg.Set("mymap", m)
   386  		cfg.Set("num", 32)
   387  		if !(cfg.IsSet("mymap") && cfg.IsSet("mymap.a") && cfg.IsSet("mymap.a.b") && cfg.IsSet("mymap.a.b.c")) {
   388  			b.Fatal("IsSet failed")
   389  		}
   390  
   391  		if cfg.Get("num") != 32 {
   392  			b.Fatal("Get failed")
   393  		}
   394  
   395  		if cfg.Get("mymap.a.b.c") != 32 {
   396  			b.Fatal("Get failed")
   397  		}
   398  	}
   399  
   400  	b.Run("Viper", func(b *testing.B) {
   401  		v := viper.New()
   402  		for i := 0; i < b.N; i++ {
   403  			runMethods(b, v)
   404  		}
   405  	})
   406  
   407  	b.Run("Custom", func(b *testing.B) {
   408  		cfg := New()
   409  		for i := 0; i < b.N; i++ {
   410  			runMethods(b, cfg)
   411  		}
   412  	})
   413  }