github.com/prysmaticlabs/prysm@v1.4.4/shared/abool/abool_test.go (about) 1 // All rights reserved to https://github.com/tevino/abool. 2 package abool 3 4 import ( 5 "math" 6 "sync" 7 "sync/atomic" 8 "testing" 9 ) 10 11 func TestDefaultValue(t *testing.T) { 12 t.Parallel() 13 v := New() 14 if v.IsSet() { 15 t.Fatal("Empty value of AtomicBool should be false") 16 } 17 18 v = NewBool(true) 19 if !v.IsSet() { 20 t.Fatal("NewValue(true) should be true") 21 } 22 23 v = NewBool(false) 24 if v.IsSet() { 25 t.Fatal("NewValue(false) should be false") 26 } 27 } 28 29 func TestIsNotSet(t *testing.T) { 30 t.Parallel() 31 v := New() 32 33 if v.IsSet() == v.IsNotSet() { 34 t.Fatal("AtomicBool.IsNotSet() should be the opposite of IsSet()") 35 } 36 } 37 38 func TestSetUnSet(t *testing.T) { 39 t.Parallel() 40 v := New() 41 42 v.Set() 43 if !v.IsSet() { 44 t.Fatal("AtomicBool.Set() failed") 45 } 46 47 v.UnSet() 48 if v.IsSet() { 49 t.Fatal("AtomicBool.UnSet() failed") 50 } 51 } 52 53 func TestSetTo(t *testing.T) { 54 t.Parallel() 55 v := New() 56 57 v.SetTo(true) 58 if !v.IsSet() { 59 t.Fatal("AtomicBool.SetTo(true) failed") 60 } 61 62 v.SetTo(false) 63 if v.IsSet() { 64 t.Fatal("AtomicBool.SetTo(false) failed") 65 } 66 67 if set := v.SetToIf(true, false); set || v.IsSet() { 68 t.Fatal("AtomicBool.SetTo(true, false) failed") 69 } 70 71 if set := v.SetToIf(false, true); !set || !v.IsSet() { 72 t.Fatal("AtomicBool.SetTo(false, true) failed") 73 } 74 } 75 76 func TestToggle(t *testing.T) { 77 t.Parallel() 78 v := New() 79 80 _ = v.Toggle() 81 if !v.IsSet() { 82 t.Fatal("AtomicBool.Toggle() to true failed") 83 } 84 85 prev := v.Toggle() 86 if v.IsSet() == prev { 87 t.Fatal("AtomicBool.Toggle() to false failed") 88 } 89 } 90 91 func TestToogleMultipleTimes(t *testing.T) { 92 t.Parallel() 93 94 v := New() 95 pre := !v.IsSet() 96 for i := 0; i < 100; i++ { 97 v.SetTo(false) 98 for j := 0; j < i; j++ { 99 pre = v.Toggle() 100 } 101 102 expected := i%2 != 0 103 if v.IsSet() != expected { 104 t.Fatalf("AtomicBool.Toogle() doesn't work after %d calls, expected: %v, got %v", i, expected, v.IsSet()) 105 } 106 107 if pre == v.IsSet() { 108 t.Fatalf("AtomicBool.Toogle() returned wrong value at the %dth calls, expected: %v, got %v", i, !v.IsSet(), pre) 109 } 110 } 111 } 112 113 func TestToogleAfterOverflow(t *testing.T) { 114 t.Parallel() 115 116 var value int32 = math.MaxInt32 117 v := (*AtomicBool)(&value) 118 119 valueBeforeToggle := *(*int32)(v) 120 121 // test first toggle after overflow 122 v.Toggle() 123 expected := math.MaxInt32%2 == 0 124 if v.IsSet() != expected { 125 t.Fatalf("AtomicBool.Toogle() doesn't work after overflow, expected: %v, got %v", expected, v.IsSet()) 126 } 127 128 // make sure overflow happened 129 var valueAfterToggle = *(*int32)(v) 130 if valueAfterToggle >= valueBeforeToggle { 131 t.Fatalf("Overflow does not happen as expected, before %d, after: %d", valueBeforeToggle, valueAfterToggle) 132 } 133 134 // test second toggle after overflow 135 v.Toggle() 136 expected = !expected 137 if v.IsSet() != expected { 138 t.Fatalf("AtomicBool.Toogle() doesn't work after the second call after overflow, expected: %v, got %v", expected, v.IsSet()) 139 } 140 } 141 142 func TestRace(t *testing.T) { 143 t.Parallel() 144 145 repeat := 10000 146 var wg sync.WaitGroup 147 wg.Add(repeat * 4) 148 v := New() 149 150 // Writer 151 go func() { 152 for i := 0; i < repeat; i++ { 153 v.Set() 154 wg.Done() 155 } 156 }() 157 158 // Reader 159 go func() { 160 for i := 0; i < repeat; i++ { 161 v.IsSet() 162 wg.Done() 163 } 164 }() 165 166 // Writer 167 go func() { 168 for i := 0; i < repeat; i++ { 169 v.UnSet() 170 wg.Done() 171 } 172 }() 173 174 // Reader And Writer 175 go func() { 176 for i := 0; i < repeat; i++ { 177 v.Toggle() 178 wg.Done() 179 } 180 }() 181 182 wg.Wait() 183 } 184 185 func ExampleAtomicBool() { 186 cond := New() // default to false 187 cond.Set() // Sets to true 188 cond.IsSet() // Returns true 189 cond.UnSet() // Sets to false 190 cond.IsNotSet() // Returns true 191 cond.SetTo(true) // Sets to whatever you want 192 cond.SetToIf(true, false) // Sets to `new` only if the Boolean matches the `old`, returns whether succeeded 193 cond.Toggle() // Inverts the boolean then returns the value before inverting 194 } 195 196 // Benchmark Read 197 198 func BenchmarkMutexRead(b *testing.B) { 199 var m sync.RWMutex 200 var v bool 201 b.ResetTimer() 202 for i := 0; i < b.N; i++ { 203 m.RLock() 204 _ = v 205 m.RUnlock() 206 } 207 } 208 209 func BenchmarkAtomicValueRead(b *testing.B) { 210 var v atomic.Value 211 b.ResetTimer() 212 for i := 0; i < b.N; i++ { 213 _ = v.Load() != nil 214 } 215 } 216 217 func BenchmarkAtomicBoolRead(b *testing.B) { 218 v := New() 219 b.ResetTimer() 220 for i := 0; i < b.N; i++ { 221 _ = v.IsSet() 222 } 223 } 224 225 // Benchmark Write 226 227 func BenchmarkMutexWrite(b *testing.B) { 228 var m sync.RWMutex 229 var v bool 230 b.ResetTimer() 231 for i := 0; i < b.N; i++ { 232 m.RLock() 233 v = true 234 m.RUnlock() 235 } 236 b.StopTimer() 237 _ = v 238 } 239 240 func BenchmarkAtomicValueWrite(b *testing.B) { 241 var v atomic.Value 242 b.ResetTimer() 243 for i := 0; i < b.N; i++ { 244 v.Store(true) 245 } 246 } 247 248 func BenchmarkAtomicBoolWrite(b *testing.B) { 249 v := New() 250 b.ResetTimer() 251 for i := 0; i < b.N; i++ { 252 v.Set() 253 } 254 } 255 256 // Benchmark CAS 257 258 func BenchmarkMutexCAS(b *testing.B) { 259 var m sync.RWMutex 260 var v bool 261 b.ResetTimer() 262 for i := 0; i < b.N; i++ { 263 m.Lock() 264 if !v { 265 v = true 266 } 267 m.Unlock() 268 } 269 } 270 271 func BenchmarkAtomicBoolCAS(b *testing.B) { 272 v := New() 273 b.ResetTimer() 274 for i := 0; i < b.N; i++ { 275 v.SetToIf(false, true) 276 } 277 } 278 279 // Benchmark toggle 280 281 func BenchmarkMutexToggle(b *testing.B) { 282 var m sync.RWMutex 283 var v bool 284 b.ResetTimer() 285 for i := 0; i < b.N; i++ { 286 m.Lock() 287 v = !v 288 m.Unlock() 289 } 290 } 291 292 func BenchmarkAtomicBoolToggle(b *testing.B) { 293 v := New() 294 b.ResetTimer() 295 for i := 0; i < b.N; i++ { 296 v.Toggle() 297 } 298 }