github.com/markusbkk/elvish@v0.0.0-20231204143114-91dc52438621/pkg/prog/prog_test.go (about) 1 package prog_test 2 3 import ( 4 "fmt" 5 "os" 6 "testing" 7 8 . "github.com/markusbkk/elvish/pkg/prog" 9 "github.com/markusbkk/elvish/pkg/prog/progtest" 10 "github.com/markusbkk/elvish/pkg/testutil" 11 ) 12 13 var ( 14 Test = progtest.Test 15 ThatElvish = progtest.ThatElvish 16 ) 17 18 func TestFlagHandling(t *testing.T) { 19 Test(t, &testProgram{}, 20 ThatElvish("-bad-flag"). 21 ExitsWith(2). 22 WritesStderrContaining("flag provided but not defined: -bad-flag\nUsage:"), 23 // -h is treated as a bad flag 24 ThatElvish("-h"). 25 ExitsWith(2). 26 WritesStderrContaining("flag provided but not defined: -h\nUsage:"), 27 28 ThatElvish("-help"). 29 WritesStdoutContaining("Usage: elvish [flags] [script]"), 30 ) 31 } 32 33 func TestLogFlag(t *testing.T) { 34 testutil.InTempDir(t) 35 Test(t, &testProgram{}, 36 ThatElvish("-log", "log").DoesNothing()) 37 _, err := os.Stat("log") 38 if err != nil { 39 t.Errorf("log file was not created: %v", err) 40 } 41 } 42 43 func TestCustomFlag(t *testing.T) { 44 Test(t, &testProgram{customFlag: true}, 45 ThatElvish("-flag", "foo"). 46 WritesStdout("-flag foo\n"), 47 ) 48 } 49 50 func TestSharedFlags(t *testing.T) { 51 Test(t, &testProgram{sharedFlags: true}, 52 ThatElvish("-sock", "sock", "-db", "db", "-json"). 53 WritesStdout("-sock sock -db db -json true\n"), 54 ) 55 } 56 57 func TestSharedFlags_MultiplePrograms(t *testing.T) { 58 Test(t, 59 Composite( 60 &testProgram{sharedFlags: true, nextProgram: true}, 61 &testProgram{sharedFlags: true}), 62 ThatElvish("-sock", "sock", "-db", "db", "-json"). 63 WritesStdout("-sock sock -db db -json true\n"), 64 ) 65 } 66 67 func TestShowDeprecations(t *testing.T) { 68 progtest.SetDeprecationLevel(t, 0) 69 70 Test(t, &testProgram{}, 71 ThatElvish("-deprecation-level", "42").DoesNothing(), 72 ) 73 74 if DeprecationLevel != 42 { 75 t.Errorf("ShowDeprecations = %d, want 42", DeprecationLevel) 76 } 77 } 78 79 func TestNoSuitableSubprogram(t *testing.T) { 80 Test(t, &testProgram{nextProgram: true}, 81 ThatElvish(). 82 ExitsWith(2). 83 WritesStderr("internal error: no suitable subprogram\n"), 84 ) 85 } 86 87 func TestComposite(t *testing.T) { 88 Test(t, 89 Composite(&testProgram{nextProgram: true}, &testProgram{writeOut: "program 2"}), 90 ThatElvish().WritesStdout("program 2"), 91 ) 92 } 93 94 func TestComposite_NoSuitableSubprogram(t *testing.T) { 95 Test(t, 96 Composite(&testProgram{nextProgram: true}, &testProgram{nextProgram: true}), 97 ThatElvish(). 98 ExitsWith(2). 99 WritesStderr("internal error: no suitable subprogram\n"), 100 ) 101 } 102 103 func TestComposite_PreferEarlierSubprogram(t *testing.T) { 104 Test(t, 105 Composite( 106 &testProgram{writeOut: "program 1"}, &testProgram{writeOut: "program 2"}), 107 ThatElvish().WritesStdout("program 1"), 108 ) 109 } 110 111 func TestBadUsageError(t *testing.T) { 112 Test(t, 113 &testProgram{returnErr: BadUsage("lorem ipsum")}, 114 ThatElvish().ExitsWith(2).WritesStderrContaining("lorem ipsum\n"), 115 ) 116 } 117 118 func TestExitError(t *testing.T) { 119 Test(t, &testProgram{returnErr: Exit(3)}, 120 ThatElvish().ExitsWith(3), 121 ) 122 } 123 124 func TestExitError_0(t *testing.T) { 125 Test(t, &testProgram{returnErr: Exit(0)}, 126 ThatElvish().ExitsWith(0), 127 ) 128 } 129 130 type testProgram struct { 131 nextProgram bool 132 writeOut string 133 returnErr error 134 customFlag bool 135 sharedFlags bool 136 137 flag string 138 daemonPaths *DaemonPaths 139 json *bool 140 } 141 142 func (p *testProgram) RegisterFlags(f *FlagSet) { 143 if p.customFlag { 144 f.StringVar(&p.flag, "flag", "default", "a flag") 145 } 146 if p.sharedFlags { 147 p.daemonPaths = f.DaemonPaths() 148 p.json = f.JSON() 149 } 150 } 151 152 func (p *testProgram) Run(fds [3]*os.File, args []string) error { 153 if p.nextProgram { 154 return ErrNextProgram 155 } 156 fds[1].WriteString(p.writeOut) 157 if p.customFlag { 158 fmt.Fprintf(fds[1], "-flag %s\n", p.flag) 159 } 160 if p.sharedFlags { 161 fmt.Fprintf(fds[1], "-sock %s -db %s -json %v\n", 162 p.daemonPaths.Sock, p.daemonPaths.DB, *p.json) 163 } 164 return p.returnErr 165 }