Skip to content

Commit

Permalink
Add test coverage for checks (#48)
Browse files Browse the repository at this point in the history
  • Loading branch information
mszostok authored Oct 23, 2020
1 parent 89d9a5f commit 659e84d
Show file tree
Hide file tree
Showing 10 changed files with 235 additions and 11 deletions.
3 changes: 3 additions & 0 deletions internal/check/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ func (bldr *OutputBuilder) ReportIssue(msg string, opts ...ReportIssueOpt) *Outp
}

func (bldr *OutputBuilder) Output() Output {
if bldr == nil {
return Output{}
}
return Output{Issues: bldr.issues}
}

Expand Down
27 changes: 27 additions & 0 deletions internal/check/api_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package check_test

import (
"testing"

"github.com/mszostok/codeowners-validator/internal/check"

"github.com/stretchr/testify/assert"
)

func TestAPIBuilder(t *testing.T) {
var bldr *check.OutputBuilder = nil

t.Run("Does not panic on ReportIssue when builder is nil", func(t *testing.T) {
assert.NotPanics(t, func() {
issue := bldr.ReportIssue("test")
assert.Nil(t, issue)
})
})

t.Run("Does not panic on Output when builder is nil", func(t *testing.T) {
assert.NotPanics(t, func() {
out := bldr.Output()
assert.Empty(t, out)
})
})
}
25 changes: 25 additions & 0 deletions internal/check/file_exists_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,31 @@ func TestFileExists(t *testing.T) {
}
}

func TestFileExistCheckFileSystemFailure(t *testing.T) {
// given
tmpdir, err := ioutil.TempDir("", "file-checker")
require.NoError(t, err)
defer func() {
assert.NoError(t, os.RemoveAll(tmpdir))
}()

err = os.MkdirAll(filepath.Join(tmpdir, "foo"), 0222)
require.NoError(t, err)

in := loadInput("* @pico")
in.RepoDir = tmpdir

ctx, cancel := context.WithTimeout(context.Background(), 30*time.Millisecond)
defer cancel()

// when
out, err := check.NewFileExist().Check(ctx, in)

// then
require.Error(t, err)
assert.Empty(t, out)
}

