pkgsrc-Changes archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

CVS commit: pkgsrc/pkgtools/pkglint



Module Name:    pkgsrc
Committed By:   rillig
Date:           Tue Nov 19 06:51:39 UTC 2019

Modified Files:
        pkgsrc/pkgtools/pkglint: Makefile
        pkgsrc/pkgtools/pkglint/files: alternatives.go alternatives_test.go
            mktypes.go pkgsrc.go pkgsrc_test.go testnames_test.go
        pkgsrc/pkgtools/pkglint/files/getopt: getopt_test.go
        pkgsrc/pkgtools/pkglint/files/histogram: histogram_test.go
        pkgsrc/pkgtools/pkglint/files/intqa: testnames.go testnames_test.go
        pkgsrc/pkgtools/pkglint/files/licenses: licenses_test.go
        pkgsrc/pkgtools/pkglint/files/pkgver: vercmp_test.go
        pkgsrc/pkgtools/pkglint/files/textproc: lexer_test.go
        pkgsrc/pkgtools/pkglint/files/trace: tracing_test.go

Log Message:
pkgtools/pkglint: update to 19.3.9

Changes since 19.3.8:

Match man pages in ALTERNATIVES with their counterparts in PLIST. In
PLIST files, ${PKGMANDIR} may be abbreviated as a simple "man", but not
in ALTERNATIVES.


To generate a diff of this commit:
cvs rdiff -u -r1.608 -r1.609 pkgsrc/pkgtools/pkglint/Makefile
cvs rdiff -u -r1.15 -r1.16 pkgsrc/pkgtools/pkglint/files/alternatives.go
cvs rdiff -u -r1.16 -r1.17 pkgsrc/pkgtools/pkglint/files/alternatives_test.go
cvs rdiff -u -r1.19 -r1.20 pkgsrc/pkgtools/pkglint/files/mktypes.go
cvs rdiff -u -r1.40 -r1.41 pkgsrc/pkgtools/pkglint/files/pkgsrc.go
cvs rdiff -u -r1.34 -r1.35 pkgsrc/pkgtools/pkglint/files/pkgsrc_test.go
cvs rdiff -u -r1.7 -r1.8 pkgsrc/pkgtools/pkglint/files/testnames_test.go
cvs rdiff -u -r1.11 -r1.12 \
    pkgsrc/pkgtools/pkglint/files/getopt/getopt_test.go
cvs rdiff -u -r1.2 -r1.3 \
    pkgsrc/pkgtools/pkglint/files/histogram/histogram_test.go
cvs rdiff -u -r1.5 -r1.6 pkgsrc/pkgtools/pkglint/files/intqa/testnames.go
cvs rdiff -u -r1.2 -r1.3 \
    pkgsrc/pkgtools/pkglint/files/intqa/testnames_test.go
cvs rdiff -u -r1.6 -r1.7 \
    pkgsrc/pkgtools/pkglint/files/licenses/licenses_test.go
cvs rdiff -u -r1.6 -r1.7 pkgsrc/pkgtools/pkglint/files/pkgver/vercmp_test.go
cvs rdiff -u -r1.7 -r1.8 pkgsrc/pkgtools/pkglint/files/textproc/lexer_test.go
cvs rdiff -u -r1.4 -r1.5 pkgsrc/pkgtools/pkglint/files/trace/tracing_test.go

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: pkgsrc/pkgtools/pkglint/Makefile
diff -u pkgsrc/pkgtools/pkglint/Makefile:1.608 pkgsrc/pkgtools/pkglint/Makefile:1.609
--- pkgsrc/pkgtools/pkglint/Makefile:1.608      Sun Nov 17 02:06:01 2019
+++ pkgsrc/pkgtools/pkglint/Makefile    Tue Nov 19 06:51:38 2019
@@ -1,6 +1,6 @@
-# $NetBSD: Makefile,v 1.608 2019/11/17 02:06:01 rillig Exp $
+# $NetBSD: Makefile,v 1.609 2019/11/19 06:51:38 rillig Exp $
 
-PKGNAME=       pkglint-19.3.8
+PKGNAME=       pkglint-19.3.9
 CATEGORIES=    pkgtools
 DISTNAME=      tools
 MASTER_SITES=  ${MASTER_SITE_GITHUB:=golang/}

