diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 57ab0c5..fcd127d 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -12,12 +12,14 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Go - uses: actions/setup-go@v4 + uses: actions/setup-go@v5 with: - go-version: '1.20' - - name: Build - run: go build -v ./... + go-version-file: 'go.mod' + - name: Run linters + uses: golangci/golangci-lint-action@v6 + with: + version: latest - name: Test - run: go test -v ./... \ No newline at end of file + run: make test \ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..fe79280 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,148 @@ +issues: + exclude-rules: + - path: _test\.go + linters: + - gocyclo + +linters: + tests-disable-all: true + # Enable specific linter + # https://golangci-lint.run/usage/linters/#enabled-by-default + disable: + - testpackage + - funlen + - gofumpt + - gocognit + - nestif + - wsl + - varnamelen + enable: + - asasalint + - asciicheck + - bidichk + - bodyclose + - canonicalheader + - containedctx + - contextcheck + - copyloopvar + - decorder + - depguard + - dogsled + - dupl + - dupword + - durationcheck + - err113 + - errcheck + - errchkjson + - errname + - errorlint + - exhaustive + - fatcontext + - forbidigo + - forcetypeassert + - gci + - ginkgolinter + - gocheckcompilerdirectives + - gochecknoglobals + - gochecknoinits + - gochecksumtype + - goconst + - gocritic + - gocyclo + - godot + - godox + - gofmt + - goheader + - goimports + - gomoddirectives + - gomodguard + - goprintffuncname + - gosec + - gosimple + - gosmopolitan + - govet + - grouper + - importas + - inamedparam + - ineffassign + - interfacebloat + - intrange + - ireturn + - lll + - loggercheck + - maintidx + - makezero + - mirror + - misspell + - mnd + - musttag + - nakedret + - nilerr + - nilnil + - nlreturn + - noctx + - nolintlint + - nonamedreturns + - nosprintfhostport + - paralleltest + - perfsprint + - prealloc + - predeclared + - promlinter + - protogetter + - reassign + - revive + - rowserrcheck + - sloglint + - spancheck + - sqlclosecheck + - staticcheck + - stylecheck + - tagalign + - tagliatelle + - tenv + - testableexamples + - testifylint + - thelper + - tparallel + - unconvert + - unparam + - unused + - usestdlibvars + - wastedassign + - whitespace + - zerologlint + # Enable presets. + # https://golangci-lint.run/usage/linters + # Default: [] + presets: + - bugs + - comment + - complexity + - error + - format + - import + - metalinter + - module + - performance + - sql + - style + - test + - unused + # Enable only fast linters from enabled linters set (first run won't be fast) + # Default: false + fast: true + +linters-settings: + gocyclo: + min-complexity: 10 + depguard: + rules: + main: + # List of file globs that will match this list of settings to compare against. + # Default: $all + files: + - $all + # List of allowed packages. + allow: + - $gostd \ No newline at end of file diff --git a/LICENSE b/LICENSE index 0d40994..0765178 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2023 Ville Vesilehto +Copyright (c) 2023-2024 Ville Vesilehto Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b527747 --- /dev/null +++ b/Makefile @@ -0,0 +1,19 @@ +.DEFAULT_GOAL := all + +all: fmt lint test + +fmt: + go fmt $$(go list ./...) + +lint: vet + golangci-lint run + +lit: lint + +vet: + go vet $$(go list ./...) + +test: + go test -v -race -run ^Test -parallel=8 ./... + +.PHONY: fmt lint test \ No newline at end of file diff --git a/README.md b/README.md index a46d957..957614c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ # go-thespine [![Go Reference](https://pkg.go.dev/badge/github.com/thevilledev/go-thespine.svg)](https://pkg.go.dev/github.com/thevilledev/go-thespine) +[![test](https://github.com/thevilledev/go-thespine/actions/workflows/ci.yml/badge.svg)](https://github.com/thevilledev/go-thespine/actions/workflows/ci.yml) +[![Go Report Card](https://goreportcard.com/badge/github.com/thevilledev/go-thespine)](https://goreportcard.com/report/github.com/thevilledev/go-thespine) The greatest death metal album of all time is "Nespithe" (1993) by Demilich from Kuopio, Finland. diff --git a/go.mod b/go.mod index 89d44ac..a144870 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module github.com/thevilledev/go-thespine -go 1.20 +go 1.23.2 diff --git a/thespine.go b/thespine.go index cc45048..fa18d10 100644 --- a/thespine.go +++ b/thespine.go @@ -6,10 +6,10 @@ import ( "unicode/utf8" ) -// THE_SIZE represents the size of grouping used by the anagram encode/decode -const THE_SIZE = 3 +// theSize represents the size of grouping used by the anagram encode/decode. +const theSize = 3 -// ErrInvalidString represents an error for invalid UTF-8 string +// ErrInvalidString represents an error for invalid UTF-8 string. var ErrInvalidString = errors.New("invalid string") // Decode takes a UTF-8 string as an input and decodes the anagram. @@ -20,24 +20,25 @@ func Decode(s string) (string, error) { } sr := []rune(s) l := len(sr) - if l <= THE_SIZE { + if l <= theSize { return s, nil } g := make([][]rune, 0) - gc := l / THE_SIZE - if l%THE_SIZE != 0 { + gc := l / theSize + if l%theSize != 0 { gc++ } - for i := 0; i < gc; i++ { - si := l - (i+1)*THE_SIZE - ei := l - i*THE_SIZE + for i := range gc { + si := l - (i+1)*theSize + ei := l - i*theSize if si < 0 { si = 0 } gs := sr[si:ei] g = append(g, gs) } + return runestring(g), nil } @@ -49,18 +50,18 @@ func Encode(s string) (string, error) { } sr := []rune(s) l := len(sr) - if l <= THE_SIZE { + if l <= theSize { return s, nil } g := make([][]rune, 0) - gc := l / THE_SIZE - if l%THE_SIZE != 0 { + gc := l / theSize + if l%theSize != 0 { gc++ } - for i := 0; i < gc; i++ { - si := i * THE_SIZE - ei := (i + 1) * THE_SIZE + for i := range gc { + si := i * theSize + ei := (i + 1) * theSize if ei > l { ei = l } @@ -70,6 +71,7 @@ func Encode(s string) (string, error) { for i, j := 0, len(g)-1; i < j; i, j = i+1, j-1 { g[i], g[j] = g[j], g[i] } + return runestring(g), nil } @@ -88,6 +90,7 @@ func EncodeText(s string) (string, error) { o += " " } } + return o, nil } @@ -106,6 +109,7 @@ func DecodeText(s string) (string, error) { o += " " } } + return o, nil } @@ -114,5 +118,6 @@ func runestring(r [][]rune) string { for _, r := range r { s += string(r) } + return s } diff --git a/thespine_test.go b/thespine_test.go index 5bb72f5..fcbb49e 100644 --- a/thespine_test.go +++ b/thespine_test.go @@ -47,6 +47,8 @@ func ExampleEncodeText() { } func Test_Decode(t *testing.T) { + t.Parallel() + tests := []struct { str string name string @@ -98,6 +100,7 @@ func Test_Decode(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { + t.Parallel() got, err := Decode(test.str) if test.wantErr && err == nil { t.Fatalf("decode err wanted but got none") @@ -110,6 +113,8 @@ func Test_Decode(t *testing.T) { } func Test_Encode(t *testing.T) { + t.Parallel() + tests := []struct { str string name string @@ -143,6 +148,7 @@ func Test_Encode(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { + t.Parallel() enc, err := Encode(test.str) if test.wantErr && err == nil { t.Fatalf("encode err wanted but got none") @@ -176,6 +182,8 @@ func FuzzEncode(f *testing.F) { } func Test_EncodeText(t *testing.T) { + t.Parallel() + tests := []struct { str string name string @@ -203,6 +211,7 @@ func Test_EncodeText(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { + t.Parallel() o, _ := EncodeText(test.str) if o != test.want { t.Fatalf("encode got: '%s'\nwant: '%s'\n", o, test.want) @@ -212,6 +221,8 @@ func Test_EncodeText(t *testing.T) { } func Test_DecodeText(t *testing.T) { + t.Parallel() + tests := []struct { str string name string @@ -233,6 +244,7 @@ func Test_DecodeText(t *testing.T) { } for _, test := range tests { t.Run(test.name, func(t *testing.T) { + t.Parallel() o, _ := DecodeText(test.str) if o != test.want { t.Fatalf("encode got: '%s'\nwant: '%s'\n", o, test.want)