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.

Reply via email to