1
2
3
4
5 package errorstest
6
7 import (
8 "bytes"
9 "fmt"
10 "internal/testenv"
11 "os"
12 "os/exec"
13 "path/filepath"
14 "regexp"
15 "strconv"
16 "strings"
17 "testing"
18 )
19
20 func path(file string) string {
21 return filepath.Join("testdata", file)
22 }
23
24 func check(t *testing.T, file string) {
25 t.Run(file, func(t *testing.T) {
26 testenv.MustHaveGoBuild(t)
27 testenv.MustHaveCGO(t)
28 t.Parallel()
29
30 contents, err := os.ReadFile(path(file))
31 if err != nil {
32 t.Fatal(err)
33 }
34 var errors []*regexp.Regexp
35 for i, line := range bytes.Split(contents, []byte("\n")) {
36 if bytes.HasSuffix(line, []byte("ERROR HERE")) {
37 re := regexp.MustCompile(regexp.QuoteMeta(fmt.Sprintf("%s:%d:", file, i+1)))
38 errors = append(errors, re)
39 continue
40 }
41
42 if _, frag, ok := bytes.Cut(line, []byte("ERROR HERE: ")); ok {
43 re, err := regexp.Compile(fmt.Sprintf(":%d:.*%s", i+1, frag))
44 if err != nil {
45 t.Errorf("Invalid regexp after `ERROR HERE: `: %#q", frag)
46 continue
47 }
48 errors = append(errors, re)
49 }
50
51 if _, frag, ok := bytes.Cut(line, []byte("ERROR MESSAGE: ")); ok {
52 re, err := regexp.Compile(string(frag))
53 if err != nil {
54 t.Errorf("Invalid regexp after `ERROR MESSAGE: `: %#q", frag)
55 continue
56 }
57 errors = append(errors, re)
58 }
59 }
60 if len(errors) == 0 {
61 t.Fatalf("cannot find ERROR HERE")
62 }
63 expect(t, file, errors)
64 })
65 }
66
67 func expect(t *testing.T, file string, errors []*regexp.Regexp) {
68 dir, err := os.MkdirTemp("", filepath.Base(t.Name()))
69 if err != nil {
70 t.Fatal(err)
71 }
72 defer os.RemoveAll(dir)
73
74 dst := filepath.Join(dir, strings.TrimSuffix(file, ".go"))
75 cmd := exec.Command("go", "build", "-gcflags=-L -e", "-o="+dst, path(file))
76 out, err := cmd.CombinedOutput()
77 if err == nil {
78 t.Errorf("expected cgo to fail but it succeeded")
79 }
80
81 lines := bytes.Split(out, []byte("\n"))
82 for _, re := range errors {
83 found := false
84 for _, line := range lines {
85 if re.Match(line) {
86 t.Logf("found match for %#q: %q", re, line)
87 found = true
88 break
89 }
90 }
91 if !found {
92 t.Errorf("expected error output to contain %#q", re)
93 }
94 }
95
96 if t.Failed() {
97 t.Logf("actual output:\n%s", out)
98 }
99 }
100
101 func sizeofLongDouble(t *testing.T) int {
102 testenv.MustHaveGoRun(t)
103 testenv.MustHaveCGO(t)
104 cmd := exec.Command("go", "run", path("long_double_size.go"))
105 out, err := cmd.CombinedOutput()
106 if err != nil {
107 t.Fatalf("%#q: %v:\n%s", strings.Join(cmd.Args, " "), err, out)
108 }
109
110 i, err := strconv.Atoi(strings.TrimSpace(string(out)))
111 if err != nil {
112 t.Fatalf("long_double_size.go printed invalid size: %s", out)
113 }
114 return i
115 }
116
117 func TestReportsTypeErrors(t *testing.T) {
118 for _, file := range []string{
119 "err1.go",
120 "err2.go",
121 "err5.go",
122 "issue11097a.go",
123 "issue11097b.go",
124 "issue18452.go",
125 "issue18889.go",
126 "issue28721.go",
127 "issue33061.go",
128 "issue50710.go",
129 "issue67517.go",
130 "issue67707.go",
131 } {
132 check(t, file)
133 }
134
135 if sizeofLongDouble(t) > 8 {
136 for _, file := range []string{
137 "err4.go",
138 "issue28069.go",
139 } {
140 check(t, file)
141 }
142 }
143 }
144
145 func TestToleratesOptimizationFlag(t *testing.T) {
146 for _, cflags := range []string{
147 "",
148 "-O",
149 } {
150 cflags := cflags
151 t.Run(cflags, func(t *testing.T) {
152 testenv.MustHaveGoBuild(t)
153 testenv.MustHaveCGO(t)
154 t.Parallel()
155
156 cmd := exec.Command("go", "build", path("issue14669.go"))
157 cmd.Env = append(os.Environ(), "CGO_CFLAGS="+cflags)
158 out, err := cmd.CombinedOutput()
159 if err != nil {
160 t.Errorf("%#q: %v:\n%s", strings.Join(cmd.Args, " "), err, out)
161 }
162 })
163 }
164 }
165
166 func TestMallocCrashesOnNil(t *testing.T) {
167 testenv.MustHaveCGO(t)
168 testenv.MustHaveGoRun(t)
169 t.Parallel()
170
171 cmd := exec.Command("go", "run", path("malloc.go"))
172 out, err := cmd.CombinedOutput()
173 if err == nil {
174 t.Logf("%#q:\n%s", strings.Join(cmd.Args, " "), out)
175 t.Fatalf("succeeded unexpectedly")
176 }
177 }
178
179 func TestNotMatchedCFunction(t *testing.T) {
180 file := "notmatchedcfunction.go"
181 check(t, file)
182 }
183
View as plain text