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 }