1
2
3
4
5
6
7
8
9
10 package main
11
12 import (
13 "bytes"
14 "flag"
15 "fmt"
16 "io"
17 "os"
18 "path"
19 "path/filepath"
20 "strings"
21 "sync"
22 "testing"
23
24 "golang.org/x/tools/internal/testenv"
25 )
26
27
28
29
30
31
32 func TestMain(m *testing.M) {
33 if os.Getenv("STRINGER_TEST_IS_STRINGER") != "" {
34 main()
35 os.Exit(0)
36 }
37
38
39
40
41 os.Setenv("STRINGER_TEST_IS_STRINGER", "1")
42
43 flag.Parse()
44 if testing.Verbose() {
45 os.Setenv("GOPACKAGESDEBUG", "true")
46 }
47
48 os.Exit(m.Run())
49 }
50
51 func TestEndToEnd(t *testing.T) {
52 testenv.NeedsTool(t, "go")
53
54 stringer := stringerPath(t)
55
56 fd, err := os.Open("testdata")
57 if err != nil {
58 t.Fatal(err)
59 }
60 defer fd.Close()
61 names, err := fd.Readdirnames(-1)
62 if err != nil {
63 t.Fatalf("Readdirnames: %s", err)
64 }
65
66 for _, name := range names {
67 if name == "typeparams" {
68
69 continue
70 }
71 if !strings.HasSuffix(name, ".go") {
72 t.Errorf("%s is not a Go file", name)
73 continue
74 }
75 if strings.HasPrefix(name, "tag_") || strings.HasPrefix(name, "vary_") {
76
77 continue
78 }
79 t.Run(name, func(t *testing.T) {
80 if name == "cgo.go" {
81 testenv.NeedsTool(t, "cgo")
82 }
83 stringerCompileAndRun(t, t.TempDir(), stringer, typeName(name), name)
84 })
85 }
86 }
87
88
89 func typeName(fname string) string {
90
91 base := path.Base(fname)
92 return fmt.Sprintf("%c%s", base[0]+'A'-'a', base[1:len(base)-len(".go")])
93 }
94
95 func moreTests(t *testing.T, dirname, prefix string) []string {
96 x, err := os.ReadDir(dirname)
97 if err != nil {
98
99 t.Errorf("can't read type param tess from %s: %v", dirname, err)
100 return nil
101 }
102 names := make([]string, len(x))
103 for i, f := range x {
104 names[i] = prefix + "/" + f.Name()
105 }
106 return names
107 }
108
109
110 func TestTags(t *testing.T) {
111 stringer := stringerPath(t)
112 dir := t.TempDir()
113 var (
114 protectedConst = []byte("TagProtected")
115 output = filepath.Join(dir, "const_string.go")
116 )
117 for _, file := range []string{"tag_main.go", "tag_tag.go"} {
118 err := copy(filepath.Join(dir, file), filepath.Join("testdata", file))
119 if err != nil {
120 t.Fatal(err)
121 }
122 }
123
124
125
126
127
128 err := runInDir(t, dir, stringer, "-type", "Const", ".")
129 if err != nil {
130 t.Fatal(err)
131 }
132 result, err := os.ReadFile(output)
133 if err != nil {
134 t.Fatal(err)
135 }
136 if bytes.Contains(result, protectedConst) {
137 t.Fatal("tagged variable appears in untagged run")
138 }
139 err = os.Remove(output)
140 if err != nil {
141 t.Fatal(err)
142 }
143 err = runInDir(t, dir, stringer, "-type", "Const", "-tags", "tag", ".")
144 if err != nil {
145 t.Fatal(err)
146 }
147 result, err = os.ReadFile(output)
148 if err != nil {
149 t.Fatal(err)
150 }
151 if !bytes.Contains(result, protectedConst) {
152 t.Fatal("tagged variable does not appear in tagged run")
153 }
154 }
155
156
157
158 func TestConstValueChange(t *testing.T) {
159 testenv.NeedsTool(t, "go")
160
161 stringer := stringerPath(t)
162 dir := t.TempDir()
163 source := filepath.Join(dir, "day.go")
164 err := copy(source, filepath.Join("testdata", "day.go"))
165 if err != nil {
166 t.Fatal(err)
167 }
168 stringSource := filepath.Join(dir, "day_string.go")
169
170 err = runInDir(t, dir, stringer, "-type", "Day", "-output", stringSource)
171 if err != nil {
172 t.Fatal(err)
173 }
174
175 err = run(t, "go", "run", stringSource, source)
176 if err != nil {
177 t.Fatal(err)
178 }
179
180 err = copy(source, filepath.Join("testdata", "vary_day.go"))
181 if err != nil {
182 t.Fatal(err)
183 }
184
185
186
187
188
189
190
191
192
193 t.Logf("Note: the following messages should indicate an out-of-bounds compiler error\n")
194 err = run(t, "go", "build", stringSource, source)
195 if err == nil {
196 t.Fatal("unexpected compiler success")
197 }
198 }
199
200 var exe struct {
201 path string
202 err error
203 once sync.Once
204 }
205
206 func stringerPath(t *testing.T) string {
207 testenv.NeedsExec(t)
208
209 exe.once.Do(func() {
210 exe.path, exe.err = os.Executable()
211 })
212 if exe.err != nil {
213 t.Fatal(exe.err)
214 }
215 return exe.path
216 }
217
218
219
220 func stringerCompileAndRun(t *testing.T, dir, stringer, typeName, fileName string) {
221 t.Logf("run: %s %s\n", fileName, typeName)
222 source := filepath.Join(dir, path.Base(fileName))
223 err := copy(source, filepath.Join("testdata", fileName))
224 if err != nil {
225 t.Fatalf("copying file to temporary directory: %s", err)
226 }
227 stringSource := filepath.Join(dir, typeName+"_string.go")
228
229 err = run(t, stringer, "-type", typeName, "-output", stringSource, source)
230 if err != nil {
231 t.Fatal(err)
232 }
233
234 err = run(t, "go", "run", stringSource, source)
235 if err != nil {
236 t.Fatal(err)
237 }
238 }
239
240
241 func copy(to, from string) error {
242 toFd, err := os.Create(to)
243 if err != nil {
244 return err
245 }
246 defer toFd.Close()
247 fromFd, err := os.Open(from)
248 if err != nil {
249 return err
250 }
251 defer fromFd.Close()
252 _, err = io.Copy(toFd, fromFd)
253 return err
254 }
255
256
257
258 func run(t testing.TB, name string, arg ...string) error {
259 t.Helper()
260 return runInDir(t, ".", name, arg...)
261 }
262
263
264
265 func runInDir(t testing.TB, dir, name string, arg ...string) error {
266 t.Helper()
267 cmd := testenv.Command(t, name, arg...)
268 cmd.Dir = dir
269 cmd.Env = append(os.Environ(), "GO111MODULE=auto")
270 out, err := cmd.CombinedOutput()
271 if len(out) > 0 {
272 t.Logf("%s", out)
273 }
274 if err != nil {
275 return fmt.Errorf("%v: %v", cmd, err)
276 }
277 return nil
278 }
279
View as plain text