feat: add cmd mire rewrite to rewrite all goldens from input again

This commit is contained in:
2026-03-24 18:45:14 +00:00
parent 8a573681be
commit 4e9459c86c
8 changed files with 450 additions and 199 deletions
+28
View File
@@ -0,0 +1,28 @@
package cmd
import (
"mire/internal/mire"
"github.com/spf13/cobra"
)
func newRewriteCommand() *cobra.Command {
return &cobra.Command{
Use: "rewrite [path]",
Short: "Refresh recorded CLI output fixtures",
Args: cobra.MaximumNArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
path := ""
if len(args) == 1 {
path = args[0]
}
if err := mire.Rewrite(path); err != nil {
cmd.SilenceUsage = true
return err
}
return nil
},
}
}
+1 -1
View File
@@ -37,7 +37,7 @@ func newRootCommand() *cobra.Command {
}, },
} }
rootCmd.AddCommand(newInitCommand(), newRecordCommand(), newTestCommand()) rootCmd.AddCommand(newInitCommand(), newRecordCommand(), newRewriteCommand(), newTestCommand())
return rootCmd return rootCmd
} }
+46
View File
@@ -24,6 +24,7 @@ func TestRunShowsHelpWhenNoArgs(t *testing.T) {
for _, want := range []string{ for _, want := range []string{
"init Initialise mire in the current project", "init Initialise mire in the current project",
"record Record a new CLI scenario", "record Record a new CLI scenario",
"rewrite Refresh recorded CLI output fixtures",
"test Replay recorded CLI scenarios", "test Replay recorded CLI scenarios",
} { } {
if !strings.Contains(stdout, want) { if !strings.Contains(stdout, want) {
@@ -129,6 +130,51 @@ func TestRunRecord(t *testing.T) {
}) })
} }
func TestRunRewrite(t *testing.T) {
testutil.AddFakeRecordDependencies(t, "bwrap", "bash")
root := t.TempDir()
testutil.WriteScenarioFixtures(t, filepath.Join(root, "e2e", "suite", "spec"), "echo rewrite\nexit\n", "stale output\n")
testutil.WithWorkingDir(t, root, func() struct{} {
initStdout, initStderr := testutil.CaptureOutput(t, func() {
if got := Run([]string{"init"}); got != 0 {
t.Fatalf("Run() code = %d, want %d", got, 0)
}
})
if initStdout != prefixed("Done initialising...\n") {
t.Fatalf("stdout = %q, want %q", initStdout, prefixed("Done initialising...\n"))
}
if initStderr != "" {
t.Fatalf("stderr = %q, want empty", initStderr)
}
stdout, stderr := testutil.CaptureOutput(t, func() {
if got := Run([]string{"rewrite"}); got != 0 {
t.Fatalf("Run() code = %d, want %d", got, 0)
}
})
for _, want := range []string{
"RUN suite/spec",
"PASS suite/spec (",
"Summary: total=1 passed=1 failed=0",
} {
if !strings.Contains(stdout, want) {
t.Fatalf("stdout = %q, want substring %q", stdout, want)
}
}
if stderr != "" {
t.Fatalf("stderr = %q, want empty", stderr)
}
return struct{}{}
})
if got := testutil.ReadFile(t, filepath.Join(root, "e2e", "suite", "spec", "out")); got == "stale output\n" {
t.Fatalf("rewrite left stale output unchanged")
}
}
func TestRunInitFailsWhenDependenciesMissing(t *testing.T) { func TestRunInitFailsWhenDependenciesMissing(t *testing.T) {
root := t.TempDir() root := t.TempDir()
t.Setenv("PATH", "") t.Setenv("PATH", "")
+211
View File
@@ -0,0 +1,211 @@
package mire
import (
"bytes"
"fmt"
"io"
"os"
"os/exec"
"sync"
"time"
"mire/internal/script"
)
type replaySuite struct {
shellPath string
scenarios []testScenario
sandboxConfig map[string]string
mounts []string
paths []string
}
func loadReplaySuite(path string) (replaySuite, error) {
root, err := currentProjectRoot()
if err != nil {
return replaySuite{}, err
}
cfg, err := readConfigFromRoot(root)
if err != nil {
return replaySuite{}, fmt.Errorf("failed to resolve test directory: %v", err)
}
testDir, err := resolveTestDirFromConfig(root, cfg)
if err != nil {
return replaySuite{}, fmt.Errorf("failed to resolve test directory: %v", err)
}
discoveryRoot, err := resolveTestDiscoveryRoot(testDir, path)
if err != nil {
return replaySuite{}, err
}
shellPath, err := resolveRecordShell(testDir)
if err != nil {
return replaySuite{}, err
}
scenarios, err := discoverTestScenarios(discoveryRoot, testDir)
if err != nil {
return replaySuite{}, err
}
if len(scenarios) == 0 {
return replaySuite{}, fmt.Errorf("no test scenarios found in %q", discoveryRoot)
}
return replaySuite{
shellPath: shellPath,
scenarios: scenarios,
sandboxConfig: cfg.Sandbox,
mounts: cfg.Mounts,
paths: cfg.Paths,
}, nil
}
func replayScenarioOutput(scenario testScenario, shellPath string, sandboxConfig map[string]string, mounts, paths []string) ([]byte, error) {
input, err := loadRecordedInput(scenario.inPath)
if err != nil {
return nil, fmt.Errorf("failed to read recorded input: %v", err)
}
_, rawOut, cleanupFiles, err := newRecordFiles()
if err != nil {
return nil, fmt.Errorf("failed to prepare replay files: %v", err)
}
defer cleanupFiles()
sandbox, cleanupSandbox, err := newRecordSandbox()
if err != nil {
return nil, fmt.Errorf("failed to prepare replay sandbox: %v", err)
}
defer cleanupSandbox()
rawOutFile, err := os.Create(rawOut)
if err != nil {
return nil, fmt.Errorf("failed to prepare replay output: %v", err)
}
cmd := exec.Command(shellPath)
cmd.Dir = scenario.dir
cmd.Env = recordSessionEnvWithExtra(sandbox, sandboxConfig, mounts, paths, scenario.setupScripts, map[string]string{
compareMarkerEnvName: compareMarkerEnabledValue,
})
ready := make(chan struct{})
promptWriter := newReplayPromptWriter(rawOutFile, replayPromptReadyMarker, ready)
promptTimeout := time.AfterFunc(replayPromptReadyTimeout, promptWriter.release)
defer promptTimeout.Stop()
replayResult := script.Replay(script.ReplayRequest{
Cmd: cmd,
Input: input,
InputReady: ready,
OutputLog: promptWriter,
})
if err := rawOutFile.Close(); err != nil {
return nil, fmt.Errorf("failed to close replay output: %v", err)
}
if !promptWriter.seen {
if err := replayResult.Err(); err != nil {
return nil, fmt.Errorf("replay failed: %v", err)
}
return nil, fmt.Errorf("replay shell never emitted %q; rerun `mire init` or refresh %q", compareOutputMarker, shellPath)
}
if replayResult.OutputErr != nil {
return nil, fmt.Errorf("replay failed: %v", replayResult.OutputErr)
}
if replayResult.InputErr != nil {
return nil, fmt.Errorf("replay failed: %v", replayResult.InputErr)
}
got, err := loadRecordedOutput(rawOut)
if err != nil {
return nil, fmt.Errorf("failed to read replay output: %v", err)
}
got, err = trimReplayOutputToMarker(got, shellPath)
if err != nil {
return nil, err
}
return got, nil
}
func trimReplayOutputToMarker(data []byte, shellPath string) ([]byte, error) {
idx := bytes.Index(data, []byte(compareOutputMarker))
if idx == -1 {
return nil, fmt.Errorf(
"missing replay start marker %q in replay output; rerun `mire init` or refresh %q",
compareOutputMarker,
shellPath,
)
}
data = data[idx+len(compareOutputMarker):]
switch {
case bytes.HasPrefix(data, []byte("\r\n")):
return data[2:], nil
case bytes.HasPrefix(data, []byte("\n")):
return data[1:], nil
default:
return data, nil
}
}
type replayPromptWriter struct {
dst io.Writer
marker []byte
tail []byte
ready chan struct{}
once sync.Once
seen bool
}
func newReplayPromptWriter(dst io.Writer, marker string, ready chan struct{}) *replayPromptWriter {
return &replayPromptWriter{
dst: dst,
marker: []byte(marker),
ready: ready,
}
}
func (w *replayPromptWriter) Write(p []byte) (int, error) {
n, err := w.dst.Write(p)
if n > 0 {
w.observe(p[:n])
}
return n, err
}
func (w *replayPromptWriter) observe(p []byte) {
if w.seen || len(w.marker) == 0 {
return
}
data := make([]byte, 0, len(w.tail)+len(p))
data = append(data, w.tail...)
data = append(data, p...)
if bytes.Contains(data, w.marker) {
w.seen = true
w.release()
}
keep := len(w.marker) - 1
if keep <= 0 {
return
}
if len(data) <= keep {
w.tail = append(w.tail[:0], data...)
return
}
w.tail = append(w.tail[:0], data[len(data)-keep:]...)
}
func (w *replayPromptWriter) release() {
w.once.Do(func() {
close(w.ready)
})
}
+57
View File
@@ -0,0 +1,57 @@
package mire
import (
"fmt"
"os"
"time"
"mire/internal/output"
)
// Rewrite replays scenarios and refreshes their recorded output fixtures.
func Rewrite(path string) error {
return rewrite(path, testIO{
out: os.Stdout,
err: os.Stderr,
})
}
func rewrite(path string, tio testIO) error {
suite, err := loadReplaySuite(path)
if err != nil {
return err
}
summary := testSummary{total: len(suite.scenarios)}
for _, scenario := range suite.scenarios {
output.Fprintf(tio.out, "%s %s\n", output.Label("RUN", output.Info), scenario.relPath)
start := time.Now()
got, err := replayScenarioOutput(scenario, suite.shellPath, suite.sandboxConfig, suite.mounts, suite.paths)
if err != nil {
elapsed := time.Since(start)
summary.failed++
output.Fprintf(tio.out, "%s %s (%s): %v\n", output.Label("FAIL", output.Fail), scenario.relPath, formatElapsed(elapsed), err)
continue
}
if err := os.WriteFile(scenario.outPath, got, 0o644); err != nil {
elapsed := time.Since(start)
summary.failed++
output.Fprintf(tio.out, "%s %s (%s): failed to write expected output: %v\n", output.Label("FAIL", output.Fail), scenario.relPath, formatElapsed(elapsed), err)
continue
}
elapsed := time.Since(start)
summary.passed++
output.Fprintf(tio.out, "%s %s (%s)\n", output.Label("PASS", output.Pass), scenario.relPath, formatElapsed(elapsed))
}
writeScenarioSummary(tio.out, summary)
if summary.failed > 0 {
return fmt.Errorf("%d scenario(s) failed to rewrite", summary.failed)
}
return nil
}
+91
View File
@@ -0,0 +1,91 @@
package mire
import (
"bytes"
"path/filepath"
"strings"
"testing"
"mire/internal/testutil"
)
func TestRewriteScopedRunOnlyUpdatesSelectedSubtree(t *testing.T) {
testutil.AddFakeRecordDependencies(t, "bwrap", "bash")
root := t.TempDir()
testDir := filepath.Join(root, "e2e")
testutil.WriteValidConfig(t, filepath.Join(root, "mire.toml"), "e2e")
mustWriteRecordShell(t, testDir)
testutil.WriteScenarioFixtures(t, filepath.Join(testDir, "a"), "echo root\nexit\n", "stale root\n")
testutil.WriteScenarioFixtures(t, filepath.Join(testDir, "nested", "b"), "echo nested\nexit\n", "stale nested\n")
var stdout bytes.Buffer
var stderr bytes.Buffer
err := testutil.WithWorkingDir(t, root, func() error {
return rewrite("nested", testIO{
out: &stdout,
err: &stderr,
})
})
if err != nil {
t.Fatalf("rewrite() error = %v", err)
}
if strings.Contains(stdout.String(), "RUN a") {
t.Fatalf("stdout = %q, want scoped rewrite to skip root scenario", stdout.String())
}
if got := testutil.ReadFile(t, filepath.Join(testDir, "a", "out")); got != "stale root\n" {
t.Fatalf("root scenario out = %q, want unchanged stale output", got)
}
if got := testutil.ReadFile(t, filepath.Join(testDir, "nested", "b", "out")); got == "stale nested\n" {
t.Fatalf("nested scenario out = %q, want rewritten output", got)
}
if stderr.String() != "" {
t.Fatalf("stderr = %q, want empty", stderr.String())
}
}
func TestRewriteContinuesAfterFailureAndReturnsError(t *testing.T) {
testutil.RequireCommands(t, "bwrap", "bash")
root := t.TempDir()
testDir := filepath.Join(root, "e2e")
testutil.WriteValidConfig(t, filepath.Join(root, "mire.toml"), "e2e")
mustWriteRecordShell(t, testDir)
testutil.WriteScenarioFixtures(t, filepath.Join(testDir, "bad"), "echo bad\nexit\n", "stale bad\n")
testutil.WriteFile(t, filepath.Join(testDir, "bad", setupScriptName), "exit 1\n")
testutil.WriteScenarioFixtures(t, filepath.Join(testDir, "ok"), "echo ok\nexit\n", "stale ok\n")
var stdout bytes.Buffer
var stderr bytes.Buffer
err := testutil.WithWorkingDir(t, root, func() error {
return rewrite("", testIO{
out: &stdout,
err: &stderr,
})
})
if err == nil {
t.Fatal("rewrite() error = nil, want failure summary error")
}
if !strings.Contains(err.Error(), "1 scenario(s) failed to rewrite") {
t.Fatalf("rewrite() error = %q, want failed rewrite summary", err.Error())
}
for _, want := range []string{
"FAIL bad (",
"PASS ok (",
"Summary: total=2 passed=1 failed=1",
} {
if !strings.Contains(stdout.String(), want) {
t.Fatalf("stdout = %q, want substring %q", stdout.String(), want)
}
}
if got := testutil.ReadFile(t, filepath.Join(testDir, "bad", "out")); got != "stale bad\n" {
t.Fatalf("bad scenario out = %q, want unchanged stale output", got)
}
if got := testutil.ReadFile(t, filepath.Join(testDir, "ok", "out")); got == "stale ok\n" {
t.Fatalf("ok scenario out = %q, want rewritten output", got)
}
if stderr.String() != "" {
t.Fatalf("stderr = %q, want empty", stderr.String())
}
}
+13 -177
View File
@@ -7,14 +7,11 @@ import (
"io" "io"
"io/fs" "io/fs"
"os" "os"
"os/exec"
"path/filepath" "path/filepath"
"sort" "sort"
"sync"
"time" "time"
"mire/internal/output" "mire/internal/output"
"mire/internal/script"
) )
type testIO struct { type testIO struct {
@@ -69,45 +66,17 @@ func RunTests(path string) error {
} }
func runTests(path string, tio testIO) error { func runTests(path string, tio testIO) error {
root, err := currentProjectRoot() suite, err := loadReplaySuite(path)
if err != nil { if err != nil {
return err return err
} }
cfg, err := readConfigFromRoot(root) summary := testSummary{total: len(suite.scenarios)}
if err != nil { for _, scenario := range suite.scenarios {
return fmt.Errorf("failed to resolve test directory: %v", err)
}
testDir, err := resolveTestDirFromConfig(root, cfg)
if err != nil {
return fmt.Errorf("failed to resolve test directory: %v", err)
}
discoveryRoot, err := resolveTestDiscoveryRoot(testDir, path)
if err != nil {
return err
}
shellPath, err := resolveRecordShell(testDir)
if err != nil {
return err
}
scenarios, err := discoverTestScenarios(discoveryRoot, testDir)
if err != nil {
return err
}
if len(scenarios) == 0 {
return fmt.Errorf("no test scenarios found in %q", discoveryRoot)
}
summary := testSummary{total: len(scenarios)}
for _, scenario := range scenarios {
output.Fprintf(tio.out, "%s %s\n", output.Label("RUN", output.Info), scenario.relPath) output.Fprintf(tio.out, "%s %s\n", output.Label("RUN", output.Info), scenario.relPath)
start := time.Now() start := time.Now()
if err := replayScenario(scenario, shellPath, tio, cfg.Sandbox, cfg.Mounts, cfg.Paths); err != nil { if err := replayScenario(scenario, suite.shellPath, suite.sandboxConfig, suite.mounts, suite.paths); err != nil {
elapsed := time.Since(start) elapsed := time.Since(start)
summary.failed++ summary.failed++
output.Fprintf(tio.out, "%s %s (%s): %v\n", output.Label("FAIL", output.Fail), scenario.relPath, formatElapsed(elapsed), err) output.Fprintf(tio.out, "%s %s (%s): %v\n", output.Label("FAIL", output.Fail), scenario.relPath, formatElapsed(elapsed), err)
@@ -123,21 +92,25 @@ func runTests(path string, tio testIO) error {
output.Fprintf(tio.out, "%s %s (%s)\n", output.Label("PASS", output.Pass), scenario.relPath, formatElapsed(elapsed)) output.Fprintf(tio.out, "%s %s (%s)\n", output.Label("PASS", output.Pass), scenario.relPath, formatElapsed(elapsed))
} }
writeScenarioSummary(tio.out, summary)
return nil
}
func writeScenarioSummary(w io.Writer, summary testSummary) {
summaryColor := output.Pass summaryColor := output.Pass
if summary.failed > 0 { if summary.failed > 0 {
summaryColor = output.Fail summaryColor = output.Fail
} }
output.Fprintf( output.Fprintf(
tio.out, w,
"%s\n", "%s\n",
output.Label( output.Label(
fmt.Sprintf("Summary: total=%d passed=%d failed=%d", summary.total, summary.passed, summary.failed), fmt.Sprintf("Summary: total=%d passed=%d failed=%d", summary.total, summary.passed, summary.failed),
summaryColor, summaryColor,
), ),
) )
return nil
} }
func formatElapsed(elapsed time.Duration) string { func formatElapsed(elapsed time.Duration) string {
@@ -236,67 +209,8 @@ func discoverTestScenarios(discoveryRoot, displayRoot string) ([]testScenario, e
return scenarios, nil return scenarios, nil
} }
func replayScenario(scenario testScenario, shellPath string, _ testIO, sandboxConfig map[string]string, mounts, paths []string) error { func replayScenario(scenario testScenario, shellPath string, sandboxConfig map[string]string, mounts, paths []string) error {
input, err := loadRecordedInput(scenario.inPath) got, err := replayScenarioOutput(scenario, shellPath, sandboxConfig, mounts, paths)
if err != nil {
return fmt.Errorf("failed to read recorded input: %v", err)
}
_, rawOut, cleanupFiles, err := newRecordFiles()
if err != nil {
return fmt.Errorf("failed to prepare replay files: %v", err)
}
defer cleanupFiles()
sandbox, cleanupSandbox, err := newRecordSandbox()
if err != nil {
return fmt.Errorf("failed to prepare replay sandbox: %v", err)
}
defer cleanupSandbox()
rawOutFile, err := os.Create(rawOut)
if err != nil {
return fmt.Errorf("failed to prepare replay output: %v", err)
}
cmd := exec.Command(shellPath)
cmd.Dir = scenario.dir
cmd.Env = recordSessionEnvWithExtra(sandbox, sandboxConfig, mounts, paths, scenario.setupScripts, map[string]string{
compareMarkerEnvName: compareMarkerEnabledValue,
})
ready := make(chan struct{})
promptWriter := newReplayPromptWriter(rawOutFile, replayPromptReadyMarker, ready)
promptTimeout := time.AfterFunc(replayPromptReadyTimeout, promptWriter.release)
defer promptTimeout.Stop()
replayResult := script.Replay(script.ReplayRequest{
Cmd: cmd,
Input: input,
InputReady: ready,
OutputLog: promptWriter,
})
if err := rawOutFile.Close(); err != nil {
return fmt.Errorf("failed to close replay output: %v", err)
}
if !promptWriter.seen {
if err := replayResult.Err(); err != nil {
return fmt.Errorf("replay failed: %v", err)
}
return fmt.Errorf("replay shell never emitted %q; rerun `mire init` or refresh %q", compareOutputMarker, shellPath)
}
if replayResult.OutputErr != nil {
return fmt.Errorf("replay failed: %v", replayResult.OutputErr)
}
if replayResult.InputErr != nil {
return fmt.Errorf("replay failed: %v", replayResult.InputErr)
}
got, err := loadRecordedOutput(rawOut)
if err != nil {
return fmt.Errorf("failed to read replay output: %v", err)
}
got, err = trimReplayOutputToMarker(got, shellPath)
if err != nil { if err != nil {
return err return err
} }
@@ -317,81 +231,3 @@ func replayScenario(scenario testScenario, shellPath string, _ testIO, sandboxCo
return nil return nil
} }
func trimReplayOutputToMarker(data []byte, shellPath string) ([]byte, error) {
idx := bytes.Index(data, []byte(compareOutputMarker))
if idx == -1 {
return nil, fmt.Errorf(
"missing replay start marker %q in replay output; rerun `mire init` or refresh %q",
compareOutputMarker,
shellPath,
)
}
data = data[idx+len(compareOutputMarker):]
switch {
case bytes.HasPrefix(data, []byte("\r\n")):
return data[2:], nil
case bytes.HasPrefix(data, []byte("\n")):
return data[1:], nil
default:
return data, nil
}
}
type replayPromptWriter struct {
dst io.Writer
marker []byte
tail []byte
ready chan struct{}
once sync.Once
seen bool
}
func newReplayPromptWriter(dst io.Writer, marker string, ready chan struct{}) *replayPromptWriter {
return &replayPromptWriter{
dst: dst,
marker: []byte(marker),
ready: ready,
}
}
func (w *replayPromptWriter) Write(p []byte) (int, error) {
n, err := w.dst.Write(p)
if n > 0 {
w.observe(p[:n])
}
return n, err
}
func (w *replayPromptWriter) observe(p []byte) {
if w.seen || len(w.marker) == 0 {
return
}
data := make([]byte, 0, len(w.tail)+len(p))
data = append(data, w.tail...)
data = append(data, p...)
if bytes.Contains(data, w.marker) {
w.seen = true
w.release()
}
keep := len(w.marker) - 1
if keep <= 0 {
return
}
if len(data) <= keep {
w.tail = append(w.tail[:0], data...)
return
}
w.tail = append(w.tail[:0], data[len(data)-keep:]...)
}
func (w *replayPromptWriter) release() {
w.once.Do(func() {
close(w.ready)
})
}
+3 -21
View File
@@ -99,28 +99,16 @@ func TestReplayScenarioUsesRecordedInputAndKeepsReplayOutputQuiet(t *testing.T)
scenarioDir := filepath.Join(testDir, "suite", "spec") scenarioDir := filepath.Join(testDir, "suite", "spec")
testutil.WriteScenarioFixtures(t, scenarioDir, "echo replay\nexit\n", "echo replay\r\nexit\r\n") testutil.WriteScenarioFixtures(t, scenarioDir, "echo replay\nexit\n", "echo replay\r\nexit\r\n")
var stdout bytes.Buffer
var stderr bytes.Buffer
err := replayScenario(testScenario{ err := replayScenario(testScenario{
dir: scenarioDir, dir: scenarioDir,
relPath: filepath.Join("suite", "spec"), relPath: filepath.Join("suite", "spec"),
inPath: filepath.Join(scenarioDir, "in"), inPath: filepath.Join(scenarioDir, "in"),
outPath: filepath.Join(scenarioDir, "out"), outPath: filepath.Join(scenarioDir, "out"),
setupScripts: nil, setupScripts: nil,
}, shellPath, testIO{ }, shellPath, defaultSandboxConfig(), nil, nil)
out: &stdout,
err: &stderr,
}, defaultSandboxConfig(), nil, nil)
if err != nil { if err != nil {
t.Fatalf("replayScenario() error = %v", err) t.Fatalf("replayScenario() error = %v", err)
} }
if stdout.String() != "" {
t.Fatalf("stdout = %q, want empty", stdout.String())
}
if stderr.String() != "" {
t.Fatalf("stderr = %q, want empty", stderr.String())
}
} }
func TestReplayScenarioWaitsForPromptReadyMarkerBeforeSendingInput(t *testing.T) { func TestReplayScenarioWaitsForPromptReadyMarkerBeforeSendingInput(t *testing.T) {
@@ -143,10 +131,7 @@ func TestReplayScenarioWaitsForPromptReadyMarkerBeforeSendingInput(t *testing.T)
inPath: filepath.Join(scenarioDir, "in"), inPath: filepath.Join(scenarioDir, "in"),
outPath: filepath.Join(scenarioDir, "out"), outPath: filepath.Join(scenarioDir, "out"),
setupScripts: nil, setupScripts: nil,
}, shellPath, testIO{ }, shellPath, defaultSandboxConfig(), nil, nil)
out: &bytes.Buffer{},
err: &bytes.Buffer{},
}, defaultSandboxConfig(), nil, nil)
if err != nil { if err != nil {
t.Fatalf("replayScenario() error = %v", err) t.Fatalf("replayScenario() error = %v", err)
} }
@@ -168,10 +153,7 @@ func TestReplayScenarioFailsWhenCompareMarkerMissing(t *testing.T) {
inPath: filepath.Join(scenarioDir, "in"), inPath: filepath.Join(scenarioDir, "in"),
outPath: filepath.Join(scenarioDir, "out"), outPath: filepath.Join(scenarioDir, "out"),
setupScripts: nil, setupScripts: nil,
}, shellPath, testIO{ }, shellPath, defaultSandboxConfig(), nil, nil)
out: &bytes.Buffer{},
err: &bytes.Buffer{},
}, defaultSandboxConfig(), nil, nil)
if err == nil { if err == nil {
t.Fatal("replayScenario() error = nil, want error") t.Fatal("replayScenario() error = nil, want error")
} }