Skip to content

Commit a5dc8ff

Browse files
committed
testscript: phase out func() int in RunMain
We wanted the user's command functions to return an exit code as an int rather than calling os.Exit directly like a main function so that we could collect coverage profiles from subprocesses. This way, Go tests using testscript would still report the full code coverage information even when using nested processes. This all thankfully went away with Go 1.20, which introduced the same feature but built right into the toolchain for both `go test` and `go build`. As such, we were able to drop all of that code, including the bit that we ran before os.Exit. For more information, see: https://go.dev/blog/integration-test-coverage At this point, testscript users continue to use the `func() int` signature, via e.g. `func main1() int` out of inertia, but there's actually no good reason to keep doing that. It causes extra boilerplate and confuses new testscript users. Moreover, avoiding the use of os.Exit was rather tricky, for example see the former use of flag.ContinueOnExit in our tests. Add a new API, Main, which uses a `func()` signature just like `func main()`, meaning that no second function declaration is needed. Deprecate RunMain in favor of Main as well.
1 parent f18544a commit a5dc8ff

File tree

13 files changed

+74
-98
lines changed

13 files changed

+74
-98
lines changed

cmd/testscript/main.go

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -41,37 +41,28 @@ func (e *envVarsFlag) Set(v string) error {
4141
}
4242

4343
func main() {
44-
os.Exit(main1())
45-
}
46-
47-
func main1() int {
4844
switch err := mainerr(); err {
4945
case nil:
50-
return 0
51-
case flag.ErrHelp:
52-
return 2
5346
default:
5447
fmt.Fprintln(os.Stderr, err)
55-
return 1
48+
os.Exit(1)
5649
}
5750
}
5851

