test: refactor tests for a leaner test setup
This commit is contained in:
+40
-572
@@ -1,18 +1,18 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"io"
|
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"miro/internal/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRunShowsHelpWhenNoArgs(t *testing.T) {
|
func TestRunShowsHelpWhenNoArgs(t *testing.T) {
|
||||||
addFakeRecordDependencies(t, "script", "bwrap", "bash")
|
testutil.AddFakeRecordDependencies(t, "script", "bwrap", "bash")
|
||||||
|
|
||||||
stdout, stderr := captureOutput(t, func() {
|
stdout, stderr := testutil.CaptureOutput(t, func() {
|
||||||
if got := Run(nil); got != 0 {
|
if got := Run(nil); got != 0 {
|
||||||
t.Fatalf("Run() code = %d, want %d", got, 0)
|
t.Fatalf("Run() code = %d, want %d", got, 0)
|
||||||
}
|
}
|
||||||
@@ -31,10 +31,10 @@ func TestRunShowsHelpWhenNoArgs(t *testing.T) {
|
|||||||
|
|
||||||
func TestRunInit(t *testing.T) {
|
func TestRunInit(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
addFakeRecordDependencies(t, "script", "bwrap", "bash")
|
testutil.AddFakeRecordDependencies(t, "script", "bwrap", "bash")
|
||||||
|
|
||||||
withWorkingDir(t, root, func() {
|
testutil.WithWorkingDir(t, root, func() struct{} {
|
||||||
stdout, stderr := captureOutput(t, func() {
|
stdout, stderr := testutil.CaptureOutput(t, func() {
|
||||||
if got := Run([]string{"init"}); got != 0 {
|
if got := Run([]string{"init"}); got != 0 {
|
||||||
t.Fatalf("Run() code = %d, want %d", got, 0)
|
t.Fatalf("Run() code = %d, want %d", got, 0)
|
||||||
}
|
}
|
||||||
@@ -46,10 +46,11 @@ func TestRunInit(t *testing.T) {
|
|||||||
if stderr != "" {
|
if stderr != "" {
|
||||||
t.Fatalf("stderr = %q, want empty", stderr)
|
t.Fatalf("stderr = %q, want empty", stderr)
|
||||||
}
|
}
|
||||||
|
return struct{}{}
|
||||||
})
|
})
|
||||||
|
|
||||||
if got := mustReadFile(t, filepath.Join(root, "miro.toml")); got != defaultWrittenConfig("e2e") {
|
if got := testutil.ReadFile(t, filepath.Join(root, "miro.toml")); got != testutil.DefaultWrittenConfig("e2e") {
|
||||||
t.Fatalf("config = %q, want %q", got, defaultWrittenConfig("e2e"))
|
t.Fatalf("config = %q, want %q", got, testutil.DefaultWrittenConfig("e2e"))
|
||||||
}
|
}
|
||||||
info, err := os.Stat(filepath.Join(root, "e2e", "shell.sh"))
|
info, err := os.Stat(filepath.Join(root, "e2e", "shell.sh"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -61,13 +62,13 @@ func TestRunInit(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRunRecord(t *testing.T) {
|
func TestRunRecord(t *testing.T) {
|
||||||
addFakeRecordDependencies(t, "script", "bwrap", "bash")
|
testutil.AddFakeRecordDependencies(t, "script", "bwrap", "bash")
|
||||||
|
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
wantDir := filepath.Join(root, "e2e")
|
wantDir := filepath.Join(root, "e2e")
|
||||||
|
|
||||||
withWorkingDir(t, root, func() {
|
testutil.WithWorkingDir(t, root, func() struct{} {
|
||||||
initStdout, initStderr := captureOutput(t, func() {
|
initStdout, initStderr := testutil.CaptureOutput(t, func() {
|
||||||
if got := Run([]string{"init"}); got != 0 {
|
if got := Run([]string{"init"}); got != 0 {
|
||||||
t.Fatalf("Run() code = %d, want %d", got, 0)
|
t.Fatalf("Run() code = %d, want %d", got, 0)
|
||||||
}
|
}
|
||||||
@@ -79,8 +80,8 @@ func TestRunRecord(t *testing.T) {
|
|||||||
t.Fatalf("stderr = %q, want empty", initStderr)
|
t.Fatalf("stderr = %q, want empty", initStderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
withStdin(t, "y\n", func() {})
|
testutil.WithStdin(t, "y\n", func() {})
|
||||||
stdout, stderr := captureOutput(t, func() {
|
stdout, stderr := testutil.CaptureOutput(t, func() {
|
||||||
if got := Run([]string{"record", "suite/spec"}); got != 0 {
|
if got := Run([]string{"record", "suite/spec"}); got != 0 {
|
||||||
t.Fatalf("Run() code = %d, want %d", got, 0)
|
t.Fatalf("Run() code = %d, want %d", got, 0)
|
||||||
}
|
}
|
||||||
@@ -99,6 +100,7 @@ func TestRunRecord(t *testing.T) {
|
|||||||
t.Fatalf("Stat(%q) error = %v", filepath.Join(createdPath, name), err)
|
t.Fatalf("Stat(%q) error = %v", filepath.Join(createdPath, name), err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return struct{}{}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,8 +108,8 @@ func TestRunInitFailsWhenDependenciesMissing(t *testing.T) {
|
|||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
t.Setenv("PATH", "")
|
t.Setenv("PATH", "")
|
||||||
|
|
||||||
withWorkingDir(t, root, func() {
|
testutil.WithWorkingDir(t, root, func() struct{} {
|
||||||
stdout, stderr := captureOutput(t, func() {
|
stdout, stderr := testutil.CaptureOutput(t, func() {
|
||||||
if got := Run([]string{"init"}); got != 1 {
|
if got := Run([]string{"init"}); got != 1 {
|
||||||
t.Fatalf("Run() code = %d, want %d", got, 1)
|
t.Fatalf("Run() code = %d, want %d", got, 1)
|
||||||
}
|
}
|
||||||
@@ -125,32 +127,15 @@ func TestRunInitFailsWhenDependenciesMissing(t *testing.T) {
|
|||||||
if _, err := os.Stat(filepath.Join(root, "e2e", "shell.sh")); !os.IsNotExist(err) {
|
if _, err := os.Stat(filepath.Join(root, "e2e", "shell.sh")); !os.IsNotExist(err) {
|
||||||
t.Fatalf("Stat(%q) error = %v, want not exists", filepath.Join(root, "e2e", "shell.sh"), err)
|
t.Fatalf("Stat(%q) error = %v, want not exists", filepath.Join(root, "e2e", "shell.sh"), err)
|
||||||
}
|
}
|
||||||
|
return struct{}{}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunRecordFailsWhenDependencyMissing(t *testing.T) {
|
func TestRunRecordMissingPath(t *testing.T) {
|
||||||
root := t.TempDir()
|
testutil.AddFakeRecordDependencies(t, "script", "bwrap", "bash")
|
||||||
wantDir := filepath.Join(root, "e2e")
|
|
||||||
if err := os.MkdirAll(wantDir, 0o755); err != nil {
|
|
||||||
t.Fatalf("MkdirAll() error = %v", err)
|
|
||||||
}
|
|
||||||
writeFile(t, filepath.Join(root, "miro.toml"), validConfigContent("e2e"))
|
|
||||||
|
|
||||||
for _, tc := range []struct {
|
stdout, stderr := testutil.CaptureOutput(t, func() {
|
||||||
name string
|
if got := Run([]string{"record"}); got != 1 {
|
||||||
deps []string
|
|
||||||
missing string
|
|
||||||
}{
|
|
||||||
{name: "script", deps: []string{"bwrap", "bash"}, missing: "script"},
|
|
||||||
{name: "bwrap", deps: []string{"script", "bash"}, missing: "bwrap"},
|
|
||||||
{name: "bash", deps: []string{"script", "bwrap"}, missing: "bash"},
|
|
||||||
} {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
addFakeRecordDependencies(t, tc.deps...)
|
|
||||||
|
|
||||||
withWorkingDir(t, root, func() {
|
|
||||||
stdout, stderr := captureOutput(t, func() {
|
|
||||||
if got := Run([]string{"record", "suite/spec"}); got != 1 {
|
|
||||||
t.Fatalf("Run() code = %d, want %d", got, 1)
|
t.Fatalf("Run() code = %d, want %d", got, 1)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -158,49 +143,24 @@ func TestRunRecordFailsWhenDependencyMissing(t *testing.T) {
|
|||||||
if stdout != "" {
|
if stdout != "" {
|
||||||
t.Fatalf("stdout = %q, want empty", stdout)
|
t.Fatalf("stdout = %q, want empty", stdout)
|
||||||
}
|
}
|
||||||
want := `required command "` + tc.missing + `" not found in PATH`
|
if !strings.Contains(stderr, "accepts 1 arg(s), received 0") {
|
||||||
if !strings.Contains(stderr, want) {
|
t.Fatalf("stderr = %q, want argument error", stderr)
|
||||||
t.Fatalf("stderr = %q, want missing dependency error %q", stderr, want)
|
|
||||||
}
|
}
|
||||||
if _, err := os.Stat(filepath.Join(wantDir, "suite", "spec", "in")); !os.IsNotExist(err) {
|
if !strings.Contains(stderr, "Usage:") || !strings.Contains(stderr, "miro record <path>") {
|
||||||
t.Fatalf("Stat() error = %v, want not exists", err)
|
t.Fatalf("stderr = %q, want record usage", stderr)
|
||||||
}
|
}
|
||||||
})
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRunRecordMissingConfigFails(t *testing.T) {
|
|
||||||
addFakeRecordDependencies(t, "script", "bwrap", "bash")
|
|
||||||
|
|
||||||
root := t.TempDir()
|
|
||||||
|
|
||||||
withWorkingDir(t, root, func() {
|
|
||||||
stdout, stderr := captureOutput(t, func() {
|
|
||||||
if got := Run([]string{"record", "suite/spec"}); got != 1 {
|
|
||||||
t.Fatalf("Run() code = %d, want %d", got, 1)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if stdout != "" {
|
|
||||||
t.Fatalf("stdout = %q, want empty", stdout)
|
|
||||||
}
|
|
||||||
if !strings.Contains(stderr, "failed to resolve test directory") || !strings.Contains(stderr, "miro.toml") {
|
|
||||||
t.Fatalf("stderr = %q, want missing config error", stderr)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunTest(t *testing.T) {
|
func TestRunTest(t *testing.T) {
|
||||||
addFakeRecordDependencies(t, "script", "bwrap", "bash")
|
testutil.AddFakeRecordDependencies(t, "script", "bwrap", "bash")
|
||||||
t.Setenv("FAKE_SCRIPT_ECHO_STDIN", "1")
|
t.Setenv("FAKE_SCRIPT_ECHO_STDIN", "1")
|
||||||
|
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
writeScenarioFixtures(t, filepath.Join(root, "e2e", "a"), "echo one\n", "echo one\n")
|
testutil.WriteScenarioFixtures(t, filepath.Join(root, "e2e", "a"), "echo one\n", "echo one\n")
|
||||||
writeScenarioFixtures(t, filepath.Join(root, "e2e", "nested", "b"), "echo two\n", "echo two\n")
|
testutil.WriteScenarioFixtures(t, filepath.Join(root, "e2e", "nested", "b"), "echo two\n", "echo two\n")
|
||||||
|
|
||||||
withWorkingDir(t, root, func() {
|
testutil.WithWorkingDir(t, root, func() struct{} {
|
||||||
initStdout, initStderr := captureOutput(t, func() {
|
initStdout, initStderr := testutil.CaptureOutput(t, func() {
|
||||||
if got := Run([]string{"init"}); got != 0 {
|
if got := Run([]string{"init"}); got != 0 {
|
||||||
t.Fatalf("Run() code = %d, want %d", got, 0)
|
t.Fatalf("Run() code = %d, want %d", got, 0)
|
||||||
}
|
}
|
||||||
@@ -212,7 +172,7 @@ func TestRunTest(t *testing.T) {
|
|||||||
t.Fatalf("stderr = %q, want empty", initStderr)
|
t.Fatalf("stderr = %q, want empty", initStderr)
|
||||||
}
|
}
|
||||||
|
|
||||||
stdout, stderr := captureOutput(t, func() {
|
stdout, stderr := testutil.CaptureOutput(t, func() {
|
||||||
if got := Run([]string{"test"}); got != 0 {
|
if got := Run([]string{"test"}); got != 0 {
|
||||||
t.Fatalf("Run() code = %d, want %d", got, 0)
|
t.Fatalf("Run() code = %d, want %d", got, 0)
|
||||||
}
|
}
|
||||||
@@ -233,270 +193,14 @@ func TestRunTest(t *testing.T) {
|
|||||||
if stderr != "" {
|
if stderr != "" {
|
||||||
t.Fatalf("stderr = %q, want empty", stderr)
|
t.Fatalf("stderr = %q, want empty", stderr)
|
||||||
}
|
}
|
||||||
|
return struct{}{}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunTestScopedDirectory(t *testing.T) {
|
|
||||||
addFakeRecordDependencies(t, "script", "bwrap", "bash")
|
|
||||||
t.Setenv("FAKE_SCRIPT_ECHO_STDIN", "1")
|
|
||||||
|
|
||||||
root := t.TempDir()
|
|
||||||
writeScenarioFixtures(t, filepath.Join(root, "e2e", "a"), "echo one\n", "echo one\n")
|
|
||||||
writeScenarioFixtures(t, filepath.Join(root, "e2e", "nested", "b"), "echo two\n", "echo two\n")
|
|
||||||
writeScenarioFixtures(t, filepath.Join(root, "e2e", "nested", "c"), "echo three\n", "echo three\n")
|
|
||||||
|
|
||||||
withWorkingDir(t, root, func() {
|
|
||||||
initStdout, initStderr := 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 := captureOutput(t, func() {
|
|
||||||
if got := Run([]string{"test", "nested"}); got != 0 {
|
|
||||||
t.Fatalf("Run() code = %d, want %d", got, 0)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
for _, want := range []string{
|
|
||||||
"RUN nested/b",
|
|
||||||
"PASS nested/b (",
|
|
||||||
"RUN nested/c",
|
|
||||||
"PASS nested/c (",
|
|
||||||
"Summary: total=2 passed=2 failed=0",
|
|
||||||
} {
|
|
||||||
if !strings.Contains(stdout, want) {
|
|
||||||
t.Fatalf("stdout = %q, want substring %q", stdout, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if strings.Contains(stdout, "RUN a") {
|
|
||||||
t.Fatalf("stdout = %q, want scoped run to exclude scenario outside nested", stdout)
|
|
||||||
}
|
|
||||||
if stderr != "" {
|
|
||||||
t.Fatalf("stderr = %q, want empty", stderr)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRunTestScopedLeafDirectory(t *testing.T) {
|
|
||||||
addFakeRecordDependencies(t, "script", "bwrap", "bash")
|
|
||||||
t.Setenv("FAKE_SCRIPT_ECHO_STDIN", "1")
|
|
||||||
|
|
||||||
root := t.TempDir()
|
|
||||||
writeScenarioFixtures(t, filepath.Join(root, "e2e", "a"), "echo one\n", "echo one\n")
|
|
||||||
writeScenarioFixtures(t, filepath.Join(root, "e2e", "nested", "b"), "echo two\n", "echo two\n")
|
|
||||||
|
|
||||||
withWorkingDir(t, root, func() {
|
|
||||||
initStdout, initStderr := 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 := captureOutput(t, func() {
|
|
||||||
if got := Run([]string{"test", filepath.Join("nested", "b")}); got != 0 {
|
|
||||||
t.Fatalf("Run() code = %d, want %d", got, 0)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
for _, want := range []string{
|
|
||||||
"RUN nested/b",
|
|
||||||
"PASS nested/b (",
|
|
||||||
"Summary: total=1 passed=1 failed=0",
|
|
||||||
} {
|
|
||||||
if !strings.Contains(stdout, want) {
|
|
||||||
t.Fatalf("stdout = %q, want substring %q", stdout, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if strings.Contains(stdout, "RUN a") {
|
|
||||||
t.Fatalf("stdout = %q, want scoped run to exclude scenario outside nested/b", stdout)
|
|
||||||
}
|
|
||||||
if stderr != "" {
|
|
||||||
t.Fatalf("stderr = %q, want empty", stderr)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRunTestReturnsZeroWhenScenarioMismatches(t *testing.T) {
|
|
||||||
addFakeRecordDependencies(t, "script", "bwrap", "bash")
|
|
||||||
t.Setenv("FAKE_SCRIPT_ECHO_STDIN", "1")
|
|
||||||
|
|
||||||
root := t.TempDir()
|
|
||||||
writeScenarioFixtures(t, filepath.Join(root, "e2e", "a"), "echo one\n", "echo one\n")
|
|
||||||
writeScenarioFixtures(t, filepath.Join(root, "e2e", "b"), "echo two\n", "different output\n")
|
|
||||||
|
|
||||||
withWorkingDir(t, root, func() {
|
|
||||||
initStdout, initStderr := 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 := captureOutput(t, func() {
|
|
||||||
if got := Run([]string{"test"}); got != 0 {
|
|
||||||
t.Fatalf("Run() code = %d, want %d", got, 0)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
for _, want := range []string{
|
|
||||||
"RUN a",
|
|
||||||
"PASS a (",
|
|
||||||
"RUN b",
|
|
||||||
"FAIL b (",
|
|
||||||
"output differed",
|
|
||||||
"Summary: total=2 passed=1 failed=1",
|
|
||||||
} {
|
|
||||||
if !strings.Contains(stdout, want) {
|
|
||||||
t.Fatalf("stdout = %q, want substring %q", stdout, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if stderr != "" {
|
|
||||||
t.Fatalf("stderr = %q, want empty", stderr)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRunTestMissingConfigFails(t *testing.T) {
|
|
||||||
addFakeRecordDependencies(t, "script", "bwrap", "bash")
|
|
||||||
|
|
||||||
root := t.TempDir()
|
|
||||||
|
|
||||||
withWorkingDir(t, root, func() {
|
|
||||||
stdout, stderr := captureOutput(t, func() {
|
|
||||||
if got := Run([]string{"test"}); got != 1 {
|
|
||||||
t.Fatalf("Run() code = %d, want %d", got, 1)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if stdout != "" {
|
|
||||||
t.Fatalf("stdout = %q, want empty", stdout)
|
|
||||||
}
|
|
||||||
if !strings.Contains(stderr, "failed to resolve test directory") || !strings.Contains(stderr, "miro.toml") {
|
|
||||||
t.Fatalf("stderr = %q, want missing config error", stderr)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRunTestFailsWhenRecorderShellMissing(t *testing.T) {
|
|
||||||
addFakeRecordDependencies(t, "script", "bwrap", "bash")
|
|
||||||
|
|
||||||
root := t.TempDir()
|
|
||||||
writeFile(t, filepath.Join(root, "miro.toml"), validConfigContent("e2e"))
|
|
||||||
|
|
||||||
withWorkingDir(t, root, func() {
|
|
||||||
stdout, stderr := captureOutput(t, func() {
|
|
||||||
if got := Run([]string{"test"}); got != 1 {
|
|
||||||
t.Fatalf("Run() code = %d, want %d", got, 1)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if stdout != "" {
|
|
||||||
t.Fatalf("stdout = %q, want empty", stdout)
|
|
||||||
}
|
|
||||||
if !strings.Contains(stderr, "rerun `miro init`") {
|
|
||||||
t.Fatalf("stderr = %q, want rerun init hint", stderr)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRunTestFailsWhenFixtureMalformed(t *testing.T) {
|
|
||||||
addFakeRecordDependencies(t, "script", "bwrap", "bash")
|
|
||||||
|
|
||||||
root := t.TempDir()
|
|
||||||
writeFile(t, filepath.Join(root, "miro.toml"), validConfigContent("e2e"))
|
|
||||||
writeFile(t, filepath.Join(root, "e2e", "shell.sh"), "#!/bin/sh\n")
|
|
||||||
writeFile(t, filepath.Join(root, "e2e", "broken", "in"), "echo broken\n")
|
|
||||||
|
|
||||||
withWorkingDir(t, root, func() {
|
|
||||||
stdout, stderr := captureOutput(t, func() {
|
|
||||||
if got := Run([]string{"test"}); got != 1 {
|
|
||||||
t.Fatalf("Run() code = %d, want %d", got, 1)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if stdout != "" {
|
|
||||||
t.Fatalf("stdout = %q, want empty", stdout)
|
|
||||||
}
|
|
||||||
if !strings.Contains(stderr, `malformed scenario "broken": missing out fixture`) {
|
|
||||||
t.Fatalf("stderr = %q, want malformed fixture error", stderr)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRunTestReturnsZeroWhenCompareMarkerMissing(t *testing.T) {
|
|
||||||
addFakeRecordDependencies(t, "script", "bwrap", "bash")
|
|
||||||
t.Setenv("FAKE_SCRIPT_ECHO_STDIN", "1")
|
|
||||||
|
|
||||||
root := t.TempDir()
|
|
||||||
writeFile(t, filepath.Join(root, "miro.toml"), validConfigContent("e2e"))
|
|
||||||
writeFile(t, filepath.Join(root, "e2e", "shell.sh"), "#!/bin/sh\n")
|
|
||||||
writeScenarioFixtures(t, filepath.Join(root, "e2e", "some"), "echo one\n", "echo one\n")
|
|
||||||
|
|
||||||
withWorkingDir(t, root, func() {
|
|
||||||
stdout, stderr := captureOutput(t, func() {
|
|
||||||
if got := Run([]string{"test"}); got != 0 {
|
|
||||||
t.Fatalf("Run() code = %d, want %d", got, 0)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
for _, want := range []string{
|
|
||||||
"RUN some",
|
|
||||||
"FAIL some (",
|
|
||||||
"missing compare marker",
|
|
||||||
"Summary: total=1 passed=0 failed=1",
|
|
||||||
} {
|
|
||||||
if !strings.Contains(stdout, want) {
|
|
||||||
t.Fatalf("stdout = %q, want substring %q", stdout, want)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if stderr != "" {
|
|
||||||
t.Fatalf("stderr = %q, want empty", stderr)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRunRecordMissingPath(t *testing.T) {
|
|
||||||
addFakeRecordDependencies(t, "script", "bwrap", "bash")
|
|
||||||
|
|
||||||
stdout, stderr := captureOutput(t, func() {
|
|
||||||
if got := Run([]string{"record"}); got != 1 {
|
|
||||||
t.Fatalf("Run() code = %d, want %d", got, 1)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
if stdout != "" {
|
|
||||||
t.Fatalf("stdout = %q, want empty", stdout)
|
|
||||||
}
|
|
||||||
if !strings.Contains(stderr, "accepts 1 arg(s), received 0") {
|
|
||||||
t.Fatalf("stderr = %q, want argument error", stderr)
|
|
||||||
}
|
|
||||||
if !strings.Contains(stderr, "Usage:") || !strings.Contains(stderr, "miro record <path>") {
|
|
||||||
t.Fatalf("stderr = %q, want record usage", stderr)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRunTestExtraArgs(t *testing.T) {
|
func TestRunTestExtraArgs(t *testing.T) {
|
||||||
addFakeRecordDependencies(t, "script", "bwrap", "bash")
|
testutil.AddFakeRecordDependencies(t, "script", "bwrap", "bash")
|
||||||
|
|
||||||
stdout, stderr := captureOutput(t, func() {
|
stdout, stderr := testutil.CaptureOutput(t, func() {
|
||||||
if got := Run([]string{"test", "a", "b"}); got != 1 {
|
if got := Run([]string{"test", "a", "b"}); got != 1 {
|
||||||
t.Fatalf("Run() code = %d, want %d", got, 1)
|
t.Fatalf("Run() code = %d, want %d", got, 1)
|
||||||
}
|
}
|
||||||
@@ -514,9 +218,9 @@ func TestRunTestExtraArgs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRunInitExtraArgs(t *testing.T) {
|
func TestRunInitExtraArgs(t *testing.T) {
|
||||||
addFakeRecordDependencies(t, "script", "bwrap", "bash")
|
testutil.AddFakeRecordDependencies(t, "script", "bwrap", "bash")
|
||||||
|
|
||||||
stdout, stderr := captureOutput(t, func() {
|
stdout, stderr := testutil.CaptureOutput(t, func() {
|
||||||
if got := Run([]string{"init", "extra"}); got != 1 {
|
if got := Run([]string{"init", "extra"}); got != 1 {
|
||||||
t.Fatalf("Run() code = %d, want %d", got, 1)
|
t.Fatalf("Run() code = %d, want %d", got, 1)
|
||||||
}
|
}
|
||||||
@@ -534,9 +238,9 @@ func TestRunInitExtraArgs(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRunUnknownCommand(t *testing.T) {
|
func TestRunUnknownCommand(t *testing.T) {
|
||||||
addFakeRecordDependencies(t, "script", "bwrap", "bash")
|
testutil.AddFakeRecordDependencies(t, "script", "bwrap", "bash")
|
||||||
|
|
||||||
stdout, stderr := captureOutput(t, func() {
|
stdout, stderr := testutil.CaptureOutput(t, func() {
|
||||||
if got := Run([]string{"wat"}); got != 1 {
|
if got := Run([]string{"wat"}); got != 1 {
|
||||||
t.Fatalf("Run() code = %d, want %d", got, 1)
|
t.Fatalf("Run() code = %d, want %d", got, 1)
|
||||||
}
|
}
|
||||||
@@ -550,242 +254,6 @@ func TestRunUnknownCommand(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func captureOutput(t *testing.T, fn func()) (string, string) {
|
|
||||||
t.Helper()
|
|
||||||
t.Setenv("NO_COLOR", "1")
|
|
||||||
|
|
||||||
stdoutReader, stdoutWriter, err := os.Pipe()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("os.Pipe() stdout error = %v", err)
|
|
||||||
}
|
|
||||||
stderrReader, stderrWriter, err := os.Pipe()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("os.Pipe() stderr error = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
oldStdout := os.Stdout
|
|
||||||
oldStderr := os.Stderr
|
|
||||||
os.Stdout = stdoutWriter
|
|
||||||
os.Stderr = stderrWriter
|
|
||||||
t.Cleanup(func() {
|
|
||||||
os.Stdout = oldStdout
|
|
||||||
os.Stderr = oldStderr
|
|
||||||
})
|
|
||||||
|
|
||||||
fn()
|
|
||||||
|
|
||||||
if err := stdoutWriter.Close(); err != nil {
|
|
||||||
t.Fatalf("stdout close error = %v", err)
|
|
||||||
}
|
|
||||||
if err := stderrWriter.Close(); err != nil {
|
|
||||||
t.Fatalf("stderr close error = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var stdoutBuf bytes.Buffer
|
|
||||||
if _, err := io.Copy(&stdoutBuf, stdoutReader); err != nil {
|
|
||||||
t.Fatalf("stdout copy error = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var stderrBuf bytes.Buffer
|
|
||||||
if _, err := io.Copy(&stderrBuf, stderrReader); err != nil {
|
|
||||||
t.Fatalf("stderr copy error = %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return stdoutBuf.String(), stderrBuf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func prefixed(msg string) string {
|
func prefixed(msg string) string {
|
||||||
return "miro › " + msg
|
return "miro › " + msg
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeFile(t *testing.T, path, content string) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
|
||||||
t.Fatalf("MkdirAll(%q) error = %v", filepath.Dir(path), err)
|
|
||||||
}
|
|
||||||
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
|
|
||||||
t.Fatalf("WriteFile(%q) error = %v", path, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeScenarioFixtures(t *testing.T, dir, in, out string) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
writeFile(t, filepath.Join(dir, "in"), in)
|
|
||||||
writeFile(t, filepath.Join(dir, "out"), out)
|
|
||||||
}
|
|
||||||
|
|
||||||
func mustReadFile(t *testing.T, path string) string {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
data, err := os.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("ReadFile(%q) error = %v", path, err)
|
|
||||||
}
|
|
||||||
return string(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
func withWorkingDir(t *testing.T, dir string, fn func()) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
wd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Getwd() error = %v", err)
|
|
||||||
}
|
|
||||||
if err := os.Chdir(dir); err != nil {
|
|
||||||
t.Fatalf("Chdir(%q) error = %v", dir, err)
|
|
||||||
}
|
|
||||||
t.Cleanup(func() {
|
|
||||||
if err := os.Chdir(wd); err != nil {
|
|
||||||
t.Fatalf("restore working directory: %v", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
fn()
|
|
||||||
}
|
|
||||||
|
|
||||||
func addFakeRecordDependencies(t *testing.T, names ...string) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
binDir := t.TempDir()
|
|
||||||
for _, name := range names {
|
|
||||||
path := filepath.Join(binDir, name)
|
|
||||||
body := "#!/bin/sh\nexit 0\n"
|
|
||||||
if name == "script" {
|
|
||||||
body = `#!/bin/sh
|
|
||||||
if [ -n "${FAKE_SCRIPT_ARGS_FILE:-}" ]; then
|
|
||||||
: > "$FAKE_SCRIPT_ARGS_FILE"
|
|
||||||
for arg in "$@"; do
|
|
||||||
printf '%s\n' "$arg" >> "$FAKE_SCRIPT_ARGS_FILE"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
in=''
|
|
||||||
out=''
|
|
||||||
cmd=''
|
|
||||||
while [ "$#" -gt 0 ]; do
|
|
||||||
case "$1" in
|
|
||||||
-I)
|
|
||||||
in="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
-O)
|
|
||||||
out="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
-c)
|
|
||||||
cmd="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
if [ -n "${FAKE_SCRIPT_COMMAND_BODY_FILE:-}" ] && [ -n "$cmd" ]; then
|
|
||||||
: > "$FAKE_SCRIPT_COMMAND_BODY_FILE"
|
|
||||||
while IFS= read -r line || [ -n "$line" ]; do
|
|
||||||
printf '%s\n' "$line" >> "$FAKE_SCRIPT_COMMAND_BODY_FILE"
|
|
||||||
done < "$cmd"
|
|
||||||
fi
|
|
||||||
command_has_compare_marker=0
|
|
||||||
if [ -n "$cmd" ] && /bin/grep -q '__MIRO_E2E_BEGIN__' "$cmd" 2>/dev/null; then
|
|
||||||
command_has_compare_marker=1
|
|
||||||
fi
|
|
||||||
stdin_file=''
|
|
||||||
if [ "${FAKE_SCRIPT_ECHO_STDIN:-}" = "1" ] || [ -n "${FAKE_SCRIPT_CAPTURE_STDIN_FILE:-}" ]; then
|
|
||||||
stdin_file="${TMPDIR:-/tmp}/miro-fake-script-stdin-$$"
|
|
||||||
/bin/cat > "$stdin_file"
|
|
||||||
fi
|
|
||||||
if [ -n "${FAKE_SCRIPT_CAPTURE_STDIN_FILE:-}" ] && [ -n "$stdin_file" ]; then
|
|
||||||
/bin/cp "$stdin_file" "$FAKE_SCRIPT_CAPTURE_STDIN_FILE"
|
|
||||||
fi
|
|
||||||
if [ -n "$in" ] && [ -n "${FAKE_SCRIPT_LOG_IN+x}" ]; then
|
|
||||||
printf '%s' "$FAKE_SCRIPT_LOG_IN" > "$in"
|
|
||||||
elif [ -n "$in" ] && [ -n "$stdin_file" ]; then
|
|
||||||
/bin/cp "$stdin_file" "$in"
|
|
||||||
elif [ -n "$in" ]; then
|
|
||||||
printf '%s' 'fake recorded input
|
|
||||||
' > "$in"
|
|
||||||
fi
|
|
||||||
if [ -n "${FAKE_SCRIPT_STREAM_OUT+x}" ]; then
|
|
||||||
printf '%s' "$FAKE_SCRIPT_STREAM_OUT"
|
|
||||||
elif [ "${FAKE_SCRIPT_ECHO_STDIN:-}" = "1" ] && [ -n "$stdin_file" ]; then
|
|
||||||
/bin/cat "$stdin_file"
|
|
||||||
if [ "${MIRO_COMPARE_MARKER:-0}" = "1" ] && [ "$command_has_compare_marker" = "1" ]; then
|
|
||||||
printf '%s\n' '__MIRO_E2E_BEGIN__'
|
|
||||||
/bin/cat "$stdin_file"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
if [ -n "${FAKE_SCRIPT_STREAM_ERR+x}" ]; then
|
|
||||||
printf '%s' "$FAKE_SCRIPT_STREAM_ERR" >&2
|
|
||||||
fi
|
|
||||||
if [ -n "$out" ] && [ -n "${FAKE_SCRIPT_LOG_OUT+x}" ]; then
|
|
||||||
printf '%s' "$FAKE_SCRIPT_LOG_OUT" > "$out"
|
|
||||||
elif [ -n "$out" ] && [ "${FAKE_SCRIPT_ECHO_STDIN:-}" = "1" ] && [ -n "$stdin_file" ]; then
|
|
||||||
{
|
|
||||||
printf '%s' 'Script started on 2026-03-18 11:13:38+00:00 [TERM="xterm-256color"]
|
|
||||||
'
|
|
||||||
/bin/cat "$stdin_file"
|
|
||||||
if [ "${MIRO_COMPARE_MARKER:-0}" = "1" ] && [ "$command_has_compare_marker" = "1" ]; then
|
|
||||||
printf '%s\n' '__MIRO_E2E_BEGIN__'
|
|
||||||
/bin/cat "$stdin_file"
|
|
||||||
fi
|
|
||||||
printf '%s' 'Script done on 2026-03-18 11:13:44+00:00 [COMMAND_EXIT_CODE="0"]
|
|
||||||
'
|
|
||||||
} > "$out"
|
|
||||||
elif [ -n "$out" ]; then
|
|
||||||
printf '%s' 'Script started on 2026-03-18 11:13:38+00:00 [TERM="xterm-256color"]
|
|
||||||
fake recorded output
|
|
||||||
Script done on 2026-03-18 11:13:44+00:00 [COMMAND_EXIT_CODE="0"]
|
|
||||||
' > "$out"
|
|
||||||
fi
|
|
||||||
if [ -n "$stdin_file" ]; then
|
|
||||||
/bin/rm -f "$stdin_file"
|
|
||||||
fi
|
|
||||||
if [ -n "${FAKE_SCRIPT_EXIT_CODE:-}" ]; then
|
|
||||||
exit "$FAKE_SCRIPT_EXIT_CODE"
|
|
||||||
fi
|
|
||||||
exit 0
|
|
||||||
`
|
|
||||||
}
|
|
||||||
if err := os.WriteFile(path, []byte(body), 0o755); err != nil {
|
|
||||||
t.Fatalf("WriteFile(%q) error = %v", path, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Setenv("PATH", binDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
func withStdin(t *testing.T, input string, fn func()) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
path := filepath.Join(t.TempDir(), "stdin.txt")
|
|
||||||
if err := os.WriteFile(path, []byte(input), 0o644); err != nil {
|
|
||||||
t.Fatalf("WriteFile(%q) error = %v", path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := os.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Open(%q) error = %v", path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
oldStdin := os.Stdin
|
|
||||||
os.Stdin = file
|
|
||||||
t.Cleanup(func() {
|
|
||||||
os.Stdin = oldStdin
|
|
||||||
if err := file.Close(); err != nil {
|
|
||||||
t.Fatalf("close stdin file: %v", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
fn()
|
|
||||||
}
|
|
||||||
|
|
||||||
func defaultWrittenConfig(testDir string) string {
|
|
||||||
return "[miro]\n test_dir = \"" + testDir + "\"\n\n[sandbox]\n visible_home = \"/home/test\"\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
func validConfigContent(testDir string) string {
|
|
||||||
return "[miro]\ntest_dir = \"" + testDir + "\"\n\n[sandbox]\nvisible_home = \"/home/test\"\n"
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -5,13 +5,15 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"miro/internal/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestResolvePathWithinTestDirAcceptsRelativePath(t *testing.T) {
|
func TestResolvePathWithinTestDirAcceptsRelativePath(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
testDir := filepath.Join(root, "e2e")
|
testDir := filepath.Join(root, "e2e")
|
||||||
|
|
||||||
got := withWorkingDir(t, root, func() string {
|
got := testutil.WithWorkingDir(t, root, func() string {
|
||||||
path, err := resolvePathWithinTestDir(testDir, filepath.Join("suite", "spec"), "record")
|
path, err := resolvePathWithinTestDir(testDir, filepath.Join("suite", "spec"), "record")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("resolvePathWithinTestDir() error = %v", err)
|
t.Fatalf("resolvePathWithinTestDir() error = %v", err)
|
||||||
@@ -29,7 +31,7 @@ func TestResolvePathWithinTestDirAcceptsExplicitTestDirPrefix(t *testing.T) {
|
|||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
testDir := filepath.Join(root, "e2e")
|
testDir := filepath.Join(root, "e2e")
|
||||||
|
|
||||||
got := withWorkingDir(t, root, func() string {
|
got := testutil.WithWorkingDir(t, root, func() string {
|
||||||
path, err := resolvePathWithinTestDir(testDir, filepath.Join("e2e", "suite", "spec"), "record")
|
path, err := resolvePathWithinTestDir(testDir, filepath.Join("e2e", "suite", "spec"), "record")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("resolvePathWithinTestDir() error = %v", err)
|
t.Fatalf("resolvePathWithinTestDir() error = %v", err)
|
||||||
@@ -74,9 +76,9 @@ func TestResolvePathWithinTestDirRejectsAbsolutePathOutsideTestDir(t *testing.T)
|
|||||||
func TestResolvePathWithinTestDirAllowsPathCurrentDirectory(t *testing.T) {
|
func TestResolvePathWithinTestDirAllowsPathCurrentDirectory(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
testDir := filepath.Join(root, "e2e")
|
testDir := filepath.Join(root, "e2e")
|
||||||
mustMkdirAll(t, testDir)
|
testutil.MustMkdirAll(t, testDir)
|
||||||
|
|
||||||
got := withWorkingDir(t, testDir, func() string {
|
got := testutil.WithWorkingDir(t, testDir, func() string {
|
||||||
path, err := resolvePathWithinTestDir(testDir, ".", "record")
|
path, err := resolvePathWithinTestDir(testDir, ".", "record")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("resolvePathWithinTestDir() error = %v", err)
|
t.Fatalf("resolvePathWithinTestDir() error = %v", err)
|
||||||
|
|||||||
@@ -3,11 +3,13 @@ package miro
|
|||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"miro/internal/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLoadRecordedInputTrimsTrailingNewlineAfterEOF(t *testing.T) {
|
func TestLoadRecordedInputTrimsTrailingNewlineAfterEOF(t *testing.T) {
|
||||||
path := filepath.Join(t.TempDir(), "in")
|
path := filepath.Join(t.TempDir(), "in")
|
||||||
writeFile(t, path, "echo hi\r"+string([]byte{eofByte})+"\n")
|
testutil.WriteFile(t, path, "echo hi\r"+string([]byte{eofByte})+"\n")
|
||||||
|
|
||||||
got, err := loadRecordedInput(path)
|
got, err := loadRecordedInput(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -22,7 +24,7 @@ func TestLoadRecordedInputTrimsTrailingNewlineAfterEOF(t *testing.T) {
|
|||||||
|
|
||||||
func TestLoadRecordedInputTrimsTrailingNewlineAfterCarriageReturn(t *testing.T) {
|
func TestLoadRecordedInputTrimsTrailingNewlineAfterCarriageReturn(t *testing.T) {
|
||||||
path := filepath.Join(t.TempDir(), "in")
|
path := filepath.Join(t.TempDir(), "in")
|
||||||
writeFile(t, path, "echo hi\rexit\r\n")
|
testutil.WriteFile(t, path, "echo hi\rexit\r\n")
|
||||||
|
|
||||||
got, err := loadRecordedInput(path)
|
got, err := loadRecordedInput(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -37,7 +39,7 @@ func TestLoadRecordedInputTrimsTrailingNewlineAfterCarriageReturn(t *testing.T)
|
|||||||
|
|
||||||
func TestLoadRecordedInputLeavesNormalTrailingNewline(t *testing.T) {
|
func TestLoadRecordedInputLeavesNormalTrailingNewline(t *testing.T) {
|
||||||
path := filepath.Join(t.TempDir(), "in")
|
path := filepath.Join(t.TempDir(), "in")
|
||||||
writeFile(t, path, "echo hi\n")
|
testutil.WriteFile(t, path, "echo hi\n")
|
||||||
|
|
||||||
got, err := loadRecordedInput(path)
|
got, err := loadRecordedInput(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+30
-243
@@ -4,23 +4,24 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"miro/internal/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRecordCreatesRelativePath(t *testing.T) {
|
func TestRecordCreatesRelativePath(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
testDir := filepath.Join(root, "e2e")
|
testDir := filepath.Join(root, "e2e")
|
||||||
mustMkdirAll(t, testDir)
|
testutil.MustMkdirAll(t, testDir)
|
||||||
writeFile(t, filepath.Join(root, "miro.toml"), validConfigContent("e2e"))
|
testutil.WriteFile(t, filepath.Join(root, "miro.toml"), testutil.ValidConfigContent("e2e"))
|
||||||
mustWriteRecordShell(t, testDir)
|
mustWriteRecordShell(t, testDir)
|
||||||
addFakeRecordDependencies(t, "script")
|
testutil.AddFakeRecordDependencies(t, "script")
|
||||||
|
|
||||||
got := withWorkingDir(t, root, func() string {
|
got := testutil.WithWorkingDir(t, root, func() string {
|
||||||
withStdin(t, "y\n", func() {})
|
testutil.WithStdin(t, "y\n", func() {})
|
||||||
path, err := Record(filepath.Join("a", "b", "c") + string(os.PathSeparator))
|
path, err := Record(filepath.Join("a", "b", "c") + string(os.PathSeparator))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("Record() error = %v", err)
|
t.Fatalf("Record() error = %v", err)
|
||||||
@@ -39,10 +40,10 @@ func TestRecordCreatesRelativePath(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if got := readFile(t, filepath.Join(want, "in")); got != "fake recorded input\n" {
|
if got := testutil.ReadFile(t, filepath.Join(want, "in")); got != "fake recorded input\n" {
|
||||||
t.Fatalf("saved in = %q, want %q", got, "fake recorded input\n")
|
t.Fatalf("saved in = %q, want %q", got, "fake recorded input\n")
|
||||||
}
|
}
|
||||||
if got := readFile(t, filepath.Join(want, "out")); got != "fake recorded output\n" {
|
if got := testutil.ReadFile(t, filepath.Join(want, "out")); got != "fake recorded output\n" {
|
||||||
t.Fatalf("saved out = %q, want %q", got, "fake recorded output\n")
|
t.Fatalf("saved out = %q, want %q", got, "fake recorded output\n")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,13 +51,13 @@ func TestRecordCreatesRelativePath(t *testing.T) {
|
|||||||
func TestRecordReturnsDiscardedErrorWhenSaveDeclined(t *testing.T) {
|
func TestRecordReturnsDiscardedErrorWhenSaveDeclined(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
testDir := filepath.Join(root, "e2e")
|
testDir := filepath.Join(root, "e2e")
|
||||||
mustMkdirAll(t, testDir)
|
testutil.MustMkdirAll(t, testDir)
|
||||||
mustWriteRecordShell(t, testDir)
|
mustWriteRecordShell(t, testDir)
|
||||||
addFakeRecordDependencies(t, "script")
|
testutil.AddFakeRecordDependencies(t, "script")
|
||||||
|
|
||||||
err := withWorkingDir(t, root, func() error {
|
err := testutil.WithWorkingDir(t, root, func() error {
|
||||||
target := filepath.Join(testDir, "a", "b", "c")
|
target := filepath.Join(testDir, "a", "b", "c")
|
||||||
mustMkdirAll(t, target)
|
testutil.MustMkdirAll(t, target)
|
||||||
return withRecordStreams(t, "n\n", func(rio recordIO) error {
|
return withRecordStreams(t, "n\n", func(rio recordIO) error {
|
||||||
return recordScenario(target, recordShellPath(testDir), rio, defaultSandboxConfig())
|
return recordScenario(target, recordShellPath(testDir), rio, defaultSandboxConfig())
|
||||||
})
|
})
|
||||||
@@ -78,13 +79,13 @@ func TestRecordReturnsDiscardedErrorWhenOverwriteDeclined(t *testing.T) {
|
|||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
testDir := filepath.Join(root, "e2e")
|
testDir := filepath.Join(root, "e2e")
|
||||||
target := filepath.Join(testDir, "a", "b", "c")
|
target := filepath.Join(testDir, "a", "b", "c")
|
||||||
mustMkdirAll(t, target)
|
testutil.MustMkdirAll(t, target)
|
||||||
mustWriteRecordShell(t, testDir)
|
mustWriteRecordShell(t, testDir)
|
||||||
addFakeRecordDependencies(t, "script")
|
testutil.AddFakeRecordDependencies(t, "script")
|
||||||
writeFile(t, filepath.Join(target, "in"), "existing in\n")
|
testutil.WriteFile(t, filepath.Join(target, "in"), "existing in\n")
|
||||||
writeFile(t, filepath.Join(target, "out"), "existing out\n")
|
testutil.WriteFile(t, filepath.Join(target, "out"), "existing out\n")
|
||||||
|
|
||||||
err := withWorkingDir(t, root, func() error {
|
err := testutil.WithWorkingDir(t, root, func() error {
|
||||||
return withRecordStreams(t, "n\n", func(rio recordIO) error {
|
return withRecordStreams(t, "n\n", func(rio recordIO) error {
|
||||||
return recordScenario(target, recordShellPath(testDir), rio, defaultSandboxConfig())
|
return recordScenario(target, recordShellPath(testDir), rio, defaultSandboxConfig())
|
||||||
})
|
})
|
||||||
@@ -187,7 +188,7 @@ func TestRecordSessionEnvWithExtraIncludesAdditionalEntries(t *testing.T) {
|
|||||||
func TestRunRecordSessionUsesSandboxedScriptCommand(t *testing.T) {
|
func TestRunRecordSessionUsesSandboxedScriptCommand(t *testing.T) {
|
||||||
testDir := filepath.Join(t.TempDir(), "e2e")
|
testDir := filepath.Join(t.TempDir(), "e2e")
|
||||||
mustWriteRecordShell(t, testDir)
|
mustWriteRecordShell(t, testDir)
|
||||||
addFakeRecordDependencies(t, "script")
|
testutil.AddFakeRecordDependencies(t, "script")
|
||||||
|
|
||||||
argsPath := filepath.Join(t.TempDir(), "script.args")
|
argsPath := filepath.Join(t.TempDir(), "script.args")
|
||||||
commandBodyPath := filepath.Join(t.TempDir(), "script.command")
|
commandBodyPath := filepath.Join(t.TempDir(), "script.command")
|
||||||
@@ -208,7 +209,7 @@ func TestRunRecordSessionUsesSandboxedScriptCommand(t *testing.T) {
|
|||||||
t.Fatalf("runRecordSession() error = %v", err)
|
t.Fatalf("runRecordSession() error = %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
args := strings.Split(strings.TrimSpace(readFile(t, argsPath)), "\n")
|
args := strings.Split(strings.TrimSpace(testutil.ReadFile(t, argsPath)), "\n")
|
||||||
if len(args) != 9 {
|
if len(args) != 9 {
|
||||||
t.Fatalf("script args = %q, want 9 args", args)
|
t.Fatalf("script args = %q, want 9 args", args)
|
||||||
}
|
}
|
||||||
@@ -225,7 +226,7 @@ func TestRunRecordSessionUsesSandboxedScriptCommand(t *testing.T) {
|
|||||||
t.Fatalf("script args[8] = %q, want %q", args[8], shellPath)
|
t.Fatalf("script args[8] = %q, want %q", args[8], shellPath)
|
||||||
}
|
}
|
||||||
|
|
||||||
body := readFile(t, commandBodyPath)
|
body := testutil.ReadFile(t, commandBodyPath)
|
||||||
for _, want := range []string{
|
for _, want := range []string{
|
||||||
"host_home=${MIRO_HOST_HOME:?}",
|
"host_home=${MIRO_HOST_HOME:?}",
|
||||||
"visible_home=${MIRO_VISIBLE_HOME:?}",
|
"visible_home=${MIRO_VISIBLE_HOME:?}",
|
||||||
@@ -244,12 +245,12 @@ func TestRunRecordSessionUsesSandboxedScriptCommand(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestRecordScenarioUsesDeterministicSandbox(t *testing.T) {
|
func TestRecordScenarioUsesDeterministicSandbox(t *testing.T) {
|
||||||
requireCommands(t, "script", "bwrap", "bash")
|
testutil.RequireCommands(t, "script", "bwrap", "bash")
|
||||||
|
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
testDir := filepath.Join(root, "e2e")
|
testDir := filepath.Join(root, "e2e")
|
||||||
target := filepath.Join(testDir, "suite", "spec")
|
target := filepath.Join(testDir, "suite", "spec")
|
||||||
mustMkdirAll(t, target)
|
testutil.MustMkdirAll(t, target)
|
||||||
mustWriteRecordShell(t, testDir)
|
mustWriteRecordShell(t, testDir)
|
||||||
sandboxConfig := map[string]string{
|
sandboxConfig := map[string]string{
|
||||||
"visible_home": "/home/test",
|
"visible_home": "/home/test",
|
||||||
@@ -287,7 +288,7 @@ func TestRecordScenarioUsesDeterministicSandbox(t *testing.T) {
|
|||||||
writeDone <- nil
|
writeDone <- nil
|
||||||
}()
|
}()
|
||||||
|
|
||||||
err = withWorkingDir(t, root, func() error {
|
err = testutil.WithWorkingDir(t, root, func() error {
|
||||||
return recordScenario(target, recordShellPath(testDir), recordIO{
|
return recordScenario(target, recordShellPath(testDir), recordIO{
|
||||||
in: reader,
|
in: reader,
|
||||||
out: ioDiscard{},
|
out: ioDiscard{},
|
||||||
@@ -301,7 +302,7 @@ func TestRecordScenarioUsesDeterministicSandbox(t *testing.T) {
|
|||||||
t.Fatalf("write session input: %v", err)
|
t.Fatalf("write session input: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
recordedIn := readFile(t, filepath.Join(target, "in"))
|
recordedIn := testutil.ReadFile(t, filepath.Join(target, "in"))
|
||||||
if strings.Contains(recordedIn, "Script started on ") {
|
if strings.Contains(recordedIn, "Script started on ") {
|
||||||
t.Fatalf("saved in = %q, want stripped script wrapper", recordedIn)
|
t.Fatalf("saved in = %q, want stripped script wrapper", recordedIn)
|
||||||
}
|
}
|
||||||
@@ -311,7 +312,7 @@ func TestRecordScenarioUsesDeterministicSandbox(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
recordedOut := readFile(t, filepath.Join(target, "out"))
|
recordedOut := testutil.ReadFile(t, filepath.Join(target, "out"))
|
||||||
if strings.Contains(recordedOut, "Script started on ") {
|
if strings.Contains(recordedOut, "Script started on ") {
|
||||||
t.Fatalf("saved out = %q, want stripped script wrapper", recordedOut)
|
t.Fatalf("saved out = %q, want stripped script wrapper", recordedOut)
|
||||||
}
|
}
|
||||||
@@ -331,12 +332,12 @@ func TestRecordScenarioUsesDeterministicSandbox(t *testing.T) {
|
|||||||
func TestRecordFailsWhenRecorderShellMissing(t *testing.T) {
|
func TestRecordFailsWhenRecorderShellMissing(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
testDir := filepath.Join(root, "e2e")
|
testDir := filepath.Join(root, "e2e")
|
||||||
writeFile(t, filepath.Join(root, "miro.toml"), validConfigContent("e2e"))
|
testutil.WriteFile(t, filepath.Join(root, "miro.toml"), testutil.ValidConfigContent("e2e"))
|
||||||
mustMkdirAll(t, testDir)
|
testutil.MustMkdirAll(t, testDir)
|
||||||
addFakeRecordDependencies(t, "script")
|
testutil.AddFakeRecordDependencies(t, "script")
|
||||||
|
|
||||||
target := filepath.Join(testDir, "suite", "spec")
|
target := filepath.Join(testDir, "suite", "spec")
|
||||||
err := withWorkingDir(t, root, func() error {
|
err := testutil.WithWorkingDir(t, root, func() error {
|
||||||
_, err := Record(filepath.Join("suite", "spec"))
|
_, err := Record(filepath.Join("suite", "spec"))
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
@@ -350,217 +351,3 @@ func TestRecordFailsWhenRecorderShellMissing(t *testing.T) {
|
|||||||
t.Fatalf("Stat(%q) error = %v, want not exists", target, statErr)
|
t.Fatalf("Stat(%q) error = %v, want not exists", target, statErr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func withRecordStreams[T any](t *testing.T, input string, fn func(recordIO) T) T {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
path := filepath.Join(t.TempDir(), "stdin.txt")
|
|
||||||
if err := os.WriteFile(path, []byte(input), 0o644); err != nil {
|
|
||||||
t.Fatalf("WriteFile(%q) error = %v", path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := os.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Open(%q) error = %v", path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Cleanup(func() {
|
|
||||||
if err := file.Close(); err != nil {
|
|
||||||
t.Fatalf("close record input: %v", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return fn(recordIO{
|
|
||||||
in: file,
|
|
||||||
out: ioDiscard{},
|
|
||||||
err: &bytes.Buffer{},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
func withStdin(t *testing.T, input string, fn func()) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
path := filepath.Join(t.TempDir(), "stdin.txt")
|
|
||||||
if err := os.WriteFile(path, []byte(input), 0o644); err != nil {
|
|
||||||
t.Fatalf("WriteFile(%q) error = %v", path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
file, err := os.Open(path)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Open(%q) error = %v", path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
oldStdin := os.Stdin
|
|
||||||
os.Stdin = file
|
|
||||||
t.Cleanup(func() {
|
|
||||||
os.Stdin = oldStdin
|
|
||||||
if err := file.Close(); err != nil {
|
|
||||||
t.Fatalf("close stdin file: %v", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
fn()
|
|
||||||
}
|
|
||||||
|
|
||||||
func readFile(t *testing.T, path string) string {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
data, err := os.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("ReadFile(%q) error = %v", path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return string(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
type ioDiscard struct{}
|
|
||||||
|
|
||||||
func (ioDiscard) Write(p []byte) (int, error) {
|
|
||||||
return len(p), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func addFakeRecordDependencies(t *testing.T, names ...string) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
binDir := t.TempDir()
|
|
||||||
for _, name := range names {
|
|
||||||
path := filepath.Join(binDir, name)
|
|
||||||
body := "#!/bin/sh\nexit 0\n"
|
|
||||||
if name == "script" {
|
|
||||||
body = `#!/bin/sh
|
|
||||||
if [ -n "${FAKE_SCRIPT_ARGS_FILE:-}" ]; then
|
|
||||||
: > "$FAKE_SCRIPT_ARGS_FILE"
|
|
||||||
for arg in "$@"; do
|
|
||||||
printf '%s\n' "$arg" >> "$FAKE_SCRIPT_ARGS_FILE"
|
|
||||||
done
|
|
||||||
fi
|
|
||||||
in=''
|
|
||||||
out=''
|
|
||||||
cmd=''
|
|
||||||
while [ "$#" -gt 0 ]; do
|
|
||||||
case "$1" in
|
|
||||||
-I)
|
|
||||||
in="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
-O)
|
|
||||||
out="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
-c)
|
|
||||||
cmd="$2"
|
|
||||||
shift 2
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
if [ -n "${FAKE_SCRIPT_COMMAND_BODY_FILE:-}" ] && [ -n "$cmd" ]; then
|
|
||||||
: > "$FAKE_SCRIPT_COMMAND_BODY_FILE"
|
|
||||||
while IFS= read -r line || [ -n "$line" ]; do
|
|
||||||
printf '%s\n' "$line" >> "$FAKE_SCRIPT_COMMAND_BODY_FILE"
|
|
||||||
done < "$cmd"
|
|
||||||
fi
|
|
||||||
command_has_compare_marker=0
|
|
||||||
if [ -n "$cmd" ] && /bin/grep -q '__MIRO_E2E_BEGIN__' "$cmd" 2>/dev/null; then
|
|
||||||
command_has_compare_marker=1
|
|
||||||
fi
|
|
||||||
stdin_file=''
|
|
||||||
if [ "${FAKE_SCRIPT_ECHO_STDIN:-}" = "1" ] || [ -n "${FAKE_SCRIPT_CAPTURE_STDIN_FILE:-}" ]; then
|
|
||||||
stdin_file="${TMPDIR:-/tmp}/miro-fake-script-stdin-$$"
|
|
||||||
/bin/cat > "$stdin_file"
|
|
||||||
fi
|
|
||||||
if [ -n "${FAKE_SCRIPT_CAPTURE_STDIN_FILE:-}" ] && [ -n "$stdin_file" ]; then
|
|
||||||
/bin/cp "$stdin_file" "$FAKE_SCRIPT_CAPTURE_STDIN_FILE"
|
|
||||||
fi
|
|
||||||
if [ -n "$in" ] && [ -n "${FAKE_SCRIPT_LOG_IN+x}" ]; then
|
|
||||||
printf '%s' "$FAKE_SCRIPT_LOG_IN" > "$in"
|
|
||||||
elif [ -n "$in" ] && [ -n "$stdin_file" ]; then
|
|
||||||
/bin/cp "$stdin_file" "$in"
|
|
||||||
elif [ -n "$in" ]; then
|
|
||||||
printf '%s' 'fake recorded input
|
|
||||||
' > "$in"
|
|
||||||
fi
|
|
||||||
if [ -n "${FAKE_SCRIPT_STREAM_OUT+x}" ]; then
|
|
||||||
printf '%s' "$FAKE_SCRIPT_STREAM_OUT"
|
|
||||||
elif [ "${FAKE_SCRIPT_ECHO_STDIN:-}" = "1" ] && [ -n "$stdin_file" ]; then
|
|
||||||
/bin/cat "$stdin_file"
|
|
||||||
if [ "${MIRO_COMPARE_MARKER:-0}" = "1" ] && [ "$command_has_compare_marker" = "1" ]; then
|
|
||||||
printf '%s\n' '__MIRO_E2E_BEGIN__'
|
|
||||||
/bin/cat "$stdin_file"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
if [ -n "${FAKE_SCRIPT_STREAM_ERR+x}" ]; then
|
|
||||||
printf '%s' "$FAKE_SCRIPT_STREAM_ERR" >&2
|
|
||||||
fi
|
|
||||||
if [ -n "$out" ] && [ -n "${FAKE_SCRIPT_LOG_OUT+x}" ]; then
|
|
||||||
printf '%s' "$FAKE_SCRIPT_LOG_OUT" > "$out"
|
|
||||||
elif [ -n "$out" ] && [ "${FAKE_SCRIPT_ECHO_STDIN:-}" = "1" ] && [ -n "$stdin_file" ]; then
|
|
||||||
{
|
|
||||||
printf '%s' 'Script started on 2026-03-18 11:13:38+00:00 [TERM="xterm-256color"]
|
|
||||||
'
|
|
||||||
/bin/cat "$stdin_file"
|
|
||||||
if [ "${MIRO_COMPARE_MARKER:-0}" = "1" ] && [ "$command_has_compare_marker" = "1" ]; then
|
|
||||||
printf '%s\n' '__MIRO_E2E_BEGIN__'
|
|
||||||
/bin/cat "$stdin_file"
|
|
||||||
fi
|
|
||||||
printf '%s' 'Script done on 2026-03-18 11:13:44+00:00 [COMMAND_EXIT_CODE="0"]
|
|
||||||
'
|
|
||||||
} > "$out"
|
|
||||||
elif [ -n "$out" ]; then
|
|
||||||
printf '%s' 'Script started on 2026-03-18 11:13:38+00:00 [TERM="xterm-256color"]
|
|
||||||
fake recorded output
|
|
||||||
Script done on 2026-03-18 11:13:44+00:00 [COMMAND_EXIT_CODE="0"]
|
|
||||||
' > "$out"
|
|
||||||
fi
|
|
||||||
if [ -n "$stdin_file" ]; then
|
|
||||||
/bin/rm -f "$stdin_file"
|
|
||||||
fi
|
|
||||||
if [ -n "${FAKE_SCRIPT_EXIT_CODE:-}" ]; then
|
|
||||||
exit "$FAKE_SCRIPT_EXIT_CODE"
|
|
||||||
fi
|
|
||||||
exit 0
|
|
||||||
`
|
|
||||||
}
|
|
||||||
if err := os.WriteFile(path, []byte(body), 0o755); err != nil {
|
|
||||||
t.Fatalf("WriteFile(%q) error = %v", path, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Setenv("PATH", binDir)
|
|
||||||
}
|
|
||||||
|
|
||||||
func requireCommands(t *testing.T, names ...string) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
for _, name := range names {
|
|
||||||
if _, err := exec.LookPath(name); err != nil {
|
|
||||||
t.Skipf("missing command %q: %v", name, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func mustWriteRecordShell(t *testing.T, testDir string) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
if err := writeRecordShell(testDir); err != nil {
|
|
||||||
t.Fatalf("writeRecordShell(%q) error = %v", testDir, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func defaultSandboxConfig() map[string]string {
|
|
||||||
return map[string]string{
|
|
||||||
"visible_home": "/home/test",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func containsEnvEntry(env []string, want string) bool {
|
|
||||||
for _, entry := range env {
|
|
||||||
if entry == want {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|||||||
+21
-26
@@ -6,6 +6,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"miro/internal/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFormatElapsed(t *testing.T) {
|
func TestFormatElapsed(t *testing.T) {
|
||||||
@@ -30,10 +32,10 @@ func TestFormatElapsed(t *testing.T) {
|
|||||||
|
|
||||||
func TestDiscoverTestScenariosFindsNestedFixturesAndSorts(t *testing.T) {
|
func TestDiscoverTestScenariosFindsNestedFixturesAndSorts(t *testing.T) {
|
||||||
testDir := filepath.Join(t.TempDir(), "e2e")
|
testDir := filepath.Join(t.TempDir(), "e2e")
|
||||||
writeScenarioFixtures(t, filepath.Join(testDir, "nested", "b"), "echo two\n", "echo two\n")
|
testutil.WriteScenarioFixtures(t, filepath.Join(testDir, "nested", "b"), "echo two\n", "echo two\n")
|
||||||
writeScenarioFixtures(t, filepath.Join(testDir, "a"), "echo one\n", "echo one\n")
|
testutil.WriteScenarioFixtures(t, filepath.Join(testDir, "a"), "echo one\n", "echo one\n")
|
||||||
writeFile(t, filepath.Join(testDir, "shell.sh"), "#!/bin/sh\n")
|
testutil.WriteFile(t, filepath.Join(testDir, "shell.sh"), "#!/bin/sh\n")
|
||||||
writeFile(t, filepath.Join(testDir, "notes.txt"), "ignore me\n")
|
testutil.WriteFile(t, filepath.Join(testDir, "notes.txt"), "ignore me\n")
|
||||||
|
|
||||||
got, err := discoverTestScenarios(testDir, testDir)
|
got, err := discoverTestScenarios(testDir, testDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -63,7 +65,7 @@ func TestDiscoverTestScenariosFindsNestedFixturesAndSorts(t *testing.T) {
|
|||||||
|
|
||||||
func TestDiscoverTestScenariosRejectsMissingOutFixture(t *testing.T) {
|
func TestDiscoverTestScenariosRejectsMissingOutFixture(t *testing.T) {
|
||||||
testDir := filepath.Join(t.TempDir(), "e2e")
|
testDir := filepath.Join(t.TempDir(), "e2e")
|
||||||
writeFile(t, filepath.Join(testDir, "broken", "in"), "echo broken\n")
|
testutil.WriteFile(t, filepath.Join(testDir, "broken", "in"), "echo broken\n")
|
||||||
|
|
||||||
_, err := discoverTestScenarios(testDir, testDir)
|
_, err := discoverTestScenarios(testDir, testDir)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -76,7 +78,7 @@ func TestDiscoverTestScenariosRejectsMissingOutFixture(t *testing.T) {
|
|||||||
|
|
||||||
func TestDiscoverTestScenariosRejectsMissingInFixture(t *testing.T) {
|
func TestDiscoverTestScenariosRejectsMissingInFixture(t *testing.T) {
|
||||||
testDir := filepath.Join(t.TempDir(), "e2e")
|
testDir := filepath.Join(t.TempDir(), "e2e")
|
||||||
writeFile(t, filepath.Join(testDir, "broken", "out"), "echo broken\n")
|
testutil.WriteFile(t, filepath.Join(testDir, "broken", "out"), "echo broken\n")
|
||||||
|
|
||||||
_, err := discoverTestScenarios(testDir, testDir)
|
_, err := discoverTestScenarios(testDir, testDir)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -88,14 +90,14 @@ func TestDiscoverTestScenariosRejectsMissingInFixture(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestReplayScenarioUsesRecordedInputAndKeepsReplayOutputQuiet(t *testing.T) {
|
func TestReplayScenarioUsesRecordedInputAndKeepsReplayOutputQuiet(t *testing.T) {
|
||||||
addFakeRecordDependencies(t, "script")
|
testutil.AddFakeRecordDependencies(t, "script")
|
||||||
t.Setenv("FAKE_SCRIPT_ECHO_STDIN", "1")
|
t.Setenv("FAKE_SCRIPT_ECHO_STDIN", "1")
|
||||||
|
|
||||||
testDir := filepath.Join(t.TempDir(), "e2e")
|
testDir := filepath.Join(t.TempDir(), "e2e")
|
||||||
shellPath := filepath.Join(testDir, "shell.sh")
|
shellPath := filepath.Join(testDir, "shell.sh")
|
||||||
mustWriteRecordShell(t, testDir)
|
mustWriteRecordShell(t, testDir)
|
||||||
scenarioDir := filepath.Join(testDir, "suite", "spec")
|
scenarioDir := filepath.Join(testDir, "suite", "spec")
|
||||||
writeScenarioFixtures(t, scenarioDir, "echo replay\nexit\n", "echo replay\nexit\n")
|
testutil.WriteScenarioFixtures(t, scenarioDir, "echo replay\nexit\n", "echo replay\nexit\n")
|
||||||
|
|
||||||
capturedInput := filepath.Join(t.TempDir(), "stdin.capture")
|
capturedInput := filepath.Join(t.TempDir(), "stdin.capture")
|
||||||
t.Setenv("FAKE_SCRIPT_CAPTURE_STDIN_FILE", capturedInput)
|
t.Setenv("FAKE_SCRIPT_CAPTURE_STDIN_FILE", capturedInput)
|
||||||
@@ -115,7 +117,7 @@ func TestReplayScenarioUsesRecordedInputAndKeepsReplayOutputQuiet(t *testing.T)
|
|||||||
t.Fatalf("replayScenario() error = %v", err)
|
t.Fatalf("replayScenario() error = %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if got := readFile(t, capturedInput); got != "echo replay\nexit\n" {
|
if got := testutil.ReadFile(t, capturedInput); got != "echo replay\nexit\n" {
|
||||||
t.Fatalf("captured stdin = %q, want recorded input", got)
|
t.Fatalf("captured stdin = %q, want recorded input", got)
|
||||||
}
|
}
|
||||||
if stdout.String() != "" {
|
if stdout.String() != "" {
|
||||||
@@ -127,14 +129,14 @@ func TestReplayScenarioUsesRecordedInputAndKeepsReplayOutputQuiet(t *testing.T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestReplayScenarioFailsWhenCompareMarkerMissing(t *testing.T) {
|
func TestReplayScenarioFailsWhenCompareMarkerMissing(t *testing.T) {
|
||||||
addFakeRecordDependencies(t, "script")
|
testutil.AddFakeRecordDependencies(t, "script")
|
||||||
t.Setenv("FAKE_SCRIPT_ECHO_STDIN", "1")
|
t.Setenv("FAKE_SCRIPT_ECHO_STDIN", "1")
|
||||||
|
|
||||||
testDir := filepath.Join(t.TempDir(), "e2e")
|
testDir := filepath.Join(t.TempDir(), "e2e")
|
||||||
shellPath := filepath.Join(testDir, "shell.sh")
|
shellPath := filepath.Join(testDir, "shell.sh")
|
||||||
writeFile(t, shellPath, "#!/bin/sh\n")
|
testutil.WriteFile(t, shellPath, "#!/bin/sh\n")
|
||||||
scenarioDir := filepath.Join(testDir, "suite", "spec")
|
scenarioDir := filepath.Join(testDir, "suite", "spec")
|
||||||
writeScenarioFixtures(t, scenarioDir, "echo replay\nexit\n", "echo replay\nexit\n")
|
testutil.WriteScenarioFixtures(t, scenarioDir, "echo replay\nexit\n", "echo replay\nexit\n")
|
||||||
|
|
||||||
err := replayScenario(testScenario{
|
err := replayScenario(testScenario{
|
||||||
dir: scenarioDir,
|
dir: scenarioDir,
|
||||||
@@ -156,7 +158,7 @@ func TestReplayScenarioFailsWhenCompareMarkerMissing(t *testing.T) {
|
|||||||
func TestDiscoverTestScenariosUsesDisplayRootForRelativePaths(t *testing.T) {
|
func TestDiscoverTestScenariosUsesDisplayRootForRelativePaths(t *testing.T) {
|
||||||
testDir := filepath.Join(t.TempDir(), "e2e")
|
testDir := filepath.Join(t.TempDir(), "e2e")
|
||||||
scopedDir := filepath.Join(testDir, "nested")
|
scopedDir := filepath.Join(testDir, "nested")
|
||||||
writeScenarioFixtures(t, filepath.Join(scopedDir, "b"), "echo two\n", "echo two\n")
|
testutil.WriteScenarioFixtures(t, filepath.Join(scopedDir, "b"), "echo two\n", "echo two\n")
|
||||||
|
|
||||||
got, err := discoverTestScenarios(scopedDir, testDir)
|
got, err := discoverTestScenarios(scopedDir, testDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -172,7 +174,7 @@ func TestDiscoverTestScenariosUsesDisplayRootForRelativePaths(t *testing.T) {
|
|||||||
|
|
||||||
func TestResolveTestDiscoveryRootRejectsMissingPath(t *testing.T) {
|
func TestResolveTestDiscoveryRootRejectsMissingPath(t *testing.T) {
|
||||||
testDir := filepath.Join(t.TempDir(), "e2e")
|
testDir := filepath.Join(t.TempDir(), "e2e")
|
||||||
mustMkdirAll(t, testDir)
|
testutil.MustMkdirAll(t, testDir)
|
||||||
|
|
||||||
_, err := resolveTestDiscoveryRoot(testDir, "missing")
|
_, err := resolveTestDiscoveryRoot(testDir, "missing")
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -186,9 +188,9 @@ func TestResolveTestDiscoveryRootRejectsMissingPath(t *testing.T) {
|
|||||||
func TestResolveTestDiscoveryRootRejectsFile(t *testing.T) {
|
func TestResolveTestDiscoveryRootRejectsFile(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
testDir := filepath.Join(root, "e2e")
|
testDir := filepath.Join(root, "e2e")
|
||||||
writeFile(t, filepath.Join(testDir, "case.txt"), "hello\n")
|
testutil.WriteFile(t, filepath.Join(testDir, "case.txt"), "hello\n")
|
||||||
|
|
||||||
err := withWorkingDir(t, root, func() error {
|
err := testutil.WithWorkingDir(t, root, func() error {
|
||||||
_, err := resolveTestDiscoveryRoot(testDir, filepath.Join("e2e", "case.txt"))
|
_, err := resolveTestDiscoveryRoot(testDir, filepath.Join("e2e", "case.txt"))
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
@@ -204,11 +206,11 @@ func TestRunTestsScopedRunEmptyDirectoryFails(t *testing.T) {
|
|||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
testDir := filepath.Join(root, "e2e")
|
testDir := filepath.Join(root, "e2e")
|
||||||
emptyDir := filepath.Join(testDir, "empty")
|
emptyDir := filepath.Join(testDir, "empty")
|
||||||
writeFile(t, filepath.Join(root, "miro.toml"), validConfigContent("e2e"))
|
testutil.WriteFile(t, filepath.Join(root, "miro.toml"), testutil.ValidConfigContent("e2e"))
|
||||||
mustWriteRecordShell(t, testDir)
|
mustWriteRecordShell(t, testDir)
|
||||||
mustMkdirAll(t, emptyDir)
|
testutil.MustMkdirAll(t, emptyDir)
|
||||||
|
|
||||||
err := withWorkingDir(t, root, func() error {
|
err := testutil.WithWorkingDir(t, root, func() error {
|
||||||
return runTests("empty", testIO{
|
return runTests("empty", testIO{
|
||||||
out: &bytes.Buffer{},
|
out: &bytes.Buffer{},
|
||||||
err: &bytes.Buffer{},
|
err: &bytes.Buffer{},
|
||||||
@@ -221,10 +223,3 @@ func TestRunTestsScopedRunEmptyDirectoryFails(t *testing.T) {
|
|||||||
t.Fatalf("runTests() error = %q, want empty-directory error", err.Error())
|
t.Fatalf("runTests() error = %q, want empty-directory error", err.Error())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeScenarioFixtures(t *testing.T, dir, in, out string) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
writeFile(t, filepath.Join(dir, "in"), in)
|
|
||||||
writeFile(t, filepath.Join(dir, "out"), out)
|
|
||||||
}
|
|
||||||
|
|||||||
+39
-109
@@ -2,36 +2,37 @@ package miro
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"miro/internal/testutil"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestInitCreatesConfigAtProjectRoot(t *testing.T) {
|
func TestInitCreatesConfigAtProjectRoot(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
|
|
||||||
withWorkingDir(t, root, func() struct{} {
|
testutil.WithWorkingDir(t, root, func() struct{} {
|
||||||
if err := Init(); err != nil {
|
if err := Init(); err != nil {
|
||||||
t.Fatalf("Init() error = %v", err)
|
t.Fatalf("Init() error = %v", err)
|
||||||
}
|
}
|
||||||
return struct{}{}
|
return struct{}{}
|
||||||
})
|
})
|
||||||
|
|
||||||
got := readFile(t, filepath.Join(root, "miro.toml"))
|
got := testutil.ReadFile(t, filepath.Join(root, "miro.toml"))
|
||||||
if got != defaultWrittenConfig("e2e") {
|
if got != testutil.DefaultWrittenConfig("e2e") {
|
||||||
t.Fatalf("config = %q, want %q", got, defaultWrittenConfig("e2e"))
|
t.Fatalf("config = %q, want %q", got, testutil.DefaultWrittenConfig("e2e"))
|
||||||
}
|
}
|
||||||
assertRecordShell(t, filepath.Join(root, "e2e", recordShellName))
|
assertRecordShell(t, filepath.Join(root, "e2e", recordShellName))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInitUsesGitRoot(t *testing.T) {
|
func TestInitUsesGitRoot(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
mustGitInit(t, root)
|
testutil.MustGitInit(t, root)
|
||||||
subdir := filepath.Join(root, "nested", "dir")
|
subdir := filepath.Join(root, "nested", "dir")
|
||||||
mustMkdirAll(t, subdir)
|
testutil.MustMkdirAll(t, subdir)
|
||||||
|
|
||||||
withWorkingDir(t, subdir, func() struct{} {
|
testutil.WithWorkingDir(t, subdir, func() struct{} {
|
||||||
if err := Init(); err != nil {
|
if err := Init(); err != nil {
|
||||||
t.Fatalf("Init() error = %v", err)
|
t.Fatalf("Init() error = %v", err)
|
||||||
}
|
}
|
||||||
@@ -46,30 +47,30 @@ func TestInitUsesGitRoot(t *testing.T) {
|
|||||||
|
|
||||||
func TestInitLeavesExistingValidConfigUntouchedAndRefreshesShell(t *testing.T) {
|
func TestInitLeavesExistingValidConfigUntouchedAndRefreshesShell(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
writeFile(t, filepath.Join(root, "miro.toml"), validConfigContent("custom/suite"))
|
testutil.WriteFile(t, filepath.Join(root, "miro.toml"), testutil.ValidConfigContent("custom/suite"))
|
||||||
writeFile(t, filepath.Join(root, "custom", "suite", recordShellName), "outdated\n")
|
testutil.WriteFile(t, filepath.Join(root, "custom", "suite", recordShellName), "outdated\n")
|
||||||
|
|
||||||
withWorkingDir(t, root, func() struct{} {
|
testutil.WithWorkingDir(t, root, func() struct{} {
|
||||||
if err := Init(); err != nil {
|
if err := Init(); err != nil {
|
||||||
t.Fatalf("Init() error = %v", err)
|
t.Fatalf("Init() error = %v", err)
|
||||||
}
|
}
|
||||||
return struct{}{}
|
return struct{}{}
|
||||||
})
|
})
|
||||||
|
|
||||||
got := readFile(t, filepath.Join(root, "miro.toml"))
|
got := testutil.ReadFile(t, filepath.Join(root, "miro.toml"))
|
||||||
if got != validConfigContent("custom/suite") {
|
if got != testutil.ValidConfigContent("custom/suite") {
|
||||||
t.Fatalf("config = %q, want %q", got, validConfigContent("custom/suite"))
|
t.Fatalf("config = %q, want %q", got, testutil.ValidConfigContent("custom/suite"))
|
||||||
}
|
}
|
||||||
if got := readFile(t, filepath.Join(root, "custom", "suite", recordShellName)); got != buildRecordShellScript() {
|
if got := testutil.ReadFile(t, filepath.Join(root, "custom", "suite", recordShellName)); got != buildRecordShellScript() {
|
||||||
t.Fatalf("shell = %q, want refreshed recorder shell", got)
|
t.Fatalf("shell = %q, want refreshed recorder shell", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestInitCreatesMissingConfiguredTestDir(t *testing.T) {
|
func TestInitCreatesMissingConfiguredTestDir(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
writeFile(t, filepath.Join(root, "miro.toml"), validConfigContent("custom/suite"))
|
testutil.WriteFile(t, filepath.Join(root, "miro.toml"), testutil.ValidConfigContent("custom/suite"))
|
||||||
|
|
||||||
withWorkingDir(t, root, func() struct{} {
|
testutil.WithWorkingDir(t, root, func() struct{} {
|
||||||
if err := Init(); err != nil {
|
if err := Init(); err != nil {
|
||||||
t.Fatalf("Init() error = %v", err)
|
t.Fatalf("Init() error = %v", err)
|
||||||
}
|
}
|
||||||
@@ -81,9 +82,9 @@ func TestInitCreatesMissingConfiguredTestDir(t *testing.T) {
|
|||||||
|
|
||||||
func TestInitFailsWhenExistingConfigInvalid(t *testing.T) {
|
func TestInitFailsWhenExistingConfigInvalid(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
writeFile(t, filepath.Join(root, "miro.toml"), "test_dir = \"e2e\"\n")
|
testutil.WriteFile(t, filepath.Join(root, "miro.toml"), "test_dir = \"e2e\"\n")
|
||||||
|
|
||||||
err := withWorkingDir(t, root, func() error {
|
err := testutil.WithWorkingDir(t, root, func() error {
|
||||||
return Init()
|
return Init()
|
||||||
})
|
})
|
||||||
if err == nil {
|
if err == nil {
|
||||||
@@ -97,10 +98,10 @@ func TestInitFailsWhenExistingConfigInvalid(t *testing.T) {
|
|||||||
func TestResolveTestDirFromConfig(t *testing.T) {
|
func TestResolveTestDirFromConfig(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
configured := filepath.Join(root, "custom", "suite")
|
configured := filepath.Join(root, "custom", "suite")
|
||||||
mustMkdirAll(t, configured)
|
testutil.MustMkdirAll(t, configured)
|
||||||
writeFile(t, filepath.Join(root, "miro.toml"), validConfigContent("custom/suite"))
|
testutil.WriteFile(t, filepath.Join(root, "miro.toml"), testutil.ValidConfigContent("custom/suite"))
|
||||||
|
|
||||||
got := withWorkingDir(t, root, func() string {
|
got := testutil.WithWorkingDir(t, root, func() string {
|
||||||
path, err := ResolveTestDir()
|
path, err := ResolveTestDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ResolveTestDir() error = %v", err)
|
t.Fatalf("ResolveTestDir() error = %v", err)
|
||||||
@@ -116,7 +117,7 @@ func TestResolveTestDirFromConfig(t *testing.T) {
|
|||||||
func TestResolveTestDirMissingConfigFails(t *testing.T) {
|
func TestResolveTestDirMissingConfigFails(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
|
|
||||||
err := withWorkingDir(t, root, func() error {
|
err := testutil.WithWorkingDir(t, root, func() error {
|
||||||
_, err := ResolveTestDir()
|
_, err := ResolveTestDir()
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
@@ -131,9 +132,9 @@ func TestResolveTestDirMissingConfigFails(t *testing.T) {
|
|||||||
|
|
||||||
func TestResolveTestDirMissingTestDirFails(t *testing.T) {
|
func TestResolveTestDirMissingTestDirFails(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
writeFile(t, filepath.Join(root, "miro.toml"), "[miro]\n")
|
testutil.WriteFile(t, filepath.Join(root, "miro.toml"), "[miro]\n")
|
||||||
|
|
||||||
err := withWorkingDir(t, root, func() error {
|
err := testutil.WithWorkingDir(t, root, func() error {
|
||||||
_, err := ResolveTestDir()
|
_, err := ResolveTestDir()
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
@@ -148,9 +149,9 @@ func TestResolveTestDirMissingTestDirFails(t *testing.T) {
|
|||||||
|
|
||||||
func TestResolveTestDirEmptyTestDirFails(t *testing.T) {
|
func TestResolveTestDirEmptyTestDirFails(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
writeFile(t, filepath.Join(root, "miro.toml"), "[miro]\ntest_dir = \"\"\n")
|
testutil.WriteFile(t, filepath.Join(root, "miro.toml"), "[miro]\ntest_dir = \"\"\n")
|
||||||
|
|
||||||
err := withWorkingDir(t, root, func() error {
|
err := testutil.WithWorkingDir(t, root, func() error {
|
||||||
_, err := ResolveTestDir()
|
_, err := ResolveTestDir()
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
@@ -165,9 +166,9 @@ func TestResolveTestDirEmptyTestDirFails(t *testing.T) {
|
|||||||
|
|
||||||
func TestResolveTestDirMalformedConfigFails(t *testing.T) {
|
func TestResolveTestDirMalformedConfigFails(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
writeFile(t, filepath.Join(root, "miro.toml"), "[miro]\ntest_dir = [\n")
|
testutil.WriteFile(t, filepath.Join(root, "miro.toml"), "[miro]\ntest_dir = [\n")
|
||||||
|
|
||||||
err := withWorkingDir(t, root, func() error {
|
err := testutil.WithWorkingDir(t, root, func() error {
|
||||||
_, err := ResolveTestDir()
|
_, err := ResolveTestDir()
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
@@ -183,9 +184,9 @@ func TestResolveTestDirMalformedConfigFails(t *testing.T) {
|
|||||||
func TestResolveTestDirConfiguredMissingDirectoryReturnsConfiguredPath(t *testing.T) {
|
func TestResolveTestDirConfiguredMissingDirectoryReturnsConfiguredPath(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
want := filepath.Join(root, "missing")
|
want := filepath.Join(root, "missing")
|
||||||
writeFile(t, filepath.Join(root, "miro.toml"), validConfigContent("missing"))
|
testutil.WriteFile(t, filepath.Join(root, "miro.toml"), testutil.ValidConfigContent("missing"))
|
||||||
|
|
||||||
got := withWorkingDir(t, root, func() string {
|
got := testutil.WithWorkingDir(t, root, func() string {
|
||||||
path, err := ResolveTestDir()
|
path, err := ResolveTestDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ResolveTestDir() error = %v", err)
|
t.Fatalf("ResolveTestDir() error = %v", err)
|
||||||
@@ -200,10 +201,10 @@ func TestResolveTestDirConfiguredMissingDirectoryReturnsConfiguredPath(t *testin
|
|||||||
|
|
||||||
func TestResolveTestDirConfiguredFileFails(t *testing.T) {
|
func TestResolveTestDirConfiguredFileFails(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
writeFile(t, filepath.Join(root, "case.txt"), "hello\n")
|
testutil.WriteFile(t, filepath.Join(root, "case.txt"), "hello\n")
|
||||||
writeFile(t, filepath.Join(root, "miro.toml"), validConfigContent("case.txt"))
|
testutil.WriteFile(t, filepath.Join(root, "miro.toml"), testutil.ValidConfigContent("case.txt"))
|
||||||
|
|
||||||
err := withWorkingDir(t, root, func() error {
|
err := testutil.WithWorkingDir(t, root, func() error {
|
||||||
_, err := ResolveTestDir()
|
_, err := ResolveTestDir()
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
@@ -218,13 +219,13 @@ func TestResolveTestDirConfiguredFileFails(t *testing.T) {
|
|||||||
|
|
||||||
func TestResolveTestDirUsesGitRoot(t *testing.T) {
|
func TestResolveTestDirUsesGitRoot(t *testing.T) {
|
||||||
root := t.TempDir()
|
root := t.TempDir()
|
||||||
mustGitInit(t, root)
|
testutil.MustGitInit(t, root)
|
||||||
want := filepath.Join(root, "e2e")
|
want := filepath.Join(root, "e2e")
|
||||||
writeFile(t, filepath.Join(root, "miro.toml"), validConfigContent("e2e"))
|
testutil.WriteFile(t, filepath.Join(root, "miro.toml"), testutil.ValidConfigContent("e2e"))
|
||||||
subdir := filepath.Join(root, "nested", "dir")
|
subdir := filepath.Join(root, "nested", "dir")
|
||||||
mustMkdirAll(t, subdir)
|
testutil.MustMkdirAll(t, subdir)
|
||||||
|
|
||||||
got := withWorkingDir(t, subdir, func() string {
|
got := testutil.WithWorkingDir(t, subdir, func() string {
|
||||||
path, err := ResolveTestDir()
|
path, err := ResolveTestDir()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("ResolveTestDir() error = %v", err)
|
t.Fatalf("ResolveTestDir() error = %v", err)
|
||||||
@@ -236,74 +237,3 @@ func TestResolveTestDirUsesGitRoot(t *testing.T) {
|
|||||||
t.Fatalf("ResolveTestDir() = %q, want %q", got, want)
|
t.Fatalf("ResolveTestDir() = %q, want %q", got, want)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func withWorkingDir[T any](t *testing.T, dir string, fn func() T) T {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
wd, err := os.Getwd()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Getwd() error = %v", err)
|
|
||||||
}
|
|
||||||
if err := os.Chdir(dir); err != nil {
|
|
||||||
t.Fatalf("Chdir(%q) error = %v", dir, err)
|
|
||||||
}
|
|
||||||
t.Cleanup(func() {
|
|
||||||
if err := os.Chdir(wd); err != nil {
|
|
||||||
t.Fatalf("restore working directory: %v", err)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
return fn()
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeFile(t *testing.T, path, content string) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
mustMkdirAll(t, filepath.Dir(path))
|
|
||||||
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
|
|
||||||
t.Fatalf("WriteFile(%q) error = %v", path, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func mustMkdirAll(t *testing.T, path string) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
if err := os.MkdirAll(path, 0o755); err != nil {
|
|
||||||
t.Fatalf("MkdirAll(%q) error = %v", path, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func mustGitInit(t *testing.T, dir string) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
cmd := exec.Command("git", "init")
|
|
||||||
cmd.Dir = dir
|
|
||||||
out, err := cmd.CombinedOutput()
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("git init: %v\n%s", err, out)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func assertRecordShell(t *testing.T, path string) {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
info, err := os.Stat(path)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("Stat(%q) error = %v", path, err)
|
|
||||||
}
|
|
||||||
if info.Mode().Perm()&0o111 == 0 {
|
|
||||||
t.Fatalf("%q mode = %o, want executable", path, info.Mode().Perm())
|
|
||||||
}
|
|
||||||
|
|
||||||
if got := readFile(t, path); got != buildRecordShellScript() {
|
|
||||||
t.Fatalf("shell = %q, want generated recorder shell", got)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func defaultWrittenConfig(testDir string) string {
|
|
||||||
return "[miro]\n test_dir = \"" + testDir + "\"\n\n[sandbox]\n visible_home = \"/home/test\"\n"
|
|
||||||
}
|
|
||||||
|
|
||||||
func validConfigContent(testDir string) string {
|
|
||||||
return "[miro]\ntest_dir = \"" + testDir + "\"\n\n[sandbox]\nvisible_home = \"/home/test\"\n"
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,80 @@
|
|||||||
|
package miro
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"miro/internal/testutil"
|
||||||
|
)
|
||||||
|
|
||||||
|
func assertRecordShell(t *testing.T, path string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
info, err := os.Stat(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Stat(%q) error = %v", path, err)
|
||||||
|
}
|
||||||
|
if info.Mode().Perm()&0o111 == 0 {
|
||||||
|
t.Fatalf("%q mode = %o, want executable", path, info.Mode().Perm())
|
||||||
|
}
|
||||||
|
|
||||||
|
if got := testutil.ReadFile(t, path); got != buildRecordShellScript() {
|
||||||
|
t.Fatalf("shell = %q, want generated recorder shell", got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func withRecordStreams[T any](t *testing.T, input string, fn func(recordIO) T) T {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
path := filepath.Join(t.TempDir(), "stdin.txt")
|
||||||
|
testutil.WriteFile(t, path, input)
|
||||||
|
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Open(%q) error = %v", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Cleanup(func() {
|
||||||
|
if err := file.Close(); err != nil {
|
||||||
|
t.Fatalf("close record input: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return fn(recordIO{
|
||||||
|
in: file,
|
||||||
|
out: ioDiscard{},
|
||||||
|
err: &bytes.Buffer{},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
type ioDiscard struct{}
|
||||||
|
|
||||||
|
func (ioDiscard) Write(p []byte) (int, error) {
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustWriteRecordShell(t *testing.T, testDir string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
if err := writeRecordShell(testDir); err != nil {
|
||||||
|
t.Fatalf("writeRecordShell(%q) error = %v", testDir, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func defaultSandboxConfig() map[string]string {
|
||||||
|
return map[string]string{
|
||||||
|
"visible_home": "/home/test",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func containsEnvEntry(env []string, want string) bool {
|
||||||
|
for _, entry := range env {
|
||||||
|
if entry == want {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
@@ -0,0 +1,273 @@
|
|||||||
|
package testutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path/filepath"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CaptureOutput(t *testing.T, fn func()) (string, string) {
|
||||||
|
t.Helper()
|
||||||
|
t.Setenv("NO_COLOR", "1")
|
||||||
|
|
||||||
|
stdoutReader, stdoutWriter, err := os.Pipe()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("os.Pipe() stdout error = %v", err)
|
||||||
|
}
|
||||||
|
stderrReader, stderrWriter, err := os.Pipe()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("os.Pipe() stderr error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
oldStdout := os.Stdout
|
||||||
|
oldStderr := os.Stderr
|
||||||
|
os.Stdout = stdoutWriter
|
||||||
|
os.Stderr = stderrWriter
|
||||||
|
t.Cleanup(func() {
|
||||||
|
os.Stdout = oldStdout
|
||||||
|
os.Stderr = oldStderr
|
||||||
|
})
|
||||||
|
|
||||||
|
fn()
|
||||||
|
|
||||||
|
if err := stdoutWriter.Close(); err != nil {
|
||||||
|
t.Fatalf("stdout close error = %v", err)
|
||||||
|
}
|
||||||
|
if err := stderrWriter.Close(); err != nil {
|
||||||
|
t.Fatalf("stderr close error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var stdoutBuf bytes.Buffer
|
||||||
|
if _, err := io.Copy(&stdoutBuf, stdoutReader); err != nil {
|
||||||
|
t.Fatalf("stdout copy error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var stderrBuf bytes.Buffer
|
||||||
|
if _, err := io.Copy(&stderrBuf, stderrReader); err != nil {
|
||||||
|
t.Fatalf("stderr copy error = %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return stdoutBuf.String(), stderrBuf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteFile(t *testing.T, path, content string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
MustMkdirAll(t, filepath.Dir(path))
|
||||||
|
if err := os.WriteFile(path, []byte(content), 0o644); err != nil {
|
||||||
|
t.Fatalf("WriteFile(%q) error = %v", path, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteScenarioFixtures(t *testing.T, dir, in, out string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
WriteFile(t, filepath.Join(dir, "in"), in)
|
||||||
|
WriteFile(t, filepath.Join(dir, "out"), out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadFile(t *testing.T, path string) string {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
data, err := os.ReadFile(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("ReadFile(%q) error = %v", path, err)
|
||||||
|
}
|
||||||
|
return string(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MustMkdirAll(t *testing.T, path string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
if err := os.MkdirAll(path, 0o755); err != nil {
|
||||||
|
t.Fatalf("MkdirAll(%q) error = %v", path, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithWorkingDir[T any](t *testing.T, dir string, fn func() T) T {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
wd, err := os.Getwd()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Getwd() error = %v", err)
|
||||||
|
}
|
||||||
|
if err := os.Chdir(dir); err != nil {
|
||||||
|
t.Fatalf("Chdir(%q) error = %v", dir, err)
|
||||||
|
}
|
||||||
|
t.Cleanup(func() {
|
||||||
|
if err := os.Chdir(wd); err != nil {
|
||||||
|
t.Fatalf("restore working directory: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithStdin(t *testing.T, input string, fn func()) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
path := filepath.Join(t.TempDir(), "stdin.txt")
|
||||||
|
if err := os.WriteFile(path, []byte(input), 0o644); err != nil {
|
||||||
|
t.Fatalf("WriteFile(%q) error = %v", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
file, err := os.Open(path)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Open(%q) error = %v", path, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
oldStdin := os.Stdin
|
||||||
|
os.Stdin = file
|
||||||
|
t.Cleanup(func() {
|
||||||
|
os.Stdin = oldStdin
|
||||||
|
if err := file.Close(); err != nil {
|
||||||
|
t.Fatalf("close stdin file: %v", err)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
fn()
|
||||||
|
}
|
||||||
|
|
||||||
|
func AddFakeRecordDependencies(t *testing.T, names ...string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
binDir := t.TempDir()
|
||||||
|
for _, name := range names {
|
||||||
|
path := filepath.Join(binDir, name)
|
||||||
|
body := "#!/bin/sh\nexit 0\n"
|
||||||
|
if name == "script" {
|
||||||
|
body = `#!/bin/sh
|
||||||
|
if [ -n "${FAKE_SCRIPT_ARGS_FILE:-}" ]; then
|
||||||
|
: > "$FAKE_SCRIPT_ARGS_FILE"
|
||||||
|
for arg in "$@"; do
|
||||||
|
printf '%s\n' "$arg" >> "$FAKE_SCRIPT_ARGS_FILE"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
in=''
|
||||||
|
out=''
|
||||||
|
cmd=''
|
||||||
|
while [ "$#" -gt 0 ]; do
|
||||||
|
case "$1" in
|
||||||
|
-I)
|
||||||
|
in="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-O)
|
||||||
|
out="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
-c)
|
||||||
|
cmd="$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
if [ -n "${FAKE_SCRIPT_COMMAND_BODY_FILE:-}" ] && [ -n "$cmd" ]; then
|
||||||
|
: > "$FAKE_SCRIPT_COMMAND_BODY_FILE"
|
||||||
|
while IFS= read -r line || [ -n "$line" ]; do
|
||||||
|
printf '%s\n' "$line" >> "$FAKE_SCRIPT_COMMAND_BODY_FILE"
|
||||||
|
done < "$cmd"
|
||||||
|
fi
|
||||||
|
command_has_compare_marker=0
|
||||||
|
if [ -n "$cmd" ] && /bin/grep -q '__MIRO_E2E_BEGIN__' "$cmd" 2>/dev/null; then
|
||||||
|
command_has_compare_marker=1
|
||||||
|
fi
|
||||||
|
stdin_file=''
|
||||||
|
if [ "${FAKE_SCRIPT_ECHO_STDIN:-}" = "1" ] || [ -n "${FAKE_SCRIPT_CAPTURE_STDIN_FILE:-}" ]; then
|
||||||
|
stdin_file="${TMPDIR:-/tmp}/miro-fake-script-stdin-$$"
|
||||||
|
/bin/cat > "$stdin_file"
|
||||||
|
fi
|
||||||
|
if [ -n "${FAKE_SCRIPT_CAPTURE_STDIN_FILE:-}" ] && [ -n "$stdin_file" ]; then
|
||||||
|
/bin/cp "$stdin_file" "$FAKE_SCRIPT_CAPTURE_STDIN_FILE"
|
||||||
|
fi
|
||||||
|
if [ -n "$in" ] && [ -n "${FAKE_SCRIPT_LOG_IN+x}" ]; then
|
||||||
|
printf '%s' "$FAKE_SCRIPT_LOG_IN" > "$in"
|
||||||
|
elif [ -n "$in" ] && [ -n "$stdin_file" ]; then
|
||||||
|
/bin/cp "$stdin_file" "$in"
|
||||||
|
elif [ -n "$in" ]; then
|
||||||
|
printf '%s' 'fake recorded input
|
||||||
|
' > "$in"
|
||||||
|
fi
|
||||||
|
if [ -n "${FAKE_SCRIPT_STREAM_OUT+x}" ]; then
|
||||||
|
printf '%s' "$FAKE_SCRIPT_STREAM_OUT"
|
||||||
|
elif [ "${FAKE_SCRIPT_ECHO_STDIN:-}" = "1" ] && [ -n "$stdin_file" ]; then
|
||||||
|
/bin/cat "$stdin_file"
|
||||||
|
if [ "${MIRO_COMPARE_MARKER:-0}" = "1" ] && [ "$command_has_compare_marker" = "1" ]; then
|
||||||
|
printf '%s\n' '__MIRO_E2E_BEGIN__'
|
||||||
|
/bin/cat "$stdin_file"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ -n "${FAKE_SCRIPT_STREAM_ERR+x}" ]; then
|
||||||
|
printf '%s' "$FAKE_SCRIPT_STREAM_ERR" >&2
|
||||||
|
fi
|
||||||
|
if [ -n "$out" ] && [ -n "${FAKE_SCRIPT_LOG_OUT+x}" ]; then
|
||||||
|
printf '%s' "$FAKE_SCRIPT_LOG_OUT" > "$out"
|
||||||
|
elif [ -n "$out" ] && [ "${FAKE_SCRIPT_ECHO_STDIN:-}" = "1" ] && [ -n "$stdin_file" ]; then
|
||||||
|
{
|
||||||
|
printf '%s' 'Script started on 2026-03-18 11:13:38+00:00 [TERM="xterm-256color"]
|
||||||
|
'
|
||||||
|
/bin/cat "$stdin_file"
|
||||||
|
if [ "${MIRO_COMPARE_MARKER:-0}" = "1" ] && [ "$command_has_compare_marker" = "1" ]; then
|
||||||
|
printf '%s\n' '__MIRO_E2E_BEGIN__'
|
||||||
|
/bin/cat "$stdin_file"
|
||||||
|
fi
|
||||||
|
printf '%s' 'Script done on 2026-03-18 11:13:44+00:00 [COMMAND_EXIT_CODE="0"]
|
||||||
|
'
|
||||||
|
} > "$out"
|
||||||
|
elif [ -n "$out" ]; then
|
||||||
|
printf '%s' 'Script started on 2026-03-18 11:13:38+00:00 [TERM="xterm-256color"]
|
||||||
|
fake recorded output
|
||||||
|
Script done on 2026-03-18 11:13:44+00:00 [COMMAND_EXIT_CODE="0"]
|
||||||
|
' > "$out"
|
||||||
|
fi
|
||||||
|
if [ -n "$stdin_file" ]; then
|
||||||
|
/bin/rm -f "$stdin_file"
|
||||||
|
fi
|
||||||
|
if [ -n "${FAKE_SCRIPT_EXIT_CODE:-}" ]; then
|
||||||
|
exit "$FAKE_SCRIPT_EXIT_CODE"
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
`
|
||||||
|
}
|
||||||
|
if err := os.WriteFile(path, []byte(body), 0o755); err != nil {
|
||||||
|
t.Fatalf("WriteFile(%q) error = %v", path, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Setenv("PATH", binDir)
|
||||||
|
}
|
||||||
|
|
||||||
|
func RequireCommands(t *testing.T, names ...string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
for _, name := range names {
|
||||||
|
if _, err := exec.LookPath(name); err != nil {
|
||||||
|
t.Skipf("missing command %q: %v", name, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func MustGitInit(t *testing.T, dir string) {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
cmd := exec.Command("git", "init")
|
||||||
|
cmd.Dir = dir
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("git init: %v\n%s", err, out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func DefaultWrittenConfig(testDir string) string {
|
||||||
|
return "[miro]\n test_dir = \"" + testDir + "\"\n\n[sandbox]\n visible_home = \"/home/test\"\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
func ValidConfigContent(testDir string) string {
|
||||||
|
return "[miro]\ntest_dir = \"" + testDir + "\"\n\n[sandbox]\nvisible_home = \"/home/test\"\n"
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user