On Fri, Nov 5, 2021 at 11:24 PM Amit Saha <amitsaha...@gmail.com> wrote: > > > > On Fri, 5 Nov 2021, 11:08 pm Axel Wagner, <axel.wagner...@googlemail.com> > wrote: >> >> First, to point out the obvious: It is a bad idea to have a test read from >> stdin. You should pass a separate io.Reader and use that. >> >> Next: exec.Cmd.{Stdin,Stdout,Stderr} are all set to os.DevNull by default, >> meaning you don't get any input or output. I assume >> >> - `go test` does not modify Cmd.Stdin (leaving it at os.DevNull) of the >> sub-process it launches and redirects Cmd.{Stdout,Stderr} to buffers. >> - Your test (if you use `exec.Command(…).Run()`) also does not modify any of >> them, so they stay at os.DevNull >> - Other languages have them default to stdin/stdout/stderr of the parent >> process, so they try to read from stdin, which is a line-buffered terminal, >> so it blocks until you input a line. >> >> Again, the solution here should be to not rely on os.Stdin at all, but >> instead test a function which uses a general io.Reader. > > > Great thank you for clarifying that. > > I ran into this as I was writing a test for an interactive input function and > I expected the test to hang but it didn't. So bit of an accidental find and > glad I found this.
I posted this as a blog post: https://echorand.me/posts/go-test-stdin/ - in case someone else finds it useful. Thanks again for your help, Axel. Best Regards, Amit. > > >> >> On Fri, Nov 5, 2021 at 12:48 PM Amit Saha <amitsaha...@gmail.com> wrote: >>> >>> >>> >>> > On 5 Nov 2021, at 10:27 pm, Amit Saha <amitsaha...@gmail.com> wrote: >>> > >>> > I have this test function: >>> > >>> > package main >>> > >>> > import ( >>> > "bufio" >>> > "fmt" >>> > "os" >>> > "testing" >>> > ) >>> > >>> > func TestInput(t *testing.T) { >>> > scanner := bufio.NewScanner(os.Stdin) >>> > msg := "Your name please? Press the Enter key when done" >>> > fmt.Fprintln(os.Stdout, msg) >>> > >>> > scanner.Scan() >>> > if err := scanner.Err(); err != nil { >>> > t.Fatal(err) >>> > } >>> > name := scanner.Text() >>> > if len(name) == 0 { >>> > t.Log("empty input") >>> > } >>> > t.Log(name) >>> > >>> > } >>> > >>> > When i run it via go test -v, this is what i get (TLDR; terminates >>> > without waiting for the interactive input): >>> > >>> > % go test -v >>> > >>> > === RUN TestInput >>> > >>> > Your name please? Press the Enter key when done >>> > >>> > stdin_test.go:21: empty input >>> > >>> > stdin_test.go:23: >>> > >>> > --- PASS: TestInput (0.00s) >>> > >>> > PASS >>> > >>> > ok test 0.370s >>> > >>> > >>> > >>> > However, when i compile the test and then run the binary, it waits for me >>> > to enter the input: >>> > >>> > >>> > >>> > % go test -c >>> > >>> > % ./test.test >>> > >>> > Your name please? Press the Enter key when done >>> > >>> > >>> > >>> > >>> > The latter behavior is more inline with what i was expecting in the first >>> > case as well. >>> > >>> > I thought may be it has something to do with the fact that go test is >>> > executing the binary (i think) after compiling, and started looking at: >>> > https://github.com/golang/go/blob/c7f2f51fed15b410dea5f608420858b401887d0a/src/cmd/go/internal/test/test.go >>> > , but can't see anything obvious. >>> > >>> > Wondering if anyone of you folks have an answer? >>> > >>> >>> Did a bit more of experimentation, and it seems like, that’s just how >>> exec.Command(“mycmd").Run() works. >>> >>> I tried with exec.Command("wc").Run() and it returns immediately as well. >>> (Running the Unix “word count” program). >>> >>> I suppose I am surprised since in another language I am familiar with >>> (Python), a command waiting for an interactive input when executed via >>> os/exec would “hang”, for example: >>> >>> % python3 >>> Python 3.8.2 (default, Apr 8 2021, 23:19:18) >>> [Clang 12.0.5 (clang-1205.0.22.9)] on darwin >>> Type "help", "copyright", "credits" or "license" for more information. >>> >>> import subprocess >>> >>> subprocess.check_output(["wc”]) >>> >>> This will hang >>> >>> > >>> > >>> > Thanks, >>> > >>> > Amit. >>> > >>> > >>> > >>> > >>> > >>> > -- >>> > You received this message because you are subscribed to a topic in the >>> > Google Groups "golang-nuts" group. >>> > To unsubscribe from this topic, visit >>> > https://groups.google.com/d/topic/golang-nuts/24pL7iQbx64/unsubscribe. >>> > To unsubscribe from this group and all its topics, send an email to >>> > golang-nuts+unsubscr...@googlegroups.com. >>> > To view this discussion on the web visit >>> > https://groups.google.com/d/msgid/golang-nuts/0f48fc8d-7e21-46a6-b736-90ea2f0bcbe6n%40googlegroups.com. >>> >>> -- >>> You received this message because you are subscribed to the Google Groups >>> "golang-nuts" group. >>> To unsubscribe from this group and stop receiving emails from it, send an >>> email to golang-nuts+unsubscr...@googlegroups.com. >>> To view this discussion on the web visit >>> https://groups.google.com/d/msgid/golang-nuts/25A4D3EA-F228-447C-A19E-8BE062840E20%40gmail.com. -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CANODV3%3DFhb-jCoxy%2BQ1WKHS9Nt3acca_trHB3Pw0B6fby7%2B_Rg%40mail.gmail.com.