github.com/vnforks/kid/v5@v5.22.1-0.20200408055009-b89d99c65676/utils/merge_test.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package utils_test 5 6 import ( 7 "fmt" 8 "reflect" 9 "testing" 10 11 "github.com/stretchr/testify/assert" 12 "github.com/stretchr/testify/require" 13 14 "github.com/vnforks/kid/v5/utils" 15 ) 16 17 // Test merging maps alone. This isolates the complexity of merging maps from merging maps recursively in 18 // a struct/ptr/etc. 19 // Remember that for our purposes, "merging" means replacing base with patch if patch is /anything/ other than nil. 20 func TestMergeWithMaps(t *testing.T) { 21 t.Run("merge maps where patch is longer", func(t *testing.T) { 22 m1 := map[string]int{"this": 1, "is": 2, "a map": 3} 23 m2 := map[string]int{"this": 1, "is": 3, "a second map": 3, "another key": 4} 24 25 expected := map[string]int{"this": 1, "is": 3, "a second map": 3, "another key": 4} 26 merged, err := mergeStringIntMap(m1, m2) 27 require.NoError(t, err) 28 29 assert.Equal(t, expected, merged) 30 }) 31 32 t.Run("merge maps where base is longer", func(t *testing.T) { 33 m1 := map[string]int{"this": 1, "is": 2, "a map": 3, "with": 4, "more keys": -12} 34 m2 := map[string]int{"this": 1, "is": 3, "a second map": 3} 35 expected := map[string]int{"this": 1, "is": 3, "a second map": 3} 36 37 merged, err := mergeStringIntMap(m1, m2) 38 require.NoError(t, err) 39 40 assert.Equal(t, expected, merged) 41 }) 42 43 t.Run("merge maps where base is empty", func(t *testing.T) { 44 m1 := make(map[string]int) 45 m2 := map[string]int{"this": 1, "is": 3, "a second map": 3, "another key": 4} 46 47 expected := map[string]int{"this": 1, "is": 3, "a second map": 3, "another key": 4} 48 merged, err := mergeStringIntMap(m1, m2) 49 require.NoError(t, err) 50 51 assert.Equal(t, expected, merged) 52 }) 53 54 t.Run("merge maps where patch is empty", func(t *testing.T) { 55 m1 := map[string]int{"this": 1, "is": 3, "a map": 3, "another key": 4} 56 var m2 map[string]int 57 expected := map[string]int{"this": 1, "is": 3, "a map": 3, "another key": 4} 58 59 merged, err := mergeStringIntMap(m1, m2) 60 require.NoError(t, err) 61 62 assert.Equal(t, expected, merged) 63 }) 64 65 t.Run("merge map[string]*int patch with different keys and values", func(t *testing.T) { 66 m1 := map[string]*int{"this": newInt(1), "is": newInt(3), "a key": newInt(3)} 67 m2 := map[string]*int{"this": newInt(2), "is": newInt(3), "a key": newInt(4)} 68 expected := map[string]*int{"this": newInt(2), "is": newInt(3), "a key": newInt(4)} 69 70 merged, err := mergeStringPtrIntMap(m1, m2) 71 require.NoError(t, err) 72 73 assert.Equal(t, expected, merged) 74 }) 75 76 t.Run("merge map[string]*int patch has nil keys -- doesn't matter, maps overwrite completely", func(t *testing.T) { 77 m1 := map[string]*int{"this": newInt(1), "is": newInt(3), "a key": newInt(3)} 78 m2 := map[string]*int{"this": newInt(1), "is": nil, "a key": newInt(3)} 79 expected := map[string]*int{"this": newInt(1), "is": nil, "a key": newInt(3)} 80 81 merged, err := mergeStringPtrIntMap(m1, m2) 82 require.NoError(t, err) 83 84 assert.Equal(t, expected, merged) 85 }) 86 87 t.Run("merge map[string]*int base has nil vals -- overwrite base with patch", func(t *testing.T) { 88 m1 := map[string]*int{"this": newInt(1), "is": nil, "base key": newInt(4)} 89 m2 := map[string]*int{"this": newInt(1), "is": newInt(3), "a key": newInt(3)} 90 expected := map[string]*int{"this": newInt(1), "is": newInt(3), "a key": newInt(3)} 91 92 merged, err := mergeStringPtrIntMap(m1, m2) 93 require.NoError(t, err) 94 95 assert.Equal(t, expected, merged) 96 }) 97 98 t.Run("merge map[string]*int base has nil vals -- but patch is nil, so keep base", func(t *testing.T) { 99 m1 := map[string]*int{"this": newInt(1), "is": nil, "base key": newInt(4)} 100 var m2 map[string]*int 101 expected := map[string]*int{"this": newInt(1), "is": nil, "base key": newInt(4)} 102 103 merged, err := mergeStringPtrIntMap(m1, m2) 104 require.NoError(t, err) 105 106 assert.Equal(t, expected, merged) 107 }) 108 109 t.Run("merge map[string]*int pointers are not copied - change in base do not affect merged", func(t *testing.T) { 110 // that should never happen, since patch overwrites completely 111 m1 := map[string]*int{"this": newInt(1), "is": newInt(3), "a key": newInt(4)} 112 m2 := map[string]*int{"this": newInt(1), "a key": newInt(5)} 113 expected := map[string]*int{"this": newInt(1), "a key": newInt(5)} 114 115 merged, err := mergeStringPtrIntMap(m1, m2) 116 require.NoError(t, err) 117 118 assert.Equal(t, expected, merged) 119 *m1["this"] = 6 120 assert.Equal(t, 1, *merged["this"]) 121 }) 122 123 t.Run("merge map[string]*int pointers are not copied - change in patched do not affect merged", func(t *testing.T) { 124 m1 := map[string]*int{"this": newInt(1), "is": newInt(3), "a key": newInt(4)} 125 m2 := map[string]*int{"this": newInt(2), "a key": newInt(5)} 126 expected := map[string]*int{"this": newInt(2), "a key": newInt(5)} 127 128 merged, err := mergeStringPtrIntMap(m1, m2) 129 require.NoError(t, err) 130 131 assert.Equal(t, expected, merged) 132 *m2["this"] = 6 133 assert.Equal(t, 2, *merged["this"]) 134 }) 135 136 t.Run("merge map[string][]int overwrite base with patch", func(t *testing.T) { 137 m1 := map[string][]int{"this": {1, 2, 3}, "is": {4, 5, 6}} 138 m2 := map[string][]int{"this": {1, 2, 3}, "new": {7, 8, 9}} 139 expected := map[string][]int{"this": {1, 2, 3}, "new": {7, 8, 9}} 140 141 merged, err := mergeStringSliceIntMap(m1, m2) 142 require.NoError(t, err) 143 144 assert.Equal(t, expected, merged) 145 }) 146 147 t.Run("merge map[string][]int nil in patch /does/ overwrite base", func(t *testing.T) { 148 m1 := map[string][]int{"this": {1, 2, 3}, "is": {4, 5, 6}} 149 m2 := map[string][]int{"this": {1, 2, 3}, "is": nil} 150 expected := map[string][]int{"this": {1, 2, 3}, "is": nil} 151 152 merged, err := mergeStringSliceIntMap(m1, m2) 153 require.NoError(t, err) 154 155 assert.Equal(t, expected, merged) 156 }) 157 158 t.Run("merge map[string][]int nil in base is overwritten", func(t *testing.T) { 159 m1 := map[string][]int{"this": {1, 2, 3}, "is": nil} 160 m2 := map[string][]int{"this": {1, 2, 3}, "is": {4, 5, 6}} 161 expected := map[string][]int{"this": {1, 2, 3}, "is": {4, 5, 6}} 162 merged, err := mergeStringSliceIntMap(m1, m2) 163 require.NoError(t, err) 164 165 assert.Equal(t, expected, merged) 166 }) 167 168 t.Run("merge map[string][]int nil in base is overwritten even without matching key", func(t *testing.T) { 169 m1 := map[string][]int{"this": {1, 2, 3}, "is": nil} 170 m2 := map[string][]int{"this": {1, 2, 3}, "new": {4, 5, 6}} 171 expected := map[string][]int{"this": {1, 2, 3}, "new": {4, 5, 6}} 172 173 merged, err := mergeStringSliceIntMap(m1, m2) 174 require.NoError(t, err) 175 176 assert.Equal(t, expected, merged) 177 }) 178 179 t.Run("merge map[string][]int slice is cloned - change in base does not affect merged", func(t *testing.T) { 180 // shouldn't, is patch clobbers 181 m1 := map[string][]int{"this": {1, 2, 3}, "is": {4, 5, 6}} 182 m2 := map[string][]int{"this": {1, 2, 3}, "new": {7, 8, 9}} 183 expected := map[string][]int{"this": {1, 2, 3}, "new": {7, 8, 9}} 184 185 merged, err := mergeStringSliceIntMap(m1, m2) 186 require.NoError(t, err) 187 188 assert.Equal(t, expected, merged) 189 m1["this"][0] = 99 190 assert.Equal(t, 1, merged["this"][0]) 191 }) 192 193 t.Run("merge map[string][]int slice is cloned - change in patch does not affect merged", func(t *testing.T) { 194 m1 := map[string][]int{"this": {1, 2, 3}, "is": {4, 5, 6}} 195 m2 := map[string][]int{"this": {1, 2, 3}, "new": {7, 8, 9}} 196 expected := map[string][]int{"this": {1, 2, 3}, "new": {7, 8, 9}} 197 198 merged, err := mergeStringSliceIntMap(m1, m2) 199 require.NoError(t, err) 200 201 assert.Equal(t, expected, merged) 202 m2["new"][1] = 0 203 assert.Equal(t, 8, merged["new"][1]) 204 }) 205 206 t.Run("merge map[string]map[string]*int", func(t *testing.T) { 207 m1 := map[string]map[string]*int{"this": {"second": newInt(99)}, "base": {"level": newInt(10)}} 208 m2 := map[string]map[string]*int{"this": {"second": newInt(77)}, "patch": {"level": newInt(15)}} 209 expected := map[string]map[string]*int{"this": {"second": newInt(77)}, "patch": {"level": newInt(15)}} 210 211 merged, err := mergeMapOfMap(m1, m2) 212 require.NoError(t, err) 213 214 assert.Equal(t, expected, merged) 215 }) 216 217 t.Run("merge map[string]map[string]*int, patch has nil keys -- /do/ overwrite base with nil", func(t *testing.T) { 218 m1 := map[string]map[string]*int{"this": {"second": newInt(99)}, "base": {"level": newInt(10)}} 219 m2 := map[string]map[string]*int{"this": {"second": nil}, "base": nil, "patch": {"level": newInt(15)}} 220 expected := map[string]map[string]*int{"this": {"second": nil}, "base": nil, "patch": {"level": newInt(15)}} 221 222 merged, err := mergeMapOfMap(m1, m2) 223 require.NoError(t, err) 224 225 assert.Equal(t, expected, merged) 226 }) 227 228 t.Run("merge map[string]map[string]*int, base has nil vals -- overwrite base with patch", func(t *testing.T) { 229 m1 := map[string]map[string]*int{"this": {"second": nil}, "base": nil} 230 m2 := map[string]map[string]*int{"this": {"second": newInt(77)}, "base": {"level": newInt(10)}, "patch": {"level": newInt(15)}} 231 expected := map[string]map[string]*int{"this": {"second": newInt(77)}, "base": {"level": newInt(10)}, "patch": {"level": newInt(15)}} 232 233 merged, err := mergeMapOfMap(m1, m2) 234 require.NoError(t, err) 235 236 assert.Equal(t, expected, merged) 237 }) 238 239 t.Run("merge map[string]map[string]*int, pointers are not copied - change in base does not affect merged", func(t *testing.T) { 240 // shouldn't, if we're overwriting completely 241 m1 := map[string]map[string]*int{"this": {"second": newInt(99)}, "base": {"level": newInt(10)}, "are belong": {"to us": newInt(23)}} 242 m2 := map[string]map[string]*int{"base": {"level": newInt(10)}} 243 expected := map[string]map[string]*int{"base": {"level": newInt(10)}} 244 245 merged, err := mergeMapOfMap(m1, m2) 246 require.NoError(t, err) 247 248 assert.Equal(t, expected, merged) 249 250 // test changing the map entry's referenced value 251 *m1["base"]["level"] = 347 252 assert.Equal(t, 10, *merged["base"]["level"]) 253 254 // test replacing map entry 255 m1["base"]["level"] = newInt(12) 256 assert.Equal(t, 10, *merged["base"]["level"]) 257 258 // test replacing a referenced map 259 m1["base"] = map[string]*int{"third": newInt(777)} 260 assert.Equal(t, 10, *merged["base"]["level"]) 261 262 }) 263 264 t.Run("merge map[string]map[string]*int, pointers are not copied - change in patch do not affect merged", func(t *testing.T) { 265 m1 := map[string]map[string]*int{"base": {"level": newInt(15)}} 266 m2 := map[string]map[string]*int{"this": {"second": newInt(99)}, "patch": {"level": newInt(10)}, 267 "are belong": {"to us": newInt(23)}} 268 expected := map[string]map[string]*int{"this": {"second": newInt(99)}, "patch": {"level": newInt(10)}, 269 "are belong": {"to us": newInt(23)}} 270 271 merged, err := mergeMapOfMap(m1, m2) 272 require.NoError(t, err) 273 274 assert.Equal(t, expected, merged) 275 276 // test replacing a referenced map 277 m2["this"] = map[string]*int{"third": newInt(777)} 278 assert.Equal(t, 99, *merged["this"]["second"]) 279 280 // test replacing map entry 281 m2["patch"]["level"] = newInt(12) 282 assert.Equal(t, 10, *merged["patch"]["level"]) 283 284 // test changing the map entry's referenced value 285 *m2["are belong"]["to us"] = 347 286 assert.Equal(t, 23, *merged["are belong"]["to us"]) 287 }) 288 289 t.Run("merge map[string]interface{}", func(t *testing.T) { 290 m1 := map[string]interface{}{"this": map[string]*int{"second": newInt(99)}, 291 "base": map[string]*int{"level": newInt(10)}} 292 m2 := map[string]interface{}{"this": map[string]*int{"second": newInt(77)}, 293 "patch": map[string]*int{"level": newInt(15)}} 294 expected := map[string]interface{}{"this": map[string]*int{"second": newInt(77)}, 295 "patch": map[string]*int{"level": newInt(15)}} 296 297 merged, err := mergeInterfaceMap(m1, m2) 298 require.NoError(t, err) 299 300 assert.Equal(t, expected, merged) 301 }) 302 303 t.Run("merge map[string]interface{}, patch has nil keys -- /do/ overwrite base with nil", func(t *testing.T) { 304 m1 := map[string]interface{}{"this": map[string]*int{"second": newInt(99)}} 305 m2 := map[string]interface{}{"this": map[string]*int{"second": nil}} 306 expected := map[string]interface{}{"this": map[string]*int{"second": nil}} 307 308 merged, err := mergeInterfaceMap(m1, m2) 309 require.NoError(t, err) 310 311 assert.Equal(t, expected, merged) 312 }) 313 314 t.Run("merge map[string]interface{}, patch has nil keys -- /do/ overwrite base with nil (more complex)", func(t *testing.T) { 315 m1 := map[string]interface{}{"this": map[string]*int{"second": newInt(99)}, 316 "base": map[string]*int{"level": newInt(10)}} 317 m2 := map[string]interface{}{"this": map[string]*int{"second": nil}, 318 "base": nil, "patch": map[string]*int{"level": newInt(15)}} 319 expected := map[string]interface{}{"this": map[string]*int{"second": nil}, 320 "base": nil, "patch": map[string]*int{"level": newInt(15)}} 321 322 merged, err := mergeInterfaceMap(m1, m2) 323 require.NoError(t, err) 324 325 assert.Equal(t, expected, merged) 326 }) 327 328 t.Run("merge map[string]map[string]*int, base has nil vals -- overwrite base with patch", func(t *testing.T) { 329 m1 := map[string]interface{}{"base": nil} 330 m2 := map[string]interface{}{"base": map[string]*int{"level": newInt(10)}} 331 expected := map[string]interface{}{"base": map[string]*int{"level": newInt(10)}} 332 333 merged, err := mergeInterfaceMap(m1, m2) 334 require.NoError(t, err) 335 336 assert.Equal(t, expected, merged) 337 }) 338 339 t.Run("merge map[string]map[string]*int, base has nil vals -- overwrite base with patch (more complex)", func(t *testing.T) { 340 m1 := map[string]interface{}{"this": map[string]*int{"second": nil}, "base": nil} 341 m2 := map[string]interface{}{"this": map[string]*int{"second": newInt(77)}, 342 "base": map[string]*int{"level": newInt(10)}, "patch": map[string]*int{"level": newInt(15)}} 343 expected := map[string]interface{}{"this": map[string]*int{"second": newInt(77)}, 344 "base": map[string]*int{"level": newInt(10)}, "patch": map[string]*int{"level": newInt(15)}} 345 346 merged, err := mergeInterfaceMap(m1, m2) 347 require.NoError(t, err) 348 349 assert.Equal(t, expected, merged) 350 }) 351 352 t.Run("merge map[string]interface{}, pointers are not copied - changes in base do not affect merged", func(t *testing.T) { 353 m1 := map[string]interface{}{"this": map[string]*int{"second": newInt(99)}, 354 "base": map[string]*int{"level": newInt(10)}, "are belong": map[string]*int{"to us": newInt(23)}} 355 m2 := map[string]interface{}{"this": map[string]*int{"second": newInt(99)}, 356 "base": map[string]*int{"level": newInt(10)}, "are belong": map[string]*int{"to us": newInt(23)}} 357 expected := map[string]interface{}{"this": map[string]*int{"second": newInt(99)}, 358 "base": map[string]*int{"level": newInt(10)}, "are belong": map[string]*int{"to us": newInt(23)}} 359 360 merged, err := mergeInterfaceMap(m1, m2) 361 require.NoError(t, err) 362 363 assert.Equal(t, expected, merged) 364 365 // test replacing a referenced map 366 m1["this"] = map[string]*int{"third": newInt(777)} 367 assert.Equal(t, 99, *merged["this"].(map[string]*int)["second"]) 368 369 // test replacing map entry 370 m1["base"].(map[string]*int)["level"] = newInt(12) 371 assert.Equal(t, 10, *merged["base"].(map[string]*int)["level"]) 372 373 // test changing the map entry's referenced value 374 *m1["are belong"].(map[string]*int)["to us"] = 347 375 assert.Equal(t, 23, *merged["are belong"].(map[string]*int)["to us"]) 376 }) 377 378 t.Run("merge map[string]interface{}, pointers are not copied - change in patch do not affect merged", func(t *testing.T) { 379 m1 := map[string]interface{}{"base": map[string]*int{"level": newInt(15)}} 380 m2 := map[string]interface{}{"this": map[string]*int{"second": newInt(99)}, 381 "patch": map[string]*int{"level": newInt(10)}, "are belong": map[string]*int{"to us": newInt(23)}} 382 expected := map[string]interface{}{"this": map[string]*int{"second": newInt(99)}, 383 "patch": map[string]*int{"level": newInt(10)}, "are belong": map[string]*int{"to us": newInt(23)}} 384 385 merged, err := mergeInterfaceMap(m1, m2) 386 require.NoError(t, err) 387 388 assert.Equal(t, expected, merged) 389 390 // test replacing a referenced map 391 m2["this"] = map[string]*int{"third": newInt(777)} 392 assert.Equal(t, 99, *merged["this"].(map[string]*int)["second"]) 393 394 // test replacing map entry 395 m2["patch"].(map[string]*int)["level"] = newInt(12) 396 assert.Equal(t, 10, *merged["patch"].(map[string]*int)["level"]) 397 398 // test changing the map entry's referenced value 399 *m2["are belong"].(map[string]*int)["to us"] = 347 400 assert.Equal(t, 23, *merged["are belong"].(map[string]*int)["to us"]) 401 }) 402 } 403 404 // Test merging slices alone. This isolates the complexity of merging slices from merging slices 405 // recursively in a struct/ptr/etc. 406 func TestMergeWithSlices(t *testing.T) { 407 t.Run("patch overwrites base slice", func(t *testing.T) { 408 m1 := []string{"this", "will", "be", "overwritten"} 409 m2 := []string{"this one", "will", "replace the other", "one", "and", "is", "longer"} 410 expected := []string{"this one", "will", "replace the other", "one", "and", "is", "longer"} 411 412 merged, err := mergeStringSlices(m1, m2) 413 require.NoError(t, err) 414 415 assert.Equal(t, expected, merged) 416 }) 417 418 t.Run("patch overwrites base even when base is longer", func(t *testing.T) { 419 m1 := []string{"this", "will", "be", "overwritten", "but", "not", "this"} 420 m2 := []string{"this one", "will", "replace the other", "one"} 421 expected := []string{"this one", "will", "replace the other", "one"} 422 423 merged, err := mergeStringSlices(m1, m2) 424 require.NoError(t, err) 425 426 assert.Equal(t, expected, merged) 427 }) 428 429 t.Run("patch overwrites when base is empty slice", func(t *testing.T) { 430 m1 := []string{} 431 m2 := []string{"this one", "will", "replace the other", "one"} 432 expected := []string{"this one", "will", "replace the other", "one"} 433 434 merged, err := mergeStringSlices(m1, m2) 435 require.NoError(t, err) 436 437 assert.Equal(t, expected, merged) 438 }) 439 440 t.Run("patch overwrites when base is nil", func(t *testing.T) { 441 var m1 []string 442 m2 := []string{"this one", "will", "replace the other", "one"} 443 expected := []string{"this one", "will", "replace the other", "one"} 444 445 merged, err := mergeStringSlices(m1, m2) 446 require.NoError(t, err) 447 448 assert.Equal(t, expected, merged) 449 }) 450 451 t.Run("patch overwites when patch is empty struct", func(t *testing.T) { 452 m1 := []string{"this", "will", "be", "overwritten"} 453 m2 := []string{} 454 expected := []string{} 455 456 merged, err := mergeStringSlices(m1, m2) 457 require.NoError(t, err) 458 459 assert.Equal(t, expected, merged) 460 }) 461 462 t.Run("use base where patch is nil", func(t *testing.T) { 463 m1 := []string{"this", "will", "not", "be", "overwritten"} 464 var m2 []string 465 expected := []string{"this", "will", "not", "be", "overwritten"} 466 467 merged, err := mergeStringSlices(m1, m2) 468 require.NoError(t, err) 469 470 assert.Equal(t, expected, merged) 471 }) 472 473 t.Run("return nil where both are nil", func(t *testing.T) { 474 var m1 []string 475 var m2 []string 476 expected := []string(nil) 477 478 merged, err := mergeStringSlices(m1, m2) 479 require.NoError(t, err) 480 481 assert.Equal(t, expected, merged) 482 }) 483 484 t.Run("return empty struct where both are empty", func(t *testing.T) { 485 m1 := []string{} 486 m2 := []string{} 487 expected := []string{} 488 489 merged, err := mergeStringSlices(m1, m2) 490 require.NoError(t, err) 491 492 assert.Equal(t, expected, merged) 493 }) 494 495 t.Run("patch is nil, slice is not copied. change in base will not affect merged", func(t *testing.T) { 496 m1 := []string{"this", "will", "not", "be", "overwritten"} 497 var m2 []string 498 expected := []string{"this", "will", "not", "be", "overwritten"} 499 500 merged, err := mergeStringSlices(m1, m2) 501 require.NoError(t, err) 502 503 assert.Equal(t, expected, merged) 504 m1[0] = "THAT" 505 assert.Equal(t, "this", merged[0]) 506 }) 507 508 t.Run("patch empty, slice is not copied. change in patch will not affect merged", func(t *testing.T) { 509 m1 := []string{"this", "will", "not", "be", "overwritten"} 510 m2 := []string{} 511 expected := []string{} 512 513 merged, err := mergeStringSlices(m1, m2) 514 require.NoError(t, err) 515 516 assert.Equal(t, expected, merged) 517 // of course this won't change merged, even if it did copy... but just in case. 518 m2 = append(m2, "test") 519 assert.Len(t, m2, 1) 520 assert.Empty(t, merged) 521 }) 522 523 t.Run("slice is not copied. change in patch will not affect merged", func(t *testing.T) { 524 var m1 []string 525 m2 := []string{"this", "will", "not", "be", "overwritten"} 526 expected := []string{"this", "will", "not", "be", "overwritten"} 527 528 merged, err := mergeStringSlices(m1, m2) 529 require.NoError(t, err) 530 531 assert.Equal(t, expected, merged) 532 m2[0] = "THAT" 533 assert.Equal(t, "this", merged[0]) 534 }) 535 536 t.Run("base overwritten, slice is not copied. change in patch will not affect merged", func(t *testing.T) { 537 m1 := []string{"this", "will", "be", "overwritten"} 538 m2 := []string{"that", "overwrote", "it"} 539 expected := []string{"that", "overwrote", "it"} 540 541 merged, err := mergeStringSlices(m1, m2) 542 require.NoError(t, err) 543 544 assert.Equal(t, expected, merged) 545 m2[0] = "THAT!!" 546 assert.Equal(t, "that", merged[0]) 547 }) 548 } 549 550 type evenSimpler struct { 551 B *bool 552 ES2 *evenSimpler2 553 } 554 555 func (e *evenSimpler) String() string { 556 if e == nil { 557 return "nil" 558 } 559 sb := "nil" 560 if e.B != nil { 561 sb = fmt.Sprintf("%t", *e.B) 562 } 563 return fmt.Sprintf("ES{B: %s, ES2: %s}", sb, e.ES2.String()) 564 } 565 566 type evenSimpler2 struct { 567 S *string 568 } 569 570 func (e *evenSimpler2) String() string { 571 if e == nil { 572 return "nil" 573 } 574 var s string 575 if e.S == nil { 576 s = "nil" 577 } else { 578 s = *e.S 579 } 580 return fmt.Sprintf("ES2{S: %s}", s) 581 } 582 583 func TestMergeWithEvenSimpler(t *testing.T) { 584 t.Run("evenSimplerStruct: base nils are overwritten by patch", func(t *testing.T) { 585 t1 := evenSimpler{newBool(true), &evenSimpler2{nil}} 586 t2 := evenSimpler{newBool(false), &evenSimpler2{newString("patch")}} 587 expected := evenSimpler{newBool(false), &evenSimpler2{newString("patch")}} 588 589 merged, err := mergeEvenSimpler(t1, t2) 590 require.NoError(t, err) 591 592 assert.Equal(t, expected, *merged) 593 }) 594 595 t.Run("evenSimplerStruct: patch nils are ignored", func(t *testing.T) { 596 t1 := evenSimpler{newBool(true), &evenSimpler2{newString("base")}} 597 t2 := evenSimpler{nil, &evenSimpler2{nil}} 598 expected := evenSimpler{newBool(true), &evenSimpler2{newString("base")}} 599 600 merged, err := mergeEvenSimpler(t1, t2) 601 require.NoError(t, err) 602 603 assert.Equal(t, expected, *merged) 604 }) 605 606 t.Run("evenSimplerStruct: can handle both nils, merged will have nil (not zero value)", func(t *testing.T) { 607 t1 := evenSimpler{nil, &evenSimpler2{nil}} 608 t2 := evenSimpler{nil, &evenSimpler2{nil}} 609 expected := evenSimpler{nil, &evenSimpler2{nil}} 610 611 merged, err := mergeEvenSimpler(t1, t2) 612 require.NoError(t, err) 613 614 assert.Equal(t, expected, *merged) 615 }) 616 617 t.Run("evenSimplerStruct: can handle both nils (ptr to ptr), merged will have nil (not zero value)", func(t *testing.T) { 618 t1 := evenSimpler{newBool(true), nil} 619 t2 := evenSimpler{newBool(true), nil} 620 expected := evenSimpler{newBool(true), nil} 621 622 merged, err := mergeEvenSimpler(t1, t2) 623 require.NoError(t, err) 624 625 assert.Equal(t, expected, *merged) 626 }) 627 628 t.Run("evenSimplerStruct: base nils (ptr to ptr) are overwritten by patch", func(t *testing.T) { 629 t1 := evenSimpler{newBool(true), nil} 630 t2 := evenSimpler{newBool(false), &evenSimpler2{newString("patch")}} 631 expected := evenSimpler{newBool(false), &evenSimpler2{newString("patch")}} 632 633 merged, err := mergeEvenSimpler(t1, t2) 634 require.NoError(t, err) 635 636 assert.Equal(t, expected, *merged) 637 }) 638 639 t.Run("evenSimplerStruct: base nils (ptr to ptr) are overwritten by patch, and not copied - changes in patch don't affect merged", func(t *testing.T) { 640 t1 := evenSimpler{newBool(true), nil} 641 t2 := evenSimpler{newBool(false), &evenSimpler2{newString("patch")}} 642 expected := evenSimpler{newBool(false), &evenSimpler2{newString("patch")}} 643 644 merged, err := mergeEvenSimpler(t1, t2) 645 require.NoError(t, err) 646 647 assert.Equal(t, expected, *merged) 648 *t2.ES2.S = "new patch" 649 assert.Equal(t, "patch", *merged.ES2.S) 650 }) 651 652 t.Run("evenSimplerStruct: patch nils (ptr to ptr) do not overwrite base, and are not copied - changes in base don't affect merged", func(t *testing.T) { 653 t1 := evenSimpler{newBool(true), &evenSimpler2{newString("base")}} 654 t2 := evenSimpler{newBool(false), nil} 655 expected := evenSimpler{newBool(false), &evenSimpler2{newString("base")}} 656 657 merged, err := mergeEvenSimpler(t1, t2) 658 require.NoError(t, err) 659 660 assert.Equal(t, expected, *merged) 661 *t1.ES2.S = "new base" 662 assert.Equal(t, "base", *merged.ES2.S) 663 }) 664 665 } 666 667 type sliceStruct struct { 668 Sls []string 669 } 670 671 func TestMergeWithSliceStruct(t *testing.T) { 672 t.Run("patch nils are ignored - sliceStruct", func(t *testing.T) { 673 t1 := sliceStruct{[]string{"this", "is", "base"}} 674 t2 := sliceStruct{nil} 675 expected := sliceStruct{[]string{"this", "is", "base"}} 676 677 merged, err := mergeSliceStruct(t1, t2) 678 require.NoError(t, err) 679 680 assert.Equal(t, expected, *merged) 681 }) 682 683 t.Run("base nils are overwritten by patch - sliceStruct", func(t *testing.T) { 684 t1 := sliceStruct{nil} 685 t2 := sliceStruct{[]string{"this", "is", "patch"}} 686 expected := sliceStruct{[]string{"this", "is", "patch"}} 687 688 merged, err := mergeSliceStruct(t1, t2) 689 require.NoError(t, err) 690 691 assert.Equal(t, expected, *merged) 692 }) 693 694 t.Run("slices are not being copied or modified", func(t *testing.T) { 695 t1 := sliceStruct{[]string{"this", "is", "base"}} 696 t2 := sliceStruct{nil} 697 expected := sliceStruct{[]string{"this", "is", "base"}} 698 699 merged, err := mergeSliceStruct(t1, t2) 700 require.NoError(t, err) 701 702 assert.Equal(t, expected, *merged) 703 704 // changes in base do not affect merged 705 t1.Sls[0] = "test0" 706 assert.Equal(t, "this", merged.Sls[0]) 707 708 // changes in merged (on slice that was cloned from base) do not affect base 709 merged.Sls[1] = "test222" 710 assert.Equal(t, "is", t1.Sls[1]) 711 }) 712 713 t.Run("slices are not being copied or modified", func(t *testing.T) { 714 t1 := sliceStruct{nil} 715 t2 := sliceStruct{[]string{"this", "is", "patch"}} 716 expected := sliceStruct{[]string{"this", "is", "patch"}} 717 718 merged, err := mergeSliceStruct(t1, t2) 719 require.NoError(t, err) 720 721 assert.Equal(t, expected, *merged) 722 723 // changes in patch do not affect merged 724 t2.Sls[0] = "test0" 725 assert.Equal(t, "this", merged.Sls[0]) 726 727 // changes in merged (on slice that was cloned from patch) do not affect patch 728 merged.Sls[1] = "test222" 729 assert.Equal(t, "is", t2.Sls[1]) 730 }) 731 } 732 733 type mapPtr struct { 734 MP map[string]*evenSimpler2 735 } 736 737 func TestMergeWithMapPtr(t *testing.T) { 738 t.Run("patch nils overwrite - mapPtr - maps overwrite completely", func(t *testing.T) { 739 t1 := mapPtr{map[string]*evenSimpler2{"base key": {newString("base")}}} 740 t2 := mapPtr{map[string]*evenSimpler2{"base key": {nil}}} 741 expected := mapPtr{map[string]*evenSimpler2{"base key": {nil}}} 742 743 merged, err := mergeMapPtr(t1, t2) 744 require.NoError(t, err) 745 746 assert.Equal(t, expected, *merged) 747 }) 748 749 t.Run("patch nil structs are ignored - mapPtr - maps overwrite ", func(t *testing.T) { 750 t1 := mapPtr{map[string]*evenSimpler2{"base key": {newString("base")}}} 751 t2 := mapPtr{map[string]*evenSimpler2{"base key": nil}} 752 expected := mapPtr{map[string]*evenSimpler2{"base key": nil}} 753 754 merged, err := mergeMapPtr(t1, t2) 755 require.NoError(t, err) 756 757 assert.Equal(t, expected, *merged) 758 }) 759 } 760 761 type mapPtrState struct { 762 MP map[string]*state 763 } 764 type state struct { 765 Enable bool 766 } 767 768 func TestMergeWithMapPtrState(t *testing.T) { 769 t.Run("inside structs, patch map overwrites completely - mapPtrState", func(t *testing.T) { 770 t1 := mapPtrState{map[string]*state{"base key": {true}}} 771 t2 := mapPtrState{map[string]*state{"base key": nil}} 772 expected := mapPtrState{map[string]*state{"base key": nil}} 773 774 merged, err := mergeMapPtrState(t1, t2) 775 require.NoError(t, err) 776 777 assert.Equal(t, expected, *merged) 778 }) 779 780 t.Run("merge identical structs - simple", func(t *testing.T) { 781 t1 := simple{42, 42.2, newFloat64(932.2), newInt(45), newBool(true), 782 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 783 simple2{30, newString("test"), []string{"test1", "test2"}}, 784 &simple2{40, newString("test2"), []string{"test3", "test4", "test5"}}} 785 t2 := simple{42, 42.2, newFloat64(932.2), newInt(45), newBool(true), 786 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 787 simple2{30, newString("test"), []string{"test1", "test2"}}, 788 &simple2{40, newString("test2"), []string{"test3", "test4", "test5"}}} 789 expected := simple{42, 0, nil, newInt(45), newBool(true), 790 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 791 simple2{30, newString("test"), []string{"test1", "test2"}}, 792 &simple2{40, newString("test2"), []string{"test3", "test4", "test5"}}} 793 794 merged, err := mergeSimple(t1, t2) 795 require.NoError(t, err) 796 797 assert.Equal(t, expected, *merged) 798 }) 799 800 t.Run("base nils are overwritten by patch", func(t *testing.T) { 801 t1 := simple{42, 42.2, newFloat64(932.2), newInt(45), nil, 802 []int{1, 2, 3}, nil, 803 simple2{30, nil, nil}, 804 nil} 805 t2 := simple{42, 42.2, newFloat64(932.2), newInt(45), newBool(true), 806 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 807 simple2{30, newString("test"), []string{"test1", "test2"}}, 808 &simple2{40, newString("test2"), []string{"test3", "test4", "test5"}}} 809 expected := simple{42, 0, nil, newInt(45), newBool(true), 810 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 811 simple2{30, newString("test"), []string{"test1", "test2"}}, 812 &simple2{40, newString("test2"), []string{"test3", "test4", "test5"}}} 813 814 merged, err := mergeSimple(t1, t2) 815 require.NoError(t, err) 816 817 assert.Equal(t, expected, *merged) 818 }) 819 } 820 821 type mapPtrState2 struct { 822 MP map[string]*state2 823 } 824 type state2 struct { 825 Enable bool 826 EPtr *bool 827 } 828 829 func TestMergeWithMapPtrState2(t *testing.T) { 830 t.Run("inside structs, maps overwrite completely - mapPtrState2", func(t *testing.T) { 831 t1 := mapPtrState2{map[string]*state2{"base key": {true, newBool(true)}}} 832 t2 := mapPtrState2{map[string]*state2{"base key": {false, nil}}} 833 expected := mapPtrState2{map[string]*state2{"base key": {false, nil}}} 834 835 merged, err := mergeMapPtrState2(t1, t2) 836 require.NoError(t, err) 837 838 assert.Equal(t, expected, *merged) 839 }) 840 841 t.Run("inside structs, maps overwrite completely - mapPtrState2 2", func(t *testing.T) { 842 t1 := mapPtrState2{map[string]*state2{"base key": {true, newBool(true)}}} // 843 t2 := mapPtrState2{map[string]*state2{"base key": nil}} 844 expected := mapPtrState2{map[string]*state2{"base key": nil}} 845 846 merged, err := mergeMapPtrState2(t1, t2) 847 require.NoError(t, err) 848 849 assert.Equal(t, expected, *merged) 850 }) 851 } 852 853 type simple struct { 854 I int 855 f float64 856 fp *float64 857 Ip *int 858 B *bool 859 Sli []int 860 Msi map[string]int 861 S2 simple2 862 S3 *simple2 863 } 864 865 type simple2 struct { 866 I int 867 S *string 868 Sls []string 869 } 870 871 func TestMergeWithSimpleStruct(t *testing.T) { 872 t.Run("patch nils are ignored", func(t *testing.T) { 873 t1 := simple{42, 42.2, newFloat64(932.2), newInt(45), newBool(true), 874 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 875 simple2{30, newString("test base"), []string{"test1", "test2"}}, 876 &simple2{40, newString("test2"), []string{"test3", "test4", "test5"}}} 877 t2 := simple{42, 42.2, newFloat64(932.2), nil, nil, 878 nil, nil, 879 simple2{30, nil, nil}, 880 &simple2{42, nil, nil}} 881 expected := simple{42, 0, nil, newInt(45), newBool(true), 882 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 883 simple2{30, newString("test base"), []string{"test1", "test2"}}, 884 &simple2{42, newString("test2"), []string{"test3", "test4", "test5"}}} 885 886 merged, err := mergeSimple(t1, t2) 887 require.NoError(t, err) 888 889 assert.Equal(t, expected, *merged) 890 }) 891 892 t.Run("patch nilled structs are ignored", func(t *testing.T) { 893 t1 := simple{42, 42.2, newFloat64(932.2), newInt(45), newBool(true), 894 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 895 simple2{30, newString("test base"), []string{"test1", "test2"}}, 896 &simple2{40, newString("test2"), []string{"test3", "test4", "test5"}}} 897 t2 := simple{42, 42.2, newFloat64(932.2), newInt(45), newBool(true), 898 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 899 simple2{30, newString("test base"), []string{"test1", "test2"}}, 900 nil} 901 expected := simple{42, 0, nil, newInt(45), newBool(true), 902 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 903 simple2{30, newString("test base"), []string{"test1", "test2"}}, 904 &simple2{40, newString("test2"), []string{"test3", "test4", "test5"}}} 905 906 merged, err := mergeSimple(t1, t2) 907 require.NoError(t, err) 908 909 assert.Equal(t, expected, *merged) 910 }) 911 912 t.Run("can handle both nils", func(t *testing.T) { 913 t1 := simple{42, 42.2, newFloat64(932.2), newInt(45), nil, 914 []int{1, 2, 3}, nil, 915 simple2{30, nil, nil}, 916 nil} 917 t2 := simple{42, 42.2, newFloat64(932.2), newInt(45), nil, 918 []int{1, 2, 3}, nil, 919 simple2{30, nil, nil}, 920 nil} 921 expected := simple{42, 0, nil, newInt(45), nil, 922 []int{1, 2, 3}, nil, 923 simple2{30, nil, nil}, 924 nil} 925 926 merged, err := mergeSimple(t1, t2) 927 require.NoError(t, err) 928 929 assert.Equal(t, expected, *merged) 930 }) 931 932 t.Run("different base vals are overwritten by patch, and unexported fields are ignored", func(t *testing.T) { 933 t1 := simple{42, 42.2, newFloat64(932.2), newInt(45), newBool(true), 934 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 935 simple2{30, newString("test"), []string{"test1", "test2"}}, 936 &simple2{40, newString("test2"), []string{"test3", "test4", "test5"}}} 937 t2 := simple{13, 53.1, newFloat64(932.2), newInt(46), newBool(false), 938 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 939 simple2{30, newString("testpatch"), []string{"test1", "test99"}}, 940 &simple2{45, nil, []string{"test3", "test123", "test5"}}} 941 expected := simple{13, 0, nil, newInt(46), newBool(false), 942 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 943 simple2{30, newString("testpatch"), []string{"test1", "test99"}}, 944 &simple2{45, newString("test2"), []string{"test3", "test123", "test5"}}} 945 946 merged, err := mergeSimple(t1, t2) 947 require.NoError(t, err) 948 949 assert.NotEqual(t, t1, *merged) 950 assert.Equal(t, expected, *merged) 951 }) 952 953 t.Run("pointers are not being copied or modified", func(t *testing.T) { 954 t1 := simple{42, 42.2, newFloat64(932.2), newInt(99), newBool(true), 955 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 956 simple2{30, newString("test"), []string{"test1", "test2"}}, 957 &simple2{40, newString("test2"), []string{"test3", "test4", "test5"}}} 958 t2 := simple{13, 53.1, newFloat64(932.2), nil, newBool(false), 959 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 960 simple2{30, newString("testpatch"), []string{"test1", "test2"}}, 961 &simple2{45, nil, []string{"test3", "test4", "test5"}}} 962 expected := simple{13, 0, nil, newInt(99), newBool(false), 963 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 964 simple2{30, newString("testpatch"), []string{"test1", "test2"}}, 965 &simple2{45, newString("test2"), []string{"test3", "test4", "test5"}}} 966 967 merged, err := mergeSimple(t1, t2) 968 require.NoError(t, err) 969 970 assert.NotEqual(t, t1, *merged) 971 assert.Equal(t, expected, *merged) 972 973 // changes in originals do not affect merged 974 *t1.S3.S = "testBASE" 975 assert.Equal(t, "test2", *merged.S3.S) 976 *t2.B = true 977 assert.Equal(t, false, *merged.B) 978 979 // changes in base do not affect patched 980 *t1.S2.S = "test from base" 981 assert.NotEqual(t, *t1.S2.S, *t2.S2.S) 982 983 // changes in merged (on pointers that were cloned from base or patch) do not affect base or patch 984 *merged.Ip = 0 985 assert.Equal(t, 99, *t1.Ip) 986 *merged.S2.S = "testMERGED" 987 assert.NotEqual(t, *t2.S2.S, *merged.S2.S) 988 }) 989 990 t.Run("slices are not being copied or modified", func(t *testing.T) { 991 t1 := simple{42, 42.2, newFloat64(932.2), newInt(99), newBool(true), 992 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 993 simple2{30, newString("test"), []string{"test1", "test2"}}, 994 &simple2{40, newString("test2"), []string{"test3", "test4", "test5"}}} 995 t2 := simple{13, 53.1, newFloat64(932.2), nil, newBool(false), 996 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 997 simple2{30, newString("testpatch"), nil}, 998 &simple2{45, nil, []string{"test3", "test4", "test99"}}} 999 expected := simple{13, 0, nil, newInt(99), newBool(false), 1000 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 1001 simple2{30, newString("testpatch"), []string{"test1", "test2"}}, 1002 &simple2{45, newString("test2"), []string{"test3", "test4", "test99"}}} 1003 1004 merged, err := mergeSimple(t1, t2) 1005 require.NoError(t, err) 1006 1007 assert.NotEqual(t, t1, *merged) 1008 assert.Equal(t, expected, *merged) 1009 1010 // changes in base do not affect merged 1011 t1.S2.Sls[0] = "test0" 1012 assert.Equal(t, "test1", merged.S2.Sls[0]) 1013 1014 // changes in patch do not affect merged 1015 t2.S3.Sls[0] = "test0" 1016 assert.Equal(t, "test3", merged.S3.Sls[0]) 1017 1018 // changes in merged (on slice that was cloned from base) do not affect base 1019 merged.S2.Sls[1] = "test222" 1020 assert.Equal(t, "test2", t1.S2.Sls[1]) 1021 }) 1022 1023 t.Run("maps are not being copied or modified: base -> merged", func(t *testing.T) { 1024 t1 := simple{42, 42.2, newFloat64(932.2), newInt(99), newBool(true), 1025 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 1026 simple2{30, newString("test"), []string{"test1", "test2"}}, 1027 &simple2{40, newString("test2"), []string{"test3", "test4", "test5"}}} 1028 t2 := simple{13, 53.1, newFloat64(932.2), nil, newBool(false), 1029 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 1030 simple2{30, newString("testpatch"), []string{"test1", "test2"}}, 1031 &simple2{45, nil, []string{"test3", "test4", "test99"}}} 1032 expected := simple{13, 0, nil, newInt(99), newBool(false), 1033 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2}, 1034 simple2{30, newString("testpatch"), []string{"test1", "test2"}}, 1035 &simple2{45, newString("test2"), []string{"test3", "test4", "test99"}}} 1036 1037 merged, err := mergeSimple(t1, t2) 1038 require.NoError(t, err) 1039 1040 assert.NotEqual(t, t1, *merged) 1041 assert.Equal(t, expected, *merged) 1042 1043 // changes in originals do not affect merged 1044 t1.Msi["key1"] = 3 1045 assert.Equal(t, 1, merged.Msi["key1"]) 1046 t2.Msi["key5"] = 5 1047 _, ok := merged.Msi["key5"] 1048 assert.False(t, ok) 1049 }) 1050 1051 t.Run("patch map overwrites", func(t *testing.T) { 1052 t1 := simple{42, 42.2, newFloat64(932.2), newInt(99), newBool(true), 1053 []int{1, 2, 3}, map[string]int{"key1": 1, "key2": 2, "key4": 4}, 1054 simple2{30, newString("test"), []string{"test1", "test2"}}, 1055 &simple2{40, newString("test2"), []string{"test3", "test4", "test5"}}} 1056 t2 := simple{13, 53.1, newFloat64(932.2), nil, newBool(false), 1057 []int{1, 2, 3}, map[string]int{"key1": 11, "key2": 2, "key3": 3}, 1058 simple2{30, newString("testpatch"), []string{"test1", "test2"}}, 1059 &simple2{45, nil, []string{"test3", "test4", "test99"}}} 1060 expected := simple{13, 0, nil, newInt(99), newBool(false), 1061 []int{1, 2, 3}, map[string]int{"key1": 11, "key2": 2, "key3": 3}, 1062 simple2{30, newString("testpatch"), []string{"test1", "test2"}}, 1063 &simple2{45, newString("test2"), []string{"test3", "test4", "test99"}}} 1064 1065 merged, err := mergeSimple(t1, t2) 1066 require.NoError(t, err) 1067 1068 assert.Equal(t, expected, *merged) 1069 }) 1070 } 1071 1072 // The following are tests to see if multiply nested structs/maps/slice and pointers to structs/maps/slices 1073 // will merge. Probably overkill, but if anything goes wrong here, it is best to isolate the problem and 1074 // make a simplified test (like many of the above tests). 1075 func TestMergeWithVeryComplexStruct(t *testing.T) { 1076 t.Run("merge identical structs", func(t *testing.T) { 1077 setupStructs(t) 1078 1079 merged, err := mergeTestStructs(base, patch) 1080 require.NoError(t, err) 1081 1082 assert.Equal(t, expectedMerged, *merged) 1083 }) 1084 1085 t.Run("merge identical structs as pointers", func(t *testing.T) { 1086 setupStructs(t) 1087 1088 merged, err := mergeTestStructsPtrs(&base, &patch) 1089 require.NoError(t, err) 1090 1091 assert.Equal(t, expectedMerged, *merged) 1092 }) 1093 1094 t.Run("different base vals are overwritten by patch", func(t *testing.T) { 1095 setupStructs(t) 1096 1097 base.F = 1342.12 1098 base.Struct1.Pi = newInt(937) 1099 base.Struct1p.Ui = 734 1100 base.Struct1.Struct2.Sli = []int{123123, 1243123} 1101 1102 merged, err := mergeTestStructs(base, patch) 1103 require.NoError(t, err) 1104 1105 assert.NotEqual(t, base, *merged) 1106 assert.Equal(t, patch, *merged) 1107 }) 1108 1109 t.Run("nil values in patch are ignored", func(t *testing.T) { 1110 setupStructs(t) 1111 1112 patch.Pi = nil 1113 patch.Struct1.Pi16 = nil 1114 1115 merged, err := mergeTestStructs(base, patch) 1116 require.NoError(t, err) 1117 1118 assert.NotEqual(t, patch, *merged) 1119 assert.Equal(t, expectedMerged, *merged) 1120 }) 1121 1122 t.Run("nil structs in patch are ignored", func(t *testing.T) { 1123 setupStructs(t) 1124 1125 patch.Struct1p = nil 1126 patch.Struct1.Struct2p = nil 1127 1128 merged, err := mergeTestStructs(base, patch) 1129 require.NoError(t, err) 1130 1131 assert.NotEqual(t, patch, *merged) 1132 assert.Equal(t, expectedMerged, *merged) 1133 }) 1134 1135 t.Run("nil slices in patch are ignored", func(t *testing.T) { 1136 setupStructs(t) 1137 1138 patch.Sls = nil 1139 patch.Struct1.Sli = nil 1140 patch.Struct1.Struct2p.Slf = nil 1141 1142 merged, err := mergeTestStructs(base, patch) 1143 require.NoError(t, err) 1144 1145 assert.NotEqual(t, patch, *merged) 1146 assert.Equal(t, expectedMerged, *merged) 1147 }) 1148 1149 t.Run("nil maps in patch are ignored", func(t *testing.T) { 1150 setupStructs(t) 1151 1152 patch.Msi = nil 1153 patch.Mspi = nil 1154 patch.Struct1.Mis = nil 1155 patch.Struct1.Struct2p.Mspi = nil 1156 1157 merged, err := mergeTestStructs(base, patch) 1158 require.NoError(t, err) 1159 1160 assert.NotEqual(t, patch, *merged) 1161 assert.Equal(t, expectedMerged, *merged) 1162 }) 1163 } 1164 1165 func TestMergeWithStructFieldFilter(t *testing.T) { 1166 t.Run("filter skips merging from patch", func(t *testing.T) { 1167 t1 := evenSimpler{newBool(true), &evenSimpler2{newString("base")}} 1168 t2 := evenSimpler{newBool(false), &evenSimpler2{newString("patch")}} 1169 expected := evenSimpler{newBool(true), &evenSimpler2{newString("base")}} 1170 1171 merged, err := mergeEvenSimplerWithConfig(t1, t2, &utils.MergeConfig{ 1172 StructFieldFilter: func(structField reflect.StructField, base, patch reflect.Value) bool { 1173 return false 1174 }, 1175 }) 1176 require.NoError(t, err) 1177 1178 assert.Equal(t, expected, *merged) 1179 }) 1180 1181 t.Run("filter skips merging configured fields from patch", func(t *testing.T) { 1182 t1 := evenSimpler{newBool(true), &evenSimpler2{newString("base")}} 1183 t2 := evenSimpler{newBool(false), &evenSimpler2{newString("patch")}} 1184 expected := evenSimpler{newBool(false), &evenSimpler2{newString("base")}} 1185 1186 merged, err := mergeEvenSimplerWithConfig(t1, t2, &utils.MergeConfig{ 1187 StructFieldFilter: func(structField reflect.StructField, base, patch reflect.Value) bool { 1188 return structField.Name == "B" 1189 }, 1190 }) 1191 require.NoError(t, err) 1192 1193 assert.Equal(t, expected, *merged) 1194 }) 1195 } 1196 1197 type testStruct struct { 1198 I int 1199 I8 int8 1200 I16 int16 1201 I32 int32 1202 I64 int64 1203 F float64 1204 F32 float32 1205 S string 1206 Ui uint 1207 Ui8 uint8 1208 Ui16 uint32 1209 Ui32 uint32 1210 Ui64 uint64 1211 Pi *int 1212 Pi8 *int8 1213 Pi16 *int16 1214 Pi32 *int32 1215 Pi64 *int64 1216 Pf *float64 1217 Pf32 *float32 1218 Ps *string 1219 Pui *uint 1220 Pui8 *uint8 1221 Pui16 *uint16 1222 Pui32 *uint32 1223 Pui64 *uint64 1224 Sls []string 1225 Sli []int 1226 Slf []float64 1227 Msi map[string]int 1228 Mis map[int]string 1229 Mspi map[string]*int 1230 Mips map[int]*string 1231 Struct1 testStructEmbed 1232 Struct1p *testStructEmbed 1233 } 1234 1235 type testStructEmbed struct { 1236 I int 1237 I8 int8 1238 I16 int16 1239 I32 int32 1240 I64 int64 1241 F float64 1242 F32 float32 1243 S string 1244 Ui uint 1245 Ui8 uint8 1246 Ui16 uint32 1247 Ui32 uint32 1248 Ui64 uint64 1249 Pi *int 1250 Pi8 *int8 1251 Pi16 *int16 1252 Pi32 *int32 1253 Pi64 *int64 1254 Pf *float64 1255 Pf32 *float32 1256 Ps *string 1257 Pui *uint 1258 Pui8 *uint8 1259 Pui16 *uint16 1260 Pui32 *uint32 1261 Pui64 *uint64 1262 Sls []string 1263 Sli []int 1264 Slf []float64 1265 Msi map[string]int 1266 Mis map[int]string 1267 Mspi map[string]*int 1268 Mips map[int]*string 1269 Struct2 testStructEmbed2 1270 Struct2p *testStructEmbed2 1271 } 1272 1273 type testStructEmbed2 struct { 1274 I int 1275 I8 int8 1276 I16 int16 1277 I32 int32 1278 I64 int64 1279 F float64 1280 F32 float32 1281 S string 1282 Ui uint 1283 Ui8 uint8 1284 Ui16 uint32 1285 Ui32 uint32 1286 Ui64 uint64 1287 Pi *int 1288 Pi8 *int8 1289 Pi16 *int16 1290 Pi32 *int32 1291 Pi64 *int64 1292 Pf *float64 1293 Pf32 *float32 1294 Ps *string 1295 Pui *uint 1296 Pui8 *uint8 1297 Pui16 *uint16 1298 Pui32 *uint32 1299 Pui64 *uint64 1300 Sls []string 1301 Sli []int 1302 Slf []float64 1303 Msi map[string]int 1304 Mis map[int]string 1305 Mspi map[string]*int 1306 Mips map[int]*string 1307 } 1308 1309 // the base structs 1310 var baseStructEmbed2A, baseStructEmbed2B, baseStructEmbed2C, baseStructEmbed2D testStructEmbed2 1311 var baseStructEmbedBaseA, baseStructEmbedBaseB testStructEmbed 1312 var base testStruct 1313 1314 // the patch structs 1315 var patchStructEmbed2A, patchStructEmbed2B, patchStructEmbed2C, patchStructEmbed2D testStructEmbed2 1316 var patchStructEmbedBaseA, patchStructEmbedBaseB testStructEmbed 1317 var patch testStruct 1318 1319 // The merged structs 1320 var mergeStructEmbed2A, mergeStructEmbed2B, mergeStructEmbed2C, mergeStructEmbed2D testStructEmbed2 1321 var mergeStructEmbedBaseA, mergeStructEmbedBaseB testStructEmbed 1322 var expectedMerged testStruct 1323 1324 func setupStructs(t *testing.T) { 1325 t.Helper() 1326 1327 baseStructEmbed2A = testStructEmbed2{1, 2, 3, 4, 5, 1.1, 2.2, "test", 10, 11, 12, 12, 13, 1328 newInt(14), newInt8(15), newInt16(16), newInt32(17), newInt64(18), 1329 newFloat64(19.9), newFloat32(20.1), newString("test pointer"), 1330 newUint(21), newUint8(22), newUint16(23), newUint32(24), newUint64(25), 1331 []string{"test", "slice", "strings"}, []int{1, 2, 3, 4}, []float64{1.1, 2.2, 3.3}, 1332 map[string]int{"this": 1, "is": 2, "a": 3, "map": 4}, map[int]string{1: "this", 2: "is", 3: "another"}, 1333 map[string]*int{"wow": newInt(1), "a map": newInt(2), "of pointers!": newInt(3)}, 1334 map[int]*string{1: newString("Another"), 2: newString("map of"), 3: newString("pointers, wow!")}, 1335 } 1336 1337 baseStructEmbed2B = testStructEmbed2{1, 2, 3, 4, 5, 1.1, 2.2, "test", 10, 11, 12, 12, 13, 1338 newInt(14), newInt8(15), newInt16(16), newInt32(17), newInt64(18), 1339 newFloat64(19.9), newFloat32(20.1), newString("test pointer"), 1340 newUint(21), newUint8(22), newUint16(23), newUint32(24), newUint64(25), 1341 []string{"test", "slice", "strings"}, []int{1, 2, 3, 4}, []float64{1.1, 2.2, 3.3}, 1342 map[string]int{"this": 1, "is": 2, "a": 3, "map": 4}, map[int]string{1: "this", 2: "is", 3: "another"}, 1343 map[string]*int{"wow": newInt(1), "a map": newInt(2), "of pointers!": newInt(3)}, 1344 map[int]*string{1: newString("Another"), 2: newString("map of"), 3: newString("pointers, wow!")}, 1345 } 1346 1347 baseStructEmbed2C = testStructEmbed2{1, 2, 3, 4, 5, 1.1, 2.2, "test", 10, 11, 12, 12, 13, 1348 newInt(14), newInt8(15), newInt16(16), newInt32(17), newInt64(18), 1349 newFloat64(19.9), newFloat32(20.1), newString("test pointer"), 1350 newUint(21), newUint8(22), newUint16(23), newUint32(24), newUint64(25), 1351 []string{"test", "slice", "strings"}, []int{1, 2, 3, 4}, []float64{1.1, 2.2, 3.3}, 1352 map[string]int{"this": 1, "is": 2, "a": 3, "map": 4}, map[int]string{1: "this", 2: "is", 3: "another"}, 1353 map[string]*int{"wow": newInt(1), "a map": newInt(2), "of pointers!": newInt(3)}, 1354 map[int]*string{1: newString("Another"), 2: newString("map of"), 3: newString("pointers, wow!")}, 1355 } 1356 1357 baseStructEmbed2D = testStructEmbed2{1, 2, 3, 4, 5, 1.1, 2.2, "test", 10, 11, 12, 12, 13, 1358 newInt(14), newInt8(15), newInt16(16), newInt32(17), newInt64(18), 1359 newFloat64(19.9), newFloat32(20.1), newString("test pointer"), 1360 newUint(21), newUint8(22), newUint16(23), newUint32(24), newUint64(25), 1361 []string{"test", "slice", "strings"}, []int{1, 2, 3, 4}, []float64{1.1, 2.2, 3.3}, 1362 map[string]int{"this": 1, "is": 2, "a": 3, "map": 4}, map[int]string{1: "this", 2: "is", 3: "another"}, 1363 map[string]*int{"wow": newInt(1), "a map": newInt(2), "of pointers!": newInt(3)}, 1364 map[int]*string{1: newString("Another"), 2: newString("map of"), 3: newString("pointers, wow!")}, 1365 } 1366 1367 baseStructEmbedBaseA = testStructEmbed{1, 2, 3, 4, 5, 1.1, 2.2, "test", 10, 11, 12, 12, 13, 1368 newInt(14), newInt8(15), newInt16(16), newInt32(17), newInt64(18), 1369 newFloat64(19.9), newFloat32(20.1), newString("test pointer"), 1370 newUint(21), newUint8(22), newUint16(23), newUint32(24), newUint64(25), 1371 []string{"test", "slice", "strings"}, []int{1, 2, 3, 4}, []float64{1.1, 2.2, 3.3}, 1372 map[string]int{"this": 1, "is": 2, "a": 3, "map": 4}, map[int]string{1: "this", 2: "is", 3: "another"}, 1373 map[string]*int{"wow": newInt(1), "a map": newInt(2), "of pointers!": newInt(3)}, 1374 map[int]*string{1: newString("Another"), 2: newString("map of"), 3: newString("pointers, wow!")}, 1375 baseStructEmbed2A, &baseStructEmbed2B, 1376 } 1377 1378 baseStructEmbedBaseB = testStructEmbed{1, 2, 3, 4, 5, 1.1, 2.2, "test", 10, 11, 12, 12, 13, 1379 newInt(14), newInt8(15), newInt16(16), newInt32(17), newInt64(18), 1380 newFloat64(19.9), newFloat32(20.1), newString("test pointer"), 1381 newUint(21), newUint8(22), newUint16(23), newUint32(24), newUint64(25), 1382 []string{"test", "slice", "strings"}, []int{1, 2, 3, 4}, []float64{1.1, 2.2, 3.3}, 1383 map[string]int{"this": 1, "is": 2, "a": 3, "map": 4}, map[int]string{1: "this", 2: "is", 3: "another"}, 1384 map[string]*int{"wow": newInt(1), "a map": newInt(2), "of pointers!": newInt(3)}, 1385 map[int]*string{1: newString("Another"), 2: newString("map of"), 3: newString("pointers, wow!")}, 1386 baseStructEmbed2C, &baseStructEmbed2D, 1387 } 1388 1389 base = testStruct{1, 2, 3, 4, 5, 1.1, 2.2, "test", 10, 11, 12, 12, 13, 1390 newInt(14), newInt8(15), newInt16(16), newInt32(17), newInt64(18), 1391 newFloat64(19.9), newFloat32(20.1), newString("test pointer"), 1392 newUint(21), newUint8(22), newUint16(23), newUint32(24), newUint64(25), 1393 []string{"test", "slice", "strings"}, []int{1, 2, 3, 4}, []float64{1.1, 2.2, 3.3}, 1394 map[string]int{"this": 1, "is": 2, "a": 3, "map": 4}, map[int]string{1: "this", 2: "is", 3: "another"}, 1395 map[string]*int{"wow": newInt(1), "a map": newInt(2), "of pointers!": newInt(3)}, 1396 map[int]*string{1: newString("Another"), 2: newString("map of"), 3: newString("pointers, wow!")}, 1397 baseStructEmbedBaseA, &baseStructEmbedBaseB, 1398 } 1399 1400 patchStructEmbed2A = testStructEmbed2{1, 2, 3, 4, 5, 1.1, 2.2, "test", 10, 11, 12, 12, 13, 1401 newInt(14), newInt8(15), newInt16(16), newInt32(17), newInt64(18), 1402 newFloat64(19.9), newFloat32(20.1), newString("test pointer"), 1403 newUint(21), newUint8(22), newUint16(23), newUint32(24), newUint64(25), 1404 []string{"test", "slice", "strings"}, []int{1, 2, 3, 4}, []float64{1.1, 2.2, 3.3}, 1405 map[string]int{"this": 1, "is": 2, "a": 3, "map": 4}, map[int]string{1: "this", 2: "is", 3: "another"}, 1406 map[string]*int{"wow": newInt(1), "a map": newInt(2), "of pointers!": newInt(3)}, 1407 map[int]*string{1: newString("Another"), 2: newString("map of"), 3: newString("pointers, wow!")}, 1408 } 1409 1410 patchStructEmbed2B = testStructEmbed2{1, 2, 3, 4, 5, 1.1, 2.2, "test", 10, 11, 12, 12, 13, 1411 newInt(14), newInt8(15), newInt16(16), newInt32(17), newInt64(18), 1412 newFloat64(19.9), newFloat32(20.1), newString("test pointer"), 1413 newUint(21), newUint8(22), newUint16(23), newUint32(24), newUint64(25), 1414 []string{"test", "slice", "strings"}, []int{1, 2, 3, 4}, []float64{1.1, 2.2, 3.3}, 1415 map[string]int{"this": 1, "is": 2, "a": 3, "map": 4}, map[int]string{1: "this", 2: "is", 3: "another"}, 1416 map[string]*int{"wow": newInt(1), "a map": newInt(2), "of pointers!": newInt(3)}, 1417 map[int]*string{1: newString("Another"), 2: newString("map of"), 3: newString("pointers, wow!")}, 1418 } 1419 1420 patchStructEmbed2C = testStructEmbed2{1, 2, 3, 4, 5, 1.1, 2.2, "test", 10, 11, 12, 12, 13, 1421 newInt(14), newInt8(15), newInt16(16), newInt32(17), newInt64(18), 1422 newFloat64(19.9), newFloat32(20.1), newString("test pointer"), 1423 newUint(21), newUint8(22), newUint16(23), newUint32(24), newUint64(25), 1424 []string{"test", "slice", "strings"}, []int{1, 2, 3, 4}, []float64{1.1, 2.2, 3.3}, 1425 map[string]int{"this": 1, "is": 2, "a": 3, "map": 4}, map[int]string{1: "this", 2: "is", 3: "another"}, 1426 map[string]*int{"wow": newInt(1), "a map": newInt(2), "of pointers!": newInt(3)}, 1427 map[int]*string{1: newString("Another"), 2: newString("map of"), 3: newString("pointers, wow!")}, 1428 } 1429 1430 patchStructEmbed2D = testStructEmbed2{1, 2, 3, 4, 5, 1.1, 2.2, "test", 10, 11, 12, 12, 13, 1431 newInt(14), newInt8(15), newInt16(16), newInt32(17), newInt64(18), 1432 newFloat64(19.9), newFloat32(20.1), newString("test pointer"), 1433 newUint(21), newUint8(22), newUint16(23), newUint32(24), newUint64(25), 1434 []string{"test", "slice", "strings"}, []int{1, 2, 3, 4}, []float64{1.1, 2.2, 3.3}, 1435 map[string]int{"this": 1, "is": 2, "a": 3, "map": 4}, map[int]string{1: "this", 2: "is", 3: "another"}, 1436 map[string]*int{"wow": newInt(1), "a map": newInt(2), "of pointers!": newInt(3)}, 1437 map[int]*string{1: newString("Another"), 2: newString("map of"), 3: newString("pointers, wow!")}, 1438 } 1439 1440 patchStructEmbedBaseA = testStructEmbed{1, 2, 3, 4, 5, 1.1, 2.2, "test", 10, 11, 12, 12, 13, 1441 newInt(14), newInt8(15), newInt16(16), newInt32(17), newInt64(18), 1442 newFloat64(19.9), newFloat32(20.1), newString("test pointer"), 1443 newUint(21), newUint8(22), newUint16(23), newUint32(24), newUint64(25), 1444 []string{"test", "slice", "strings"}, []int{1, 2, 3, 4}, []float64{1.1, 2.2, 3.3}, 1445 map[string]int{"this": 1, "is": 2, "a": 3, "map": 4}, map[int]string{1: "this", 2: "is", 3: "another"}, 1446 map[string]*int{"wow": newInt(1), "a map": newInt(2), "of pointers!": newInt(3)}, 1447 map[int]*string{1: newString("Another"), 2: newString("map of"), 3: newString("pointers, wow!")}, 1448 patchStructEmbed2A, &patchStructEmbed2B, 1449 } 1450 1451 patchStructEmbedBaseB = testStructEmbed{1, 2, 3, 4, 5, 1.1, 2.2, "test", 10, 11, 12, 12, 13, 1452 newInt(14), newInt8(15), newInt16(16), newInt32(17), newInt64(18), 1453 newFloat64(19.9), newFloat32(20.1), newString("test pointer"), 1454 newUint(21), newUint8(22), newUint16(23), newUint32(24), newUint64(25), 1455 []string{"test", "slice", "strings"}, []int{1, 2, 3, 4}, []float64{1.1, 2.2, 3.3}, 1456 map[string]int{"this": 1, "is": 2, "a": 3, "map": 4}, map[int]string{1: "this", 2: "is", 3: "another"}, 1457 map[string]*int{"wow": newInt(1), "a map": newInt(2), "of pointers!": newInt(3)}, 1458 map[int]*string{1: newString("Another"), 2: newString("map of"), 3: newString("pointers, wow!")}, 1459 patchStructEmbed2C, &patchStructEmbed2D, 1460 } 1461 1462 patch = testStruct{1, 2, 3, 4, 5, 1.1, 2.2, "test", 10, 11, 12, 12, 13, 1463 newInt(14), newInt8(15), newInt16(16), newInt32(17), newInt64(18), 1464 newFloat64(19.9), newFloat32(20.1), newString("test pointer"), 1465 newUint(21), newUint8(22), newUint16(23), newUint32(24), newUint64(25), 1466 []string{"test", "slice", "strings"}, []int{1, 2, 3, 4}, []float64{1.1, 2.2, 3.3}, 1467 map[string]int{"this": 1, "is": 2, "a": 3, "map": 4}, map[int]string{1: "this", 2: "is", 3: "another"}, 1468 map[string]*int{"wow": newInt(1), "a map": newInt(2), "of pointers!": newInt(3)}, 1469 map[int]*string{1: newString("Another"), 2: newString("map of"), 3: newString("pointers, wow!")}, 1470 patchStructEmbedBaseA, &patchStructEmbedBaseB, 1471 } 1472 1473 mergeStructEmbed2A = testStructEmbed2{1, 2, 3, 4, 5, 1.1, 2.2, "test", 10, 11, 12, 12, 13, 1474 newInt(14), newInt8(15), newInt16(16), newInt32(17), newInt64(18), 1475 newFloat64(19.9), newFloat32(20.1), newString("test pointer"), 1476 newUint(21), newUint8(22), newUint16(23), newUint32(24), newUint64(25), 1477 []string{"test", "slice", "strings"}, []int{1, 2, 3, 4}, []float64{1.1, 2.2, 3.3}, 1478 map[string]int{"this": 1, "is": 2, "a": 3, "map": 4}, map[int]string{1: "this", 2: "is", 3: "another"}, 1479 map[string]*int{"wow": newInt(1), "a map": newInt(2), "of pointers!": newInt(3)}, 1480 map[int]*string{1: newString("Another"), 2: newString("map of"), 3: newString("pointers, wow!")}, 1481 } 1482 1483 mergeStructEmbed2B = testStructEmbed2{1, 2, 3, 4, 5, 1.1, 2.2, "test", 10, 11, 12, 12, 13, 1484 newInt(14), newInt8(15), newInt16(16), newInt32(17), newInt64(18), 1485 newFloat64(19.9), newFloat32(20.1), newString("test pointer"), 1486 newUint(21), newUint8(22), newUint16(23), newUint32(24), newUint64(25), 1487 []string{"test", "slice", "strings"}, []int{1, 2, 3, 4}, []float64{1.1, 2.2, 3.3}, 1488 map[string]int{"this": 1, "is": 2, "a": 3, "map": 4}, map[int]string{1: "this", 2: "is", 3: "another"}, 1489 map[string]*int{"wow": newInt(1), "a map": newInt(2), "of pointers!": newInt(3)}, 1490 map[int]*string{1: newString("Another"), 2: newString("map of"), 3: newString("pointers, wow!")}, 1491 } 1492 1493 mergeStructEmbed2C = testStructEmbed2{1, 2, 3, 4, 5, 1.1, 2.2, "test", 10, 11, 12, 12, 13, 1494 newInt(14), newInt8(15), newInt16(16), newInt32(17), newInt64(18), 1495 newFloat64(19.9), newFloat32(20.1), newString("test pointer"), 1496 newUint(21), newUint8(22), newUint16(23), newUint32(24), newUint64(25), 1497 []string{"test", "slice", "strings"}, []int{1, 2, 3, 4}, []float64{1.1, 2.2, 3.3}, 1498 map[string]int{"this": 1, "is": 2, "a": 3, "map": 4}, map[int]string{1: "this", 2: "is", 3: "another"}, 1499 map[string]*int{"wow": newInt(1), "a map": newInt(2), "of pointers!": newInt(3)}, 1500 map[int]*string{1: newString("Another"), 2: newString("map of"), 3: newString("pointers, wow!")}, 1501 } 1502 1503 mergeStructEmbed2D = testStructEmbed2{1, 2, 3, 4, 5, 1.1, 2.2, "test", 10, 11, 12, 12, 13, 1504 newInt(14), newInt8(15), newInt16(16), newInt32(17), newInt64(18), 1505 newFloat64(19.9), newFloat32(20.1), newString("test pointer"), 1506 newUint(21), newUint8(22), newUint16(23), newUint32(24), newUint64(25), 1507 []string{"test", "slice", "strings"}, []int{1, 2, 3, 4}, []float64{1.1, 2.2, 3.3}, 1508 map[string]int{"this": 1, "is": 2, "a": 3, "map": 4}, map[int]string{1: "this", 2: "is", 3: "another"}, 1509 map[string]*int{"wow": newInt(1), "a map": newInt(2), "of pointers!": newInt(3)}, 1510 map[int]*string{1: newString("Another"), 2: newString("map of"), 3: newString("pointers, wow!")}, 1511 } 1512 1513 mergeStructEmbedBaseA = testStructEmbed{1, 2, 3, 4, 5, 1.1, 2.2, "test", 10, 11, 12, 12, 13, 1514 newInt(14), newInt8(15), newInt16(16), newInt32(17), newInt64(18), 1515 newFloat64(19.9), newFloat32(20.1), newString("test pointer"), 1516 newUint(21), newUint8(22), newUint16(23), newUint32(24), newUint64(25), 1517 []string{"test", "slice", "strings"}, []int{1, 2, 3, 4}, []float64{1.1, 2.2, 3.3}, 1518 map[string]int{"this": 1, "is": 2, "a": 3, "map": 4}, map[int]string{1: "this", 2: "is", 3: "another"}, 1519 map[string]*int{"wow": newInt(1), "a map": newInt(2), "of pointers!": newInt(3)}, 1520 map[int]*string{1: newString("Another"), 2: newString("map of"), 3: newString("pointers, wow!")}, 1521 mergeStructEmbed2A, &mergeStructEmbed2B, 1522 } 1523 1524 mergeStructEmbedBaseB = testStructEmbed{1, 2, 3, 4, 5, 1.1, 2.2, "test", 10, 11, 12, 12, 13, 1525 newInt(14), newInt8(15), newInt16(16), newInt32(17), newInt64(18), 1526 newFloat64(19.9), newFloat32(20.1), newString("test pointer"), 1527 newUint(21), newUint8(22), newUint16(23), newUint32(24), newUint64(25), 1528 []string{"test", "slice", "strings"}, []int{1, 2, 3, 4}, []float64{1.1, 2.2, 3.3}, 1529 map[string]int{"this": 1, "is": 2, "a": 3, "map": 4}, map[int]string{1: "this", 2: "is", 3: "another"}, 1530 map[string]*int{"wow": newInt(1), "a map": newInt(2), "of pointers!": newInt(3)}, 1531 map[int]*string{1: newString("Another"), 2: newString("map of"), 3: newString("pointers, wow!")}, 1532 mergeStructEmbed2C, &mergeStructEmbed2D, 1533 } 1534 1535 expectedMerged = testStruct{1, 2, 3, 4, 5, 1.1, 2.2, "test", 10, 11, 12, 12, 13, 1536 newInt(14), newInt8(15), newInt16(16), newInt32(17), newInt64(18), 1537 newFloat64(19.9), newFloat32(20.1), newString("test pointer"), 1538 newUint(21), newUint8(22), newUint16(23), newUint32(24), newUint64(25), 1539 []string{"test", "slice", "strings"}, []int{1, 2, 3, 4}, []float64{1.1, 2.2, 3.3}, 1540 map[string]int{"this": 1, "is": 2, "a": 3, "map": 4}, map[int]string{1: "this", 2: "is", 3: "another"}, 1541 map[string]*int{"wow": newInt(1), "a map": newInt(2), "of pointers!": newInt(3)}, 1542 map[int]*string{1: newString("Another"), 2: newString("map of"), 3: newString("pointers, wow!")}, 1543 mergeStructEmbedBaseA, &mergeStructEmbedBaseB, 1544 } 1545 } 1546 1547 func mergeSimple(base, patch simple) (*simple, error) { 1548 ret, err := utils.Merge(base, patch, nil) 1549 if err != nil { 1550 return nil, err 1551 } 1552 retS := ret.(simple) 1553 return &retS, nil 1554 } 1555 1556 func mergeEvenSimpler(base, patch evenSimpler) (*evenSimpler, error) { 1557 ret, err := utils.Merge(base, patch, nil) 1558 if err != nil { 1559 return nil, err 1560 } 1561 retTS := ret.(evenSimpler) 1562 return &retTS, nil 1563 } 1564 1565 func mergeEvenSimplerWithConfig(base, patch evenSimpler, mergeConfig *utils.MergeConfig) (*evenSimpler, error) { 1566 ret, err := utils.Merge(base, patch, mergeConfig) 1567 if err != nil { 1568 return nil, err 1569 } 1570 retTS := ret.(evenSimpler) 1571 return &retTS, nil 1572 } 1573 1574 func mergeSliceStruct(base, patch sliceStruct) (*sliceStruct, error) { 1575 ret, err := utils.Merge(base, patch, nil) 1576 if err != nil { 1577 return nil, err 1578 } 1579 retTS := ret.(sliceStruct) 1580 return &retTS, nil 1581 } 1582 1583 func mergeMapPtr(base, patch mapPtr) (*mapPtr, error) { 1584 ret, err := utils.Merge(base, patch, nil) 1585 if err != nil { 1586 return nil, err 1587 } 1588 retTS := ret.(mapPtr) 1589 return &retTS, nil 1590 } 1591 1592 func mergeMapPtrState(base, patch mapPtrState) (*mapPtrState, error) { 1593 ret, err := utils.Merge(base, patch, nil) 1594 if err != nil { 1595 return nil, err 1596 } 1597 retTS := ret.(mapPtrState) 1598 return &retTS, nil 1599 } 1600 1601 func mergeMapPtrState2(base, patch mapPtrState2) (*mapPtrState2, error) { 1602 ret, err := utils.Merge(base, patch, nil) 1603 if err != nil { 1604 return nil, err 1605 } 1606 retTS := ret.(mapPtrState2) 1607 return &retTS, nil 1608 } 1609 1610 func mergeTestStructs(base, patch testStruct) (*testStruct, error) { 1611 ret, err := utils.Merge(base, patch, nil) 1612 if err != nil { 1613 return nil, err 1614 } 1615 retTS := ret.(testStruct) 1616 return &retTS, nil 1617 } 1618 1619 func mergeStringIntMap(base, patch map[string]int) (map[string]int, error) { 1620 ret, err := utils.Merge(base, patch, nil) 1621 if err != nil { 1622 return nil, err 1623 } 1624 retTS := ret.(map[string]int) 1625 return retTS, nil 1626 } 1627 1628 func mergeStringPtrIntMap(base, patch map[string]*int) (map[string]*int, error) { 1629 ret, err := utils.Merge(base, patch, nil) 1630 if err != nil { 1631 return nil, err 1632 } 1633 retTS := ret.(map[string]*int) 1634 return retTS, nil 1635 } 1636 1637 func mergeStringSliceIntMap(base, patch map[string][]int) (map[string][]int, error) { 1638 ret, err := utils.Merge(base, patch, nil) 1639 if err != nil { 1640 return nil, err 1641 } 1642 retTS := ret.(map[string][]int) 1643 return retTS, nil 1644 } 1645 1646 func mergeMapOfMap(base, patch map[string]map[string]*int) (map[string]map[string]*int, error) { 1647 ret, err := utils.Merge(base, patch, nil) 1648 if err != nil { 1649 return nil, err 1650 } 1651 retTS := ret.(map[string]map[string]*int) 1652 return retTS, nil 1653 } 1654 1655 func mergeInterfaceMap(base, patch map[string]interface{}) (map[string]interface{}, error) { 1656 ret, err := utils.Merge(base, patch, nil) 1657 if err != nil { 1658 return nil, err 1659 } 1660 retTS := ret.(map[string]interface{}) 1661 return retTS, nil 1662 } 1663 1664 func mergeStringSlices(base, patch []string) ([]string, error) { 1665 ret, err := utils.Merge(base, patch, nil) 1666 if err != nil { 1667 return nil, err 1668 } 1669 retTS := ret.([]string) 1670 return retTS, nil 1671 } 1672 1673 func mergeTestStructsPtrs(base, patch *testStruct) (*testStruct, error) { 1674 ret, err := utils.Merge(base, patch, nil) 1675 if err != nil { 1676 return nil, err 1677 } 1678 retTS := ret.(testStruct) 1679 return &retTS, nil 1680 } 1681 1682 func newBool(b bool) *bool { return &b } 1683 func newInt(n int) *int { return &n } 1684 func newInt64(n int64) *int64 { return &n } 1685 func newString(s string) *string { return &s } 1686 func newInt8(n int8) *int8 { return &n } 1687 func newInt16(n int16) *int16 { return &n } 1688 func newInt32(n int32) *int32 { return &n } 1689 func newFloat64(f float64) *float64 { return &f } 1690 func newFloat32(f float32) *float32 { return &f } 1691 func newUint(n uint) *uint { return &n } 1692 func newUint8(n uint8) *uint8 { return &n } 1693 func newUint16(n uint16) *uint16 { return &n } 1694 func newUint32(n uint32) *uint32 { return &n } 1695 func newUint64(n uint64) *uint64 { return &n }