istio.io/istio@v0.0.0-20240520182934-d79c90f27776/pkg/util/sets/set_test.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package sets 16 17 import ( 18 "fmt" 19 "reflect" 20 "testing" 21 22 "k8s.io/apimachinery/pkg/util/rand" 23 24 "istio.io/istio/pkg/test/util/assert" 25 ) 26 27 func TestNewSet(t *testing.T) { 28 elements := []string{"a", "b", "c"} 29 set := New(elements...) 30 31 if len(set) != len(elements) { 32 t.Errorf("Expected length %d != %d", len(set), len(elements)) 33 } 34 35 for _, e := range elements { 36 if _, exist := set[e]; !exist { 37 t.Errorf("%s is not in set %v", e, set) 38 } 39 } 40 } 41 42 func TestUnion(t *testing.T) { 43 elements := []string{"a", "b", "c", "d"} 44 elements2 := []string{"a", "b", "e"} 45 want := New("a", "b", "c", "d", "e") 46 for _, sets := range [][]Set[string]{ 47 {New(elements...), New(elements2...)}, 48 {New(elements2...), New(elements...)}, 49 } { 50 s1, s2 := sets[0], sets[1] 51 if got := s1.Union(s2); !got.Equals(want) { 52 t.Errorf("expected %v; got %v", want, got) 53 } 54 } 55 } 56 57 func TestDifference(t *testing.T) { 58 s1 := New("a", "b", "c", "d") 59 s2 := New("a", "b", "e") 60 want := New("c", "d") 61 62 t.Run("difference", func(t *testing.T) { 63 d := s1.Difference(s2) 64 if !want.Equals(d) { 65 t.Errorf("want %+v, but got %+v", want, d) 66 } 67 }) 68 69 t.Run("difference in place", func(t *testing.T) { 70 s1c := s1.Copy() 71 r := s1c.DifferenceInPlace(s2) 72 if !want.Equals(r) { 73 t.Errorf("want %+v, but got %+v", want, r) 74 } 75 // s1c should be updated 76 if !want.Equals(s1c) { 77 t.Errorf("want %+v, but got %+v", want, s1c) 78 } 79 }) 80 } 81 82 func TestIntersection(t *testing.T) { 83 s1 := New("a", "b", "d") 84 s2 := New("a", "b", "c") 85 want := New("a", "b") 86 87 t.Run("intersection", func(t *testing.T) { 88 d := s1.Intersection(s2) 89 if !d.Equals(want) { 90 t.Errorf("want %+v, but got %+v", want, d) 91 } 92 }) 93 94 t.Run("intersect in replace", func(t *testing.T) { 95 s1c := s1.Copy() 96 d := s1c.IntersectInPlace(s2) 97 if !want.Equals(d) { 98 t.Errorf("want %+v, but got %+v", want, d) 99 } 100 // s1c should be updated 101 if !want.Equals(s1c) { 102 t.Errorf("want %+v, but got %+v", want, s1c) 103 } 104 }) 105 } 106 107 func TestSupersetOf(t *testing.T) { 108 testCases := []struct { 109 name string 110 first Set[string] 111 second Set[string] 112 want bool 113 }{ 114 { 115 name: "both nil", 116 first: nil, 117 second: nil, 118 want: true, 119 }, 120 { 121 name: "first nil", 122 first: nil, 123 second: New("a"), 124 want: false, 125 }, 126 { 127 name: "second nil", 128 first: New("a"), 129 second: nil, 130 want: true, 131 }, 132 { 133 name: "both empty", 134 first: New[string](), 135 second: New[string](), 136 want: true, 137 }, 138 { 139 name: "first empty", 140 first: New[string](), 141 second: New("a"), 142 want: false, 143 }, 144 { 145 name: "second empty", 146 first: New("a"), 147 second: New[string](), 148 want: true, 149 }, 150 { 151 name: "equal", 152 first: New("a", "b"), 153 second: New("a", "b"), 154 want: true, 155 }, 156 { 157 name: "first contains all second", 158 first: New("a", "b", "c"), 159 second: New("a", "b"), 160 want: true, 161 }, 162 { 163 name: "second contains all first", 164 first: New("a", "b"), 165 second: New("a", "b", "c"), 166 want: false, 167 }, 168 } 169 for _, tt := range testCases { 170 t.Run(tt.name, func(t *testing.T) { 171 if got := tt.first.SupersetOf(tt.second); got != tt.want { 172 t.Errorf("want %v, but got %v", tt.want, got) 173 } 174 }) 175 } 176 } 177 178 func BenchmarkSupersetOf(b *testing.B) { 179 set1 := New[string]() 180 for i := 0; i < 1000; i++ { 181 set1.Insert(fmt.Sprint(i)) 182 } 183 set2 := New[string]() 184 for i := 0; i < 50; i++ { 185 set2.Insert(fmt.Sprint(i)) 186 } 187 b.ResetTimer() 188 189 b.Run("SupersetOf", func(b *testing.B) { 190 for n := 0; n < b.N; n++ { 191 set1.SupersetOf(set2) 192 } 193 }) 194 } 195 196 func TestEquals(t *testing.T) { 197 tests := []struct { 198 name string 199 first Set[string] 200 second Set[string] 201 want bool 202 }{ 203 { 204 "both nil", 205 nil, 206 nil, 207 true, 208 }, 209 { 210 "unequal length", 211 New("test"), 212 New("test", "test1"), 213 false, 214 }, 215 { 216 "equal sets", 217 New("test", "test1"), 218 New("test", "test1"), 219 true, 220 }, 221 { 222 "unequal sets", 223 New("test", "test1"), 224 New("test", "test2"), 225 false, 226 }, 227 } 228 for _, tt := range tests { 229 t.Run(tt.name, func(t *testing.T) { 230 if got := tt.first.Equals(tt.second); got != tt.want { 231 t.Errorf("Unexpected Equal. got %v, want %v", got, tt.want) 232 } 233 }) 234 } 235 } 236 237 func TestMerge(t *testing.T) { 238 cases := []struct { 239 s1, s2 Set[string] 240 expected []string 241 }{ 242 { 243 s1: New("a1", "a2"), 244 s2: New("a1", "a2"), 245 expected: []string{"a1", "a2"}, 246 }, 247 { 248 s1: New("a1", "a2", "a3"), 249 s2: New("a1", "a2"), 250 expected: []string{"a1", "a2", "a3"}, 251 }, 252 { 253 s1: New("a1", "a2"), 254 s2: New("a3", "a4"), 255 expected: []string{"a1", "a2", "a3", "a4"}, 256 }, 257 } 258 259 for _, tc := range cases { 260 got := tc.s1.Merge(tc.s2) 261 assert.Equal(t, tc.expected, SortedList(got)) 262 } 263 } 264 265 func TestInsertAll(t *testing.T) { 266 tests := []struct { 267 name string 268 s Set[string] 269 items []string 270 want Set[string] 271 }{ 272 { 273 name: "insert new item", 274 s: New("a1", "a2"), 275 items: []string{"a3"}, 276 want: New("a1", "a2", "a3"), 277 }, 278 { 279 name: "inserted item already exists", 280 s: New("a1", "a2"), 281 items: []string{"a1"}, 282 want: New("a1", "a2"), 283 }, 284 } 285 for _, tt := range tests { 286 t.Run(tt.name, func(t *testing.T) { 287 if got := tt.s.InsertAll(tt.items...); !reflect.DeepEqual(got, tt.want) { 288 t.Errorf("InsertAll() = %v, want %v", got, tt.want) 289 } 290 }) 291 } 292 } 293 294 func TestInsertContains(t *testing.T) { 295 s := New[string]() 296 assert.Equal(t, s.InsertContains("k1"), false) 297 assert.Equal(t, s.InsertContains("k1"), true) 298 assert.Equal(t, s.InsertContains("k2"), false) 299 assert.Equal(t, s.InsertContains("k2"), true) 300 } 301 302 func BenchmarkSet(b *testing.B) { 303 containsTest := New[string]() 304 for i := 0; i < 1000; i++ { 305 containsTest.Insert(fmt.Sprint(i)) 306 } 307 sortOrder := []string{} 308 for i := 0; i < 1000; i++ { 309 sortOrder = append(sortOrder, fmt.Sprint(rand.Intn(1000))) 310 } 311 b.ResetTimer() 312 var s Set[string] // ensure no inlining 313 b.Run("insert", func(b *testing.B) { 314 for n := 0; n < b.N; n++ { 315 s = New[string]() 316 for i := 0; i < 1000; i++ { 317 s.Insert("item") 318 } 319 } 320 }) 321 b.Run("contains", func(b *testing.B) { 322 for n := 0; n < b.N; n++ { 323 containsTest.Contains("100") 324 } 325 }) 326 b.Run("sorted", func(b *testing.B) { 327 for n := 0; n < b.N; n++ { 328 b.StopTimer() 329 s := New(sortOrder...) 330 b.StartTimer() 331 SortedList(s) 332 } 333 }) 334 } 335 336 func TestMapOfSet(t *testing.T) { 337 m := map[int]String{} 338 InsertOrNew(m, 1, "a") 339 InsertOrNew(m, 1, "b") 340 InsertOrNew(m, 2, "c") 341 assert.Equal(t, m, map[int]String{1: New("a", "b"), 2: New("c")}) 342 343 DeleteCleanupLast(m, 1, "a") 344 assert.Equal(t, m, map[int]String{1: New("b"), 2: New("c")}) 345 DeleteCleanupLast(m, 1, "b") 346 DeleteCleanupLast(m, 1, "not found") 347 assert.Equal(t, m, map[int]String{2: New("c")}) 348 } 349 350 func TestSetString(t *testing.T) { 351 elements := []string{"a"} 352 set := New(elements...) 353 assert.Equal(t, "[a]", set.String()) 354 } 355 356 func BenchmarkOperateInPlace(b *testing.B) { 357 s1 := New[int]() 358 for i := 0; i < 100; i++ { 359 s1.Insert(i) 360 } 361 s2 := New[int]() 362 for i := 0; i < 100; i += 2 { 363 s2.Insert(i) 364 } 365 b.ResetTimer() 366 367 b.Run("Difference", func(b *testing.B) { 368 for i := 0; i < b.N; i++ { 369 s1.Difference(s2) 370 } 371 }) 372 b.Run("DifferenceInPlace", func(b *testing.B) { 373 for i := 0; i < b.N; i++ { 374 s1.DifferenceInPlace(s2) 375 } 376 }) 377 b.Run("Intersection", func(b *testing.B) { 378 for i := 0; i < b.N; i++ { 379 s1.Intersection(s2) 380 } 381 }) 382 b.Run("IntersectInPlace", func(b *testing.B) { 383 for i := 0; i < b.N; i++ { 384 s1.IntersectInPlace(s2) 385 } 386 }) 387 }