github.com/hairyhenderson/gomplate/v4@v4.0.0-pre-2.0.20240520121557-362f058f0c93/coll/coll_test.go (about) 1 package coll 2 3 import ( 4 "fmt" 5 "testing" 6 7 "github.com/stretchr/testify/assert" 8 "github.com/stretchr/testify/require" 9 ) 10 11 func TestSlice(t *testing.T) { 12 expected := []string{"foo", "bar"} 13 actual := Slice("foo", "bar") 14 assert.Equal(t, expected[0], actual[0]) 15 assert.Equal(t, expected[1], actual[1]) 16 } 17 18 func TestHas(t *testing.T) { 19 in := map[string]interface{}{ 20 "foo": "bar", 21 "baz": map[string]interface{}{ 22 "qux": "quux", 23 }, 24 } 25 26 testdata := []struct { 27 in interface{} 28 key interface{} 29 out bool 30 }{ 31 {in, "foo", true}, 32 {in, "bar", false}, 33 {in["baz"], "qux", true}, 34 {[]string{"foo", "bar", "baz"}, "bar", true}, 35 {[]interface{}{"foo", "bar", "baz"}, "bar", true}, 36 {[]interface{}{"foo", "bar", "baz"}, 42, false}, 37 {[]int{1, 2, 42}, 42, true}, 38 } 39 40 for _, d := range testdata { 41 assert.Equal(t, d.out, Has(d.in, d.key)) 42 } 43 } 44 45 func TestDict(t *testing.T) { 46 testdata := []struct { 47 expected map[string]interface{} 48 args []interface{} 49 }{ 50 {expected: map[string]interface{}{}}, 51 {args: []interface{}{}, expected: map[string]interface{}{}}, 52 {args: []interface{}{"foo"}, expected: map[string]interface{}{"foo": ""}}, 53 {args: []interface{}{42}, expected: map[string]interface{}{"42": ""}}, 54 {args: []interface{}{"foo", nil}, expected: map[string]interface{}{"foo": nil}}, 55 {args: []interface{}{"foo", "bar"}, expected: map[string]interface{}{"foo": "bar"}}, 56 {args: []interface{}{"foo", "bar", "baz", true}, expected: map[string]interface{}{ 57 "foo": "bar", 58 "baz": true, 59 }}, 60 } 61 62 for _, d := range testdata { 63 actual, _ := Dict(d.args...) 64 assert.Equal(t, d.expected, actual) 65 } 66 } 67 68 func TestKeys(t *testing.T) { 69 _, err := Keys() 70 require.Error(t, err) 71 72 in := map[string]interface{}{ 73 "foo": 1, 74 "bar": 2, 75 } 76 expected := []string{"bar", "foo"} 77 keys, err := Keys(in) 78 require.NoError(t, err) 79 assert.EqualValues(t, expected, keys) 80 81 in2 := map[string]interface{}{ 82 "baz": 3, 83 "qux": 4, 84 } 85 expected = []string{"bar", "foo", "baz", "qux"} 86 keys, err = Keys(in, in2) 87 require.NoError(t, err) 88 assert.EqualValues(t, expected, keys) 89 90 in3 := map[string]interface{}{ 91 "Foo": 5, 92 "Bar": 6, 93 "foo": 7, 94 "bar": 8, 95 } 96 expected = []string{"bar", "foo", "baz", "qux", "Bar", "Foo", "bar", "foo"} 97 keys, err = Keys(in, in2, in3) 98 require.NoError(t, err) 99 assert.EqualValues(t, expected, keys) 100 } 101 102 func TestValues(t *testing.T) { 103 _, err := Values() 104 require.Error(t, err) 105 106 in := map[string]interface{}{ 107 "foo": 1, 108 "bar": 2, 109 } 110 expected := []interface{}{2, 1} 111 values, err := Values(in) 112 require.NoError(t, err) 113 assert.EqualValues(t, expected, values) 114 115 in2 := map[string]interface{}{ 116 "baz": 3, 117 "qux": 4, 118 } 119 expected = []interface{}{2, 1, 3, 4} 120 values, err = Values(in, in2) 121 require.NoError(t, err) 122 assert.EqualValues(t, expected, values) 123 124 in3 := map[string]interface{}{ 125 "Foo": 5, 126 "Bar": 6, 127 "foo": 7, 128 "bar": 8, 129 } 130 expected = []interface{}{2, 1, 3, 4, 6, 5, 8, 7} 131 values, err = Values(in, in2, in3) 132 require.NoError(t, err) 133 assert.EqualValues(t, expected, values) 134 } 135 136 func TestAppend(t *testing.T) { 137 out, err := Append(42, []interface{}{}) 138 require.NoError(t, err) 139 assert.EqualValues(t, []interface{}{42}, out) 140 141 out, err = Append(42, []interface{}{4.9, false, "foo"}) 142 require.NoError(t, err) 143 assert.EqualValues(t, []interface{}{4.9, false, "foo", 42}, out) 144 145 // a strange but valid use-cases, since we're converting to an []interface{} 146 out, err = Append(42, []string{"foo"}) 147 require.NoError(t, err) 148 assert.EqualValues(t, []interface{}{"foo", 42}, out) 149 150 out, err = Append("baz", []string{"foo", "bar"}) 151 require.NoError(t, err) 152 assert.EqualValues(t, []interface{}{"foo", "bar", "baz"}, out) 153 } 154 155 func TestPrepend(t *testing.T) { 156 out, err := Prepend(42, []interface{}{}) 157 require.NoError(t, err) 158 assert.EqualValues(t, []interface{}{42}, out) 159 160 out, err = Prepend(42, []interface{}{4.9, false, "foo"}) 161 require.NoError(t, err) 162 assert.EqualValues(t, []interface{}{42, 4.9, false, "foo"}, out) 163 164 // a strange but valid use-cases, since we're converting to an []interface{} 165 out, err = Prepend(42, []string{"foo"}) 166 require.NoError(t, err) 167 assert.EqualValues(t, []interface{}{42, "foo"}, out) 168 169 out, err = Prepend("foo", []string{"bar", "baz"}) 170 require.NoError(t, err) 171 assert.EqualValues(t, []interface{}{"foo", "bar", "baz"}, out) 172 } 173 174 func TestUniq(t *testing.T) { 175 out, err := Uniq([]interface{}{1, 2, 3, 1, true, false, true, "1", 2}) 176 require.NoError(t, err) 177 assert.EqualValues(t, []interface{}{1, 2, 3, true, false, "1"}, out) 178 179 out, err = Uniq([]string{"one", "two", "one", "three"}) 180 require.NoError(t, err) 181 assert.EqualValues(t, []interface{}{"one", "two", "three"}, out) 182 } 183 184 func TestReverse(t *testing.T) { 185 out, err := Reverse([]interface{}{}) 186 require.NoError(t, err) 187 assert.EqualValues(t, []interface{}{}, out) 188 189 out, err = Reverse([]interface{}{8}) 190 require.NoError(t, err) 191 assert.EqualValues(t, []interface{}{8}, out) 192 193 out, err = Reverse([]interface{}{1, 2, 3, 4}) 194 require.NoError(t, err) 195 assert.EqualValues(t, []interface{}{4, 3, 2, 1}, out) 196 197 out, err = Reverse([]int{1, 2, 3, 4}) 198 require.NoError(t, err) 199 assert.EqualValues(t, []interface{}{4, 3, 2, 1}, out) 200 } 201 202 func TestMerge(t *testing.T) { 203 dst := map[string]interface{}{} 204 src := map[string]interface{}{} 205 expected := map[string]interface{}{} 206 207 out, err := Merge(dst, src) 208 require.NoError(t, err) 209 assert.EqualValues(t, expected, out) 210 211 dst = map[string]interface{}{"a": 4, "c": 5} 212 src = map[string]interface{}{"a": 1, "b": 2, "c": 3} 213 expected = map[string]interface{}{ 214 "a": dst["a"], "b": src["b"], "c": dst["c"], 215 } 216 217 out, err = Merge(dst, src) 218 require.NoError(t, err) 219 assert.EqualValues(t, expected, out) 220 221 dst = map[string]interface{}{"a": 4, "c": 5} 222 src = map[string]interface{}{"a": 1, "b": 2, "c": 3} 223 src2 := map[string]interface{}{"a": 1, "b": 2, "c": 3, "d": 4} 224 expected = map[string]interface{}{ 225 "a": dst["a"], "b": src["b"], "c": dst["c"], "d": src2["d"], 226 } 227 228 out, err = Merge(dst, src, src2) 229 require.NoError(t, err) 230 assert.EqualValues(t, expected, out) 231 232 dst = map[string]interface{}{"a": false, "c": 5} 233 src = map[string]interface{}{"a": true, "b": 2, "c": 3} 234 src2 = map[string]interface{}{"a": true, "b": 2, "c": 3, "d": 4} 235 expected = map[string]interface{}{ 236 "a": dst["a"], "b": src["b"], "c": dst["c"], "d": src2["d"], 237 } 238 239 out, err = Merge(dst, src, src2) 240 require.NoError(t, err) 241 assert.EqualValues(t, expected, out) 242 243 dst = map[string]interface{}{"a": true, "c": 5} 244 src = map[string]interface{}{ 245 "a": false, 246 "b": map[string]interface{}{ 247 "ca": "foo", 248 }, 249 } 250 src2 = map[string]interface{}{"a": false, "b": 2, "c": 3, "d": 4} 251 expected = map[string]interface{}{ 252 "a": dst["a"], "b": src["b"], "c": dst["c"], "d": src2["d"], 253 } 254 255 out, err = Merge(dst, src, src2) 256 require.NoError(t, err) 257 assert.EqualValues(t, expected, out) 258 259 dst = map[string]interface{}{ 260 "a": true, 261 "b": map[string]interface{}{ 262 "ca": "foo", 263 "cb": "bar", 264 }, 265 "c": 5, 266 } 267 src = map[string]interface{}{ 268 "a": false, 269 "b": map[string]interface{}{ 270 "ca": 8, 271 }, 272 } 273 expected = map[string]interface{}{ 274 "a": dst["a"], "b": map[string]interface{}{ 275 "ca": "foo", 276 "cb": "bar", 277 }, "c": dst["c"], 278 } 279 280 out, err = Merge(dst, src) 281 require.NoError(t, err) 282 assert.EqualValues(t, expected, out) 283 } 284 285 type coords struct { 286 X, Y int 287 } 288 289 func TestSameTypes(t *testing.T) { 290 data := []struct { 291 in []interface{} 292 out bool 293 }{ 294 {[]interface{}{}, true}, 295 {[]interface{}{"a", "b"}, true}, 296 {[]interface{}{1.0, 3.14}, true}, 297 {[]interface{}{1, 3}, true}, 298 {[]interface{}{true, false}, true}, 299 {[]interface{}{1, 3.0}, false}, 300 {[]interface{}{"a", nil}, false}, 301 {[]interface{}{"a", true}, false}, 302 {[]interface{}{coords{2, 3}, coords{3, 4}}, true}, 303 {[]interface{}{coords{2, 3}, &coords{3, 4}}, false}, 304 } 305 306 for _, d := range data { 307 assert.Equal(t, d.out, sameTypes(d.in)) 308 } 309 } 310 311 func TestLessThan(t *testing.T) { 312 data := []struct { 313 left, right interface{} 314 key string 315 out bool 316 }{ 317 {key: ""}, 318 {left: "a", right: "b", out: true}, 319 {left: "a", right: "a"}, 320 {left: "b", right: "a"}, 321 {left: 1.00, right: 3.14, out: true}, 322 {left: 'a', right: 'A'}, 323 {left: 'a', right: 'b', out: true}, 324 {left: uint(0xff), right: uint(0x32)}, 325 {left: 1, right: 3, out: true}, 326 {left: true, right: false, out: false}, 327 {left: map[string]interface{}{"foo": 1}, right: map[string]interface{}{"foo": 2}}, 328 { 329 key: "foo", 330 left: map[string]interface{}{"foo": 1}, 331 right: map[string]interface{}{"foo": 2}, 332 out: true, 333 }, 334 { 335 key: "bar", 336 left: map[string]interface{}{"foo": 1}, 337 right: map[string]interface{}{"foo": 2}, 338 }, 339 {key: "X", left: coords{}, right: coords{-1, 2}}, 340 {key: "Y", left: &coords{1, 1}, right: &coords{-1, 2}, out: true}, 341 {left: &coords{1, 1}, right: &coords{-1, 2}}, 342 {key: "foo", left: &coords{1, 1}, right: &coords{-1, 2}}, 343 } 344 345 for _, d := range data { 346 d := d 347 t.Run(fmt.Sprintf(`LessThan("%s")(<%T>%#v,%#v)==%v`, d.key, d.left, d.left, d.right, d.out), func(t *testing.T) { 348 assert.Equal(t, d.out, lessThan(d.key)(d.left, d.right)) 349 }) 350 } 351 } 352 353 func TestSort(t *testing.T) { 354 out, err := Sort("", 42) 355 require.Error(t, err) 356 assert.Nil(t, out) 357 358 data := []struct { 359 key string 360 in interface{} 361 out []interface{} 362 }{ 363 { 364 key: "", 365 in: []string{"b", "c", "a", "d"}, 366 out: []interface{}{"a", "b", "c", "d"}, 367 }, 368 { 369 key: "", 370 in: []interface{}{"b", "c", "a", "d"}, 371 out: []interface{}{"a", "b", "c", "d"}, 372 }, 373 { 374 key: "", 375 in: []interface{}{"c", "a", "b", 3, 1, 2}, 376 out: []interface{}{"c", "a", "b", 3, 1, 2}, 377 }, 378 { 379 key: "", 380 in: nil, 381 out: nil, 382 }, 383 384 { 385 key: "", 386 in: []map[string]interface{}{ 387 {"name": "Bart", "age": 12}, 388 {"age": 1, "name": "Maggie"}, 389 {"name": "Lisa", "age": 6}, 390 }, 391 out: []interface{}{ 392 map[string]interface{}{"name": "Bart", "age": 12}, 393 map[string]interface{}{"age": 1, "name": "Maggie"}, 394 map[string]interface{}{"name": "Lisa", "age": 6}, 395 }, 396 }, 397 { 398 key: "name", 399 in: []map[string]interface{}{ 400 {"name": "Bart", "age": 12}, 401 {"age": 1, "name": "Maggie"}, 402 {"name": "Lisa", "age": 6}, 403 }, 404 out: []interface{}{ 405 map[string]interface{}{"name": "Bart", "age": 12}, 406 map[string]interface{}{"name": "Lisa", "age": 6}, 407 map[string]interface{}{"age": 1, "name": "Maggie"}, 408 }, 409 }, 410 { 411 key: "age", 412 in: []map[string]interface{}{ 413 {"name": "Bart", "age": 12}, 414 {"age": 1, "name": "Maggie"}, 415 {"name": "Lisa", "age": 6}, 416 }, 417 out: []interface{}{ 418 map[string]interface{}{"age": 1, "name": "Maggie"}, 419 map[string]interface{}{"name": "Lisa", "age": 6}, 420 map[string]interface{}{"name": "Bart", "age": 12}, 421 }, 422 }, 423 { 424 key: "y", 425 in: []map[string]int{ 426 {"x": 54, "y": 6}, 427 {"x": 13, "y": -8}, 428 {"x": 1, "y": 0}, 429 }, 430 out: []interface{}{ 431 map[string]int{"x": 13, "y": -8}, 432 map[string]int{"x": 1, "y": 0}, 433 map[string]int{"x": 54, "y": 6}, 434 }, 435 }, 436 { 437 key: "X", 438 in: []coords{ 439 {2, 4}, 440 {3, 3}, 441 {1, 5}, 442 }, 443 out: []interface{}{ 444 coords{1, 5}, 445 coords{2, 4}, 446 coords{3, 3}, 447 }, 448 }, 449 { 450 key: "X", 451 in: []*coords{ 452 {2, 4}, 453 {3, 3}, 454 {1, 5}, 455 }, 456 out: []interface{}{ 457 &coords{1, 5}, 458 &coords{2, 4}, 459 &coords{3, 3}, 460 }, 461 }, 462 } 463 464 for _, d := range data { 465 d := d 466 t.Run(fmt.Sprintf(`Sort("%s",<%T>)==%#v`, d.key, d.in, d.out), func(t *testing.T) { 467 out, err := Sort(d.key, d.in) 468 require.NoError(t, err) 469 assert.EqualValues(t, d.out, out) 470 }) 471 } 472 } 473 474 func TestFlatten(t *testing.T) { 475 data := []struct { 476 in interface{} 477 expected []interface{} 478 depth int 479 }{ 480 {in: []int{1, 2, 3}, expected: []interface{}{1, 2, 3}}, 481 {in: [3]int{1, 2, 3}, expected: []interface{}{1, 2, 3}}, 482 {in: []interface{}{[]string{}, []int{1, 2}, 3}, expected: []interface{}{[]string{}, []int{1, 2}, 3}}, 483 { 484 in: []interface{}{[]string{"one"}, [][]int{{1, 2}}, 3}, 485 expected: []interface{}{[]string{"one"}, [][]int{{1, 2}}, 3}, 486 }, 487 {depth: 1, in: []int{1, 2, 3}, expected: []interface{}{1, 2, 3}}, 488 {depth: 1, in: [3]int{1, 2, 3}, expected: []interface{}{1, 2, 3}}, 489 {depth: 1, in: []interface{}{[]string{}, []int{1, 2}, 3}, expected: []interface{}{1, 2, 3}}, 490 { 491 depth: 1, 492 in: []interface{}{[]string{"one"}, [][]int{{1, 2}}, 3}, 493 expected: []interface{}{"one", []int{1, 2}, 3}, 494 }, 495 {depth: 2, in: []int{1, 2, 3}, expected: []interface{}{1, 2, 3}}, 496 {depth: 2, in: [3]int{1, 2, 3}, expected: []interface{}{1, 2, 3}}, 497 {depth: 2, in: []interface{}{[]string{}, []int{1, 2}, 3}, expected: []interface{}{1, 2, 3}}, 498 { 499 depth: 2, 500 in: []interface{}{[]string{"one"}, [][]int{{1, 2}}, 3}, 501 expected: []interface{}{"one", 1, 2, 3}, 502 }, 503 { 504 depth: 2, 505 in: []interface{}{ 506 []string{"one"}, 507 []interface{}{ 508 []interface{}{ 509 []int{1}, 510 []interface{}{2, []int{3}}, 511 }, 512 []int{4, 5}, 513 }, 514 6, 515 }, 516 expected: []interface{}{"one", []int{1}, []interface{}{2, []int{3}}, 4, 5, 6}, 517 }, 518 {depth: -1, in: []int{1, 2, 3}, expected: []interface{}{1, 2, 3}}, 519 {depth: -1, in: [3]int{1, 2, 3}, expected: []interface{}{1, 2, 3}}, 520 {depth: -1, in: []interface{}{[]string{}, []int{1, 2}, 3}, expected: []interface{}{1, 2, 3}}, 521 { 522 depth: -1, 523 in: []interface{}{[]string{"one"}, [][]int{{1, 2}}, 3}, 524 expected: []interface{}{"one", 1, 2, 3}, 525 }, 526 { 527 depth: -1, 528 in: []interface{}{ 529 []string{"one"}, 530 []interface{}{ 531 []interface{}{ 532 []int{1}, 533 []interface{}{2, []int{3}}, 534 }, 535 []int{4, 5}, 536 }, 537 6, 538 }, 539 expected: []interface{}{"one", 1, 2, 3, 4, 5, 6}, 540 }, 541 } 542 543 for _, d := range data { 544 out, err := Flatten(d.in, d.depth) 545 require.NoError(t, err) 546 assert.EqualValues(t, d.expected, out) 547 } 548 549 _, err := Flatten(42, -1) 550 require.Error(t, err) 551 } 552 553 func BenchmarkFlatten(b *testing.B) { 554 data := []interface{}{ 555 []int{1, 2, 3}, 556 [3]int{1, 2, 3}, 557 []interface{}{[]string{}, []int{1, 2}, 3}, 558 []interface{}{[]string{"one"}, [][]int{{1, 2}}, 3}, 559 []interface{}{ 560 []string{"one"}, 561 []interface{}{ 562 []interface{}{ 563 []int{1}, 564 []interface{}{2, []int{3}}, 565 }, 566 []int{4, 5}, 567 }, 568 6, 569 }, 570 } 571 for depth := -1; depth <= 2; depth++ { 572 depth := depth 573 for _, d := range data { 574 d := d 575 b.Run(fmt.Sprintf("depth%d %T(%v)", depth, d, d), func(b *testing.B) { 576 for i := 0; i < b.N; i++ { 577 Flatten(d, depth) 578 } 579 }) 580 } 581 } 582 } 583 584 func TestOmit(t *testing.T) { 585 in := map[string]interface{}{ 586 "foo": "bar", 587 "bar": true, 588 "": "baz", 589 } 590 assert.EqualValues(t, in, Omit(in, "baz")) 591 592 expected := map[string]interface{}{ 593 "foo": "bar", 594 "bar": true, 595 } 596 assert.EqualValues(t, expected, Omit(in, "")) 597 598 expected = map[string]interface{}{ 599 "": "baz", 600 } 601 assert.EqualValues(t, expected, Omit(in, "foo", "bar")) 602 603 assert.EqualValues(t, map[string]interface{}{}, Omit(in, "foo", "bar", "")) 604 } 605 606 func TestPick(t *testing.T) { 607 in := map[string]interface{}{ 608 "foo": "bar", 609 "bar": true, 610 "": "baz", 611 } 612 expected := map[string]interface{}{} 613 assert.EqualValues(t, expected, Pick(in, "baz")) 614 615 expected = map[string]interface{}{ 616 "": "baz", 617 } 618 assert.EqualValues(t, expected, Pick(in, "")) 619 620 expected = map[string]interface{}{ 621 "foo": "bar", 622 "bar": true, 623 } 624 assert.EqualValues(t, expected, Pick(in, "foo", "bar")) 625 626 assert.EqualValues(t, in, Pick(in, "foo", "bar", "")) 627 }