diff --git a/taskfile/node_stdin.go b/taskfile/node_stdin.go index 0816d1a0a3..e05c88bae5 100644 --- a/taskfile/node_stdin.go +++ b/taskfile/node_stdin.go @@ -1,8 +1,7 @@ package taskfile import ( - "bufio" - "fmt" + "io" "os" "github.com/go-task/task/v3/internal/execext" @@ -29,15 +28,7 @@ func (node *StdinNode) Remote() bool { } func (node *StdinNode) Read() ([]byte, error) { - var stdin []byte - scanner := bufio.NewScanner(os.Stdin) - for scanner.Scan() { - stdin = fmt.Appendln(stdin, scanner.Text()) - } - if err := scanner.Err(); err != nil { - return nil, err - } - return stdin, nil + return io.ReadAll(os.Stdin) } func (node *StdinNode) ResolveEntrypoint(entrypoint string) (string, error) { diff --git a/taskfile/node_stdin_test.go b/taskfile/node_stdin_test.go new file mode 100644 index 0000000000..35d8f68fa3 --- /dev/null +++ b/taskfile/node_stdin_test.go @@ -0,0 +1,65 @@ +package taskfile + +import ( + "os" + "path/filepath" + "strings" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestStdinNodeReadPreservesInput(t *testing.T) { //nolint:paralleltest // replaces process-wide stdin + node, err := NewStdinNode("") + require.NoError(t, err) + + tests := []struct { + name string + input []byte + }{ + { + name: "line longer than 64 KiB", + input: []byte(strings.Repeat("a", 64*1024+1)), + }, + { + name: "no trailing newline", + input: []byte("version: '3'"), + }, + { + name: "CRLF line endings", + input: []byte("version: '3'\r\ntasks:\r\n"), + }, + { + name: "empty input", + input: []byte{}, + }, + } + + for _, tt := range tests { //nolint:paralleltest // subtests replace process-wide stdin + t.Run(tt.name, func(t *testing.T) { + replaceStdin(t, tt.input) + + got, err := node.Read() + require.NoError(t, err) + assert.Equal(t, tt.input, got) + }) + } +} + +func replaceStdin(t *testing.T, input []byte) { + t.Helper() + + path := filepath.Join(t.TempDir(), "stdin") + require.NoError(t, os.WriteFile(path, input, 0o600)) + + stdin, err := os.Open(path) + require.NoError(t, err) + + original := os.Stdin + os.Stdin = stdin + t.Cleanup(func() { + os.Stdin = original + require.NoError(t, stdin.Close()) + }) +}