Skip to content

Commit

Permalink
Test the fancy interruptable reader
Browse files Browse the repository at this point in the history
And add hints for any future Windows implementation.
  • Loading branch information
walles committed Jul 16, 2024
1 parent b77151e commit 0091a15
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 0 deletions.
4 changes: 4 additions & 0 deletions twin/screen-setup-windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ import (
"golang.org/x/term"
)

// NOTE: Karma points for replacing TestInterruptableReader_blockedOnRead() with
// TestInterruptableReader_blockedOnReadImmediate() and fixing the Windows
// implementation here so that the tests pass.

type interruptableReaderImpl struct {
base *os.File
shutdownRequested atomic.Bool
Expand Down
66 changes: 66 additions & 0 deletions twin/screen-setup_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//go:build !windows
// +build !windows

package twin

import (
"io"
"os"
"testing"
"time"

"gotest.tools/v3/assert"
)

// This test should replace TestInterruptableReader_blockedOnRead if or when
// Windows catches up with the shutdown implementation.
func TestInterruptableReader_blockedOnReadImmediate(t *testing.T) {
// Make a pipe to read from and write to
pipeReader, pipeWriter, err := os.Pipe()
assert.NilError(t, err)

// Make an interruptable reader
testMe, err := newInterruptableReader(pipeReader)
assert.NilError(t, err)
assert.Assert(t, testMe != nil)

// Start a thread that reads from the pipe
type readResult struct {
n int
err error
}
readResultChan := make(chan readResult)
go func() {
buffer := make([]byte, 1)
n, err := testMe.Read(buffer)
readResultChan <- readResult{n, err}
}()

// Give the reader thread some time to start waiting
time.Sleep(100 * time.Millisecond)

// Interrupt the reader
testMe.Interrupt()

// Wait for the reader thread to finish
result := <-readResultChan

// Check the result
assert.Equal(t, result.n, 0)
assert.Equal(t, result.err, io.EOF)

// Another read should return EOF immediately
buffer := make([]byte, 1)
n, err := testMe.Read(buffer)
assert.Equal(t, err, io.EOF)
assert.Equal(t, n, 0)

// Even if there are bytes, the interrupted reader should still return EOF
n, err = pipeWriter.Write([]byte{42})
assert.NilError(t, err)
assert.Equal(t, n, 1)

n, err = testMe.Read(buffer)
assert.Equal(t, err, io.EOF)
assert.Equal(t, n, 0)
}
4 changes: 4 additions & 0 deletions twin/screen_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,10 @@ func TestMultiCharHyperlink(t *testing.T) {
//
// What we really want is for the reader to return EOF immediately when
// interrupted, with no write needed.
//
// This test should be replaced by
// TestInterruptableReader_blockedOnReadImmediate if or when the Windows
// implementation catches up.
func TestInterruptableReader_blockedOnRead(t *testing.T) {
// Make a pipe to read from and write to
pipeReader, pipeWriter, err := os.Pipe()
Expand Down

0 comments on commit 0091a15

Please sign in to comment.