feat: configure stdin, stdout and stderr per interpreter

The goal is to provide greater control of input, output and error
streams of the interpreter. It is now possible to specify those
as options when creating a new interpreter. The provided values
are propagated to relevant stdlib symbols (i.e fmt.Print, etc).
Care is taken to not update the global variables os.Stdout, os.Stdin
and os.Stderr, as to not interfere with the host process.

The REPL function is now simplified. The deprecated version is removed.

The tests are updated to take advantage of the simplified access
to the interpreter output and errors.

Fixes #752.
This commit is contained in:
Marc Vertes
2020-08-31 14:42:03 +01:00
committed by GitHub
parent f4cc059e3e
commit 341c69d922
9 changed files with 145 additions and 80 deletions

View File

@@ -1,6 +1,7 @@
package interp_test
import (
"bytes"
"go/build"
"go/parser"
"go/token"
@@ -42,16 +43,11 @@ func runCheck(t *testing.T, p string) {
}
wanted = strings.TrimSpace(wanted)
// catch stdout
backupStdout := os.Stdout
defer func() { os.Stdout = backupStdout }()
r, w, _ := os.Pipe()
os.Stdout = w
if goPath == "" {
goPath = build.Default.GOPATH
}
i := interp.New(interp.Options{GoPath: goPath})
var stdout, stderr bytes.Buffer
i := interp.New(interp.Options{GoPath: goPath, Stdout: &stdout, Stderr: &stderr})
i.Use(interp.Symbols)
i.Use(stdlib.Symbols)
i.Use(unsafe.Symbols)
@@ -71,15 +67,7 @@ func runCheck(t *testing.T, p string) {
t.Fatal(err)
}
// read stdout
if err = w.Close(); err != nil {
t.Fatal(err)
}
outInterp, err := ioutil.ReadAll(r)
if err != nil {
t.Fatal(err)
}
if res := strings.TrimSpace(string(outInterp)); res != wanted {
if res := strings.TrimSpace(stdout.String()); res != wanted {
t.Errorf("\ngot: %q,\nwant: %q", res, wanted)
}
}