func newErrIssue(msg string) check.Issue {
return check.Issue{
Severity: check.Error,
Expand Down
43 changes: 43 additions & 0 deletions internal/check/package_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package check_test

import (
"context"
"errors"
"testing"

"github.com/mszostok/codeowners-validator/internal/check"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestRespectingCanceledContext(t *testing.T) {
must := func(checker check.Checker, err error) check.Checker {
require.NoError(t, err)
return checker
}

checkers := []check.Checker{
check.NewDuplicatedPattern(),
check.NewFileExist(),
check.NewValidSyntax(),
check.NewNotOwnedFile(check.NotOwnedFileConfig{}),
must(check.NewValidOwner(check.ValidOwnerConfig{Repository: "org/repo"}, nil)),
}

for _, checker := range checkers {
sut := checker
t.Run(checker.Name(), func(t *testing.T) {
// given: canceled context
ctx, cancel := context.WithCancel(context.Background())
cancel()

// when
out, err := sut.Check(ctx, loadInput(validCODEOWNERS))

// then
assert.True(t, errors.Is(err, context.Canceled))
assert.Empty(t, out)
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
==> Executing Foo Checker (1s)
Check OK
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
==> Executing Foo Checker (1s)
[err] line 42: Simulate error in line 42
[war] line 2020: Simulate warning in line 2020
[err] Error without line number
[war] Warning without line number
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

20 check(s) executed, no failure(s)
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@

20 check(s) executed, 10 failure(s)
27 changes: 16 additions & 11 deletions internal/printer/tty.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package printer

import (
"fmt"
"io"
"os"
"strings"
"sync"
"time"
Expand All @@ -10,6 +12,9 @@ import (
"github.com/mszostok/codeowners-validator/internal/check"
)

// writer used for test purpose
var writer io.Writer = os.Stdout

type TTYPrinter struct {
m sync.RWMutex
}
Expand All @@ -18,27 +23,27 @@ func (tty *TTYPrinter) PrintCheckResult(checkName string, duration time.Duration
tty.m.Lock()
defer tty.m.Unlock()

header := color.New(color.Bold).PrintfFunc()
issueBody := color.New(color.FgWhite).PrintfFunc()
okCheck := color.New(color.FgGreen).PrintlnFunc()
header := color.New(color.Bold).FprintfFunc()
issueBody := color.New(color.FgWhite).FprintfFunc()
okCheck := color.New(color.FgGreen).FprintlnFunc()

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

issueSeverity(" [%s]", strings.ToLower(i.Severity.String()[:3]))
issueSeverity(writer, " [%s]", strings.ToLower(i.Severity.String()[:3]))
if i.LineNo != nil {
issueBody(" line %d:", *i.LineNo)
issueBody(writer, " line %d:", *i.LineNo)
}
issueBody(" %s\n", i.Message)
issueBody(writer, " %s\n", i.Message)
}

if len(checkOut.Issues) == 0 {
okCheck(" Check OK")
okCheck(writer, " Check OK")
}
}

func (*TTYPrinter) severityPrintfFunc(severity check.SeverityType) func(format string, a ...interface{}) {
func (*TTYPrinter) severityPrintfFunc(severity check.SeverityType) func(w io.Writer, format string, a ...interface{}) {
p := color.New()
switch severity {
case check.Warning:
Expand All @@ -47,13 +52,13 @@ func (*TTYPrinter) severityPrintfFunc(severity check.SeverityType) func(format s
p.Add(color.FgRed)
}

return p.PrintfFunc()
return p.FprintfFunc()
}

func (*TTYPrinter) PrintSummary(allCheck, failedChecks int) {
failures := "no"
if failedChecks > 0 {
failures = fmt.Sprintf("%d", failedChecks)
}
fmt.Printf("\n%d check(s) executed, %s failure(s)\n", allCheck, failures)
fmt.Fprintf(writer, "\n%d check(s) executed, %s failure(s)\n", allCheck, failures)
}
110 changes: 110 additions & 0 deletions internal/printer/tty_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package printer

import (
"bytes"
"io"
"testing"
"time"

"github.com/mszostok/codeowners-validator/internal/check"
"github.com/mszostok/codeowners-validator/internal/ptr"

"github.com/sebdah/goldie/v2"
)

func TestTTYPrinterPrintCheckResult(t *testing.T) {
t.Run("Should print all reported issues", func(t *testing.T) {
// given
tty := TTYPrinter{}

buff := &bytes.Buffer{}
restore := overrideWriter(buff)
defer restore()

// when
tty.PrintCheckResult("Foo Checker", time.Second, check.Output{
Issues: []check.Issue{
{
Severity: check.Error,
LineNo: ptr.Uint64Ptr(42),
Message: "Simulate error in line 42",
},
{
Severity: check.Warning,
LineNo: ptr.Uint64Ptr(2020),
Message: "Simulate warning in line 2020",
},
{
Severity: check.Error,
Message: "Error without line number",
},
{
Severity: check.Warning,
Message: "Warning without line number",
},
},
})

// then
g := goldie.New(t, goldie.WithNameSuffix(".golden.txt"))
g.Assert(t, t.Name(), buff.Bytes())
})

t.Run("Should print OK status on empty issues list", func(t *testing.T) {
// given
tty := TTYPrinter{}

buff := &bytes.Buffer{}
restore := overrideWriter(buff)
defer restore()

// when
tty.PrintCheckResult("Foo Checker", time.Second, check.Output{
Issues: nil,
})

// then
g := goldie.New(t, goldie.WithNameSuffix(".golden.txt"))
g.Assert(t, t.Name(), buff.Bytes())
})
}

func TestTTYPrinterPrintSummary(t *testing.T) {
t.Run("Should print number of failures", func(t *testing.T) {
// given
tty := TTYPrinter{}

buff := &bytes.Buffer{}
restore := overrideWriter(buff)
defer restore()

// when
tty.PrintSummary(20, 10)

// then
g := goldie.New(t, goldie.WithNameSuffix(".golden.txt"))
g.Assert(t, t.Name(), buff.Bytes())
})

t.Run("Should print 'no' when there is no failures", func(t *testing.T) {
// given
tty := TTYPrinter{}

buff := &bytes.Buffer{}
restore := overrideWriter(buff)
defer restore()

// when
tty.PrintSummary(20, 0)

// then
g := goldie.New(t, goldie.WithNameSuffix(".golden.txt"))
g.Assert(t, t.Name(), buff.Bytes())
})
}

func overrideWriter(in io.Writer) func() {
old := writer
writer = in
return func() { writer = old }
}

0 comments on commit 659e84d

Please sign in to comment.