mirror of
https://github.com/zoriya/bubbles.git
synced 2026-08-05 04:36:07 +00:00
51 lines
1.4 KiB
Go
51 lines
1.4 KiB
Go
package cursor
|
|
|
|
import (
|
|
"sync"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// TestBlinkCmdDataRace tests for a race on [Cursor.blinkTag].
|
|
//
|
|
// The original [Model.Blink] implementation returned a closure over the pointer receiver:
|
|
//
|
|
// return func() tea.Msg {
|
|
// defer cancel()
|
|
// <-ctx.Done()
|
|
// if ctx.Err() == context.DeadlineExceeded {
|
|
// return BlinkMsg{id: m.id, tag: m.blinkTag}
|
|
// }
|
|
// return blinkCanceled{}
|
|
// }
|
|
//
|
|
// A race on “m.blinkTag” will occur if:
|
|
// 1. [Model.Blink] is called e.g. by calling [Model.Focus] from
|
|
// ["charm.land/bubbletea/v2".Model.Update];
|
|
// 2. ["charm.land/bubbletea/v2".handleCommands] is kept sufficiently busy that it does not receive and
|
|
// execute the [Model.BlinkCmd] e.g. by other long running command or commands;
|
|
// 3. at least [Mode.BlinkSpeed] time elapses;
|
|
// 4. [Model.Blink] is called again;
|
|
// 5. ["charm.land/bubbletea/v2".handleCommands] gets around to receiving and executing the original
|
|
// closure.
|
|
//
|
|
// Even if this did not formally race, the value of the tag fetched would be semantically incorrect (likely being the
|
|
// current value rather than the value at the time the closure was created).
|
|
func TestBlinkCmdDataRace(t *testing.T) {
|
|
m := New()
|
|
cmd := m.Blink()
|
|
var wg sync.WaitGroup
|
|
wg.Add(2)
|
|
go func() {
|
|
defer wg.Done()
|
|
time.Sleep(m.BlinkSpeed * 3)
|
|
cmd()
|
|
}()
|
|
go func() {
|
|
defer wg.Done()
|
|
time.Sleep(m.BlinkSpeed * 2)
|
|
m.Blink()
|
|
}()
|
|
wg.Wait()
|
|
}
|