Search code examples
gostdintty

Simulating continuous inputs on stdin and scanning lines


My program normally uses the controlling terminal to read input from the user.

// GetCtty gets the file descriptor of the controlling terminal.
func GetCtty() (*os.File, error) {
    return os.OpenFile("/dev/tty", os.O_RDONLY, 0)
}

I am currently constructing several times a s := bufio.NewScanner(GetCtty()) during the programm and read the input from s.Scan() with s.Text(). Which works nice.

However, for testing I am simulating the following input on stdin to my CLI Go-Program

echo -e "yes\nno\nyes\n" | app

This will not work correctly because the first construction of s and s.Scan() will already have buffered other test inputs which will not be available to a new construction by bufio.NewScanner and subsequent scan.

I am wondering how I can make sure that only one line is read from the stdin stream by s *bufio.Scanner or how I can mock my input to the controlling terminal.

I had several guesses but I am not sure if they work:

  • using only one bufio.Scanner in the whole program is a solution but I did not want to go this way...
  • write back the buffered data to GetCtty() with s.WriteTo(GetCtty()) (?) want work as the stuff gets appended instead of prepended on stdin?
  • Somehow only read a single line and do not consume more bytes, does that untimately mean to read not in chunks but byte by bytes (?)...

Solution

  • Use iotest.OneByteReader to disable buffering in the scanner:

    s := bufio.NewScanner(iotest.OneByteReader(GetCtty()))