From a558f5a85c6e4c15f2b8fc8641a5f4018a3486ed Mon Sep 17 00:00:00 2001 From: Gene Heinrich Date: Thu, 18 Jul 2024 16:55:30 -0400 Subject: [PATCH] Fix data race in keyboard.Listen() and unit tests, enable race detection --- .github/workflows/go.yml | 2 +- go.mod | 16 +++++++++++++++- go.sum | 3 --- keyboard.go | 10 ++++++---- keyboard_test.go | 5 +++++ 5 files changed, 27 insertions(+), 9 deletions(-) diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index cd98365..a5b1920 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -36,7 +36,7 @@ jobs: run: go build -v . - name: Test - run: go test -coverprofile="coverage.txt" -covermode=atomic -v -p 1 . + run: go test -coverprofile="coverage.txt" -covermode=atomic -v -p 1 . -race - name: Upload coverage to Codecov uses: codecov/codecov-action@v1 diff --git a/go.mod b/go.mod index 6951cd5..9edcc39 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,22 @@ module atomicgo.dev/keyboard -go 1.15 +go 1.19 require ( github.com/MarvinJWendt/testza v0.4.2 github.com/containerd/console v1.0.3 ) + +require ( + github.com/atomicgo/cursor v0.0.1 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/gookit/color v1.5.0 // indirect + github.com/klauspost/cpuid/v2 v2.0.12 // indirect + github.com/mattn/go-runewidth v0.0.13 // indirect + github.com/pterm/pterm v0.12.40 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/sergi/go-diff v1.2.0 // indirect + github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect + golang.org/x/sys v0.0.0-20220319134239-a9b59b0215f8 // indirect + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect +) diff --git a/go.sum b/go.sum index e63e9bd..0d53491 100644 --- a/go.sum +++ b/go.sum @@ -20,10 +20,8 @@ github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa02 github.com/klauspost/cpuid/v2 v2.0.10/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= github.com/klauspost/cpuid/v2 v2.0.12 h1:p9dKCg8i4gmOxtv35DvrYoWqYzQrvEVdjQ762Y0OqZE= github.com/klauspost/cpuid/v2 v2.0.12/go.mod h1:g2LTdtYhdyuGPqyWyv7qRAmj1WBqxuObKfj5c0PQa7c= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= @@ -60,7 +58,6 @@ golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuX golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/keyboard.go b/keyboard.go index 0171d22..b7ed4d5 100644 --- a/keyboard.go +++ b/keyboard.go @@ -3,6 +3,7 @@ package keyboard import ( "fmt" "os" + "sync/atomic" "github.com/containerd/console" @@ -68,7 +69,7 @@ func stopListener() error { // }) func Listen(onKeyPress func(key keys.Key) (stop bool, err error)) error { cancel := make(chan bool) - stopRoutine := false + stopRoutine := atomic.Bool{} go func() { for { @@ -78,11 +79,12 @@ func Listen(onKeyPress func(key keys.Key) (stop bool, err error)) error { return } case keyInfo := <-mockChannel: - stopRoutine, _ = onKeyPress(keyInfo) - if stopRoutine { + shouldStop, _ := onKeyPress(keyInfo) + if shouldStop { closeInput() inputTTY.Close() } + stopRoutine.Store(shouldStop) } } }() @@ -94,7 +96,7 @@ func Listen(onKeyPress func(key keys.Key) (stop bool, err error)) error { } } - for !stopRoutine { + for !stopRoutine.Load() { key, err := getKeyPress() if err != nil { return err diff --git a/keyboard_test.go b/keyboard_test.go index 59f817c..5a1b794 100644 --- a/keyboard_test.go +++ b/keyboard_test.go @@ -1,6 +1,7 @@ package keyboard_test import ( + "sync" "testing" "atomicgo.dev/keyboard" @@ -18,9 +19,13 @@ func TestMocking(t *testing.T) { var aPressed, bPressed, cPressed, enterPressed bool var keyList []keys.Key + var lock = sync.Mutex{} err := keyboard.Listen(func(key keys.Key) (stop bool, err error) { + lock.Lock() keyList = append(keyList, key) + lock.Unlock() + switch key.Code { case keys.RuneKey: switch key.String() {