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 }