Skip to content

Commit 6249032

Browse files
committed
dev: follow standard by using 'want' instead of 'ERROR'
1 parent 5e14049 commit 6249032

File tree

136 files changed

+1391
-901
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

136 files changed

+1391
-901
lines changed

test/analysis.go

+197
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
package test
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
"go/parser"
7+
"go/token"
8+
"os"
9+
"path/filepath"
10+
"regexp"
11+
"sort"
12+
"strconv"
13+
"strings"
14+
"testing"
15+
"text/scanner"
16+
17+
"github.com/stretchr/testify/require"
18+
19+
"github.com/golangci/golangci-lint/pkg/result"
20+
)
21+
22+
const keyword = "want"
23+
24+
type jsonResult struct {
25+
Issues []*result.Issue
26+
}
27+
28+
type expectation struct {
29+
kind string // either "fact" or "diagnostic"
30+
name string // name of object to which fact belongs, or "package" ("fact" only)
31+
rx *regexp.Regexp
32+
}
33+
34+
type key struct {
35+
file string
36+
line int
37+
}
38+
39+
// inspired by https://github.com/golang/tools/blob/b3b5c13b291f9653da6f31b95db100a2e26bd186/go/analysis/analysistest/analysistest.go
40+
func analyze(t *testing.T, sourcePath string, rawData []byte) {
41+
fileData, err := os.ReadFile(sourcePath)
42+
require.NoError(t, err)
43+
44+
want, err := parseComments(sourcePath, fileData)
45+
require.NoError(t, err)
46+
47+
var reportData jsonResult
48+
err = json.Unmarshal(rawData, &reportData)
49+
require.NoError(t, err)
50+
51+
for _, issue := range reportData.Issues {
52+
if !strings.HasPrefix(issue.Pos.Filename, testdataDir) {
53+
issue.Pos.Filename = filepath.Join(testdataDir, issue.Pos.Filename)
54+
}
55+
checkMessage(t, want, issue.Pos, "diagnostic", issue.FromLinter, issue.Text)
56+
}
57+
58+
var surplus []string
59+
for key, expects := range want {
60+
for _, exp := range expects {
61+
err := fmt.Sprintf("%s:%d: no %s was reported matching %#q", key.file, key.line, exp.kind, exp.rx)
62+
surplus = append(surplus, err)
63+
}
64+
}
65+
66+
sort.Strings(surplus)
67+
68+
for _, err := range surplus {
69+
t.Errorf("%s", err)
70+
}
71+
}
72+
73+
// inspired by https://github.com/golang/tools/blob/b3b5c13b291f9653da6f31b95db100a2e26bd186/go/analysis/analysistest/analysistest.go
74+
func parseComments(sourcePath string, fileData []byte) (map[key][]expectation, error) {
75+
fset := token.NewFileSet()
76+
77+
// the error is ignored to let 'typecheck' handle compilation error
78+
f, _ := parser.ParseFile(fset, sourcePath, fileData, parser.ParseComments)
79+
80+
want := make(map[key][]expectation)
81+
82+
for _, comment := range f.Comments {
83+
for _, c := range comment.List {
84+
text := strings.TrimPrefix(c.Text, "//")
85+
if text == c.Text { // not a //-comment.
86+
text = strings.TrimPrefix(text, "/*")
87+
text = strings.TrimSuffix(text, "*/")
88+
}
89+
90+
if i := strings.Index(text, "// "+keyword); i >= 0 {
91+
text = text[i+len("// "):]
92+
}
93+
94+
posn := fset.Position(c.Pos())
95+
96+
text = strings.TrimSpace(text)
97+
98+
if rest := strings.TrimPrefix(text, keyword); rest != text {
99+
delta, expects, err := parseExpectations(rest)
100+
if err != nil {
101+
return nil, err
102+
}
103+
104+
want[key{sourcePath, posn.Line + delta}] = expects
105+
}
106+
}
107+
}
108+
109+
return want, nil
110+
}
111+
112+
// inspired by https://github.com/golang/tools/blob/b3b5c13b291f9653da6f31b95db100a2e26bd186/go/analysis/analysistest/analysistest.go
113+
func parseExpectations(text string) (lineDelta int, expects []expectation, err error) {
114+
var scanErr string
115+
sc := new(scanner.Scanner).Init(strings.NewReader(text))
116+
sc.Error = func(s *scanner.Scanner, msg string) {
117+
scanErr = msg // e.g. bad string escape
118+
}
119+
sc.Mode = scanner.ScanIdents | scanner.ScanStrings | scanner.ScanRawStrings | scanner.ScanInts
120+
121+
scanRegexp := func(tok rune) (*regexp.Regexp, error) {
122+
if tok != scanner.String && tok != scanner.RawString {
123+
return nil, fmt.Errorf("got %s, want regular expression",
124+
scanner.TokenString(tok))
125+
}
126+
pattern, _ := strconv.Unquote(sc.TokenText()) // can't fail
127+
return regexp.Compile(pattern)
128+
}
129+
130+
for {
131+
tok := sc.Scan()
132+
switch tok {
133+
case '+':
134+
tok = sc.Scan()
135+
if tok != scanner.Int {
136+
return 0, nil, fmt.Errorf("got +%s, want +Int", scanner.TokenString(tok))
137+
}
138+
lineDelta, _ = strconv.Atoi(sc.TokenText())
139+
case scanner.String, scanner.RawString:
140+
rx, err := scanRegexp(tok)
141+
if err != nil {
142+
return 0, nil, err
143+
}
144+
expects = append(expects, expectation{"diagnostic", "", rx})
145+
146+
case scanner.Ident:
147+
name := sc.TokenText()
148+
tok = sc.Scan()
149+
if tok != ':' {
150+
return 0, nil, fmt.Errorf("got %s after %s, want ':'",
151+
scanner.TokenString(tok), name)
152+
}
153+
tok = sc.Scan()
154+
rx, err := scanRegexp(tok)
155+
if err != nil {
156+
return 0, nil, err
157+
}
158+
expects = append(expects, expectation{"diagnostic", name, rx})
159+
160+
case scanner.EOF:
161+
if scanErr != "" {
162+
return 0, nil, fmt.Errorf("%s", scanErr)
163+
}
164+
return lineDelta, expects, nil
165+
166+
default:
167+
return 0, nil, fmt.Errorf("unexpected %s", scanner.TokenString(tok))
168+
}
169+
}
170+
}
171+
172+
// inspired by https://github.com/golang/tools/blob/b3b5c13b291f9653da6f31b95db100a2e26bd186/go/analysis/analysistest/analysistest.go
173+
func checkMessage(t *testing.T, want map[key][]expectation, posn token.Position, kind, name, message string) {
174+
k := key{posn.Filename, posn.Line}
175+
expects := want[k]
176+
var unmatched []string
177+
178+
for i, exp := range expects {
179+
if exp.kind == kind && (exp.name == "" || exp.name == name) {
180+
if exp.rx.MatchString(message) {
181+
// matched: remove the expectation.
182+
expects[i] = expects[len(expects)-1]
183+
expects = expects[:len(expects)-1]
184+
want[k] = expects
185+
return
186+
}
187+
unmatched = append(unmatched, fmt.Sprintf("%#q", exp.rx))
188+
}
189+
}
190+
191+
if unmatched == nil {
192+
t.Errorf("%v: unexpected %s: %v", posn, kind, message)
193+
} else {
194+
t.Errorf("%v: %s %q does not match pattern %s",
195+
posn, kind, message, strings.Join(unmatched, " or "))
196+
}
197+
}

