Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add linter to makefile, configuration and fix few linting issues #6

Merged
merged 4 commits into from
Sep 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
- 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
15 changes: 12 additions & 3 deletions generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ import (
"encoding/json"
"errors"
"fmt"
"github.com/survivorbat/go-tsyncmap"
"reflect"
"regexp"
"strings"

"github.com/survivorbat/go-tsyncmap"
)

// typeCacheMap is used to easily fetch json keys from a type
Expand All @@ -20,6 +21,8 @@ type iKind[T any] interface {
}

// ensureConcrete ensures that the given value is a value and not a pointer, if it is, convert it to its element type
//
//nolint:ireturn // Does not matter in this context
func ensureConcrete[T iKind[T]](value T) T {
if value.Kind() == reflect.Ptr {
return ensureConcrete[T](value.Elem())
Expand All @@ -28,11 +31,14 @@ func ensureConcrete[T iKind[T]](value T) T {
return value
}

// errNotAStruct can be exported in the future if need be
var errNotAStruct = errors.New("object is not a struct")

// getFieldNameFromJson returns the field name from the json tag
func getFieldNameFromJson(object any, jsonKey string) (string, error) {
typeInfo := ensureConcrete(reflect.TypeOf(object))
if typeInfo.Kind() != reflect.Struct {
return "", errors.New("object is not a struct")
return "", errNotAStruct
}

typeName := typeNameOf(object)
Expand Down Expand Up @@ -62,6 +68,7 @@ func getFieldNameFromJson(object any, jsonKey string) (string, error) {
}

typeCacheMap.Store(typeName, typeCache)

return typeCache[jsonKey], nil
}

Expand Down Expand Up @@ -95,7 +102,7 @@ func injectLinks(registry LinkRegistry, object any, result map[string]any) {

// Replace the {name} with the actual value
matchString := fmt.Sprintf("{%s}", match[1])
linkInfo.Href = strings.Replace(linkInfo.Href, matchString, fmt.Sprintf("%v", urlValue), -1)
linkInfo.Href = strings.ReplaceAll(linkInfo.Href, matchString, fmt.Sprintf("%v", urlValue))
}

// Save the linkInfo in the object
Expand Down Expand Up @@ -159,6 +166,7 @@ func InjectLinks(registry LinkRegistry, object any) []byte {

var resultObject any

//nolint:exhaustive // Doesn't make sense to add more here
switch ensureConcrete(reflect.ValueOf(object)).Kind() {
case reflect.Slice, reflect.Struct, reflect.Array:
_ = json.Unmarshal(rawResponseJson, &resultObject)
Expand All @@ -170,5 +178,6 @@ func InjectLinks(registry LinkRegistry, object any) []byte {
}

finalResponse, _ := json.Marshal(resultObject)

return finalResponse
}
15 changes: 7 additions & 8 deletions generator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ package gohateoas
import (
"encoding/json"
"fmt"
"github.com/stretchr/testify/assert"
"net/http"
"reflect"
"testing"
"time"

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

type cupcake struct {
Expand Down Expand Up @@ -503,8 +504,7 @@ func TestInjectLinks_CreatesExpectedJsonWithDeeperSlice(t *testing.T) {
}

// empty is used as a dummy to make sure the if-statement in InjectLinks doesn't halt execution on no registered links
type empty struct {
}
type empty struct{}

func TestInjectLinks_ReturnsJsonOnUnknownType(t *testing.T) {
t.Parallel()
Expand Down Expand Up @@ -595,8 +595,7 @@ func TestInjectLinks_IgnoresOnNonStructSlices(t *testing.T) {
func TestInjectLinks_IgnoresIfRegistryIsEmpty(t *testing.T) {
t.Parallel()
// Arrange
type testType3 struct {
}
type testType3 struct{}

registry := NewLinkRegistry()

Expand Down Expand Up @@ -851,13 +850,12 @@ func BenchmarkInjectLinks(b *testing.B) {

registryTests := map[string]func() LinkRegistry{
// This test won't do much because there's an if-statement blocking execution, but it gives us a bit of insight
"no links": func() LinkRegistry {
return NewLinkRegistry()
},
"no links": NewLinkRegistry,

"3 links for fridge": func() LinkRegistry {
registry := NewLinkRegistry()
RegisterOn(registry, fridge{}, Self("/api/fridges", "Get this fridge"), Post("/api/fridges", "Create a new fridge"), Delete("/api/v1/fridges/{id}", "Delete a fridge"))

return registry
},

Expand All @@ -867,6 +865,7 @@ func BenchmarkInjectLinks(b *testing.B) {
RegisterOn(registry, vegetable{}, Self("/api/vegetables", "Get this vegetable"), Post("/api/vegetables", "Create a new vegetable"), Delete("/api/v1/vegetables/{id}", "Delete a vegetable"))
RegisterOn(registry, fruit{}, Self("/api/fruits", "Get this fruit"), Post("/api/fruits", "Create a new fruit"), Delete("/api/v1/fruits/{id}", "Delete a fruit"))
RegisterOn(registry, cake{}, Self("/api/cakes", "Get this cake"), Post("/api/cakes", "Create a new cake"), Delete("/api/v1/cakes/{id}", "Delete a cake"))

return registry
},
}
Expand Down
3 changes: 2 additions & 1 deletion registry_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package gohateoas

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

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

func TestGetTypeName_ReturnsNameOnTypeA(t *testing.T) {
Expand Down