Index: pkgsrc/pkgtools/pkglint/files/alternatives.go
diff -u pkgsrc/pkgtools/pkglint/files/alternatives.go:1.15 pkgsrc/pkgtools/pkglint/files/alternatives.go:1.16
--- pkgsrc/pkgtools/pkglint/files/alternatives.go:1.15  Sun Nov 17 01:26:25 2019
+++ pkgsrc/pkgtools/pkglint/files/alternatives.go       Tue Nov 19 06:51:38 2019
@@ -28,6 +28,9 @@ func CheckFileAlternatives(filename stri
                if plist.Files[plistName] != nil || G.Pkg.vars.IsDefined("ALTERNATIVES_SRC") {
                        return
                }
+               if plist.Files[strings.Replace(plistName, "${PKGMANDIR}", "man", 1)] != nil {
+                       return
+               }
 
                switch {
 

Index: pkgsrc/pkgtools/pkglint/files/alternatives_test.go
diff -u pkgsrc/pkgtools/pkglint/files/alternatives_test.go:1.16 pkgsrc/pkgtools/pkglint/files/alternatives_test.go:1.17
--- pkgsrc/pkgtools/pkglint/files/alternatives_test.go:1.16     Sun Jul 14 21:25:47 2019
+++ pkgsrc/pkgtools/pkglint/files/alternatives_test.go  Tue Nov 19 06:51:38 2019
@@ -106,3 +106,25 @@ func (s *Suite) Test_CheckFileAlternativ
 
        t.CheckOutputEmpty()
 }
+
+// When a man page is mentioned in the ALTERNATIVES file, it must use the
+// PKGMANDIR variable. In the PLIST files though, there is some magic
+// in the pkgsrc infrastructure that maps man/ to ${PKGMANDIR}, which
+// leads to a bit less typing.
+//
+// Seen in graphics/py-blockdiag.
+func (s *Suite) Test_CheckFileAlternatives__PLIST_man(c *check.C) {
+       t := s.Init(c)
+
+       t.SetUpPackage("category/package")
+       t.CreateFileLines("category/package/ALTERNATIVES",
+               "@PKGMANDIR@/man1/blockdiag @PREFIX@/@PKGMANDIR@/man1/blockdiag-@PYVERSSUFFIX@.1")
+       t.CreateFileLines("category/package/PLIST",
+               PlistCvsID,
+               "man/man1/blockdiag-${PYVERSSUFFIX}.1")
+       t.FinishSetUp()
+
+       G.Check(t.File("category/package"))
+
+       t.CheckOutputEmpty()
+}

Index: pkgsrc/pkgtools/pkglint/files/mktypes.go
diff -u pkgsrc/pkgtools/pkglint/files/mktypes.go:1.19 pkgsrc/pkgtools/pkglint/files/mktypes.go:1.20
--- pkgsrc/pkgtools/pkglint/files/mktypes.go:1.19       Fri Nov  1 19:56:53 2019
+++ pkgsrc/pkgtools/pkglint/files/mktypes.go    Tue Nov 19 06:51:38 2019
@@ -110,7 +110,7 @@ func (m MkVarUseModifier) IsToLower() bo
 func (m MkVarUseModifier) ChangesWords() bool {
        text := m.Text
 
-       // See MkParser.VarUseModifiers for the meaning of these modifiers.
+       // See MkParser.varUseModifier for the meaning of these modifiers.
        switch text[0] {
 
        case 'E', 'H', 'M', 'N', 'O', 'R', 'T':

Index: pkgsrc/pkgtools/pkglint/files/pkgsrc.go
diff -u pkgsrc/pkgtools/pkglint/files/pkgsrc.go:1.40 pkgsrc/pkgtools/pkglint/files/pkgsrc.go:1.41
--- pkgsrc/pkgtools/pkglint/files/pkgsrc.go:1.40        Sun Nov 17 02:55:56 2019
+++ pkgsrc/pkgtools/pkglint/files/pkgsrc.go     Tue Nov 19 06:51:38 2019
@@ -219,7 +219,7 @@ func (src *Pkgsrc) loadDocChangesFromFil
                        continue
                }
 
-               if year != "" && len(change.Date) >= 4 && change.Date[0:4] != year {
+               if year != "" && change.Date[0:4] != year {
                        line.Warnf("Year %q for %s does not match the filename %s.",
                                change.Date[0:4], change.Pkgpath, filename)
                }

Index: pkgsrc/pkgtools/pkglint/files/pkgsrc_test.go
diff -u pkgsrc/pkgtools/pkglint/files/pkgsrc_test.go:1.34 pkgsrc/pkgtools/pkglint/files/pkgsrc_test.go:1.35
--- pkgsrc/pkgtools/pkglint/files/pkgsrc_test.go:1.34   Sun Nov 17 02:55:56 2019
+++ pkgsrc/pkgtools/pkglint/files/pkgsrc_test.go        Tue Nov 19 06:51:38 2019
@@ -368,6 +368,10 @@ func (s *Suite) Test_Pkgsrc_parseDocChan
        test("\t Too large indentation",
                "WARN: doc/CHANGES-2019:123: Package changes should be indented using a single tab, not \"\\t \".")
 
+       test("\t",
+               "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: \t")
+       test("\t1",
+               "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: \t1")
        test("\t1 2 3 4",
                "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: \t1 2 3 4")
        test("\t1 2 3 4 5",
@@ -387,25 +391,25 @@ func (s *Suite) Test_Pkgsrc_parseDocChan
                nil...)
 
        // "to" is wrong
-       test("\tAdded pkgpath to 1.0 [author date]",
+       test("\tAdded pkgpath to 1.0 [author 2019-01-01]",
                "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+
-                       "\tAdded pkgpath to 1.0 [author date]")
+                       "\tAdded pkgpath to 1.0 [author 2019-01-01]")
 
        test("\tUpdated pkgpath to 1.0 [author 2019-01-01]",
                nil...)
 
        // "from" is wrong
-       test("\tUpdated pkgpath from 1.0 [author date]",
+       test("\tUpdated pkgpath from 1.0 [author 2019-01-01]",
                "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+
-                       "\tUpdated pkgpath from 1.0 [author date]")
+                       "\tUpdated pkgpath from 1.0 [author 2019-01-01]")
 
        test("\tDowngraded pkgpath to 1.0 [author 2019-01-01]",
                nil...)
 
        // "from" is wrong
-       test("\tDowngraded pkgpath from 1.0 [author date]",
+       test("\tDowngraded pkgpath from 1.0 [author 2019-01-01]",
                "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+
-                       "\tDowngraded pkgpath from 1.0 [author date]")
+                       "\tDowngraded pkgpath from 1.0 [author 2019-01-01]")
 
        test("\tRemoved pkgpath [author 2019-01-01]",
                nil...)
@@ -414,30 +418,30 @@ func (s *Suite) Test_Pkgsrc_parseDocChan
                nil...)
 
        // "and" is wrong
-       test("\tRemoved pkgpath and pkgpath [author date]",
+       test("\tRemoved pkgpath and pkgpath [author 2019-01-01]",
                "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+
-                       "\tRemoved pkgpath and pkgpath [author date]")
+                       "\tRemoved pkgpath and pkgpath [author 2019-01-01]")
 
        test("\tRenamed pkgpath to other [author 2019-01-01]",
                nil...)
 
        // "from" is wrong
-       test("\tRenamed pkgpath from previous [author date]",
+       test("\tRenamed pkgpath from previous [author 2019-01-01]",
                "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+
-                       "\tRenamed pkgpath from previous [author date]")
+                       "\tRenamed pkgpath from previous [author 2019-01-01]")
 
        test("\tMoved pkgpath to other [author 2019-01-01]",
                nil...)
 
        // "from" is wrong
-       test("\tMoved pkgpath from previous [author date]",
+       test("\tMoved pkgpath from previous [author 2019-01-01]",
                "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+
-                       "\tMoved pkgpath from previous [author date]")
+                       "\tMoved pkgpath from previous [author 2019-01-01]")
 
        // "Split" is wrong
-       test("\tSplit pkgpath into a and b [author date]",
+       test("\tSplit pkgpath into a and b [author 2019-01-01]",
                "WARN: doc/CHANGES-2019:123: Invalid doc/CHANGES line: "+
-                       "\tSplit pkgpath into a and b [author date]")
+                       "\tSplit pkgpath into a and b [author 2019-01-01]")
 
        // Entries ending in a colon are used for infrastructure changes.
        test("\tmk: remove support for USE_CROSSBASE [author 2016-06-19]",

Index: pkgsrc/pkgtools/pkglint/files/testnames_test.go
diff -u pkgsrc/pkgtools/pkglint/files/testnames_test.go:1.7 pkgsrc/pkgtools/pkglint/files/testnames_test.go:1.8
--- pkgsrc/pkgtools/pkglint/files/testnames_test.go:1.7 Sun Nov 17 01:26:25 2019
+++ pkgsrc/pkgtools/pkglint/files/testnames_test.go     Tue Nov 19 06:51:38 2019
@@ -10,7 +10,7 @@ import (
 //  Test_${Type}_${Method}__${description_using_underscores}
 func (s *Suite) Test__test_names(c *check.C) {
        ck := intqa.NewTestNameChecker(c.Errorf)
-       ck.IgnoreFiles("*yacc.go")
-       ck.Enable(intqa.EAll, -intqa.EMissingTest)
+       ck.Configure("*", "*", "*", -intqa.EMissingTest)
+       ck.Configure("*yacc.go", "*", "*", intqa.ENone)
        ck.Check()
 }

Index: pkgsrc/pkgtools/pkglint/files/getopt/getopt_test.go
diff -u pkgsrc/pkgtools/pkglint/files/getopt/getopt_test.go:1.11 pkgsrc/pkgtools/pkglint/files/getopt/getopt_test.go:1.12
--- pkgsrc/pkgtools/pkglint/files/getopt/getopt_test.go:1.11    Sun Nov 17 01:26:26 2019
+++ pkgsrc/pkgtools/pkglint/files/getopt/getopt_test.go Tue Nov 19 06:51:38 2019
@@ -411,6 +411,6 @@ func (s *Suite) Test_Options_Help__with_
 
 func (s *Suite) Test__test_names(c *check.C) {
        ck := intqa.NewTestNameChecker(c.Errorf)
-       ck.Enable(intqa.EAll, -intqa.EMissingTest)
+       ck.Configure("*", "*", "*", -intqa.EMissingTest)
        ck.Check()
 }

Index: pkgsrc/pkgtools/pkglint/files/histogram/histogram_test.go
diff -u pkgsrc/pkgtools/pkglint/files/histogram/histogram_test.go:1.2 pkgsrc/pkgtools/pkglint/files/histogram/histogram_test.go:1.3
--- pkgsrc/pkgtools/pkglint/files/histogram/histogram_test.go:1.2       Sun Nov 17 01:26:26 2019
+++ pkgsrc/pkgtools/pkglint/files/histogram/histogram_test.go   Tue Nov 19 06:51:38 2019
@@ -30,6 +30,6 @@ func (s *Suite) Test_Histogram(c *check.
 
 func (s *Suite) Test__test_names(c *check.C) {
        ck := intqa.NewTestNameChecker(c.Errorf)
-       ck.Enable(intqa.EAll, -intqa.EMissingTest)
+       ck.Configure("*", "*", "*", -intqa.EMissingTest)
        ck.Check()
 }

Index: pkgsrc/pkgtools/pkglint/files/intqa/testnames.go
diff -u pkgsrc/pkgtools/pkglint/files/intqa/testnames.go:1.5 pkgsrc/pkgtools/pkglint/files/intqa/testnames.go:1.6
--- pkgsrc/pkgtools/pkglint/files/intqa/testnames.go:1.5        Sun Nov 17 01:26:26 2019
+++ pkgsrc/pkgtools/pkglint/files/intqa/testnames.go    Tue Nov 19 06:51:38 2019
@@ -8,7 +8,8 @@ import (
        "go/token"
        "io"
        "os"
-       "path/filepath"
+       "path"
+       "reflect"
        "sort"
        "strings"
        "unicode"
@@ -17,7 +18,7 @@ import (
 type Error int
 
 const (
-       ENone Error = iota
+       ENone Error = iota + 1
        EAll
 
        // A function or method does not have a corresponding test.
@@ -45,43 +46,47 @@ const (
 type TestNameChecker struct {
        errorf func(format string, args ...interface{})
 
-       ignoredFiles []string
-       order        int
+       filters []filter
+       order   int
 
        testees []*testee
        tests   []*test
 
-       errorsMask uint64
-       errors     []string
-       out        io.Writer
+       errors []string
+       out    io.Writer
 }
 
 // NewTestNameChecker creates a new checker.
-// By default, all errors are disabled; call Enable to enable them.
+// By default, all errors are enabled;
+// call Configure to disable them selectively.
 func NewTestNameChecker(errorf func(format string, args ...interface{})) *TestNameChecker {
-       return &TestNameChecker{errorf: errorf, out: os.Stderr}
-}
+       ck := TestNameChecker{errorf: errorf, out: os.Stderr}
 
-func (ck *TestNameChecker) IgnoreFiles(fileGlob string) {
-       ck.ignoredFiles = append(ck.ignoredFiles, fileGlob)
-}
-
-func (ck *TestNameChecker) Enable(errors ...Error) {
-       for _, err := range errors {
-               if err == ENone {
-                       ck.errorsMask = 0
-               } else if err == EAll {
-                       ck.errorsMask = ^uint64(0)
-               } else if err < 0 {
-                       ck.errorsMask &= ^(uint64(1) << -uint(err))
-               } else {
-                       ck.errorsMask |= uint64(1) << uint(err)
-               }
-       }
+       // For test fixtures from https://gopkg.in/check/v1.
+       ck.Configure("*_test.go", "*", "SetUpTest", -EMissingTest)
+       ck.Configure("*_test.go", "*", "TearDownTest", -EMissingTest)
+
+       // See https://github.com/rillig/gobco.
+       ck.Configure("gobco_*.go", "gobco*", "*", -EMissingTest)
+       ck.Configure("gobco_*.go", "", "gobco*", -EMissingTest)
+
+       return &ck
+}
+
+// Configure sets the errors that are activated for the given code,
+// specified by shell patterns like in path.Match.
+//
+// All rules are applied in order. Later rules overwrite earlier rules.
+//
+// Individual errors can be enabled by giving their constant and disabled
+// by negating them, such as -EMissingTestee. To reset everything, use
+// either EAll or ENone.
+func (ck *TestNameChecker) Configure(filenames, typeNames, funcNames string, errors ...Error) {
+       ck.filters = append(ck.filters, filter{filenames, typeNames, funcNames, errors})
 }
 
 func (ck *TestNameChecker) Check() {
-       ck.load()
+       ck.load(".")
        ck.checkTestees()
        ck.checkTests()
        ck.checkOrder()
@@ -89,29 +94,18 @@ func (ck *TestNameChecker) Check() {
 }
 
 // load loads all type, function and method names from the current package.
-func (ck *TestNameChecker) load() {
+func (ck *TestNameChecker) load(dir string) {
+
        fileSet := token.NewFileSet()
-       pkgs, err := parser.ParseDir(fileSet, ".", nil, 0)
+       pkgs, err := parser.ParseDir(fileSet, dir, nil, 0)
        if err != nil {
                panic(err)
        }
 
-       var pkgnames []string
-       for pkgname := range pkgs {
-               pkgnames = append(pkgnames, pkgname)
-       }
-       sort.Strings(pkgnames)
-
-       for _, pkgname := range pkgnames {
+       for _, pkgname := range sortedKeys(pkgs) {
                files := pkgs[pkgname].Files
 
-               var filenames []string
-               for filename := range files {
-                       filenames = append(filenames, filename)
-               }
-               sort.Strings(filenames)
-
-               for _, filename := range filenames {
+               for _, filename := range sortedKeys(files) {
                        file := files[filename]
                        for _, decl := range file.Decls {
                                ck.loadDecl(decl, filename)
@@ -131,7 +125,7 @@ func (ck *TestNameChecker) loadDecl(decl
                        switch spec := spec.(type) {
                        case *ast.TypeSpec:
                                typeName := spec.Name.Name
-                               ck.addCode(code{filename, typeName, "", ck.nextOrder()})
+                               ck.addCode(code{filename, typeName, "", 0})
                        }
                }
 
@@ -145,16 +139,28 @@ func (ck *TestNameChecker) loadDecl(decl
                                typeName = typeExpr.(*ast.Ident).Name
                        }
                }
-               ck.addCode(code{filename, typeName, decl.Name.Name, ck.nextOrder()})
+               funcName := decl.Name.Name
+               ck.addCode(code{filename, typeName, funcName, 0})
        }
 }
 
 func (ck *TestNameChecker) addCode(code code) {
-       isTest := strings.HasSuffix(code.file, "_test.go") &&
-               code.Type != "" &&
-               strings.HasPrefix(code.Func, "Test")
+       if code.isTestScope() && code.isFunc() && code.Func == "TestMain" {
+               // This is not a test for Main, but a wrapper function of the test.
+               // Therefore it is completely ignored.
+               // See https://golang.org/pkg/testing/#hdr-Main.
+               //
+               // Among others, this function is created by
+               // https://github.com/rillig/gobco when measuring the branch
+               // coverage of a package.
+               return
+       }
 
-       if isTest {
+       if !ck.isRelevant(code.file, code.Type, code.Func, EAll) {
+               return
+       }
+
+       if code.isTest() {
                ck.addTest(code)
        } else {
                ck.addTestee(code)
@@ -162,15 +168,19 @@ func (ck *TestNameChecker) addCode(code 
 }
 
 func (ck *TestNameChecker) addTestee(code code) {
+       code.order = ck.nextOrder()
        ck.testees = append(ck.testees, &testee{code})
 }
 
 func (ck *TestNameChecker) addTest(code code) {
-       if !strings.HasPrefix(code.Func, "Test_") {
+       if !strings.HasPrefix(code.Func, "Test_") &&
+               code.Func != "Test" &&
                ck.addError(
                        EName,
+                       code,
                        "Test %q must start with %q.",
-                       code.fullName(), "Test_")
+                       code.fullName(), "Test_") {
+
                return
        }
 
@@ -178,16 +188,18 @@ func (ck *TestNameChecker) addTest(code 
        testeeName := strings.TrimPrefix(strings.TrimPrefix(parts[0], "Test"), "_")
        descr := ""
        if len(parts) > 1 {
-               if parts[1] == "" {
+               if parts[1] == "" &&
                        ck.addError(
                                EName,
-                               "Test %q must not have a nonempty description.",
-                               code.fullName())
+                               code,
+                               "Test %q must have a nonempty description.",
+                               code.fullName()) {
                        return
                }
                descr = parts[1]
        }
 
+       code.order = ck.nextOrder()
        ck.tests = append(ck.tests, &test{code, testeeName, descr, nil})
 }
 
@@ -213,8 +225,8 @@ func (ck *TestNameChecker) relate() {
 func (ck *TestNameChecker) checkTests() {
        for _, test := range ck.tests {
                ck.checkTestFile(test)
-               ck.checkTestName(test)
                ck.checkTestTestee(test)
+               ck.checkTestDescr(test)
        }
 }
 
@@ -225,12 +237,15 @@ func (ck *TestNameChecker) checkTestFile
        }
 
        correctTestFile := strings.TrimSuffix(testee.file, ".go") + "_test.go"
-       if correctTestFile != test.file {
-               ck.addError(
-                       EFile,
-                       "Test %q for %q must be in %s instead of %s.",
-                       test.fullName(), testee.fullName(), correctTestFile, test.file)
+       if correctTestFile == test.file {
+               return
        }
+
+       ck.addError(
+               EFile,
+               test.code,
+               "Test %q for %q must be in %s instead of %s.",
+               test.fullName(), testee.fullName(), correctTestFile, test.file)
 }
 
 func (ck *TestNameChecker) checkTestTestee(test *test) {
@@ -242,27 +257,23 @@ func (ck *TestNameChecker) checkTestTest
        testeeName := strings.Replace(test.testeeName, "_", ".", -1)
        ck.addError(
                EMissingTestee,
+               test.code,
                "Missing testee %q for test %q.",
                testeeName, test.fullName())
 }
 
-// checkTestName ensures that the method name does not accidentally
-// end up in the description of the test. This could happen if there is a
-// double underscore instead of a single underscore.
-func (ck *TestNameChecker) checkTestName(test *test) {
+// checkTestDescr ensures that the type or function name of the testee
+// does not accidentally end up in the description of the test. This could
+// happen if there is a double underscore instead of a single underscore.
+func (ck *TestNameChecker) checkTestDescr(test *test) {
        testee := test.testee
-       if testee == nil {
-               return
-       }
-       if testee.Type != "" && testee.Func != "" {
-               return
-       }
-       if !isCamelCase(test.descr) {
+       if testee == nil || testee.isMethod() || !isCamelCase(test.descr) {
                return
        }
 
        ck.addError(
                EName,
+               testee.code,
                "%s: Test description %q must not use CamelCase in the first word.",
                test.fullName(), test.descr)
 }
@@ -274,29 +285,49 @@ func (ck *TestNameChecker) checkTestees(
        }
 
        for _, testee := range ck.testees {
-               if tested[testee] || testee.Func == "" {
-                       continue
-               }
+               ck.checkTesteeTest(testee, tested)
+       }
+}
 
-               testName := "Test_" + join(testee.Type, "_", testee.Func)
-               ck.addError(
-                       EMissingTest,
-                       "Missing unit test %q for %q.",
-                       testName, testee.fullName())
+func (ck *TestNameChecker) checkTesteeTest(testee *testee, tested map[*testee]bool) {
+       if tested[testee] || testee.isType() {
+               return
        }
+
+       testName := "Test_" + join(testee.Type, "_", testee.Func)
+       ck.addError(
+               EMissingTest,
+               testee.code,
+               "Missing unit test %q for %q.",
+               testName, testee.fullName())
 }
 
-func (ck *TestNameChecker) isIgnored(filename string) bool {
-       for _, mask := range ck.ignoredFiles {
-               ok, err := filepath.Match(mask, filename)
-               if err != nil {
-                       panic(err)
+// isRelevant checks whether the given error is enabled.
+func (ck *TestNameChecker) isRelevant(filename, typeName, funcName string, e Error) bool {
+       mask := ^uint64(0)
+       for _, filter := range ck.filters {
+               if matches(filename, filter.filenames) &&
+                       matches(typeName, filter.typeNames) &&
+                       matches(funcName, filter.funcNames) {
+                       mask = ck.errorsMask(mask, filter.errors...)
                }
-               if ok {
-                       return true
+       }
+       return mask&ck.errorsMask(0, e) != 0
+}
+
+func (ck *TestNameChecker) errorsMask(mask uint64, errors ...Error) uint64 {
+       for _, err := range errors {
+               if err == ENone {
+                       mask = 0
+               } else if err == EAll {
+                       mask = ^uint64(0)
+               } else if err < 0 {
+                       mask &= ^(uint64(1) << -uint(err))
+               } else {
+                       mask |= uint64(1) << uint(err)
                }
        }
-       return false
+       return mask
 }
 
 // checkOrder ensures that the tests appear in the same order as their
@@ -323,18 +354,22 @@ func (ck *TestNameChecker) checkOrder() 
                                        break
                                }
                        }
+
                        ck.addError(
                                EOrder,
-                               "Test %q should be ordered before %q.",
+                               test.code,
+                               "Test %q must be ordered before %q.",
                                test.fullName(), insertBefore.fullName())
                }
        }
 }
 
-func (ck *TestNameChecker) addError(e Error, format string, args ...interface{}) {
-       if ck.errorsMask&(uint64(1)<<uint(e)) != 0 {
+func (ck *TestNameChecker) addError(e Error, c code, format string, args ...interface{}) bool {
+       relevant := ck.isRelevant(c.file, c.Type, c.Func, e)
+       if relevant {
                ck.errors = append(ck.errors, fmt.Sprintf(format, args...))
        }
+       return relevant
 }
 
 func (ck *TestNameChecker) print() {
@@ -342,23 +377,22 @@ func (ck *TestNameChecker) print() {
                _, _ = fmt.Fprintln(ck.out, msg)
        }
 
-       errors := plural(len(ck.errors), "error", "errors")
-       if len(ck.errors) > 0 {
-               ck.errorf("%s.", errors)
+       n := len(ck.errors)
+       if n > 1 {
+               ck.errorf("%d errors.", n)
+       } else if n == 1 {
+               ck.errorf("%d error.", n)
        }
 }
 
-type code struct {
-       file  string // The file containing the code
-       Type  string // The type, e.g. MkLine
-       Func  string // The function or method name, e.g. Warnf
-       order int    // The relative order in the file
+type filter struct {
+       filenames string
+       typeNames string
+       funcNames string
+       errors    []Error
 }
 
-func (c *code) fullName() string { return join(c.Type, ".", c.Func) }
-
 // testee is an element of the source code that can be tested.
-// It is either a type, a function or a method.
 type testee struct {
        code
 }
@@ -371,15 +405,24 @@ type test struct {
        testee     *testee
 }
 
-func plural(n int, sg, pl string) string {
-       if n == 0 {
-               return ""
-       }
-       form := pl
-       if n == 1 {
-               form = sg
-       }
-       return fmt.Sprintf("%d %s", n, form)
+// code is either a type, a function or a method.
+type code struct {
+       file  string // the file containing the code
+       Type  string // the type, e.g. MkLine
+       Func  string // the function or method name, e.g. Warnf
+       order int    // the relative order in the file
+}
+
+func (c *code) fullName() string { return join(c.Type, ".", c.Func) }
+func (c *code) isFunc() bool     { return c.Type == "" }
+func (c *code) isType() bool     { return c.Func == "" }
+func (c *code) isMethod() bool   { return c.Type != "" && c.Func != "" }
+
+func (c *code) isTest() bool {
+       return c.isTestScope() && strings.HasPrefix(c.Func, "Test")
+}
+func (c *code) isTestScope() bool {
+       return strings.HasSuffix(c.file, "_test.go")
 }
 
 func isCamelCase(str string) bool {
@@ -400,3 +443,21 @@ func join(a, sep, b string) string {
        }
        return a + sep + b
 }
+
+func matches(subj string, pattern string) bool {
+       ok, err := path.Match(pattern, subj)
+       if err != nil {
+               panic(err)
+       }
+       return ok
+}
+
+// sortedKeys returns the sorted keys from an arbitrary map.
+func sortedKeys(m interface{}) []string {
+       var keys []string
+       for _, key := range reflect.ValueOf(m).MapKeys() {
+               keys = append(keys, key.Interface().(string))
+       }
+       sort.Strings(keys)
+       return keys
+}

Index: pkgsrc/pkgtools/pkglint/files/intqa/testnames_test.go
diff -u pkgsrc/pkgtools/pkglint/files/intqa/testnames_test.go:1.2 pkgsrc/pkgtools/pkglint/files/intqa/testnames_test.go:1.3
--- pkgsrc/pkgtools/pkglint/files/intqa/testnames_test.go:1.2   Sun Nov 17 02:06:01 2019
+++ pkgsrc/pkgtools/pkglint/files/intqa/testnames_test.go       Tue Nov 19 06:51:38 2019
@@ -3,8 +3,10 @@ package intqa
 import (
        "bytes"
        "fmt"
+       "go/ast"
        "gopkg.in/check.v1"
        "io/ioutil"
+       "path"
        "testing"
 )
 
@@ -26,7 +28,6 @@ func (s *Suite) Init(c *check.C) *TestNa
 
        s.c = c
        s.ck = NewTestNameChecker(errorf)
-       s.ck.Enable(EAll)
        s.ck.out = ioutil.Discard
        return s.ck
 }
@@ -37,6 +38,25 @@ func (s *Suite) TearDownTest(c *check.C)
        s.CheckSummary("")
 }
 
+func (s *Suite) CheckTestees(testees ...*testee) {
+       s.c.Check(s.ck.testees, check.DeepEquals, testees)
+       s.ck.testees = nil
+}
+
+func (*Suite) newTestee(filename, typeName, funcName string, order int) *testee {
+       return &testee{code{filename, typeName, funcName, order}}
+}
+
+func (s *Suite) CheckTests(tests ...*test) {
+       s.c.Check(s.ck.tests, check.DeepEquals, tests)
+       s.ck.tests = nil
+}
+
+func (*Suite) newTest(filename, typeName, funcName string, order int, testeeName, descr string, testee *testee) *test {
+       c := code{filename, typeName, funcName, order}
+       return &test{c, testeeName, descr, testee}
+}
+
 func (s *Suite) CheckErrors(errors ...string) {
        s.c.Check(s.ck.errors, check.DeepEquals, errors)
        s.ck.errors = nil
@@ -47,51 +67,169 @@ func (s *Suite) CheckSummary(summary str
        s.summary = ""
 }
 
-func (s *Suite) Test_TestNameChecker_Enable(c *check.C) {
+func (s *Suite) Test_NewTestNameChecker(c *check.C) {
+       ck := s.Init(c)
+
+       c.Check(ck.isRelevant("*_test.go", "Suite", "SetUpTest", EAll), check.Equals, true)
+       c.Check(ck.isRelevant("*_test.go", "Suite", "SetUpTest", EMissingTest), check.Equals, false)
+
+       c.Check(ck.isRelevant("*_test.go", "Suite", "TearDownTest", EAll), check.Equals, true)
+       c.Check(ck.isRelevant("*_test.go", "Suite", "TearDownTest", EMissingTest), check.Equals, false)
+}
+
+func (s *Suite) Test_TestNameChecker_Configure(c *check.C) {
        ck := s.Init(c)
 
-       ck.Enable(ENone) // overwrite initialization from Suite.Init
+       ck.Configure("*", "*", "*", ENone) // overwrite initialization from Suite.Init
+
+       c.Check(ck.isRelevant("", "", "", EAll), check.Equals, false)
+       c.Check(ck.isRelevant("", "", "", EMissingTestee), check.Equals, false)
+       c.Check(ck.isRelevant("", "", "", EMissingTest), check.Equals, false)
+
+       ck.Configure("*", "*", "*", EAll)
 
-       c.Check(ck.errorsMask, check.Equals, uint64(0))
+       c.Check(ck.isRelevant("", "", "", EAll), check.Equals, true)
+       c.Check(ck.isRelevant("", "", "", EMissingTestee), check.Equals, true)
+       c.Check(ck.isRelevant("", "", "", EMissingTest), check.Equals, true)
 
-       ck.Enable(EAll)
+       ck.Configure("*", "*", "*", -EMissingTestee)
 
-       c.Check(ck.errorsMask, check.Equals, ^uint64(0))
+       c.Check(ck.isRelevant("", "", "", EAll), check.Equals, true)
+       c.Check(ck.isRelevant("", "", "", EMissingTestee), check.Equals, false)
+       c.Check(ck.isRelevant("", "", "", EMissingTest), check.Equals, true)
+
+       ck.Configure("*", "*", "*", ENone, EMissingTest)
+
+       c.Check(ck.isRelevant("", "", "", EAll), check.Equals, true)
+       c.Check(ck.isRelevant("", "", "", EMissingTestee), check.Equals, false)
+       c.Check(ck.isRelevant("", "", "", EMissingTest), check.Equals, true)
+
+       ck.Configure("*", "*", "*", EAll, -EMissingTest)
+
+       c.Check(ck.isRelevant("", "", "", EAll), check.Equals, true)
+       c.Check(ck.isRelevant("", "", "", EMissingTestee), check.Equals, true)
+       c.Check(ck.isRelevant("", "", "", EMissingTest), check.Equals, false)
+}
 
-       ck.Enable(ENone, EMissingTest)
+func (s *Suite) Test_TestNameChecker_Configure__ignore_single_function(c *check.C) {
+       ck := s.Init(c)
 
-       c.Check(ck.errorsMask, check.Equals, uint64(4))
+       ck.Configure("*", "*", "*", EAll)
 
-       ck.Enable(EAll, -EMissingTest)
+       // The intention of this rule is that this particular function is ignored.
+       // Everything else from that file is still processed.
+       ck.Configure("*_test.go", "", "TestMain", ENone)
 
-       c.Check(ck.errorsMask, check.Equals, ^uint64(0)^4)
+       c.Check(ck.isRelevant("file_test.go", "", "", EAll), check.Equals, true)
+       c.Check(ck.isRelevant("file_test.go", "*", "*", EAll), check.Equals, true)
+       c.Check(ck.isRelevant("file_test.go", "*", "Other", EAll), check.Equals, true)
+       c.Check(ck.isRelevant("file_test.go", "", "TestMain", EAll), check.Equals, false)
+       c.Check(ck.isRelevant("file_test.go", "*", "TestMain", EAll), check.Equals, true)
 }
 
 func (s *Suite) Test_TestNameChecker_Check(c *check.C) {
        ck := s.Init(c)
 
+       ck.Configure("*", "Suite", "*", -EMissingTest)
+
        ck.Check()
 
        s.CheckErrors(
-               "Missing unit test \"Test_NewTestNameChecker\" for \"NewTestNameChecker\".",
-               "Missing unit test \"Test_TestNameChecker_IgnoreFiles\" for \"TestNameChecker.IgnoreFiles\".",
-               "Missing unit test \"Test_TestNameChecker_load\" for \"TestNameChecker.load\".",
-               "Missing unit test \"Test_TestNameChecker_loadDecl\" for \"TestNameChecker.loadDecl\".",
                "Missing unit test \"Test_TestNameChecker_addCode\" for \"TestNameChecker.addCode\".",
-               "Missing unit test \"Test_TestNameChecker_addTestee\" for \"TestNameChecker.addTestee\".",
-               "Missing unit test \"Test_TestNameChecker_nextOrder\" for \"TestNameChecker.nextOrder\".",
                "Missing unit test \"Test_TestNameChecker_relate\" for \"TestNameChecker.relate\".",
-               "Missing unit test \"Test_TestNameChecker_checkTests\" for \"TestNameChecker.checkTests\".",
-               "Missing unit test \"Test_TestNameChecker_checkTestees\" for \"TestNameChecker.checkTestees\".",
-               "Missing unit test \"Test_TestNameChecker_isIgnored\" for \"TestNameChecker.isIgnored\".",
-               "Missing unit test \"Test_TestNameChecker_addError\" for \"TestNameChecker.addError\".",
-               "Missing unit test \"Test_Test\" for \"Test\".",
-               "Missing unit test \"Test_Suite_Init\" for \"Suite.Init\".",
-               "Missing unit test \"Test_Suite_TearDownTest\" for \"Suite.TearDownTest\".",
-               "Missing unit test \"Test_Suite_CheckErrors\" for \"Suite.CheckErrors\".",
-               "Missing unit test \"Test_Suite_CheckSummary\" for \"Suite.CheckSummary\".",
-               "Missing unit test \"Test_Value_Method\" for \"Value.Method\".")
-       s.CheckSummary("18 errors.")
+               "Missing unit test \"Test_TestNameChecker_isRelevant\" for \"TestNameChecker.isRelevant\".")
+       s.CheckSummary("3 errors.")
+}
+
+func (s *Suite) Test_TestNameChecker_load__filtered_nothing(c *check.C) {
+       ck := s.Init(c)
+
+       ck.Configure("*", "*", "*", ENone)
+
+       ck.load(".")
+
+       c.Check(ck.testees, check.IsNil)
+       c.Check(ck.tests, check.IsNil)
+}
+
+func (s *Suite) Test_TestNameChecker_load__filtered_only_Value(c *check.C) {
+       ck := s.Init(c)
+
+       ck.Configure("*", "*", "*", ENone)
+       ck.Configure("*", "Value", "*", EAll)
+
+       ck.load(".")
+
+       c.Check(ck.testees, check.DeepEquals, []*testee{
+               {code{"testnames_test.go", "Value", "", 0}},
+               {code{"testnames_test.go", "Value", "Method", 1}}})
+       c.Check(ck.tests, check.IsNil)
+}
+
+func (s *Suite) Test_TestNameChecker_load__panic(c *check.C) {
+       ck := s.Init(c)
+
+       c.Check(
+               func() { ck.load("does-not-exist") },
+               check.PanicMatches,
+               `^open does-not-exist\b.*`)
+}
+
+func (s *Suite) Test_TestNameChecker_loadDecl(c *check.C) {
+       ck := s.Init(c)
+
+       typeDecl := func(name string) *ast.GenDecl {
+               return &ast.GenDecl{Specs: []ast.Spec{&ast.TypeSpec{Name: &ast.Ident{Name: name}}}}
+       }
+       funcDecl := func(name string) *ast.FuncDecl {
+               return &ast.FuncDecl{Name: &ast.Ident{Name: name}}
+       }
+       methodDecl := func(typeName, methodName string) *ast.FuncDecl {
+               return &ast.FuncDecl{
+                       Name: &ast.Ident{Name: methodName},
+                       Recv: &ast.FieldList{List: []*ast.Field{{Type: &ast.Ident{Name: typeName}}}}}
+       }
+
+       ck.loadDecl(typeDecl("TypeName"), "file_test.go")
+
+       s.CheckTestees(
+               s.newTestee("file_test.go", "TypeName", "", 0))
+
+       // The freestanding TestMain function is ignored by a hardcoded rule,
+       // independently of the configuration.
+       ck.loadDecl(funcDecl("TestMain"), "file_test.go")
+
+       // The TestMain method on a type is relevant, but violates the naming rule.
+       // Therefore it is ignored.
+       ck.loadDecl(methodDecl("Suite", "TestMain"), "file_test.go")
+
+       s.CheckTests(
+               nil...)
+       s.CheckErrors(
+               "Test \"Suite.TestMain\" must start with \"Test_\".")
+
+       // The above error can be disabled, and then the method is handled
+       // like any other test method.
+       ck.Configure("*", "Suite", "*", -EName)
+       ck.loadDecl(methodDecl("Suite", "TestMain"), "file_test.go")
+
+       s.CheckTests(
+               s.newTest("file_test.go", "Suite", "TestMain", 1, "Main", "", nil))
+
+       // There is no special handling for TestMain method with a description.
+       ck.loadDecl(methodDecl("Suite", "TestMain__descr"), "file_test.go")
+
+       s.CheckTests(
+               s.newTest("file_test.go", "Suite", "TestMain__descr", 2, "Main", "descr", nil))
+}
+
+func (s *Suite) Test_TestNameChecker_addTestee(c *check.C) {
+       ck := s.Init(c)
+
+       code := code{"filename.go", "Type", "Method", 0}
+       ck.addTestee(code)
+
+       c.Check(ck.testees, check.DeepEquals, []*testee{{code}})
 }
 
 func (s *Suite) Test_TestNameChecker_addTest(c *check.C) {
@@ -99,6 +237,7 @@ func (s *Suite) Test_TestNameChecker_add
 
        ck.addTest(code{"filename.go", "Type", "Method", 0})
 
+       c.Check(ck.tests, check.IsNil)
        s.CheckErrors(
                "Test \"Type.Method\" must start with \"Test_\".")
 }
@@ -106,10 +245,56 @@ func (s *Suite) Test_TestNameChecker_add
 func (s *Suite) Test_TestNameChecker_addTest__empty_description(c *check.C) {
        ck := s.Init(c)
 
-       ck.addTest(code{"filename.go", "Suite", "Test_Method__", 0})
+       ck.addTest(code{"f_test.go", "Suite", "Test_Method__", 0})
+
+       s.CheckErrors(
+               "Test \"Suite.Test_Method__\" must have a nonempty description.")
+
+       // The test is not registered and thus cannot complain about its missing
+       // testee.
+       ck.checkTests()
+
+       s.CheckErrors(
+               nil...)
+}
+
+func (s *Suite) Test_TestNameChecker_addTest__suppressed_empty_description(c *check.C) {
+       ck := s.Init(c)
+
+       ck.Configure("*", "*", "*", -EName)
+       ck.addTest(code{"f_test.go", "Suite", "Test_Method__", 0})
+
+       s.CheckErrors(
+               nil...)
+
+       // Since there was no error above, the test is added normally
+       // and can complain about its missing testee.
+       ck.checkTests()
+
+       s.CheckErrors(
+               "Missing testee \"Method\" for test \"Suite.Test_Method__\".")
+}
+
+func (s *Suite) Test_TestNameChecker_nextOrder(c *check.C) {
+       ck := s.Init(c)
+
+       c.Check(ck.nextOrder(), check.Equals, 0)
+       c.Check(ck.nextOrder(), check.Equals, 1)
+       c.Check(ck.nextOrder(), check.Equals, 2)
+}
+
+func (s *Suite) Test_TestNameChecker_checkTests(c *check.C) {
+       ck := s.Init(c)
+
+       ck.tests = append(ck.tests,
+               s.newTest("wrong_test.go", "", "Test_Func", 0, "Func", "",
+                       s.newTestee("source.go", "", "Func", 1)))
+
+       ck.checkTests()
 
        s.CheckErrors(
-               "Test \"Suite.Test_Method__\" must not have a nonempty description.")
+               "Test \"Test_Func\" for \"Func\" " +
+                       "must be in source_test.go instead of wrong_test.go.")
 }
 
 func (s *Suite) Test_TestNameChecker_checkTestFile__global(c *check.C) {
@@ -165,10 +350,10 @@ func (s *Suite) Test_TestNameChecker_che
                nil...)
 }
 
-func (s *Suite) Test_TestNameChecker_checkTestName__camel_case(c *check.C) {
+func (s *Suite) Test_TestNameChecker_checkTestDescr__camel_case(c *check.C) {
        ck := s.Init(c)
 
-       ck.checkTestName(&test{
+       ck.checkTestDescr(&test{
                code{"demo_test.go", "Suite", "Test_Missing__CamelCase", 0},
                "Missing",
                "CamelCase",
@@ -179,6 +364,45 @@ func (s *Suite) Test_TestNameChecker_che
                        "must not use CamelCase in the first word.")
 }
 
+func (s *Suite) Test_TestNameChecker_checkTestees(c *check.C) {
+       ck := s.Init(c)
+
+       ck.testees = []*testee{s.newTestee("s.go", "", "Func", 0)}
+       ck.tests = nil // force an error
+
+       ck.checkTestees()
+
+       s.CheckErrors(
+               "Missing unit test \"Test_Func\" for \"Func\".")
+}
+
+func (s *Suite) Test_TestNameChecker_checkTesteeTest(c *check.C) {
+       ck := s.Init(c)
+
+       ck.checkTesteeTest(
+               &testee{code{"demo.go", "Type", "", 0}},
+               nil)
+       ck.checkTesteeTest(
+               &testee{code{"demo.go", "", "Func", 0}},
+               nil)
+       ck.checkTesteeTest(
+               &testee{code{"demo.go", "Type", "Method", 0}},
+               nil)
+
+       s.CheckErrors(
+               "Missing unit test \"Test_Func\" for \"Func\".",
+               "Missing unit test \"Test_Type_Method\" for \"Type.Method\".")
+}
+
+func (s *Suite) Test_TestNameChecker_errorsMask(c *check.C) {
+       ck := s.Init(c)
+
+       c.Check(ck.errorsMask(0, EAll), check.Equals, ^uint64(0))
+       c.Check(ck.errorsMask(12345, ENone), check.Equals, uint64(0))
+       c.Check(ck.errorsMask(12345, ENone, EMissingTest), check.Equals, uint64(8))
+       c.Check(ck.errorsMask(2, EMissingTest), check.Equals, uint64(10))
+}
+
 func (s *Suite) Test_TestNameChecker_checkOrder(c *check.C) {
        ck := s.Init(c)
 
@@ -186,6 +410,8 @@ func (s *Suite) Test_TestNameChecker_che
        ck.addTestee(code{"f.go", "T", "M1", 11})
        ck.addTestee(code{"f.go", "T", "M2", 12})
        ck.addTestee(code{"f.go", "T", "M3", 13})
+       ck.addTest(code{"a_test.go", "S", "Test_A", 98})        // different file, is skipped
+       ck.addTest(code{"f_test.go", "S", "Test_Missing", 99})  // missing testee, is skipped
        ck.addTest(code{"f_test.go", "S", "Test_T_M1", 100})    // maxTestee = 11
        ck.addTest(code{"f_test.go", "S", "Test_T_M2", 101})    // maxTestee = 12
        ck.addTest(code{"f_test.go", "S", "Test_T", 102})       // testee 10 < maxTestee 12: insert before first [.testee > testee 10] == T_M1
@@ -198,10 +424,23 @@ func (s *Suite) Test_TestNameChecker_che
        ck.checkOrder()
 
        s.CheckErrors(
-               "Test \"S.Test_T\" should be ordered before \"S.Test_T_M1\".",
-               "Test \"S.Test_T__1\" should be ordered before \"S.Test_T_M1\".",
-               "Test \"S.Test_T__2\" should be ordered before \"S.Test_T_M1\".",
-               "Test \"S.Test_T_M2__1\" should be ordered before \"S.Test_T_M3\".")
+               "Test \"S.Test_T\" must be ordered before \"S.Test_T_M1\".",
+               "Test \"S.Test_T__1\" must be ordered before \"S.Test_T_M1\".",
+               "Test \"S.Test_T__2\" must be ordered before \"S.Test_T_M1\".",
+               "Test \"S.Test_T_M2__1\" must be ordered before \"S.Test_T_M3\".")
+}
+
+func (s *Suite) Test_TestNameChecker_addError(c *check.C) {
+       ck := s.Init(c)
+
+       ck.Configure("ignored*", "*", "*", -EName)
+       ok1 := ck.addError(EName, code{"ignored.go", "", "Func", 0}, "E1")
+       ok2 := ck.addError(EName, code{"reported.go", "", "Func", 0}, "E2")
+
+       c.Check(ok1, check.Equals, false)
+       c.Check(ok2, check.Equals, true)
+       s.CheckErrors(
+               "E2")
 }
 
 func (s *Suite) Test_TestNameChecker_print__empty(c *check.C) {
@@ -214,12 +453,12 @@ func (s *Suite) Test_TestNameChecker_pri
        c.Check(out.String(), check.Equals, "")
 }
 
-func (s *Suite) Test_TestNameChecker_print__errors(c *check.C) {
+func (s *Suite) Test_TestNameChecker_print__1_error(c *check.C) {
        var out bytes.Buffer
        ck := s.Init(c)
        ck.out = &out
+       ck.addError(EName, code{}, "1")
 
-       ck.addError(EName, "1")
        ck.print()
 
        c.Check(out.String(), check.Equals, "1\n")
@@ -227,6 +466,20 @@ func (s *Suite) Test_TestNameChecker_pri
        s.CheckSummary("1 error.")
 }
 
+func (s *Suite) Test_TestNameChecker_print__2_errors(c *check.C) {
+       var out bytes.Buffer
+       ck := s.Init(c)
+       ck.out = &out
+       ck.addError(EName, code{}, "1")
+       ck.addError(EName, code{}, "2")
+
+       ck.print()
+
+       c.Check(out.String(), check.Equals, "1\n2\n")
+       s.CheckErrors("1", "2")
+       s.CheckSummary("2 errors.")
+}
+
 func (s *Suite) Test_code_fullName(c *check.C) {
        _ = s.Init(c)
 
@@ -240,13 +493,77 @@ func (s *Suite) Test_code_fullName(c *ch
        test("Type", "Method", "Type.Method")
 }
 
-func (s *Suite) Test_plural(c *check.C) {
+func (s *Suite) Test_code_isFunc(c *check.C) {
        _ = s.Init(c)
 
-       c.Check(plural(0, "singular", "plural"), check.Equals, "")
-       c.Check(plural(1, "singular", "plural"), check.Equals, "1 singular")
-       c.Check(plural(2, "singular", "plural"), check.Equals, "2 plural")
-       c.Check(plural(1000, "singular", "plural"), check.Equals, "1000 plural")
+       test := func(typeName, funcName string, isFunc bool) {
+               code := code{"filename", typeName, funcName, 0}
+               c.Check(code.isFunc(), check.Equals, isFunc)
+       }
+
+       test("Type", "", false)
+       test("", "Func", true)
+       test("Type", "Method", false)
+}
+
+func (s *Suite) Test_code_isType(c *check.C) {
+       _ = s.Init(c)
+
+       test := func(typeName, funcName string, isType bool) {
+               code := code{"filename", typeName, funcName, 0}
+               c.Check(code.isType(), check.Equals, isType)
+       }
+
+       test("Type", "", true)
+       test("", "Func", false)
+       test("Type", "Method", false)
+}
+
+func (s *Suite) Test_code_isMethod(c *check.C) {
+       _ = s.Init(c)
+
+       test := func(typeName, funcName string, isMethod bool) {
+               code := code{"filename", typeName, funcName, 0}
+               c.Check(code.isMethod(), check.Equals, isMethod)
+       }
+
+       test("Type", "", false)
+       test("", "Func", false)
+       test("Type", "Method", true)
+}
+
+func (s *Suite) Test_code_isTest(c *check.C) {
+       _ = s.Init(c)
+
+       test := func(filename, typeName, funcName string, isTest bool) {
+               code := code{filename, typeName, funcName, 0}
+               c.Check(code.isTest(), check.Equals, isTest)
+       }
+
+       test("f.go", "Type", "", false)
+       test("f.go", "", "Func", false)
+       test("f.go", "Type", "Method", false)
+       test("f.go", "Type", "Test", false)
+       test("f.go", "Type", "Test_Type_Method", false)
+       test("f.go", "", "Test_Type_Method", false)
+       test("f_test.go", "Type", "Test", true)
+       test("f_test.go", "Type", "Test_Type_Method", true)
+       test("f_test.go", "", "Test_Type_Method", true)
+}
+
+func (s *Suite) Test_code_isTestScope(c *check.C) {
+       _ = s.Init(c)
+
+       test := func(filename string, isTestScope bool) {
+               code := code{filename, "", "", 0}
+               c.Check(code.isTestScope(), check.Equals, isTestScope)
+       }
+
+       test("f.go", false)
+       test("test.go", false)
+       test("_test.go", true)
+       test("file_test.go", true)
+       test("file_linux_test.go", true)
 }
 
 func (s *Suite) Test_isCamelCase(c *check.C) {
@@ -273,6 +590,37 @@ func (s *Suite) Test_join(c *check.C) {
        c.Check(join("one", " and ", "two"), check.Equals, "one and two")
 }
 
+func (s *Suite) Test_matches(c *check.C) {
+       _ = s.Init(c)
+
+       c.Check(matches("*", "*"), check.Equals, true)
+       c.Check(matches("anything", "*"), check.Equals, true)
+       c.Check(matches("*", "anything"), check.Equals, false)
+       c.Check(func() { matches("any", "[") }, check.Panics, path.ErrBadPattern)
+}
+
+func (s *Suite) Test_sortedKeys(c *check.C) {
+       _ = s.Init(c)
+
+       m := make(map[string]uint8)
+       m["first"] = 1
+       m["second"] = 2
+       m["third"] = 3
+       m["fourth"] = 4
+
+       c.Check(
+               sortedKeys(m),
+               check.DeepEquals,
+               []string{"first", "fourth", "second", "third"})
+}
+
+func (s *Suite) Test_Value_Method(c *check.C) {
+       _ = s.Init(c)
+
+       // Just for code coverage of checkTestFile, to have a piece of code
+       // that lives in the same file as its test.
+}
+
 type Value struct{}
 
 // Method has no star on the receiver,

Index: pkgsrc/pkgtools/pkglint/files/licenses/licenses_test.go
diff -u pkgsrc/pkgtools/pkglint/files/licenses/licenses_test.go:1.6 pkgsrc/pkgtools/pkglint/files/licenses/licenses_test.go:1.7
--- pkgsrc/pkgtools/pkglint/files/licenses/licenses_test.go:1.6 Sun Nov 17 01:26:26 2019
+++ pkgsrc/pkgtools/pkglint/files/licenses/licenses_test.go     Tue Nov 19 06:51:38 2019
@@ -133,6 +133,6 @@ func Test(t *testing.T) {
 
 func (s *Suite) Test__test_names(c *check.C) {
        ck := intqa.NewTestNameChecker(c.Errorf)
-       ck.Enable(intqa.EAll, -intqa.EMissingTest)
+       ck.Configure("*", "*", "*", -intqa.EMissingTest)
        ck.Check()
 }

Index: pkgsrc/pkgtools/pkglint/files/pkgver/vercmp_test.go
diff -u pkgsrc/pkgtools/pkglint/files/pkgver/vercmp_test.go:1.6 pkgsrc/pkgtools/pkglint/files/pkgver/vercmp_test.go:1.7
--- pkgsrc/pkgtools/pkglint/files/pkgver/vercmp_test.go:1.6     Sun Nov 17 01:26:26 2019
+++ pkgsrc/pkgtools/pkglint/files/pkgver/vercmp_test.go Tue Nov 19 06:51:38 2019
@@ -95,6 +95,6 @@ func (s *Suite) Test_newVersion(c *check
 
 func (s *Suite) Test__test_names(c *check.C) {
        ck := intqa.NewTestNameChecker(c.Errorf)
-       ck.Enable(intqa.EAll, -intqa.EMissingTest)
+       ck.Configure("*", "*", "*", -intqa.EMissingTest)
        ck.Check()
 }

Index: pkgsrc/pkgtools/pkglint/files/textproc/lexer_test.go
diff -u pkgsrc/pkgtools/pkglint/files/textproc/lexer_test.go:1.7 pkgsrc/pkgtools/pkglint/files/textproc/lexer_test.go:1.8
--- pkgsrc/pkgtools/pkglint/files/textproc/lexer_test.go:1.7    Sun Nov 17 01:26:26 2019
+++ pkgsrc/pkgtools/pkglint/files/textproc/lexer_test.go        Tue Nov 19 06:51:39 2019
@@ -415,6 +415,6 @@ func (s *Suite) Test__Alpha(c *check.C) 
 
 func (s *Suite) Test__test_names(c *check.C) {
        ck := intqa.NewTestNameChecker(c.Errorf)
-       ck.Enable(intqa.EAll, -intqa.EMissingTest)
+       ck.Configure("*", "*", "*", -intqa.EMissingTest)
        ck.Check()
 }

Index: pkgsrc/pkgtools/pkglint/files/trace/tracing_test.go
diff -u pkgsrc/pkgtools/pkglint/files/trace/tracing_test.go:1.4 pkgsrc/pkgtools/pkglint/files/trace/tracing_test.go:1.5
--- pkgsrc/pkgtools/pkglint/files/trace/tracing_test.go:1.4     Sun Nov 17 01:26:26 2019
+++ pkgsrc/pkgtools/pkglint/files/trace/tracing_test.go Tue Nov 19 06:51:39 2019
@@ -145,6 +145,6 @@ func (str) String() string {
 
 func (s *Suite) Test__test_names(c *check.C) {
        ck := intqa.NewTestNameChecker(c.Errorf)
-       ck.Enable(intqa.EAll, -intqa.EMissingTest)
+       ck.Configure("*", "*", "*", -intqa.EMissingTest)
        ck.Check()
 }



Home | Main Index | Thread Index | Old Index