test/analysis_test.go

+138
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
package test
2+
3+
import (
4+
"regexp"
5+
"testing"
6+
7+
"github.com/stretchr/testify/assert"
8+
"github.com/stretchr/testify/require"
9+
)
10+
11+
//nolint:funlen
12+
func Test_parseComments(t *testing.T) {
13+
testCases := []struct {
14+
filename string
15+
data string
16+
expected map[key][]expectation
17+
}{
18+
{
19+
filename: "a/b.go",
20+
data: `package main // want package:"found"
21+
22+
`,
23+
expected: map[key][]expectation{
24+
{file: "a/b.go", line: 1}: {
25+
{kind: "diagnostic", name: "package", rx: regexp.MustCompile(`found`)},
26+
},
27+
},
28+
},
29+
{
30+
filename: "a/c.go",
31+
data: `package main
32+
33+
func main() {
34+
println("hello, world") // want "call of println"
35+
}
36+
`,
37+
expected: map[key][]expectation{
38+
{file: "a/c.go", line: 4}: {
39+
{kind: "diagnostic", name: "", rx: regexp.MustCompile(`call of println`)},
40+
},
41+
},
42+
},
43+
{
44+
filename: "a/d.go",
45+
data: `package main
46+
47+
func main() {
48+
// OK /* */-form.
49+
println("hello") /* want "call of println" */
50+
}
51+
`,
52+
expected: map[key][]expectation{
53+
{file: "a/d.go", line: 5}: {
54+
{kind: "diagnostic", name: "", rx: regexp.MustCompile(`call of println`)},
55+
},
56+
},
57+
},
58+
{
59+
filename: "a/e.go",
60+
data: `package main
61+
62+
func main() {
63+
// OK (nested comment)
64+
println("hello") // some comment // want "call of println"
65+
}
66+
`,
67+
expected: map[key][]expectation{
68+
{file: "a/e.go", line: 5}: {
69+
{kind: "diagnostic", name: "", rx: regexp.MustCompile(`call of println`)},
70+
},
71+
},
72+
},
73+
{
74+
filename: "a/f.go",
75+
data: `package main
76+
77+
func main() {
78+
// OK (nested comment in /**/)
79+
println("hello") /* some comment // want "call of println" */
80+
}
81+
`,
82+
expected: map[key][]expectation{
83+
{file: "a/f.go", line: 5}: {
84+
{kind: "diagnostic", name: "", rx: regexp.MustCompile(`call of println`)},
85+
},
86+
},
87+
},
88+
{
89+
filename: "a/g.go",
90+
data: `package main
91+
92+
func main() {
93+
// OK (multiple expectations on same line)
94+
println(); println() // want "call of println(...)" "call of println(...)"
95+
}
96+
`,
97+
expected: map[key][]expectation{
98+
{file: "a/g.go", line: 5}: {
99+
{kind: "diagnostic", name: "", rx: regexp.MustCompile(`call of println(...)`)},
100+
{kind: "diagnostic", name: "", rx: regexp.MustCompile(`call of println(...)`)},
101+
},
102+
},
103+
},
104+
{
105+
filename: "a/h.go",
106+
data: `package main
107+
108+
func println(...interface{}) { println() } // want println:"found" "call of println(...)"
109+
`,
110+
expected: map[key][]expectation{
111+
{file: "a/h.go", line: 3}: {
112+
{kind: "diagnostic", name: "println", rx: regexp.MustCompile(`found`)},
113+
{kind: "diagnostic", name: "", rx: regexp.MustCompile(`call of println(...)`)},
114+
},
115+
},
116+
},
117+
{
118+
filename: "a/b_test.go",
119+
data: `package main
120+
121+
// Test file shouldn't mess with things
122+
`,
123+
expected: map[key][]expectation{},
124+
},
125+
}
126+
127+
for _, test := range testCases {
128+
test := test
129+
t.Run(test.filename, func(t *testing.T) {
130+
t.Parallel()
131+
132+
expectations, err := parseComments(test.filename, []byte(test.data))
133+
require.NoError(t, err)
134+
135+
assert.Equal(t, test.expected, expectations)
136+
})
137+
}
138+
}

0 commit comments

Comments
 (0)