1616package cmd
1717
1818import (
19+ "fmt"
20+ "os"
21+ "path/filepath"
22+ "strings"
1923 "testing"
2024
2125 "magician/exec"
@@ -26,29 +30,93 @@ type sandbox struct {
2630 Runner ExecRunner
2731}
2832
33+ // Routes some commands to fake sandbox scripts, bypassing $PATH.
34+ type interceptingRunner struct {
35+ * exec.Runner
36+ sbDir string
37+ allowedPassthrough map [string ]bool
38+ strictMode bool
39+ }
40+
41+ func (s * interceptingRunner ) Run (name string , args []string , env map [string ]string ) (string , error ) {
42+ if ! s .strictMode {
43+ if ! strings .Contains (name , string (filepath .Separator )) {
44+ sandboxBin := filepath .Join (s .sbDir , name )
45+ if _ , err := os .Stat (sandboxBin ); err == nil {
46+ name = sandboxBin
47+ }
48+ }
49+ return s .Runner .Run (name , args , env )
50+ }
51+
52+ baseName := filepath .Base (name )
53+
54+ sandboxBin := filepath .Join (s .sbDir , baseName )
55+ if _ , err := os .Stat (sandboxBin ); err == nil {
56+ return s .Runner .Run (sandboxBin , args , env )
57+ }
58+
59+ if s .allowedPassthrough [baseName ] {
60+ return s .Runner .Run (name , args , env )
61+ }
62+
63+ return "" , fmt .Errorf ("command %q is not in the passthrough list and no sandbox mock was found. Please mock it or add it to the passthrough list" , baseName )
64+ }
65+
2966func newSandbox (t * testing.T ) * sandbox {
3067 dir := t .TempDir ()
3168
32- runner , err := exec .NewRunner ()
69+ realRunner , err := exec .NewRunner ()
3370 if err != nil {
3471 t .Fatalf ("Failed to create runner: %v" , err )
3572 }
3673
37- if err := runner .PushDir (dir ); err != nil {
74+ if err := realRunner .PushDir (dir ); err != nil {
3875 t .Fatalf ("Failed to push dir: %v" , err )
3976 }
4077
41- runner .MustRun ("git" , []string {"init" , "-b" , "main" }, nil )
78+ realRunner .MustRun ("git" , []string {"init" , "-b" , "main" }, nil )
79+
80+ realRunner .MustRun ("touch" , []string {"README.md" }, nil )
81+ realRunner .MustRun ("git" , []string {"add" , "." }, nil )
82+ realRunner .MustRun ("git" , []string {"config" , "user.email" , "test@example.com" }, nil )
83+ realRunner .MustRun ("git" , []string {"config" , "user.name" , "Test Sandbox" }, nil )
84+ realRunner .MustRun ("git" , []string {"config" , "commit.gpgsign" , "false" }, nil )
85+ realRunner .MustRun ("git" , []string {"commit" , "-m" , "Initial sandbox commit" }, nil )
4286
43- runner .MustRun ("touch" , []string {"README.md" }, nil )
44- runner .MustRun ("git" , []string {"add" , "." }, nil )
45- runner .MustRun ("git" , []string {"config" , "user.email" , "test@example.com" }, nil )
46- runner .MustRun ("git" , []string {"config" , "user.name" , "Test Sandbox" }, nil )
47- runner .MustRun ("git" , []string {"config" , "commit.gpgsign" , "false" }, nil )
48- runner .MustRun ("git" , []string {"commit" , "-m" , "Initial sandbox commit" }, nil )
87+ runner := & interceptingRunner {
88+ Runner : realRunner ,
89+ sbDir : dir ,
90+ allowedPassthrough : map [string ]bool {
91+ "chmod" : true ,
92+ "rm" : true ,
93+ "mkdir" : true ,
94+ "touch" : true ,
95+ "cp" : true ,
96+ "mv" : true ,
97+ "ls" : true ,
98+ "echo" : true ,
99+ "cat" : true ,
100+ "grep" : true ,
101+ },
102+ }
49103
50104 return & sandbox {
51105 Dir : dir ,
52106 Runner : runner ,
53107 }
54108}
109+
110+ func (s * sandbox ) AllowPassthrough (commands ... string ) {
111+ if runner , ok := s .Runner .(* interceptingRunner ); ok {
112+ for _ , cmd := range commands {
113+ runner .allowedPassthrough [cmd ] = true
114+ }
115+ }
116+ }
117+
118+ func (s * sandbox ) RequireWhitelist () {
119+ if runner , ok := s .Runner .(* interceptingRunner ); ok {
120+ runner .strictMode = true
121+ }
122+ }
0 commit comments