Browse Source

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).
Joey H 2 năm trước cách đây
mục cha
commit
8948278568
2 tập tin đã thay đổi với 48 bổ sung0 xóa
  1. 10 0
      pkg/settings/parser/parser.go
  2. 38 0
      pkg/settings/parser/parser_test.go

+ 10 - 0
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)
 

+ 38 - 0
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)
+}