github.com/authzed/spicedb@v1.32.1-0.20240520085336-ebda56537386/pkg/genutil/mapz/set_test.go (about)

     1  package mapz
     2  
     3  import (
     4  	"fmt"
     5  	"sort"
     6  	"testing"
     7  
     8  	"github.com/stretchr/testify/require"
     9  )
    10  
    11  func TestSetOperations(t *testing.T) {
    12  	// Create a set and ensure it is empty.
    13  	set := NewSet[string]()
    14  	require.True(t, set.IsEmpty())
    15  
    16  	// Add some items to the set.
    17  	require.True(t, set.Add("hi"))
    18  	require.True(t, set.Add("hello"))
    19  	require.False(t, set.Add("hello"))
    20  	require.True(t, set.Add("heyo"))
    21  
    22  	// Ensure the items are in the set.
    23  	require.False(t, set.IsEmpty())
    24  	require.True(t, set.Has("hi"))
    25  	require.True(t, set.Has("hello"))
    26  	require.True(t, set.Has("heyo"))
    27  
    28  	require.False(t, set.Has("hola"))
    29  	require.False(t, set.Has("hiya"))
    30  
    31  	slice := set.AsSlice()
    32  	sort.Strings(slice)
    33  	require.Equal(t, slice, []string{"hello", "heyo", "hi"})
    34  
    35  	// Delete some items.
    36  	set.Delete("hi")
    37  	set.Delete("hi")
    38  
    39  	require.False(t, set.Has("hi"))
    40  	require.True(t, set.Has("hello"))
    41  	require.True(t, set.Has("heyo"))
    42  
    43  	require.False(t, set.Has("hola"))
    44  	require.False(t, set.Has("hiya"))
    45  
    46  	slice = set.AsSlice()
    47  	sort.Strings(slice)
    48  	require.Equal(t, slice, []string{"hello", "heyo"})
    49  
    50  	// Extend the set with a slice of values
    51  	set.Extend([]string{"1", "2", "3"})
    52  
    53  	slice = set.AsSlice()
    54  	sort.Strings(slice)
    55  	require.Equal(t, slice, []string{"1", "2", "3", "hello", "heyo"})
    56  
    57  	// Create another set and remove its items.
    58  	otherSet := NewSet[string]()
    59  	otherSet.Extend([]string{"1", "2", "3"})
    60  
    61  	set.RemoveAll(otherSet)
    62  
    63  	slice = set.AsSlice()
    64  	sort.Strings(slice)
    65  	require.Equal(t, slice, []string{"hello", "heyo"})
    66  
    67  	// Create a third set and perform intersection difference.
    68  	thirdSet := NewSet[string]()
    69  	thirdSet.Extend([]string{"hello", "hi"})
    70  
    71  	set.IntersectionDifference(thirdSet)
    72  
    73  	slice = set.AsSlice()
    74  	sort.Strings(slice)
    75  	require.Equal(t, slice, []string{"hello"})
    76  }
    77  
    78  func TestSetIntersect(t *testing.T) {
    79  	// Create a set and ensure it is empty.
    80  	set := NewSet[string]()
    81  	require.True(t, set.IsEmpty())
    82  
    83  	// Add some items to the set.
    84  	require.True(t, set.Add("1"))
    85  	require.True(t, set.Add("2"))
    86  	require.True(t, set.Add("3"))
    87  	require.True(t, set.Add("4"))
    88  
    89  	// Subtract some items.
    90  	updated := set.Intersect(NewSet[string]("1", "2", "3", "5"))
    91  	updatedSlice := updated.AsSlice()
    92  	sort.Strings(updatedSlice)
    93  	require.Equal(t, []string{"1", "2", "3"}, updatedSlice)
    94  
    95  	slice := set.AsSlice()
    96  	sort.Strings(slice)
    97  	require.Equal(t, []string{"1", "2", "3", "4"}, slice)
    98  
    99  	// Perform in reverse.
   100  	updated = NewSet[string]("1", "2", "3", "5").Intersect(set)
   101  	updatedSlice = updated.AsSlice()
   102  	sort.Strings(updatedSlice)
   103  	require.Equal(t, []string{"1", "2", "3"}, updatedSlice)
   104  }
   105  
   106  func TestSetSubtract(t *testing.T) {
   107  	// Create a set and ensure it is empty.
   108  	set := NewSet[string]()
   109  	require.True(t, set.IsEmpty())
   110  
   111  	// Add some items to the set.
   112  	require.True(t, set.Add("1"))
   113  	require.True(t, set.Add("2"))
   114  	require.True(t, set.Add("3"))
   115  	require.True(t, set.Add("4"))
   116  
   117  	// Subtract some items.
   118  	updated := set.Subtract(NewSet[string]("1", "2", "3", "5"))
   119  	require.Equal(t, []string{"4"}, updated.AsSlice())
   120  
   121  	slice := set.AsSlice()
   122  	sort.Strings(slice)
   123  	require.Equal(t, []string{"1", "2", "3", "4"}, slice)
   124  }
   125  
   126  func TestEqual(t *testing.T) {
   127  	require.True(t, NewSet[string]().Equal(NewSet[string]()))
   128  	require.True(t, NewSet[string]("2").Equal(NewSet[string]("2")))
   129  	require.False(t, NewSet[string]("1", "2").Equal(NewSet[string]("1", "3")))
   130  }
   131  
   132  func TestUnion(t *testing.T) {
   133  	u1 := NewSet[string]("1", "2").Union(NewSet[string]("2", "3")).AsSlice()
   134  	sort.Strings(u1)
   135  
   136  	u2 := NewSet[string]("2", "3").Union(NewSet[string]("1", "2")).AsSlice()
   137  	sort.Strings(u2)
   138  
   139  	require.Equal(t, []string{"1", "2", "3"}, u1)
   140  	require.Equal(t, []string{"1", "2", "3"}, u2)
   141  }
   142  
   143  func TestMerge(t *testing.T) {
   144  	u1 := NewSet[string]("1", "2")
   145  	u2 := NewSet[string]("2", "3")
   146  
   147  	u1.Merge(u2)
   148  
   149  	slice := u1.AsSlice()
   150  	sort.Strings(slice)
   151  
   152  	require.Equal(t, []string{"1", "2", "3"}, slice)
   153  
   154  	// Try the reverse.
   155  	u1 = NewSet[string]("1", "2")
   156  	u2 = NewSet[string]("2", "3")
   157  
   158  	u2.Merge(u1)
   159  
   160  	slice = u2.AsSlice()
   161  	sort.Strings(slice)
   162  
   163  	require.Equal(t, []string{"1", "2", "3"}, slice)
   164  }
   165  
   166  func TestSetIntersectionDifference(t *testing.T) {
   167  	tcs := []struct {
   168  		first    []int
   169  		second   []int
   170  		expected []int
   171  	}{
   172  		{
   173  			[]int{1, 2, 3, 4, 5},
   174  			[]int{1, 2, 3, 4, 5},
   175  			[]int{1, 2, 3, 4, 5},
   176  		},
   177  		{
   178  			[]int{1, 3, 5, 7, 9},
   179  			[]int{2, 4, 6, 8, 10},
   180  			nil,
   181  		},
   182  		{
   183  			[]int{1, 2, 3, 4, 5},
   184  			[]int{6, 5, 4, 3},
   185  			[]int{3, 4, 5},
   186  		},
   187  	}
   188  
   189  	for index, tc := range tcs {
   190  		tc := tc
   191  		t.Run(fmt.Sprintf("%d", index), func(t *testing.T) {
   192  			firstSet := NewSet[int]()
   193  			firstSet.Extend(tc.first)
   194  
   195  			secondSet := NewSet[int]()
   196  			secondSet.Extend(tc.second)
   197  
   198  			firstSet.IntersectionDifference(secondSet)
   199  			slice := firstSet.AsSlice()
   200  			sort.Ints(slice)
   201  			require.Equal(t, tc.expected, slice)
   202  		})
   203  	}
   204  }
   205  
   206  func BenchmarkAdd(b *testing.B) {
   207  	set := NewSet[int]()
   208  	for i := 0; i < b.N; i++ {
   209  		set.Add(i)
   210  	}
   211  }
   212  
   213  func BenchmarkInsert(b *testing.B) {
   214  	set := NewSet[int]()
   215  	for i := 0; i < b.N; i++ {
   216  		set.Insert(i)
   217  	}
   218  }
   219  
   220  func BenchmarkCopy(b *testing.B) {
   221  	set := NewSet[int]()
   222  	for i := 0; i < b.N; i++ {
   223  		set.Add(i)
   224  	}
   225  	b.ResetTimer()
   226  	for i := 0; i < b.N; i++ {
   227  		set.Copy()
   228  	}
   229  }
   230  
   231  func BenchmarkHas(b *testing.B) {
   232  	set := NewSet[int]()
   233  	for i := 0; i < b.N; i++ {
   234  		set.Add(i)
   235  	}
   236  	b.ResetTimer()
   237  	for i := 0; i < b.N; i++ {
   238  		set.Has(i)
   239  	}
   240  }
   241  
   242  func BenchmarkDelete(b *testing.B) {
   243  	set := NewSet[int]()
   244  	for i := 0; i < b.N; i++ {
   245  		set.Add(i)
   246  	}
   247  	b.ResetTimer()
   248  	for i := 0; i < b.N; i++ {
   249  		set.Delete(i)
   250  	}
   251  }
   252  
   253  func BenchmarkIntersect(b *testing.B) {
   254  	set := NewSet[int]()
   255  	for i := 0; i < b.N; i++ {
   256  		set.Add(i)
   257  	}
   258  	other := NewSet[int]()
   259  	for i := 0; i < b.N; i++ {
   260  		other.Add(i)
   261  	}
   262  	b.ResetTimer()
   263  	for i := 0; i < b.N; i++ {
   264  		set.Intersect(other)
   265  	}
   266  }
   267  
   268  func BenchmarkSubtract(b *testing.B) {
   269  	set := NewSet[int]()
   270  	for i := 0; i < b.N; i++ {
   271  		set.Add(i)
   272  	}
   273  	other := NewSet[int]()
   274  	for i := 0; i < b.N; i++ {
   275  		other.Add(i)
   276  	}
   277  	b.ResetTimer()
   278  	for i := 0; i < b.N; i++ {
   279  		set.Subtract(other)
   280  	}
   281  }
   282  
   283  func BenchmarkAsSlice(b *testing.B) {
   284  	set := NewSet[int]()
   285  	for i := 0; i < b.N; i++ {
   286  		set.Add(i)
   287  	}
   288  	b.ResetTimer()
   289  	for i := 0; i < b.N; i++ {
   290  		set.AsSlice()
   291  	}
   292  }
   293  
   294  func BenchmarkEqual(b *testing.B) {
   295  	set := NewSet[int]()
   296  	for i := 0; i < b.N; i++ {
   297  		set.Add(i)
   298  	}
   299  	other := NewSet[int]()
   300  	for i := 0; i < b.N; i++ {
   301  		other.Add(i)
   302  	}
   303  	b.ResetTimer()
   304  	for i := 0; i < b.N; i++ {
   305  		set.Equal(other)
   306  	}
   307  }
   308  
   309  func BenchmarkExtendFromSlice(b *testing.B) {
   310  	set := NewSet[int]()
   311  	for i := 0; i < b.N; i++ {
   312  		set.Add(i)
   313  	}
   314  	other := NewSet[int]()
   315  	for i := 0; i < b.N; i++ {
   316  		other.Add(i)
   317  	}
   318  	b.ResetTimer()
   319  	for i := 0; i < b.N; i++ {
   320  		set.Extend(other.AsSlice())
   321  	}
   322  }
   323  
   324  func BenchmarkMerge(b *testing.B) {
   325  	set := NewSet[int]()
   326  	for i := 0; i < b.N; i++ {
   327  		set.Add(i)
   328  	}
   329  	other := NewSet[int]()
   330  	for i := 0; i < b.N; i++ {
   331  		other.Add(i)
   332  	}
   333  	b.ResetTimer()
   334  	for i := 0; i < b.N; i++ {
   335  		set.Merge(other)
   336  	}
   337  }
   338  
   339  func BenchmarkUnion(b *testing.B) {
   340  	set := NewSet[int]()
   341  	for i := 0; i < b.N; i++ {
   342  		set.Add(i)
   343  	}
   344  	other := NewSet[int]()
   345  	for i := 0; i < b.N; i++ {
   346  		other.Add(i)
   347  	}
   348  	b.ResetTimer()
   349  	for i := 0; i < b.N; i++ {
   350  		set.Union(other)
   351  	}
   352  }