Skip to content

Commit

Permalink
Add linter
Browse files Browse the repository at this point in the history
  • Loading branch information
Maarten van der Heijden committed Sep 21, 2023
1 parent abe91c6 commit 85e8bbe
Show file tree
Hide file tree
Showing 9 changed files with 144 additions and 28 deletions.
86 changes: 86 additions & 0 deletions .golangci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
linters-settings:
gocritic:
disabled-checks:
- "paramTypeCombine"
enabled-tags:
- "performance"
- "style"
- "diagnostic"
linters:
enable:
- asasalint
- asciicheck
- bidichk
- bodyclose
- containedctx
- contextcheck
- cyclop
- decorder
- dogsled
- dupword
- durationcheck
- errcheck
- errname
- errorlint
- execinquery
- exhaustive
- exportloopref
- forbidigo
- ginkgolinter
- gocheckcompilerdirectives
- gochecknoinits
- gocognit
- goconst
- gocritic
- gocyclo
# - goerr113 # extensively used in the test files
- gofmt
- gofumpt
- goheader
- goimports
- gomoddirectives
- gomodguard
- goprintffuncname
- gosec
- gosimple
- gosmopolitan
- govet
- grouper
- ifshort
- importas
- ineffassign
- interfacebloat
- interfacer
- ireturn
- loggercheck
- maintidx
- makezero
- mirror
- misspell
- musttag
- nakedret
- nestif
- nilerr
- nilnil
- nlreturn
- nonamedreturns
- nosprintfhostport
- paralleltest
- prealloc
- predeclared
- promlinter
- reassign
- rowserrcheck
- sqlclosecheck
- staticcheck
- tenv
- thelper
- tparallel
- typecheck
- unconvert
- unparam
- unused
- usestdlibvars
- wastedassign
- whitespace
- zerologlint
9 changes: 8 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,11 @@ test: fmt ## Run unit tests, alias: t

fmt: ## Format go code
@go mod tidy
@go fmt ./...
@gofumpt -l -w .

tools: ## Install extra tools for development
go install mvdan.cc/gofumpt@latest
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest

