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