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  }