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  }