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, errors, file)
64 })
65 }
66
67 func expect(t *testing.T, errors []*regexp.Regexp, files ...string) {
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(files[0], ".go"))
75 args := []string{"build", "-gcflags=-L -e", "-o=" + dst}
76 for _, file := range files {
77 args = append(args, path(file))
78 }
79 cmd := exec.Command("go", args...)
80 out, err := cmd.CombinedOutput()
81 if err == nil {
82 t.Errorf("expected cgo to fail but it succeeded")
83 }
84
85 lines := bytes.Split(out, []byte("\n"))
86 for _, re := range errors {
87 found := false
88 for _, line := range lines {
89 if re.Match(line) {
90 t.Logf("found match for %#q: %q", re, line)
91 found = true
92 break
93 }
94 }
95 if !found {
96 t.Errorf("expected error output to contain %#q", re)
97 }
98 }
99
100 if t.Failed() {
101 t.Logf("actual output:\n%s", out)
102 }
103 }
104
105 func sizeofLongDouble(t *testing.T) int {
106 testenv.MustHaveGoRun(t)
107 testenv.MustHaveCGO(t)
108 cmd := exec.Command("go", "run", path("long_double_size.go"))
109 out, err := cmd.CombinedOutput()
110 if err != nil {
111 t.Fatalf("%#q: %v:\n%s", strings.Join(cmd.Args, " "), err, out)
112 }
113
114 i, err := strconv.Atoi(strings.TrimSpace(string(out)))
115 if err != nil {
116 t.Fatalf("long_double_size.go printed invalid size: %s", out)
117 }
118 return i
119 }
120
121 func TestReportsTypeErrors(t *testing.T) {
122 for _, file := range []string{
123 "err1.go",
124 "err2.go",
125 "err5.go",
126 "issue11097a.go",
127 "issue11097b.go",
128 "issue18452.go",
129 "issue18889.go",
130 "issue28721.go",
131 "issue33061.go",
132 "issue50710.go",
133 "issue67517.go",
134 "issue67707.go",
135 "issue69176.go",
136 } {
137 check(t, file)
138 }
139
140 if sizeofLongDouble(t) > 8 {
141 for _, file := range []string{
142 "err4.go",
143 "issue28069.go",
144 } {
145 check(t, file)
146 }
147 }
148 }
149
150 func TestToleratesOptimizationFlag(t *testing.T) {
151 for _, cflags := range []string{
152 "",
153 "-O",
154 } {
155 cflags := cflags
156 t.Run(cflags, func(t *testing.T) {
157 testenv.MustHaveGoBuild(t)
158 testenv.MustHaveCGO(t)
159 t.Parallel()
160
161 cmd := exec.Command("go", "build", path("issue14669.go"))
162 cmd.Env = append(os.Environ(), "CGO_CFLAGS="+cflags)
163 out, err := cmd.CombinedOutput()
164 if err != nil {
165 t.Errorf("%#q: %v:\n%s", strings.Join(cmd.Args, " "), err, out)
166 }
167 })
168 }
169 }
170
171 func TestMallocCrashesOnNil(t *testing.T) {
172 testenv.MustHaveCGO(t)
173 testenv.MustHaveGoRun(t)
174 t.Parallel()
175
176 cmd := exec.Command("go", "run", path("malloc.go"))
177 out, err := cmd.CombinedOutput()
178 if err == nil {
179 t.Logf("%#q:\n%s", strings.Join(cmd.Args, " "), out)
180 t.Fatalf("succeeded unexpectedly")
181 }
182 }
183
184 func TestNotMatchedCFunction(t *testing.T) {
185 file := "notmatchedcfunction.go"
186 check(t, file)
187 }
188
189 func TestIncompatibleDeclarations(t *testing.T) {
190 testenv.MustHaveCGO(t)
191 testenv.MustHaveGoRun(t)
192 t.Parallel()
193 expect(t, []*regexp.Regexp{
194 regexp.MustCompile("inconsistent definitions for C[.]f"),
195 regexp.MustCompile("inconsistent definitions for C[.]g"),
196 }, "issue67699a.go", "issue67699b.go")
197 }
198
View as plain text