1
2
3
4
5 package scripttest
6
7 import (
8 "bytes"
9 "cmd/internal/script"
10 "internal/diff"
11 "internal/testenv"
12 "os"
13 "path/filepath"
14 "strings"
15 "testing"
16 "text/template"
17 )
18
19 func checkScriptReadme(t *testing.T, engine *script.Engine, env []string, scriptspath, gotool string, fixReadme bool) {
20 var args struct {
21 Language string
22 Commands string
23 Conditions string
24 }
25
26 cmds := new(strings.Builder)
27 if err := engine.ListCmds(cmds, true); err != nil {
28 t.Fatal(err)
29 }
30 args.Commands = cmds.String()
31
32 conds := new(strings.Builder)
33 if err := engine.ListConds(conds, nil); err != nil {
34 t.Fatal(err)
35 }
36 args.Conditions = conds.String()
37
38 doc := new(strings.Builder)
39 cmd := testenv.Command(t, gotool, "doc", "cmd/internal/script")
40 cmd.Dir = t.TempDir()
41 cmd.Env = env
42 cmd.Stdout = doc
43 if err := cmd.Run(); err != nil {
44 t.Fatal(cmd, ":", err)
45 }
46 _, lang, ok := strings.Cut(doc.String(), "# Script Language\n\n")
47 if !ok {
48 t.Fatalf("%q did not include Script Language section", cmd)
49 }
50 lang, _, ok = strings.Cut(lang, "\n\nvar ")
51 if !ok {
52 t.Fatalf("%q did not include vars after Script Language section", cmd)
53 }
54 args.Language = lang
55
56 tmpl := template.Must(template.New("README").Parse(readmeTmpl[1:]))
57 buf := new(bytes.Buffer)
58 if err := tmpl.Execute(buf, args); err != nil {
59 t.Fatal(err)
60 }
61
62 readmePath := filepath.Join(scriptspath, "README")
63 old, err := os.ReadFile(readmePath)
64 if err != nil {
65 t.Fatal(err)
66 }
67 diff := diff.Diff(readmePath, old, "readmeTmpl", buf.Bytes())
68 if diff == nil {
69 t.Logf("%s is up to date.", readmePath)
70 return
71 }
72
73 if fixReadme {
74 if err := os.WriteFile(readmePath, buf.Bytes(), 0666); err != nil {
75 t.Fatal(err)
76 }
77 t.Logf("wrote %d bytes to %s", buf.Len(), readmePath)
78 } else {
79 t.Logf("\n%s", diff)
80 t.Errorf("%s is stale. To update, run 'go generate cmd/go'.", readmePath)
81 }
82 }
83
84 const readmeTmpl = `
85 This file is generated by 'go generate'. DO NOT EDIT.
86
87 This directory holds test scripts *.txt run during 'go test cmd/<toolname>'.
88 To run a specific script foo.txt
89
90 go test cmd/<toolname> -run=Script/^foo$
91
92 In general script files should have short names: a few words,
93 not whole sentences.
94 The first word should be the general category of behavior being tested,
95 often the name of a go subcommand (build, link, compile, ...) or concept (vendor, pattern).
96
97 Each script is a text archive (go doc internal/txtar).
98 The script begins with an actual command script to run
99 followed by the content of zero or more supporting files to
100 create in the script's temporary file system before it starts executing.
101
102 As an example, run_hello.txt says:
103
104 # hello world
105 go run hello.go
106 stderr 'hello world'
107 ! stdout .
108
109 -- hello.go --
110 package main
111 func main() { println("hello world") }
112
113 Each script runs in a fresh temporary work directory tree, available to scripts as $WORK.
114 Scripts also have access to other environment variables, including:
115
116 GOARCH=<target GOARCH>
117 GOOS=<target GOOS>
118 TMPDIR=$WORK/tmp
119 devnull=<value of os.DevNull>
120 goversion=<current Go version; for example, 1.12>
121
122 On Plan 9, the variables $path and $home are set instead of $PATH and $HOME.
123 On Windows, the variables $USERPROFILE and $TMP are set instead of
124 $HOME and $TMPDIR.
125
126 The lines at the top of the script are a sequence of commands to be executed by
127 a small script engine configured in .../cmd/internal/script/scripttest/run.go (not the system shell).
128
129 {{.Language}}
130
131 When TestScript runs a script and the script fails, by default TestScript shows
132 the execution of the most recent phase of the script (since the last # comment)
133 and only shows the # comments for earlier phases.
134
135 Note also that in reported output, the actual name of the per-script temporary directory
136 has been consistently replaced with the literal string $WORK.
137
138 The available commands are:
139 {{.Commands}}
140
141 The available conditions are:
142 {{.Conditions}}
143 `
144
View as plain text