Skip to content

Commit e9a45b2

Browse files
authored
analysis, header: improve test coverage (#8)
1 parent 68ab096 commit e9a45b2

File tree

5 files changed

+347
-5
lines changed

5 files changed

+347
-5
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ run: build
4949

5050
.PHONY: test
5151
test:
52-
go test -v -coverprofile=.cover ./...
52+
go test -coverprofile=.cover ./...
5353

5454
.PHONY: cover
5555
cover:

analysis.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const (
3737
analyzerName = "golicenser"
3838

3939
// DefaultCopyrightHeaderMatcher is the default regexp used to detect the
40-
// existence of any copyright header This will match any header containing
40+
// existence of any copyright header. This will match any header containing
4141
// "copyright".
4242
DefaultCopyrightHeaderMatcher = "(?i)copyright"
4343
)

analysis_test.go

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ package golicenser
2222

2323
import (
2424
"path/filepath"
25+
"reflect"
2526
"testing"
2627
"time"
2728

@@ -35,7 +36,11 @@ func init() {
3536
}
3637

3738
func TestAnalyzer(t *testing.T) {
39+
t.Parallel()
40+
3841
t.Run("simple", func(t *testing.T) {
42+
t.Parallel()
43+
3944
cfg := Config{
4045
Header: HeaderOpts{
4146
Template: "Copyright (c) {{.year}} {{.author}}",
@@ -52,20 +57,23 @@ func TestAnalyzer(t *testing.T) {
5257
// Different header contains a file with a different license header.
5358
// This license header should stay as-is and should not be modified.
5459
t.Run("differentheader", func(t *testing.T) {
60+
t.Parallel()
5561
packageDir := filepath.Join(analysistest.TestData(), "src/differentheader/")
5662
_ = analysistest.Run(t, packageDir, a)
5763
})
5864

5965
// Empty contains an empty file without any existing license header and
6066
// creates a new header.
6167
t.Run("empty", func(t *testing.T) {
68+
t.Parallel()
6269
packageDir := filepath.Join(analysistest.TestData(), "src/empty/")
6370
_ = analysistest.RunWithSuggestedFixes(t, packageDir, a)
6471
})
6572

6673
// Outdated contains a file with a license header which has a different
6774
// copyright year. The year should be updated due to YearModeThisYear.
6875
t.Run("outdated", func(t *testing.T) {
76+
t.Parallel()
6977
packageDir := filepath.Join(analysistest.TestData(), "src/outdated/")
7078
_ = analysistest.RunWithSuggestedFixes(t, packageDir, a)
7179
})
@@ -74,12 +82,14 @@ func TestAnalyzer(t *testing.T) {
7482
// no license header. A license header should be generated without
7583
// modifying the doc comment.
7684
t.Run("packagecomment", func(t *testing.T) {
85+
t.Parallel()
7786
packageDir := filepath.Join(analysistest.TestData(), "src/packagecomment/")
7887
_ = analysistest.RunWithSuggestedFixes(t, packageDir, a)
7988
})
8089
})
8190

8291
t.Run("with matcher", func(t *testing.T) {
92+
t.Parallel()
8393
cfg := Config{
8494
Header: HeaderOpts{
8595
Template: "Copyright (c) {{.year}} {{.author}}",
@@ -97,12 +107,14 @@ func TestAnalyzer(t *testing.T) {
97107
// differentmatcher contains a header that will be matched by Matcher
98108
// but is different from the Template.
99109
t.Run("differentmatcher", func(t *testing.T) {
110+
t.Parallel()
100111
packageDir := filepath.Join(analysistest.TestData(), "src/differentmatcher/")
101112
_ = analysistest.Run(t, packageDir, a)
102113
})
103114
})
104115

105116
t.Run("with escaped matcher", func(t *testing.T) {
117+
t.Parallel()
106118
cfg := Config{
107119
Header: HeaderOpts{
108120
Template: "Copyright (c) {{.year}} {{.author}}",
@@ -121,8 +133,169 @@ func TestAnalyzer(t *testing.T) {
121133
// differentmatcher contains a header that will be matched with the
122134
// escaped Matcher but is different from the Template.
123135
t.Run("differentmatcher", func(t *testing.T) {
136+
t.Parallel()
124137
packageDir := filepath.Join(analysistest.TestData(), "src/differentmatcher/")
125138
_ = analysistest.Run(t, packageDir, a)
126139
})
127140
})
128141
}
142+
143+
func TestNewAnalyzer(t *testing.T) {
144+
t.Parallel()
145+
146+
header := HeaderOpts{
147+
Template: "test",
148+
Author: "test",
149+
}
150+
151+
tests := []struct {
152+
name string
153+
cfg Config
154+
wantErr bool
155+
check func(t *testing.T, a *analyzer)
156+
}{
157+
{
158+
name: "defaults",
159+
cfg: Config{
160+
Header: header,
161+
},
162+
check: func(t *testing.T, a *analyzer) {
163+
t.Helper()
164+
if a.cfg.MaxConcurrent != DefaultMaxConcurrent {
165+
t.Errorf("MaxConcurrent = %v, want %v",
166+
a.cfg.MaxConcurrent, DefaultMaxConcurrent)
167+
}
168+
if a.cfg.CopyrightHeaderMatcher != DefaultCopyrightHeaderMatcher {
169+
t.Errorf("CopyrightHeaderMatcher = %v, want %v",
170+
a.cfg.CopyrightHeaderMatcher, DefaultCopyrightHeaderMatcher)
171+
}
172+
if !reflect.DeepEqual(a.cfg.Exclude, DefaultExcludes) {
173+
t.Errorf("Exclude = %v, want %v", a.cfg.Exclude, DefaultExcludes)
174+
}
175+
},
176+
},
177+
{
178+
name: "invalid copyright header matcher",
179+
cfg: Config{
180+
Header: header,
181+
CopyrightHeaderMatcher: "(test",
182+
},
183+
wantErr: true,
184+
},
185+
{
186+
name: "excludes",
187+
cfg: Config{
188+
Header: header,
189+
Exclude: []string{
190+
"/abc/*",
191+
"**/testdata/**",
192+
"", // empty strings should be ignored
193+
"/test/**",
194+
},
195+
},
196+
check: func(t *testing.T, a *analyzer) {
197+
t.Helper()
198+
199+
if l := len(a.excludes); l != 3 {
200+
t.Errorf("excludes len = %d, want 3", l)
201+
}
202+
tests := map[string]bool{
203+
"afile.go": false,
204+
"/subdir/test": false,
205+
"/abc/": true,
206+
"/abc/test": true,
207+
"/testdata/": true,
208+
"/testdata/abc": true,
209+
"/subdir/testdata/test": true,
210+
"/test/somefile": true,
211+
"/test/": true,
212+
}
213+
for path, want := range tests {
214+
var excluded bool
215+
for _, exclude := range a.excludes {
216+
if !excluded && exclude(path) {
217+
excluded = true
218+
}
219+
}
220+
if excluded != want {
221+
t.Errorf("exclude(%q) = %v, want %v", path, excluded, want)
222+
}
223+
}
224+
},
225+
},
226+
{
227+
name: "excludes regex",
228+
cfg: Config{
229+
Header: header,
230+
Exclude: []string{
231+
"r!(.+)_test\\.go",
232+
"", // empty strings should be ignored
233+
"r!(dir[0-9])/(test1|test2)\\.go",
234+
},
235+
},
236+
check: func(t *testing.T, a *analyzer) {
237+
t.Helper()
238+
239+
if l := len(a.excludes); l != 2 {
240+
t.Errorf("excludes len = %d, want 2", l)
241+
}
242+
tests := map[string]bool{
243+
"afile.go": false,
244+
"/subdir/test": false,
245+
"/golicenser_test.go": true,
246+
"/subdir/golicenser_test.go": true,
247+
"/dir1/test1.go": true,
248+
"/dir2/test2.go": true,
249+
"/subdir/dir1/test1.go": true,
250+
"/dir1/otherfile.go": false,
251+
}
252+
for path, want := range tests {
253+
var excluded bool
254+
for _, exclude := range a.excludes {
255+
if !excluded && exclude(path) {
256+
excluded = true
257+
}
258+
}
259+
if excluded != want {
260+
t.Errorf("exclude(%q) = %v, want %v", path, excluded, want)
261+
}
262+
}
263+
},
264+
},
265+
{
266+
name: "excludes invalid regex",
267+
cfg: Config{
268+
Header: header,
269+
Exclude: []string{
270+
"/abc/*",
271+
"r!test)",
272+
},
273+
},
274+
wantErr: true,
275+
},
276+
{
277+
name: "excludes invalid doublestar",
278+
cfg: Config{
279+
Header: header,
280+
Exclude: []string{
281+
"/abc/*",
282+
"**/testdata/*{*",
283+
},
284+
},
285+
wantErr: true,
286+
},
287+
}
288+
for _, tt := range tests {
289+
t.Run(tt.name, func(t *testing.T) {
290+
t.Parallel()
291+
292+
a, err := newAnalyzer(tt.cfg)
293+
if (err != nil) != tt.wantErr {
294+
t.Errorf("newAnalyzer err = %v, want %v", err, tt.wantErr)
295+
}
296+
if tt.check != nil {
297+
tt.check(t, a)
298+
}
299+
})
300+
}
301+
}

header.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ func detectCommentStyle(s string) (CommentStyle, error) {
161161
switch {
162162
case strings.HasPrefix(s, "// "):
163163
return CommentStyleLine, nil
164-
case strings.HasSuffix(s, "/*\n"):
164+
case strings.HasPrefix(s, "/*\n"):
165165
return CommentStyleBlock, nil
166166
default:
167167
return 0, fmt.Errorf("not a comment: %q", s)
@@ -341,7 +341,8 @@ func (h *Header) Create(filename string) (string, error) {
341341

342342
// Update updates an existing license header if it matches the
343343
func (h *Header) Update(filename, header string) (string, bool, error) {
344-
if cs, err := detectCommentStyle(header); err == nil {
344+
cs, err := detectCommentStyle(header)
345+
if err == nil {
345346
header = cs.Parse(header)
346347
}
347348
match := h.matcher.FindStringSubmatch(header)
@@ -410,7 +411,9 @@ func (h *Header) Update(filename, header string) (string, bool, error) {
410411
if err != nil {
411412
return "", false, fmt.Errorf("render header: %w", err)
412413
}
413-
return h.commentStyle.Render(newHeader), newHeader != header, nil
414+
modified := newHeader != header || cs != h.commentStyle
415+
416+
return h.commentStyle.Render(newHeader), modified, nil
414417
}
415418

416419
func (h *Header) render(filename, year string) (string, error) {

0 commit comments

Comments
 (0)