-
Notifications
You must be signed in to change notification settings - Fork 501
Expand file tree
/
Copy pathspec_test.go
More file actions
209 lines (193 loc) · 10.3 KB
/
Copy pathspec_test.go
File metadata and controls
209 lines (193 loc) · 10.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
//go:build !integration
package linters_test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"golang.org/x/tools/go/analysis"
"github.com/github/gh-aw/pkg/linters"
"github.com/github/gh-aw/pkg/linters/appendbytestring"
"github.com/github/gh-aw/pkg/linters/contextcancelnotdeferred"
"github.com/github/gh-aw/pkg/linters/ctxbackground"
"github.com/github/gh-aw/pkg/linters/deferinloop"
"github.com/github/gh-aw/pkg/linters/errorfwrapv"
"github.com/github/gh-aw/pkg/linters/errormessage"
"github.com/github/gh-aw/pkg/linters/errortypeassertion"
"github.com/github/gh-aw/pkg/linters/errstringmatch"
"github.com/github/gh-aw/pkg/linters/excessivefuncparams"
"github.com/github/gh-aw/pkg/linters/execcommandwithoutcontext"
"github.com/github/gh-aw/pkg/linters/fileclosenotdeferred"
"github.com/github/gh-aw/pkg/linters/fmterrorfnoverbs"
"github.com/github/gh-aw/pkg/linters/fprintlnsprintf"
"github.com/github/gh-aw/pkg/linters/hardcodedfilepath"
"github.com/github/gh-aw/pkg/linters/httpnoctx"
"github.com/github/gh-aw/pkg/linters/jsonmarshalignoredeerror"
"github.com/github/gh-aw/pkg/linters/largefunc"
"github.com/github/gh-aw/pkg/linters/lenstringsplit"
"github.com/github/gh-aw/pkg/linters/lenstringzero"
"github.com/github/gh-aw/pkg/linters/manualmutexunlock"
"github.com/github/gh-aw/pkg/linters/osexitinlibrary"
"github.com/github/gh-aw/pkg/linters/ossetenvlibrary"
panicinlibrarycode "github.com/github/gh-aw/pkg/linters/panic-in-library-code"
"github.com/github/gh-aw/pkg/linters/rawloginlib"
"github.com/github/gh-aw/pkg/linters/regexpcompileinfunction"
"github.com/github/gh-aw/pkg/linters/seenmapbool"
"github.com/github/gh-aw/pkg/linters/sortslice"
"github.com/github/gh-aw/pkg/linters/sprintferrdot"
"github.com/github/gh-aw/pkg/linters/sprintferrorsnew"
"github.com/github/gh-aw/pkg/linters/ssljson"
"github.com/github/gh-aw/pkg/linters/strconvparseignorederror"
"github.com/github/gh-aw/pkg/linters/stringreplaceminusone"
"github.com/github/gh-aw/pkg/linters/stringscountcontains"
"github.com/github/gh-aw/pkg/linters/stringsindexcontains"
"github.com/github/gh-aw/pkg/linters/timeafterleak"
"github.com/github/gh-aw/pkg/linters/timesleepnocontext"
"github.com/github/gh-aw/pkg/linters/tolowerequalfold"
"github.com/github/gh-aw/pkg/linters/uncheckedtypeassertion"
"github.com/github/gh-aw/pkg/linters/wgdonenotdeferred"
"github.com/github/gh-aw/pkg/linters/writebytestring"
)
// TestSpec tests derive from pkg/linters/README.md. They enforce the documented
// public surface of the linters namespace (the Analyzer entry point exposed by
// each documented subpackage and the documented default thresholds) without
// coupling to analyzer internals.
// docAnalyzer pairs a README "Subpackages" table label with the Analyzer value
// that subpackage is documented to expose.
type docAnalyzer struct {
label string
analyzer *analysis.Analyzer
}
// documentedAnalyzers returns the analyzer subpackages documented in the README
// "Public API > Subpackages" table. The README documents 40 analyzers
// subpackages (the non-analyzer `internal` helper subpackage is excluded because
// it exposes no Analyzer).
//
// Spec (README "Public API > Subpackages"):
//
// appendbytestring, contextcancelnotdeferred, ctxbackground, deferinloop, errorfwrapv, excessivefuncparams, errormessage,
// errortypeassertion, errstringmatch, execcommandwithoutcontext, fileclosenotdeferred, fmterrorfnoverbs, fprintlnsprintf,
// hardcodedfilepath, httpnoctx, jsonmarshalignoredeerror, largefunc, lenstringsplit, lenstringzero,
// manualmutexunlock, osexitinlibrary, ossetenvlibrary, panic-in-library-code, rawloginlib,
// regexpcompileinfunction, seenmapbool, sortslice, sprintferrdot, sprintferrorsnew, ssljson,
// strconvparseignorederror, stringreplaceminusone, stringscountcontains, stringsindexcontains, timeafterleak, timesleepnocontext,
// tolowerequalfold, uncheckedtypeassertion, wgdonenotdeferred, writebytestring
func documentedAnalyzers() []docAnalyzer {
return []docAnalyzer{
{"appendbytestring", appendbytestring.Analyzer},
{"contextcancelnotdeferred", contextcancelnotdeferred.Analyzer},
{"ctxbackground", ctxbackground.Analyzer},
{"deferinloop", deferinloop.Analyzer},
{"errorfwrapv", errorfwrapv.Analyzer},
{"excessivefuncparams", excessivefuncparams.Analyzer},
{"errormessage", errormessage.Analyzer},
{"errortypeassertion", errortypeassertion.Analyzer},
{"errstringmatch", errstringmatch.Analyzer},
{"execcommandwithoutcontext", execcommandwithoutcontext.Analyzer},
{"fileclosenotdeferred", fileclosenotdeferred.Analyzer},
{"fmterrorfnoverbs", fmterrorfnoverbs.Analyzer},
{"fprintlnsprintf", fprintlnsprintf.Analyzer},
{"hardcodedfilepath", hardcodedfilepath.Analyzer},
{"httpnoctx", httpnoctx.Analyzer},
{"jsonmarshalignoredeerror", jsonmarshalignoredeerror.Analyzer},
{"largefunc", largefunc.Analyzer},
{"lenstringsplit", lenstringsplit.Analyzer},
{"lenstringzero", lenstringzero.Analyzer},
{"manualmutexunlock", manualmutexunlock.Analyzer},
{"osexitinlibrary", osexitinlibrary.Analyzer},
{"ossetenvlibrary", ossetenvlibrary.Analyzer},
{"panic-in-library-code", panicinlibrarycode.Analyzer},
{"rawloginlib", rawloginlib.Analyzer},
{"regexpcompileinfunction", regexpcompileinfunction.Analyzer},
{"seenmapbool", seenmapbool.Analyzer},
{"sortslice", sortslice.Analyzer},
{"sprintferrdot", sprintferrdot.Analyzer},
{"sprintferrorsnew", sprintferrorsnew.Analyzer},
{"ssljson", ssljson.Analyzer},
{"strconvparseignorederror", strconvparseignorederror.Analyzer},
{"stringreplaceminusone", stringreplaceminusone.Analyzer},
{"stringscountcontains", stringscountcontains.Analyzer},
{"stringsindexcontains", stringsindexcontains.Analyzer},
{"timeafterleak", timeafterleak.Analyzer},
{"timesleepnocontext", timesleepnocontext.Analyzer},
{"tolowerequalfold", tolowerequalfold.Analyzer},
{"uncheckedtypeassertion", uncheckedtypeassertion.Analyzer},
{"wgdonenotdeferred", wgdonenotdeferred.Analyzer},
{"writebytestring", writebytestring.Analyzer},
}
}
// TestSpec_PublicAPI_SubpackageAnalyzers validates that every analyzer
// subpackage documented in the README "Subpackages" table exposes a non-nil
// `Analyzer` entry point of type *analysis.Analyzer with its Name and Run wired,
// so each can be consumed by a go/analysis driver (multichecker/singlechecker).
func TestSpec_PublicAPI_SubpackageAnalyzers(t *testing.T) {
for _, d := range documentedAnalyzers() {
t.Run(d.label, func(t *testing.T) {
require.NotNil(t, d.analyzer, "%s must expose a non-nil *analysis.Analyzer per the README Subpackages table", d.label)
assert.IsType(t, (*analysis.Analyzer)(nil), d.analyzer, "%s.Analyzer should be *analysis.Analyzer for go/analysis drivers", d.label)
assert.NotEmpty(t, d.analyzer.Name, "%s.Analyzer.Name should be set so go/analysis drivers can identify it", d.label)
assert.NotNil(t, d.analyzer.Run, "%s.Analyzer.Run must be wired so the analyzer is executable", d.label)
})
}
}
// TestSpec_NamespaceExports_ErrorMessageAnalyzer validates the documented
// namespace-level compatibility alias `ErrorMessageAnalyzer` referenced in the
// README "Namespace exports" table.
// Spec: "ErrorMessageAnalyzer | Compatibility alias to pkg/linters/errormessage.Analyzer"
func TestSpec_NamespaceExports_ErrorMessageAnalyzer(t *testing.T) {
require.NotNil(t, linters.ErrorMessageAnalyzer,
"linters.ErrorMessageAnalyzer must be a non-nil compatibility alias per the README")
assert.Same(t, errormessage.Analyzer, linters.ErrorMessageAnalyzer,
"linters.ErrorMessageAnalyzer should be the same *analysis.Analyzer as errormessage.Analyzer")
}
// TestSpec_Constants_DefaultMaxParams validates the documented default
// "8 parameters" threshold for the excessivefuncparams analyzer.
// Spec: "excessivefuncparams ... defaults to 8 parameters (DefaultMaxParams)."
func TestSpec_Constants_DefaultMaxParams(t *testing.T) {
assert.Equal(t, 8, excessivefuncparams.DefaultMaxParams,
"DefaultMaxParams should match the documented default of 8")
}
// TestSpec_Constants_DefaultMaxLines validates the documented default
// "60 lines" threshold for the largefunc analyzer.
// Spec: "largefunc ... defaults to 60 lines (DefaultMaxLines)."
func TestSpec_Constants_DefaultMaxLines(t *testing.T) {
assert.Equal(t, 60, largefunc.DefaultMaxLines,
"DefaultMaxLines should match the documented default of 60")
}
// TestSpec_DesignDecision_MaxParamsFlag validates the documented "-max-params"
// analyzer flag for excessivefuncparams.
// Spec: "excessivefuncparams exposes a -max-params analyzer flag"
func TestSpec_DesignDecision_MaxParamsFlag(t *testing.T) {
flag := excessivefuncparams.Analyzer.Flags.Lookup("max-params")
require.NotNil(t, flag, "excessivefuncparams should expose a -max-params flag per the spec")
}
// TestSpec_DesignDecision_MaxLinesFlag validates the documented "-max-lines"
// analyzer flag for largefunc.
// Spec: "largefunc exposes a -max-lines analyzer flag"
func TestSpec_DesignDecision_MaxLinesFlag(t *testing.T) {
flag := largefunc.Analyzer.Flags.Lookup("max-lines")
require.NotNil(t, flag, "largefunc should expose a -max-lines flag per the spec")
}
// TestSpec_UsageExample_AnalyzersUsable validates the documented usage pattern:
// each documented Analyzer can be referenced (e.g. passed to a
// multichecker/singlechecker slice). The README "Usage Examples" block assigns
// `_ = <subpackage>.Analyzer` for the documented analyzers; this test exercises
// the same pattern across all documented subpackages.
func TestSpec_UsageExample_AnalyzersUsable(t *testing.T) {
for _, d := range documentedAnalyzers() {
assert.NotNil(t, d.analyzer, "documented Analyzer %q should be usable in a multichecker/singlechecker slice", d.label)
}
}
// TestSpec_DesignDecision_UniqueAnalyzerNames validates that each documented
// subpackage exposes a distinct Analyzer.Name so they can coexist in a single
// go/analysis driver (multichecker) without conflict.
// Spec: "intentionally organized as a namespace ... so individual analyzers
// remain isolated and independently testable."
func TestSpec_DesignDecision_UniqueAnalyzerNames(t *testing.T) {
documented := documentedAnalyzers()
names := make(map[string]bool, len(documented))
for _, d := range documented {
names[d.analyzer.Name] = true
}
assert.Len(t, names, len(documented),
"each documented subpackage should expose a distinct Analyzer.Name")
}