tools/linters: Add copied golangci-lint lll linter code

In this commit, we copy the implementation of the golangci-lint lll
linter which we currently use in our CI flow during the `make lint`
check. This commit copies the code mostly as is (the only exception
being the line which trims white space before checking if a line starts
with "import"), and formats it to fit our codebase guidelines. A test is
also added so that we can be sure that the following commits which
adjust the implementation have the intended results.

The custom linter is put into its own module as this is requied by the
`golangci-lint custom` when building the custom linter binary which
includes the plugin.
This commit is contained in:
Elle Mouton
2024-11-29 10:39:32 +02:00
parent 506586a37e
commit acbcb771af
4 changed files with 450 additions and 0 deletions

44
tools/linters/go.mod Normal file
View File

@@ -0,0 +1,44 @@
module github.com/lightningnetwork/lnd/tools/linters
go 1.22.6
require (
github.com/golangci/golangci-lint v1.62.2
github.com/stretchr/testify v1.10.0
golang.org/x/tools v0.27.0
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/fatih/color v1.18.0 // indirect
github.com/fsnotify/fsnotify v1.5.4 // indirect
github.com/go-viper/mapstructure/v2 v2.2.1 // indirect
github.com/hashicorp/go-version v1.7.0 // indirect
github.com/hashicorp/hcl v1.0.0 // indirect
github.com/ldez/gomoddirectives v0.2.4 // indirect
github.com/magiconair/properties v1.8.6 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/pelletier/go-toml v1.9.5 // indirect
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/sirupsen/logrus v1.9.3 // indirect
github.com/spf13/afero v1.11.0 // indirect
github.com/spf13/cast v1.5.0 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.12.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/subosito/gotenv v1.4.1 // indirect
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/sync v0.9.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/text v0.18.0 // indirect
gopkg.in/ini.v1 v1.67.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

90
tools/linters/go.sum Normal file
View File

@@ -0,0 +1,90 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
github.com/frankban/quicktest v1.14.3/go.mod h1:mgiwOwqx65TmIk1wJ6Q7wvnVMocbUorkibMOrVTHZps=
github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss=
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
github.com/golangci/golangci-lint v1.62.2 h1:b8K5K9PN+rZN1+mKLtsZHz2XXS9aYKzQ9i25x3Qnxxw=
github.com/golangci/golangci-lint v1.62.2/go.mod h1:ILWWyeFUrctpHVGMa1dg2xZPKoMUTc5OIMgW7HZr34g=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/hashicorp/go-version v1.7.0 h1:5tqGy27NaOTB8yJKUZELlFAS/LTKJkrmONwQKeRZfjY=
github.com/hashicorp/go-version v1.7.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/ldez/gomoddirectives v0.2.4 h1:j3YjBIjEBbqZ0NKtBNzr8rtMHTOrLPeiwTkfUJZ3alg=
github.com/ldez/gomoddirectives v0.2.4/go.mod h1:oWu9i62VcQDYp9EQ0ONTfqLNh+mDLWWDO+SO0qSQw5g=
github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo=
github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8=
github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/viper v1.12.0 h1:CZ7eSOd3kZoaYDLbXnmzgQI5RlciuXBMA+18HwHRfZQ=
github.com/spf13/viper v1.12.0/go.mod h1:b6COn30jlNxbm/V2IqWiNWkJ+vZNiMNksliPCiuKtSI=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/subosito/gotenv v1.4.1 h1:jyEFiXpy21Wm81FBN71l9VoMMV8H8jG+qIK3GCpY6Qs=
github.com/subosito/gotenv v1.4.1/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk=
golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY=
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
golang.org/x/tools v0.27.0 h1:qEKojBykQkQ4EynWy4S8Weg69NumxKdn40Fce3uc/8o=
golang.org/x/tools v0.27.0/go.mod h1:sUi0ZgbwW9ZPAq26Ekut+weQPR5eIM6GQLQ1Yjm1H0Q=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

219
tools/linters/ll.go Normal file
View File

@@ -0,0 +1,219 @@
// The following code is based on code from GolangCI.
// Source: https://github.com/golangci-lint/pkg/golinters/lll/lll.go
// License: GNU
package linters
import (
"bufio"
"errors"
"fmt"
"go/token"
"os"
"path/filepath"
"strings"
"sync"
"unicode/utf8"
"github.com/golangci/golangci-lint/pkg/config"
"github.com/golangci/golangci-lint/pkg/goanalysis"
"github.com/golangci/golangci-lint/pkg/lint/linter"
"github.com/golangci/golangci-lint/pkg/result"
"golang.org/x/tools/go/analysis"
)
const (
linterName = "lll"
goCommentDirectivePrefix = "//go:"
)
// New creates a new lll linter from the given settings. It satisfies the
// signature required by the golangci-lint linter for plugins.
func New(settings *config.LllSettings) *goanalysis.Linter {
var (
mu sync.Mutex
resIssues []goanalysis.Issue
)
analyzer := &analysis.Analyzer{
Name: linterName,
Doc: goanalysis.TheOnlyanalyzerDoc,
Run: func(pass *analysis.Pass) (any, error) {
issues, err := runLll(pass, settings)
if err != nil {
return nil, err
}
if len(issues) == 0 {
return nil, nil
}
mu.Lock()
resIssues = append(resIssues, issues...)
mu.Unlock()
return nil, nil
},
}
return goanalysis.NewLinter(
linterName, "Reports long lines",
[]*analysis.Analyzer{analyzer}, nil,
).WithIssuesReporter(func(*linter.Context) []goanalysis.Issue {
return resIssues
}).WithLoadMode(goanalysis.LoadModeSyntax)
}
func runLll(pass *analysis.Pass, settings *config.LllSettings) (
[]goanalysis.Issue, error) {
var (
fileNames = getFileNames(pass)
spaces = strings.Repeat(" ", settings.TabWidth)
issues []goanalysis.Issue
)
for _, f := range fileNames {
lintIssues, err := getLLLIssuesForFile(
f, settings.LineLength, spaces,
)
if err != nil {
return nil, err
}
for i := range lintIssues {
issues = append(issues, goanalysis.NewIssue(
&lintIssues[i], pass,
))
}
}
return issues, nil
}
func getLLLIssuesForFile(filename string, maxLineLen int,
tabSpaces string) ([]result.Issue, error) {
f, err := os.Open(filename)
if err != nil {
return nil, fmt.Errorf("can't open file %s: %w", filename, err)
}
defer f.Close()
var (
res []result.Issue
lineNumber int
multiImportEnabled bool
)
// Scan over each line.
scanner := bufio.NewScanner(f)
for scanner.Scan() {
lineNumber++
// Replace all tabs with spaces.
line := scanner.Text()
line = strings.ReplaceAll(line, "\t", tabSpaces)
// Ignore any //go: directives since these cant be wrapped onto
// a new line.
if strings.HasPrefix(line, goCommentDirectivePrefix) {
continue
}
// We never want the linter to run on imports since these cannot
// be wrapped onto a new line. If this is a single line import
// we can skip the line entirely. If this is a multi-line import
// skip until the closing bracket.
//
// NOTE: We trim the line space around the line here purely for
// the purpose of being able to test this part of the linter
// without the risk of the `gosimports` tool reformatting the
// test case and removing the import.
if strings.HasPrefix(strings.TrimSpace(line), "import") {
multiImportEnabled = strings.HasSuffix(line, "(")
continue
}
// If we have marked the start of a multi-line import, we should
// skip until the closing bracket of the import block.
if multiImportEnabled {
if line == ")" {
multiImportEnabled = false
}
continue
}
// Otherwise, we can check the length of the line and report if
// it exceeds the maximum line length.
lineLen := utf8.RuneCountInString(line)
if lineLen > maxLineLen {
res = append(res, result.Issue{
Pos: token.Position{
Filename: filename,
Line: lineNumber,
},
Text: fmt.Sprintf("the line is %d "+
"characters long, which exceeds the "+
"maximum of %d characters.", lineLen,
maxLineLen),
FromLinter: linterName,
})
}
}
if err := scanner.Err(); err != nil {
if errors.Is(err, bufio.ErrTooLong) &&
maxLineLen < bufio.MaxScanTokenSize {
// scanner.Scan() might fail if the line is longer than
// bufio.MaxScanTokenSize. In the case where the
// specified maxLineLen is smaller than
// bufio.MaxScanTokenSize we can return this line as a
// long line instead of returning an error. The reason
// for this change is that this case might happen with
// autogenerated files. The go-bindata tool for instance
// might generate a file with a very long line. In this
// case, as it's an auto generated file, the warning
// returned by lll will be ignored.
// But if we return a linter error here, and this error
// happens for an autogenerated file the error will be
// discarded (fine), but all the subsequent errors for
// lll will be discarded for other files, and we'll miss
// legit error.
res = append(res, result.Issue{
Pos: token.Position{
Filename: filename,
Line: lineNumber,
Column: 1,
},
Text: fmt.Sprintf("line is more than "+
"%d characters",
bufio.MaxScanTokenSize),
FromLinter: linterName,
})
} else {
return nil, fmt.Errorf("can't scan file %s: %w",
filename, err)
}
}
return res, nil
}
func getFileNames(pass *analysis.Pass) []string {
var fileNames []string
for _, f := range pass.Files {
fileName := pass.Fset.PositionFor(f.Pos(), true).Filename
ext := filepath.Ext(fileName)
if ext != "" && ext != ".go" {
// The position has been adjusted to a non-go file,
// revert to original file.
position := pass.Fset.PositionFor(f.Pos(), false)
fileName = position.Filename
}
fileNames = append(fileNames, fileName)
}
return fileNames
}

97
tools/linters/ll_test.go Normal file
View File

@@ -0,0 +1,97 @@
package linters
import (
"os"
"strings"
"testing"
"github.com/stretchr/testify/require"
)
// TestGetLLLIssuesForFile tests the line-too-long linter.
//
//nolint:ll
func TestGetLLLIssuesForFile(t *testing.T) {
// Test data
testCases := []struct {
name string
content string
expectedIssue []string
}{
{
name: "Single long line",
content: `
fmt.Println("This is a very long line that exceeds the maximum length and should be flagged by the linter.")`,
expectedIssue: []string{
"the line is 140 characters long, which " +
"exceeds the maximum of 80 characters.",
},
},
{
name: "Multiple long lines",
content: `
fmt.Println("This is a very long line that exceeds the maximum length and should be flagged by the linter.")
fmt.Println("This is a another very long line that exceeds the maximum length and should be flagged by the linter.")`,
expectedIssue: []string{
"the line is 140 characters long, which " +
"exceeds the maximum of 80 characters.",
"the line is 148 characters long, which " +
"exceeds the maximum of 80 characters.",
},
},
{
name: "Short lines",
content: `
fmt.Println("Short line")`,
},
{
name: "Directive ignored",
content: `//go:generate something very very very very very very very very very long and complex here wowowow`,
},
{
name: "Long single line import",
content: `import "github.com/lightningnetwork/lnd/lnrpc/walletrpc/more/more/more/more/more/more/ok/that/is/enough"`,
},
{
name: "Multi-line import",
content: `
import (
"os"
"fmt"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc/more/ok/that/is/enough"
)`,
},
{
name: "Long single line log",
content: `
log.Infof("This is a very long log line but since it is a log line, it should be skipped by the linter.")`,
expectedIssue: []string{
"the line is 121 characters long, which " +
"exceeds the maximum of 80 characters.",
},
},
}
tabSpaces := strings.Repeat(" ", 8)
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// Write content to a temporary file.
tmpFile := t.TempDir() + "/test.go"
err := os.WriteFile(tmpFile, []byte(tc.content), 0644)
require.NoError(t, err)
// Run the linter on the file.
issues, err := getLLLIssuesForFile(
tmpFile, 80, tabSpaces,
)
require.NoError(t, err)
require.Len(t, issues, len(tc.expectedIssue))
for i, issue := range issues {
require.Equal(t, tc.expectedIssue[i], issue.Text)
}
})
}
}