github.com/jxskiss/gopkg/v2@v2.14.9-0.20240514120614-899f3e7952b4/easy/slices_test.go (about) 1 package easy 2 3 import ( 4 "math/rand" 5 "reflect" 6 "testing" 7 8 "github.com/stretchr/testify/assert" 9 10 "github.com/jxskiss/gopkg/v2/unsafe/reflectx" 11 "github.com/jxskiss/gopkg/v2/utils/ptr" 12 ) 13 14 func TestClip(t *testing.T) { 15 s := make([]int, 5, 10) 16 got := Clip(s) 17 assert.Equal(t, 5, len(got)) 18 assert.Equal(t, 5, cap(got)) 19 } 20 21 func TestCopy(t *testing.T) { 22 s := []int64{1, 2, 3} 23 24 got1 := Copy(s) 25 assert.Equal(t, got1, s) 26 assert.Equal(t, 3, cap(got1)) 27 28 got2 := Copy(s, 10) 29 assert.Equal(t, got2, s) 30 assert.Equal(t, 10, cap(got2)) 31 } 32 33 func TestConcat(t *testing.T) { 34 s1 := []string{"1", "2"} 35 s2 := []string{"a", "b"} 36 s3 := []string{"x", "y"} 37 want := []string{"1", "2", "a", "b", "x", "y"} 38 got := Concat(s1, s2, s3) 39 assert.Equal(t, want, got) 40 } 41 42 func TestCount(t *testing.T) { 43 s := []string{"1", "2", "a", "b", "3", "4", "x", "y"} 44 got := Count(func(s string) bool { 45 return s[0] >= '0' && s[0] <= '9' 46 }, s) 47 assert.Equal(t, 4, got) 48 } 49 50 type simple struct { 51 A string 52 } 53 54 type comptyp struct { 55 I32 int32 56 I32_p *int32 57 58 I64 int64 59 I64_p *int64 60 61 Str string 62 Str_p *string 63 64 Simple simple 65 Simple_p *simple 66 } 67 68 func TestDiff(t *testing.T) { 69 s1 := []int{1, 2, 3, 4, 5, 6} 70 s2 := []int{2, 4, 6, 8, 10} 71 72 got1 := Diff(s1, s2) 73 assert.Equal(t, []int{1, 3, 5}, got1) 74 assert.Equal(t, []int{1, 2, 3, 4, 5, 6}, s1) 75 assert.Equal(t, []int{2, 4, 6, 8, 10}, s2) 76 77 got2 := Diff(s2, s1) 78 assert.Equal(t, []int{8, 10}, got2) 79 assert.Equal(t, []int{1, 2, 3, 4, 5, 6}, s1) 80 assert.Equal(t, []int{2, 4, 6, 8, 10}, s2) 81 82 s3 := []int{1, 3} 83 got3 := Diff(s1, s2, s3) 84 assert.Equal(t, []int{5}, got3) 85 } 86 87 func TestFilter(t *testing.T) { 88 a := &comptyp{I32: 1, Str_p: ptr.String("a")} 89 b := &comptyp{I64: 2, Str_p: ptr.String("b")} 90 c := &comptyp{I64_p: ptr.Int64(3), Str_p: ptr.String("c")} 91 slice := []*comptyp{a, b, c} 92 93 f1 := func(_ int, x *comptyp) bool { return x.Str_p == nil } 94 got1 := Filter(f1, slice) 95 96 assert.NotNil(t, got1) 97 assert.Len(t, got1, 0) 98 99 f3 := func(_ int, x *comptyp) bool { return ptr.DerefInt64(x.I64_p) == 3 } 100 got3 := Filter(f3, slice) 101 assert.Len(t, got3, 1) 102 } 103 104 func TestFilterInMap(t *testing.T) { 105 s := []int{1, 2, 3, 4, 5} 106 m := map[int]string{1: "", 3: "", 5: ""} 107 108 got1 := FilterInMap(s, m, false) 109 assert.Equal(t, []int{1, 3, 5}, got1) 110 assert.Equal(t, []int{1, 2, 3, 4, 5}, s) 111 112 got2 := FilterInMap(s, m, true) 113 assert.Equal(t, []int{1, 3, 5}, got2) 114 assert.Equal(t, []int{1, 3, 5, 4, 5}, s) 115 } 116 117 func TestFilterNotInMap(t *testing.T) { 118 s := []int{1, 2, 3, 4, 5} 119 m := map[int]string{1: "", 3: "", 5: ""} 120 121 got1 := FilterNotInMap(s, m, false) 122 assert.Equal(t, []int{2, 4}, got1) 123 assert.Equal(t, []int{1, 2, 3, 4, 5}, s) 124 125 got2 := FilterNotInMap(s, m, true) 126 assert.Equal(t, []int{2, 4}, got2) 127 assert.Equal(t, []int{2, 4, 3, 4, 5}, s) 128 } 129 130 func TestInSlice(t *testing.T) { 131 assert.True(t, InSlice([]int32{4, 5, 6}, int32(6))) 132 assert.False(t, InSlice([]string{"4", "5", "6"}, "7")) 133 } 134 135 func callFunction(f any, args ...any) any { 136 fVal := reflect.ValueOf(f) 137 argsVal := make([]reflect.Value, 0, len(args)) 138 for _, arg := range args { 139 argsVal = append(argsVal, reflect.ValueOf(arg)) 140 } 141 outVals := fVal.Call(argsVal) 142 if len(outVals) > 0 { 143 return outVals[0].Interface() 144 } 145 return nil 146 } 147 148 var splitBatchTests = []map[string]any{ 149 { 150 "total": 0, 151 "batch": 10, 152 "want": []IJ(nil), 153 }, 154 { 155 "total": 72, 156 "batch": -36, 157 "want": []IJ{{0, 72}}, 158 }, 159 { 160 "total": 72, 161 "batch": 0, 162 "want": []IJ{{0, 72}}, 163 }, 164 { 165 "total": 72, 166 "batch": 35, 167 "want": []IJ{{0, 35}, {35, 70}, {70, 72}}, 168 }, 169 { 170 "total": 72, 171 "batch": 24, 172 "want": []IJ{{0, 24}, {24, 48}, {48, 72}}, 173 }, 174 } 175 176 func TestSplitBatch(t *testing.T) { 177 for _, test := range splitBatchTests { 178 got := SplitBatch(test["total"].(int), test["batch"].(int)) 179 assert.Equal(t, test["want"], got) 180 } 181 } 182 183 func TestRepeat(t *testing.T) { 184 s := []int{1, 2, 3} 185 got := Repeat(s, 3) 186 assert.Equal(t, []int{1, 2, 3, 1, 2, 3, 1, 2, 3}, got) 187 } 188 189 func TestReverseSlice(t *testing.T) { 190 var reverseSliceTests = []map[string]any{ 191 { 192 "func": ReverseInt64s, 193 "slice": []int64{1, 2, 3}, 194 "want": []int64{3, 2, 1}, 195 }, 196 { 197 "func": ReverseInt32s, 198 "slice": []int32{1, 2, 3, 4}, 199 "want": []int32{4, 3, 2, 1}, 200 }, 201 { 202 "func": ReverseStrings, 203 "slice": []string{"1", "2", "3"}, 204 "want": []string{"3", "2", "1"}, 205 }, 206 { 207 "func": Reverse[[]int8, int8], 208 "slice": []int8{1, 2, 3, 4}, 209 "want": []int8{4, 3, 2, 1}, 210 }, 211 { 212 "func": Reverse[[]simple, simple], 213 "slice": []simple{{"a"}, {"b"}, {"c"}, {"d"}}, 214 "want": []simple{{"d"}, {"c"}, {"b"}, {"a"}}, 215 }, 216 { 217 "func": Reverse[[]int, int], 218 "slice": []int(nil), 219 "want": []int(nil), 220 }, 221 } 222 for _, test := range reverseSliceTests { 223 got := callFunction(test["func"], test["slice"], false) 224 assert.Equal(t, test["want"], got) 225 } 226 } 227 228 func TestReverseSliceInplace(t *testing.T) { 229 var reverseSliceInplaceTests = []map[string]any{ 230 { 231 "func": ReverseInt64s, 232 "slice": []int64{1, 2, 3}, 233 "want": []int64{3, 2, 1}, 234 }, 235 { 236 "func": ReverseInt32s, 237 "slice": []int32{1, 2, 3}, 238 "want": []int32{3, 2, 1}, 239 }, 240 { 241 "func": ReverseStrings, 242 "slice": []string{"1", "2", "3"}, 243 "want": []string{"3", "2", "1"}, 244 }, 245 { 246 "func": Reverse[[]int8, int8], 247 "slice": []int8{1, 2, 3, 4}, 248 "want": []int8{4, 3, 2, 1}, 249 }, 250 { 251 "func": Reverse[[]simple, simple], 252 "slice": []simple{{"a"}, {"b"}, {"c"}, {"d"}}, 253 "want": []simple{{"d"}, {"c"}, {"b"}, {"a"}}, 254 }, 255 { 256 "func": Reverse[[]int, int], 257 "slice": []int(nil), 258 "want": []int(nil), 259 }, 260 } 261 for _, test := range reverseSliceInplaceTests { 262 got := callFunction(test["func"], test["slice"], true) 263 assert.Equal(t, test["want"], got) 264 assert.Equal(t, test["want"], test["slice"]) 265 } 266 } 267 268 var uniqueSliceTests = []map[string]any{ 269 { 270 "func": UniqueInt64s, 271 "slice": []int64{2, 2, 1, 3, 2, 3, 1, 3}, 272 "want": []int64{2, 1, 3}, 273 }, 274 { 275 "func": UniqueInt32s, 276 "slice": []int32{2, 2, 1, 3, 2, 3, 1, 3}, 277 "want": []int32{2, 1, 3}, 278 }, 279 { 280 "func": UniqueStrings, 281 "slice": []string{"2", "2", "1", "3", "2", "3", "1", "3"}, 282 "want": []string{"2", "1", "3"}, 283 }, 284 } 285 286 func TestUniqueSlice(t *testing.T) { 287 for _, test := range uniqueSliceTests { 288 got := callFunction(test["func"], test["slice"], false) 289 assert.Equal(t, test["want"], got) 290 } 291 for _, test := range uniqueSliceTests { 292 got := callFunction(test["func"], test["slice"], true) 293 assert.Equal(t, test["want"], got) 294 n := reflectx.SliceLen(got) 295 changed := reflect.ValueOf(test["slice"]).Slice(0, n).Interface() 296 assert.Equal(t, test["want"], changed) 297 } 298 } 299 300 func TestUniqueByLoopCmp(t *testing.T) { 301 var dst0 []int64 302 src0 := uniqueSliceTests[0]["slice"].([]int64) 303 want0 := uniqueSliceTests[0]["want"].([]int64) 304 got0 := uniqueByLoopCmp(dst0, src0) 305 assert.Equal(t, want0, got0) 306 307 var dst1 []int32 308 src1 := uniqueSliceTests[1]["slice"].([]int32) 309 want1 := uniqueSliceTests[1]["want"].([]int32) 310 got1 := uniqueByLoopCmp(dst1, src1) 311 assert.Equal(t, want1, got1) 312 313 var dst2 []string 314 src2 := uniqueSliceTests[2]["slice"].([]string) 315 want2 := uniqueSliceTests[2]["want"].([]string) 316 got2 := uniqueByLoopCmp(dst2, src2) 317 assert.Equal(t, want2, got2) 318 } 319 320 func TestUniqueByHashset(t *testing.T) { 321 var dst0 []int64 322 src0 := uniqueSliceTests[0]["slice"].([]int64) 323 want0 := uniqueSliceTests[0]["want"].([]int64) 324 got0 := uniqueByHashset(dst0, src0) 325 assert.Equal(t, want0, got0) 326 327 var dst1 []int32 328 src1 := uniqueSliceTests[1]["slice"].([]int32) 329 want1 := uniqueSliceTests[1]["want"].([]int32) 330 got1 := uniqueByHashset(dst1, src1) 331 assert.Equal(t, want1, got1) 332 333 var dst2 []string 334 src2 := uniqueSliceTests[2]["slice"].([]string) 335 want2 := uniqueSliceTests[2]["want"].([]string) 336 got2 := uniqueByHashset(dst2, src2) 337 assert.Equal(t, want2, got2) 338 } 339 340 func TestUniqueFunc(t *testing.T) { 341 src0 := uniqueSliceTests[0]["slice"].([]int64) 342 want0 := uniqueSliceTests[0]["want"].([]int64) 343 got0 := UniqueFunc(src0, false, func(e int64) int32 { 344 return int32(e) 345 }) 346 assert.Equal(t, want0, got0) 347 348 src2 := uniqueSliceTests[2]["slice"].([]string) 349 want2 := uniqueSliceTests[2]["want"].([]string) 350 got2 := UniqueFunc(src2, false, func(e string) string { 351 return e 352 }) 353 assert.Equal(t, want2, got2) 354 } 355 356 func TestSum(t *testing.T) { 357 s1 := []int{1, 2, 3, 4, 5} 358 assert.Equal(t, int64(15), Sum(s1)) 359 s2 := []uint8{1, 2, 3, 4, 5} 360 assert.Equal(t, int64(15), Sum(s2)) 361 } 362 363 func TestSumFloat(t *testing.T) { 364 s1 := []int{1, 2, 3, 4, 5} 365 assert.Equal(t, float64(15), SumFloat(s1)) 366 s2 := []float32{1, 2, 3, 4, 5} 367 assert.Equal(t, float64(15), SumFloat(s2)) 368 } 369 370 func TestSort(t *testing.T) { 371 s1 := []int{5, 3, 4, 8, 2, 1, 9} 372 want1 := []int{1, 2, 3, 4, 5, 8, 9} 373 assert.Equal(t, want1, Sort(s1)) 374 375 s2 := []string{"b", "c", "a"} 376 want2 := []string{"a", "b", "c"} 377 assert.Equal(t, want2, Sort(s2)) 378 } 379 380 func TestSortDesc(t *testing.T) { 381 s1 := []int{5, 3, 4, 8, 2, 1, 9} 382 want1 := []int{9, 8, 5, 4, 3, 2, 1} 383 assert.Equal(t, want1, SortDesc(s1)) 384 385 s2 := []string{"b", "c", "a"} 386 want2 := []string{"c", "b", "a"} 387 assert.Equal(t, want2, SortDesc(s2)) 388 } 389 390 var benchUniqueData []int64 391 var benchUniqueDst []int64 392 393 func initBenchUniqueData() { 394 if len(benchUniqueData) > 0 { 395 return 396 } 397 for i := 0; i < 10000; i++ { 398 benchUniqueData = append(benchUniqueData, rand.Int63()) 399 } 400 benchUniqueDst = make([]int64, 10000) 401 } 402 403 func BenchmarkUniqueByLoopCmp_64(b *testing.B) { 404 initBenchUniqueData() 405 f := uniqueByLoopCmp[[]int64, int64] 406 407 b.ReportAllocs() 408 b.ResetTimer() 409 for i := 0; i < b.N; i++ { 410 got := execUniqueFunc(64, f) 411 _ = got 412 } 413 } 414 415 func BenchmarkUniqueByHashset_64(b *testing.B) { 416 initBenchUniqueData() 417 f := uniqueByHashset[[]int64, int64] 418 419 b.ReportAllocs() 420 b.ResetTimer() 421 for i := 0; i < b.N; i++ { 422 got := execUniqueFunc(64, f) 423 _ = got 424 } 425 } 426 427 func BenchmarkUniqueByLoopCmp_128(b *testing.B) { 428 initBenchUniqueData() 429 f := uniqueByLoopCmp[[]int64, int64] 430 431 b.ReportAllocs() 432 b.ResetTimer() 433 for i := 0; i < b.N; i++ { 434 got := execUniqueFunc(128, f) 435 _ = got 436 } 437 } 438 439 func BenchmarkUniqueByHashset_128(b *testing.B) { 440 initBenchUniqueData() 441 f := uniqueByHashset[[]int64, int64] 442 443 b.ReportAllocs() 444 b.ResetTimer() 445 for i := 0; i < b.N; i++ { 446 got := execUniqueFunc(128, f) 447 _ = got 448 } 449 } 450 451 func BenchmarkUniqueByLoopCmp_256(b *testing.B) { 452 initBenchUniqueData() 453 f := uniqueByLoopCmp[[]int64, int64] 454 455 b.ReportAllocs() 456 b.ResetTimer() 457 for i := 0; i < b.N; i++ { 458 got := execUniqueFunc(256, f) 459 _ = got 460 } 461 } 462 463 func BenchmarkUniqueByHashset_256(b *testing.B) { 464 initBenchUniqueData() 465 f := uniqueByHashset[[]int64, int64] 466 467 b.ReportAllocs() 468 b.ResetTimer() 469 for i := 0; i < b.N; i++ { 470 got := execUniqueFunc(256, f) 471 _ = got 472 } 473 } 474 475 func BenchmarkUniqueByLoopCmp_512(b *testing.B) { 476 initBenchUniqueData() 477 f := uniqueByLoopCmp[[]int64, int64] 478 479 b.ReportAllocs() 480 b.ResetTimer() 481 for i := 0; i < b.N; i++ { 482 got := execUniqueFunc(512, f) 483 _ = got 484 } 485 } 486 487 func BenchmarkUniqueByHashset_512(b *testing.B) { 488 initBenchUniqueData() 489 f := uniqueByHashset[[]int64, int64] 490 491 b.ReportAllocs() 492 b.ResetTimer() 493 for i := 0; i < b.N; i++ { 494 got := execUniqueFunc(512, f) 495 _ = got 496 } 497 } 498 499 func BenchmarkUniqueByLoopCmp_1024(b *testing.B) { 500 initBenchUniqueData() 501 f := uniqueByLoopCmp[[]int64, int64] 502 503 b.ReportAllocs() 504 b.ResetTimer() 505 for i := 0; i < b.N; i++ { 506 got := execUniqueFunc(1024, f) 507 _ = got 508 } 509 } 510 511 func BenchmarkUniqueByHashset_1024(b *testing.B) { 512 initBenchUniqueData() 513 f := uniqueByHashset[[]int64, int64] 514 515 b.ReportAllocs() 516 b.ResetTimer() 517 for i := 0; i < b.N; i++ { 518 got := execUniqueFunc(1024, f) 519 _ = got 520 } 521 } 522 523 func execUniqueFunc(length int, f func(dst, src []int64) []int64) []int64 { 524 dst := benchUniqueDst[:0] 525 src := benchUniqueData[:length] 526 return f(dst, src) 527 }