github.com/viant/toolbox@v0.34.5/collections_test.go (about) 1 package toolbox_test 2 3 import ( 4 "strings" 5 "testing" 6 7 "github.com/stretchr/testify/assert" 8 "github.com/viant/toolbox" 9 "reflect" 10 ) 11 12 func TestIndexSlice(t *testing.T) { 13 14 { 15 type Foo struct { 16 id int 17 name string 18 } 19 20 var fooCollection = []Foo{{1, "A"}, {2, "B"}} 21 var indexedMap = make(map[int]Foo) 22 toolbox.IndexSlice(fooCollection, indexedMap, func(foo Foo) int { 23 return foo.id 24 }) 25 assert.Equal(t, "A", indexedMap[1].name) 26 } 27 28 { 29 aSlice := []string{"a", "c"} 30 aMap := make(map[string]int) 31 index := 0 32 toolbox.SliceToMap(aSlice, aMap, toolbox.CopyStringValueProvider, func(s string) int { 33 index++ 34 return index 35 }) 36 assert.Equal(t, 2, len(aMap)) 37 38 } 39 } 40 41 type sliceItem struct { 42 Id int 43 } 44 45 func TestReverseSlice(t *testing.T) { 46 47 { 48 aSlice := []interface{}{ 49 "abc", "def", "cyz", "adc", "z", 50 } 51 52 toolbox.ReverseSlice(aSlice) 53 assert.Equal(t, []interface{}{"z", "adc", "cyz", "def", "abc"}, aSlice) 54 } 55 56 toolbox.ReverseSlice(nil) 57 { 58 aSlice := []*sliceItem{ 59 {1}, {10}, 60 } 61 62 toolbox.ReverseSlice(aSlice) 63 assert.Equal(t, []*sliceItem{ 64 {10}, {1}, 65 }, aSlice) 66 } 67 68 } 69 70 func TestProcessSlice(t *testing.T) { 71 { 72 aSlice := []interface{}{ 73 "abc", "def", "cyz", "adc", 74 } 75 count := 0 76 toolbox.ProcessSlice(aSlice, func(item interface{}) bool { 77 count++ 78 return true 79 }) 80 81 assert.Equal(t, 4, count) 82 } 83 84 { 85 aSlice := []string{ 86 "abc", "def", "cyz", "adc", 87 } 88 count := 0 89 toolbox.ProcessSlice(aSlice, func(item interface{}) bool { 90 count++ 91 return false 92 }) 93 94 assert.Equal(t, 1, count) 95 } 96 97 { 98 aSlice := []int{ 99 1, 2, 3, 100 } 101 count := 0 102 toolbox.ProcessSlice(aSlice, func(item interface{}) bool { 103 count++ 104 return false 105 }) 106 107 assert.Equal(t, 1, count) 108 } 109 { 110 aSlice := []string{ 111 "abc", "def", "cyz", "adc", 112 } 113 count := 0 114 toolbox.ProcessSlice(aSlice, func(item interface{}) bool { 115 count++ 116 return true 117 }) 118 119 assert.Equal(t, 4, count) 120 } 121 { 122 aSlice := []interface{}{ 123 "abc", "def", "cyz", "adc", 124 } 125 126 count := 0 127 toolbox.ProcessSlice(aSlice, func(item interface{}) bool { 128 count++ 129 return false 130 }) 131 assert.Equal(t, 1, count) 132 } 133 } 134 135 func TestProcessSliceWithIndex(t *testing.T) { 136 { 137 aSlice := []interface{}{ 138 "abc", "def", "cyz", "adc", 139 } 140 count := 0 141 toolbox.ProcessSliceWithIndex(aSlice, func(index int, item interface{}) bool { 142 count = index 143 return true 144 }) 145 146 assert.Equal(t, 3, count) 147 } 148 { 149 aSlice := []string{ 150 "abc", "def", "cyz", "adc", 151 } 152 count := 0 153 toolbox.ProcessSliceWithIndex(aSlice, func(index int, item interface{}) bool { 154 count = index 155 return true 156 }) 157 158 assert.Equal(t, 3, count) 159 } 160 } 161 162 func TestMakeMapFromSlice(t *testing.T) { 163 type Foo struct { 164 id int 165 name string 166 } 167 168 var fooCollection = []Foo{{1, "A"}, {2, "B"}} 169 var testMap = make(map[int]string) 170 toolbox.SliceToMap(fooCollection, testMap, func(foo Foo) int { 171 return foo.id 172 }, 173 func(foo Foo) string { 174 return foo.name 175 }) 176 177 assert.Equal(t, "A", testMap[1]) 178 assert.Equal(t, "B", testMap[2]) 179 180 } 181 182 func TestSliceToMap(t *testing.T) { 183 aSlice := []string{"a", "c"} 184 aMap := make(map[string]bool) 185 186 toolbox.SliceToMap(aSlice, aMap, func(s string) string { 187 return s 188 }, func(s string) bool { 189 return true 190 }) 191 assert.Equal(t, 2, len(aMap)) 192 193 } 194 195 func TestProcess2DSliceInBatches(t *testing.T) { 196 slice := [][]interface{}{ 197 {1, 2, 3}, 198 {4, 5, 7}, 199 {7, 8, 9}, 200 {10, 11, 12}, 201 {13, 14, 15}, 202 {16, 17, 18}, 203 {19, 20, 21}, 204 } 205 206 actualItemCount := 0 207 toolbox.Process2DSliceInBatches(slice, 2, func(item [][]interface{}) { 208 actualItemCount = actualItemCount + len(item) 209 }) 210 assert.Equal(t, 7, actualItemCount) 211 } 212 213 func TestCopySliceElements(t *testing.T) { 214 { 215 source := []interface{}{ 216 "abc", "def", "cyz", 217 } 218 var target = make([]string, 0) 219 toolbox.CopySliceElements(source, &target) 220 assert.Equal(t, 3, len(target)) 221 for i := 0; i < len(source); i++ { 222 assert.Equal(t, source[i], target[i]) 223 } 224 } 225 { 226 source := []interface{}{ 227 1, 2, 3, 228 } 229 var target = make([]int, 0) 230 toolbox.CopySliceElements(source, &target) 231 assert.Equal(t, 3, len(target)) 232 for i := 0; i < len(source); i++ { 233 assert.Equal(t, source[i], target[i]) 234 } 235 } 236 { 237 source := []interface{}{ 238 1, 2, 3, 239 } 240 var target = make([]interface{}, 0) 241 toolbox.CopySliceElements(source, &target) 242 assert.Equal(t, 3, len(target)) 243 for i := 0; i < len(source); i++ { 244 assert.Equal(t, source[i], target[i]) 245 } 246 } 247 248 } 249 250 func TestFilterSliceElements(t *testing.T) { 251 { 252 source := []interface{}{ 253 1, 2, 3, 254 } 255 var target = make([]int, 0) 256 //filter all elements starting with a 257 toolbox.FilterSliceElements(source, func(item int) bool { 258 return item > 1 259 }, &target) 260 assert.Equal(t, 2, len(target)) 261 assert.Equal(t, 2, target[0]) 262 assert.Equal(t, 3, target[1]) 263 } 264 265 { 266 source := []interface{}{ 267 "abc", "def", "cyz", "adc", 268 } 269 var target = make([]string, 0) 270 //filter all elements starting with a 271 toolbox.FilterSliceElements(source, func(item string) bool { 272 return strings.HasPrefix(item, "a") 273 }, &target) 274 assert.Equal(t, 2, len(target)) 275 assert.Equal(t, "abc", target[0]) 276 assert.Equal(t, "adc", target[1]) 277 } 278 279 } 280 281 func TestHasSliceAnyElements(t *testing.T) { 282 source := []interface{}{ 283 "abc", "def", "cyz", "adc", 284 } 285 assert.True(t, toolbox.HasSliceAnyElements(source, "cyz")) 286 assert.False(t, toolbox.HasSliceAnyElements(source, "cyze")) 287 assert.True(t, toolbox.HasSliceAnyElements(source, "cyze", "cyz")) 288 } 289 290 func TestMapKeysToSlice(t *testing.T) { 291 m := map[string]int{ 292 "abc": 1, 293 "efg": 2, 294 } 295 var keys = make([]string, 0) 296 toolbox.MapKeysToSlice(m, &keys) 297 assert.Equal(t, 2, len(keys)) 298 } 299 300 func TestMapKeysToStringSlice(t *testing.T) { 301 m := map[string]int{ 302 "abc": 1, 303 "efg": 2, 304 } 305 slice := toolbox.MapKeysToStringSlice(m) 306 assert.Equal(t, 2, len(slice)) 307 } 308 309 func TestCopyMapEntries(t *testing.T) { 310 type Foo struct { 311 id int 312 name string 313 } 314 source := map[interface{}]interface{}{ 315 1: Foo{1, "A"}, 316 2: Foo{2, "B"}, 317 } 318 var target = make(map[int]Foo) 319 320 toolbox.CopyMapEntries(source, target) 321 assert.Equal(t, 2, len(target)) 322 assert.Equal(t, "B", target[2].name) 323 } 324 325 func TestIndexMultimap(t *testing.T) { 326 type Product struct{ vendor, name string } 327 products := []Product{ 328 {"Vendor1", "Product1"}, 329 {"Vendor2", "Product2"}, 330 {"Vendor1", "Product3"}, 331 {"Vendor1", "Product4"}, 332 } 333 334 productsByVendor := make(map[string][]Product) 335 toolbox.GroupSliceElements(products, productsByVendor, func(product Product) string { 336 return product.vendor 337 }) 338 assert.Equal(t, 2, len(productsByVendor)) 339 assert.Equal(t, 3, len(productsByVendor["Vendor1"])) 340 assert.Equal(t, "Product4", productsByVendor["Vendor1"][2].name) 341 342 } 343 344 func TestSliceToMultiMap(t *testing.T) { 345 type Product struct { 346 vendor, name string 347 productId int 348 } 349 350 products := []Product{ 351 {"Vendor1", "Product1", 1}, 352 {"Vendor2", "Product2", 2}, 353 {"Vendor1", "Product3", 3}, 354 {"Vendor1", "Product4", 4}, 355 } 356 357 productsByVendor := make(map[string][]int) 358 toolbox.SliceToMultimap(products, productsByVendor, func(product Product) string { 359 return product.vendor 360 }, 361 func(product Product) int { 362 return product.productId 363 }) 364 365 assert.Equal(t, 2, len(productsByVendor)) 366 assert.Equal(t, 3, len(productsByVendor["Vendor1"])) 367 assert.Equal(t, 4, productsByVendor["Vendor1"][2]) 368 369 } 370 371 func TestTransformSlice(t *testing.T) { 372 type Product struct{ vendor, name string } 373 products := []Product{ 374 {"Vendor1", "Product1"}, 375 {"Vendor2", "Product2"}, 376 {"Vendor1", "Product3"}, 377 {"Vendor1", "Product4"}, 378 } 379 var vendors = make([]string, 0) 380 toolbox.TransformSlice(products, &vendors, func(product Product) string { 381 return product.vendor 382 }) 383 assert.Equal(t, 4, len(vendors)) 384 assert.Equal(t, "Vendor1", vendors[3]) 385 } 386 387 func TestMakeStringMap(t *testing.T) { 388 aMap := toolbox.MakeStringMap("a:1, b:2", ":", ",") 389 assert.Equal(t, 2, len(aMap)) 390 assert.Equal(t, "1", aMap["a"]) 391 assert.Equal(t, "2", aMap["b"]) 392 } 393 394 func TestMakeReverseStringMap(t *testing.T) { 395 aMap := toolbox.MakeReverseStringMap("a:1, b:2", ":", ",") 396 assert.Equal(t, 2, len(aMap)) 397 assert.Equal(t, "a", aMap["1"]) 398 assert.Equal(t, "b", aMap["2"]) 399 } 400 401 func TestSortStrings(t *testing.T) { 402 sorted := toolbox.SortStrings([]string{"z", "b", "c", "a"}) 403 assert.Equal(t, "a", sorted[0]) 404 assert.Equal(t, "z", sorted[3]) 405 406 } 407 408 func TestJoinAsString(t *testing.T) { 409 assert.Equal(t, "a,b", toolbox.JoinAsString([]string{"a", "b"}, ",")) 410 } 411 412 func TestSetSliceValue(t *testing.T) { 413 414 { 415 var aSlice = make([]string, 2) 416 toolbox.SetSliceValue(aSlice, 0, "abc") 417 assert.Equal(t, "abc", aSlice[0]) 418 assert.Equal(t, "abc", toolbox.GetSliceValue(aSlice, 0)) 419 } 420 421 { 422 var aSlice = make([]int, 2) 423 toolbox.SetSliceValue(aSlice, 0, 100) 424 assert.Equal(t, 100, aSlice[0]) 425 assert.Equal(t, 100, toolbox.GetSliceValue(aSlice, 0)) 426 } 427 { 428 var aSlice = make([]interface{}, 2) 429 toolbox.SetSliceValue(aSlice, 0, "a") 430 assert.Equal(t, "a", aSlice[0]) 431 assert.Equal(t, "a", toolbox.GetSliceValue(aSlice, 0)) 432 } 433 } 434 435 func TestTrueValueProvider(t *testing.T) { 436 assert.True(t, toolbox.TrueValueProvider(1)) 437 } 438 439 func Test_DeleteEmptyKeys(t *testing.T) { 440 aMap := map[string]interface{}{ 441 "k1": []int{}, 442 "k2": []int{1}, 443 "k3": "", 444 "k40": map[interface{}]interface{}{ 445 "k1": nil, 446 1: 2, 447 "k31": []map[string]interface{}{}, 448 "k41": []map[string]interface{}{ 449 { 450 "z": 1, 451 }, 452 }, 453 }, 454 "k5": map[string]interface{}{ 455 "k1": "", 456 "10": 20, 457 }, 458 } 459 cloned := toolbox.DeleteEmptyKeys(aMap) 460 assert.Equal(t, map[string]interface{}{ 461 "k2": []interface{}{1}, 462 "k40": map[interface{}]interface{}{ 463 1: 2, 464 "k41": []interface{}{ 465 map[string]interface{}{ 466 "z": 1, 467 }, 468 }, 469 }, 470 "k5": map[string]interface{}{ 471 "10": 20, 472 }, 473 }, cloned) 474 } 475 476 func TestReplaceMapKeys(t *testing.T) { 477 478 aMap := map[string]interface{}{ 479 "k1": []int{}, 480 "k2": []int{1}, 481 "k3": "", 482 "k40": map[interface{}]interface{}{ 483 "k1": nil, 484 1: 2, 485 "k31": []map[string]interface{}{}, 486 "k41": []map[string]interface{}{ 487 { 488 "z": 1, 489 }, 490 }, 491 }, 492 "k5": map[string]interface{}{ 493 "k1": "", 494 "k10": 20, 495 }, 496 } 497 replaced := toolbox.ReplaceMapKeys(aMap, map[string]interface{}{ 498 "k1": 123, 499 "k10": 30, 500 }, true) 501 502 assert.EqualValues(t, replaced, map[string]interface{}{ 503 "k1": 123, 504 "k2": []interface{}{1}, 505 "k40": map[interface{}]interface{}{ 506 "k1": 123, 507 1: 2, 508 "k41": []interface{}{ 509 map[string]interface{}{ 510 "z": 1, 511 }, 512 }, 513 }, 514 "k5": map[string]interface{}{ 515 "k10": 30, 516 "k1": 123, 517 }, 518 }) 519 } 520 521 522 523 524 525 func TestIntersection(t *testing.T) { 526 527 useCase1Actual := []string{} 528 useCase2Actual := []int{} 529 useCase3Actual := []float32{} 530 531 var useCases = []struct { 532 description string 533 sliceA interface{} 534 sliceB interface{} 535 actual interface{} 536 expect interface{} 537 hasError bool 538 }{ 539 { 540 description: "string slice intersection", 541 sliceA: []string{"a", "bc", "z", "eee"}, 542 sliceB: []string{"a2", "bc", "5z", "eee"}, 543 actual: &useCase1Actual, 544 expect: []string{"bc", "eee"}, 545 }, 546 { 547 description: "int slice intersection", 548 sliceA: []int{1, 2, 3, 4}, 549 sliceB: []int{3, 4, 5, 6}, 550 actual: &useCase2Actual, 551 expect: []int{3, 4}, 552 }, 553 { 554 description: "float slice intersection", 555 sliceA: []float32{1.1, 2.1, 3.1, 4.1}, 556 sliceB: []float32{3.1, 4.1, 5.1, 6.1}, 557 actual: &useCase3Actual, 558 expect: []float32{3.1, 4.1}, 559 }, 560 } 561 562 for _, useCase := range useCases { 563 err := toolbox.Intersect(useCase.sliceA, useCase.sliceB, useCase.actual) 564 if useCase.hasError { 565 assert.NotNil(t, err, useCase.description) 566 continue 567 } 568 if !assert.Nil(t, err, useCase.description) { 569 continue 570 } 571 actual := reflect.ValueOf(useCase.actual).Elem().Interface() 572 assert.EqualValues(t, useCase.expect, actual, useCase.description) 573 } 574 575 }