From 89482785682ae8391598f753119cdcbeeca70b4e Mon Sep 17 00:00:00 2001 From: Joey H <89617856+jdholtz@users.noreply.github.com> Date: Tue, 3 Jan 2023 13:43:15 -0600 Subject: [PATCH] fix(parser): ensure data is piped when using '-' argument (#1881) fix(parser): ensure data is piped when using '-' argument Fixes #1626. Check to see if data was actually piped to yay, otherwise it will hang forever. This error will give users better feedback of how to use the '-' argument (it is also the same exact error pacman throws for invalid piped data). Two tests were added. However, I didn't know how to add a test for the actual part that detects whether data was piped or not (which is essentially what this commit adds). --- pkg/settings/parser/parser.go | 10 ++++++++ pkg/settings/parser/parser_test.go | 38 ++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/pkg/settings/parser/parser.go b/pkg/settings/parser/parser.go index 38a64814..b9a2b534 100644 --- a/pkg/settings/parser/parser.go +++ b/pkg/settings/parser/parser.go @@ -610,6 +610,16 @@ func (a *Arguments) parseLongOption(arg, param string) (usedNext bool, err error } func (a *Arguments) parseStdin() error { + fi, err := os.Stdin.Stat() + if err != nil { + return err + } + + // Ensure data is piped + if (fi.Mode() & os.ModeCharDevice) != 0 { + return errors.New(gotext.Get("argument '-' specified without input on stdin")) + } + scanner := bufio.NewScanner(os.Stdin) scanner.Split(bufio.ScanLines) diff --git a/pkg/settings/parser/parser_test.go b/pkg/settings/parser/parser_test.go index 013ee9a9..0e4956a6 100644 --- a/pkg/settings/parser/parser_test.go +++ b/pkg/settings/parser/parser_test.go @@ -1,9 +1,11 @@ package parser import ( + "os" "testing" "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" ) func TestOption_Add(t *testing.T) { @@ -330,3 +332,39 @@ func Test_isArg(t *testing.T) { got = isArg("dbpath") assert.True(t, got) } + +func TestArguments_ParseStdin(t *testing.T) { + input := []byte("yay") + + r, w, err := os.Pipe() + require.NoError(t, err) + + _, err = w.Write(input) + require.NoError(t, err) + w.Close() + + // Restore stdin after the test. + defer func(o *os.File) { os.Stdin = o }(os.Stdin) + os.Stdin = r + + args := MakeArguments() + err = args.parseStdin() + assert.NoError(t, err) + + expectedTargets := []string{string(input)} + assert.ElementsMatch(t, args.Targets, expectedTargets) +} + +func TestArguments_ParseStdin_broken_pipe(t *testing.T) { + r, _, err := os.Pipe() + require.NoError(t, err) + r.Close() // Close early to break pipe + + // Restore stdin after the test. + defer func(o *os.File) { os.Stdin = o }(os.Stdin) + os.Stdin = r + + args := MakeArguments() + err = args.parseStdin() + assert.Error(t, err) +}