testutil: add new CaptureStdio helper
This commit adds a new testutil.CaptureStdio helper so that we
can test external go modules that use os.Std{out,err} but now
allow mocking or overwriting.
This commit is contained in:
parent
c78ea5f2b2
commit
e41cf0e429
2 changed files with 61 additions and 0 deletions
|
|
@ -1,9 +1,12 @@
|
||||||
package testutil
|
package testutil
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
|
@ -60,3 +63,50 @@ func (mc *MockCmd) Calls() [][]string {
|
||||||
}
|
}
|
||||||
return calls
|
return calls
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CaptureStdio runs the given function f() in an environment that
|
||||||
|
// captures stdout, stderr and returns the the result as string.
|
||||||
|
//
|
||||||
|
// Use this very targeted to avoid real stdout/stderr output
|
||||||
|
// from being displayed.
|
||||||
|
func CaptureStdio(t *testing.T, f func()) (string, string) {
|
||||||
|
saved1 := os.Stdout
|
||||||
|
saved2 := os.Stderr
|
||||||
|
|
||||||
|
r1, w1, err := os.Pipe()
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer r1.Close()
|
||||||
|
defer w1.Close()
|
||||||
|
r2, w2, err := os.Pipe()
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer r2.Close()
|
||||||
|
defer w2.Close()
|
||||||
|
|
||||||
|
var wg sync.WaitGroup
|
||||||
|
var stdout, stderr bytes.Buffer
|
||||||
|
wg.Add(1)
|
||||||
|
// this needs to be a go-routines or we could deadlock
|
||||||
|
// when the pipe is full
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
io.Copy(&stdout, r1)
|
||||||
|
}()
|
||||||
|
wg.Add(1)
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
|
io.Copy(&stderr, r2)
|
||||||
|
}()
|
||||||
|
|
||||||
|
os.Stdout = w1
|
||||||
|
os.Stderr = w2
|
||||||
|
defer func() {
|
||||||
|
os.Stdout = saved1
|
||||||
|
os.Stderr = saved2
|
||||||
|
}()
|
||||||
|
|
||||||
|
f()
|
||||||
|
w1.Close()
|
||||||
|
w2.Close()
|
||||||
|
wg.Wait()
|
||||||
|
return stdout.String(), stderr.String()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
package testutil_test
|
package testutil_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
|
@ -23,3 +25,12 @@ func TestMockCommand(t *testing.T) {
|
||||||
{"run2-arg1", "run2-arg2"},
|
{"run2-arg1", "run2-arg2"},
|
||||||
}, fakeCmd.Calls())
|
}, fakeCmd.Calls())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCaptureStdout(t *testing.T) {
|
||||||
|
stdout, stderr := testutil.CaptureStdio(t, func() {
|
||||||
|
fmt.Fprintf(os.Stdout, "output on stdout")
|
||||||
|
fmt.Fprintf(os.Stderr, "output on stderr")
|
||||||
|
})
|
||||||
|
assert.Equal(t, "output on stdout", stdout)
|
||||||
|
assert.Equal(t, "output on stderr", stderr)
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue