Skip to content

Commit 659e84d

Browse files
authored
Add test coverage for checks (#48)
1 parent 89d9a5f commit 659e84d

File tree

10 files changed

+235
-11
lines changed

10 files changed

+235
-11
lines changed

internal/check/api.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ func (bldr *OutputBuilder) ReportIssue(msg string, opts ...ReportIssueOpt) *Outp
7474
}
7575

7676
func (bldr *OutputBuilder) Output() Output {
77+
if bldr == nil {
78+
return Output{}
79+
}
7780
return Output{Issues: bldr.issues}
7881
}
7982

internal/check/api_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package check_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/mszostok/codeowners-validator/internal/check"
7+
8+
"github.com/stretchr/testify/assert"
9+
)
10+
11+
func TestAPIBuilder(t *testing.T) {
12+
var bldr *check.OutputBuilder = nil
13+
14+
t.Run("Does not panic on ReportIssue when builder is nil", func(t *testing.T) {
15+
assert.NotPanics(t, func() {
16+
issue := bldr.ReportIssue("test")
17+
assert.Nil(t, issue)
18+
})
19+
})
20+
21+
t.Run("Does not panic on Output when builder is nil", func(t *testing.T) {
22+
assert.NotPanics(t, func() {
23+
out := bldr.Output()
24+
assert.Empty(t, out)
25+
})
26+
})
27+
}

internal/check/file_exists_test.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,31 @@ func TestFileExists(t *testing.T) {
180180
}
181181
}
182182

183+
func TestFileExistCheckFileSystemFailure(t *testing.T) {
184+
// given
185+
tmpdir, err := ioutil.TempDir("", "file-checker")
186+
require.NoError(t, err)
187+
defer func() {
188+
assert.NoError(t, os.RemoveAll(tmpdir))
189+
}()
190+
191+
err = os.MkdirAll(filepath.Join(tmpdir, "foo"), 0222)
192+
require.NoError(t, err)
193+
194+
in := loadInput("* @pico")
195+
in.RepoDir = tmpdir
196+
197+
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Millisecond)
198+
defer cancel()
199+
200+
// when
201+
out, err := check.NewFileExist().Check(ctx, in)
202+
203+
// then
204+
require.Error(t, err)
205+
assert.Empty(t, out)
206+
}
207+
183208
func newErrIssue(msg string) check.Issue {
184209
return check.Issue{
185210
Severity: check.Error,

internal/check/package_test.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package check_test
2+
3+
import (
4+
"context"
5+
"errors"
6+
"testing"
7+
8+
"github.com/mszostok/codeowners-validator/internal/check"
9+
10+
"github.com/stretchr/testify/assert"
11+
"github.com/stretchr/testify/require"
12+
)
13+
14+
func TestRespectingCanceledContext(t *testing.T) {
15+
must := func(checker check.Checker, err error) check.Checker {
16+
require.NoError(t, err)
17+
return checker
18+
}
19+
20+
checkers := []check.Checker{
21+
check.NewDuplicatedPattern(),
22+
check.NewFileExist(),
23+
check.NewValidSyntax(),
24+
check.NewNotOwnedFile(check.NotOwnedFileConfig{}),
25+
must(check.NewValidOwner(check.ValidOwnerConfig{Repository: "org/repo"}, nil)),
26+
}
27+
28+
for _, checker := range checkers {
29+
sut := checker
30+
t.Run(checker.Name(), func(t *testing.T) {
31+
// given: canceled context
32+
ctx, cancel := context.WithCancel(context.Background())
33+
cancel()
34+
35+
// when
36+
out, err := sut.Check(ctx, loadInput(validCODEOWNERS))
37+
38+
// then
39+
assert.True(t, errors.Is(err, context.Canceled))
40+
assert.Empty(t, out)
41+
})
42+
}
43+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
==> Executing Foo Checker (1s)
2+
Check OK
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
==> Executing Foo Checker (1s)
2+
[err] line 42: Simulate error in line 42
3+
[war] line 2020: Simulate warning in line 2020
4+
[err] Error without line number
5+
[war] Warning without line number
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
20 check(s) executed, no failure(s)
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
2+
20 check(s) executed, 10 failure(s)

internal/printer/tty.go

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ package printer
22

33
import (
44
"fmt"
5+
"io"
6+
"os"
57
"strings"
68
"sync"
79
"time"
@@ -10,6 +12,9 @@ import (
1012
"github.com/mszostok/codeowners-validator/internal/check"
1113
)
1214

15+
// writer used for test purpose
16+
var writer io.Writer = os.Stdout
17+
1318
type TTYPrinter struct {
1419
m sync.RWMutex
1520
}
@@ -18,27 +23,27 @@ func (tty *TTYPrinter) PrintCheckResult(checkName string, duration time.Duration
1823
tty.m.Lock()
1924
defer tty.m.Unlock()
2025

21-
header := color.New(color.Bold).PrintfFunc()
22-
issueBody := color.New(color.FgWhite).PrintfFunc()
23-
okCheck := color.New(color.FgGreen).PrintlnFunc()
26+
header := color.New(color.Bold).FprintfFunc()
27+
issueBody := color.New(color.FgWhite).FprintfFunc()
28+
okCheck := color.New(color.FgGreen).FprintlnFunc()
2429

25-
header("==> Executing %s (%v)\n", checkName, duration)
30+
header(writer, "==> Executing %s (%v)\n", checkName, duration)
2631
for _, i := range checkOut.Issues {
2732
issueSeverity := tty.severityPrintfFunc(i.Severity)
2833

29-
issueSeverity(" [%s]", strings.ToLower(i.Severity.String()[:3]))
34+
issueSeverity(writer, " [%s]", strings.ToLower(i.Severity.String()[:3]))
3035
if i.LineNo != nil {
31-
issueBody(" line %d:", *i.LineNo)
36+
issueBody(writer, " line %d:", *i.LineNo)
3237
}
33-
issueBody(" %s\n", i.Message)
38+
issueBody(writer, " %s\n", i.Message)
3439
}
3540

3641
if len(checkOut.Issues) == 0 {
37-
okCheck(" Check OK")
42+
okCheck(writer, " Check OK")
3843
}
3944
}
4045

41-
func (*TTYPrinter) severityPrintfFunc(severity check.SeverityType) func(format string, a ...interface{}) {
46+
func (*TTYPrinter) severityPrintfFunc(severity check.SeverityType) func(w io.Writer, format string, a ...interface{}) {
4247
p := color.New()
4348
switch severity {
4449
case check.Warning:
@@ -47,13 +52,13 @@ func (*TTYPrinter) severityPrintfFunc(severity check.SeverityType) func(format s
4752
p.Add(color.FgRed)
4853
}
4954

50-
return p.PrintfFunc()
55+
return p.FprintfFunc()
5156
}
5257

5358
func (*TTYPrinter) PrintSummary(allCheck, failedChecks int) {
5459
failures := "no"
5560
if failedChecks > 0 {
5661
failures = fmt.Sprintf("%d", failedChecks)
5762
}
58-
fmt.Printf("\n%d check(s) executed, %s failure(s)\n", allCheck, failures)
63+
fmt.Fprintf(writer, "\n%d check(s) executed, %s failure(s)\n", allCheck, failures)
5964
}

internal/printer/tty_test.go

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
package printer
2+
3+
import (
4+
"bytes"
5+
"io"
6+
"testing"
7+
"time"
8+
9+
"github.com/mszostok/codeowners-validator/internal/check"
10+
"github.com/mszostok/codeowners-validator/internal/ptr"
11+
12+
"github.com/sebdah/goldie/v2"
13+
)
14+
15+
func TestTTYPrinterPrintCheckResult(t *testing.T) {
16+
t.Run("Should print all reported issues", func(t *testing.T) {
17+
// given
18+
tty := TTYPrinter{}
19+
20+
buff := &bytes.Buffer{}
21+
restore := overrideWriter(buff)
22+
defer restore()
23+
24+
// when
25+
tty.PrintCheckResult("Foo Checker", time.Second, check.Output{
26+
Issues: []check.Issue{
27+
{
28+
Severity: check.Error,
29+
LineNo: ptr.Uint64Ptr(42),
30+
Message: "Simulate error in line 42",
31+
},
32+
{
33+
Severity: check.Warning,
34+
LineNo: ptr.Uint64Ptr(2020),
35+
Message: "Simulate warning in line 2020",
36+
},
37+
{
38+
Severity: check.Error,
39+
Message: "Error without line number",
40+
},
41+
{
42+
Severity: check.Warning,
43+
Message: "Warning without line number",
44+
},
45+
},
46+
})
47+
48+
// then
49+
g := goldie.New(t, goldie.WithNameSuffix(".golden.txt"))
50+
g.Assert(t, t.Name(), buff.Bytes())
51+
})
52+
53+
t.Run("Should print OK status on empty issues list", func(t *testing.T) {
54+
// given
55+
tty := TTYPrinter{}
56+
57+
buff := &bytes.Buffer{}
58+
restore := overrideWriter(buff)
59+
defer restore()
60+
61+
// when
62+
tty.PrintCheckResult("Foo Checker", time.Second, check.Output{
63+
Issues: nil,
64+
})
65+
66+
// then
67+
g := goldie.New(t, goldie.WithNameSuffix(".golden.txt"))
68+
g.Assert(t, t.Name(), buff.Bytes())
69+
})
70+
}
71+
72+
func TestTTYPrinterPrintSummary(t *testing.T) {
73+
t.Run("Should print number of failures", func(t *testing.T) {
74+
// given
75+
tty := TTYPrinter{}
76+
77+
buff := &bytes.Buffer{}
78+
restore := overrideWriter(buff)
79+
defer restore()
80+
81+
// when
82+
tty.PrintSummary(20, 10)
83+
84+
// then
85+
g := goldie.New(t, goldie.WithNameSuffix(".golden.txt"))
86+
g.Assert(t, t.Name(), buff.Bytes())
87+
})
88+
89+
t.Run("Should print 'no' when there is no failures", func(t *testing.T) {
90+
// given
91+
tty := TTYPrinter{}
92+
93+
buff := &bytes.Buffer{}
94+
restore := overrideWriter(buff)
95+
defer restore()
96+
97+
// when
98+
tty.PrintSummary(20, 0)
99+
100+
// then
101+
g := goldie.New(t, goldie.WithNameSuffix(".golden.txt"))
102+
g.Assert(t, t.Name(), buff.Bytes())
103+
})
104+
}
105+
106+
func overrideWriter(in io.Writer) func() {
107+
old := writer
108+
writer = in
109+
return func() { writer = old }
110+
}

0 commit comments

Comments
 (0)