5952
func mainerr() (retErr error) {
60-
fs := flag.NewFlagSet(os.Args[0], flag.ContinueOnError)
61-
fs.Usage = func() {
53+
flag.Usage = func() {
6254
mainUsage(os.Stderr)
55+
os.Exit(2)
6356
}
6457
var envVars envVarsFlag
65-
fUpdate := fs.Bool("u", false, "update archive file if a cmp fails")
66-
fWork := fs.Bool("work", false, "print temporary work directory and do not remove when done")
67-
fContinue := fs.Bool("continue", false, "continue running the script if an error occurs")
68-
fVerbose := fs.Bool("v", false, "run tests verbosely")
69-
fs.Var(&envVars, "e", "pass through environment variable to script (can appear multiple times)")
70-
if err := fs.Parse(os.Args[1:]); err != nil {
71-
return err
72-
}
73-
74-
files := fs.Args()
58+
fUpdate := flag.Bool("u", false, "update archive file if a cmp fails")
59+
fWork := flag.Bool("work", false, "print temporary work directory and do not remove when done")
60+
fContinue := flag.Bool("continue", false, "continue running the script if an error occurs")
61+
fVerbose := flag.Bool("v", false, "run tests verbosely")
62+
flag.Var(&envVars, "e", "pass through environment variable to script (can appear multiple times)")
63+
flag.Parse()
64+
65+
files := flag.Args()
7566
if len(files) == 0 {
7667
files = []string{"-"}
7768
}

cmd/testscript/main_test.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ package main
66

77
import (
88
"bytes"
9-
"os"
109
"os/exec"
1110
"path/filepath"
1211
"runtime"
@@ -19,9 +18,9 @@ import (
1918
)
2019

2120
func TestMain(m *testing.M) {
22-
os.Exit(testscript.RunMain(m, map[string]func() int{
23-
"testscript": main1,
24-
}))
21+
testscript.Main(m, map[string]func(){
22+
"testscript": main,
23+
})
2524
}
2625

2726
func TestScripts(t *testing.T) {

cmd/txtar-addmod/addmod.go

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,13 +62,9 @@ func fatalf(format string, args ...interface{}) {
6262

6363
const goCmd = "go"
6464

65-
func main() {
66-
os.Exit(main1())
67-
}
68-
6965
var allFiles = flag.Bool("all", false, "include all source files")
7066

71-
func main1() int {
67+
func main() {
7268
flag.Usage = usage
7369
flag.Parse()
7470
if flag.NArg() < 2 {
@@ -211,5 +207,5 @@ func main1() int {
211207
}
212208
}
213209
os.RemoveAll(tmpdir)
214-
return exitCode
210+
os.Exit(exitCode)
215211
}

cmd/txtar-addmod/script_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@ import (
1717
var proxyURL string
1818

1919
func TestMain(m *testing.M) {
20-
os.Exit(testscript.RunMain(gobinMain{m}, map[string]func() int{
21-
"txtar-addmod": main1,
22-
}))
20+
testscript.Main(gobinMain{m}, map[string]func(){
21+
"txtar-addmod": main,
22+
})
2323
}
2424

2525
type gobinMain struct {

cmd/txtar-c/savedir.go

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ package main
1414

1515
import (
1616
"bytes"
17-
stdflag "flag"
17+
"flag"
1818
"fmt"
1919
"log"
2020
"os"
@@ -25,11 +25,10 @@ import (
2525
"github.com/rogpeppe/go-internal/txtar"
2626
)
2727

28-
var flag = stdflag.NewFlagSet(os.Args[0], stdflag.ContinueOnError)
29-
3028
func usage() {
3129
fmt.Fprintf(os.Stderr, "usage: txtar-c dir >saved.txtar\n")
3230
flag.PrintDefaults()
31+
os.Exit(2)
3332
}
3433

3534
var (
@@ -38,17 +37,10 @@ var (
3837
)
3938

4039
func main() {
41-
os.Exit(main1())
42-
}
43-
44-
func main1() int {
4540
flag.Usage = usage
46-
if flag.Parse(os.Args[1:]) != nil {
47-
return 2
48-
}
41+
flag.Parse()
4942
if flag.NArg() != 1 {
5043
usage()
51-
return 2
5244
}
5345

5446
log.SetPrefix("txtar-c: ")
@@ -111,6 +103,4 @@ func main1() int {
111103

112104
data := txtar.Format(a)
113105
os.Stdout.Write(data)
114-
115-
return 0
116106
}

cmd/txtar-c/script_test.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,15 @@
55
package main
66

77
import (
8-
"os"
98
"testing"
109

1110
"github.com/rogpeppe/go-internal/testscript"
1211
)
1312

1413
func TestMain(m *testing.M) {
15-
os.Exit(testscript.RunMain(m, map[string]func() int{
16-
"txtar-c": main1,
17-
}))
14+
testscript.Main(m, map[string]func(){
15+
"txtar-c": main,
16+
})
1817
}
1918

2019
func TestScripts(t *testing.T) {

cmd/txtar-x/extract.go

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -29,18 +29,14 @@ var (
2929
func usage() {
3030
fmt.Fprintf(os.Stderr, "usage: txtar-x [flags] [file]\n")
3131
flag.PrintDefaults()
32+
os.Exit(2)
3233
}
3334

3435
func main() {
35-
os.Exit(main1())
36-
}
37-
38-
func main1() int {
3936
flag.Usage = usage
4037
flag.Parse()
4138
if flag.NArg() > 1 {
4239
usage()
43-
return 2
4440
}
4541
log.SetPrefix("txtar-x: ")
4642
log.SetFlags(0)
@@ -50,20 +46,19 @@ func main1() int {
5046
data, err := io.ReadAll(os.Stdin)
5147
if err != nil {
5248
log.Printf("cannot read stdin: %v", err)
53-
return 1
49+
os.Exit(1)
5450
}
5551
a = txtar.Parse(data)
5652
} else {
5753
a1, err := txtar.ParseFile(flag.Arg(0))
5854
if err != nil {
5955
log.Print(err)
60-
return 1
56+
os.Exit(1)
6157
}
6258
a = a1
6359
}
6460
if err := txtar.Write(a, *extractDir); err != nil {
6561
log.Print(err)
66-
return 1
62+
os.Exit(1)
6763
}
68-
return 0
6964
}

cmd/txtar-x/extract_test.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ import (
1313
)
1414

1515
func TestMain(m *testing.M) {
16-
os.Exit(testscript.RunMain(m, map[string]func() int{
17-
"txtar-x": main1,
18-
}))
16+
testscript.Main(m, map[string]func(){
17+
"txtar-x": main,
18+
})
1919
}
2020

2121
func TestScripts(t *testing.T) {

gotooltest/testdata/cover.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ import (
5151
)
5252

5353
func TestMain(m *testing.M) {
54+
// Note that here we still use RunMain, which is the older deprecated API,
55+
// to sanity check that it works OK.
5456
os.Exit(testscript.RunMain(m, map[string] func() int{
5557
"foo": foo1,
5658
}))

testscript/doc.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,14 @@ To run a specific script foo.txtar or foo.txt, run
2424
where TestName is the name of the test that Run is called from.
2525
2626
To define an executable command (or several) that can be run as part of the script,
27-
call RunMain with the functions that implement the command's functionality.
27+
call Main with the functions that implement the command's functionality.
2828
The command functions will be called in a separate process, so are
2929
free to mutate global variables without polluting the top level test binary.
3030
3131
func TestMain(m *testing.M) {
32-
os.Exit(testscript.RunMain(m, map[string] func() int{
32+
testscript.Main(m, map[string] func() {
3333
"testscript": testscriptMain,
34-
}))
34+
})
3535
}
3636
3737
In general script files should have short names: a few words, not whole sentences.

0 commit comments

Comments
 (0)