lint: ## Lint the code locally
golangci-lint run
6 changes: 4 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,10 @@ func handleGet(c *gin.Context) {
## 🚀 Development

1. Clone the repository
2. Run `make t` to run unit tests
3. Run `make fmt` to format code
2. Run `make tools` to install necessary tools
3. Run `make t` to run unit tests
4. Run `make fmt` to format code
4. Run `make lint` to lint your code

You can run `make` to see a list of useful commands.

Expand Down
15 changes: 11 additions & 4 deletions errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ const defaultCode = http.StatusInternalServerError

var DefaultErrorRegistry = NewErrorRegistry()

type internalHandler func(err error) (int, any)
type internalStringHandler func(err string) (int, any)
type (
internalHandler func(err error) (int, any)
internalStringHandler func(err string) (int, any)
)

// CustomErrorHandler is the template for unexported errors. For example binding.SliceValidationError
// or uuid.invalidLengthError
Expand Down Expand Up @@ -64,13 +66,17 @@ func (e *ErrorRegistry) SetDefaultResponse(code int, response any) {
}

// NewErrorResponse Returns an error response using the DefaultErrorRegistry. If no specific handler could be found,
// it will return the defaults.
// it will return the defaults. It returns an HTTP status code and a response object.
//
//nolint:gocritic // Unnamed return arguments are described
func NewErrorResponse(err error) (int, any) {
return NewErrorResponseFrom(DefaultErrorRegistry, err)
}

// NewErrorResponseFrom Returns an error response using the given registry. If no specific handler could be found,
// it will return the defaults.
// it will return the defaults. It returns an HTTP status code and a response object.
//
//nolint:gocritic // Unnamed return arguments are described
func NewErrorResponseFrom(registry *ErrorRegistry, err error) (int, any) {
errorType := fmt.Sprintf("%T", err)

Expand Down Expand Up @@ -98,6 +104,7 @@ func RegisterErrorHandlerOn[E error, R any](registry *ErrorRegistry, handler Err
// be available in the closure when it is called. Check out TestErrorResponseFrom_ReturnsErrorBInInterface for an example.
registry.handlers[errorType] = func(err error) (int, any) {
// We can safely cast it here, because we know it's the right type.
//nolint:errorlint // Not relevant, we're casting anyway
return handler(err.(E))
}
}
Expand Down
41 changes: 27 additions & 14 deletions errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package ginerr

import (
"errors"
"github.com/stretchr/testify/assert"
"net/http"
"testing"

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

func TestDefaultErrorGenerator_IsSet(t *testing.T) {
Expand All @@ -18,37 +19,38 @@ func TestDefaultErrorGenerator_IsSet(t *testing.T) {

// Register functions are tested through NewErrorResponse[E error]

type ErrorA struct {
type aError struct {
message string
}

func (e ErrorA) Error() string {
func (e aError) Error() string {
return e.message
}

type ErrorB struct {
type bError struct {
message string
}

func (e ErrorB) Error() string {
func (e bError) Error() string {
return e.message
}

// The top ones are not parallel because it uses the DefaultErrorRegistry, which is a global

//nolint:paralleltest // Because of global state
func TestErrorResponse_UsesDefaultErrorRegistry(t *testing.T) {
// Arrange
expectedResponse := Response{
Errors: map[string]any{"error": "It was the man with one hand!"},
}

callback := func(err *ErrorA) (int, Response) {
callback := func(err *aError) (int, Response) {
return 634, Response{
Errors: map[string]any{"error": err.Error()},
}
}

err := &ErrorA{message: "It was the man with one hand!"}
err := &aError{message: "It was the man with one hand!"}

RegisterErrorHandler(callback)

Expand All @@ -60,6 +62,7 @@ func TestErrorResponse_UsesDefaultErrorRegistry(t *testing.T) {
assert.Equal(t, expectedResponse, response)
}

//nolint:paralleltest // Because of global state
func TestErrorResponse_UsesDefaultErrorRegistryForStrings(t *testing.T) {
// Arrange
expectedResponse := Response{
Expand All @@ -84,6 +87,7 @@ func TestErrorResponse_UsesDefaultErrorRegistryForStrings(t *testing.T) {
assert.Equal(t, expectedResponse, response)
}

//nolint:paralleltest // Because of global state
func TestErrorResponse_UsesDefaultErrorRegistryForCustomTypes(t *testing.T) {
// Arrange
expectedResponse := Response{
Expand All @@ -108,6 +112,7 @@ func TestErrorResponse_UsesDefaultErrorRegistryForCustomTypes(t *testing.T) {
assert.Equal(t, expectedResponse, response)
}

//nolint:paralleltest // Because of global state
func TestErrorResponseFrom_ReturnsGenericErrorOnNotFound(t *testing.T) {
t.Parallel()
// Arrange
Expand All @@ -123,6 +128,7 @@ func TestErrorResponseFrom_ReturnsGenericErrorOnNotFound(t *testing.T) {
assert.Equal(t, "test", response)
}

//nolint:paralleltest // Because of global state
func TestErrorResponseFrom_ReturnsErrorA(t *testing.T) {
t.Parallel()
// Arrange
Expand All @@ -131,11 +137,11 @@ func TestErrorResponseFrom_ReturnsErrorA(t *testing.T) {
Errors: map[string]any{"error": "It was the man with one hand!"},
}

callback := func(err *ErrorA) (int, Response) {
callback := func(err *aError) (int, Response) {
return 500, expectedResponse
}

err := &ErrorA{message: "It was the man with one hand!"}
err := &aError{message: "It was the man with one hand!"}

RegisterErrorHandlerOn(registry, callback)

Expand All @@ -147,6 +153,7 @@ func TestErrorResponseFrom_ReturnsErrorA(t *testing.T) {
assert.Equal(t, expectedResponse, response)
}

//nolint:paralleltest // Because of global state
func TestErrorResponseFrom_ReturnsErrorB(t *testing.T) {
t.Parallel()
// Arrange
Expand All @@ -155,11 +162,11 @@ func TestErrorResponseFrom_ReturnsErrorB(t *testing.T) {
Errors: map[string]any{"error": "It was the man with one hand!"},
}

callback := func(err *ErrorB) (int, Response) {
callback := func(err *bError) (int, Response) {
return 500, expectedResponse
}

err := &ErrorB{message: "It was the man with one hand!"}
err := &bError{message: "It was the man with one hand!"}

RegisterErrorHandlerOn(registry, callback)

Expand All @@ -171,6 +178,7 @@ func TestErrorResponseFrom_ReturnsErrorB(t *testing.T) {
assert.Equal(t, expectedResponse, response)
}

//nolint:paralleltest // Because of global state
func TestErrorResponseFrom_ReturnsErrorBInInterface(t *testing.T) {
t.Parallel()
// Arrange
Expand All @@ -179,11 +187,11 @@ func TestErrorResponseFrom_ReturnsErrorBInInterface(t *testing.T) {
Errors: map[string]any{"error": "It was the man with one hand!"},
}

callback := func(err *ErrorB) (int, Response) {
callback := func(err *bError) (int, Response) {
return 500, expectedResponse
}

var err error = &ErrorB{message: "It was the man with one hand!"}
var err error = &bError{message: "It was the man with one hand!"}

RegisterErrorHandlerOn(registry, callback)

Expand All @@ -196,6 +204,7 @@ func TestErrorResponseFrom_ReturnsErrorBInInterface(t *testing.T) {
}

func TestErrorResponseFrom_ReturnsErrorStrings(t *testing.T) {
t.Parallel()
tests := []string{
"Something went completely wrong!",
"Record not found",
Expand All @@ -204,6 +213,7 @@ func TestErrorResponseFrom_ReturnsErrorStrings(t *testing.T) {
for _, errorString := range tests {
errorString := errorString
t.Run(errorString, func(t *testing.T) {
t.Parallel()
// Arrange
registry := NewErrorRegistry()
expectedResponse := Response{
Expand Down Expand Up @@ -231,6 +241,7 @@ func TestErrorResponseFrom_ReturnsErrorStrings(t *testing.T) {
}

func TestErrorResponseFrom_CanConfigureMultipleErrorStrings(t *testing.T) {
t.Parallel()
// Arrange
registry := NewErrorRegistry()

Expand Down Expand Up @@ -258,6 +269,7 @@ func TestErrorResponseFrom_CanConfigureMultipleErrorStrings(t *testing.T) {
}

func TestErrorResponseFrom_ReturnsCustomErrorHandlers(t *testing.T) {
t.Parallel()
tests := []string{
"Something went completely wrong!",
"Record not found",
Expand All @@ -266,6 +278,7 @@ func TestErrorResponseFrom_ReturnsCustomErrorHandlers(t *testing.T) {
for _, errorString := range tests {
errorString := errorString
t.Run(errorString, func(t *testing.T) {
t.Parallel()
// Arrange
registry := NewErrorRegistry()
expectedResponse := Response{
Expand Down Expand Up @@ -298,7 +311,7 @@ func TestErrorResponseFrom_ReturnsGenericErrorOnTypeNotFound(t *testing.T) {
registry := NewErrorRegistry()

// Act
code, response := NewErrorResponseFrom(registry, &ErrorB{})
code, response := NewErrorResponseFrom(registry, &bError{})

// Assert
assert.Equal(t, http.StatusInternalServerError, code)
Expand Down
3 changes: 1 addition & 2 deletions examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ type Response struct {
Errors map[string]any `json:"errors,omitempty"`
}

type MyError struct {
}
type MyError struct{}

func (m MyError) Error() string {
return "Something went wrong!"
Expand Down
6 changes: 4 additions & 2 deletions v2/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ const defaultCode = http.StatusInternalServerError

var DefaultErrorRegistry = NewErrorRegistry()

type internalHandler func(ctx context.Context, err error) (int, any)
type internalStringHandler func(ctx context.Context, err string) (int, any)
type (
internalHandler func(ctx context.Context, err error) (int, any)
internalStringHandler func(ctx context.Context, err string) (int, any)
)

func NewErrorRegistry() *ErrorRegistry {
registry := &ErrorRegistry{
Expand Down
3 changes: 2 additions & 1 deletion v2/errors_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ package ginerr
import (
"context"
"errors"
"github.com/stretchr/testify/assert"
"net/http"
"testing"

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

// Register functions are tested through NewErrorResponse[E error]
Expand Down
3 changes: 1 addition & 2 deletions v2/examples_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,7 @@ type Response struct {
Errors map[string]any `json:"errors,omitempty"`
}

type MyError struct {
}
type MyError struct{}

func (m MyError) Error() string {
return "Something went wrong!"
Expand Down

0 comments on commit 85e8bbe

Please sign in to comment.