github.com/asifdxtreme/cli@v6.1.3-0.20150123051144-9ead8700b4ae+incompatible/testhelpers/io/io.go (about) 1 package io 2 3 import ( 4 "bytes" 5 "io" 6 "os" 7 "strings" 8 ) 9 10 func SimulateStdin(input string, block func(r io.Reader)) { 11 reader, writer := io.Pipe() 12 13 go func() { 14 writer.Write([]byte(input)) 15 defer writer.Close() 16 }() 17 18 block(reader) 19 } 20 21 func CaptureOutput(block func()) []string { 22 oldSTDOUT := os.Stdout 23 r, w, err := os.Pipe() 24 if err != nil { 25 panic(err) 26 } 27 28 os.Stdout = w 29 defer func() { 30 os.Stdout = oldSTDOUT 31 }() 32 33 doneWriting := make(chan bool) 34 result := make(chan []string) 35 36 go captureOutputAsyncronously(doneWriting, result, r) 37 38 block() 39 w.Close() 40 doneWriting <- true 41 return <-result 42 } 43 44 /* 45 The reason we're doing is that you can't write an infinite amount of bytes into a pipe. 46 On some platforms, the limit is fairly high; on other platforms, the limit is infuriatingly small 47 (looking at you, Windows). To counteract this, we need to read in a goroutine from one end of 48 the pipe and return the result across a channel. 49 */ 50 func captureOutputAsyncronously(doneWriting <-chan bool, result chan<- []string, reader io.Reader) { 51 var readingString string 52 53 for { 54 var buf bytes.Buffer 55 io.Copy(&buf, reader) 56 readingString += buf.String() 57 58 _, ok := <-doneWriting 59 if ok { 60 // there is no guarantee that the writer did not 61 // write more in between the read above and reading from this channel 62 // so we absolute must read once more if we want all the bytes 63 var buf bytes.Buffer 64 io.Copy(&buf, reader) 65 readingString += buf.String() 66 break 67 } 68 } 69 70 result <- strings.Split(readingString, "\n") 71 }