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:           Sat Jan 27 18:50:37 UTC 2018

Modified Files:
        pkgsrc/pkgtools/pkglint: Makefile
        pkgsrc/pkgtools/pkglint/files: autofix.go autofix_test.go
            buildlink3_test.go category_test.go check_test.go distinfo.go
            distinfo_test.go files.go files_test.go globaldata_test.go
            licenses_test.go line.go linechecker_test.go logging.go
            logging_test.go mkline.go mkline_test.go mklinechecker_test.go
            mklines.go mklines_test.go mkparser_test.go mkshwalker_test.go
            package.go package_test.go parser_test.go patches_test.go
            pkglint.go pkglint_test.go plist.go plist_test.go shell_test.go
            shtokenizer_test.go substcontext_test.go toplevel_test.go
            tree_test.go util.go util_test.go vardefs.go vartypecheck_test.go
        pkgsrc/pkgtools/pkglint/files/getopt: getopt.go getopt_test.go
Added Files:
        pkgsrc/pkgtools/pkglint/files: mklines_varalign_test.go

Log Message:
pkgtools/pkglint: Update to 5.5.2

Changes since 5.5.1:

* Fixed command line parsing for the --only option.
* Improved alignment of variable values in Makefiles.
* Code cleanup: better abstraction in the tests.


To generate a diff of this commit:
cvs rdiff -u -r1.525 -r1.526 pkgsrc/pkgtools/pkglint/Makefile
cvs rdiff -u -r1.1 -r1.2 pkgsrc/pkgtools/pkglint/files/autofix.go \
    pkgsrc/pkgtools/pkglint/files/autofix_test.go \
    pkgsrc/pkgtools/pkglint/files/logging_test.go \
    pkgsrc/pkgtools/pkglint/files/mkshwalker_test.go
cvs rdiff -u -r1.10 -r1.11 pkgsrc/pkgtools/pkglint/files/buildlink3_test.go \
    pkgsrc/pkgtools/pkglint/files/substcontext_test.go
cvs rdiff -u -r1.6 -r1.7 pkgsrc/pkgtools/pkglint/files/category_test.go \
    pkgsrc/pkgtools/pkglint/files/parser_test.go
cvs rdiff -u -r1.15 -r1.16 pkgsrc/pkgtools/pkglint/files/check_test.go \
    pkgsrc/pkgtools/pkglint/files/mklines_test.go
cvs rdiff -u -r1.17 -r1.18 pkgsrc/pkgtools/pkglint/files/distinfo.go
cvs rdiff -u -r1.11 -r1.12 pkgsrc/pkgtools/pkglint/files/distinfo_test.go
cvs rdiff -u -r1.13 -r1.14 pkgsrc/pkgtools/pkglint/files/files.go \
    pkgsrc/pkgtools/pkglint/files/patches_test.go
cvs rdiff -u -r1.12 -r1.13 pkgsrc/pkgtools/pkglint/files/files_test.go \
    pkgsrc/pkgtools/pkglint/files/globaldata_test.go \
    pkgsrc/pkgtools/pkglint/files/pkglint_test.go
cvs rdiff -u -r1.9 -r1.10 pkgsrc/pkgtools/pkglint/files/licenses_test.go \
    pkgsrc/pkgtools/pkglint/files/logging.go
cvs rdiff -u -r1.19 -r1.20 pkgsrc/pkgtools/pkglint/files/line.go \
    pkgsrc/pkgtools/pkglint/files/plist.go \
    pkgsrc/pkgtools/pkglint/files/shell_test.go
cvs rdiff -u -r1.5 -r1.6 pkgsrc/pkgtools/pkglint/files/linechecker_test.go \
    pkgsrc/pkgtools/pkglint/files/shtokenizer_test.go
cvs rdiff -u -r1.25 -r1.26 pkgsrc/pkgtools/pkglint/files/mkline.go
cvs rdiff -u -r1.28 -r1.29 pkgsrc/pkgtools/pkglint/files/mkline_test.go
cvs rdiff -u -r1.4 -r1.5 pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go
cvs rdiff -u -r1.18 -r1.19 pkgsrc/pkgtools/pkglint/files/mklines.go \
    pkgsrc/pkgtools/pkglint/files/plist_test.go \
    pkgsrc/pkgtools/pkglint/files/util.go
cvs rdiff -u -r0 -r1.1 pkgsrc/pkgtools/pkglint/files/mklines_varalign_test.go
cvs rdiff -u -r1.7 -r1.8 pkgsrc/pkgtools/pkglint/files/mkparser_test.go \
    pkgsrc/pkgtools/pkglint/files/toplevel_test.go
cvs rdiff -u -r1.23 -r1.24 pkgsrc/pkgtools/pkglint/files/package.go
cvs rdiff -u -r1.16 -r1.17 pkgsrc/pkgtools/pkglint/files/package_test.go
cvs rdiff -u -r1.24 -r1.25 pkgsrc/pkgtools/pkglint/files/pkglint.go
cvs rdiff -u -r1.3 -r1.4 pkgsrc/pkgtools/pkglint/files/tree_test.go
cvs rdiff -u -r1.8 -r1.9 pkgsrc/pkgtools/pkglint/files/util_test.go
cvs rdiff -u -r1.34 -r1.35 pkgsrc/pkgtools/pkglint/files/vardefs.go
cvs rdiff -u -r1.20 -r1.21 pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go
cvs rdiff -u -r1.3 -r1.4 pkgsrc/pkgtools/pkglint/files/getopt/getopt.go \
    pkgsrc/pkgtools/pkglint/files/getopt/getopt_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.525 pkgsrc/pkgtools/pkglint/Makefile:1.526
--- pkgsrc/pkgtools/pkglint/Makefile:1.525      Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/Makefile    Sat Jan 27 18:50:36 2018
@@ -1,6 +1,6 @@
-# $NetBSD: Makefile,v 1.525 2018/01/13 23:56:14 rillig Exp $
+# $NetBSD: Makefile,v 1.526 2018/01/27 18:50:36 rillig Exp $
 
-PKGNAME=       pkglint-5.5.1
+PKGNAME=       pkglint-5.5.2
 DISTFILES=     # none
 CATEGORIES=    pkgtools
 

Index: pkgsrc/pkgtools/pkglint/files/autofix.go
diff -u pkgsrc/pkgtools/pkglint/files/autofix.go:1.1 pkgsrc/pkgtools/pkglint/files/autofix.go:1.2
--- pkgsrc/pkgtools/pkglint/files/autofix.go:1.1        Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/autofix.go    Sat Jan 27 18:50:36 2018
@@ -6,6 +6,7 @@ import (
        "netbsd.org/pkglint/regex"
        "netbsd.org/pkglint/trace"
        "os"
+       "strconv"
        "strings"
 )
 
@@ -15,16 +16,20 @@ import (
 // until they are written to disk by SaveAutofixChanges.
 type Autofix struct {
        line        Line
-       linesBefore []string      // Newly inserted lines, including \n
-       lines       []*RawLine    // Original lines, available for diff
-       linesAfter  []string      // Newly inserted lines, including \n
-       modified    bool          // Modified in memory, but not necessarily written back to disk
-       descrFormat string        // Human-readable description of the latest modification
-       descrArgs   []interface{} //
-       level       *LogLevel     //
-       diagFormat  string        // Is printed only if it couldn't be fixed automatically
-       diagArgs    []interface{} //
-       explanation []string      // Is printed together with the diagnostic
+       linesBefore []string        // Newly inserted lines, including \n
+       lines       []*RawLine      // Original lines, available for diff
+       linesAfter  []string        // Newly inserted lines, including \n
+       modified    bool            // Modified in memory, but not necessarily written back to disk
+       actions     []autofixAction // Human-readable description of the actual autofix actions
+       level       *LogLevel       //
+       diagFormat  string          // Is printed only if it couldn't be fixed automatically
+       diagArgs    []interface{}   //
+       explanation []string        // Is printed together with the diagnostic
+}
+
+type autofixAction struct {
+       description string
+       lineno      int
 }
 
 func NewAutofix(line Line) *Autofix {
@@ -34,17 +39,24 @@ func NewAutofix(line Line) *Autofix {
 }
 
 func (fix *Autofix) Replace(from string, to string) {
+       fix.ReplaceAfter("", from, to)
+}
+
+// ReplaceAfter replaces the text "prefix+from" with "prefix+to",
+// but in the diagnostic, only the replacement of "from" with "to"
+// is mentioned.
+func (fix *Autofix) ReplaceAfter(prefix, from string, to string) {
        if fix.skip() {
                return
        }
 
        for _, rawLine := range fix.lines {
                if rawLine.Lineno != 0 {
-                       if replaced := strings.Replace(rawLine.textnl, from, to, 1); replaced != rawLine.textnl {
+                       if replaced := strings.Replace(rawLine.textnl, prefix+from, prefix+to, 1); replaced != rawLine.textnl {
                                if G.opts.PrintAutofix || G.opts.Autofix {
                                        rawLine.textnl = replaced
                                }
-                               fix.Describef("Replacing %q with %q.", from, to)
+                               fix.Describef(rawLine.Lineno, "Replacing %q with %q.", from, to)
                        }
                }
        }
@@ -61,19 +73,71 @@ func (fix *Autofix) ReplaceRegex(from re
                                if G.opts.PrintAutofix || G.opts.Autofix {
                                        rawLine.textnl = replaced
                                }
-                               fix.Describef("Replacing regular expression %q with %q.", from, to)
+                               fix.Describef(rawLine.Lineno, "Replacing regular expression %q with %q.", from, to)
                        }
                }
        }
 }
 
+func (fix *Autofix) Realign(mkline MkLine, newWidth int) {
+       if fix.skip() || !mkline.IsMultiline() || !mkline.IsVarassign() {
+               return
+       }
+
+       normalized := true // Whether all indentation is tabs, followed by spaces.
+       oldWidth := 0      // The minimum required indentation in the original lines.
+
+       {
+               // Interpreting the continuation marker as variable value
+               // is cheating, but works well.
+               m, _, _, _, valueAlign, value, _, _ := MatchVarassign(mkline.raw[0].orignl)
+               if m && value != "\\" {
+                       oldWidth = tabWidth(valueAlign)
+               }
+       }
+
+       for _, rawLine := range fix.lines[1:] {
+               _, space := regex.Match1(rawLine.textnl, `^(\s*)`)
+               width := tabWidth(space)
+               if oldWidth == 0 || width < oldWidth {
+                       oldWidth = width
+               }
+               if !regex.Matches(space, `^\t*\s{0,7}`) {
+                       normalized = false
+               }
+       }
+
+       if normalized && newWidth == oldWidth {
+               return
+       }
+
+       // Continuation lines with the minimal unambiguous indentation
+       // attempt to keep the indentation as small as possible, so don't
+       // realign them.
+       if oldWidth == 8 {
+               return
+       }
+
+       for _, rawLine := range fix.lines[1:] {
+               _, oldSpace := regex.Match1(rawLine.textnl, `^(\s*)`)
+               newWidth := tabWidth(oldSpace) - oldWidth + newWidth
+               newSpace := strings.Repeat("\t", newWidth/8) + strings.Repeat(" ", newWidth%8)
+               if replaced := strings.Replace(rawLine.textnl, oldSpace, newSpace, 1); replaced != rawLine.textnl {
+                       if G.opts.PrintAutofix || G.opts.Autofix {
+                               rawLine.textnl = replaced
+                       }
+                       fix.Describef(rawLine.Lineno, "Replacing indentation %q with %q.", oldSpace, newSpace)
+               }
+       }
+}
+
 func (fix *Autofix) InsertBefore(text string) {
        if fix.skip() {
                return
        }
 
        fix.linesBefore = append(fix.linesBefore, text+"\n")
-       fix.Describef("Inserting a line %q before this line.", text)
+       fix.Describef(fix.lines[0].Lineno, "Inserting a line %q before this line.", text)
 }
 
 func (fix *Autofix) InsertAfter(text string) {
@@ -82,7 +146,7 @@ func (fix *Autofix) InsertAfter(text str
        }
 
        fix.linesAfter = append(fix.linesAfter, text+"\n")
-       fix.Describef("Inserting a line %q after this line.", text)
+       fix.Describef(fix.lines[len(fix.lines)-1].Lineno, "Inserting a line %q after this line.", text)
 }
 
 func (fix *Autofix) Delete() {
@@ -91,34 +155,40 @@ func (fix *Autofix) Delete() {
        }
 
        for _, line := range fix.lines {
+               fix.Describef(line.Lineno, "Deleting this line.")
                line.textnl = ""
        }
-       fix.Describef("Deleting this line.")
 }
 
-func (fix *Autofix) Describef(format string, args ...interface{}) {
-       fix.descrFormat = format
-       fix.descrArgs = args
+// Describef remembers a description of the actual fix
+// for logging it later when Apply is called.
+// There may be multiple fixes in one pass.
+func (fix *Autofix) Describef(lineno int, format string, args ...interface{}) {
+       fix.actions = append(fix.actions, autofixAction{fmt.Sprintf(format, args...), lineno})
 }
 
+// Notef remembers the note for logging it later when Apply is called.
 func (fix *Autofix) Notef(format string, args ...interface{}) {
        fix.level = llNote
        fix.diagFormat = format
        fix.diagArgs = args
 }
 
+// Notef remembers the warning for logging it later when Apply is called.
 func (fix *Autofix) Warnf(format string, args ...interface{}) {
        fix.level = llWarn
        fix.diagFormat = format
        fix.diagArgs = args
 }
 
+// Notef remembers the error for logging it later when Apply is called.
 func (fix *Autofix) Errorf(format string, args ...interface{}) {
        fix.level = llError
        fix.diagFormat = format
        fix.diagArgs = args
 }
 
+// Explain remembers the explanation for logging it later when Apply is called.
 func (fix *Autofix) Explain(explanation ...string) {
        fix.explanation = explanation
 }
@@ -134,17 +204,19 @@ func (fix *Autofix) Apply() {
                return
        }
 
-       if shallBeLogged(fix.diagFormat) && fix.descrFormat != "" {
-               logDiagnostic := fix.level != nil && fix.diagFormat != "Silent-Magic-Diagnostic" && !G.opts.Autofix
+       if shallBeLogged(fix.diagFormat) {
+               logDiagnostic := fix.level != nil && fix.diagFormat != "Silent-Magic-Diagnostic" &&
+                       !(G.opts.Autofix && !G.opts.PrintAutofix) && len(fix.actions) > 0
                if logDiagnostic {
                        msg := fmt.Sprintf(fix.diagFormat, fix.diagArgs...)
                        logs(fix.level, line.Filename, line.Linenos(), fix.diagFormat, msg)
                }
 
-               logRepair := G.opts.Autofix || G.opts.PrintAutofix
+               logRepair := len(fix.actions) > 0 && (G.opts.Autofix || G.opts.PrintAutofix)
                if logRepair {
-                       msg := fmt.Sprintf(fix.descrFormat, fix.descrArgs...)
-                       logs(llAutofix, line.Filename, line.Linenos(), "", msg)
+                       for _, action := range fix.actions {
+                               logs(llAutofix, line.Filename, strconv.Itoa(action.lineno), "", action.description)
+                       }
                }
 
                if logDiagnostic || logRepair {
@@ -157,10 +229,9 @@ func (fix *Autofix) Apply() {
                }
        }
 
-       fix.modified = fix.modified || fix.descrFormat != ""
+       fix.modified = fix.modified || len(fix.actions) > 0
 
-       fix.descrFormat = ""
-       fix.descrArgs = nil
+       fix.actions = nil
        fix.level = nil
        fix.diagFormat = ""
        fix.diagArgs = nil
@@ -168,6 +239,7 @@ func (fix *Autofix) Apply() {
 }
 
 func (fix *Autofix) skip() bool {
+       // This check is necessary for the --only command line option.
        if fix.diagFormat == "" {
                panic("Autofix: The diagnostic must be given before the action.")
        }
@@ -230,8 +302,6 @@ func SaveAutofixChanges(lines []Line) (a
                        NewLineWhole(fname).Errorf("Cannot overwrite with auto-fixed content.")
                        continue
                }
-               msg := "Has been auto-fixed. Please re-run pkglint."
-               logs(llAutofix, fname, "", msg, msg)
                autofixed = true
        }
        return
Index: pkgsrc/pkgtools/pkglint/files/autofix_test.go
diff -u pkgsrc/pkgtools/pkglint/files/autofix_test.go:1.1 pkgsrc/pkgtools/pkglint/files/autofix_test.go:1.2
--- pkgsrc/pkgtools/pkglint/files/autofix_test.go:1.1   Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/autofix_test.go       Sat Jan 27 18:50:36 2018
@@ -3,13 +3,13 @@ package main
 import "gopkg.in/check.v1"
 
 func (s *Suite) Test_Autofix_ReplaceRegex(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("--show-autofix")
-       fname := s.CreateTmpFile("Makefile", ""+
-               "line1\n"+
-               "line2\n"+
-               "line3\n")
-       lines := LoadExistingLines(fname, true)
+       t := s.Init(c)
+
+       t.SetupCommandLine("--show-autofix")
+       lines := t.SetupFileLines("Makefile",
+               "line1",
+               "line2",
+               "line3")
 
        fix := lines[1].Autofix()
        fix.Warnf("Something's wrong here.")
@@ -18,20 +18,23 @@ func (s *Suite) Test_Autofix_ReplaceRege
        SaveAutofixChanges(lines)
 
        c.Check(lines[1].raw[0].textnl, equals, "XXXXX\n")
-       c.Check(s.LoadTmpFile("Makefile"), equals, "line1\nline2\nline3\n")
-       s.CheckOutputLines(
+       t.CheckFileLines("Makefile",
+               "line1",
+               "line2",
+               "line3")
+       t.CheckOutputLines(
                "WARN: ~/Makefile:2: Something's wrong here.",
                "AUTOFIX: ~/Makefile:2: Replacing regular expression \".\" with \"X\".")
 }
 
 func (s *Suite) Test_Autofix_ReplaceRegex_with_autofix(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("--autofix", "--source")
-       fname := s.CreateTmpFile("Makefile", ""+
-               "line1\n"+
-               "line2\n"+
-               "line3\n")
-       lines := LoadExistingLines(fname, true)
+       t := s.Init(c)
+
+       t.SetupCommandLine("--autofix", "--source")
+       lines := t.SetupFileLines("Makefile",
+               "line1",
+               "line2",
+               "line3")
 
        fix := lines[1].Autofix()
        fix.Warnf("Something's wrong here.")
@@ -44,30 +47,28 @@ func (s *Suite) Test_Autofix_ReplaceRege
 
        SaveAutofixChanges(lines)
 
-       c.Check(s.LoadTmpFile("Makefile"), equals, ""+
-               "line1\n"+
-               "YXXXX\n"+
-               "line3\n")
-       s.CheckOutputLines(
+       t.CheckFileLines("Makefile",
+               "line1",
+               "YXXXX",
+               "line3")
+       t.CheckOutputLines(
                "AUTOFIX: ~/Makefile:2: Replacing regular expression \".\" with \"X\".",
-               "- line2",
-               "+ XXXXX",
+               "-\tline2",
+               "+\tXXXXX",
                "",
                "AUTOFIX: ~/Makefile:2: Replacing \"X\" with \"Y\".",
-               "- line2",
-               "+ YXXXX",
-               "",
-               "AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.")
+               "-\tline2",
+               "+\tYXXXX")
 }
 
 func (s *Suite) Test_Autofix_ReplaceRegex_with_show_autofix(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("--show-autofix", "--source")
-       fname := s.CreateTmpFile("Makefile", ""+
-               "line1\n"+
-               "line2\n"+
-               "line3\n")
-       lines := LoadExistingLines(fname, true)
+       t := s.Init(c)
+
+       t.SetupCommandLine("--show-autofix", "--source")
+       lines := t.SetupFileLines("Makefile",
+               "line1",
+               "line2",
+               "line3")
 
        fix := lines[1].Autofix()
        fix.Warnf("Something's wrong here.")
@@ -80,53 +81,55 @@ func (s *Suite) Test_Autofix_ReplaceRege
 
        SaveAutofixChanges(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: ~/Makefile:2: Something's wrong here.",
                "AUTOFIX: ~/Makefile:2: Replacing regular expression \".\" with \"X\".",
-               "- line2",
-               "+ XXXXX",
+               "-\tline2",
+               "+\tXXXXX",
                "",
                "WARN: ~/Makefile:2: Use Y instead of X.",
                "AUTOFIX: ~/Makefile:2: Replacing \"X\" with \"Y\".",
-               "- line2",
-               "+ YXXXX")
+               "-\tline2",
+               "+\tYXXXX")
 }
 
 func (s *Suite) Test_autofix_MkLines(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("--autofix")
-       fname := s.CreateTmpFile("Makefile", ""+
-               "line1 := value1\n"+
-               "line2 := value2\n"+
-               "line3 := value3\n")
+       t := s.Init(c)
+
+       t.SetupCommandLine("--autofix")
+       t.SetupFileLines("Makefile",
+               "line1 := value1",
+               "line2 := value2",
+               "line3 := value3")
        pkg := NewPackage("category/basename")
        G.Pkg = pkg
-       mklines := pkg.loadPackageMakefile(fname)
+       mklines := pkg.loadPackageMakefile(t.TempFilename("Makefile"))
        G.Pkg = nil
 
        fix := mklines.mklines[1].Autofix()
        fix.Warnf("Something's wrong here.")
        fix.ReplaceRegex(`.`, "X")
        fix.Apply()
+
        SaveAutofixChanges(mklines.lines)
 
-       c.Check(s.LoadTmpFile("Makefile"), equals, ""+
-               "line1 := value1\n"+
-               "XXXXXXXXXXXXXXX\n"+
-               "line3 := value3\n")
-       s.CheckOutputLines(
-               "AUTOFIX: ~/Makefile:2: Replacing regular expression \".\" with \"X\".",
-               "AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.")
+       t.CheckFileLines("Makefile",
+               "line1 := value1",
+               "XXXXXXXXXXXXXXX",
+               "line3 := value3")
+       t.CheckOutputLines(
+               "AUTOFIX: ~/Makefile:2: Replacing regular expression \".\" with \"X\".")
 }
 
 func (s *Suite) Test_Autofix_multiple_modifications(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("--show-autofix", "--explain")
+       t := s.Init(c)
+
+       t.SetupCommandLine("--show-autofix", "--explain")
 
-       line := NewLine("fname", 1, "dummy", T.NewRawLines(1, "original\n"))
+       line := t.NewLine("fname", 1, "original")
 
        c.Check(line.autofix, check.IsNil)
-       c.Check(line.raw, check.DeepEquals, T.NewRawLines(1, "original\n"))
+       c.Check(line.raw, check.DeepEquals, t.NewRawLines(1, "original\n"))
 
        {
                fix := line.Autofix()
@@ -136,8 +139,8 @@ func (s *Suite) Test_Autofix_multiple_mo
        }
 
        c.Check(line.autofix, check.NotNil)
-       c.Check(line.raw, check.DeepEquals, T.NewRawLines(1, "original\n", "lriginao\n"))
-       s.CheckOutputLines(
+       c.Check(line.raw, check.DeepEquals, t.NewRawLines(1, "original\n", "lriginao\n"))
+       t.CheckOutputLines(
                "AUTOFIX: fname:1: Replacing regular expression \"(.)(.*)(.)\" with \"$3$2$1\".")
 
        {
@@ -148,9 +151,9 @@ func (s *Suite) Test_Autofix_multiple_mo
        }
 
        c.Check(line.autofix, check.NotNil)
-       c.Check(line.raw, check.DeepEquals, T.NewRawLines(1, "original\n", "lruginao\n"))
+       c.Check(line.raw, check.DeepEquals, t.NewRawLines(1, "original\n", "lruginao\n"))
        c.Check(line.raw[0].textnl, equals, "lruginao\n")
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "AUTOFIX: fname:1: Replacing \"i\" with \"u\".")
 
        {
@@ -161,9 +164,9 @@ func (s *Suite) Test_Autofix_multiple_mo
        }
 
        c.Check(line.autofix, check.NotNil)
-       c.Check(line.raw, check.DeepEquals, T.NewRawLines(1, "original\n", "middle\n"))
+       c.Check(line.raw, check.DeepEquals, t.NewRawLines(1, "original\n", "middle\n"))
        c.Check(line.raw[0].textnl, equals, "middle\n")
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "AUTOFIX: fname:1: Replacing \"lruginao\" with \"middle\".")
 
        {
@@ -195,7 +198,7 @@ func (s *Suite) Test_Autofix_multiple_mo
        c.Check(line.autofix.linesAfter, deepEquals, []string{
                "between middle and after\n",
                "after\n"})
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "AUTOFIX: fname:1: Inserting a line \"before\" before this line.",
                "AUTOFIX: fname:1: Inserting a line \"between before and middle\" before this line.",
                "AUTOFIX: fname:1: Inserting a line \"between middle and after\" after this line.",
@@ -220,17 +223,20 @@ func (s *Suite) Test_Autofix_multiple_mo
        c.Check(line.autofix.linesAfter, deepEquals, []string{
                "between middle and after\n",
                "after\n"})
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "AUTOFIX: fname:1: Deleting this line.")
 }
 
 func (s *Suite) Test_Autofix_show_source_code(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("--show-autofix", "--source")
-       line := NewLineMulti("Makefile", 27, 29, "# old", T.NewRawLines(
-               27, "before\n",
-               28, "The old song\n",
-               29, "after\n"))
+       t := s.Init(c)
+
+       t.SetupCommandLine("--show-autofix", "--source")
+       lines := t.SetupFileLinesContinuation("Makefile",
+               MkRcsId,
+               "before \\",
+               "The old song \\",
+               "after")
+       line := lines[1]
 
        {
                fix := line.Autofix()
@@ -239,54 +245,57 @@ func (s *Suite) Test_Autofix_show_source
                fix.Apply()
        }
 
-       s.CheckOutputLines(
-               "WARN: Makefile:27--29: Using \"old\" is deprecated.",
-               "AUTOFIX: Makefile:27--29: Replacing \"old\" with \"new\".",
-               "> before",
-               "- The old song",
-               "+ The new song",
-               "> after")
+       t.CheckOutputLines(
+               "WARN: ~/Makefile:2--4: Using \"old\" is deprecated.",
+               "AUTOFIX: ~/Makefile:3: Replacing \"old\" with \"new\".",
+               ">\tbefore \\",
+               "-\tThe old song \\",
+               "+\tThe new song \\",
+               ">\tafter")
 }
 
 func (s *Suite) Test_Autofix_InsertBefore(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("--show-autofix", "--source")
-       line := NewLine("Makefile", 30, "original", T.NewRawLines(30, "original\n"))
+       t := s.Init(c)
+
+       t.SetupCommandLine("--show-autofix", "--source")
+       line := t.NewLine("Makefile", 30, "original")
 
        fix := line.Autofix()
        fix.Warnf("Dummy")
        fix.InsertBefore("inserted")
        fix.Apply()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:30: Dummy",
                "AUTOFIX: Makefile:30: Inserting a line \"inserted\" before this line.",
-               "+ inserted",
-               "> original")
+               "+\tinserted",
+               ">\toriginal")
 }
 
 func (s *Suite) Test_Autofix_Delete(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("--show-autofix", "--source")
-       line := NewLine("Makefile", 30, "to be deleted", T.NewRawLines(30, "to be deleted\n"))
+       t := s.Init(c)
+
+       t.SetupCommandLine("--show-autofix", "--source")
+       line := t.NewLine("Makefile", 30, "to be deleted")
 
        fix := line.Autofix()
        fix.Warnf("Dummy")
        fix.Delete()
        fix.Apply()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:30: Dummy",
                "AUTOFIX: Makefile:30: Deleting this line.",
-               "- to be deleted")
+               "-\tto be deleted")
 }
 
 // Demonstrates that the --show-autofix option only shows those diagnostics
 // that would be fixed.
 func (s *Suite) Test_Autofix_suppress_unfixable_warnings(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("--show-autofix", "--source")
-       lines := T.NewLines("Makefile",
+       t := s.Init(c)
+
+       t.SetupCommandLine("--show-autofix", "--source")
+       lines := t.NewLines("Makefile",
                "line1",
                "line2",
                "line3")
@@ -304,25 +313,40 @@ func (s *Suite) Test_Autofix_suppress_un
 
        lines[2].Warnf("Neither is this warning shown.")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:2: Something's wrong here.",
                "AUTOFIX: Makefile:2: Replacing regular expression \".\" with \"X\".",
-               "- line2",
-               "+ XXXXX",
+               "-\tline2",
+               "+\tXXXXX",
                "",
                "WARN: Makefile:2: The XXX marks are usually not fixed, use TODO instead.",
                "AUTOFIX: Makefile:2: Replacing \"XXX\" with \"TODO\".",
-               "- line2",
-               "+ TODOXX")
+               "-\tline2",
+               "+\tTODOXX")
+}
+
+// If an Autofix doesn't do anything it must not log any diagnostics.
+func (s *Suite) Test_Autofix_failed_replace(c *check.C) {
+       t := s.Init(c)
+
+       line := t.NewLine("Makefile", 14, "Original text")
+
+       fix := line.Autofix()
+       fix.Warnf("All-uppercase words should not be used at all.")
+       fix.ReplaceRegex(`\b[A-Z]{3,}\b`, "---censored---")
+       fix.Apply()
+
+       // No output since there was no all-uppercase word in the text.
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_SaveAutofixChanges(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("--autofix")
-       filename := s.CreateTmpFileLines("DESCR",
+       t := s.Init(c)
+
+       t.SetupCommandLine("--autofix")
+       lines := t.SetupFileLines("DESCR",
                "Line 1",
                "Line 2")
-       lines := LoadExistingLines(filename, false)
 
        fix := lines[0].Autofix()
        fix.Warnf("Dummy warning.")
@@ -334,5 +358,5 @@ func (s *Suite) Test_SaveAutofixChanges(
        SaveAutofixChanges(lines)
 
        // And therefore, no AUTOFIX action must appear in the log.
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 }
Index: pkgsrc/pkgtools/pkglint/files/logging_test.go
diff -u pkgsrc/pkgtools/pkglint/files/logging_test.go:1.1 pkgsrc/pkgtools/pkglint/files/logging_test.go:1.2
--- pkgsrc/pkgtools/pkglint/files/logging_test.go:1.1   Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/logging_test.go       Sat Jan 27 18:50:36 2018
@@ -14,15 +14,15 @@ import "gopkg.in/check.v1"
 //
 // To keep the output layout consistent between all these
 // modes, the source code is written below the diagnostic
-// even in the default (check-only) mode, for consistency.
+// also in the default (check-only) mode.
 func (s *Suite) Test_show_source_separator(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("--source")
-       fileName := s.CreateTmpFileLines("DESCR",
+       t := s.Init(c)
+
+       t.SetupCommandLine("--source")
+       lines := t.SetupFileLines("DESCR",
                "The first line",
                "The second line",
                "The third line")
-       lines := LoadExistingLines(fileName, true)
 
        fix := lines[1].Autofix()
        fix.Warnf("Using \"second\" is deprecated.")
@@ -36,25 +36,25 @@ func (s *Suite) Test_show_source_separat
        fix.Replace("third", "bronze medal")
        fix.Apply()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: ~/DESCR:2: Using \"second\" is deprecated.",
-               "> The second line",
+               ">\tThe second line",
                "",
                "WARN: ~/DESCR:3: Dummy warning.",
-               "> The third line",
+               ">\tThe third line",
                "",
                "WARN: ~/DESCR:3: Using \"third\" is deprecated.",
-               "> The third line")
+               ">\tThe third line")
 }
 
 func (s *Suite) Test_show_source_separator_show_autofix(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("--source", "--show-autofix")
-       fileName := s.CreateTmpFileLines("DESCR",
+       t := s.Init(c)
+
+       t.SetupCommandLine("--source", "--show-autofix")
+       lines := t.SetupFileLines("DESCR",
                "The first line",
                "The second line",
                "The third line")
-       lines := LoadExistingLines(fileName, true)
 
        fix := lines[1].Autofix()
        fix.Warnf("Using \"second\" is deprecated.")
@@ -68,26 +68,26 @@ func (s *Suite) Test_show_source_separat
        fix.Replace("third", "bronze medal")
        fix.Apply()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: ~/DESCR:2: Using \"second\" is deprecated.",
                "AUTOFIX: ~/DESCR:2: Replacing \"second\" with \"silver medal\".",
-               "- The second line",
-               "+ The silver medal line",
+               "-\tThe second line",
+               "+\tThe silver medal line",
                "",
                "WARN: ~/DESCR:3: Using \"third\" is deprecated.",
                "AUTOFIX: ~/DESCR:3: Replacing \"third\" with \"bronze medal\".",
-               "- The third line",
-               "+ The bronze medal line")
+               "-\tThe third line",
+               "+\tThe bronze medal line")
 }
 
 func (s *Suite) Test_show_source_separator_autofix(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("--source", "--autofix")
-       fileName := s.CreateTmpFileLines("DESCR",
+       t := s.Init(c)
+
+       t.SetupCommandLine("--source", "--autofix")
+       lines := t.SetupFileLines("DESCR",
                "The first line",
                "The second line",
                "The third line")
-       lines := LoadExistingLines(fileName, true)
 
        fix := lines[1].Autofix()
        fix.Warnf("Using \"second\" is deprecated.")
@@ -101,27 +101,26 @@ func (s *Suite) Test_show_source_separat
        fix.Replace("third", "bronze medal")
        fix.Apply()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "AUTOFIX: ~/DESCR:2: Replacing \"second\" with \"silver medal\".",
-               "- The second line",
-               "+ The silver medal line",
+               "-\tThe second line",
+               "+\tThe silver medal line",
                "",
                "AUTOFIX: ~/DESCR:3: Replacing \"third\" with \"bronze medal\".",
-               "- The third line",
-               "+ The bronze medal line")
+               "-\tThe third line",
+               "+\tThe bronze medal line")
 }
 
 // Demonstrates how to filter log messages.
 // This is useful in combination with the --autofix option,
 // to restrict the fixes to exactly one group or topic.
 func (s *Suite) Test_Line_log_only(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("--autofix", "--source", "--only", "interesting")
-       line := NewLineMulti("Makefile", 27, 29, "Dummy text", T.NewRawLines(
-               27, "before\n",
-               28, "The old song\n",
-               29, "after\n"))
+       t := s.Init(c)
+
+       t.SetupCommandLine("--autofix", "--source", "--only", "interesting")
+       line := t.NewLine("Makefile", 27, "The old song")
 
+       // Is completely ignored, including any autofixes.
        fix := line.Autofix()
        fix.Warnf("Using \"old\" is deprecated.")
        fix.Replace("old", "new1")
@@ -131,10 +130,8 @@ func (s *Suite) Test_Line_log_only(c *ch
        fix.Replace("old", "new2")
        fix.Apply()
 
-       s.CheckOutputLines(
-               "AUTOFIX: Makefile:27--29: Replacing \"old\" with \"new2\".",
-               "> before",
-               "- The old song",
-               "+ The new2 song",
-               "> after")
+       t.CheckOutputLines(
+               "AUTOFIX: Makefile:27: Replacing \"old\" with \"new2\".",
+               "-\tThe old song",
+               "+\tThe new2 song")
 }
Index: pkgsrc/pkgtools/pkglint/files/mkshwalker_test.go
diff -u pkgsrc/pkgtools/pkglint/files/mkshwalker_test.go:1.1 pkgsrc/pkgtools/pkglint/files/mkshwalker_test.go:1.2
--- pkgsrc/pkgtools/pkglint/files/mkshwalker_test.go:1.1        Thu Jul  7 12:09:27 2016
+++ pkgsrc/pkgtools/pkglint/files/mkshwalker_test.go    Sat Jan 27 18:50:36 2018
@@ -12,6 +12,7 @@ func (s *Suite) Test_MkShWalker_Walk(c *
                "  [ \"$${lang}\" = \"wxstd.po\" ] && continue; "+
                "  ${TOOLS_PATH.msgfmt} -c -o \"$${lang%.po}.mo\" \"$${lang}\"; "+
                "done")
+
        if c.Check(err, check.IsNil) && c.Check(list, check.NotNil) {
                var commands []string
                (*MkShWalker).Walk(nil, list, func(node interface{}) {

Index: pkgsrc/pkgtools/pkglint/files/buildlink3_test.go
diff -u pkgsrc/pkgtools/pkglint/files/buildlink3_test.go:1.10 pkgsrc/pkgtools/pkglint/files/buildlink3_test.go:1.11
--- pkgsrc/pkgtools/pkglint/files/buildlink3_test.go:1.10       Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/buildlink3_test.go    Sat Jan 27 18:50:36 2018
@@ -3,10 +3,11 @@ package main
 import "gopkg.in/check.v1"
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("buildlink3.mk",
-               mkrcsid,
+       mklines := t.NewMkLines("buildlink3.mk",
+               MkRcsId,
                "# XXX This file was created automatically using createbuildlink-@PKGVERSION@",
                "",
                "BUILDLINK_TREE+=        Xbae",
@@ -26,7 +27,7 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: buildlink3.mk:12: \"/x11/Xbae\" does not exist.",
                "ERROR: buildlink3.mk:12: There is no package in \"x11/Xbae\".",
                "ERROR: buildlink3.mk:14: \"/mk/motif.buildlink3.mk\" does not exist.",
@@ -37,13 +38,14 @@ func (s *Suite) Test_ChecklinesBuildlink
 // The mk/haskell.mk file takes care of constructing the correct PKGNAME,
 // but pkglint had not looked at that file.
 func (s *Suite) Test_ChecklinesBuildlink3Mk_name_mismatch(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
        G.Pkg = NewPackage("x11/hs-X11")
        G.Pkg.EffectivePkgbase = "X11"
-       G.Pkg.EffectivePkgnameLine = T.NewMkLine("Makefile", 3, "DISTNAME=\tX11-1.0")
-       mklines := T.NewMkLines("buildlink3.mk",
-               mkrcsid,
+       G.Pkg.EffectivePkgnameLine = t.NewMkLine("Makefile", 3, "DISTNAME=\tX11-1.0")
+       mklines := t.NewMkLines("buildlink3.mk",
+               MkRcsId,
                "",
                "BUILDLINK_TREE+=\ths-X11",
                "",
@@ -59,15 +61,16 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: buildlink3.mk:3: Package name mismatch between \"hs-X11\" in this file and \"X11\" from Makefile:3.")
 }
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk_name_mismatch_multiple_inclusion(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("buildlink3.mk",
-               mkrcsid,
+       mklines := t.NewMkLines("buildlink3.mk",
+               MkRcsId,
                "",
                "BUILDLINK_TREE+=\tpkgbase1",
                "",
@@ -80,16 +83,17 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: buildlink3.mk:5: Package name mismatch between multiple-inclusion guard \"PKGBASE2\" (expected \"PKGBASE1\") and package name \"pkgbase1\" (from line 3).",
                "WARN: buildlink3.mk:9: Definition of BUILDLINK_API_DEPENDS is missing.")
 }
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk_name_mismatch_abi_api(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("buildlink3.mk",
-               mkrcsid,
+       mklines := t.NewMkLines("buildlink3.mk",
+               MkRcsId,
                "",
                "BUILDLINK_TREE+=\ths-X11",
                "",
@@ -105,15 +109,16 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: buildlink3.mk:9: Package name mismatch between ABI \"hs-X12\" and API \"hs-X11\" (from line 8).")
 }
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk_abi_api_versions(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("buildlink3.mk",
-               mkrcsid,
+       mklines := t.NewMkLines("buildlink3.mk",
+               MkRcsId,
                "",
                "BUILDLINK_TREE+=\ths-X11",
                "",
@@ -129,15 +134,16 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: buildlink3.mk:9: ABI version \"1.6.0\" should be at least API version \"1.6.1\" (see line 8).")
 }
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk_no_BUILDLINK_TREE_at_beginning(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("buildlink3.mk",
-               mkrcsid,
+       mklines := t.NewMkLines("buildlink3.mk",
+               MkRcsId,
                "",
                ".if !defined(HS_X11_BUILDLINK3_MK)",
                "HS_X11_BUILDLINK3_MK:=",
@@ -152,15 +158,16 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: buildlink3.mk:3: Expected a BUILDLINK_TREE line.")
 }
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk_no_BUILDLINK_TREE_at_end(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("buildlink3.mk",
-               mkrcsid,
+       mklines := t.NewMkLines("buildlink3.mk",
+               MkRcsId,
                "",
                "BUILDLINK_DEPMETHOD.hs-X11?=\tfull",
                "",
@@ -179,16 +186,17 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: buildlink3.mk:3: This line belongs inside the .ifdef block.",
                "WARN: buildlink3.mk:15: This line should contain the following text: BUILDLINK_TREE+=\t-hs-X11")
 }
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk_multiple_inclusion_wrong(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("buildlink3.mk",
-               mkrcsid,
+       mklines := t.NewMkLines("buildlink3.mk",
+               MkRcsId,
                "",
                "BUILDLINK_TREE+=\ths-X11",
                "",
@@ -197,16 +205,17 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: buildlink3.mk:6: UNRELATED_BUILDLINK3_MK is defined but not used. Spelling mistake?",
                "WARN: buildlink3.mk:6: This line should contain the following text: HS_X11_BUILDLINK3_MK:=")
 }
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk_missing_endif(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("buildlink3.mk",
-               mkrcsid,
+       mklines := t.NewMkLines("buildlink3.mk",
+               MkRcsId,
                "",
                "BUILDLINK_TREE+=\tpkgbase1",
                "",
@@ -215,15 +224,16 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: buildlink3.mk:EOF: Expected .endif")
 }
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk_unknown_dependency_patterns(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("buildlink3.mk",
-               mkrcsid,
+       mklines := t.NewMkLines("buildlink3.mk",
+               MkRcsId,
                "",
                "BUILDLINK_TREE+= hs-X11",
                "",
@@ -240,16 +250,17 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: buildlink3.mk:9: Unknown dependency pattern \"hs-X11!=1.6.1\".",
                "WARN: buildlink3.mk:10: Unknown dependency pattern \"hs-X11!=1.6.1.2nb2\".")
 }
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk_PKGBASE_with_variable(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("buildlink3.mk",
-               mkrcsid,
+       mklines := t.NewMkLines("buildlink3.mk",
+               MkRcsId,
                "",
                "BUILDLINK_TREE+=\t${PYPKGPREFIX}-wxWidgets",
                "",
@@ -265,15 +276,16 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: buildlink3.mk:3: Please use \"py\" instead of \"${PYPKGPREFIX}\" (also in other variables in this file).")
 }
 
 func (s *Suite) Test_ChecklinesBuildlink3Mk_PKGBASE_with_unknown_variable(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("buildlink3.mk",
-               mkrcsid,
+       mklines := t.NewMkLines("buildlink3.mk",
+               MkRcsId,
                "",
                "BUILDLINK_TREE+=\t${LICENSE}-wxWidgets",
                "",
@@ -289,7 +301,7 @@ func (s *Suite) Test_ChecklinesBuildlink
 
        ChecklinesBuildlink3Mk(mklines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: buildlink3.mk:3: Please replace \"${LICENSE}\" with a simple string (also in other variables in this file).",
                "WARN: buildlink3.mk:13: This line should contain the following text: BUILDLINK_TREE+=\t-${LICENSE}-wxWidgets")
 }
@@ -299,11 +311,12 @@ func (s *Suite) Test_ChecklinesBuildlink
 // but ideally should be handled like everywhere else.
 // See MkLineChecker.checkInclude.
 func (s *Suite) Test_ChecklinesBuildlink3Mk_indentation(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("buildlink3.mk",
-               mkrcsid,
+       mklines := t.NewMkLines("buildlink3.mk",
+               MkRcsId,
                "",
                ".if ${VAAPI_AVAILABLE} == \"yes\"",
                "",
@@ -326,7 +339,7 @@ func (s *Suite) Test_ChecklinesBuildlink
        ChecklinesBuildlink3Mk(mklines)
 
        // No warning about the indentation of the .include lines.
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: buildlink3.mk:11: \"/multimedia/libva\" does not exist.",
                "ERROR: buildlink3.mk:11: There is no package in \"multimedia/libva\".",
                "ERROR: buildlink3.mk:13: \"/x11/libX11/buildlink3.mk\" does not exist.",
Index: pkgsrc/pkgtools/pkglint/files/substcontext_test.go
diff -u pkgsrc/pkgtools/pkglint/files/substcontext_test.go:1.10 pkgsrc/pkgtools/pkglint/files/substcontext_test.go:1.11
--- pkgsrc/pkgtools/pkglint/files/substcontext_test.go:1.10     Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/substcontext_test.go  Sat Jan 27 18:50:36 2018
@@ -6,91 +6,96 @@ import (
 )
 
 func (s *Suite) Test_SubstContext__incomplete(c *check.C) {
-       s.Init(c)
-       G.opts.WarnExtra = true
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wextra")
        ctx := NewSubstContext()
 
-       ctx.Varassign(newSubstLine(10, "PKGNAME=pkgname-1.0"))
+       ctx.Varassign(newSubstLine(t, 10, "PKGNAME=pkgname-1.0"))
 
        c.Check(ctx.id, equals, "")
 
-       ctx.Varassign(newSubstLine(11, "SUBST_CLASSES+=interp"))
+       ctx.Varassign(newSubstLine(t, 11, "SUBST_CLASSES+=interp"))
 
        c.Check(ctx.id, equals, "interp")
 
-       ctx.Varassign(newSubstLine(12, "SUBST_FILES.interp=Makefile"))
+       ctx.Varassign(newSubstLine(t, 12, "SUBST_FILES.interp=Makefile"))
 
        c.Check(ctx.IsComplete(), equals, false)
 
-       ctx.Varassign(newSubstLine(13, "SUBST_SED.interp=s,@PREFIX@,${PREFIX},g"))
+       ctx.Varassign(newSubstLine(t, 13, "SUBST_SED.interp=s,@PREFIX@,${PREFIX},g"))
 
        c.Check(ctx.IsComplete(), equals, false)
 
-       ctx.Finish(newSubstLine(14, ""))
+       ctx.Finish(newSubstLine(t, 14, ""))
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:14: Incomplete SUBST block: SUBST_STAGE.interp missing.")
 }
 
 func (s *Suite) Test_SubstContext__complete(c *check.C) {
-       s.Init(c)
-       G.opts.WarnExtra = true
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wextra")
        ctx := NewSubstContext()
 
-       ctx.Varassign(newSubstLine(10, "PKGNAME=pkgname-1.0"))
-       ctx.Varassign(newSubstLine(11, "SUBST_CLASSES+=p"))
-       ctx.Varassign(newSubstLine(12, "SUBST_FILES.p=Makefile"))
-       ctx.Varassign(newSubstLine(13, "SUBST_SED.p=s,@PREFIX@,${PREFIX},g"))
+       ctx.Varassign(newSubstLine(t, 10, "PKGNAME=pkgname-1.0"))
+       ctx.Varassign(newSubstLine(t, 11, "SUBST_CLASSES+=p"))
+       ctx.Varassign(newSubstLine(t, 12, "SUBST_FILES.p=Makefile"))
+       ctx.Varassign(newSubstLine(t, 13, "SUBST_SED.p=s,@PREFIX@,${PREFIX},g"))
 
        c.Check(ctx.IsComplete(), equals, false)
 
-       ctx.Varassign(newSubstLine(14, "SUBST_STAGE.p=post-configure"))
+       ctx.Varassign(newSubstLine(t, 14, "SUBST_STAGE.p=post-configure"))
 
        c.Check(ctx.IsComplete(), equals, true)
 
-       ctx.Finish(newSubstLine(15, ""))
+       ctx.Finish(newSubstLine(t, 15, ""))
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_SubstContext__OPSYSVARS(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.opts.WarnExtra = true
        ctx := NewSubstContext()
 
-       ctx.Varassign(newSubstLine(11, "SUBST_CLASSES.SunOS+=prefix"))
-       ctx.Varassign(newSubstLine(12, "SUBST_CLASSES.NetBSD+=prefix"))
-       ctx.Varassign(newSubstLine(13, "SUBST_FILES.prefix=Makefile"))
-       ctx.Varassign(newSubstLine(14, "SUBST_SED.prefix=s,@PREFIX@,${PREFIX},g"))
-       ctx.Varassign(newSubstLine(15, "SUBST_STAGE.prefix=post-configure"))
+       ctx.Varassign(newSubstLine(t, 11, "SUBST_CLASSES.SunOS+=prefix"))
+       ctx.Varassign(newSubstLine(t, 12, "SUBST_CLASSES.NetBSD+=prefix"))
+       ctx.Varassign(newSubstLine(t, 13, "SUBST_FILES.prefix=Makefile"))
+       ctx.Varassign(newSubstLine(t, 14, "SUBST_SED.prefix=s,@PREFIX@,${PREFIX},g"))
+       ctx.Varassign(newSubstLine(t, 15, "SUBST_STAGE.prefix=post-configure"))
 
        c.Check(ctx.IsComplete(), equals, true)
 
-       ctx.Finish(newSubstLine(15, ""))
+       ctx.Finish(newSubstLine(t, 15, ""))
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_SubstContext__no_class(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wextra")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wextra")
        ctx := NewSubstContext()
 
-       ctx.Varassign(newSubstLine(10, "UNRELATED=anything"))
-       ctx.Varassign(newSubstLine(11, "SUBST_FILES.repl+=Makefile.in"))
-       ctx.Varassign(newSubstLine(12, "SUBST_SED.repl+=-e s,from,to,g"))
-       ctx.Finish(newSubstLine(13, ""))
+       ctx.Varassign(newSubstLine(t, 10, "UNRELATED=anything"))
+       ctx.Varassign(newSubstLine(t, 11, "SUBST_FILES.repl+=Makefile.in"))
+       ctx.Varassign(newSubstLine(t, 12, "SUBST_SED.repl+=-e s,from,to,g"))
+       ctx.Finish(newSubstLine(t, 13, ""))
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:11: SUBST_CLASSES should come before the definition of \"SUBST_FILES.repl\".",
                "WARN: Makefile:13: Incomplete SUBST block: SUBST_STAGE.repl missing.")
 }
 
 func (s *Suite) Test_SubstContext__conditionals(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wextra")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wextra")
 
-       simulateSubstLines(
+       simulateSubstLines(t,
                "10: SUBST_CLASSES+=         os",
                "11: SUBST_STAGE.os=         post-configure",
                "12: SUBST_MESSAGE.os=       Guessing operating system",
@@ -110,15 +115,16 @@ func (s *Suite) Test_SubstContext__condi
        // All the other lines are correctly determined as being alternatives
        // to each other. And since every branch contains some transformation
        // (SED, VARS, FILTER_CMD), everything is fine.
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:18: All but the first \"SUBST_SED.os\" lines should use the \"+=\" operator.")
 }
 
 func (s *Suite) Test_SubstContext__one_conditional_missing_transformation(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wextra")
+       t := s.Init(c)
 
-       simulateSubstLines(
+       t.SetupCommandLine("-Wextra")
+
+       simulateSubstLines(t,
                "10: SUBST_CLASSES+=         os",
                "11: SUBST_STAGE.os=         post-configure",
                "12: SUBST_MESSAGE.os=       Guessing operating system",
@@ -133,17 +139,18 @@ func (s *Suite) Test_SubstContext__one_c
                "21: .endif",
                "22: ")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:15: All but the first \"SUBST_FILES.os\" lines should use the \"+=\" operator.",
                "WARN: Makefile:18: All but the first \"SUBST_SED.os\" lines should use the \"+=\" operator.",
                "WARN: Makefile:22: Incomplete SUBST block: SUBST_SED.os, SUBST_VARS.os or SUBST_FILTER_CMD.os missing.")
 }
 
 func (s *Suite) Test_SubstContext__nested_conditionals(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wextra")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wextra")
 
-       simulateSubstLines(
+       simulateSubstLines(t,
                "10: SUBST_CLASSES+=         os",
                "11: SUBST_STAGE.os=         post-configure",
                "12: SUBST_MESSAGE.os=       Guessing operating system",
@@ -162,17 +169,17 @@ func (s *Suite) Test_SubstContext__neste
                "25: ")
 
        // The branch in line 23 omits SUBST_FILES.
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:25: Incomplete SUBST block: SUBST_FILES.os missing.")
 }
 
-func simulateSubstLines(texts ...string) {
+func simulateSubstLines(t *Tester, texts ...string) {
        ctx := NewSubstContext()
        for _, lineText := range texts {
                var lineno int
                fmt.Sscanf(lineText[0:4], "%d: ", &lineno)
                text := lineText[4:]
-               line := newSubstLine(lineno, text)
+               line := newSubstLine(t, lineno, text)
 
                switch {
                case text == "":
@@ -185,6 +192,6 @@ func simulateSubstLines(texts ...string)
        }
 }
 
-func newSubstLine(lineno int, text string) MkLine {
-       return T.NewMkLine("Makefile", lineno, text)
+func newSubstLine(t *Tester, lineno int, text string) MkLine {
+       return t.NewMkLine("Makefile", lineno, text)
 }

Index: pkgsrc/pkgtools/pkglint/files/category_test.go
diff -u pkgsrc/pkgtools/pkglint/files/category_test.go:1.6 pkgsrc/pkgtools/pkglint/files/category_test.go:1.7
--- pkgsrc/pkgtools/pkglint/files/category_test.go:1.6  Sun Jan 29 14:27:48 2017
+++ pkgsrc/pkgtools/pkglint/files/category_test.go      Sat Jan 27 18:50:36 2018
@@ -1,56 +1,58 @@
 package main
 
-import (
-       check "gopkg.in/check.v1"
-)
+import "gopkg.in/check.v1"
 
 func (s *Suite) Test_CheckdirCategory_totally_broken(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
-       s.CreateTmpFile("archivers/Makefile", ""+
-               "# $\n"+
-               "SUBDIR+=pkg1\n"+
-               "SUBDIR+=\u0020aaaaa\n"+
-               "SUBDIR-=unknown #doesn\u2019t work\n"+
-               "\n"+
-               ".include \"../mk/category.mk\"\n")
+       t.SetupFileLines("archivers/Makefile",
+               "# $",
+               "SUBDIR+=pkg1",
+               "SUBDIR+=\u0020aaaaa",
+               "SUBDIR-=unknown #doesn\u2019t work",
+               "",
+               ".include \"../mk/category.mk\"")
+       G.CurrentDir = t.TempFilename("archivers")
 
-       G.CurrentDir = s.tmpdir + "/archivers"
        CheckdirCategory()
 
-       c.Check(s.Output(), equals, ""+
-               "ERROR: ~/archivers/Makefile:1: Expected \"# $"+"NetBSD$\".\n"+
-               "WARN: ~/archivers/Makefile:4: Line contains invalid characters (U+2019).\n"+
-               "WARN: ~/archivers/Makefile:4: SUBDIR- is defined but not used. Spelling mistake?\n"+
-               "ERROR: ~/archivers/Makefile:6: \"../mk/category.mk\" does not exist.\n"+
-               "ERROR: ~/archivers/Makefile:2: COMMENT= line expected.\n"+
-               "WARN: ~/archivers/Makefile:2: Indentation should be a single tab character.\n"+
-               "WARN: ~/archivers/Makefile:3: Indentation should be a single tab character.\n"+
-               "WARN: ~/archivers/Makefile:3: \"aaaaa\" should come before \"pkg1\".\n"+
-               "ERROR: ~/archivers/Makefile:4: SUBDIR+= line or empty line expected.\n"+
-               "ERROR: ~/archivers/Makefile:2: \"pkg1\" exists in the Makefile, but not in the file system.\n"+
-               "ERROR: ~/archivers/Makefile:3: \"aaaaa\" exists in the Makefile, but not in the file system.\n"+
-               "WARN: ~/archivers/Makefile:4: This line should contain the following text: .include \"../mk/misc/category.mk\"\n"+
-               "ERROR: ~/archivers/Makefile:4: The file should end here.\n")
+       t.CheckOutputLines(
+               "ERROR: ~/archivers/Makefile:1: Expected \"# $"+"NetBSD$\".",
+               "WARN: ~/archivers/Makefile:4: Line contains invalid characters (U+2019).",
+               "WARN: ~/archivers/Makefile:4: SUBDIR- is defined but not used. Spelling mistake?",
+               "ERROR: ~/archivers/Makefile:6: \"../mk/category.mk\" does not exist.",
+               "ERROR: ~/archivers/Makefile:2: COMMENT= line expected.",
+               "WARN: ~/archivers/Makefile:2: Indentation should be a single tab character.",
+               "WARN: ~/archivers/Makefile:3: Indentation should be a single tab character.",
+               "WARN: ~/archivers/Makefile:3: \"aaaaa\" should come before \"pkg1\".",
+               "ERROR: ~/archivers/Makefile:4: SUBDIR+= line or empty line expected.",
+               "ERROR: ~/archivers/Makefile:2: \"pkg1\" exists in the Makefile, but not in the file system.",
+               "ERROR: ~/archivers/Makefile:3: \"aaaaa\" exists in the Makefile, but not in the file system.",
+               "WARN: ~/archivers/Makefile:4: This line should contain the following text: .include \"../mk/misc/category.mk\"",
+               "ERROR: ~/archivers/Makefile:4: The file should end here.")
 }
 
 func (s *Suite) Test_CheckdirCategory_invalid_comment(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
-       s.CreateTmpFile("archivers/Makefile", ""+
-               "# $"+"NetBSD$\n"+
-               "COMMENT=\t\\Make $$$$ fast\"\n"+
-               "\n"+
-               "SUBDIR+=\tpackage\n"+
-               "\n"+
-               ".include \"../mk/misc/category.mk\"\n")
-       s.CreateTmpFile("archivers/package/Makefile", "# dummy\n")
-       s.CreateTmpFile("mk/misc/category.mk", "# dummy\n")
-       G.CurrentDir = s.tmpdir + "/archivers"
+       t.SetupFileLines("archivers/Makefile",
+               MkRcsId,
+               "COMMENT=\t\\Make $$$$ fast\"",
+               "",
+               "SUBDIR+=\tpackage",
+               "",
+               ".include \"../mk/misc/category.mk\"")
+       t.SetupFileLines("archivers/package/Makefile",
+               "# dummy")
+       t.SetupFileLines("mk/misc/category.mk",
+               "# dummy")
+       G.CurrentDir = t.TempFilename("archivers")
        G.CurPkgsrcdir = ".."
 
        CheckdirCategory()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: ~/archivers/Makefile:2: COMMENT contains invalid characters (U+005C U+0024 U+0024 U+0024 U+0024 U+0022).")
 }
Index: pkgsrc/pkgtools/pkglint/files/parser_test.go
diff -u pkgsrc/pkgtools/pkglint/files/parser_test.go:1.6 pkgsrc/pkgtools/pkglint/files/parser_test.go:1.7
--- pkgsrc/pkgtools/pkglint/files/parser_test.go:1.6    Sat Jul  9 09:43:48 2016
+++ pkgsrc/pkgtools/pkglint/files/parser_test.go        Sat Jan 27 18:50:36 2018
@@ -5,6 +5,7 @@ import (
 )
 
 func (s *Suite) Test_Parser_PkgbasePattern(c *check.C) {
+
        checkRest := func(pattern, expected, rest string) {
                parser := NewParser(dummyLine, pattern, false)
                actual := parser.PkgbasePattern()
@@ -29,6 +30,7 @@ func (s *Suite) Test_Parser_Dependency(c
                        c.Check(parser.Rest(), equals, rest)
                }
        }
+
        check := func(pattern string, expected DependencyPattern) {
                checkRest(pattern, expected, "")
        }

Index: pkgsrc/pkgtools/pkglint/files/check_test.go
diff -u pkgsrc/pkgtools/pkglint/files/check_test.go:1.15 pkgsrc/pkgtools/pkglint/files/check_test.go:1.16
--- pkgsrc/pkgtools/pkglint/files/check_test.go:1.15    Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/check_test.go Sat Jan 27 18:50:36 2018
@@ -18,85 +18,89 @@ import (
 var equals = check.Equals
 var deepEquals = check.DeepEquals
 
+const RcsId = "$" + "NetBSD$"
+const MkRcsId = "# $" + "NetBSD$"
+const PlistRcsId = "@comment $" + "NetBSD$"
+
 type Suite struct {
-       stdout bytes.Buffer
-       stderr bytes.Buffer
-       tmpdir string
-       checkC *check.C
+       Tester *Tester
 }
 
 // Init initializes the suite with the check.C instance for the actual
 // test run. See https://github.com/go-check/check/issues/22
-func (s *Suite) Init(c *check.C) {
-       if s.checkC != nil {
+func (s *Suite) Init(c *check.C) *Tester {
+       t := s.Tester // Has been initialized by SetUpTest
+       if t.checkC != nil {
                panic("Suite.Init must only be called once.")
        }
-       s.checkC = c
+       t.checkC = c
+       return t
 }
 
-func (s *Suite) c() *check.C {
-       if s.checkC == nil {
-               panic("Suite.Init must be called before accessing check.C.")
-       }
-       return s.checkC
-}
+func (s *Suite) SetUpTest(c *check.C) {
+       t := &Tester{checkC: c}
+       s.Tester = t
 
-func (s *Suite) Stdout() string {
-       defer s.stdout.Reset()
-       return s.stdout.String()
-}
+       G = GlobalVars{Testing: true}
+       textproc.Testing = true
+       G.logOut = NewSeparatorWriter(&t.stdout)
+       G.logErr = NewSeparatorWriter(&t.stderr)
+       trace.Out = &t.stdout
+
+       t.checkC = c
+       t.SetupCommandLine( /* no arguments */ )
+       t.checkC = nil
 
-func (s *Suite) Stderr() string {
-       defer s.stderr.Reset()
-       return s.stderr.String()
+       G.opts.LogVerbose = true // To detect duplicate work being done
 }
 
-// Returns and consumes the output from both stdout and stderr.
-// The temporary directory is replaced with a tilde (~).
-func (s *Suite) Output() string {
-       output := s.Stdout() + s.Stderr()
-       if s.tmpdir != "" {
-               output = strings.Replace(output, s.tmpdir, "~", -1)
+func (s *Suite) TearDownTest(c *check.C) {
+       t := s.Tester
+       t.checkC = nil // No longer usable; see https://github.com/go-check/check/issues/22
+
+       G = GlobalVars{}
+       textproc.Testing = false
+       if out := t.Output(); out != "" {
+               fmt.Fprintf(os.Stderr, "Unchecked output in %q; check with: t.CheckOutputLines(%v)",
+                       c.TestName(), strings.Split(out, "\n"))
        }
-       return output
+       t.tmpdir = ""
 }
 
-func (s *Suite) CheckOutputEmpty() {
-       s.c().Check(s.Output(), equals, "")
-}
+var _ = check.Suite(new(Suite))
 
-func (s *Suite) CheckOutputLines(expectedLines ...string) {
-       expectedOutput := ""
-       for _, expectedLine := range expectedLines {
-               expectedOutput += expectedLine + "\n"
-       }
-       s.c().Check(s.Output(), equals, expectedOutput)
-}
+func Test(t *testing.T) { check.TestingT(t) }
 
-func (s *Suite) BeginDebugToStdout() {
-       G.logOut = NewSeparatorWriter(os.Stdout)
-       trace.Out = os.Stdout
-       trace.Tracing = true
+// Tester provides utility methods for testing pkglint.
+// It is separated from the Suite since the latter contains
+// all the test methods, which makes it difficult to find
+// a method by auto-completion.
+type Tester struct {
+       stdout bytes.Buffer
+       stderr bytes.Buffer
+       tmpdir string
+       checkC *check.C
 }
 
-func (s *Suite) EndDebugToStdout() {
-       G.logOut = NewSeparatorWriter(&s.stdout)
-       trace.Out = &s.stdout
-       trace.Tracing = false
+func (t *Tester) c() *check.C {
+       if t.checkC == nil {
+               panic("Suite.Init must be called before accessing check.C.")
+       }
+       return t.checkC
 }
 
-// UseCommandLine simulates a command line for the remainder of the test.
-// See Pkglint.ParseCommandLine
-func (s *Suite) UseCommandLine(args ...string) {
+// SetupCommandLine simulates a command line for the remainder of the test.
+// See Pkglint.ParseCommandLine.
+func (t *Tester) SetupCommandLine(args ...string) {
        exitcode := new(Pkglint).ParseCommandLine(append([]string{"pkglint"}, args...))
        if exitcode != nil && *exitcode != 0 {
-               s.CheckOutputEmpty()
-               s.c().Fatalf("Cannot parse command line: %#v", args)
+               t.CheckOutputEmpty()
+               t.c().Fatalf("Cannot parse command line: %#v", args)
        }
        G.opts.LogVerbose = true // See SetUpTest
 }
 
-func (s *Suite) RegisterMasterSite(varname string, urls ...string) {
+func (t *Tester) SetupMasterSite(varname string, urls ...string) {
        name2url := &G.globalData.MasterSiteVarToURL
        url2name := &G.globalData.MasterSiteURLToVar
        if *name2url == nil {
@@ -109,7 +113,7 @@ func (s *Suite) RegisterMasterSite(varna
        }
 }
 
-func (s *Suite) RegisterTool(tool *Tool) {
+func (t *Tester) SetupTool(tool *Tool) {
        reg := G.globalData.Tools
 
        if len(reg.byName) == 0 && len(reg.byVarname) == 0 {
@@ -124,40 +128,56 @@ func (s *Suite) RegisterTool(tool *Tool)
        }
 }
 
-func (s *Suite) CreateTmpFile(relFname, content string) (absFname string) {
-       c := s.c()
-       absFname = s.TmpDir() + "/" + relFname
-       err := os.MkdirAll(path.Dir(absFname), 0777)
-       c.Assert(err, check.IsNil)
+// SetupFileLines creates a temporary file and writes the given lines to it.
+// The file is then read in, without considering line continuations.
+func (t *Tester) SetupFileLines(relativeFilename string, lines ...string) []Line {
+       filename := t.CreateFileLines(relativeFilename, lines...)
+       return LoadExistingLines(filename, false)
+}
 
-       err = ioutil.WriteFile(absFname, []byte(content), 0666)
-       c.Check(err, check.IsNil)
-       return
+// SetupFileLines creates a temporary file and writes the given lines to it.
+// The file is then read in, handling line continuations for Makefiles.
+func (t *Tester) SetupFileLinesContinuation(relativeFilename string, lines ...string) []Line {
+       filename := t.CreateFileLines(relativeFilename, lines...)
+       return LoadExistingLines(filename, true)
 }
 
-func (s *Suite) CreateTmpFileLines(relFname string, rawTexts ...string) (absFname string) {
-       text := ""
-       for _, rawText := range rawTexts {
-               text += rawText + "\n"
+func (t *Tester) CreateFileLines(relativeFilename string, lines ...string) (filename string) {
+       content := ""
+       for _, line := range lines {
+               content += line + "\n"
        }
-       return s.CreateTmpFile(relFname, text)
+
+       filename = t.TempFilename(relativeFilename)
+       err := os.MkdirAll(path.Dir(filename), 0777)
+       t.c().Assert(err, check.IsNil)
+
+       err = ioutil.WriteFile(filename, []byte(content), 0666)
+       t.c().Check(err, check.IsNil)
+
+       return filename
 }
 
-func (s *Suite) LoadTmpFile(relFname string) (absFname string) {
-       c := s.c()
-       bytes, err := ioutil.ReadFile(s.TmpDir() + "/" + relFname)
-       c.Assert(err, check.IsNil)
+func (t *Tester) LoadTmpFile(relFname string) (absFname string) {
+       bytes, err := ioutil.ReadFile(t.TmpDir() + "/" + relFname)
+       t.c().Assert(err, check.IsNil)
        return string(bytes)
 }
 
-func (s *Suite) TmpDir() string {
-       if s.tmpdir == "" {
-               s.tmpdir = filepath.ToSlash(s.c().MkDir())
+func (t *Tester) TmpDir() string {
+       if t.tmpdir == "" {
+               t.tmpdir = filepath.ToSlash(t.c().MkDir())
        }
-       return s.tmpdir
+       return t.tmpdir
 }
 
-func (s *Suite) ExpectFatalError(action func()) {
+// TempFilename returns the absolute path to the given file in the
+// temporary directory. It doesn't check whether that file exists.
+func (t *Tester) TempFilename(relativeFilename string) string {
+       return t.TmpDir() + "/" + relativeFilename
+}
+
+func (t *Tester) ExpectFatalError(action func()) {
        if r := recover(); r != nil {
                if _, ok := r.(pkglintFatal); ok {
                        action()
@@ -167,35 +187,8 @@ func (s *Suite) ExpectFatalError(action 
        }
 }
 
-func (s *Suite) SetUpTest(c *check.C) {
-       G = GlobalVars{Testing: true}
-       textproc.Testing = true
-       G.logOut, G.logErr, trace.Out = NewSeparatorWriter(&s.stdout), NewSeparatorWriter(&s.stderr), &s.stdout
-       s.checkC = c
-       s.UseCommandLine( /* no arguments */ )
-       s.checkC = nil
-       G.opts.LogVerbose = true // To detect duplicate work being done
-}
-
-func (s *Suite) TearDownTest(c *check.C) {
-       G = GlobalVars{}
-       textproc.Testing = false
-       if out := s.Output(); out != "" {
-               fmt.Fprintf(os.Stderr, "Unchecked output in %q; check with: c.Check(s.Output(), equals, %q)", c.TestName(), out)
-       }
-       s.tmpdir = ""
-}
-
-var _ = check.Suite(new(Suite))
-
-func Test(t *testing.T) { check.TestingT(t) }
-
-var T TestObjectCreator
-
-type TestObjectCreator struct{}
-
 // Arguments are either (lineno, orignl) or (lineno, orignl, textnl).
-func (t TestObjectCreator) NewRawLines(args ...interface{}) []*RawLine {
+func (t *Tester) NewRawLines(args ...interface{}) []*RawLine {
        rawlines := make([]*RawLine, len(args)/2)
        j := 0
        for i := 0; i < len(args); i += 2 {
@@ -214,41 +207,116 @@ func (t TestObjectCreator) NewRawLines(a
        return rawlines[:j]
 }
 
-func (t TestObjectCreator) NewLine(filename string, lineno int, text string) Line {
+func (t *Tester) NewLine(filename string, lineno int, text string) Line {
        textnl := text + "\n"
        rawLine := RawLine{lineno, textnl, textnl}
        return NewLine(filename, lineno, text, []*RawLine{&rawLine})
 }
 
-func (t TestObjectCreator) NewMkLine(fileName string, lineno int, text string) MkLine {
+func (t *Tester) NewMkLine(fileName string, lineno int, text string) MkLine {
        return NewMkLine(t.NewLine(fileName, lineno, text))
 }
 
-func (t TestObjectCreator) NewShellLine(fileName string, lineno int, text string) *ShellLine {
+func (t *Tester) NewShellLine(fileName string, lineno int, text string) *ShellLine {
        return NewShellLine(t.NewMkLine(fileName, lineno, text))
 }
 
 // NewLines generates a slice of simple lines,
 // i.e. each logical line has exactly one physical line.
 // To work with line continuations like in Makefiles,
-// use Suite.CreateTmpFileLines together with Suite.LoadExistingLines.
-func (t TestObjectCreator) NewLines(fname string, texts ...string) []Line {
-       return t.NewLinesAt(fname, 1, texts...)
-}
-
-func (t TestObjectCreator) NewMkLines(fname string, lines ...string) *MkLines {
-       return NewMkLines(t.NewLines(fname, lines...))
+// use CreateFileLines together with LoadExistingLines.
+func (t *Tester) NewLines(fileName string, lines ...string) []Line {
+       return t.NewLinesAt(fileName, 1, lines...)
 }
 
 // NewLinesAt generates a slice of simple lines,
 // i.e. each logical line has exactly one physical line.
 // To work with line continuations like in Makefiles,
-// use Suite.CreateTmpFileLines together with Suite.LoadExistingLines.
-func (t TestObjectCreator) NewLinesAt(fname string, firstLine int, texts ...string) []Line {
+// use Suite.CreateFileLines together with Suite.LoadExistingLines.
+func (t *Tester) NewLinesAt(fileName string, firstLine int, texts ...string) []Line {
        result := make([]Line, len(texts))
        for i, text := range texts {
                textnl := text + "\n"
-               result[i] = NewLine(fname, i+firstLine, text, t.NewRawLines(i+firstLine, textnl))
+               result[i] = NewLine(fileName, i+firstLine, text, t.NewRawLines(i+firstLine, textnl))
        }
        return result
 }
+
+func (t *Tester) NewMkLines(fileName string, lines ...string) *MkLines {
+       return NewMkLines(t.NewLines(fileName, lines...))
+}
+
+// Returns and consumes the output from both stdout and stderr.
+// The temporary directory is replaced with a tilde (~).
+func (t *Tester) Output() string {
+       stdout := t.stdout.String()
+       stderr := t.stderr.String()
+
+       t.stdout.Reset()
+       t.stderr.Reset()
+
+       output := stdout + stderr
+       if t.tmpdir != "" {
+               output = strings.Replace(output, t.tmpdir, "~", -1)
+       }
+       return output
+}
+
+func (t *Tester) CheckOutputEmpty() {
+       t.CheckOutputLines( /* none */ )
+}
+
+// CheckOutputLines checks that the output up to now equals the given lines.
+// After the comparison, the output buffers are cleared so that later
+// calls only check against the newly added output.
+func (t *Tester) CheckOutputLines(expectedLines ...string) {
+       output := t.Output()
+       actualLines := strings.Split(output, "\n")
+       actualLines = actualLines[:len(actualLines)-1]
+       t.c().Check(emptyToNil(actualLines), deepEquals, emptyToNil(expectedLines))
+}
+
+// BeginDebugToStdout redirects all logging output to stdout instead of
+// the buffer. This is useful when stepping through the code, especially
+// in combination with SetupCommandLine("--debug").
+func (t *Tester) BeginDebugToStdout() {
+       G.logOut = NewSeparatorWriter(os.Stdout)
+       trace.Out = os.Stdout
+       trace.Tracing = true
+}
+
+// EndDebugToStdout logs the output to the buffers again, ready to be
+// checked with CheckOutputLines.
+func (t *Tester) EndDebugToStdout() {
+       G.logOut = NewSeparatorWriter(&t.stdout)
+       trace.Out = &t.stdout
+       trace.Tracing = false
+}
+
+// CheckFileLines loads the lines from the temporary file and checks that
+// they equal the given lines.
+func (t *Tester) CheckFileLines(relativeFileName string, lines ...string) {
+       text := t.LoadTmpFile(relativeFileName)
+       actualLines := strings.Split(text, "\n")
+       actualLines = actualLines[:len(actualLines)-1]
+       t.c().Check(emptyToNil(actualLines), deepEquals, emptyToNil(lines))
+}
+
+// CheckFileLinesDetab loads the lines from the temporary file and checks
+// that they equal the given lines. The loaded file may use tabs or spaces
+// for indentation, while the lines in the code use spaces exclusively,
+// in order to make the depth of the indentation clearly visible.
+func (t *Tester) CheckFileLinesDetab(relativeFileName string, lines ...string) {
+       actualLines, err := readLines(t.TempFilename(relativeFileName), false)
+       if !t.c().Check(err, check.IsNil) {
+               return
+       }
+
+       var detabbed []string
+       for _, line := range actualLines {
+               rawText := strings.TrimRight(detab(line.raw[0].orignl), "\n")
+               detabbed = append(detabbed, rawText)
+       }
+
+       t.c().Check(detabbed, deepEquals, lines)
+}
Index: pkgsrc/pkgtools/pkglint/files/mklines_test.go
diff -u pkgsrc/pkgtools/pkglint/files/mklines_test.go:1.15 pkgsrc/pkgtools/pkglint/files/mklines_test.go:1.16
--- pkgsrc/pkgtools/pkglint/files/mklines_test.go:1.15  Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/mklines_test.go       Sat Jan 27 18:50:36 2018
@@ -4,179 +4,91 @@ import (
        "gopkg.in/check.v1"
 )
 
-const mkrcsid = "# $" + "NetBSD$"
-
 func (s *Suite) Test_MkLines_Check__autofix_conditional_indentation(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("--autofix", "-Wspace")
-       tmpfile := s.CreateTmpFile("fname.mk", "")
-       mklines := T.NewMkLines(tmpfile,
-               mkrcsid,
+       t := s.Init(c)
+
+       t.SetupCommandLine("--autofix", "-Wspace")
+       lines := t.SetupFileLines("fname.mk",
+               MkRcsId,
                ".if defined(A)",
                ".for a in ${A}",
                ".if defined(C)",
                ".endif",
                ".endfor",
                ".endif")
+       mklines := NewMkLines(lines)
 
        mklines.Check()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "AUTOFIX: ~/fname.mk:3: Replacing \".\" with \".  \".",
                "AUTOFIX: ~/fname.mk:4: Replacing \".\" with \".    \".",
                "AUTOFIX: ~/fname.mk:5: Replacing \".\" with \".    \".",
-               "AUTOFIX: ~/fname.mk:6: Replacing \".\" with \".  \".",
-               "AUTOFIX: ~/fname.mk: Has been auto-fixed. Please re-run pkglint.")
-       c.Check(s.LoadTmpFile("fname.mk"), equals, ""+
-               "# $"+"NetBSD$\n"+
-               ".if defined(A)\n"+
-               ".  for a in ${A}\n"+
-               ".    if defined(C)\n"+
-               ".    endif\n"+
-               ".  endfor\n"+
-               ".endif\n")
+               "AUTOFIX: ~/fname.mk:6: Replacing \".\" with \".  \".")
+       t.CheckFileLines("fname.mk",
+               "# $"+"NetBSD$",
+               ".if defined(A)",
+               ".  for a in ${A}",
+               ".    if defined(C)",
+               ".    endif",
+               ".  endfor",
+               ".endif")
 }
 
 func (s *Suite) Test_MkLines_Check__unusual_target(c *check.C) {
-       s.Init(c)
-       mklines := T.NewMkLines("Makefile",
-               mkrcsid,
+       t := s.Init(c)
+
+       mklines := t.NewMkLines("Makefile",
+               MkRcsId,
                "",
                "echo: echo.c",
                "\tcc -o ${.TARGET} ${.IMPSRC}")
 
        mklines.Check()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:3: Unusual target \"echo\".")
 }
 
 func (s *Suite) Test_MkLineChecker_checkInclude__Makefile(c *check.C) {
-       s.Init(c)
-       mkline := T.NewMkLine("Makefile", 2, ".include \"../../other/package/Makefile\"")
+       t := s.Init(c)
+
+       mkline := t.NewMkLine("Makefile", 2, ".include \"../../other/package/Makefile\"")
 
        MkLineChecker{mkline}.checkInclude()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: Makefile:2: \"/other/package/Makefile\" does not exist.",
                "ERROR: Makefile:2: Other Makefiles must not be included directly.")
 }
 
 func (s *Suite) Test_MkLines_quoting_LDFLAGS_for_GNU_configure(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
        G.Pkg = NewPackage("category/pkgbase")
-       mklines := T.NewMkLines("Makefile",
-               mkrcsid,
+       mklines := t.NewMkLines("Makefile",
+               MkRcsId,
                "GNU_CONFIGURE=\tyes",
                "CONFIGURE_ENV+=\tX_LIBS=${X11_LDFLAGS:Q}")
 
        mklines.Check()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:3: Please use ${X11_LDFLAGS:M*:Q} instead of ${X11_LDFLAGS:Q}.",
                "WARN: Makefile:3: Please use ${X11_LDFLAGS:M*:Q} instead of ${X11_LDFLAGS:Q}.")
 }
 
-func (s *Suite) Test_MkLines__variable_alignment_advanced(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wspace")
-       fname := s.CreateTmpFileLines("Makefile",
-               mkrcsid,
-               "",
-               "VAR= \\", // In continuation lines, indenting with spaces is ok
-               "\tvalue",
-               "",
-               "VAR= indented with one space",   // Exactly one space is ok in general
-               "VAR=  indented with two spaces", // Two spaces are uncommon
-               "",
-               "BLOCK=\tindented with tab",
-               "BLOCK_LONGVAR= indented with space", // This is ok, to prevent the block from being indented further
-               "",
-               "BLOCK=\tshort",
-               "BLOCK_LONGVAR=\tlong",
-               "",
-               "GRP_A= avalue", // The values in a block should be aligned
-               "GRP_AA= value",
-               "GRP_AAA= value",
-               "GRP_AAAA= value",
-               "",
-               "VAR=\t${VAR}${BLOCK}${BLOCK_LONGVAR} # suppress warnings about unused variables",
-               "VAR=\t${GRP_A}${GRP_AA}${GRP_AAA}${GRP_AAAA}")
-       mklines := NewMkLines(LoadExistingLines(fname, true))
-
-       mklines.Check()
-
-       s.CheckOutputLines(
-               "NOTE: ~/Makefile:6: This variable value should be aligned with tabs, not spaces, to column 9.",
-               "NOTE: ~/Makefile:7: This variable value should be aligned with tabs, not spaces, to column 9.",
-               "NOTE: ~/Makefile:12: This variable value should be aligned to column 17.",
-               "NOTE: ~/Makefile:15: This variable value should be aligned with tabs, not spaces, to column 17.",
-               "NOTE: ~/Makefile:16: This variable value should be aligned with tabs, not spaces, to column 17.",
-               "NOTE: ~/Makefile:17: This variable value should be aligned with tabs, not spaces, to column 17.",
-               "NOTE: ~/Makefile:18: This variable value should be aligned with tabs, not spaces, to column 17.")
-
-       s.UseCommandLine("-Wspace", "--autofix")
-
-       mklines.Check()
-
-       s.CheckOutputLines(
-               "AUTOFIX: ~/Makefile:6: Replacing \"VAR= \" with \"VAR=\\t\".",
-               "AUTOFIX: ~/Makefile:7: Replacing \"VAR=  \" with \"VAR=\\t\".",
-               "AUTOFIX: ~/Makefile:12: Replacing \"BLOCK=\\t\" with \"BLOCK=\\t\\t\".",
-               "AUTOFIX: ~/Makefile:15: Replacing \"GRP_A= \" with \"GRP_A=\\t\\t\".",
-               "AUTOFIX: ~/Makefile:16: Replacing \"GRP_AA= \" with \"GRP_AA=\\t\\t\".",
-               "AUTOFIX: ~/Makefile:17: Replacing \"GRP_AAA= \" with \"GRP_AAA=\\t\".",
-               "AUTOFIX: ~/Makefile:18: Replacing \"GRP_AAAA= \" with \"GRP_AAAA=\\t\".",
-               "AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.")
-       c.Check(s.LoadTmpFile("Makefile"), equals, ""+
-               "# $"+"NetBSD$\n"+
-               "\n"+
-               "VAR= \\\n"+
-               "\tvalue\n"+
-               "\n"+
-               "VAR=\tindented with one space\n"+
-               "VAR=\tindented with two spaces\n"+
-               "\n"+
-               "BLOCK=\tindented with tab\n"+
-               "BLOCK_LONGVAR= indented with space\n"+
-               "\n"+
-               "BLOCK=\t\tshort\n"+
-               "BLOCK_LONGVAR=\tlong\n"+
-               "\n"+
-               "GRP_A=\t\tavalue\n"+
-               "GRP_AA=\t\tvalue\n"+
-               "GRP_AAA=\tvalue\n"+
-               "GRP_AAAA=\tvalue\n"+
-               "\n"+
-               "VAR=\t${VAR}${BLOCK}${BLOCK_LONGVAR} # suppress warnings about unused variables\n"+
-               "VAR=\t${GRP_A}${GRP_AA}${GRP_AAA}${GRP_AAAA}\n")
-}
-
-func (s *Suite) Test_MkLines__variable_alignment_space_and_tab(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wspace")
-       mklines := T.NewMkLines("Makefile",
-               mkrcsid,
-               "",
-               "VAR=    space",
-               "VAR=\ttab ${VAR}")
-
-       mklines.Check()
-
-       s.CheckOutputLines(
-               "NOTE: Makefile:3: Variable values should be aligned with tabs, not spaces.")
-}
-
 func (s *Suite) Test_MkLines__for_loop_multiple_variables(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
-       s.RegisterTool(&Tool{Name: "echo", Varname: "ECHO", Predefined: true})
-       s.RegisterTool(&Tool{Name: "find", Varname: "FIND", Predefined: true})
-       s.RegisterTool(&Tool{Name: "pax", Varname: "PAX", Predefined: true})
-       mklines := T.NewMkLines("audio/squeezeboxserver/Makefile",
-               mkrcsid,
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
+       t.SetupTool(&Tool{Name: "echo", Varname: "ECHO", Predefined: true})
+       t.SetupTool(&Tool{Name: "find", Varname: "FIND", Predefined: true})
+       t.SetupTool(&Tool{Name: "pax", Varname: "PAX", Predefined: true})
+       mklines := t.NewMkLines("Makefile", // From audio/squeezeboxserver
+               MkRcsId,
                "",
                ".for _list_ _dir_ in ${SBS_COPY}",
                "\tcd ${WRKSRC} && ${FIND} ${${_list_}} -type f ! -name '*.orig' 2>/dev/null "+
@@ -185,18 +97,19 @@ func (s *Suite) Test_MkLines__for_loop_m
 
        mklines.Check()
 
-       s.CheckOutputLines(
-               "WARN: audio/squeezeboxserver/Makefile:3: Variable names starting with an underscore (_list_) are reserved for internal pkgsrc use.",
-               "WARN: audio/squeezeboxserver/Makefile:3: Variable names starting with an underscore (_dir_) are reserved for internal pkgsrc use.",
-               "WARN: audio/squeezeboxserver/Makefile:4: The exitcode of \"${FIND}\" at the left of the | operator is ignored.")
+       t.CheckOutputLines(
+               "WARN: Makefile:3: Variable names starting with an underscore (_list_) are reserved for internal pkgsrc use.",
+               "WARN: Makefile:3: Variable names starting with an underscore (_dir_) are reserved for internal pkgsrc use.",
+               "WARN: Makefile:4: The exitcode of \"${FIND}\" at the left of the | operator is ignored.")
 }
 
 func (s *Suite) Test_MkLines__comparing_YesNo_variable_to_string(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("databases/gdbm_compat/builtin.mk",
-               mkrcsid,
+       mklines := t.NewMkLines("databases/gdbm_compat/builtin.mk",
+               MkRcsId,
                ".if ${USE_BUILTIN.gdbm} == \"no\"",
                ".endif",
                ".if ${USE_BUILTIN.gdbm:tu} == \"no\"", // Can never be true, since "no" is not uppercase.
@@ -204,16 +117,18 @@ func (s *Suite) Test_MkLines__comparing_
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, "WARN: databases/gdbm_compat/builtin.mk:2: "+
-               "USE_BUILTIN.gdbm should be matched against \"[yY][eE][sS]\" or \"[nN][oO]\", not compared with \"no\".\n")
+       t.CheckOutputLines(
+               "WARN: databases/gdbm_compat/builtin.mk:2: " +
+                       "USE_BUILTIN.gdbm should be matched against \"[yY][eE][sS]\" or \"[nN][oO]\", not compared with \"no\".")
 }
 
 func (s *Suite) Test_MkLines__varuse_sh_modifier(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("lang/qore/module.mk",
-               mkrcsid,
+       mklines := t.NewMkLines("lang/qore/module.mk",
+               MkRcsId,
                "qore-version=\tqore --short-version | ${SED} -e s/-.*//",
                "PLIST_SUBST+=\tQORE_VERSION=\"${qore-version:sh}\"")
 
@@ -227,29 +142,33 @@ func (s *Suite) Test_MkLines__varuse_sh_
 
        mklines.Check()
 
-       s.CheckOutputEmpty() // No warnings about defined but not used or vice versa
+       // No warnings about defined but not used or vice versa
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_MkLines__varuse_parameterized(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("converters/wv2/Makefile",
-               mkrcsid,
+       mklines := t.NewMkLines("converters/wv2/Makefile",
+               MkRcsId,
                "CONFIGURE_ARGS+=\t\t${CONFIGURE_ARGS.${ICONV_TYPE}-iconv}",
                "CONFIGURE_ARGS.gnu-iconv=\t--with-libiconv=${BUILDLINK_PREFIX.iconv}")
 
        mklines.Check()
 
-       s.CheckOutputEmpty() // No warnings about defined but not used or vice versa
+       // No warnings about defined but not used or vice versa
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_MkLines__loop_modifier(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("chat/xchat/Makefile",
-               mkrcsid,
+       mklines := t.NewMkLines("chat/xchat/Makefile",
+               MkRcsId,
                "GCONF_SCHEMAS=\tapps_xchat_url_handler.schemas",
                "post-install:",
                "\t${GCONF_SCHEMAS:@.s.@"+
@@ -257,17 +176,20 @@ func (s *Suite) Test_MkLines__loop_modif
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, ""+ // No warning about missing @ at the end
-               "WARN: chat/xchat/Makefile:4: Unknown shell command \"${GCONF_SCHEMAS:@.s.@"+
-               "${INSTALL_DATA} ${WRKSRC}/src/common/dbus/${.s.} ${DESTDIR}${GCONF_SCHEMAS_DIR}/@}\".\n")
+       t.CheckOutputLines(
+               // No warning about missing @ at the end
+               "WARN: chat/xchat/Makefile:4: " +
+                       "Unknown shell command \"${GCONF_SCHEMAS:@.s.@" +
+                       "${INSTALL_DATA} ${WRKSRC}/src/common/dbus/${.s.} ${DESTDIR}${GCONF_SCHEMAS_DIR}/@}\".")
 }
 
 // PR 46570
 func (s *Suite) Test_MkLines__PKG_SKIP_REASON_depending_on_OPSYS(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("Makefile",
-               mkrcsid,
+       mklines := t.NewMkLines("Makefile",
+               MkRcsId,
                "PKG_SKIP_REASON+=\t\"Fails everywhere\"",
                ".if ${OPSYS} == \"Cygwin\"",
                "PKG_SKIP_REASON+=\t\"Fails on Cygwin\"",
@@ -275,16 +197,17 @@ func (s *Suite) Test_MkLines__PKG_SKIP_R
 
        mklines.Check()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "NOTE: Makefile:4: Consider defining NOT_FOR_PLATFORM instead of setting PKG_SKIP_REASON depending on ${OPSYS}.")
 }
 
 // PR 46570, item "15. net/uucp/Makefile has a make loop"
 func (s *Suite) Test_MkLines__indirect_variables(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
-       mklines := T.NewMkLines("net/uucp/Makefile",
-               mkrcsid,
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
+       mklines := t.NewMkLines("net/uucp/Makefile",
+               MkRcsId,
                "",
                "post-configure:",
                ".for var in MAIL_PROGRAM CMDPATH",
@@ -294,30 +217,32 @@ func (s *Suite) Test_MkLines__indirect_v
        mklines.Check()
 
        // No warning about UUCP_${var} being used but not defined.
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: net/uucp/Makefile:5: Unknown shell command \"${ECHO}\".")
 }
 
 func (s *Suite) Test_MkLines_Check__list_variable_as_part_of_word(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
-       mklines := T.NewMkLines("converters/chef/Makefile",
-               mkrcsid,
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
+       mklines := t.NewMkLines("converters/chef/Makefile",
+               MkRcsId,
                "\tcd ${WRKSRC} && tr '\\r' '\\n' < ${DISTDIR}/${DIST_SUBDIR}/${DISTFILES} > chef.l")
 
        mklines.Check()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: converters/chef/Makefile:2: Unknown shell command \"tr\".",
                "WARN: converters/chef/Makefile:2: The list variable DISTFILES should not be embedded in a word.")
 }
 
 func (s *Suite) Test_MkLines_Check__absolute_pathname_depending_on_OPSYS(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("games/heretic2-demo/Makefile",
-               mkrcsid,
+       mklines := t.NewMkLines("games/heretic2-demo/Makefile",
+               MkRcsId,
                ".if ${OPSYS} == \"DragonFly\"",
                "TOOLS_PLATFORM.gtar=\t/usr/bin/bsdtar",
                ".endif",
@@ -327,57 +252,58 @@ func (s *Suite) Test_MkLines_Check__abso
 
        // No warning about an unknown shell command in line 3,
        // since that line depends on OPSYS.
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: games/heretic2-demo/Makefile:3: The variable TOOLS_PLATFORM.gtar may not be set by any package.",
                "WARN: games/heretic2-demo/Makefile:5: The variable TOOLS_PLATFORM.gtar may not be set by any package.",
                "WARN: games/heretic2-demo/Makefile:5: Unknown shell command \"/usr/bin/bsdtar\".")
 }
 
 func (s *Suite) Test_MkLines_checkForUsedComment(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("--show-autofix")
-       T.NewMkLines("Makefile.common",
-               mkrcsid,
+       t := s.Init(c)
+
+       t.SetupCommandLine("--show-autofix")
+       t.NewMkLines("Makefile.common",
+               MkRcsId,
                "",
                "# used by sysutils/mc",
        ).checkForUsedComment("sysutils/mc")
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 
-       T.NewMkLines("Makefile.common").checkForUsedComment("category/package")
+       t.NewMkLines("Makefile.common").checkForUsedComment("category/package")
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 
-       T.NewMkLines("Makefile.common",
-               mkrcsid,
+       t.NewMkLines("Makefile.common",
+               MkRcsId,
        ).checkForUsedComment("category/package")
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 
-       T.NewMkLines("Makefile.common",
-               mkrcsid,
+       t.NewMkLines("Makefile.common",
+               MkRcsId,
                "",
        ).checkForUsedComment("category/package")
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 
-       T.NewMkLines("Makefile.common",
-               mkrcsid,
+       t.NewMkLines("Makefile.common",
+               MkRcsId,
                "",
                "VARNAME=\tvalue",
        ).checkForUsedComment("category/package")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile.common:2: Please add a line \"# used by category/package\" here.",
                "AUTOFIX: Makefile.common:2: Inserting a line \"# used by category/package\" before this line.")
 
-       T.NewMkLines("Makefile.common",
-               mkrcsid,
+       t.NewMkLines("Makefile.common",
+               MkRcsId,
                "#",
                "#",
        ).checkForUsedComment("category/package")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile.common:3: Please add a line \"# used by category/package\" here.",
                "AUTOFIX: Makefile.common:3: Inserting a line \"# used by category/package\" before this line.")
 
@@ -385,7 +311,9 @@ func (s *Suite) Test_MkLines_checkForUse
 }
 
 func (s *Suite) Test_MkLines_DetermineUsedVariables__simple(c *check.C) {
-       mklines := T.NewMkLines("fname",
+       t := s.Init(c)
+
+       mklines := t.NewMkLines("fname",
                "\t${VAR}")
        mkline := mklines.mklines[0]
        G.Mk = mklines
@@ -397,7 +325,9 @@ func (s *Suite) Test_MkLines_DetermineUs
 }
 
 func (s *Suite) Test_MkLines_DetermineUsedVariables__nested(c *check.C) {
-       mklines := T.NewMkLines("fname",
+       t := s.Init(c)
+
+       mklines := t.NewMkLines("fname",
                "\t${outer.${inner}}")
        mkline := mklines.mklines[0]
        G.Mk = mklines
@@ -411,40 +341,43 @@ func (s *Suite) Test_MkLines_DetermineUs
 }
 
 func (s *Suite) Test_MkLines_PrivateTool_Undefined(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("fname",
-               mkrcsid,
+       mklines := t.NewMkLines("fname",
+               MkRcsId,
                "",
                "\tmd5sum filename")
 
        mklines.Check()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:3: Unknown shell command \"md5sum\".")
 }
 
 func (s *Suite) Test_MkLines_PrivateTool_Defined(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("fname",
-               mkrcsid,
+       mklines := t.NewMkLines("fname",
+               MkRcsId,
                "TOOLS_CREATE+=\tmd5sum",
                "",
                "\tmd5sum filename")
 
        mklines.Check()
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_MkLines_Check_indentation(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
-       mklines := T.NewMkLines("options.mk",
-               mkrcsid,
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
+       mklines := t.NewMkLines("options.mk",
+               MkRcsId,
                ". if !defined(GUARD_MK)",
                ". if ${OPSYS} == ${OPSYS}",
                ".   for i in ${FILES}",
@@ -462,34 +395,35 @@ func (s *Suite) Test_MkLines_Check_inden
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, ""+
-               "NOTE: options.mk:2: This directive should be indented by 0 spaces.\n"+
-               "NOTE: options.mk:3: This directive should be indented by 0 spaces.\n"+
-               "NOTE: options.mk:4: This directive should be indented by 2 spaces.\n"+
-               "NOTE: options.mk:5: This directive should be indented by 4 spaces.\n"+
-               "NOTE: options.mk:6: This directive should be indented by 4 spaces.\n"+
-               "NOTE: options.mk:7: This directive should be indented by 4 spaces.\n"+
-               "NOTE: options.mk:8: This directive should be indented by 2 spaces.\n"+
-               "NOTE: options.mk:9: This directive should be indented by 2 spaces.\n"+
-               "NOTE: options.mk:10: This directive should be indented by 2 spaces.\n"+
-               "NOTE: options.mk:11: This directive should be indented by 2 spaces.\n"+
-               "ERROR: options.mk:11: \".else\" does not take arguments.\n"+
-               "NOTE: options.mk:11: If you meant \"else if\", use \".elif\".\n"+
-               "NOTE: options.mk:12: This directive should be indented by 2 spaces.\n"+
-               "NOTE: options.mk:13: This directive should be indented by 0 spaces.\n"+
-               "NOTE: options.mk:14: This directive should be indented by 0 spaces.\n"+
-               "ERROR: options.mk:15: Unmatched .endif.\n"+
-               "NOTE: options.mk:15: This directive should be indented by 0 spaces.\n")
+       t.CheckOutputLines(""+
+               "NOTE: options.mk:2: This directive should be indented by 0 spaces.",
+               "NOTE: options.mk:3: This directive should be indented by 0 spaces.",
+               "NOTE: options.mk:4: This directive should be indented by 2 spaces.",
+               "NOTE: options.mk:5: This directive should be indented by 4 spaces.",
+               "NOTE: options.mk:6: This directive should be indented by 4 spaces.",
+               "NOTE: options.mk:7: This directive should be indented by 4 spaces.",
+               "NOTE: options.mk:8: This directive should be indented by 2 spaces.",
+               "NOTE: options.mk:9: This directive should be indented by 2 spaces.",
+               "NOTE: options.mk:10: This directive should be indented by 2 spaces.",
+               "NOTE: options.mk:11: This directive should be indented by 2 spaces.",
+               "ERROR: options.mk:11: \".else\" does not take arguments.",
+               "NOTE: options.mk:11: If you meant \"else if\", use \".elif\".",
+               "NOTE: options.mk:12: This directive should be indented by 2 spaces.",
+               "NOTE: options.mk:13: This directive should be indented by 0 spaces.",
+               "NOTE: options.mk:14: This directive should be indented by 0 spaces.",
+               "ERROR: options.mk:15: Unmatched .endif.",
+               "NOTE: options.mk:15: This directive should be indented by 0 spaces.")
 }
 
 // Demonstrates how to define your own make(1) targets.
 func (s *Suite) Test_MkLines_wip_category_Makefile(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       s.RegisterTool(&Tool{Name: "rm", Varname: "RM", Predefined: true})
-       mklines := T.NewMkLines("Makefile",
-               mkrcsid,
+       t.SetupTool(&Tool{Name: "rm", Varname: "RM", Predefined: true})
+       mklines := t.NewMkLines("Makefile",
+               MkRcsId,
                "",
                "COMMENT=\tWIP pkgsrc packages",
                "",
@@ -506,6 +440,6 @@ func (s *Suite) Test_MkLines_wip_categor
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, ""+
-               "ERROR: Makefile:14: \"/mk/misc/category.mk\" does not exist.\n")
+       t.CheckOutputLines(
+               "ERROR: Makefile:14: \"/mk/misc/category.mk\" does not exist.")
 }

Index: pkgsrc/pkgtools/pkglint/files/distinfo.go
diff -u pkgsrc/pkgtools/pkglint/files/distinfo.go:1.17 pkgsrc/pkgtools/pkglint/files/distinfo.go:1.18
--- pkgsrc/pkgtools/pkglint/files/distinfo.go:1.17      Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/distinfo.go   Sat Jan 27 18:50:36 2018
@@ -106,20 +106,21 @@ func (ck *distinfoLinesChecker) onFilena
        ck.algorithms = nil
 }
 
+// Same as in mk/checksum/distinfo.awk:/function patchsum/
 func computePatchSha1Hex(patchFilename string) (string, error) {
        patchBytes, err := ioutil.ReadFile(patchFilename)
        if err != nil {
                return "", err
        }
 
-       h := sha1.New()
+       hash := sha1.New()
        netbsd := []byte("$" + "NetBSD")
        for _, patchLine := range bytes.SplitAfter(patchBytes, []byte("\n")) {
                if !bytes.Contains(patchLine, netbsd) {
-                       h.Write(patchLine)
+                       hash.Write(patchLine)
                }
        }
-       return fmt.Sprintf("%x", h.Sum(nil)), nil
+       return fmt.Sprintf("%x", hash.Sum(nil)), nil
 }
 
 func (ck *distinfoLinesChecker) checkPatchSha1(line Line, patchFname, distinfoSha1Hex string) {

Index: pkgsrc/pkgtools/pkglint/files/distinfo_test.go
diff -u pkgsrc/pkgtools/pkglint/files/distinfo_test.go:1.11 pkgsrc/pkgtools/pkglint/files/distinfo_test.go:1.12
--- pkgsrc/pkgtools/pkglint/files/distinfo_test.go:1.11 Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/distinfo_test.go      Sat Jan 27 18:50:36 2018
@@ -3,15 +3,16 @@ package main
 import "gopkg.in/check.v1"
 
 func (s *Suite) Test_ChecklinesDistinfo(c *check.C) {
-       s.Init(c)
-       s.CreateTmpFile("patches/patch-aa", ""+
-               "$"+"NetBSD$ line is ignored\n"+
-               "patch contents\n")
-       s.CreateTmpFile("patches/patch-ab", ""+
-               "patch contents\n")
-       G.CurrentDir = s.tmpdir
+       t := s.Init(c)
 
-       ChecklinesDistinfo(T.NewLines("distinfo",
+       t.SetupFileLines("patches/patch-aa",
+               "$"+"NetBSD$ line is ignored",
+               "patch contents")
+       t.SetupFileLines("patches/patch-ab",
+               "patch contents")
+       G.CurrentDir = t.TmpDir()
+
+       ChecklinesDistinfo(t.NewLines("distinfo",
                "should be the RCS ID",
                "should be empty",
                "MD5 (distfile.tar.gz) = 12345678901234567890123456789012",
@@ -20,7 +21,7 @@ func (s *Suite) Test_ChecklinesDistinfo(
                "SHA1 (patch-ab) = 6b98dd609f85a9eb9c4c1e4e7055a6aaa62b7cc7",
                "SHA1 (patch-nonexistent) = 1234"))
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: distinfo:1: Expected \"$"+"NetBSD$\".",
                "NOTE: distinfo:2: Empty line expected.",
                "ERROR: distinfo:5: Expected SHA1, RMD160, SHA512, Size checksums for \"distfile.tar.gz\", got MD5, SHA1.",
@@ -28,74 +29,81 @@ func (s *Suite) Test_ChecklinesDistinfo(
 }
 
 func (s *Suite) Test_ChecklinesDistinfo_global_hash_mismatch(c *check.C) {
-       s.Init(c)
-       otherLine := T.NewLine("other/distinfo", 7, "dummy")
-       G.Hash = make(map[string]*Hash)
-       G.Hash["SHA512:pkgname-1.0.tar.gz"] = &Hash{"asdfasdf", otherLine}
+       t := s.Init(c)
 
-       ChecklinesDistinfo(T.NewLines("distinfo",
-               "$"+"NetBSD$",
+       otherLine := t.NewLine("other/distinfo", 7, "dummy")
+       G.Hash = map[string]*Hash{"SHA512:pkgname-1.0.tar.gz": {"Some-512-bit-hash", otherLine}}
+       lines := t.NewLines("distinfo",
+               RcsId,
                "",
-               "SHA512 (pkgname-1.0.tar.gz) = 12341234"))
+               "SHA512 (pkgname-1.0.tar.gz) = 12341234")
+
+       ChecklinesDistinfo(lines)
 
-       s.CheckOutputLines(
-               "ERROR: distinfo:3: The hash SHA512 for pkgname-1.0.tar.gz is 12341234, which differs from asdfasdf in other/distinfo:7.",
+       t.CheckOutputLines(
+               "ERROR: distinfo:3: The hash SHA512 for pkgname-1.0.tar.gz is 12341234, which differs from Some-512-bit-hash in other/distinfo:7.",
                "ERROR: distinfo:EOF: Expected SHA1, RMD160, SHA512, Size checksums for \"pkgname-1.0.tar.gz\", got SHA512.")
 }
 
 func (s *Suite) Test_ChecklinesDistinfo_uncommitted_patch(c *check.C) {
-       s.Init(c)
-       s.CreateTmpFile("patches/patch-aa", ""+
-               "$"+"NetBSD$\n"+
-               "\n"+
-               "--- oldfile\n"+
-               "+++ newfile\n"+
-               "@@ -1,1 +1,1 @@\n"+
-               "-old\n"+
-               "+new\n")
-       s.CreateTmpFile("CVS/Entries",
-               "/distinfo/...\n")
-       G.CurrentDir = s.tmpdir
+       t := s.Init(c)
 
-       ChecklinesDistinfo(T.NewLines(s.tmpdir+"/distinfo",
-               "$"+"NetBSD$",
+       t.SetupFileLines("patches/patch-aa",
+               RcsId,
+               "",
+               "--- oldfile",
+               "+++ newfile",
+               "@@ -1,1 +1,1 @@",
+               "-old",
+               "+new")
+       t.SetupFileLines("CVS/Entries",
+               "/distinfo/...")
+       lines := t.SetupFileLines("distinfo",
+               RcsId,
                "",
-               "SHA1 (patch-aa) = 5ad1fb9b3c328fff5caa1a23e8f330e707dd50c0"))
+               "SHA1 (patch-aa) = 5ad1fb9b3c328fff5caa1a23e8f330e707dd50c0")
+       G.CurrentDir = t.TmpDir()
 
-       s.CheckOutputLines(
+       ChecklinesDistinfo(lines)
+
+       t.CheckOutputLines(
                "WARN: ~/distinfo:3: patches/patch-aa is registered in distinfo but not added to CVS.")
 }
 
 func (s *Suite) Test_ChecklinesDistinfo_unrecorded_patches(c *check.C) {
-       s.Init(c)
-       s.CreateTmpFile("patches/CVS/Entries", "")
-       s.CreateTmpFile("patches/patch-aa", "")
-       s.CreateTmpFile("patches/patch-src-Makefile", "")
-       G.CurrentDir = s.tmpdir
+       t := s.Init(c)
 
-       ChecklinesDistinfo(T.NewLines(s.tmpdir+"/distinfo",
-               "$"+"NetBSD$",
+       t.SetupFileLines("patches/CVS/Entries")
+       t.SetupFileLines("patches/patch-aa")
+       t.SetupFileLines("patches/patch-src-Makefile")
+       lines := t.SetupFileLines("distinfo",
+               RcsId,
                "",
                "SHA1 (distfile.tar.gz) = ...",
                "RMD160 (distfile.tar.gz) = ...",
                "SHA512 (distfile.tar.gz) = ...",
-               "Size (distfile.tar.gz) = 1024 bytes"))
+               "Size (distfile.tar.gz) = 1024 bytes")
+       G.CurrentDir = t.TmpDir()
+
+       ChecklinesDistinfo(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: ~/distinfo: patch \"patches/patch-aa\" is not recorded. Run \""+confMake+" makepatchsum\".",
                "ERROR: ~/distinfo: patch \"patches/patch-src-Makefile\" is not recorded. Run \""+confMake+" makepatchsum\".")
 }
 
 func (s *Suite) Test_ChecklinesDistinfo_manual_patches(c *check.C) {
-       s.Init(c)
-       s.CreateTmpFile("patches/manual-libtool.m4", "")
-       G.CurrentDir = s.tmpdir
+       t := s.Init(c)
 
-       ChecklinesDistinfo(T.NewLines(s.tmpdir+"/distinfo",
-               "$"+"NetBSD$",
+       t.SetupFileLines("patches/manual-libtool.m4")
+       lines := t.SetupFileLines("distinfo",
+               RcsId,
                "",
-               "SHA1 (patch-aa) = ..."))
+               "SHA1 (patch-aa) = ...")
+       G.CurrentDir = t.TmpDir()
+
+       ChecklinesDistinfo(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: ~/distinfo:3: Patch file \"patch-aa\" does not exist in directory \"patches\".")
 }

Index: pkgsrc/pkgtools/pkglint/files/files.go
diff -u pkgsrc/pkgtools/pkglint/files/files.go:1.13 pkgsrc/pkgtools/pkglint/files/files.go:1.14
--- pkgsrc/pkgtools/pkglint/files/files.go:1.13 Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/files.go      Sat Jan 27 18:50:36 2018
@@ -23,9 +23,6 @@ func LoadExistingLines(fname string, joi
        if err != nil {
                NewLineWhole(fname).Fatalf("Cannot be read.")
        }
-       if lines == nil {
-               NewLineWhole(fname).Fatalf("Must not be empty.")
-       }
        return lines
 }
 
Index: pkgsrc/pkgtools/pkglint/files/patches_test.go
diff -u pkgsrc/pkgtools/pkglint/files/patches_test.go:1.13 pkgsrc/pkgtools/pkglint/files/patches_test.go:1.14
--- pkgsrc/pkgtools/pkglint/files/patches_test.go:1.13  Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/patches_test.go       Sat Jan 27 18:50:36 2018
@@ -1,15 +1,13 @@
 package main
 
-import (
-       check "gopkg.in/check.v1"
-       "io/ioutil"
-)
+import "gopkg.in/check.v1"
 
 func (s *Suite) Test_ChecklinesPatch__with_comment(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
-       lines := T.NewLines("patch-WithComment",
-               "$"+"NetBSD$",
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
+       lines := t.NewLines("patch-WithComment",
+               RcsId,
                "",
                "Text",
                "Text",
@@ -24,13 +22,14 @@ func (s *Suite) Test_ChecklinesPatch__wi
 
        ChecklinesPatch(lines)
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_ChecklinesPatch__without_empty_line__autofix(c *check.C) {
-       s.Init(c)
-       patchFilename := s.CreateTmpFileLines("patch-WithoutEmptyLines",
-               "$"+"NetBSD$",
+       t := s.Init(c)
+
+       patchLines := t.SetupFileLines("patch-WithoutEmptyLines",
+               RcsId,
                "Text",
                "--- file.orig",
                "+++ file",
@@ -39,53 +38,47 @@ func (s *Suite) Test_ChecklinesPatch__wi
                "-old line",
                "+old line",
                " context after")
-       distinfoFilename := s.CreateTmpFileLines("distinfo",
-               "$"+"NetBSD$",
+       t.SetupFileLines("distinfo",
+               RcsId,
                "",
                "SHA1 (some patch) = 87ffcaaa0b0677ec679fff612b44df1af05f04df") // Taken from breakpoint at AutofixDistinfo
 
-       s.UseCommandLine("-Wall", "--autofix")
-       lines := LoadExistingLines(patchFilename, false)
-       G.CurrentDir = s.TmpDir()
+       t.SetupCommandLine("-Wall", "--autofix")
+       G.CurrentDir = t.TmpDir()
        G.Pkg = &Package{DistinfoFile: "distinfo"}
 
-       ChecklinesPatch(lines)
+       ChecklinesPatch(patchLines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "AUTOFIX: ~/patch-WithoutEmptyLines:2: Inserting a line \"\" before this line.",
                "AUTOFIX: ~/patch-WithoutEmptyLines:3: Inserting a line \"\" before this line.",
-               "AUTOFIX: ~/patch-WithoutEmptyLines: Has been auto-fixed. Please re-run pkglint.",
                "AUTOFIX: ~/distinfo:3: Replacing \"87ffcaaa0b0677ec679fff612b44df1af05f04df\" "+
-                       "with \"a7c35294b3853da0acedf8a972cb266baa9582a3\".",
-               "AUTOFIX: ~/distinfo: Has been auto-fixed. Please re-run pkglint.")
+                       "with \"a7c35294b3853da0acedf8a972cb266baa9582a3\".")
 
-       fixed, err := ioutil.ReadFile(patchFilename)
-       c.Assert(err, check.IsNil)
-       c.Check(string(fixed), equals, ""+
-               "$"+"NetBSD$\n"+
-               "\n"+
-               "Text\n"+
-               "\n"+
-               "--- file.orig\n"+
-               "+++ file\n"+
-               "@@ -5,3 +5,3 @@\n"+
-               " context before\n"+
-               "-old line\n"+
-               "+old line\n"+
-               " context after\n")
-       fixedDistinfo, err := ioutil.ReadFile(distinfoFilename)
-       c.Assert(err, check.IsNil)
-       c.Check(string(fixedDistinfo), equals, ""+
-               "$"+"NetBSD$\n"+
-               "\n"+
-               "SHA1 (some patch) = a7c35294b3853da0acedf8a972cb266baa9582a3\n")
+       t.CheckFileLines("patch-WithoutEmptyLines",
+               RcsId,
+               "",
+               "Text",
+               "",
+               "--- file.orig",
+               "+++ file",
+               "@@ -5,3 +5,3 @@",
+               " context before",
+               "-old line",
+               "+old line",
+               " context after")
+       t.CheckFileLines("distinfo",
+               RcsId,
+               "",
+               "SHA1 (some patch) = a7c35294b3853da0acedf8a972cb266baa9582a3")
 }
 
 func (s *Suite) Test_ChecklinesPatch__without_comment(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
-       lines := T.NewLines("patch-WithoutComment",
-               "$"+"NetBSD$",
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
+       lines := t.NewLines("patch-WithoutComment",
+               RcsId,
                "",
                "--- file.orig",
                "+++ file",
@@ -97,15 +90,16 @@ func (s *Suite) Test_ChecklinesPatch__wi
 
        ChecklinesPatch(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: patch-WithoutComment:3: Each patch must be documented.")
 }
 
 func (s *Suite) Test_ChecklinesPatch__git_without_comment(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
-       lines := T.NewLines("patch-aa",
-               "$"+"NetBSD$",
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
+       lines := t.NewLines("patch-aa",
+               RcsId,
                "",
                "diff --git a/aa b/aa",
                "index 1234567..1234567 100644",
@@ -117,24 +111,26 @@ func (s *Suite) Test_ChecklinesPatch__gi
 
        ChecklinesPatch(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: patch-aa:5: Each patch must be documented.")
 }
 
 func (s *Suite) Test_checklineOtherAbsolutePathname(c *check.C) {
-       s.Init(c)
-       line := T.NewLine("patch-ag", 1, "+$install -s -c ./bin/rosegarden ${DESTDIR}$BINDIR")
+       t := s.Init(c)
+
+       line := t.NewLine("patch-ag", 1, "+$install -s -c ./bin/rosegarden ${DESTDIR}$BINDIR")
 
        checklineOtherAbsolutePathname(line, line.Text)
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_ChecklinesPatch__error_code(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
-       lines := T.NewLines("patch-ErrorCode",
-               "$"+"NetBSD$",
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
+       lines := t.NewLines("patch-ErrorCode",
+               RcsId,
                "",
                "*** Error code 1", // Looks like a context diff, but isn't.
                "",
@@ -148,14 +144,15 @@ func (s *Suite) Test_ChecklinesPatch__er
 
        ChecklinesPatch(lines)
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_ChecklinesPatch__wrong_header_order(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
-       lines := T.NewLines("patch-WrongOrder",
-               "$"+"NetBSD$",
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
+       lines := t.NewLines("patch-WrongOrder",
+               RcsId,
                "",
                "Text",
                "Text",
@@ -170,15 +167,16 @@ func (s *Suite) Test_ChecklinesPatch__wr
 
        ChecklinesPatch(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: patch-WrongOrder:7: Unified diff headers should be first ---, then +++.")
 }
 
 func (s *Suite) Test_ChecklinesPatch__context_diff(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
-       lines := T.NewLines("patch-ctx",
-               "$"+"NetBSD$",
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
+       lines := t.NewLines("patch-ctx",
+               RcsId,
                "",
                "diff -cr history.c.orig history.c",
                "*** history.c.orig",
@@ -186,29 +184,31 @@ func (s *Suite) Test_ChecklinesPatch__co
 
        ChecklinesPatch(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: patch-ctx:4: Each patch must be documented.",
                "WARN: patch-ctx:4: Please use unified diffs (diff -u) for patches.")
 }
 
 func (s *Suite) Test_ChecklinesPatch__no_patch(c *check.C) {
-       s.Init(c)
-       lines := T.NewLines("patch-aa",
-               "$"+"NetBSD$",
+       t := s.Init(c)
+
+       lines := t.NewLines("patch-aa",
+               RcsId,
                "",
                "-- oldfile",
                "++ newfile")
 
        ChecklinesPatch(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: patch-aa: Contains no patch.")
 }
 
 func (s *Suite) Test_ChecklinesPatch__two_patched_files(c *check.C) {
-       s.Init(c)
-       lines := T.NewLines("patch-aa",
-               "$"+"NetBSD$",
+       t := s.Init(c)
+
+       lines := t.NewLines("patch-aa",
+               RcsId,
                "",
                "--- oldfile",
                "+++ newfile",
@@ -223,15 +223,16 @@ func (s *Suite) Test_ChecklinesPatch__tw
 
        ChecklinesPatch(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: patch-aa:3: Each patch must be documented.",
                "WARN: patch-aa: Contains patches for 2 files, should be only one.")
 }
 
 func (s *Suite) Test_ChecklinesPatch__documentation_that_looks_like_patch_lines(c *check.C) {
-       s.Init(c)
-       lines := T.NewLines("patch-aa",
-               "$"+"NetBSD$",
+       t := s.Init(c)
+
+       lines := t.NewLines("patch-aa",
+               RcsId,
                "",
                "--- oldfile",
                "",
@@ -241,14 +242,15 @@ func (s *Suite) Test_ChecklinesPatch__do
 
        ChecklinesPatch(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: patch-aa: Contains no patch.")
 }
 
 func (s *Suite) Test_ChecklinesPatch__only_unified_header_but_no_content(c *check.C) {
-       s.Init(c)
-       lines := T.NewLines("patch-unified",
-               "$"+"NetBSD$",
+       t := s.Init(c)
+
+       lines := t.NewLines("patch-unified",
+               RcsId,
                "",
                "Documentation for the patch",
                "",
@@ -257,14 +259,15 @@ func (s *Suite) Test_ChecklinesPatch__on
 
        ChecklinesPatch(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: patch-unified:EOF: No patch hunks for \"file\".")
 }
 
 func (s *Suite) Test_ChecklinesPatch__only_context_header_but_no_content(c *check.C) {
-       s.Init(c)
-       lines := T.NewLines("patch-context",
-               "$"+"NetBSD$",
+       t := s.Init(c)
+
+       lines := t.NewLines("patch-context",
+               RcsId,
                "",
                "Documentation for the patch",
                "",
@@ -275,14 +278,15 @@ func (s *Suite) Test_ChecklinesPatch__on
 
        // Context diffs are deprecated, therefore it is not worth
        // adding extra code for checking them thoroughly.
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: patch-context:5: Please use unified diffs (diff -u) for patches.")
 }
 
 func (s *Suite) Test_ChecklinesPatch__Makefile_with_absolute_pathnames(c *check.C) {
-       s.Init(c)
-       lines := T.NewLines("patch-unified",
-               "$"+"NetBSD$",
+       t := s.Init(c)
+
+       lines := t.NewLines("patch-unified",
+               RcsId,
                "",
                "Documentation for the patch",
                "",
@@ -300,7 +304,7 @@ func (s *Suite) Test_ChecklinesPatch__Ma
 
        ChecklinesPatch(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: patch-unified:10: Found absolute pathname: /bin/cp",
                "WARN: patch-unified:13: Found absolute pathname: /bin/cp")
 
@@ -308,7 +312,7 @@ func (s *Suite) Test_ChecklinesPatch__Ma
 
        ChecklinesPatch(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: patch-unified:8: Found absolute pathname: /bin/cp",
                "WARN: patch-unified:10: Found absolute pathname: /bin/cp",
                "WARN: patch-unified:13: Found absolute pathname: /bin/cp",
@@ -316,9 +320,10 @@ func (s *Suite) Test_ChecklinesPatch__Ma
 }
 
 func (s *Suite) Test_ChecklinesPatch__no_newline_with_text_following(c *check.C) {
-       s.Init(c)
-       lines := T.NewLines("patch-aa",
-               "$"+"NetBSD$",
+       t := s.Init(c)
+
+       lines := t.NewLines("patch-aa",
+               RcsId,
                "",
                "comment",
                "",
@@ -333,14 +338,15 @@ func (s *Suite) Test_ChecklinesPatch__no
 
        ChecklinesPatch(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: patch-aa:12: Empty line or end of file expected.")
 }
 
 func (s *Suite) Test_ChecklinesPatch__no_newline(c *check.C) {
-       s.Init(c)
-       lines := T.NewLines("patch-aa",
-               "$"+"NetBSD$",
+       t := s.Init(c)
+
+       lines := t.NewLines("patch-aa",
+               RcsId,
                "",
                "comment",
                "",
@@ -354,13 +360,14 @@ func (s *Suite) Test_ChecklinesPatch__no
 
        ChecklinesPatch(lines)
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_ChecklinesPatch__empty_lines_left_out_at_eof(c *check.C) {
-       s.Init(c)
-       lines := T.NewLines("patch-aa",
-               "$"+"NetBSD$",
+       t := s.Init(c)
+
+       lines := t.NewLines("patch-aa",
+               RcsId,
                "",
                "comment",
                "",
@@ -376,15 +383,16 @@ func (s *Suite) Test_ChecklinesPatch__em
 
        ChecklinesPatch(lines)
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 }
 
 // In some context lines, the leading space character is missing.
 // Since this is no problem for patch(1), pkglint also doesn't complain.
 func (s *Suite) Test_ChecklinesPatch__context_lines_with_tab_instead_of_space(c *check.C) {
-       s.Init(c)
-       lines := T.NewLines("patch-aa",
-               "$"+"NetBSD$",
+       t := s.Init(c)
+
+       lines := t.NewLines("patch-aa",
+               RcsId,
                "",
                "comment",
                "",
@@ -398,5 +406,5 @@ func (s *Suite) Test_ChecklinesPatch__co
 
        ChecklinesPatch(lines)
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 }

Index: pkgsrc/pkgtools/pkglint/files/files_test.go
diff -u pkgsrc/pkgtools/pkglint/files/files_test.go:1.12 pkgsrc/pkgtools/pkglint/files/files_test.go:1.13
--- pkgsrc/pkgtools/pkglint/files/files_test.go:1.12    Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/files_test.go Sat Jan 27 18:50:36 2018
@@ -30,6 +30,8 @@ func (s *Suite) Test_convertToLogicalLin
 }
 
 func (s *Suite) Test_convertToLogicalLines_continuationInLastLine(c *check.C) {
+       t := s.Init(c)
+
        rawText := "" +
                "last line\\"
 
@@ -37,7 +39,8 @@ func (s *Suite) Test_convertToLogicalLin
 
        c.Check(lines, check.HasLen, 1)
        c.Check(lines[0].String(), equals, "fname_contlast:1: last line\\")
-       c.Check(s.Stdout(), equals, "ERROR: fname_contlast:EOF: File must end with a newline.\n")
+       t.CheckOutputLines(
+               "ERROR: fname_contlast:EOF: File must end with a newline.")
 }
 
 func (s *Suite) Test_splitRawLine(c *check.C) {
Index: pkgsrc/pkgtools/pkglint/files/globaldata_test.go
diff -u pkgsrc/pkgtools/pkglint/files/globaldata_test.go:1.12 pkgsrc/pkgtools/pkglint/files/globaldata_test.go:1.13
--- pkgsrc/pkgtools/pkglint/files/globaldata_test.go:1.12       Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/globaldata_test.go    Sat Jan 27 18:50:36 2018
@@ -13,7 +13,9 @@ func (s *Suite) Test_GlobalData_InitVart
 }
 
 func (s *Suite) Test_parselinesSuggestedUpdates(c *check.C) {
-       lines := T.NewLines("doc/TODO",
+       t := s.Init(c)
+
+       lines := t.NewLines("doc/TODO",
                "",
                "Suggested package updates",
                "==============",
@@ -32,26 +34,27 @@ func (s *Suite) Test_parselinesSuggested
 }
 
 func (s *Suite) Test_GlobalData_loadTools(c *check.C) {
-       s.Init(c)
-       s.CreateTmpFileLines("mk/tools/bsd.tools.mk",
+       t := s.Init(c)
+
+       t.SetupFileLines("mk/tools/bsd.tools.mk",
                ".include \"flex.mk\"",
                ".include \"gettext.mk\"")
-       s.CreateTmpFileLines("mk/tools/defaults.mk",
+       t.SetupFileLines("mk/tools/defaults.mk",
                "_TOOLS_VARNAME.chown=CHOWN",
                "_TOOLS_VARNAME.gawk=AWK",
                "_TOOLS_VARNAME.mv=MV",
                "_TOOLS_VARNAME.pwd=PWD")
-       s.CreateTmpFileLines("mk/tools/flex.mk",
+       t.SetupFileLines("mk/tools/flex.mk",
                "# empty")
-       s.CreateTmpFileLines("mk/tools/gettext.mk",
+       t.SetupFileLines("mk/tools/gettext.mk",
                "USE_TOOLS+=msgfmt",
                "TOOLS_CREATE+=msgfmt")
-       s.CreateTmpFileLines("mk/bsd.prefs.mk",
+       t.SetupFileLines("mk/bsd.prefs.mk",
                "USE_TOOLS+=\tpwd")
-       s.CreateTmpFileLines("mk/bsd.pkg.mk",
+       t.SetupFileLines("mk/bsd.pkg.mk",
                "USE_TOOLS+=\tmv")
-       G.globalData.Pkgsrcdir = s.tmpdir
-       G.CurrentDir = s.tmpdir
+       G.globalData.Pkgsrcdir = t.TmpDir()
+       G.CurrentDir = t.TmpDir()
        G.CurPkgsrcdir = "."
 
        G.globalData.loadTools()
@@ -59,35 +62,36 @@ func (s *Suite) Test_GlobalData_loadTool
        trace.Tracing = true
        G.globalData.Tools.Trace()
 
-       c.Check(s.Output(), equals, ""+
-               "TRACE: + (*ToolRegistry).Trace()\n"+
-               "TRACE: 1   tool &{Name:TOOLS_mv Varname: MustUseVarForm:false Predefined:true UsableAtLoadtime:false}\n"+
-               "TRACE: 1   tool &{Name:TOOLS_pwd Varname: MustUseVarForm:false Predefined:true UsableAtLoadtime:true}\n"+
-               "TRACE: 1   tool &{Name:chown Varname:CHOWN MustUseVarForm:false Predefined:false UsableAtLoadtime:false}\n"+
-               "TRACE: 1   tool &{Name:echo Varname:ECHO MustUseVarForm:true Predefined:true UsableAtLoadtime:true}\n"+
-               "TRACE: 1   tool &{Name:echo -n Varname:ECHO_N MustUseVarForm:true Predefined:true UsableAtLoadtime:true}\n"+
-               "TRACE: 1   tool &{Name:false Varname:FALSE MustUseVarForm:true Predefined:true UsableAtLoadtime:false}\n"+
-               "TRACE: 1   tool &{Name:gawk Varname:AWK MustUseVarForm:false Predefined:false UsableAtLoadtime:false}\n"+
-               "TRACE: 1   tool &{Name:msgfmt Varname: MustUseVarForm:false Predefined:false UsableAtLoadtime:false}\n"+
-               "TRACE: 1   tool &{Name:mv Varname:MV MustUseVarForm:false Predefined:true UsableAtLoadtime:false}\n"+
-               "TRACE: 1   tool &{Name:pwd Varname:PWD MustUseVarForm:false Predefined:true UsableAtLoadtime:true}\n"+
-               "TRACE: 1   tool &{Name:test Varname:TEST MustUseVarForm:true Predefined:true UsableAtLoadtime:true}\n"+
-               "TRACE: 1   tool &{Name:true Varname:TRUE MustUseVarForm:true Predefined:true UsableAtLoadtime:true}\n"+
-               "TRACE: - (*ToolRegistry).Trace()\n")
+       t.CheckOutputLines(
+               "TRACE: + (*ToolRegistry).Trace()",
+               "TRACE: 1   tool &{Name:TOOLS_mv Varname: MustUseVarForm:false Predefined:true UsableAtLoadtime:false}",
+               "TRACE: 1   tool &{Name:TOOLS_pwd Varname: MustUseVarForm:false Predefined:true UsableAtLoadtime:true}",
+               "TRACE: 1   tool &{Name:chown Varname:CHOWN MustUseVarForm:false Predefined:false UsableAtLoadtime:false}",
+               "TRACE: 1   tool &{Name:echo Varname:ECHO MustUseVarForm:true Predefined:true UsableAtLoadtime:true}",
+               "TRACE: 1   tool &{Name:echo -n Varname:ECHO_N MustUseVarForm:true Predefined:true UsableAtLoadtime:true}",
+               "TRACE: 1   tool &{Name:false Varname:FALSE MustUseVarForm:true Predefined:true UsableAtLoadtime:false}",
+               "TRACE: 1   tool &{Name:gawk Varname:AWK MustUseVarForm:false Predefined:false UsableAtLoadtime:false}",
+               "TRACE: 1   tool &{Name:msgfmt Varname: MustUseVarForm:false Predefined:false UsableAtLoadtime:false}",
+               "TRACE: 1   tool &{Name:mv Varname:MV MustUseVarForm:false Predefined:true UsableAtLoadtime:false}",
+               "TRACE: 1   tool &{Name:pwd Varname:PWD MustUseVarForm:false Predefined:true UsableAtLoadtime:true}",
+               "TRACE: 1   tool &{Name:test Varname:TEST MustUseVarForm:true Predefined:true UsableAtLoadtime:true}",
+               "TRACE: 1   tool &{Name:true Varname:TRUE MustUseVarForm:true Predefined:true UsableAtLoadtime:true}",
+               "TRACE: - (*ToolRegistry).Trace()")
 }
 
 func (s *Suite) Test_GlobalData_loadDocChangesFromFile(c *check.C) {
-       s.Init(c)
-       s.CreateTmpFile("doc/CHANGES-2015", ""+
-               "\tAdded category/package version 1.0 [author1 2015-01-01]\n"+
-               "\tUpdated category/package to 1.5 [author2 2015-01-02]\n"+
-               "\tRenamed category/package to category/pkg [author3 2015-01-03]\n"+
-               "\tMoved category/package to other/package [author4 2015-01-04]\n"+
-               "\tRemoved category/package [author5 2015-01-05]\n"+
-               "\tRemoved category/package successor category/package2 [author6 2015-01-06]\n"+
-               "\tDowngraded category/package to 1.2 [author7 2015-01-07]\n")
+       t := s.Init(c)
+
+       t.SetupFileLines("doc/CHANGES-2015",
+               "\tAdded category/package version 1.0 [author1 2015-01-01]",
+               "\tUpdated category/package to 1.5 [author2 2015-01-02]",
+               "\tRenamed category/package to category/pkg [author3 2015-01-03]",
+               "\tMoved category/package to other/package [author4 2015-01-04]",
+               "\tRemoved category/package [author5 2015-01-05]",
+               "\tRemoved category/package successor category/package2 [author6 2015-01-06]",
+               "\tDowngraded category/package to 1.2 [author7 2015-01-07]")
 
-       changes := G.globalData.loadDocChangesFromFile(s.tmpdir + "/doc/CHANGES-2015")
+       changes := G.globalData.loadDocChangesFromFile(t.TmpDir() + "/doc/CHANGES-2015")
 
        c.Assert(len(changes), equals, 7)
        c.Check(*changes[0], equals, Change{changes[0].Line, "Added", "category/package", "1.0", "author1", "2015-01-01"})
@@ -100,22 +104,27 @@ func (s *Suite) Test_GlobalData_loadDocC
 }
 
 func (s *Suite) Test_GlobalData_deprecated(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.loadDeprecatedVars()
-       mkline := T.NewMkLine("Makefile", 5, "USE_PERL5=\tyes")
+       mkline := t.NewMkLine("Makefile", 5, "USE_PERL5=\tyes")
 
        MkLineChecker{mkline}.checkVarassign()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:5: Definition of USE_PERL5 is deprecated. Use USE_TOOLS+=perl or USE_TOOLS+=perl:run instead.")
 }
 
-// https://mail-index.netbsd.org/tech-pkg/2017/01/18/msg017698.html
+// Ensures that pkglint can handle MASTER_SITES definitions with and
+// without line continuations.
+//
+// See https://mail-index.netbsd.org/tech-pkg/2017/01/18/msg017698.html.
 func (s *Suite) Test_GlobalData_loadDistSites(c *check.C) {
-       s.Init(c)
-       G.globalData.Pkgsrcdir = s.TmpDir()
-       s.CreateTmpFileLines("mk/fetch/sites.mk",
-               mkrcsid,
+       t := s.Init(c)
+
+       G.globalData.Pkgsrcdir = t.TmpDir()
+       t.CreateFileLines("mk/fetch/sites.mk",
+               MkRcsId,
                "",
                "MASTER_SITE_A+= https://example.org/distfiles/";,
                "MASTER_SITE_B+= https://b.example.org/distfiles/ \\",
Index: pkgsrc/pkgtools/pkglint/files/pkglint_test.go
diff -u pkgsrc/pkgtools/pkglint/files/pkglint_test.go:1.12 pkgsrc/pkgtools/pkglint/files/pkglint_test.go:1.13
--- pkgsrc/pkgtools/pkglint/files/pkglint_test.go:1.12  Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/pkglint_test.go       Sat Jan 27 18:50:36 2018
@@ -3,30 +3,49 @@ package main
 import (
        "strings"
 
-       check "gopkg.in/check.v1"
+       "gopkg.in/check.v1"
        "netbsd.org/pkglint/trace"
        "os"
 )
 
 func (s *Suite) Test_Pkglint_Main_help(c *check.C) {
+       t := s.Init(c)
+
        exitcode := new(Pkglint).Main("pkglint", "-h")
 
        c.Check(exitcode, equals, 0)
-       c.Check(s.Output(), check.Matches, `^\Qusage: pkglint [options] dir...\E\n(?s).+`)
+       c.Check(t.Output(), check.Matches, `^\Qusage: pkglint [options] dir...\E\n(?s).+`)
 }
 
 func (s *Suite) Test_Pkglint_Main_version(c *check.C) {
+       t := s.Init(c)
+
        exitcode := new(Pkglint).Main("pkglint", "--version")
 
        c.Check(exitcode, equals, 0)
-       c.Check(s.Output(), equals, confVersion+"\n")
+       t.CheckOutputLines(
+               confVersion)
 }
 
 func (s *Suite) Test_Pkglint_Main_no_args(c *check.C) {
+       t := s.Init(c)
+
        exitcode := new(Pkglint).Main("pkglint")
 
        c.Check(exitcode, equals, 1)
-       c.Check(s.Stderr(), equals, "FATAL: \".\" is not inside a pkgsrc tree.\n")
+       t.CheckOutputLines(
+               "FATAL: \".\" is not inside a pkgsrc tree.")
+}
+
+func (s *Suite) Test_Pkglint_Main__only(c *check.C) {
+       t := s.Init(c)
+
+       exitcode := new(Pkglint).ParseCommandLine([]string{"pkglint", "-Wall", "-o", ":Q", "--version"})
+
+       c.Check(exitcode, deepEquals, new(int))
+       c.Check(G.opts.LogOnly, deepEquals, []string{":Q"})
+       t.CheckOutputLines(
+               "@VERSION@")
 }
 
 // go test -c -covermode count
@@ -42,47 +61,51 @@ func (s *Suite) Test_Pkglint_coverage(c 
 }
 
 func (s *Suite) Test_Pkglint_CheckDirent__outside(c *check.C) {
-       s.Init(c)
-       s.CreateTmpFile("empty", "")
+       t := s.Init(c)
+
+       t.SetupFileLines("empty")
 
-       new(Pkglint).CheckDirent(s.tmpdir)
+       new(Pkglint).CheckDirent(t.TmpDir())
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: ~: Cannot determine the pkgsrc root directory for \"~\".")
 }
 
 func (s *Suite) Test_Pkglint_CheckDirent(c *check.C) {
-       s.Init(c)
-       s.CreateTmpFile("mk/bsd.pkg.mk", "")
-       s.CreateTmpFile("category/package/Makefile", "")
-       s.CreateTmpFile("category/Makefile", "")
-       s.CreateTmpFile("Makefile", "")
-       G.globalData.Pkgsrcdir = s.tmpdir
+       t := s.Init(c)
+
+       t.SetupFileLines("mk/bsd.pkg.mk")
+       t.SetupFileLines("category/package/Makefile")
+       t.SetupFileLines("category/Makefile")
+       t.SetupFileLines("Makefile")
+       G.globalData.Pkgsrcdir = t.TmpDir()
        pkglint := new(Pkglint)
 
-       pkglint.CheckDirent(s.tmpdir)
+       pkglint.CheckDirent(t.TmpDir())
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: ~/Makefile: Must not be empty.")
 
-       pkglint.CheckDirent(s.tmpdir + "/category")
+       pkglint.CheckDirent(t.TempFilename("category"))
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: ~/category/Makefile: Must not be empty.")
 
-       pkglint.CheckDirent(s.tmpdir + "/category/package")
+       pkglint.CheckDirent(t.TempFilename("category/package"))
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: ~/category/package/Makefile: Must not be empty.")
 
-       pkglint.CheckDirent(s.tmpdir + "/category/package/nonexistent")
+       pkglint.CheckDirent(t.TempFilename("category/package/nonexistent"))
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: ~/category/package/nonexistent: No such file or directory.")
 }
 
 func (s *Suite) Test_resolveVariableRefs__circular_reference(c *check.C) {
-       mkline := T.NewMkLine("fname", 1, "GCC_VERSION=${GCC_VERSION}")
+       t := s.Init(c)
+
+       mkline := t.NewMkLine("fname", 1, "GCC_VERSION=${GCC_VERSION}")
        G.Pkg = NewPackage(".")
        G.Pkg.vardef["GCC_VERSION"] = mkline
 
@@ -92,9 +115,11 @@ func (s *Suite) Test_resolveVariableRefs
 }
 
 func (s *Suite) Test_resolveVariableRefs__multilevel(c *check.C) {
-       mkline1 := T.NewMkLine("fname", 10, "_=${SECOND}")
-       mkline2 := T.NewMkLine("fname", 11, "_=${THIRD}")
-       mkline3 := T.NewMkLine("fname", 12, "_=got it")
+       t := s.Init(c)
+
+       mkline1 := t.NewMkLine("fname", 10, "_=${SECOND}")
+       mkline2 := t.NewMkLine("fname", 11, "_=${THIRD}")
+       mkline3 := t.NewMkLine("fname", 12, "_=got it")
        G.Pkg = NewPackage(".")
        defineVar(mkline1, "FIRST")
        defineVar(mkline2, "SECOND")
@@ -106,7 +131,9 @@ func (s *Suite) Test_resolveVariableRefs
 }
 
 func (s *Suite) Test_resolveVariableRefs__special_chars(c *check.C) {
-       mkline := T.NewMkLine("fname", 10, "_=x11")
+       t := s.Init(c)
+
+       mkline := t.NewMkLine("fname", 10, "_=x11")
        G.Pkg = NewPackage("category/pkg")
        G.Pkg.vardef["GST_PLUGINS0.10_TYPE"] = mkline
 
@@ -116,8 +143,9 @@ func (s *Suite) Test_resolveVariableRefs
 }
 
 func (s *Suite) Test_ChecklinesDescr(c *check.C) {
-       s.Init(c)
-       lines := T.NewLines("DESCR",
+       t := s.Init(c)
+
+       lines := t.NewLines("DESCR",
                strings.Repeat("X", 90),
                "", "", "", "", "", "", "", "", "10",
                "Try ${PREFIX}",
@@ -126,26 +154,28 @@ func (s *Suite) Test_ChecklinesDescr(c *
 
        ChecklinesDescr(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: DESCR:1: Line too long (should be no more than 80 characters).",
                "NOTE: DESCR:11: Variables are not expanded in the DESCR file.",
                "WARN: DESCR:25: File too long (should be no more than 24 lines).")
 }
 
 func (s *Suite) Test_ChecklinesMessage__short(c *check.C) {
-       s.Init(c)
-       lines := T.NewLines("MESSAGE",
+       t := s.Init(c)
+
+       lines := t.NewLines("MESSAGE",
                "one line")
 
        ChecklinesMessage(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: MESSAGE:1: File too short.")
 }
 
 func (s *Suite) Test_ChecklinesMessage__malformed(c *check.C) {
-       s.Init(c)
-       lines := T.NewLines("MESSAGE",
+       t := s.Init(c)
+
+       lines := t.NewLines("MESSAGE",
                "1",
                "2",
                "3",
@@ -154,44 +184,45 @@ func (s *Suite) Test_ChecklinesMessage__
 
        ChecklinesMessage(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: MESSAGE:1: Expected a line of exactly 75 \"=\" characters.",
                "ERROR: MESSAGE:2: Expected \"$"+"NetBSD$\".",
                "WARN: MESSAGE:5: Expected a line of exactly 75 \"=\" characters.")
 }
 
 func (s *Suite) Test_GlobalData_Latest(c *check.C) {
-       s.Init(c)
-       G.globalData.Pkgsrcdir = s.TmpDir()
+       t := s.Init(c)
+
+       G.globalData.Pkgsrcdir = t.TmpDir()
 
        latest1 := G.globalData.Latest("lang", `^python[0-9]+$`, "../../lang/$0")
 
        c.Check(latest1, equals, "")
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: Cannot find latest version of \"^python[0-9]+$\" in \"~\".")
 
-       s.CreateTmpFile("lang/Makefile", "")
+       t.SetupFileLines("lang/Makefile")
        G.globalData.latest = nil
 
        latest2 := G.globalData.Latest("lang", `^python[0-9]+$`, "../../lang/$0")
 
        c.Check(latest2, equals, "")
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: Cannot find latest version of \"^python[0-9]+$\" in \"~\".")
 
-       s.CreateTmpFile("lang/python27/Makefile", "")
+       t.SetupFileLines("lang/python27/Makefile")
        G.globalData.latest = nil
 
        latest3 := G.globalData.Latest("lang", `^python[0-9]+$`, "../../lang/$0")
 
        c.Check(latest3, equals, "../../lang/python27")
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 
-       s.CreateTmpFile("lang/python35/Makefile", "")
+       t.SetupFileLines("lang/python35/Makefile")
        G.globalData.latest = nil
 
        latest4 := G.globalData.Latest("lang", `^python[0-9]+$`, "../../lang/$0")
 
        c.Check(latest4, equals, "../../lang/python35")
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 }

Index: pkgsrc/pkgtools/pkglint/files/licenses_test.go
diff -u pkgsrc/pkgtools/pkglint/files/licenses_test.go:1.9 pkgsrc/pkgtools/pkglint/files/licenses_test.go:1.10
--- pkgsrc/pkgtools/pkglint/files/licenses_test.go:1.9  Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/licenses_test.go      Sat Jan 27 18:50:36 2018
@@ -5,26 +5,28 @@ import (
 )
 
 func (s *Suite) Test_checklineLicense(c *check.C) {
-       s.Init(c)
-       s.CreateTmpFile("licenses/gnu-gpl-v2", "Most software \u2026")
-       mkline := T.NewMkLine("Makefile", 7, "LICENSE=dummy")
-       G.globalData.Pkgsrcdir = s.tmpdir
-       G.CurrentDir = s.tmpdir
+       t := s.Init(c)
+
+       t.SetupFileLines("licenses/gnu-gpl-v2",
+               "Most software \u2026")
+       mkline := t.NewMkLine("Makefile", 7, "LICENSE=dummy")
+       G.globalData.Pkgsrcdir = t.TmpDir()
+       G.CurrentDir = t.TmpDir()
 
        licenseChecker := &LicenseChecker{mkline}
        licenseChecker.Check("gpl-v2", opAssign)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:7: License file ~/licenses/gpl-v2 does not exist.")
 
        licenseChecker.Check("no-profit shareware", opAssign)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: Makefile:7: Parse error for license condition \"no-profit shareware\".")
 
        licenseChecker.Check("no-profit AND shareware", opAssign)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:7: License file ~/licenses/no-profit does not exist.",
                "ERROR: Makefile:7: License \"no-profit\" must not be used.",
                "WARN: Makefile:7: License file ~/licenses/shareware does not exist.",
@@ -32,14 +34,14 @@ func (s *Suite) Test_checklineLicense(c 
 
        licenseChecker.Check("gnu-gpl-v2", opAssign)
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 
        licenseChecker.Check("gnu-gpl-v2 AND gnu-gpl-v2 OR gnu-gpl-v2", opAssign)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: Makefile:7: AND and OR operators in license conditions can only be combined using parentheses.")
 
        licenseChecker.Check("(gnu-gpl-v2 OR gnu-gpl-v2) AND gnu-gpl-v2", opAssign)
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 }
Index: pkgsrc/pkgtools/pkglint/files/logging.go
diff -u pkgsrc/pkgtools/pkglint/files/logging.go:1.9 pkgsrc/pkgtools/pkglint/files/logging.go:1.10
--- pkgsrc/pkgtools/pkglint/files/logging.go:1.9        Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/logging.go    Sat Jan 27 18:50:36 2018
@@ -120,7 +120,7 @@ func Explain(explanation ...string) {
 
        if G.Testing {
                for _, s := range explanation {
-                       if l := tabLength(s); l > 68 && contains(s, " ") {
+                       if l := tabWidth(s); l > 68 && contains(s, " ") {
                                lastSpace := strings.LastIndexByte(s[:68], ' ')
                                print(fmt.Sprintf("Long explanation line: %s\nBreak after: %s\n", s, s[:lastSpace]))
                        }

Index: pkgsrc/pkgtools/pkglint/files/line.go
diff -u pkgsrc/pkgtools/pkglint/files/line.go:1.19 pkgsrc/pkgtools/pkglint/files/line.go:1.20
--- pkgsrc/pkgtools/pkglint/files/line.go:1.19  Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/line.go       Sat Jan 27 18:50:36 2018
@@ -92,24 +92,24 @@ func (line *LineImpl) printSource(out *S
                for _, rawLine := range rawLines {
                        if rawLine.textnl != rawLine.orignl {
                                if rawLine.orignl != "" {
-                                       out.Write("- " + rawLine.orignl)
+                                       out.Write("-\t" + rawLine.orignl)
                                }
                                if rawLine.textnl != "" {
-                                       out.Write("+ " + rawLine.textnl)
+                                       out.Write("+\t" + rawLine.textnl)
                                }
                        } else {
-                               out.Write("> " + rawLine.orignl)
+                               out.Write(">\t" + rawLine.orignl)
                        }
                }
        }
 
        if line.autofix != nil {
                for _, before := range line.autofix.linesBefore {
-                       out.Write("+ " + before)
+                       out.Write("+\t" + before)
                }
                printDiff(line.autofix.lines)
                for _, after := range line.autofix.linesAfter {
-                       out.Write("+ " + after)
+                       out.Write("+\t" + after)
                }
        } else {
                printDiff(line.raw)
@@ -159,12 +159,6 @@ func (line *LineImpl) String() string {
        return line.Filename + ":" + line.Linenos() + ": " + line.Text
 }
 
-// Autofix returns a builder object for automatically fixing the line.
-// After building the object, call Apply to actually apply the changes to the line.
-//
-// The changed lines are not written back to disk immediately.
-// This is done by SaveAutofixChanges.
-//
 func (line *LineImpl) Autofix() *Autofix {
        if line.autofix == nil {
                line.autofix = NewAutofix(line)
Index: pkgsrc/pkgtools/pkglint/files/plist.go
diff -u pkgsrc/pkgtools/pkglint/files/plist.go:1.19 pkgsrc/pkgtools/pkglint/files/plist.go:1.20
--- pkgsrc/pkgtools/pkglint/files/plist.go:1.19 Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/plist.go      Sat Jan 27 18:50:36 2018
@@ -523,7 +523,7 @@ func (s *plistLineSorter) Sort() {
        }
 
        fix := firstLine.Autofix()
-       fix.Describef("Sorting the whole file.")
+       fix.Describef(int(firstLine.firstLine), "Sorting the whole file.")
        fix.Apply()
 
        var lines []Line
Index: pkgsrc/pkgtools/pkglint/files/shell_test.go
diff -u pkgsrc/pkgtools/pkglint/files/shell_test.go:1.19 pkgsrc/pkgtools/pkglint/files/shell_test.go:1.20
--- pkgsrc/pkgtools/pkglint/files/shell_test.go:1.19    Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/shell_test.go Sat Jan 27 18:50:36 2018
@@ -6,13 +6,14 @@ import (
 )
 
 func (s *Suite) Test_splitIntoShellTokens__line_continuation(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        words, rest := splitIntoShellTokens(dummyLine, "if true; then \\")
 
        c.Check(words, check.DeepEquals, []string{"if", "true", ";", "then"})
        c.Check(rest, equals, "\\")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Pkglint parse error in ShTokenizer.ShAtom at \"\\\\\" (quoting=plain)")
 }
 
@@ -105,11 +106,12 @@ func (s *Suite) Test_splitIntoShellToken
 }
 
 func (s *Suite) Test_ShellLine_CheckShellCommandLine(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
 
        checkShellCommandLine := func(shellCommand string) {
-               G.Mk = T.NewMkLines("fname",
+               G.Mk = t.NewMkLines("fname",
                        "\t"+shellCommand)
                shline := NewShellLine(G.Mk.mklines[0])
 
@@ -118,70 +120,72 @@ func (s *Suite) Test_ShellLine_CheckShel
 
        checkShellCommandLine("@# Comment")
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 
        checkShellCommandLine("uname=`uname`; echo $$uname; echo")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: Unknown shell command \"uname\".",
                "WARN: fname:1: Unknown shell command \"echo\".",
                "WARN: fname:1: Unknown shell command \"echo\".")
 
-       s.RegisterTool(&Tool{Name: "echo", Predefined: true})
+       t.SetupTool(&Tool{Name: "echo", Predefined: true})
        G.globalData.InitVartypes()
 
        checkShellCommandLine("echo ${PKGNAME:Q}") // vucQuotPlain
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: PKGNAME may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.",
                "NOTE: fname:1: The :Q operator isn't necessary for ${PKGNAME} here.")
 
        checkShellCommandLine("echo \"${CFLAGS:Q}\"") // vucQuotDquot
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: Please don't use the :Q operator in double quotes.",
-               "WARN: fname:1: CFLAGS may not be used in this file; it would be ok in Makefile, Makefile.common, options.mk, *.mk.",
-               "WARN: fname:1: Please use ${CFLAGS:M*:Q} instead of ${CFLAGS:Q} and make sure the variable appears outside of any quoting characters.")
+               "WARN: fname:1: CFLAGS may not be used in this file; "+
+                       "it would be ok in Makefile, Makefile.common, options.mk, *.mk.",
+               "WARN: fname:1: Please use ${CFLAGS:M*:Q} instead of ${CFLAGS:Q} "+
+                       "and make sure the variable appears outside of any quoting characters.")
 
        checkShellCommandLine("echo '${COMMENT:Q}'") // vucQuotSquot
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: COMMENT may not be used in any file; it is a write-only variable.",
                "WARN: fname:1: Please move ${COMMENT:Q} outside of any quoting characters.")
 
        checkShellCommandLine("echo target=$@ exitcode=$$? '$$' \"\\$$\"")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: Please use \"${.TARGET}\" instead of \"$@\".",
                "WARN: fname:1: The $? shell variable is often not available in \"set -e\" mode.")
 
        checkShellCommandLine("echo $$@")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: The $@ shell variable should only be used in double quotes.")
 
        checkShellCommandLine("echo \"$$\"") // As seen by make(1); the shell sees: echo "$"
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: Pkglint parse error in ShTokenizer.ShAtom at \"$$\\\"\" (quoting=d)",
                "WARN: fname:1: Pkglint ShellLine.CheckShellCommand: parse error at [\"]")
 
        checkShellCommandLine("echo \"\\n\"")
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 
        checkShellCommandLine("${RUN} for f in *.c; do echo $${f%.c}; done")
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 
        checkShellCommandLine("${RUN} echo $${variable+set}")
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 
        // Based on mail/thunderbird/Makefile, rev. 1.159
        checkShellCommandLine("${RUN} subdir=\"`unzip -c \"$$e\" install.rdf | awk '/re/ { print \"hello\" }'`\"")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: The exitcode of \"unzip\" at the left of the | operator is ignored.",
                "WARN: fname:1: Unknown shell command \"unzip\".",
                "WARN: fname:1: Unknown shell command \"awk\".")
@@ -189,13 +193,14 @@ func (s *Suite) Test_ShellLine_CheckShel
        // From mail/thunderbird/Makefile, rev. 1.159
        checkShellCommandLine("" +
                "${RUN} for e in ${XPI_FILES}; do " +
-               "  subdir=\"`${UNZIP_CMD} -c \"$$e\" install.rdf | awk '/^    <em:id>/ {sub(\".*<em:id>\",\"\");sub(\"</em:id>.*\",\"\");print;exit;}'`\" && " +
+               "  subdir=\"`${UNZIP_CMD} -c \"$$e\" install.rdf | " +
+               "" + "awk '/^    <em:id>/ {sub(\".*<em:id>\",\"\");sub(\"</em:id>.*\",\"\");print;exit;}'`\" && " +
                "  ${MKDIR} \"${WRKDIR}/extensions/$$subdir\" && " +
                "  cd \"${WRKDIR}/extensions/$$subdir\" && " +
                "  ${UNZIP_CMD} -aqo $$e; " +
                "done")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: XPI_FILES is used but not defined. Spelling mistake?",
                "WARN: fname:1: The exitcode of \"${UNZIP_CMD}\" at the left of the | operator is ignored.",
                "WARN: fname:1: UNZIP_CMD is used but not defined. Spelling mistake?",
@@ -212,14 +217,14 @@ func (s *Suite) Test_ShellLine_CheckShel
                "  ${TOOLS_PATH.msgfmt} -c -o \"$${lang%.po}.mo\" \"$${lang}\"; " +
                "done")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: WRKSRC may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.",
                "WARN: fname:1: Unknown shell command \"[\".",
                "WARN: fname:1: Unknown shell command \"${TOOLS_PATH.msgfmt}\".")
 
        checkShellCommandLine("@cp from to")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: The shell command \"cp\" should not be hidden.",
                "WARN: fname:1: Unknown shell command \"cp\".")
 
@@ -229,14 +234,15 @@ func (s *Suite) Test_ShellLine_CheckShel
        // A directory that is found in the PLIST.
        checkShellCommandLine("${RUN} ${INSTALL_DATA_DIR} share/pkgbase ${PREFIX}/share/pkgbase")
 
-       s.CheckOutputLines(
-               "NOTE: fname:1: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= share/pkgbase\" instead of \"${INSTALL_DATA_DIR}\".",
+       t.CheckOutputLines(
+               "NOTE: fname:1: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= share/pkgbase\" "+
+                       "instead of \"${INSTALL_DATA_DIR}\".",
                "WARN: fname:1: The INSTALL_*_DIR commands can only handle one directory at a time.")
 
        // A directory that is not found in the PLIST.
        checkShellCommandLine("${RUN} ${INSTALL_DATA_DIR} ${PREFIX}/share/other")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "NOTE: fname:1: You can use \"INSTALLATION_DIRS+= share/other\" instead of \"${INSTALL_DATA_DIR}\".")
 
        G.Pkg = nil
@@ -244,51 +250,54 @@ func (s *Suite) Test_ShellLine_CheckShel
        // See PR 46570, item "1. It does not"
        checkShellCommandLine("for x in 1 2 3; do echo \"$$x\" || exit 1; done")
 
-       s.CheckOutputEmpty() // No warning about missing error checking.
+       t.CheckOutputEmpty() // No warning about missing error checking.
 }
 
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__nofix(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       s.RegisterTool(&Tool{Name: "echo", Predefined: true})
-       G.Mk = T.NewMkLines("Makefile",
+       t.SetupTool(&Tool{Name: "echo", Predefined: true})
+       G.Mk = t.NewMkLines("Makefile",
                "\techo ${PKGNAME:Q}")
        shline := NewShellLine(G.Mk.mklines[0])
 
        shline.CheckShellCommandLine("echo ${PKGNAME:Q}")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "NOTE: Makefile:1: The :Q operator isn't necessary for ${PKGNAME} here.")
 }
 
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__show_autofix(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall", "--show-autofix")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall", "--show-autofix")
        G.globalData.InitVartypes()
-       s.RegisterTool(&Tool{Name: "echo", Predefined: true})
-       G.Mk = T.NewMkLines("Makefile",
+       t.SetupTool(&Tool{Name: "echo", Predefined: true})
+       G.Mk = t.NewMkLines("Makefile",
                "\techo ${PKGNAME:Q}")
        shline := NewShellLine(G.Mk.mklines[0])
 
        shline.CheckShellCommandLine("echo ${PKGNAME:Q}")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "NOTE: Makefile:1: The :Q operator isn't necessary for ${PKGNAME} here.",
                "AUTOFIX: Makefile:1: Replacing \"${PKGNAME:Q}\" with \"${PKGNAME}\".")
 }
 
 // Simple commands like echo(1) or printf(1) are assumed to never fail.
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__exitcode(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       s.RegisterTool(&Tool{Name: "cat", Predefined: true})
-       s.RegisterTool(&Tool{Name: "echo", Predefined: true})
-       s.RegisterTool(&Tool{Name: "printf", Predefined: true})
-       s.RegisterTool(&Tool{Name: "sed", Predefined: true})
-       s.RegisterTool(&Tool{Name: "right-side", Predefined: true})
-       G.Mk = T.NewMkLines("Makefile",
+       t.SetupTool(&Tool{Name: "cat", Predefined: true})
+       t.SetupTool(&Tool{Name: "echo", Predefined: true})
+       t.SetupTool(&Tool{Name: "printf", Predefined: true})
+       t.SetupTool(&Tool{Name: "sed", Predefined: true})
+       t.SetupTool(&Tool{Name: "right-side", Predefined: true})
+       G.Mk = t.NewMkLines("Makefile",
                "\t echo | right-side",
                "\t sed s,s,s, | right-side",
                "\t printf | sed s,s,s, | right-side ",
@@ -303,7 +312,7 @@ func (s *Suite) Test_ShellLine_CheckShel
                shline.CheckShellCommandLine(mkline.Shellcmd())
        }
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:4: The exitcode of \"cat\" at the left of the | operator is ignored.",
                "WARN: Makefile:5: The exitcode of \"cat\" at the left of the | operator is ignored.",
                "WARN: Makefile:6: The exitcode of \"cat\" at the left of the | operator is ignored.",
@@ -312,25 +321,27 @@ func (s *Suite) Test_ShellLine_CheckShel
 }
 
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__autofix(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall", "--autofix")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall", "--autofix")
        G.globalData.InitVartypes()
-       s.RegisterTool(&Tool{Name: "echo", Predefined: true})
-       G.Mk = T.NewMkLines("Makefile",
+       t.SetupTool(&Tool{Name: "echo", Predefined: true})
+       G.Mk = t.NewMkLines("Makefile",
                "\techo ${PKGNAME:Q}")
        shline := NewShellLine(G.Mk.mklines[0])
 
        shline.CheckShellCommandLine("echo ${PKGNAME:Q}")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "AUTOFIX: Makefile:1: Replacing \"${PKGNAME:Q}\" with \"${PKGNAME}\".")
 }
 
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__implementation(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       G.Mk = T.NewMkLines("fname",
+       G.Mk = t.NewMkLines("fname",
                "# dummy")
        shline := NewShellLine(G.Mk.mklines[0])
 
@@ -344,36 +355,39 @@ func (s *Suite) Test_ShellLine_CheckShel
 
        shline.CheckWord(text, false)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: Unknown shell command \"echo\".")
 
        shline.CheckShellCommandLine(text)
 
-       c.Check(s.Output(), equals, ""+ // No parse errors
-               "WARN: fname:1: Unknown shell command \"echo\".\n")
+       // No parse errors
+       t.CheckOutputLines(
+               "WARN: fname:1: Unknown shell command \"echo\".")
 }
 
 func (s *Suite) Test_ShellLine_CheckShelltext__dollar_without_variable(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
-       G.Mk = T.NewMkLines("fname",
+       G.Mk = t.NewMkLines("fname",
                "# dummy")
        shline := NewShellLine(G.Mk.mklines[0])
-       s.RegisterTool(&Tool{Name: "pax", Varname: "PAX"})
+       t.SetupTool(&Tool{Name: "pax", Varname: "PAX"})
        G.Mk.tools["pax"] = true
 
        shline.CheckShellCommandLine("pax -rwpp -s /.*~$$//g . ${DESTDIR}${PREFIX}")
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_ShellLine_CheckWord(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
 
        checkWord := func(shellWord string, checkQuoting bool) {
-               shline := T.NewShellLine("dummy.mk", 1, "\t echo "+shellWord)
+               shline := t.NewShellLine("dummy.mk", 1, "\t echo "+shellWord)
 
                shline.CheckWord(shellWord, checkQuoting)
        }
@@ -382,76 +396,79 @@ func (s *Suite) Test_ShellLine_CheckWord
 
        checkWord("${${list}}", false)
 
-       s.CheckOutputEmpty() // No warning for variables that are completely indirect.
+       t.CheckOutputEmpty() // No warning for variables that are completely indirect.
 
        checkWord("${SED_FILE.${id}}", false)
 
-       s.CheckOutputEmpty() // No warning for variables that are partly indirect.
+       t.CheckOutputEmpty() // No warning for variables that are partly indirect.
 
        checkWord("\"$@\"", false)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: dummy.mk:1: Please use \"${.TARGET}\" instead of \"$@\".")
 
        checkWord("${COMMENT:Q}", true)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: dummy.mk:1: COMMENT may not be used in any file; it is a write-only variable.")
 
        checkWord("\"${DISTINFO_FILE:Q}\"", true)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "NOTE: dummy.mk:1: The :Q operator isn't necessary for ${DISTINFO_FILE} here.")
 
        checkWord("embed${DISTINFO_FILE:Q}ded", true)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "NOTE: dummy.mk:1: The :Q operator isn't necessary for ${DISTINFO_FILE} here.")
 
        checkWord("s,\\.,,", true)
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 
        checkWord("\"s,\\.,,\"", true)
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_ShellLine_CheckWord__dollar_without_variable(c *check.C) {
-       s.Init(c)
-       shline := T.NewShellLine("fname", 1, "# dummy")
+       t := s.Init(c)
+
+       shline := t.NewShellLine("fname", 1, "# dummy")
 
        shline.CheckWord("/.*~$$//g", false) // Typical argument to pax(1).
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__echo(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
-       s.RegisterTool(&Tool{Name: "echo", Varname: "ECHO", MustUseVarForm: true, Predefined: true})
-       G.Mk = T.NewMkLines("fname",
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
+       t.SetupTool(&Tool{Name: "echo", Varname: "ECHO", MustUseVarForm: true, Predefined: true})
+       G.Mk = t.NewMkLines("fname",
                "# dummy")
-       mkline := T.NewMkLine("fname", 3, "# dummy")
+       mkline := t.NewMkLine("fname", 3, "# dummy")
 
        MkLineChecker{mkline}.checkText("echo \"hello, world\"")
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 
        NewShellLine(mkline).CheckShellCommandLine("echo \"hello, world\"")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:3: Please use \"${ECHO}\" instead of \"echo\".")
 }
 
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__shell_variables(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        text := "\tfor f in *.pl; do ${SED} s,@PREFIX@,${PREFIX}, < $f > $f.tmp && ${MV} $f.tmp $f; done"
 
-       shline := T.NewShellLine("Makefile", 3, text)
+       shline := t.NewShellLine("Makefile", 3, text)
        shline.CheckShellCommandLine(text)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.",
                "WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.",
                "WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.",
@@ -460,31 +477,32 @@ func (s *Suite) Test_ShellLine_CheckShel
 
        shline.CheckShellCommandLine("install -c manpage.1 ${PREFIX}/man/man1/manpage.1")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:3: Please use ${PKGMANDIR} instead of \"man\".")
 
        shline.CheckShellCommandLine("cp init-script ${PREFIX}/etc/rc.d/service")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:3: Please use the RCD_SCRIPTS mechanism to install rc.d scripts automatically to ${RCD_SCRIPTS_EXAMPLEDIR}.")
 }
 
 func (s *Suite) Test_ShellLine_checkCommandUse(c *check.C) {
-       s.Init(c)
-       G.Mk = T.NewMkLines("fname",
+       t := s.Init(c)
+
+       G.Mk = t.NewMkLines("fname",
                "# dummy")
        G.Mk.target = "do-install"
 
-       shline := T.NewShellLine("fname", 1, "\tdummy")
+       shline := t.NewShellLine("fname", 1, "\tdummy")
 
        shline.checkCommandUse("sed")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: The shell command \"sed\" should not be used in the install phase.")
 
        shline.checkCommandUse("cp")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: ${CP} should not be used to install files.")
 }
 
@@ -508,32 +526,35 @@ func (s *Suite) Test_splitIntoMkWords(c 
 }
 
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__sed_and_mv(c *check.C) {
-       s.Init(c)
-       shline := T.NewShellLine("Makefile", 85, "\t${RUN} ${SED} 's,#,// comment:,g' fname > fname.tmp; ${MV} fname.tmp fname")
+       t := s.Init(c)
+
+       shline := t.NewShellLine("Makefile", 85, "\t${RUN} ${SED} 's,#,// comment:,g' fname > fname.tmp; ${MV} fname.tmp fname")
 
        shline.CheckShellCommandLine(shline.mkline.Shellcmd())
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "NOTE: Makefile:85: Please use the SUBST framework instead of ${SED} and ${MV}.")
 }
 
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__subshell(c *check.C) {
-       s.Init(c)
-       shline := T.NewShellLine("Makefile", 85, "\t${RUN} uname=$$(uname)")
+       t := s.Init(c)
+
+       shline := t.NewShellLine("Makefile", 85, "\t${RUN} uname=$$(uname)")
 
        shline.CheckShellCommandLine(shline.mkline.Shellcmd())
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:85: Invoking subshells via $(...) is not portable enough.")
 }
 
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__install_dir(c *check.C) {
-       s.Init(c)
-       shline := T.NewShellLine("Makefile", 85, "\t${RUN} ${INSTALL_DATA_DIR} ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2")
+       t := s.Init(c)
+
+       shline := t.NewShellLine("Makefile", 85, "\t${RUN} ${INSTALL_DATA_DIR} ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2")
 
        shline.CheckShellCommandLine(shline.mkline.Shellcmd())
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "NOTE: Makefile:85: You can use \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL_DATA_DIR}\".",
                "NOTE: Makefile:85: You can use \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL_DATA_DIR}\".",
                "WARN: Makefile:85: The INSTALL_*_DIR commands can only handle one directory at a time.")
@@ -541,45 +562,48 @@ func (s *Suite) Test_ShellLine_CheckShel
        shline.CheckShellCommandLine("${INSTALL_DATA_DIR} -d -m 0755 ${DESTDIR}${PREFIX}/share/examples/gdchart")
 
        // No warning about multiple directories, since 0755 is an option, not an argument.
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "NOTE: Makefile:85: You can use \"INSTALLATION_DIRS+= share/examples/gdchart\" instead of \"${INSTALL_DATA_DIR}\".")
 
        shline.CheckShellCommandLine("${INSTALL_DATA_DIR} -d -m 0755 ${DESTDIR}${PREFIX}/dir1 ${PREFIX}/dir2")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "NOTE: Makefile:85: You can use \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL_DATA_DIR}\".",
                "NOTE: Makefile:85: You can use \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL_DATA_DIR}\".",
                "WARN: Makefile:85: The INSTALL_*_DIR commands can only handle one directory at a time.")
 }
 
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__install_option_d(c *check.C) {
-       s.Init(c)
-       shline := T.NewShellLine("Makefile", 85, "\t${RUN} ${INSTALL} -d ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2")
+       t := s.Init(c)
+
+       shline := t.NewShellLine("Makefile", 85, "\t${RUN} ${INSTALL} -d ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2")
 
        shline.CheckShellCommandLine(shline.mkline.Shellcmd())
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "NOTE: Makefile:85: You can use \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL} -d\".",
                "NOTE: Makefile:85: You can use \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL} -d\".")
 }
 
 func (s *Suite) Test_ShellLine__shell_comment_with_line_continuation(c *check.C) {
-       s.Init(c)
-       tmpfile := s.CreateTmpFile("Makefile", ""+
-               "# $"+"NetBSD$\n"+
-               "pre-install:\n"+
-               "\t"+"# comment\\\n"+
-               "\t"+"echo \"hello\"\n")
-       lines := LoadNonemptyLines(tmpfile, true)
+       t := s.Init(c)
+
+       lines := t.SetupFileLinesContinuation("Makefile",
+               MkRcsId,
+               "pre-install:",
+               "\t"+"# comment\\",
+               "\t"+"echo \"hello\"")
 
        NewMkLines(lines).Check()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: ~/Makefile:3--4: A shell comment does not stop at the end of line.")
 }
 
 func (s *Suite) Test_ShellLine_unescapeBackticks(c *check.C) {
-       shline := T.NewShellLine("dummy.mk", 13, "# dummy")
+       t := s.Init(c)
+
+       shline := t.NewShellLine("dummy.mk", 13, "# dummy")
        // foobar="`echo \"foo   bar\"`"
        text := "foobar=\"`echo \\\"foo   bar\\\"`\""
        repl := textproc.NewPrefixReplacer(text)
@@ -591,3 +615,20 @@ func (s *Suite) Test_ShellLine_unescapeB
        c.Check(newQuoting, equals, shqDquot)
        c.Check(repl.Rest(), equals, "\"")
 }
+
+func (s *Suite) Test_ShellLine__variable_outside_quotes(c *check.C) {
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
+       G.globalData.InitVartypes()
+       mklines := t.NewMkLines("dummy.mk",
+               MkRcsId,
+               "GZIP=\t${ECHO} $$comment")
+
+       mklines.Check()
+
+       t.CheckOutputLines(
+               "WARN: dummy.mk:2: The variable GZIP may not be set by any package.",
+               "WARN: dummy.mk:2: Unquoted shell variable \"comment\".",
+               "WARN: dummy.mk:2: ECHO should not be evaluated indirectly at load time.")
+}

Index: pkgsrc/pkgtools/pkglint/files/linechecker_test.go
diff -u pkgsrc/pkgtools/pkglint/files/linechecker_test.go:1.5 pkgsrc/pkgtools/pkglint/files/linechecker_test.go:1.6
--- pkgsrc/pkgtools/pkglint/files/linechecker_test.go:1.5       Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/linechecker_test.go   Sat Jan 27 18:50:36 2018
@@ -5,29 +5,32 @@ import (
 )
 
 func (s *Suite) Test_LineChecker_CheckAbsolutePathname(c *check.C) {
-       s.Init(c)
-       line := T.NewLine("Makefile", 1, "# dummy")
+       t := s.Init(c)
+
+       line := t.NewLine("Makefile", 1, "# dummy")
 
        CheckLineAbsolutePathname(line, "bindir=/bin")
        CheckLineAbsolutePathname(line, "bindir=/../lib")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:1: Found absolute pathname: /bin")
 }
 
-func (s *Suite) Test_LineChecker_CheckTrailingWhitespace(c *check.C) {
-       s.Init(c)
-       line := T.NewLine("Makefile", 32, "The line must go on   ")
+func (s *Suite) Test_CheckLineTrailingWhitespace(c *check.C) {
+       t := s.Init(c)
+
+       line := t.NewLine("Makefile", 32, "The line must go on   ")
 
        CheckLineTrailingWhitespace(line)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "NOTE: Makefile:32: Trailing white-space.")
 }
 
-func (s *Suite) Test_LineChecker_CheckRcsid(c *check.C) {
-       s.Init(c)
-       lines := T.NewLines("fname",
+func (s *Suite) Test_CheckLineRcsid(c *check.C) {
+       t := s.Init(c)
+
+       lines := t.NewLines("fname",
                "$"+"NetBSD: dummy $",
                "$"+"NetBSD$",
                "$"+"Id: dummy $",
@@ -38,7 +41,7 @@ func (s *Suite) Test_LineChecker_CheckRc
                CheckLineRcsid(line, ``, "")
        }
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: fname:3: Expected \"$"+"NetBSD$\".",
                "ERROR: fname:4: Expected \"$"+"NetBSD$\".",
                "ERROR: fname:5: Expected \"$"+"NetBSD$\".")
Index: pkgsrc/pkgtools/pkglint/files/shtokenizer_test.go
diff -u pkgsrc/pkgtools/pkglint/files/shtokenizer_test.go:1.5 pkgsrc/pkgtools/pkglint/files/shtokenizer_test.go:1.6
--- pkgsrc/pkgtools/pkglint/files/shtokenizer_test.go:1.5       Sun Jan 29 14:27:48 2017
+++ pkgsrc/pkgtools/pkglint/files/shtokenizer_test.go   Sat Jan 27 18:50:36 2018
@@ -1,11 +1,10 @@
 package main
 
-import (
-       check "gopkg.in/check.v1"
-)
+import "gopkg.in/check.v1"
 
 func (s *Suite) Test_ShTokenizer_ShAtom(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        checkRest := func(s string, expected ...*ShAtom) string {
                p := NewShTokenizer(dummyLine, s, false)
                q := shqPlain
@@ -18,7 +17,7 @@ func (s *Suite) Test_ShTokenizer_ShAtom(
        check := func(str string, expected ...*ShAtom) {
                rest := checkRest(str, expected...)
                c.Check(rest, equals, "")
-               s.CheckOutputEmpty()
+               t.CheckOutputEmpty()
        }
 
        token := func(typ ShAtomType, text string, quoting ShQuoting) *ShAtom {
@@ -357,14 +356,15 @@ func (s *Suite) Test_Shtokenizer_ShAtom_
 }
 
 func (s *Suite) Test_ShTokenizer_ShToken(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        check := func(str string, expected ...*ShToken) {
                p := NewShTokenizer(dummyLine, str, false)
                for _, exp := range expected {
                        c.Check(p.ShToken(), deepEquals, exp)
                }
                c.Check(p.Rest(), equals, "")
-               s.CheckOutputEmpty()
+               t.CheckOutputEmpty()
        }
 
        check("",

Index: pkgsrc/pkgtools/pkglint/files/mkline.go
diff -u pkgsrc/pkgtools/pkglint/files/mkline.go:1.25 pkgsrc/pkgtools/pkglint/files/mkline.go:1.26
--- pkgsrc/pkgtools/pkglint/files/mkline.go:1.25        Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/mkline.go     Sat Jan 27 18:50:36 2018
@@ -16,12 +16,12 @@ type MkLineImpl struct {
        data interface{} // One of the following mkLine* types
 }
 type mkLineAssign struct {
-       varname    string
-       varcanon   string
-       varparam   string
-       op         MkOperator
-       valueAlign string
-       value      string
+       varname    string     // e.g. "HOMEPAGE", "SUBST_SED.perl"
+       varcanon   string     // e.g. "HOMEPAGE", "SUBST_SED.*"
+       varparam   string     // e.g. "", "perl"
+       op         MkOperator //
+       valueAlign string     // The text up to and including the assignment operator, e.g. VARNAME+=\t
+       value      string     // The trimmed value
        comment    string
 }
 type mkLineShell struct {
@@ -152,7 +152,9 @@ func (mkline *MkLineImpl) IsVarassign() 
 func (mkline *MkLineImpl) IsShellcmd() bool  { _, ok := mkline.data.(mkLineShell); return ok }
 func (mkline *MkLineImpl) IsComment() bool   { _, ok := mkline.data.(mkLineComment); return ok }
 func (mkline *MkLineImpl) IsEmpty() bool     { _, ok := mkline.data.(mkLineEmpty); return ok }
-func (mkline *MkLineImpl) IsCond() bool      { _, ok := mkline.data.(mkLineConditional); return ok }
+
+// IsCond checks whether the line is a conditional (.if/.ifelse/.else/.if) or a loop (.for/.endfor).
+func (mkline *MkLineImpl) IsCond() bool { _, ok := mkline.data.(mkLineConditional); return ok }
 func (mkline *MkLineImpl) IsInclude() bool {
        incl, ok := mkline.data.(mkLineInclude)
        return ok && !incl.sys
@@ -161,11 +163,13 @@ func (mkline *MkLineImpl) IsSysinclude()
        incl, ok := mkline.data.(mkLineInclude)
        return ok && incl.sys
 }
-func (mkline *MkLineImpl) IsDependency() bool       { _, ok := mkline.data.(mkLineDependency); return ok }
-func (mkline *MkLineImpl) Varname() string          { return mkline.data.(mkLineAssign).varname }
-func (mkline *MkLineImpl) Varcanon() string         { return mkline.data.(mkLineAssign).varcanon }
-func (mkline *MkLineImpl) Varparam() string         { return mkline.data.(mkLineAssign).varparam }
-func (mkline *MkLineImpl) Op() MkOperator           { return mkline.data.(mkLineAssign).op }
+func (mkline *MkLineImpl) IsDependency() bool { _, ok := mkline.data.(mkLineDependency); return ok }
+func (mkline *MkLineImpl) Varname() string    { return mkline.data.(mkLineAssign).varname }
+func (mkline *MkLineImpl) Varcanon() string   { return mkline.data.(mkLineAssign).varcanon }
+func (mkline *MkLineImpl) Varparam() string   { return mkline.data.(mkLineAssign).varparam }
+func (mkline *MkLineImpl) Op() MkOperator     { return mkline.data.(mkLineAssign).op }
+
+// For a variable assignment, the text up to and including the assignment operator, e.g. VARNAME+=\t
 func (mkline *MkLineImpl) ValueAlign() string       { return mkline.data.(mkLineAssign).valueAlign }
 func (mkline *MkLineImpl) Value() string            { return mkline.data.(mkLineAssign).value }
 func (mkline *MkLineImpl) VarassignComment() string { return mkline.data.(mkLineAssign).comment }
@@ -448,7 +452,7 @@ func (mkline *MkLineImpl) VariableNeedsQ
        return nqDontKnow
 }
 
-// Returns the type of the variable (maybe guessed based on the variable name),
+// Returns the type of the variable (possibly guessed based on the variable name),
 // or nil if the type cannot even be guessed.
 func (mkline *MkLineImpl) VariableType(varname string) *Vartype {
        if trace.Tracing {
@@ -596,14 +600,16 @@ func (mkline *MkLineImpl) DetermineUsedV
 // or used. Whether that is allowed depends on:
 //
 // * The variable's data type, as defined in vardefs.go.
+//
 // * When used on the right-hand side of an assigment, the variable can
-//   represent a list of words, a single word or even only part of a
-//   word. This distinction decides upon the correct use of the :Q
-//   operator.
+// represent a list of words, a single word or even only part of a
+// word. This distinction decides upon the correct use of the :Q
+// operator.
+//
 // * When used in preprocessing statements like .if or .for, the other
-//   operands of that statement should fit to the variable and are
-//   checked against the variable type. For example, comparing OPSYS to
-//   x86_64 doesn't make sense.
+// operands of that statement should fit to the variable and are
+// checked against the variable type. For example, comparing OPSYS to
+// x86_64 doesn't make sense.
 type VarUseContext struct {
        vartype    *Vartype
        time       vucTime

Index: pkgsrc/pkgtools/pkglint/files/mkline_test.go
diff -u pkgsrc/pkgtools/pkglint/files/mkline_test.go:1.28 pkgsrc/pkgtools/pkglint/files/mkline_test.go:1.29
--- pkgsrc/pkgtools/pkglint/files/mkline_test.go:1.28   Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/mkline_test.go        Sat Jan 27 18:50:36 2018
@@ -3,10 +3,11 @@ package main
 import "gopkg.in/check.v1"
 
 func (s *Suite) Test_VaralignBlock_Check_autofix(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wspace", "--show-autofix")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wspace", "--show-autofix")
 
-       lines := T.NewLines("file.mk",
+       lines := t.NewLines("file.mk",
                "VAR=   value",    // Indentation 7, fixed to 8.
                "",                //
                "VAR=    value",   // Indentation 8, fixed to 8.
@@ -17,7 +18,7 @@ func (s *Suite) Test_VaralignBlock_Check
                "",                //
                "VAR=   \tvalue",  // Mixed indentation 8, fixed to 8.
                "",                //
-               "VAR=    \tvalue", // Mixed indentation 16, fixed to 8.
+               "VAR=    \tvalue", // Mixed indentation 16, fixed to 16.
                "",                //
                "VAR=\tvalue")     // Already aligned with tabs only, left unchanged.
 
@@ -27,25 +28,26 @@ func (s *Suite) Test_VaralignBlock_Check
        }
        varalign.Finish()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "NOTE: file.mk:1: This variable value should be aligned with tabs, not spaces, to column 9.",
-               "AUTOFIX: file.mk:1: Replacing \"VAR=   \" with \"VAR=\\t\".",
+               "AUTOFIX: file.mk:1: Replacing \"   \" with \"\\t\".",
                "NOTE: file.mk:3: Variable values should be aligned with tabs, not spaces.",
-               "AUTOFIX: file.mk:3: Replacing \"VAR=    \" with \"VAR=\\t\".",
+               "AUTOFIX: file.mk:3: Replacing \"    \" with \"\\t\".",
                "NOTE: file.mk:5: This variable value should be aligned with tabs, not spaces, to column 9.",
-               "AUTOFIX: file.mk:5: Replacing \"VAR=     \" with \"VAR=\\t\".",
+               "AUTOFIX: file.mk:5: Replacing \"     \" with \"\\t\".",
                "NOTE: file.mk:7: Variable values should be aligned with tabs, not spaces.",
-               "AUTOFIX: file.mk:7: Replacing \"VAR= \\t\" with \"VAR=\\t\".",
+               "AUTOFIX: file.mk:7: Replacing \" \\t\" with \"\\t\".",
                "NOTE: file.mk:9: Variable values should be aligned with tabs, not spaces.",
-               "AUTOFIX: file.mk:9: Replacing \"VAR=   \\t\" with \"VAR=\\t\".",
-               "NOTE: file.mk:11: This variable value should be aligned with tabs, not spaces, to column 9.",
-               "AUTOFIX: file.mk:11: Replacing \"VAR=    \\t\" with \"VAR=\\t\".")
+               "AUTOFIX: file.mk:9: Replacing \"   \\t\" with \"\\t\".",
+               "NOTE: file.mk:11: Variable values should be aligned with tabs, not spaces.",
+               "AUTOFIX: file.mk:11: Replacing \"    \\t\" with \"\\t\\t\".")
 }
 
 func (s *Suite) Test_VaralignBlock_Check__reduce_indentation(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wspace")
-       mklines := T.NewMkLines("file.mk",
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wspace")
+       mklines := t.NewMkLines("file.mk",
                "VAR= \tvalue",
                "VAR=    \tvalue",
                "VAR=\t\t\t\tvalue",
@@ -60,16 +62,17 @@ func (s *Suite) Test_VaralignBlock_Check
        }
        varalign.Finish()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "NOTE: file.mk:1: Variable values should be aligned with tabs, not spaces.",
                "NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 9.",
                "NOTE: file.mk:3: This variable value should be aligned to column 9.")
 }
 
 func (s *Suite) Test_VaralignBlock_Check_longest_line_no_space(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wspace")
-       mklines := T.NewMkLines("file.mk",
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wspace")
+       mklines := t.NewMkLines("file.mk",
                "SUBST_CLASSES+= aaaaaaaa",
                "SUBST_STAGE.aaaaaaaa= pre-configure",
                "SUBST_FILES.aaaaaaaa= *.pl",
@@ -81,7 +84,7 @@ func (s *Suite) Test_VaralignBlock_Check
        }
        varalign.Finish()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "NOTE: file.mk:1: This variable value should be aligned with tabs, not spaces, to column 33.",
                "NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 33.",
                "NOTE: file.mk:3: This variable value should be aligned with tabs, not spaces, to column 33.",
@@ -89,9 +92,10 @@ func (s *Suite) Test_VaralignBlock_Check
 }
 
 func (s *Suite) Test_VaralignBlock_Check_only_spaces(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wspace")
-       mklines := T.NewMkLines("file.mk",
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wspace")
+       mklines := t.NewMkLines("file.mk",
                "SUBST_CLASSES+= aaaaaaaa",
                "SUBST_STAGE.aaaaaaaa= pre-configure",
                "SUBST_FILES.aaaaaaaa= *.pl",
@@ -103,7 +107,7 @@ func (s *Suite) Test_VaralignBlock_Check
        }
        varalign.Finish()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "NOTE: file.mk:1: This variable value should be aligned with tabs, not spaces, to column 33.",
                "NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 33.",
                "NOTE: file.mk:3: This variable value should be aligned with tabs, not spaces, to column 33.",
@@ -111,9 +115,10 @@ func (s *Suite) Test_VaralignBlock_Check
 }
 
 func (s *Suite) Test_NewMkLine(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wspace")
-       mklines := T.NewMkLines("test.mk",
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wspace")
+       mklines := t.NewMkLines("test.mk",
                "VARNAME.param?=value # varassign comment",
                "\tshell command # shell comment",
                "# whole line comment",
@@ -165,15 +170,16 @@ func (s *Suite) Test_NewMkLine(c *check.
        c.Check(ln[9].Varcanon(), equals, "VARNAME")
        c.Check(ln[9].Varparam(), equals, "")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: test.mk:9: Space before colon in dependency line.")
 }
 
 func (s *Suite) Test_NewMkLine__autofix_space_after_varname(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wspace")
-       fname := s.CreateTmpFileLines("Makefile",
-               mkrcsid,
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wspace")
+       fname := t.CreateFileLines("Makefile",
+               MkRcsId,
                "VARNAME +=\t${VARNAME}",
                "VARNAME+ =\t${VARNAME+}",
                "VARNAME+ +=\t${VARNAME+}",
@@ -181,29 +187,29 @@ func (s *Suite) Test_NewMkLine__autofix_
 
        CheckfileMk(fname)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: ~/Makefile:2: Unnecessary space after variable name \"VARNAME\".",
                "WARN: ~/Makefile:4: Unnecessary space after variable name \"VARNAME+\".")
 
-       s.UseCommandLine("-Wspace", "--autofix")
+       t.SetupCommandLine("-Wspace", "--autofix")
 
        CheckfileMk(fname)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "AUTOFIX: ~/Makefile:2: Replacing \"VARNAME +=\" with \"VARNAME+=\".",
-               "AUTOFIX: ~/Makefile:4: Replacing \"VARNAME+ +=\" with \"VARNAME++=\".",
-               "AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.",
-               "AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.")
-       c.Check(s.LoadTmpFile("Makefile"), equals, ""+
-               mkrcsid+"\n"+
-               "VARNAME+=\t${VARNAME}\n"+
-               "VARNAME+ =\t${VARNAME+}\n"+
-               "VARNAME++=\t${VARNAME+}\n"+
-               "pkgbase := pkglint\n")
+               "AUTOFIX: ~/Makefile:4: Replacing \"VARNAME+ +=\" with \"VARNAME++=\".")
+       t.CheckFileLines("Makefile",
+               MkRcsId+"",
+               "VARNAME+=\t${VARNAME}",
+               "VARNAME+ =\t${VARNAME+}",
+               "VARNAME++=\t${VARNAME+}",
+               "pkgbase := pkglint")
 }
 
 func (s *Suite) Test_MkLine_VariableType_varparam(c *check.C) {
-       mkline := T.NewMkLine("fname", 1, "# dummy")
+       t := s.Init(c)
+
+       mkline := t.NewMkLine("fname", 1, "# dummy")
        G.globalData.InitVartypes()
 
        t1 := mkline.VariableType("FONT_DIRS")
@@ -218,8 +224,10 @@ func (s *Suite) Test_MkLine_VariableType
 }
 
 func (s *Suite) Test_VarUseContext_String(c *check.C) {
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
-       mkline := T.NewMkLine("fname", 1, "# dummy")
+       mkline := t.NewMkLine("fname", 1, "# dummy")
        vartype := mkline.VariableType("PKGNAME")
        vuc := &VarUseContext{vartype, vucTimeUnknown, vucQuotBackt, false}
 
@@ -230,44 +238,47 @@ func (s *Suite) Test_VarUseContext_Strin
 // it is escaped by a backslash. In shell commands, on the other hand, it
 // is interpreted literally.
 func (s *Suite) Test_NewMkLine_numbersign(c *check.C) {
-       s.Init(c)
-       mklineVarassignEscaped := T.NewMkLine("fname", 1, "SED_CMD=\t's,\\#,hash,g'")
+       t := s.Init(c)
+
+       mklineVarassignEscaped := t.NewMkLine("fname", 1, "SED_CMD=\t's,\\#,hash,g'")
 
        c.Check(mklineVarassignEscaped.Varname(), equals, "SED_CMD")
        c.Check(mklineVarassignEscaped.Value(), equals, "'s,#,hash,g'")
 
-       mklineCommandEscaped := T.NewMkLine("fname", 1, "\tsed -e 's,\\#,hash,g'")
+       mklineCommandEscaped := t.NewMkLine("fname", 1, "\tsed -e 's,\\#,hash,g'")
 
        c.Check(mklineCommandEscaped.Shellcmd(), equals, "sed -e 's,\\#,hash,g'")
 
        // From shells/zsh/Makefile.common, rev. 1.78
-       mklineCommandUnescaped := T.NewMkLine("fname", 1, "\t# $ sha1 patches/patch-ac")
+       mklineCommandUnescaped := t.NewMkLine("fname", 1, "\t# $ sha1 patches/patch-ac")
 
        c.Check(mklineCommandUnescaped.Shellcmd(), equals, "# $ sha1 patches/patch-ac")
-       s.CheckOutputEmpty() // No warning about parsing the lonely dollar sign.
+       t.CheckOutputEmpty() // No warning about parsing the lonely dollar sign.
 
-       mklineVarassignUnescaped := T.NewMkLine("fname", 1, "SED_CMD=\t's,#,hash,'")
+       mklineVarassignUnescaped := t.NewMkLine("fname", 1, "SED_CMD=\t's,#,hash,'")
 
        c.Check(mklineVarassignUnescaped.Value(), equals, "'s,")
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: The # character starts a comment.")
 }
 
 func (s *Suite) Test_NewMkLine_leading_space(c *check.C) {
-       s.Init(c)
-       _ = T.NewMkLine("rubyversion.mk", 427, " _RUBYVER=\t2.15")
+       t := s.Init(c)
 
-       s.CheckOutputLines(
+       _ = t.NewMkLine("rubyversion.mk", 427, " _RUBYVER=\t2.15")
+
+       t.CheckOutputLines(
                "WARN: rubyversion.mk:427: Makefile lines should not start with space characters.")
 }
 
 func (s *Suite) Test_MkLines_Check__extra(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wextra")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wextra")
        G.globalData.InitVartypes()
        G.Pkg = NewPackage("category/pkgbase")
-       G.Mk = T.NewMkLines("options.mk",
-               mkrcsid,
+       G.Mk = t.NewMkLines("options.mk",
+               MkRcsId,
                ".for word in ${PKG_FAIL_REASON}",
                "PYTHON_VERSIONS_ACCEPTED=\t27 35 30",
                "CONFIGURE_ARGS+=\t--sharedir=${PREFIX}/share/kde",
@@ -280,7 +291,7 @@ func (s *Suite) Test_MkLines_Check__extr
 
        G.Mk.Check()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: options.mk:3: The values for PYTHON_VERSIONS_ACCEPTED should be in decreasing order.",
                "NOTE: options.mk:5: Please use \"# empty\", \"# none\" or \"yes\" instead of \"# defined\".",
                "WARN: options.mk:7: Please include \"../../mk/bsd.prefs.mk\" before using \"?=\".",
@@ -289,7 +300,9 @@ func (s *Suite) Test_MkLines_Check__extr
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__unknown_rhs(c *check.C) {
-       mkline := T.NewMkLine("fname", 1, "PKGNAME := ${UNKNOWN}")
+       t := s.Init(c)
+
+       mkline := t.NewMkLine("fname", 1, "PKGNAME := ${UNKNOWN}")
        G.globalData.InitVartypes()
 
        vuc := &VarUseContext{G.globalData.vartypes["PKGNAME"], vucTimeParse, vucQuotUnknown, false}
@@ -299,11 +312,12 @@ func (s *Suite) Test_MkLine_variableNeed
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__append_URL_to_list_of_URLs(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       s.RegisterMasterSite("MASTER_SITE_SOURCEFORGE", "http://downloads.sourceforge.net/sourceforge/";)
-       mkline := T.NewMkLine("Makefile", 95, "MASTER_SITES=\t${HOMEPAGE}")
+       t.SetupMasterSite("MASTER_SITE_SOURCEFORGE", "http://downloads.sourceforge.net/sourceforge/";)
+       mkline := t.NewMkLine("Makefile", 95, "MASTER_SITES=\t${HOMEPAGE}")
 
        vuc := &VarUseContext{G.globalData.vartypes["MASTER_SITES"], vucTimeRun, vucQuotPlain, false}
        nq := mkline.VariableNeedsQuoting("HOMEPAGE", G.globalData.vartypes["HOMEPAGE"], vuc)
@@ -312,115 +326,122 @@ func (s *Suite) Test_MkLine_variableNeed
 
        MkLineChecker{mkline}.checkVarassign()
 
-       s.CheckOutputEmpty() // Up to pkglint 5.3.6, it warned about a missing :Q here, which was wrong.
+       t.CheckOutputEmpty() // Up to pkglint 5.3.6, it warned about a missing :Q here, which was wrong.
 }
 
-// Assigning lists to lists is ok.
 func (s *Suite) Test_MkLine_variableNeedsQuoting__append_list_to_list(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       s.RegisterMasterSite("MASTER_SITE_SOURCEFORGE", "http://downloads.sourceforge.net/sourceforge/";)
-       mkline := T.NewMkLine("Makefile", 96, "MASTER_SITES=\t${MASTER_SITE_SOURCEFORGE:=squirrel-sql/}")
+       t.SetupMasterSite("MASTER_SITE_SOURCEFORGE", "http://downloads.sourceforge.net/sourceforge/";)
+       mkline := t.NewMkLine("Makefile", 96, "MASTER_SITES=\t${MASTER_SITE_SOURCEFORGE:=squirrel-sql/}")
 
        MkLineChecker{mkline}.checkVarassign()
 
-       s.CheckOutputEmpty()
+       // Assigning lists to lists is ok.
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__eval_shell(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       mkline := T.NewMkLine("builtin.mk", 3, "USE_BUILTIN.Xfixes!=\t${PKG_ADMIN} pmatch 'pkg-[0-9]*' ${BUILTIN_PKG.Xfixes:Q}")
+       mkline := t.NewMkLine("builtin.mk", 3, "USE_BUILTIN.Xfixes!=\t${PKG_ADMIN} pmatch 'pkg-[0-9]*' ${BUILTIN_PKG.Xfixes:Q}")
 
        MkLineChecker{mkline}.checkVarassign()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: builtin.mk:3: PKG_ADMIN should not be evaluated at load time.",
                "NOTE: builtin.mk:3: The :Q operator isn't necessary for ${BUILTIN_PKG.Xfixes} here.")
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__command_in_single_quotes(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       mkline := T.NewMkLine("Makefile", 3, "SUBST_SED.hpath=\t-e 's|^\\(INSTALL[\t:]*=\\).*|\\1${INSTALL}|'")
+       mkline := t.NewMkLine("Makefile", 3, "SUBST_SED.hpath=\t-e 's|^\\(INSTALL[\t:]*=\\).*|\\1${INSTALL}|'")
 
        MkLineChecker{mkline}.checkVarassign()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:3: Please use ${INSTALL:Q} instead of ${INSTALL} and make sure the variable appears outside of any quoting characters.")
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__command_in_command(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       s.RegisterTool(&Tool{Name: "find", Varname: "FIND", Predefined: true})
-       s.RegisterTool(&Tool{Name: "sort", Varname: "SORT", Predefined: true})
+       t.SetupTool(&Tool{Name: "find", Varname: "FIND", Predefined: true})
+       t.SetupTool(&Tool{Name: "sort", Varname: "SORT", Predefined: true})
        G.Pkg = NewPackage("category/pkgbase")
-       G.Mk = T.NewMkLines("Makefile",
-               mkrcsid,
+       G.Mk = t.NewMkLines("Makefile",
+               MkRcsId,
                "GENERATE_PLIST= cd ${DESTDIR}${PREFIX}; ${FIND} * \\( -type f -or -type l \\) | ${SORT};")
 
        G.Mk.DetermineDefinedVariables()
        MkLineChecker{G.Mk.mklines[1]}.Check()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:2: The exitcode of \"${FIND}\" at the left of the | operator is ignored.")
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__word_as_part_of_word(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       G.Mk = T.NewMkLines("Makefile",
-               mkrcsid,
+       G.Mk = t.NewMkLines("Makefile",
+               MkRcsId,
                "EGDIR=\t${EGDIR}/${MACHINE_GNU_PLATFORM}")
 
        MkLineChecker{G.Mk.mklines[1]}.Check()
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 }
 
 // As an argument to ${ECHO}, the :Q modifier should be used, but pkglint
 // currently does not know all shell commands and how they handle their
 // arguments. As an argument to xargs(1), the :Q modifier would be misplaced,
-// therefore no warning is issued.
+// therefore no warning is issued in both these cases.
 //
 // Based on graphics/circos/Makefile.
 func (s *Suite) Test_MkLine_variableNeedsQuoting__command_as_command_argument(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
-       s.RegisterTool(&Tool{Name: "perl", Varname: "PERL5", Predefined: true})
-       s.RegisterTool(&Tool{Name: "bash", Varname: "BASH", Predefined: true})
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
+       t.SetupTool(&Tool{Name: "perl", Varname: "PERL5", Predefined: true})
+       t.SetupTool(&Tool{Name: "bash", Varname: "BASH", Predefined: true})
        G.globalData.InitVartypes()
-       G.Mk = T.NewMkLines("Makefile",
-               mkrcsid,
+       G.Mk = t.NewMkLines("Makefile",
+               MkRcsId,
                "\t${RUN} cd ${WRKSRC} && ( ${ECHO} ${PERL5:Q} ; ${ECHO} ) | ${BASH} ./install",
                "\t${RUN} cd ${WRKSRC} && ( ${ECHO} ${PERL5} ; ${ECHO} ) | ${BASH} ./install")
 
        MkLineChecker{G.Mk.mklines[1]}.Check()
        MkLineChecker{G.Mk.mklines[2]}.Check()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:2: The exitcode of the command at the left of the | operator is ignored.",
                "WARN: Makefile:3: The exitcode of the command at the left of the | operator is ignored.")
 }
 
 // Based on mail/mailfront/Makefile.
 func (s *Suite) Test_MkLine_variableNeedsQuoting__URL_as_part_of_word_in_list(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       G.Mk = T.NewMkLines("Makefile",
-               mkrcsid,
+       G.Mk = t.NewMkLines("Makefile",
+               MkRcsId,
                "MASTER_SITES=${HOMEPAGE}archive/")
 
        MkLineChecker{G.Mk.mklines[1]}.Check()
 
-       s.CheckOutputEmpty() // Don't suggest to use ${HOMEPAGE:Q}.
+       t.CheckOutputEmpty() // Don't suggest to use ${HOMEPAGE:Q}.
 }
 
 // Pkglint currently does not parse $$(subshell) commands very well. As
@@ -429,39 +450,42 @@ func (s *Suite) Test_MkLine_variableNeed
 //
 // Based on www/firefox31/xpi.mk.
 func (s *Suite) Test_MkLine_variableNeedsQuoting__command_in_subshell(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       s.RegisterTool(&Tool{Name: "awk", Varname: "AWK", Predefined: true})
-       s.RegisterTool(&Tool{Name: "echo", Varname: "ECHO", Predefined: true})
-       G.Mk = T.NewMkLines("xpi.mk",
-               mkrcsid,
+       t.SetupTool(&Tool{Name: "awk", Varname: "AWK", Predefined: true})
+       t.SetupTool(&Tool{Name: "echo", Varname: "ECHO", Predefined: true})
+       G.Mk = t.NewMkLines("xpi.mk",
+               MkRcsId,
                "\t id=$$(${AWK} '{print}' < ${WRKSRC}/idfile) && echo \"$$id\"",
                "\t id=`${AWK} '{print}' < ${WRKSRC}/idfile` && echo \"$$id\"")
 
        MkLineChecker{G.Mk.mklines[1]}.Check()
        MkLineChecker{G.Mk.mklines[2]}.Check()
 
-       s.CheckOutputLines(
-               "WARN: xpi.mk:2: Invoking subshells via $(...) is not portable enough.") // Don't suggest to use ${AWK:Q}.
+       // Don't suggest to use ${AWK:Q}.
+       t.CheckOutputLines(
+               "WARN: xpi.mk:2: Invoking subshells via $(...) is not portable enough.")
 }
 
 // LDFLAGS (and even more so CPPFLAGS and CFLAGS) may contain special
 // shell characters like quotes or backslashes. Therefore, quoting them
 // correctly is more tricky than with other variables.
 func (s *Suite) Test_MkLine_variableNeedsQuoting__LDFLAGS_in_single_quotes(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       G.Mk = T.NewMkLines("x11/mlterm/Makefile",
-               mkrcsid,
+       G.Mk = t.NewMkLines("x11/mlterm/Makefile",
+               MkRcsId,
                "SUBST_SED.link=-e 's|(LIBTOOL_LINK).*(LIBS)|& ${LDFLAGS:M*:Q}|g'",
                "SUBST_SED.link=-e 's|(LIBTOOL_LINK).*(LIBS)|& '${LDFLAGS:M*:Q}'|g'")
 
        MkLineChecker{G.Mk.mklines[1]}.Check()
        MkLineChecker{G.Mk.mklines[2]}.Check()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: x11/mlterm/Makefile:2: Please move ${LDFLAGS:M*:Q} outside of any quoting characters.")
 }
 
@@ -470,27 +494,29 @@ func (s *Suite) Test_MkLine_variableNeed
 // using make's .for loop, which splits them at whitespace and usually
 // requires the variable to be declared as "lkSpace".
 // In this case it doesn't matter though since each option is an identifier,
-// and these do not pose any quoting problems.
+// and these do not pose any quoting or escaping problems.
 func (s *Suite) Test_MkLine_variableNeedsQuoting__package_options(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       G.Mk = T.NewMkLines("Makefile",
-               mkrcsid,
+       G.Mk = t.NewMkLines("Makefile",
+               MkRcsId,
                "PKG_SUGGESTED_OPTIONS+=\t${PKG_DEFAULT_OPTIONS:Mcdecimal} ${PKG_OPTIONS.py-trytond:Mcdecimal}")
 
        MkLineChecker{G.Mk.mklines[1]}.Check()
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_MkLines_Check__MASTER_SITE_in_HOMEPAGE(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
-       s.RegisterMasterSite("MASTER_SITE_GITHUB", "https://github.com/";)
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
+       t.SetupMasterSite("MASTER_SITE_GITHUB", "https://github.com/";)
        G.globalData.InitVartypes()
-       G.Mk = T.NewMkLines("devel/catch/Makefile",
-               mkrcsid,
+       G.Mk = t.NewMkLines("devel/catch/Makefile",
+               MkRcsId,
                "HOMEPAGE=\t${MASTER_SITE_GITHUB:=philsquared/Catch/}",
                "HOMEPAGE=\t${MASTER_SITE_GITHUB}",
                "HOMEPAGE=\t${MASTER_SITES}",
@@ -498,7 +524,7 @@ func (s *Suite) Test_MkLines_Check__MAST
 
        G.Mk.Check()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: devel/catch/Makefile:2: HOMEPAGE should not be defined in terms of MASTER_SITEs. Use https://github.com/philsquared/Catch/ directly.",
                "WARN: devel/catch/Makefile:3: HOMEPAGE should not be defined in terms of MASTER_SITEs. Use https://github.com/ directly.",
                "WARN: devel/catch/Makefile:4: HOMEPAGE should not be defined in terms of MASTER_SITEs.",
@@ -506,165 +532,183 @@ func (s *Suite) Test_MkLines_Check__MAST
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__tool_in_quotes_in_subshell_in_shellwords(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
-       s.RegisterTool(&Tool{Name: "echo", Varname: "ECHO", Predefined: true})
-       s.RegisterTool(&Tool{Name: "sh", Varname: "SH", Predefined: true})
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
+       t.SetupTool(&Tool{Name: "echo", Varname: "ECHO", Predefined: true})
+       t.SetupTool(&Tool{Name: "sh", Varname: "SH", Predefined: true})
        G.globalData.InitVartypes()
-       G.Mk = T.NewMkLines("x11/labltk/Makefile",
-               mkrcsid,
+       G.Mk = t.NewMkLines("x11/labltk/Makefile",
+               MkRcsId,
                "CONFIGURE_ARGS+=\t-tklibs \"`${SH} -c '${ECHO} $$TK_LD_FLAGS'`\"")
 
        MkLineChecker{G.Mk.mklines[1]}.Check()
 
-       s.CheckOutputEmpty() // Don't suggest ${ECHO:Q} here.
+       // Don't suggest ${ECHO:Q} here.
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__LDADD_in_BUILDLINK_TRANSFORM(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       G.Mk = T.NewMkLines("x11/qt5-qtbase/Makefile.common",
+       G.Mk = t.NewMkLines("x11/qt5-qtbase/Makefile.common",
                "BUILDLINK_TRANSFORM+=opt:-ldl:${BUILDLINK_LDADD.dl:M*}")
 
        MkLineChecker{G.Mk.mklines[0]}.Check()
 
        // Note: The :M* modifier is not necessary, since this is not a GNU Configure package.
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: x11/qt5-qtbase/Makefile.common:1: Please use ${BUILDLINK_LDADD.dl:Q} instead of ${BUILDLINK_LDADD.dl:M*}.")
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__command_in_message(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       G.Mk = T.NewMkLines("benchmarks/iozone/Makefile",
+       G.Mk = t.NewMkLines("benchmarks/iozone/Makefile",
                "SUBST_MESSAGE.crlf=\tStripping EOL CR in ${REPLACE_PERL}")
 
        MkLineChecker{G.Mk.mklines[0]}.Check()
 
-       s.CheckOutputEmpty() // Don't suggest ${REPLACE_PERL:Q}.
+       // Don't suggest ${REPLACE_PERL:Q}.
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__guessed_list_variable_in_quotes(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       G.Mk = T.NewMkLines("audio/jack-rack/Makefile",
-               mkrcsid,
+       G.Mk = t.NewMkLines("audio/jack-rack/Makefile",
+               MkRcsId,
                "LADSPA_PLUGIN_PATH?=\t${PREFIX}/lib/ladspa",
                "CPPFLAGS+=\t\t-DLADSPA_PATH=\"\\\"${LADSPA_PLUGIN_PATH}\\\"\"")
 
        G.Mk.Check()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: audio/jack-rack/Makefile:3: The list variable LADSPA_PLUGIN_PATH should not be embedded in a word.")
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__list_in_list(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       G.Mk = T.NewMkLines("x11/eterm/Makefile",
-               mkrcsid,
+       G.Mk = t.NewMkLines("x11/eterm/Makefile",
+               MkRcsId,
                "DISTFILES=\t${DEFAULT_DISTFILES} ${PIXMAP_FILES}")
 
        G.Mk.Check()
 
-       s.CheckOutputEmpty() // Don't warn about missing :Q modifiers.
+       t.CheckOutputEmpty() // Don't warn about missing :Q modifiers.
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__PKGNAME_and_URL_list_in_URL_list(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
-       s.RegisterMasterSite("MASTER_SITE_GNOME", "http://ftp.gnome.org/";)
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
+       t.SetupMasterSite("MASTER_SITE_GNOME", "http://ftp.gnome.org/";)
        G.globalData.InitVartypes()
-       G.Mk = T.NewMkLines("x11/gtk3/Makefile",
-               mkrcsid,
+       G.Mk = t.NewMkLines("x11/gtk3/Makefile",
+               MkRcsId,
                "MASTER_SITES=\tftp://ftp.gtk.org/${PKGNAME}/ ${MASTER_SITE_GNOME:=subdir/}")
 
        MkLineChecker{G.Mk.mklines[1]}.checkVarassignVaruse()
 
-       s.CheckOutputEmpty() // Don't warn about missing :Q modifiers.
+       t.CheckOutputEmpty() // Don't warn about missing :Q modifiers.
 }
 
 func (s *Suite) Test_MkLine_variableNeedsQuoting__tool_in_CONFIGURE_ENV(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
        G.globalData.Tools = NewToolRegistry()
        G.globalData.Tools.RegisterVarname("tar", "TAR")
-
-       mklines := T.NewMkLines("Makefile",
-               mkrcsid,
+       mklines := t.NewMkLines("Makefile",
+               MkRcsId,
                "",
                "CONFIGURE_ENV+=\tSYS_TAR_COMMAND_PATH=${TOOLS_TAR:Q}")
 
        MkLineChecker{mklines.mklines[2]}.checkVarassignVaruse()
 
        // The TOOLS_* variables only contain the path to the tool,
-       // without any additional arguments that might be necessary.
-       s.CheckOutputLines(
+       // without any additional arguments that might be necessary
+       // for invoking the tool properly (e.g. touch -t).
+       // Therefore, no quoting is necessary.
+       t.CheckOutputLines(
                "NOTE: Makefile:3: The :Q operator isn't necessary for ${TOOLS_TAR} here.")
 }
 
 func (s *Suite) Test_MkLine_Pkgmandir(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       G.Mk = T.NewMkLines("chat/ircII/Makefile",
-               mkrcsid,
+       G.Mk = t.NewMkLines("chat/ircII/Makefile",
+               MkRcsId,
                "CONFIGURE_ARGS+=--mandir=${DESTDIR}${PREFIX}/man",
                "CONFIGURE_ARGS+=--mandir=${DESTDIR}${PREFIX}/${PKGMANDIR}")
 
        G.Mk.Check()
 
-       s.CheckOutputLines(
-               "WARN: chat/ircII/Makefile:2: Please use ${PKGMANDIR} instead of \"man\".")
+       t.CheckOutputLines(
+               "WARN: chat/ircII/Makefile:2: Please use ${PKGMANDIR} instead of \"man\".",
+               "NOTE: chat/ircII/Makefile:2: This variable value should be aligned to column 25.",
+               "NOTE: chat/ircII/Makefile:3: This variable value should be aligned to column 25.")
 }
 
 func (s *Suite) Test_MkLines_Check__VERSION_as_wordpart_in_MASTER_SITES(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("geography/viking/Makefile",
-               mkrcsid,
+       mklines := t.NewMkLines("geography/viking/Makefile",
+               MkRcsId,
                "MASTER_SITES=\t${MASTER_SITE_SOURCEFORGE:=viking/}${VERSION}/")
 
        mklines.Check()
 
-       c.Check(s.Output(), equals, "WARN: geography/viking/Makefile:2: "+
-               "The list variable MASTER_SITE_SOURCEFORGE should not be embedded in a word.\n")
+       t.CheckOutputLines(
+               "WARN: geography/viking/Makefile:2: " +
+                       "The list variable MASTER_SITE_SOURCEFORGE should not be embedded in a word.")
 }
 
 func (s *Suite) Test_MkLines_Check__shell_command_as_wordpart_in_ENV_list(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("x11/lablgtk1/Makefile",
-               mkrcsid,
+       mklines := t.NewMkLines("x11/lablgtk1/Makefile",
+               MkRcsId,
                "CONFIGURE_ENV+=\tCC=${CC}")
 
        mklines.Check()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: x11/lablgtk1/Makefile:2: Please use ${CC:Q} instead of ${CC}.",
                "WARN: x11/lablgtk1/Makefile:2: Please use ${CC:Q} instead of ${CC}.")
 }
 
 func (s *Suite) Test_MkLine_shell_varuse_in_backt_dquot(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("x11/motif/Makefile",
-               mkrcsid,
+       mklines := t.NewMkLines("x11/motif/Makefile",
+               MkRcsId,
                "post-patch:",
                "\tfiles=`${GREP} -l \".fB$${name}.fP(3)\" *.3`")
 
        mklines.Check()
 
-       s.CheckOutputLines(
-               "WARN: x11/motif/Makefile:3: Unknown shell command \"${GREP}\".") // No parse errors.
+       // Just ensure that there are no parse errors.
+       t.CheckOutputLines(
+               "WARN: x11/motif/Makefile:3: Unknown shell command \"${GREP}\".")
 }
 
 // See PR 46570, Ctrl+F "3. In lang/perl5".
@@ -678,21 +722,23 @@ func (s *Suite) Test_MkLine_VariableType
 
 // PR 51696, security/py-pbkdf2/Makefile, r1.2
 func (s *Suite) Test_MkLine__comment_in_comment(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("Makefile",
-               mkrcsid,
+       mklines := t.NewMkLines("Makefile",
+               MkRcsId,
                "COMMENT=\tPKCS#5 v2.0 PBKDF2 Module")
 
        mklines.Check()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:2: The # character starts a comment.")
 }
 
 func (s *Suite) Test_MkLine_ConditionVars(c *check.C) {
-       s.Init(c)
-       mkline := T.NewMkLine("Makefile", 45, ".include \"../../category/package/buildlink3.mk\"")
+       t := s.Init(c)
+
+       mkline := t.NewMkLine("Makefile", 45, ".include \"../../category/package/buildlink3.mk\"")
 
        c.Check(mkline.ConditionVars(), equals, "")
 
@@ -703,17 +749,18 @@ func (s *Suite) Test_MkLine_ConditionVar
 
 func (s *Suite) Test_MatchVarassign(c *check.C) {
        s.Init(c)
+
        checkVarassign := func(text string, ck check.Checker, varname, spaceAfterVarname, op, align, value, spaceAfterValue, comment string) {
-               type va struct {
+               type VarAssign struct {
                        varname, spaceAfterVarname, op, align, value, spaceAfterValue, comment string
                }
-               expected := va{varname, spaceAfterVarname, op, align, value, spaceAfterValue, comment}
+               expected := VarAssign{varname, spaceAfterVarname, op, align, value, spaceAfterValue, comment}
                am, avarname, aspaceAfterVarname, aop, aalign, avalue, aspaceAfterValue, acomment := MatchVarassign(text)
                if !am {
                        c.Errorf("Text %q doesn't match variable assignment", text)
                        return
                }
-               actual := va{avarname, aspaceAfterVarname, aop, aalign, avalue, aspaceAfterValue, acomment}
+               actual := VarAssign{avarname, aspaceAfterVarname, aop, aalign, avalue, aspaceAfterValue, acomment}
                c.Check(actual, ck, expected)
        }
        checkNotVarassign := func(text string) {
@@ -774,5 +821,4 @@ func (s *Suite) Test_Indentation(c *chec
 
        c.Check(ind.Varnames(), equals, "")
        c.Check(ind.IsConditional(), equals, false)
-
 }

Index: pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go
diff -u pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go:1.4 pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go:1.5
--- pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go:1.4     Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go Sat Jan 27 18:50:36 2018
@@ -3,10 +3,11 @@ package main
 import "gopkg.in/check.v1"
 
 func (s *Suite) Test_MkLineChecker_CheckVartype__simple_type(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wtypes")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wtypes")
        G.globalData.InitVartypes()
-       mkline := T.NewMkLine("fname", 1, "COMMENT=\tA nice package")
+       mkline := t.NewMkLine("fname", 1, "COMMENT=\tA nice package")
 
        vartype1 := G.globalData.vartypes["COMMENT"]
        c.Assert(vartype1, check.NotNil)
@@ -21,112 +22,149 @@ func (s *Suite) Test_MkLineChecker_Check
 
        MkLineChecker{mkline}.CheckVartype("COMMENT", opAssign, "A nice package", "")
 
-       c.Check(s.Stdout(), equals, "WARN: fname:1: COMMENT should not begin with \"A\".\n")
+       t.CheckOutputLines(
+               "WARN: fname:1: COMMENT should not begin with \"A\".")
 }
 
 func (s *Suite) Test_MkLineChecker_CheckVartype(c *check.C) {
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
-       mkline := T.NewMkLine("fname", 1, "DISTNAME=gcc-${GCC_VERSION}")
+       mkline := t.NewMkLine("fname", 1, "DISTNAME=gcc-${GCC_VERSION}")
 
        MkLineChecker{mkline}.CheckVartype("DISTNAME", opAssign, "gcc-${GCC_VERSION}", "")
+
+       t.CheckOutputEmpty()
 }
 
 // Pkglint once interpreted all lists as consisting of shell tokens,
-// splitting this URL at the ampersands.
+// splitting this URL at the ampersand.
 func (s *Suite) Test_MkLineChecker_checkVarassign__URL_with_shell_special_characters(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.Pkg = NewPackage("graphics/gimp-fix-ca")
        G.globalData.InitVartypes()
-       mkline := T.NewMkLine("fname", 10, "MASTER_SITES=http://registry.gimp.org/file/fix-ca.c?action=download&id=9884&file=";)
+       mkline := t.NewMkLine("fname", 10, "MASTER_SITES=http://registry.gimp.org/file/fix-ca.c?action=download&id=9884&file=";)
 
        MkLineChecker{mkline}.checkVarassign()
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_MkLineChecker_Check__conditions(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wtypes")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wtypes")
        G.globalData.InitVartypes()
 
-       MkLineChecker{T.NewMkLine("fname", 1, ".if !empty(PKGSRC_COMPILER:Mmycc)")}.CheckCond()
+       MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(PKGSRC_COMPILER:Mmycc)")}.CheckCond()
 
-       c.Check(s.Stdout(), equals, "WARN: fname:1: The pattern \"mycc\" cannot match any of "+
-               "{ ccache ccc clang distcc f2c gcc hp icc ido "+
-               "mipspro mipspro-ucode pcc sunpro xlc } for PKGSRC_COMPILER.\n")
+       t.CheckOutputLines(
+               "WARN: fname:1: The pattern \"mycc\" cannot match any of " +
+                       "{ ccache ccc clang distcc f2c gcc hp icc ido " +
+                       "mipspro mipspro-ucode pcc sunpro xlc } for PKGSRC_COMPILER.")
 
-       MkLineChecker{T.NewMkLine("fname", 1, ".elif ${A} != ${B}")}.CheckCond()
+       MkLineChecker{t.NewMkLine("fname", 1, ".elif ${A} != ${B}")}.CheckCond()
 
-       c.Check(s.Stdout(), equals, "")
+       t.CheckOutputEmpty()
 
-       MkLineChecker{T.NewMkLine("fname", 1, ".if ${HOMEPAGE} == \"mailto:someone%example.org@localhost\"";)}.CheckCond()
+       MkLineChecker{t.NewMkLine("fname", 1, ".if ${HOMEPAGE} == \"mailto:someone%example.org@localhost\"";)}.CheckCond()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: \"mailto:someone%example.org@localhost\"; is not a valid URL.")
 
-       MkLineChecker{T.NewMkLine("fname", 1, ".if !empty(PKGSRC_RUN_TEST:M[Y][eE][sS])")}.CheckCond()
+       MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(PKGSRC_RUN_TEST:M[Y][eE][sS])")}.CheckCond()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: PKGSRC_RUN_TEST should be matched against \"[yY][eE][sS]\" or \"[nN][oO]\", not \"[Y][eE][sS]\".")
 
-       MkLineChecker{T.NewMkLine("fname", 1, ".if !empty(IS_BUILTIN.Xfixes:M[yY][eE][sS])")}.CheckCond()
+       MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(IS_BUILTIN.Xfixes:M[yY][eE][sS])")}.CheckCond()
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 
-       MkLineChecker{T.NewMkLine("fname", 1, ".if !empty(${IS_BUILTIN.Xfixes:M[yY][eE][sS]})")}.CheckCond()
+       MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(${IS_BUILTIN.Xfixes:M[yY][eE][sS]})")}.CheckCond()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: The empty() function takes a variable name as parameter, not a variable expression.")
 
-       MkLineChecker{T.NewMkLine("fname", 1, ".if ${EMUL_PLATFORM} == \"linux-x386\"")}.CheckCond()
-
-       s.CheckOutputLines(
-               "WARN: fname:1: \"x386\" is not valid for the hardware architecture part of EMUL_PLATFORM. Use one of { aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex 
dreamcast earm earmeb earmhf earmhfeb earmv4 earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 
m68000 m68k m88k mips mips64 mips64eb mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } instead.")
+       MkLineChecker{t.NewMkLine("fname", 1, ".if ${EMUL_PLATFORM} == \"linux-x386\"")}.CheckCond()
 
-       MkLineChecker{T.NewMkLine("fname", 1, ".if ${EMUL_PLATFORM:Mlinux-x386}")}.CheckCond()
-
-       s.CheckOutputLines(
-               "WARN: fname:1: The pattern \"x386\" cannot match any of { aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex dreamcast earm earmeb earmhf earmhfeb earmv4 
earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 m68000 m68k m88k mips mips64 mips64eb mips64el 
mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } for the hardware architecture part of EMUL_PLATFORM.")
-
-       MkLineChecker{T.NewMkLine("fname", 98, ".if ${MACHINE_PLATFORM:MUnknownOS-*-*} || ${MACHINE_ARCH:Mx86}")}.CheckCond()
-
-       s.CheckOutputLines(
-               "WARN: fname:98: The pattern \"UnknownOS\" cannot match any of { AIX BSDOS Bitrig Cygwin Darwin DragonFly FreeBSD FreeMiNT GNUkFreeBSD HPUX Haiku IRIX Interix Linux Minix MirBSD 
NetBSD OSF1 OpenBSD QNX SCO_SV SunOS UnixWare } for the operating system part of MACHINE_PLATFORM.",
-               "WARN: fname:98: The pattern \"x86\" cannot match any of { aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex dreamcast earm earmeb earmhf earmhfeb earmv4 
earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 m68000 m68k m88k mips mips64 mips64eb mips64el 
mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } for MACHINE_ARCH.")
+       t.CheckOutputLines(
+               "WARN: fname:1: " +
+                       "\"x386\" is not valid for the hardware architecture part of EMUL_PLATFORM. " +
+                       "Use one of " +
+                       "{ aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex " +
+                       "dreamcast earm earmeb earmhf earmhfeb earmv4 earmv4eb earmv5 earmv5eb earmv6 earmv6eb " +
+                       "earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 " +
+                       "i386 i586 i686 ia64 m68000 m68k m88k mips mips64 mips64eb mips64el mipseb mipsel mipsn32 " +
+                       "mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 " +
+                       "} instead.")
+
+       MkLineChecker{t.NewMkLine("fname", 1, ".if ${EMUL_PLATFORM:Mlinux-x386}")}.CheckCond()
+
+       t.CheckOutputLines(
+               "WARN: fname:1: " +
+                       "The pattern \"x386\" cannot match any of { aarch64 aarch64eb alpha amd64 arc arm arm26 " +
+                       "arm32 cobalt coldfire convex dreamcast earm earmeb earmhf earmhfeb earmv4 earmv4eb " +
+                       "earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf " +
+                       "earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 m68000 m68k m88k " +
+                       "mips mips64 mips64eb mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 " +
+                       "rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } " +
+                       "for the hardware architecture part of EMUL_PLATFORM.")
+
+       MkLineChecker{t.NewMkLine("fname", 98, ".if ${MACHINE_PLATFORM:MUnknownOS-*-*} || ${MACHINE_ARCH:Mx86}")}.CheckCond()
+
+       t.CheckOutputLines(
+               "WARN: fname:98: "+
+                       "The pattern \"UnknownOS\" cannot match any of "+
+                       "{ AIX BSDOS Bitrig Cygwin Darwin DragonFly FreeBSD FreeMiNT GNUkFreeBSD HPUX Haiku "+
+                       "IRIX Interix Linux Minix MirBSD NetBSD OSF1 OpenBSD QNX SCO_SV SunOS UnixWare "+
+                       "} for the operating system part of MACHINE_PLATFORM.",
+               "WARN: fname:98: "+
+                       "The pattern \"x86\" cannot match any of "+
+                       "{ aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex dreamcast earm "+
+                       "earmeb earmhf earmhfeb earmv4 earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb "+
+                       "earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 "+
+                       "m68000 m68k m88k mips mips64 mips64eb mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax "+
+                       "powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 "+
+                       "} for MACHINE_ARCH.")
 }
 
 func (s *Suite) Test_MkLineChecker_checkVarassign(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
 
-       G.Mk = T.NewMkLines("Makefile",
-               mkrcsid,
+       G.Mk = t.NewMkLines("Makefile",
+               MkRcsId,
                "ac_cv_libpari_libs+=\t-L${BUILDLINK_PREFIX.pari}/lib") // From math/clisp-pari/Makefile, rev. 1.8
 
        MkLineChecker{G.Mk.mklines[1]}.checkVarassign()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:2: ac_cv_libpari_libs is defined but not used. Spelling mistake?")
 }
 
 func (s *Suite) Test_MkLineChecker_checkVarassignDefPermissions(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       mkline := T.NewMkLine("options.mk", 2, "PKG_DEVELOPER?=\tyes")
+       mkline := t.NewMkLine("options.mk", 2, "PKG_DEVELOPER?=\tyes")
 
        MkLineChecker{mkline}.checkVarassignDefPermissions()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: options.mk:2: The variable PKG_DEVELOPER may not be given a default value by any package.")
 }
 
 func (s *Suite) Test_MkLineChecker_CheckVarusePermissions(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("options.mk",
-               mkrcsid,
+       mklines := t.NewMkLines("options.mk",
+               MkRcsId,
                "COMMENT=\t${GAMES_USER}",
                "COMMENT:=\t${PKGBASE}",
                "PYPKGPREFIX=${PKGBASE}")
@@ -136,7 +174,7 @@ func (s *Suite) Test_MkLineChecker_Check
 
        mklines.Check()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: options.mk:2: The user-defined variable GAMES_USER is used but not added to BUILD_DEFS.",
                "WARN: options.mk:3: PKGBASE should not be evaluated at load time.",
                "WARN: options.mk:4: The variable PYPKGPREFIX may not be set in this file; it would be ok in pyversion.mk.",
@@ -145,101 +183,114 @@ func (s *Suite) Test_MkLineChecker_Check
 }
 
 func (s *Suite) Test_MkLineChecker_CheckVarusePermissions__load_time(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("options.mk",
-               mkrcsid,
+       mklines := t.NewMkLines("options.mk",
+               MkRcsId,
                "WRKSRC:=${.CURDIR}")
 
        mklines.Check()
 
-       s.CheckOutputEmpty() // Don't warn that ".CURDIR should not be evaluated at load time."
+       // Don't warn that ".CURDIR should not be evaluated at load time."
+       t.CheckOutputLines(
+               "NOTE: options.mk:2: This variable value should be aligned to column 17.")
 }
 
 func (s *Suite) Test_MkLineChecker_WarnVaruseLocalbase(c *check.C) {
-       s.Init(c)
-       mkline := T.NewMkLine("options.mk", 56, "PKGNAME=${LOCALBASE}")
+       t := s.Init(c)
+
+       mkline := t.NewMkLine("options.mk", 56, "PKGNAME=${LOCALBASE}")
 
        MkLineChecker{mkline}.WarnVaruseLocalbase()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: options.mk:56: The LOCALBASE variable should not be used by packages.")
 }
 
 func (s *Suite) Test_MkLineChecker_CheckRelativePkgdir(c *check.C) {
-       s.Init(c)
-       mkline := T.NewMkLine("Makefile", 46, "# dummy")
+       t := s.Init(c)
+
+       mkline := t.NewMkLine("Makefile", 46, "# dummy")
 
        MkLineChecker{mkline}.CheckRelativePkgdir("../pkgbase")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: Makefile:46: \"../pkgbase\" does not exist.",
                "WARN: Makefile:46: \"../pkgbase\" is not a valid relative package directory.")
 }
 
 // PR pkg/46570, item 2
 func (s *Suite) Test_MkLineChecker__unclosed_varuse(c *check.C) {
-       s.Init(c)
-       mkline := T.NewMkLine("Makefile", 93, "EGDIRS=${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d")
+       t := s.Init(c)
+
+       mkline := t.NewMkLine("Makefile", 93, "EGDIRS=${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d")
 
        MkLineChecker{mkline}.checkVarassign()
 
-       s.CheckOutputLines(
-               "WARN: Makefile:93: Pkglint parse error in MkLine.Tokenize at \"${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d\".",
-               "WARN: Makefile:93: Pkglint parse error in ShTokenizer.ShAtom at \"${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d\" (quoting=plain)",
+       t.CheckOutputLines(
+               "WARN: Makefile:93: Pkglint parse error in MkLine.Tokenize at "+
+                       "\"${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d\".",
+               "WARN: Makefile:93: Pkglint parse error in ShTokenizer.ShAtom at "+
+                       "\"${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d\" (quoting=plain)",
                "WARN: Makefile:93: EGDIRS is defined but not used. Spelling mistake?")
 }
 
 func (s *Suite) Test_MkLineChecker__Varuse_Modifier_L(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       G.Mk = T.NewMkLines("x11/xkeyboard-config/Makefile",
+       G.Mk = t.NewMkLines("x11/xkeyboard-config/Makefile",
                "FILES_SUBST+=XKBCOMP_SYMLINK=${${XKBBASE}/xkbcomp:L:Q}")
 
        MkLineChecker{G.Mk.mklines[0]}.Check()
 
-       s.CheckOutputEmpty() // Don't warn that ${XKBBASE}/xkbcomp is used but not defined.
+       // Don't warn that ${XKBBASE}/xkbcomp is used but not defined.
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_MkLineChecker_CheckCond__comparison_with_shell_command(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       G.Mk = T.NewMkLines("security/openssl/Makefile",
-               mkrcsid,
+       G.Mk = t.NewMkLines("security/openssl/Makefile",
+               MkRcsId,
                ".if ${PKGSRC_COMPILER} == \"gcc\" && ${CC} == \"cc\"",
                ".endif")
 
        G.Mk.Check()
 
        // Don't warn about unknown shell command "cc".
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: security/openssl/Makefile:2: Use ${PKGSRC_COMPILER:Mgcc} instead of the == operator.")
 }
 
 func (s *Suite) Test_MkLine_CheckCond_comparing_PKGSRC_COMPILER_with_eqeq(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       G.Mk = T.NewMkLines("audio/pulseaudio/Makefile",
-               mkrcsid,
+       G.Mk = t.NewMkLines("audio/pulseaudio/Makefile",
+               MkRcsId,
                ".if ${OPSYS} == \"Darwin\" && ${PKGSRC_COMPILER} == \"clang\"",
                ".endif")
 
        G.Mk.Check()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: audio/pulseaudio/Makefile:2: Use ${PKGSRC_COMPILER:Mclang} instead of the == operator.")
 }
 
 func (s *Suite) Test_MkLineChecker_CheckVartype__CFLAGS_with_backticks(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.globalData.InitVartypes()
-       G.Mk = T.NewMkLines("chat/pidgin-icb/Makefile",
-               mkrcsid,
+       G.Mk = t.NewMkLines("chat/pidgin-icb/Makefile",
+               MkRcsId,
                "CFLAGS+=\t`pkg-config pidgin --cflags`")
        mkline := G.Mk.mklines[1]
 
@@ -250,22 +301,24 @@ func (s *Suite) Test_MkLineChecker_Check
 
        MkLineChecker{G.Mk.mklines[1]}.CheckVartype("CFLAGS", opAssignAppend, "`pkg-config pidgin --cflags`", "")
 
-       s.CheckOutputEmpty() // No warning about "`pkg-config" being an unknown CFlag.
+       // No warning about "`pkg-config" being an unknown CFlag.
+       t.CheckOutputEmpty()
 }
 
 // See PR 46570, Ctrl+F "4. Shell quoting".
 // Pkglint is correct, since the shell sees this definition for
 // CPPFLAGS as three words, not one word.
 func (s *Suite) Test_MkLineChecker_CheckVartype_CFLAGS(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
-       mklines := T.NewMkLines("Makefile",
-               mkrcsid,
+       mklines := t.NewMkLines("Makefile",
+               MkRcsId,
                "CPPFLAGS.SunOS+=\t-DPIPECOMMAND=\\\"/usr/sbin/sendmail -bs %s\\\"")
 
        mklines.Check()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:2: Unknown compiler flag \"-bs\".",
                "WARN: Makefile:2: Compiler flag \"%s\\\\\\\"\" should start with a hyphen.")
 }

Index: pkgsrc/pkgtools/pkglint/files/mklines.go
diff -u pkgsrc/pkgtools/pkglint/files/mklines.go:1.18 pkgsrc/pkgtools/pkglint/files/mklines.go:1.19
--- pkgsrc/pkgtools/pkglint/files/mklines.go:1.18       Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/mklines.go    Sat Jan 27 18:50:36 2018
@@ -233,118 +233,195 @@ func (mklines *MkLines) setSeenBsdPrefsM
        }
 }
 
+// VaralignBlock checks that all variable assignments from a paragraph
+// use the same indentation depth for their values.
+// It also checks that the indentation uses tabs instead of spaces.
+//
+// In general, all values should be aligned using tabs.
+// As an exception, very long lines may be aligned with a single space.
+// A typical example is a SITES.very-long-filename.tar.gz variable
+// between HOMEPAGE and DISTFILES.
 type VaralignBlock struct {
-       info []struct {
-               mkline MkLine
-               prefix string
-               align  string
-       }
-       skip           bool
-       differ         bool
-       maxPrefixWidth int
-       maxSpaceWidth  int
-       maxTabWidth    int
+       infos []*varalignBlockInfo
+       skip  bool
+}
+
+type varalignBlockInfo struct {
+       mkline         MkLine
+       varnameOp      string // Variable name + assignment operator
+       varnameOpWidth int    // Screen width of varnameOp + space
+       space          string // Whitespace between varnameOp and the variable value
+       totalWidth     int    // Screen width of varnameOp + space
+       continuation   bool   // A continuation line with no value in the first line.
 }
 
 func (va *VaralignBlock) Check(mkline MkLine) {
-       if !G.opts.WarnSpace || mkline.IsMultiline() || mkline.IsComment() || mkline.IsCond() {
+       switch {
+       case !G.opts.WarnSpace:
                return
-       }
-       if mkline.IsEmpty() {
+
+       case mkline.IsComment():
+               return
+
+       case mkline.IsCond():
+               return
+
+       case mkline.IsEmpty():
                va.Finish()
                return
-       }
-       if !mkline.IsVarassign() {
+
+       case !mkline.IsVarassign():
+               trace.Stepf("Skipping")
                va.skip = true
                return
-       }
 
-       valueAlign := mkline.ValueAlign()
-       prefix := strings.TrimRight(valueAlign, " \t")
-       align := valueAlign[len(prefix):]
+       case mkline.Op() == opAssignEval && matches(mkline.Varname(), `^[a-z]`):
+               // Arguments to procedures do not take part in block alignment.
+               return
 
-       va.info = append(va.info, struct {
-               mkline MkLine
-               prefix string
-               align  string
-       }{mkline, prefix, align})
+       case mkline.Value() == "" && mkline.VarassignComment() == "":
+               // Multiple-inclusion guards usually appear in a block of
+               // their own and therefore do not need alignment.
+               return
+       }
 
-       alignedWidth := tabLength(valueAlign)
-       if contains(align, " ") {
-               if va.maxSpaceWidth != 0 && alignedWidth != va.maxSpaceWidth {
-                       va.differ = true
-               }
-               if alignedWidth > va.maxSpaceWidth {
-                       va.maxSpaceWidth = alignedWidth
-               }
-       } else {
-               if va.maxTabWidth != 0 && alignedWidth != va.maxTabWidth {
-                       va.differ = true
-               }
-               if alignedWidth > va.maxTabWidth {
-                       va.maxTabWidth = alignedWidth
-               }
+       continuation := false
+       if mkline.IsMultiline() {
+               // Interpreting the continuation marker as variable value
+               // is cheating, but works well.
+               m, _, _, _, _, value, _, _ := MatchVarassign(mkline.raw[0].orignl)
+               continuation = m && value == "\\"
        }
 
-       va.maxPrefixWidth = imax(va.maxPrefixWidth, tabLength(prefix))
+       valueAlign := mkline.ValueAlign()
+       varnameOp := strings.TrimRight(valueAlign, " \t")
+       space := valueAlign[len(varnameOp):]
+
+       width := tabWidth(valueAlign)
+       va.infos = append(va.infos, &varalignBlockInfo{mkline, varnameOp, tabWidth(varnameOp), space, width, continuation})
 }
 
 func (va *VaralignBlock) Finish() {
-       if !va.skip {
-               for _, info := range va.info {
-                       if !info.mkline.IsMultiline() {
-                               va.fixalign(info.mkline, info.prefix, info.align)
-                       }
-               }
-       }
+       infos := va.infos
+       skip := va.skip
        *va = VaralignBlock{}
-}
 
-func (va *VaralignBlock) fixalign(mkline MkLine, prefix, oldalign string) {
-       if mkline.Value() == "" && mkline.VarassignComment() == "" {
+       if len(infos) == 0 || skip {
                return
        }
 
-       hasSpace := contains(oldalign, " ")
-       if hasSpace &&
-               va.maxTabWidth != 0 &&
-               va.maxSpaceWidth > va.maxTabWidth &&
-               tabLength(prefix+oldalign) == va.maxSpaceWidth {
-               return
+       if trace.Tracing {
+               defer trace.Call(infos[0].mkline.Line)()
        }
 
-       // Don't warn about procedure parameters
-       if mkline.Op() == opAssignEval && matches(mkline.Varname(), `^[a-z]`) {
+       newWidth := va.optimalWidth(infos)
+       if newWidth == 0 {
                return
        }
 
-       goodWidth := va.maxTabWidth
-       if goodWidth == 0 && va.differ {
-               goodWidth = va.maxSpaceWidth
+       for _, info := range infos {
+               va.realign(info.mkline, info.varnameOp, info.space, info.continuation, newWidth)
        }
-       minWidth := va.maxPrefixWidth + 1
-       if goodWidth == 0 || minWidth < goodWidth && va.differ {
-               goodWidth = minWidth
+}
+
+// optimalWidth computes the minimum necessary screen width for the
+// variable assignment lines. There may be a single line sticking out
+// from the others (called outlier). This is to prevent a single SITES.*
+// variable from forcing the rest of the paragraph to be indented too
+// far to the right.
+func (va *VaralignBlock) optimalWidth(infos []*varalignBlockInfo) int {
+       longest := 0
+       secondLongest := 0
+       for _, info := range infos {
+               if info.continuation {
+                       continue
+               }
+
+               width := info.varnameOpWidth
+               if width >= longest {
+                       secondLongest = longest
+                       longest = width
+               } else if width > secondLongest {
+                       secondLongest = width
+               }
        }
-       goodWidth = (goodWidth + 7) & -8
 
-       newalign := ""
-       for tabLength(prefix+newalign) < goodWidth {
-               newalign += "\t"
+       // Minimum required width of varnameOp, without the trailing whitespace.
+       minVarnameOpWidth := longest
+       outlier := 0
+       if secondLongest != 0 && secondLongest/8+1 < longest/8 {
+               minVarnameOpWidth = secondLongest
+               outlier = longest
        }
-       if newalign == oldalign {
-               return
+
+       // Widths of the current indentation (including whitespace)
+       minTotalWidth := 0
+       maxTotalWidth := 0
+       for _, info := range infos {
+               if info.continuation {
+                       continue
+               }
+
+               if width := info.totalWidth; info.varnameOpWidth != outlier {
+                       if minTotalWidth == 0 || width < minTotalWidth {
+                               minTotalWidth = width
+                       }
+                       maxTotalWidth = imax(maxTotalWidth, width)
+               }
+       }
+
+       if trace.Tracing {
+               trace.Stepf("Indentation including whitespace is between %d and %d.",
+                       minTotalWidth, maxTotalWidth)
+               trace.Stepf("Minimum required indentation is %d + 1.",
+                       minVarnameOpWidth)
+               if outlier != 0 {
+                       trace.Stepf("The outlier is at indentation %d.", outlier)
+               }
+       }
+
+       if minTotalWidth > minVarnameOpWidth && minTotalWidth == maxTotalWidth && minTotalWidth%8 == 0 {
+               return minTotalWidth
        }
 
-       fix := mkline.Line.Autofix()
-       wrongColumn := tabLength(prefix+oldalign) != tabLength(prefix+newalign)
+       if minVarnameOpWidth == 0 {
+               // Only continuation lines in this paragraph.
+               return 0
+       }
+
+       return (minVarnameOpWidth & -8) + 8
+}
+
+func (va *VaralignBlock) realign(mkline MkLine, varnameOp, oldSpace string, continuation bool, newWidth int) {
+       hasSpace := contains(oldSpace, " ")
+
+       newSpace := ""
+       for tabWidth(varnameOp+newSpace) < newWidth {
+               newSpace += "\t"
+       }
+       // Indent the outlier with a space instead of a tab to keep the line short.
+       if newSpace == "" {
+               if hasPrefix(oldSpace, "\t") {
+                       // Even though it is an outlier, it uses a tab and therefore
+                       // didn't seem to be too long to the original developer.
+                       // Therefore, leave it as-is, but still fix any continuation lines.
+                       newSpace = oldSpace
+               } else {
+                       newSpace = " "
+               }
+       }
+
+       fix := mkline.Autofix()
+       wrongColumn := tabWidth(varnameOp+oldSpace) != tabWidth(varnameOp+newSpace)
        switch {
        case hasSpace && wrongColumn:
-               fix.Notef("This variable value should be aligned with tabs, not spaces, to column %d.", goodWidth+1)
-       case hasSpace:
+               fix.Notef("This variable value should be aligned with tabs, not spaces, to column %d.", newWidth+1)
+       case hasSpace && oldSpace != newSpace:
                fix.Notef("Variable values should be aligned with tabs, not spaces.")
        case wrongColumn:
-               fix.Notef("This variable value should be aligned to column %d.", goodWidth+1)
+               fix.Notef("This variable value should be aligned to column %d.", newWidth+1)
+       default:
+               fix.Notef("Silent-Magic-Diagnostic")
        }
        if wrongColumn {
                fix.Explain(
@@ -358,9 +435,17 @@ func (va *VaralignBlock) fixalign(mkline
                        "Variable definitions that span multiple lines are not checked for",
                        "alignment at all.",
                        "",
-                       "When the block contains something else than variable definitions,",
-                       "it is not checked at all.")
+                       "When the block contains something else than variable definitions",
+                       "and conditionals, it is not checked at all.")
        }
-       fix.Replace(prefix+oldalign, prefix+newalign)
+       fix.ReplaceAfter(varnameOp, oldSpace, newSpace)
        fix.Apply()
+
+       if mkline.IsMultiline() {
+               indentation := strings.Repeat("\t", newWidth/8) + strings.Repeat(" ", newWidth%8)
+               fix := mkline.Autofix()
+               fix.Notef("This line should be aligned with %q.", indentation)
+               fix.Realign(mkline, newWidth)
+               fix.Apply()
+       }
 }
Index: pkgsrc/pkgtools/pkglint/files/plist_test.go
diff -u pkgsrc/pkgtools/pkglint/files/plist_test.go:1.18 pkgsrc/pkgtools/pkglint/files/plist_test.go:1.19
--- pkgsrc/pkgtools/pkglint/files/plist_test.go:1.18    Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/plist_test.go Sat Jan 27 18:50:36 2018
@@ -1,14 +1,13 @@
 package main
 
-import (
-       check "gopkg.in/check.v1"
-)
+import "gopkg.in/check.v1"
 
 func (s *Suite) Test_ChecklinesPlist(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
        G.Pkg = NewPackage("category/pkgbase")
-       lines := T.NewLines("PLIST",
+       lines := t.NewLines("PLIST",
                "bin/i386/6c",
                "bin/program",
                "etc/my.cnf",
@@ -30,10 +29,11 @@ func (s *Suite) Test_ChecklinesPlist(c *
 
        ChecklinesPlist(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: PLIST:1: Expected \"@comment $"+"NetBSD$\".",
                "WARN: PLIST:1: The bin/ directory should not have subdirectories.",
-               "ERROR: PLIST:3: Configuration files must not be registered in the PLIST. Please use the CONF_FILES framework, which is described in mk/pkginstall/bsd.pkginstall.mk.",
+               "ERROR: PLIST:3: Configuration files must not be registered in the PLIST. "+
+                       "Please use the CONF_FILES framework, which is described in mk/pkginstall/bsd.pkginstall.mk.",
                "ERROR: PLIST:4: RCD_SCRIPTS must not be registered in the PLIST. Please use the RCD_SCRIPTS framework.",
                "ERROR: PLIST:6: \"info/dir\" must not be listed. Use install-info to add/remove an entry.",
                "WARN: PLIST:7: Library filename \"c.so\" should start with \"lib\".",
@@ -45,54 +45,59 @@ func (s *Suite) Test_ChecklinesPlist(c *
                "WARN: PLIST:12: Please remove this line. It is no longer necessary.",
                "ERROR: PLIST:14: The package Makefile must include \"../../graphics/gnome-icon-theme/buildlink3.mk\".",
                "WARN: PLIST:14: Packages that install icon theme files should set ICON_THEMES.",
-               "ERROR: PLIST:15: Packages that install hicolor icons must include \"../../graphics/hicolor-icon-theme/buildlink3.mk\" in the Makefile.",
+               "ERROR: PLIST:15: Packages that install hicolor icons "+
+                       "must include \"../../graphics/hicolor-icon-theme/buildlink3.mk\" in the Makefile.",
                "ERROR: PLIST:18: Duplicate filename \"share/tzinfo\", already appeared in line 17.")
 }
 
 func (s *Suite) Test_ChecklinesPlist__empty(c *check.C) {
-       s.Init(c)
-       lines := T.NewLines("PLIST",
-               "@comment $"+"NetBSD$")
+       t := s.Init(c)
+
+       lines := t.NewLines("PLIST",
+               PlistRcsId)
 
        ChecklinesPlist(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: PLIST:1: PLIST files shouldn't be empty.")
 }
 
 func (s *Suite) Test_ChecklinesPlist__commonEnd(c *check.C) {
-       s.Init(c)
-       s.CreateTmpFile("PLIST.common", ""+
-               "@comment $"+"NetBSD$\n"+
-               "bin/common\n")
-       fname := s.CreateTmpFile("PLIST.common_end", ""+
-               "@comment $"+"NetBSD$\n"+
-               "sbin/common_end\n")
+       t := s.Init(c)
 
-       ChecklinesPlist(LoadExistingLines(fname, false))
+       t.SetupFileLines("PLIST.common",
+               PlistRcsId,
+               "bin/common")
+       lines := t.SetupFileLines("PLIST.common_end",
+               PlistRcsId,
+               "sbin/common_end")
 
-       s.CheckOutputEmpty()
+       ChecklinesPlist(lines)
+
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_ChecklinesPlist__conditional(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.Pkg = NewPackage("category/pkgbase")
        G.Pkg.plistSubstCond["PLIST.bincmds"] = true
-       lines := T.NewLines("PLIST",
-               "@comment $"+"NetBSD$",
+       lines := t.NewLines("PLIST",
+               PlistRcsId,
                "${PLIST.bincmds}bin/subdir/command")
 
        ChecklinesPlist(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: PLIST:2: The bin/ directory should not have subdirectories.")
 }
 
 func (s *Suite) Test_ChecklinesPlist__sorting(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wplist-sort")
-       lines := T.NewLines("PLIST",
-               "@comment $"+"NetBSD$",
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wplist-sort")
+       lines := t.NewLines("PLIST",
+               PlistRcsId,
                "@comment Do not remove",
                "sbin/i386/6c",
                "sbin/program",
@@ -101,17 +106,17 @@ func (s *Suite) Test_ChecklinesPlist__so
 
        ChecklinesPlist(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: PLIST:5: \"bin/otherprogram\" should be sorted before \"sbin/program\".",
                "WARN: PLIST:6: \"bin/cat\" should be sorted before \"bin/otherprogram\".")
 }
 
 func (s *Suite) Test_PlistLineSorter_Sort(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("--autofix")
-       tmpfile := s.CreateTmpFile("PLIST", "dummy\n")
-       lines := T.NewLines(tmpfile,
-               "@comment $"+"NetBSD$",
+       t := s.Init(c)
+
+       t.SetupCommandLine("--autofix")
+       lines := t.SetupFileLines("PLIST",
+               PlistRcsId,
                "@comment Do not remove",
                "A",
                "b",
@@ -142,86 +147,91 @@ func (s *Suite) Test_PlistLineSorter_Sor
 
        sorter2.Sort()
 
-       s.CheckOutputLines(
-               "AUTOFIX: ~/PLIST:3: Sorting the whole file.",
-               "AUTOFIX: ~/PLIST: Has been auto-fixed. Please re-run pkglint.")
-       c.Check(s.LoadTmpFile("PLIST"), equals, ""+
-               "@comment $"+"NetBSD$\n"+
-               "@comment Do not remove\n"+ // The header ends here
-               "A\n"+
-               "C\n"+
-               "CCC\n"+
-               "b\n"+
-               "${PLIST.one}bin/program\n"+ // Conditionals are ignored while sorting
-               "${PLIST.two}bin/program2\n"+
-               "ddd\n"+
-               "lib/after.la\n"+
-               "lib/before.la\n"+
-               "${PLIST.linux}${PLIST.x86_64}lib/lib-linux-x86_64.so\n"+
-               "man/man1/program.1\n"+
-               "sbin/program\n"+
-               "@exec echo \"after lib/after.la\"\n") // The footer starts here
+       t.CheckOutputLines(
+               "AUTOFIX: ~/PLIST:3: Sorting the whole file.")
+       t.CheckFileLines("PLIST",
+               PlistRcsId,
+               "@comment Do not remove", // The header ends here
+               "A",
+               "C",
+               "CCC",
+               "b",
+               "${PLIST.one}bin/program", // Conditionals are ignored while sorting
+               "${PLIST.two}bin/program2",
+               "ddd",
+               "lib/after.la",
+               "lib/before.la",
+               "${PLIST.linux}${PLIST.x86_64}lib/lib-linux-x86_64.so",
+               "man/man1/program.1",
+               "sbin/program",
+               "@exec echo \"after lib/after.la\"") // The footer starts here
 }
 
 func (s *Suite) Test_PlistChecker_checkpathShare_Desktop(c *check.C) {
        // Disabled due to PR 46570, item "10. It should stop".
        return
 
-       s.Init(c)
-       s.UseCommandLine("-Wextra")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wextra")
        G.Pkg = NewPackage("category/pkgpath")
 
-       ChecklinesPlist(T.NewLines("PLIST",
-               "@comment $"+"NetBSD$",
+       ChecklinesPlist(t.NewLines("PLIST",
+               PlistRcsId,
                "share/applications/pkgbase.desktop"))
 
-       s.CheckOutputLines(
-               "WARN: PLIST:2: Packages that install a .desktop entry should .include \"../../sysutils/desktop-file-utils/desktopdb.mk\".")
+       t.CheckOutputLines(
+               "WARN: PLIST:2: Packages that install a .desktop entry " +
+                       "should .include \"../../sysutils/desktop-file-utils/desktopdb.mk\".")
 }
 
 func (s *Suite) Test_PlistChecker_checkpathMan_gz(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.Pkg = NewPackage("category/pkgbase")
-       lines := T.NewLines("PLIST",
-               "@comment $"+"NetBSD$",
+       lines := t.NewLines("PLIST",
+               PlistRcsId,
                "man/man3/strerror.3.gz")
 
        ChecklinesPlist(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "NOTE: PLIST:2: The .gz extension is unnecessary for manual pages.")
 }
 
 func (s *Suite) TestPlistChecker_checkpath__PKGMANDIR(c *check.C) {
-       s.Init(c)
-       lines := T.NewLines("PLIST",
-               "@comment $"+"NetBSD$",
+       t := s.Init(c)
+
+       lines := t.NewLines("PLIST",
+               PlistRcsId,
                "${PKGMANDIR}/man1/sh.1")
 
        ChecklinesPlist(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "NOTE: PLIST:2: PLIST files should mention \"man/\" instead of \"${PKGMANDIR}\".")
 }
 
 func (s *Suite) TestPlistChecker_checkpath__python_egg(c *check.C) {
-       s.Init(c)
-       lines := T.NewLines("PLIST",
-               "@comment $"+"NetBSD$",
+       t := s.Init(c)
+
+       lines := t.NewLines("PLIST",
+               PlistRcsId,
                "${PYSITELIB}/gdspy-${PKGVERSION}-py${PYVERSSUFFIX}.egg-info/PKG-INFO")
 
        ChecklinesPlist(lines)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: PLIST:2: Include \"../../lang/python/egg.mk\" instead of listing .egg-info files directly.")
 }
 
 func (s *Suite) Test_PlistChecker__autofix(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Wall")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Wall")
 
-       fname := s.CreateTmpFileLines("PLIST",
-               "@comment $"+"NetBSD$",
+       fname := t.CreateFileLines("PLIST",
+               PlistRcsId,
                "lib/libvirt/connection-driver/libvirt_driver_storage.la",
                "${PLIST.hal}lib/libvirt/connection-driver/libvirt_driver_nodedev.la",
                "${PLIST.xen}lib/libvirt/connection-driver/libvirt_driver_libxl.la",
@@ -244,40 +254,41 @@ func (s *Suite) Test_PlistChecker__autof
        lines := LoadExistingLines(fname, false)
        ChecklinesPlist(lines)
 
-       s.CheckOutputLines(
-               "WARN: ~/PLIST:3: \"lib/libvirt/connection-driver/libvirt_driver_nodedev.la\" should be sorted before \"lib/libvirt/connection-driver/libvirt_driver_storage.la\".",
-               "WARN: ~/PLIST:4: \"lib/libvirt/connection-driver/libvirt_driver_libxl.la\" should be sorted before \"lib/libvirt/connection-driver/libvirt_driver_nodedev.la\".",
+       t.CheckOutputLines(
+               "WARN: ~/PLIST:3: \"lib/libvirt/connection-driver/libvirt_driver_nodedev.la\" "+
+                       "should be sorted before \"lib/libvirt/connection-driver/libvirt_driver_storage.la\".",
+               "WARN: ~/PLIST:4: \"lib/libvirt/connection-driver/libvirt_driver_libxl.la\" "+
+                       "should be sorted before \"lib/libvirt/connection-driver/libvirt_driver_nodedev.la\".",
                "NOTE: ~/PLIST:6: PLIST files should mention \"man/\" instead of \"${PKGMANDIR}\".")
 
-       s.UseCommandLine("-Wall", "--autofix")
+       t.SetupCommandLine("-Wall", "--autofix")
        ChecklinesPlist(lines)
 
        fixedLines := LoadExistingLines(fname, false)
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "AUTOFIX: ~/PLIST:6: Replacing \"${PKGMANDIR}/\" with \"man/\".",
-               "AUTOFIX: ~/PLIST:2: Sorting the whole file.",
-               "AUTOFIX: ~/PLIST: Has been auto-fixed. Please re-run pkglint.")
+               "AUTOFIX: ~/PLIST:2: Sorting the whole file.")
        c.Check(len(lines), equals, len(fixedLines))
-       c.Check(s.LoadTmpFile("PLIST"), equals, ""+
-               "@comment $"+"NetBSD$\n"+
-               "${PLIST.xen}lib/libvirt/connection-driver/libvirt_driver_libxl.la\n"+
-               "${PLIST.hal}lib/libvirt/connection-driver/libvirt_driver_nodedev.la\n"+
-               "lib/libvirt/connection-driver/libvirt_driver_storage.la\n"+
-               "lib/libvirt/lock-driver/lockd.la\n"+
-               "man/man1/sh.1\n"+
-               "share/augeas/lenses/virtlockd.aug\n"+
-               "share/doc/pkgname-1.0/html/32favicon.png\n"+
-               "share/doc/pkgname-1.0/html/404.html\n"+
-               "share/doc/pkgname-1.0/html/acl.html\n"+
-               "share/doc/pkgname-1.0/html/aclpolkit.html\n"+
-               "share/doc/pkgname-1.0/html/windows.html\n"+
-               "share/examples/libvirt/libvirt.conf\n"+
-               "share/locale/zh_CN/LC_MESSAGES/libvirt.mo\n"+
-               "share/locale/zh_TW/LC_MESSAGES/libvirt.mo\n"+
-               "share/locale/zu/LC_MESSAGES/libvirt.mo\n"+
-               "@pkgdir share/examples/libvirt/nwfilter\n"+
-               "@pkgdir        etc/libvirt/qemu/networks/autostart\n"+
-               "@pkgdir        etc/logrotate.d\n"+
-               "@pkgdir        etc/sasl2\n")
+       t.CheckFileLines("PLIST",
+               PlistRcsId,
+               "${PLIST.xen}lib/libvirt/connection-driver/libvirt_driver_libxl.la",
+               "${PLIST.hal}lib/libvirt/connection-driver/libvirt_driver_nodedev.la",
+               "lib/libvirt/connection-driver/libvirt_driver_storage.la",
+               "lib/libvirt/lock-driver/lockd.la",
+               "man/man1/sh.1",
+               "share/augeas/lenses/virtlockd.aug",
+               "share/doc/pkgname-1.0/html/32favicon.png",
+               "share/doc/pkgname-1.0/html/404.html",
+               "share/doc/pkgname-1.0/html/acl.html",
+               "share/doc/pkgname-1.0/html/aclpolkit.html",
+               "share/doc/pkgname-1.0/html/windows.html",
+               "share/examples/libvirt/libvirt.conf",
+               "share/locale/zh_CN/LC_MESSAGES/libvirt.mo",
+               "share/locale/zh_TW/LC_MESSAGES/libvirt.mo",
+               "share/locale/zu/LC_MESSAGES/libvirt.mo",
+               "@pkgdir share/examples/libvirt/nwfilter",
+               "@pkgdir        etc/libvirt/qemu/networks/autostart",
+               "@pkgdir        etc/logrotate.d",
+               "@pkgdir        etc/sasl2")
 }
Index: pkgsrc/pkgtools/pkglint/files/util.go
diff -u pkgsrc/pkgtools/pkglint/files/util.go:1.18 pkgsrc/pkgtools/pkglint/files/util.go:1.19
--- pkgsrc/pkgtools/pkglint/files/util.go:1.18  Wed Jan 10 00:39:52 2018
+++ pkgsrc/pkgtools/pkglint/files/util.go       Sat Jan 27 18:50:36 2018
@@ -158,7 +158,7 @@ func loadCvsEntries(fname string) []Line
 
 // Returns the number of columns that a string occupies when printed with
 // a tabulator size of 8.
-func tabLength(s string) int {
+func tabWidth(s string) int {
        length := 0
        for _, r := range s {
                if r == '\t' {
@@ -170,6 +170,18 @@ func tabLength(s string) int {
        return length
 }
 
+func detab(s string) string {
+       detabbed := ""
+       for _, r := range s {
+               if r == '\t' {
+                       detabbed += "        "[:8-len(detabbed)%8]
+               } else {
+                       detabbed += string(r)
+               }
+       }
+       return detabbed
+}
+
 func varnameBase(varname string) string {
        dot := strings.IndexByte(varname, '.')
        if dot != -1 {

Index: pkgsrc/pkgtools/pkglint/files/mkparser_test.go
diff -u pkgsrc/pkgtools/pkglint/files/mkparser_test.go:1.7 pkgsrc/pkgtools/pkglint/files/mkparser_test.go:1.8
--- pkgsrc/pkgtools/pkglint/files/mkparser_test.go:1.7  Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/mkparser_test.go      Sat Jan 27 18:50:36 2018
@@ -5,9 +5,10 @@ import (
 )
 
 func (s *Suite) Test_MkParser_MkTokens(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        checkRest := func(input string, expectedTokens []*MkToken, expectedRest string) {
-               line := T.NewLines("Test_MkParser_MkTokens.mk", input)[0]
+               line := t.NewLines("Test_MkParser_MkTokens.mk", input)[0]
                p := NewMkParser(line, input, true)
                actualTokens := p.MkTokens()
                c.Check(actualTokens, deepEquals, expectedTokens)
@@ -110,16 +111,16 @@ func (s *Suite) Test_MkParser_MkTokens(c
        check("${VAR:ts\\124}", varuse("VAR", "ts\\124"))       // Or even decimal.
 
        check("$(GNUSTEP_USER_ROOT)", varuseText("$(GNUSTEP_USER_ROOT)", "GNUSTEP_USER_ROOT"))
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Test_MkParser_MkTokens.mk:1: Please use curly braces {} instead of round parentheses () for GNUSTEP_USER_ROOT.")
 
        checkRest("${VAR)", nil, "${VAR)") // Opening brace, closing parenthesis
        checkRest("$(VAR}", nil, "$(VAR}") // Opening parenthesis, closing brace
-       s.CheckOutputEmpty()               // Warnings are only printed for balanced expressions.
+       t.CheckOutputEmpty()               // Warnings are only printed for balanced expressions.
 
        check("${PLIST_SUBST_VARS:@var@${var}=${${var}:Q}@}", varuse("PLIST_SUBST_VARS", "@var@${var}=${${var}:Q}@"))
        check("${PLIST_SUBST_VARS:@var@${var}=${${var}:Q}}", varuse("PLIST_SUBST_VARS", "@var@${var}=${${var}:Q}")) // Missing @ at the end
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Test_MkParser_MkTokens.mk:1: Modifier ${PLIST_SUBST_VARS:@var@...@} is missing the final \"@\".")
 
        checkRest("hello, ${W:L:tl}orld", []*MkToken{
@@ -217,22 +218,22 @@ func (s *Suite) Test_MkParser_MkCond(c *
 }
 
 func (s *Suite) Test_MkParser__varuse_parentheses_autofix(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("--autofix")
+       t := s.Init(c)
+
+       t.SetupCommandLine("--autofix")
        G.globalData.InitVartypes()
-       filename := s.CreateTmpFile("Makefile", "")
-       mklines := T.NewMkLines(filename,
-               mkrcsid,
+       lines := t.SetupFileLines("Makefile",
+               MkRcsId,
                "COMMENT=$(P1) $(P2)) $(P3:Q) ${BRACES}")
+       mklines := NewMkLines(lines)
 
        mklines.Check()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "AUTOFIX: ~/Makefile:2: Replacing \"$(P1)\" with \"${P1}\".",
                "AUTOFIX: ~/Makefile:2: Replacing \"$(P2)\" with \"${P2}\".",
-               "AUTOFIX: ~/Makefile:2: Replacing \"$(P3:Q)\" with \"${P3:Q}\".",
-               "AUTOFIX: ~/Makefile: Has been auto-fixed. Please re-run pkglint.")
-       c.Check(s.LoadTmpFile("Makefile"), equals, ""+
-               mkrcsid+"\n"+
-               "COMMENT=${P1} ${P2}) ${P3:Q} ${BRACES}\n")
+               "AUTOFIX: ~/Makefile:2: Replacing \"$(P3:Q)\" with \"${P3:Q}\".")
+       t.CheckFileLines("Makefile",
+               MkRcsId,
+               "COMMENT=${P1} ${P2}) ${P3:Q} ${BRACES}")
 }
Index: pkgsrc/pkgtools/pkglint/files/toplevel_test.go
diff -u pkgsrc/pkgtools/pkglint/files/toplevel_test.go:1.7 pkgsrc/pkgtools/pkglint/files/toplevel_test.go:1.8
--- pkgsrc/pkgtools/pkglint/files/toplevel_test.go:1.7  Sun Jan 29 14:27:48 2017
+++ pkgsrc/pkgtools/pkglint/files/toplevel_test.go      Sat Jan 27 18:50:36 2018
@@ -1,31 +1,30 @@
 package main
 
-import (
-       check "gopkg.in/check.v1"
-)
+import "gopkg.in/check.v1"
 
 func (s *Suite) Test_CheckdirToplevel(c *check.C) {
-       s.Init(c)
-       s.CreateTmpFile("Makefile", ""+
-               "# $"+"NetBSD$\n"+
-               "\n"+
-               "SUBDIR+= x11\n"+
-               "SUBDIR+=\tarchivers\n"+
-               "SUBDIR+=\tccc\n"+
-               "SUBDIR+=\tccc\n"+
-               "#SUBDIR+=\tignoreme\n"+
-               "SUBDIR+=\tnonexisting\n"+ // This doesn't happen in practice, therefore no warning.
-               "SUBDIR+=\tbbb\n")
-       s.CreateTmpFile("archivers/Makefile", "")
-       s.CreateTmpFile("bbb/Makefile", "")
-       s.CreateTmpFile("ccc/Makefile", "")
-       s.CreateTmpFile("x11/Makefile", "")
+       t := s.Init(c)
+
+       t.SetupFileLines("Makefile",
+               MkRcsId,
+               "",
+               "SUBDIR+= x11",
+               "SUBDIR+=\tarchivers",
+               "SUBDIR+=\tccc",
+               "SUBDIR+=\tccc",
+               "#SUBDIR+=\tignoreme",
+               "SUBDIR+=\tnonexisting", // This doesn't happen in practice, therefore no warning.
+               "SUBDIR+=\tbbb")
+       t.SetupFileLines("archivers/Makefile")
+       t.SetupFileLines("bbb/Makefile")
+       t.SetupFileLines("ccc/Makefile")
+       t.SetupFileLines("x11/Makefile")
        G.globalData.InitVartypes()
 
-       G.CurrentDir = s.tmpdir
+       G.CurrentDir = t.TmpDir()
        CheckdirToplevel()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: ~/Makefile:3: Indentation should be a single tab character.",
                "ERROR: ~/Makefile:6: Each subdir must only appear once.",
                "WARN: ~/Makefile:7: \"ignoreme\" commented out without giving a reason.",

Index: pkgsrc/pkgtools/pkglint/files/package.go
diff -u pkgsrc/pkgtools/pkglint/files/package.go:1.23 pkgsrc/pkgtools/pkglint/files/package.go:1.24
--- pkgsrc/pkgtools/pkglint/files/package.go:1.23       Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/package.go    Sat Jan 27 18:50:36 2018
@@ -1,7 +1,6 @@
 package main
 
 import (
-       "fmt"
        "netbsd.org/pkglint/pkgver"
        "netbsd.org/pkglint/regex"
        "netbsd.org/pkglint/trace"
@@ -236,9 +235,9 @@ func (pkg *Package) loadPackageMakefile(
        }
 
        if G.opts.DumpMakefile {
-               fmt.Printf("Whole Makefile (with all included files) follows:\n")
+               G.logOut.WriteLine("Whole Makefile (with all included files) follows:")
                for _, line := range allLines.lines {
-                       fmt.Printf("%s\n", line.String())
+                       G.logOut.WriteLine(line.String())
                }
        }
 

Index: pkgsrc/pkgtools/pkglint/files/package_test.go
diff -u pkgsrc/pkgtools/pkglint/files/package_test.go:1.16 pkgsrc/pkgtools/pkglint/files/package_test.go:1.17
--- pkgsrc/pkgtools/pkglint/files/package_test.go:1.16  Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/package_test.go       Sat Jan 27 18:50:36 2018
@@ -3,9 +3,10 @@ package main
 import "gopkg.in/check.v1"
 
 func (s *Suite) Test_Package_pkgnameFromDistname(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        pkg := NewPackage("dummy")
-       pkg.vardef["PKGNAME"] = T.NewMkLine("Makefile", 5, "PKGNAME=dummy")
+       pkg.vardef["PKGNAME"] = t.NewMkLine("Makefile", 5, "PKGNAME=dummy")
 
        c.Check(pkg.pkgnameFromDistname("pkgname-1.0", "whatever"), equals, "pkgname-1.0")
        c.Check(pkg.pkgnameFromDistname("${DISTNAME}", "distname-1.0"), equals, "distname-1.0")
@@ -17,45 +18,47 @@ func (s *Suite) Test_Package_pkgnameFrom
        c.Check(pkg.pkgnameFromDistname("${DISTNAME:C/beta/.0./}", "fspanel-0.8beta1"), equals, "${DISTNAME:C/beta/.0./}")
        c.Check(pkg.pkgnameFromDistname("${DISTNAME:S/-0$/.0/1}", "aspell-af-0.50-0"), equals, "aspell-af-0.50.0")
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_Package_ChecklinesPackageMakefileVarorder(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Worder")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Worder")
        pkg := NewPackage("x11/9term")
 
-       pkg.ChecklinesPackageMakefileVarorder(T.NewMkLines("Makefile",
-               mkrcsid,
+       pkg.ChecklinesPackageMakefileVarorder(t.NewMkLines("Makefile",
+               MkRcsId,
                "",
                "DISTNAME=9term",
                "CATEGORIES=x11"))
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 
-       pkg.ChecklinesPackageMakefileVarorder(T.NewMkLines("Makefile",
-               mkrcsid,
+       pkg.ChecklinesPackageMakefileVarorder(t.NewMkLines("Makefile",
+               MkRcsId,
                "",
                "DISTNAME=9term",
                "CATEGORIES=x11",
                "",
                ".include \"../../mk/bsd.pkg.mk\""))
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: Makefile:6: The canonical position for the required variable COMMENT is here.",
                "WARN: Makefile:6: The canonical position for the required variable LICENSE is here.")
 }
 
 func (s *Suite) Test_Package_varorder_license(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Worder")
+       t := s.Init(c)
 
-       s.CreateTmpFileLines("mk/bsd.pkg.mk", "# dummy")
-       s.CreateTmpFileLines("x11/Makefile", mkrcsid)
-       s.CreateTmpFileLines("x11/9term/PLIST", "@comment $"+"NetBSD$", "bin/9term")
-       s.CreateTmpFileLines("x11/9term/distinfo", "$"+"NetBSD$")
-       s.CreateTmpFileLines("x11/9term/Makefile",
-               mkrcsid,
+       t.SetupCommandLine("-Worder")
+
+       t.CreateFileLines("mk/bsd.pkg.mk", "# dummy")
+       t.CreateFileLines("x11/Makefile", MkRcsId)
+       t.CreateFileLines("x11/9term/PLIST", PlistRcsId, "bin/9term")
+       t.CreateFileLines("x11/9term/distinfo", RcsId)
+       t.CreateFileLines("x11/9term/Makefile",
+               MkRcsId,
                "",
                "DISTNAME=9term-1.0",
                "CATEGORIES=x11",
@@ -65,49 +68,55 @@ func (s *Suite) Test_Package_varorder_li
                ".include \"../../mk/bsd.pkg.mk\"")
 
        G.globalData.InitVartypes()
-       G.globalData.Pkgsrcdir = s.TmpDir()
-       G.CurrentDir = s.TmpDir()
+       G.globalData.Pkgsrcdir = t.TmpDir()
+       G.CurrentDir = t.TmpDir()
 
-       (&Pkglint{}).CheckDirent(s.TmpDir() + "/x11/9term")
+       (&Pkglint{}).CheckDirent(t.TmpDir() + "/x11/9term")
 
        // Since the error is grave enough, the warning about the correct position is suppressed.
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: ~/x11/9term/Makefile: Each package must define its LICENSE.")
 }
 
 // https://mail-index.netbsd.org/tech-pkg/2017/01/18/msg017698.html
 func (s *Suite) Test_Package_ChecklinesPackageMakefileVarorder__MASTER_SITES(c *check.C) {
-       s.Init(c)
-       s.UseCommandLine("-Worder")
+       t := s.Init(c)
+
+       t.SetupCommandLine("-Worder")
        pkg := NewPackage("category/package")
 
-       pkg.ChecklinesPackageMakefileVarorder(T.NewMkLines("Makefile",
-               mkrcsid,
+       pkg.ChecklinesPackageMakefileVarorder(t.NewMkLines("Makefile",
+               MkRcsId,
                "",
                "PKGNAME=\tpackage-1.0",
                "CATEGORIES=\tcategory",
                "MASTER_SITES=\thttp://example.org/";,
                "MASTER_SITES+=\thttp://mirror.example.org/";))
 
-       s.CheckOutputEmpty() // No warning that "MASTER_SITES appears too late"
+       // No warning that "MASTER_SITES appears too late"
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_Package_getNbpart(c *check.C) {
+       t := s.Init(c)
+
        pkg := NewPackage("category/pkgbase")
-       pkg.vardef["PKGREVISION"] = T.NewMkLine("Makefile", 1, "PKGREVISION=14")
+       pkg.vardef["PKGREVISION"] = t.NewMkLine("Makefile", 1, "PKGREVISION=14")
 
        c.Check(pkg.getNbpart(), equals, "nb14")
 
-       pkg.vardef["PKGREVISION"] = T.NewMkLine("Makefile", 1, "PKGREVISION=asdf")
+       pkg.vardef["PKGREVISION"] = t.NewMkLine("Makefile", 1, "PKGREVISION=asdf")
 
        c.Check(pkg.getNbpart(), equals, "")
 }
 
 func (s *Suite) Test_Package_determineEffectivePkgVars__precedence(c *check.C) {
+       t := s.Init(c)
+
        pkg := NewPackage("category/pkgbase")
-       pkgnameLine := T.NewMkLine("Makefile", 3, "PKGNAME=pkgname-1.0")
-       distnameLine := T.NewMkLine("Makefile", 4, "DISTNAME=distname-1.0")
-       pkgrevisionLine := T.NewMkLine("Makefile", 5, "PKGREVISION=13")
+       pkgnameLine := t.NewMkLine("Makefile", 3, "PKGNAME=pkgname-1.0")
+       distnameLine := t.NewMkLine("Makefile", 4, "DISTNAME=distname-1.0")
+       pkgrevisionLine := t.NewMkLine("Makefile", 5, "PKGREVISION=13")
 
        pkg.defineVar(pkgnameLine, pkgnameLine.Varname())
        pkg.defineVar(distnameLine, distnameLine.Varname())
@@ -121,40 +130,42 @@ func (s *Suite) Test_Package_determineEf
 }
 
 func (s *Suite) Test_Package_checkPossibleDowngrade(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.Pkg = NewPackage("category/pkgbase")
        G.CurPkgsrcdir = "../.."
        G.Pkg.EffectivePkgname = "package-1.0nb15"
-       G.Pkg.EffectivePkgnameLine = T.NewMkLine("category/pkgbase/Makefile", 5, "PKGNAME=dummy")
+       G.Pkg.EffectivePkgnameLine = t.NewMkLine("category/pkgbase/Makefile", 5, "PKGNAME=dummy")
        G.globalData.LastChange = map[string]*Change{
                "category/pkgbase": {
                        Action:  "Updated",
                        Version: "1.8",
-                       Line:    T.NewLine("doc/CHANGES", 116, "dummy"),
+                       Line:    t.NewLine("doc/CHANGES", 116, "dummy"),
                },
        }
 
        G.Pkg.checkPossibleDowngrade()
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: category/pkgbase/Makefile:5: The package is being downgraded from 1.8 (see ../../doc/CHANGES:116) to 1.0nb15")
 
        G.globalData.LastChange["category/pkgbase"].Version = "1.0nb22"
 
        G.Pkg.checkPossibleDowngrade()
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_checkdirPackage(c *check.C) {
-       s.Init(c)
-       s.CreateTmpFile("Makefile", ""+
-               "# $"+"NetBSD$\n")
-       G.CurrentDir = s.tmpdir
+       t := s.Init(c)
 
-       checkdirPackage(s.tmpdir)
+       t.SetupFileLines("Makefile",
+               MkRcsId)
+       G.CurrentDir = t.TmpDir()
 
-       s.CheckOutputLines(
+       checkdirPackage(t.TmpDir())
+
+       t.CheckOutputLines(
                "WARN: ~/Makefile: Neither PLIST nor PLIST.common exist, and PLIST_SRC is unset. Are you sure PLIST handling is ok?",
                "WARN: ~/distinfo: File not found. Please run \"@BMAKE@ makesum\".",
                "ERROR: ~/Makefile: Each package must define its LICENSE.",
@@ -162,48 +173,50 @@ func (s *Suite) Test_checkdirPackage(c *
 }
 
 func (s *Suite) Test_checkdirPackage__meta_package_without_license(c *check.C) {
-       s.Init(c)
-       s.CreateTmpFileLines("Makefile",
-               mkrcsid,
+       t := s.Init(c)
+
+       t.CreateFileLines("Makefile",
+               MkRcsId,
                "",
                "META_PACKAGE=\tyes")
-       G.CurrentDir = s.TmpDir()
+       G.CurrentDir = t.TmpDir()
        G.globalData.InitVartypes()
 
-       checkdirPackage(s.TmpDir())
+       checkdirPackage(t.TmpDir())
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: ~/Makefile: No COMMENT given.") // No error about missing LICENSE.
 }
 
 func (s *Suite) Test_Package__varuse_at_load_time(c *check.C) {
-       s.Init(c)
-       s.CreateTmpFileLines("doc/CHANGES-2016",
+       t := s.Init(c)
+
+       t.CreateFileLines("doc/CHANGES-2016",
                "# dummy")
-       s.CreateTmpFileLines("doc/TODO",
+       t.CreateFileLines("doc/TODO",
                "# dummy")
-       s.CreateTmpFileLines("licenses/bsd-2",
+       t.CreateFileLines("licenses/bsd-2",
                "# dummy")
-       s.CreateTmpFileLines("mk/fetch/sites.mk",
+       t.CreateFileLines("mk/fetch/sites.mk",
                "# dummy")
-       s.CreateTmpFileLines("mk/bsd.pkg.mk",
+       t.CreateFileLines("mk/bsd.pkg.mk",
                "# dummy")
-       s.CreateTmpFileLines("mk/defaults/options.description",
+       t.CreateFileLines("mk/defaults/options.description",
                "option Description")
-       s.CreateTmpFileLines("mk/defaults/mk.conf",
+       t.CreateFileLines("mk/defaults/mk.conf",
                "# dummy")
-       s.CreateTmpFileLines("mk/tools/bsd.tools.mk",
+       t.CreateFileLines("mk/tools/bsd.tools.mk",
                ".include \"defaults.mk\"")
-       s.CreateTmpFileLines("mk/tools/defaults.mk",
+       t.CreateFileLines("mk/tools/defaults.mk",
                "TOOLS_CREATE+=false",
                "TOOLS_CREATE+=nice",
                "TOOLS_CREATE+=true",
                "_TOOLS_VARNAME.nice=NICE")
-       s.CreateTmpFileLines("mk/bsd.prefs.mk",
+       t.CreateFileLines("mk/bsd.prefs.mk",
                "# dummy")
 
-       s.CreateTmpFileLines("category/pkgbase/Makefile",
-               mkrcsid,
+       t.CreateFileLines("category/pkgbase/Makefile",
+               MkRcsId,
                "",
                "COMMENT= Unit test",
                "LICENSE= bsd-2",
@@ -227,12 +240,12 @@ func (s *Suite) Test_Package__varuse_at_
                "\t${ECHO}; ${FALSE}; ${NICE}; ${TRUE}",
                "",
                ".include \"../../mk/bsd.pkg.mk\"")
-       s.CreateTmpFileLines("category/pkgbase/distinfo",
-               "$"+"NetBSD$")
+       t.CreateFileLines("category/pkgbase/distinfo",
+               RcsId)
 
-       (&Pkglint{}).Main("pkglint", "-q", "-Wperm", s.tmpdir+"/category/pkgbase")
+       (&Pkglint{}).Main("pkglint", "-q", "-Wperm", t.TmpDir()+"/category/pkgbase")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: ~/category/pkgbase/Makefile:8: To use the tool \"FALSE\" at load time, bsd.prefs.mk has to be included before.",
                "WARN: ~/category/pkgbase/Makefile:9: To use the tool \"NICE\" at load time, bsd.prefs.mk has to be included before.",
                "WARN: ~/category/pkgbase/Makefile:10: To use the tool \"TRUE\" at load time, bsd.prefs.mk has to be included before.",
@@ -240,28 +253,32 @@ func (s *Suite) Test_Package__varuse_at_
 }
 
 func (s *Suite) Test_Package_loadPackageMakefile(c *check.C) {
-       s.Init(c)
-       makefile := s.CreateTmpFile("category/package/Makefile", ""+
-               "# $"+"NetBSD$\n"+
-               "\n"+
-               "PKGNAME=pkgname-1.67\n"+
-               "DISTNAME=distfile_1_67\n"+
-               ".include \"../../category/package/Makefile\"\n")
+       t := s.Init(c)
+
+       t.SetupFileLines("category/package/Makefile",
+               MkRcsId,
+               "",
+               "PKGNAME=pkgname-1.67",
+               "DISTNAME=distfile_1_67",
+               ".include \"../../category/package/Makefile\"")
        pkg := NewPackage("category/package")
-       G.CurrentDir = s.tmpdir + "/category/package"
+       G.CurrentDir = t.TempFilename("category/package")
        G.CurPkgsrcdir = "../.."
        G.Pkg = pkg
 
-       pkg.loadPackageMakefile(makefile)
+       pkg.loadPackageMakefile(t.TempFilename("category/package/Makefile"))
 
-       s.CheckOutputEmpty()
+       // Including a package Makefile directly is an error (in the last line),
+       // but that is checked later.
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_Package_conditionalAndUnconditionalInclude(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.InitVartypes()
-       s.CreateTmpFileLines("category/package/Makefile",
-               mkrcsid,
+       t.CreateFileLines("category/package/Makefile",
+               MkRcsId,
                "",
                "COMMENT\t=Description",
                "LICENSE\t= gnu-gpl-v2",
@@ -270,34 +287,36 @@ func (s *Suite) Test_Package_conditional
                ".include \"../../sysutils/coreutils/buildlink3.mk\"",
                ".endif",
                ".include \"../../mk/bsd.pkg.mk\"")
-       s.CreateTmpFileLines("category/package/options.mk",
-               mkrcsid,
+       t.CreateFileLines("category/package/options.mk",
+               MkRcsId,
                "",
                ".if !empty(PKG_OPTIONS:Mzlib)",
                ".  include \"../../devel/zlib/buildlink3.mk\"",
                ".endif",
                ".include \"../../sysutils/coreutils/buildlink3.mk\"")
-       s.CreateTmpFileLines("category/package/PLIST",
-               "@comment $"+"NetBSD$",
+       t.CreateFileLines("category/package/PLIST",
+               PlistRcsId,
                "bin/program")
-       s.CreateTmpFileLines("category/package/distinfo",
-               "$"+"NetBSD$")
+       t.CreateFileLines("category/package/distinfo",
+               RcsId)
 
-       s.CreateTmpFileLines("devel/zlib/buildlink3.mk", "")
-       s.CreateTmpFileLines("licenses/gnu-gpl-v2", "")
-       s.CreateTmpFileLines("mk/bsd.pkg.mk", "")
-       s.CreateTmpFileLines("sysutils/coreutils/buildlink3.mk", "")
+       t.CreateFileLines("devel/zlib/buildlink3.mk", "")
+       t.CreateFileLines("licenses/gnu-gpl-v2", "")
+       t.CreateFileLines("mk/bsd.pkg.mk", "")
+       t.CreateFileLines("sysutils/coreutils/buildlink3.mk", "")
 
        pkg := NewPackage("category/package")
-       G.globalData.Pkgsrcdir = s.tmpdir
-       G.CurrentDir = s.tmpdir + "/category/package"
+       G.globalData.Pkgsrcdir = t.TmpDir()
+       G.CurrentDir = t.TmpDir() + "/category/package"
        G.CurPkgsrcdir = "../.."
        G.Pkg = pkg
 
        checkdirPackage("category/package")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: ~/category/package/options.mk:3: Unknown option \"zlib\".",
-               "WARN: ~/category/package/options.mk:4: \"../../devel/zlib/buildlink3.mk\" is included conditionally here (depending on PKG_OPTIONS) and unconditionally in Makefile:5.",
-               "WARN: ~/category/package/options.mk:6: \"../../sysutils/coreutils/buildlink3.mk\" is included unconditionally here and conditionally in Makefile:7 (depending on OPSYS).")
+               "WARN: ~/category/package/options.mk:4: \"../../devel/zlib/buildlink3.mk\" is "+
+                       "included conditionally here (depending on PKG_OPTIONS) and unconditionally in Makefile:5.",
+               "WARN: ~/category/package/options.mk:6: \"../../sysutils/coreutils/buildlink3.mk\" is "+
+                       "included unconditionally here and conditionally in Makefile:7 (depending on OPSYS).")
 }

Index: pkgsrc/pkgtools/pkglint/files/pkglint.go
diff -u pkgsrc/pkgtools/pkglint/files/pkglint.go:1.24 pkgsrc/pkgtools/pkglint/files/pkglint.go:1.25
--- pkgsrc/pkgtools/pkglint/files/pkglint.go:1.24       Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/pkglint.go    Sat Jan 27 18:50:36 2018
@@ -18,7 +18,9 @@ const confMake = "@BMAKE@"
 const confVersion = "@VERSION@"
 
 func main() {
-       G.logOut, G.logErr, trace.Out = NewSeparatorWriter(os.Stdout), NewSeparatorWriter(os.Stderr), os.Stdout
+       G.logOut = NewSeparatorWriter(os.Stdout)
+       G.logErr = NewSeparatorWriter(os.Stderr)
+       trace.Out = os.Stdout
        os.Exit(new(Pkglint).Main(os.Args...))
 }
 
@@ -157,7 +159,7 @@ func (pkglint *Pkglint) ParseCommandLine
 }
 
 func (pkglint *Pkglint) PrintSummary() {
-       if !G.opts.Quiet {
+       if !G.opts.Quiet && !G.opts.Autofix {
                if G.errors != 0 || G.warnings != 0 {
                        G.logOut.Printf("%d %s and %d %s found.\n",
                                G.errors, ifelseStr(G.errors == 1, "error", "errors"),
@@ -168,7 +170,7 @@ func (pkglint *Pkglint) PrintSummary() {
                if G.explanationsAvailable && !G.opts.Explain {
                        G.logOut.WriteLine("(Run \"pkglint -e\" to show explanations.)")
                }
-               if G.autofixAvailable && !G.opts.PrintAutofix && !G.opts.Autofix {
+               if G.autofixAvailable && !G.opts.PrintAutofix {
                        G.logOut.WriteLine("(Run \"pkglint -fs\" to show what can be fixed automatically.)")
                }
                if G.autofixAvailable && !G.opts.Autofix {

Index: pkgsrc/pkgtools/pkglint/files/tree_test.go
diff -u pkgsrc/pkgtools/pkglint/files/tree_test.go:1.3 pkgsrc/pkgtools/pkglint/files/tree_test.go:1.4
--- pkgsrc/pkgtools/pkglint/files/tree_test.go:1.3      Sat Jul  9 09:43:48 2016
+++ pkgsrc/pkgtools/pkglint/files/tree_test.go  Sat Jan 27 18:50:36 2018
@@ -1,8 +1,6 @@
 package main
 
-import (
-       check "gopkg.in/check.v1"
-)
+import "gopkg.in/check.v1"
 
 func (s *Suite) Test_Tree_String(c *check.C) {
        c.Check(NewTree("not", NewTree("empty", "varname")).String(), equals, "(not (empty \"varname\"))")

Index: pkgsrc/pkgtools/pkglint/files/util_test.go
diff -u pkgsrc/pkgtools/pkglint/files/util_test.go:1.8 pkgsrc/pkgtools/pkglint/files/util_test.go:1.9
--- pkgsrc/pkgtools/pkglint/files/util_test.go:1.8      Tue Jan 17 22:37:27 2017
+++ pkgsrc/pkgtools/pkglint/files/util_test.go  Sat Jan 27 18:50:36 2018
@@ -1,7 +1,7 @@
 package main
 
 import (
-       check "gopkg.in/check.v1"
+       "gopkg.in/check.v1"
        "netbsd.org/pkglint/regex"
        "netbsd.org/pkglint/textproc"
        "testing"
@@ -43,11 +43,11 @@ func (s *Suite) Test_replaceFirst(c *che
 }
 
 func (s *Suite) Test_tabLength(c *check.C) {
-       c.Check(tabLength("12345"), equals, 5)
-       c.Check(tabLength("\t"), equals, 8)
-       c.Check(tabLength("123\t"), equals, 8)
-       c.Check(tabLength("1234567\t"), equals, 8)
-       c.Check(tabLength("12345678\t"), equals, 16)
+       c.Check(tabWidth("12345"), equals, 5)
+       c.Check(tabWidth("\t"), equals, 8)
+       c.Check(tabWidth("123\t"), equals, 8)
+       c.Check(tabWidth("1234567\t"), equals, 8)
+       c.Check(tabWidth("12345678\t"), equals, 16)
 }
 
 func (s *Suite) Test_cleanpath(c *check.C) {
@@ -63,21 +63,23 @@ func (s *Suite) Test_cleanpath(c *check.
 }
 
 func (s *Suite) Test_isEmptyDir_and_getSubdirs(c *check.C) {
-       s.Init(c)
-       s.CreateTmpFile("CVS/Entries", "dummy\n")
+       t := s.Init(c)
 
-       c.Check(isEmptyDir(s.tmpdir), equals, true)
-       c.Check(getSubdirs(s.tmpdir), check.DeepEquals, []string(nil))
+       t.SetupFileLines("CVS/Entries",
+               "dummy")
 
-       s.CreateTmpFile("somedir/file", "")
+       c.Check(isEmptyDir(t.TmpDir()), equals, true)
+       c.Check(getSubdirs(t.TmpDir()), check.DeepEquals, []string(nil))
 
-       c.Check(isEmptyDir(s.tmpdir), equals, false)
-       c.Check(getSubdirs(s.tmpdir), check.DeepEquals, []string{"somedir"})
+       t.SetupFileLines("somedir/file")
 
-       if nodir := s.tmpdir + "/nonexistent"; true {
+       c.Check(isEmptyDir(t.TmpDir()), equals, false)
+       c.Check(getSubdirs(t.TmpDir()), check.DeepEquals, []string{"somedir"})
+
+       if nodir := t.TmpDir() + "/nonexistent"; true {
                c.Check(isEmptyDir(nodir), equals, true) // Counts as empty.
-               defer s.ExpectFatalError(func() {
-                       c.Check(s.Output(), check.Matches, `FATAL: (.+): Cannot be read: open (.+): (.+)\n`)
+               defer t.ExpectFatalError(func() {
+                       c.Check(t.Output(), check.Matches, `FATAL: (.+): Cannot be read: open (.+): (.+)\n`)
                })
                c.Check(getSubdirs(nodir), check.DeepEquals, []string(nil))
                c.FailNow()
@@ -91,6 +93,14 @@ func (s *Suite) Test_PrefixReplacer_Sinc
        c.Check(repl.Since(mark), equals, "hello")
 }
 
+func (s *Suite) Test_detab(c *check.C) {
+       c.Check(detab(""), equals, "")
+       c.Check(detab("\t"), equals, "        ")
+       c.Check(detab("1234\t9"), equals, "1234    9")
+       c.Check(detab("1234567\t"), equals, "1234567 ")
+       c.Check(detab("12345678\t"), equals, "12345678        ")
+}
+
 const reMkIncludeBenchmark = `^\.(\s*)(s?include)\s+\"([^\"]+)\"\s*(?:#.*)?$`
 const reMkIncludeBenchmarkPositive = `^\.(\s*)(s?include)\s+\"(.+)\"\s*(?:#.*)?$`
 
@@ -147,3 +157,10 @@ func Benchmark_match3_explicit(b *testin
                MatchMkInclude(".include \"../../mk/bsd.pkg.mk\"          # infrastructure     ")
        }
 }
+
+func emptyToNil(slice []string) []string {
+       if len(slice) == 0 {
+               return nil
+       }
+       return slice
+}

Index: pkgsrc/pkgtools/pkglint/files/vardefs.go
diff -u pkgsrc/pkgtools/pkglint/files/vardefs.go:1.34 pkgsrc/pkgtools/pkglint/files/vardefs.go:1.35
--- pkgsrc/pkgtools/pkglint/files/vardefs.go:1.34       Sun Jan  7 17:08:15 2018
+++ pkgsrc/pkgtools/pkglint/files/vardefs.go    Sat Jan 27 18:50:36 2018
@@ -14,6 +14,9 @@ import (
 //
 // See vartypecheck.go for how these types are checked.
 
+// InitVartypes initializes the long list of predefined pkgsrc variables.
+// After this is done, ${PKGNAME}, ${MAKE_ENV} and all the other variables
+// can be used in Makefiles without triggering warnings about typos.
 func (gd *GlobalData) InitVartypes() {
 
        // A package-defined variable may be set in all Makefiles except buildlink3.mk and builtin.mk.

Index: pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go
diff -u pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go:1.20 pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go:1.21
--- pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go:1.20     Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/vartypecheck_test.go  Sat Jan 27 18:50:36 2018
@@ -7,56 +7,63 @@ import (
 )
 
 func (s *Suite) Test_VartypeCheck_AwkCommand(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("PLIST_AWK", opAssignAppend, (*VartypeCheck).AwkCommand,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "PLIST_AWK", opAssignAppend, (*VartypeCheck).AwkCommand,
                "{print $0}",
                "{print $$0}")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: $0 is ambiguous. Use ${0} if you mean a Makefile variable or $$0 if you mean a shell variable.")
 }
 
 func (s *Suite) Test_VartypeCheck_BasicRegularExpression(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("REPLACE_FILES.pl", opAssign, (*VartypeCheck).BasicRegularExpression,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "REPLACE_FILES.pl", opAssign, (*VartypeCheck).BasicRegularExpression,
                ".*\\.pl$",
                ".*\\.pl$$")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: Pkglint parse error in MkLine.Tokenize at \"$\".")
 }
 
 func (s *Suite) Test_VartypeCheck_BuildlinkDepmethod(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("BUILDLINK_DEPMETHOD.libc", opAssignDefault, (*VartypeCheck).BuildlinkDepmethod,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "BUILDLINK_DEPMETHOD.libc", opAssignDefault, (*VartypeCheck).BuildlinkDepmethod,
                "full",
                "unknown")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:2: Invalid dependency method \"unknown\". Valid methods are \"build\" or \"full\".")
 }
 
 func (s *Suite) Test_VartypeCheck_Category(c *check.C) {
-       s.Init(c)
-       s.CreateTmpFile("filesyscategory/Makefile", "# empty\n")
-       s.CreateTmpFile("wip/Makefile", "# empty\n")
-       G.CurrentDir = s.tmpdir
+       t := s.Init(c)
+
+       t.SetupFileLines("filesyscategory/Makefile",
+               "# empty")
+       t.SetupFileLines("wip/Makefile",
+               "# empty")
+       G.CurrentDir = t.TmpDir()
        G.CurPkgsrcdir = "."
 
-       runVartypeChecks("CATEGORIES", opAssign, (*VartypeCheck).Category,
+       runVartypeChecks(t, "CATEGORIES", opAssign, (*VartypeCheck).Category,
                "chinese",
                "arabic",
                "filesyscategory",
                "wip")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: fname:2: Invalid category \"arabic\".",
                "ERROR: fname:4: Invalid category \"wip\".")
 }
 
 func (s *Suite) Test_VartypeCheck_CFlag(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("CFLAGS", opAssignAppend, (*VartypeCheck).CFlag,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "CFLAGS", opAssignAppend, (*VartypeCheck).CFlag,
                "-Wall",
                "/W3",
                "target:sparc64",
@@ -64,15 +71,16 @@ func (s *Suite) Test_VartypeCheck_CFlag(
                "-XX:+PrintClassHistogramAfterFullGC",
                "`pkg-config pidgin --cflags`")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:2: Compiler flag \"/W3\" should start with a hyphen.",
                "WARN: fname:3: Compiler flag \"target:sparc64\" should start with a hyphen.",
                "WARN: fname:5: Unknown compiler flag \"-XX:+PrintClassHistogramAfterFullGC\".")
 }
 
 func (s *Suite) Test_VartypeCheck_Comment(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("COMMENT", opAssign, (*VartypeCheck).Comment,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "COMMENT", opAssign, (*VartypeCheck).Comment,
                "Versatile Programming Language",
                "TODO: Short description of the package",
                "A great package.",
@@ -80,7 +88,7 @@ func (s *Suite) Test_VartypeCheck_Commen
                "\"Quoting the comment is wrong\"",
                "'Quoting the comment is wrong'")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: fname:2: COMMENT must be set.",
                "WARN: fname:3: COMMENT should not begin with \"A\".",
                "WARN: fname:3: COMMENT should not end with a period.",
@@ -91,15 +99,16 @@ func (s *Suite) Test_VartypeCheck_Commen
 }
 
 func (s *Suite) Test_VartypeCheck_ConfFiles(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("CONF_FILES", opAssignAppend, (*VartypeCheck).ConfFiles,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "CONF_FILES", opAssignAppend, (*VartypeCheck).ConfFiles,
                "single/file",
                "share/etc/config ${PKG_SYSCONFDIR}/etc/config",
                "share/etc/config ${PKG_SYSCONFBASE}/etc/config file",
                "share/etc/config ${PREFIX}/etc/config share/etc/config2 ${VARBASE}/config2",
                "share/etc/bootrc /etc/bootrc")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: Values for CONF_FILES should always be pairs of paths.",
                "WARN: fname:3: Values for CONF_FILES should always be pairs of paths.",
                "WARN: fname:5: Found absolute pathname: /etc/bootrc",
@@ -107,7 +116,9 @@ func (s *Suite) Test_VartypeCheck_ConfFi
 }
 
 func (s *Suite) Test_VartypeCheck_Dependency(c *check.C) {
-       runVartypeChecks("CONFLICTS", opAssignAppend, (*VartypeCheck).Dependency,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "CONFLICTS", opAssignAppend, (*VartypeCheck).Dependency,
                "Perl",
                "perl5>=5.22",
                "perl5-*",
@@ -130,28 +141,31 @@ func (s *Suite) Test_VartypeCheck_Depend
                "{ssh{,6}-[0-9]*,openssh-[0-9]*}",
                "gnome-control-center>=2.20.1{,nb*}")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:1: Unknown dependency pattern \"Perl\".\n"+
-               "WARN: fname:3: Please use \"perl5-[0-9]*\" instead of \"perl5-*\".\n"+
-               "WARN: fname:5: Only [0-9]* is allowed in the numeric part of a dependency.\n"+
-               "WARN: fname:5: The version pattern \"[5.10-5.22]*\" should not contain a hyphen.\n"+
-               "WARN: fname:6: Unknown dependency pattern \"py-docs\".\n"+
-               "WARN: fname:10: Please use \"5.22{,nb*}\" instead of \"5.22\" as the version pattern.\n"+
-               "WARN: fname:11: Please use \"5.*\" instead of \"5*\" as the version pattern.\n"+
-               "WARN: fname:12: The version pattern \"2.0-[0-9]*\" should not contain a hyphen.\n"+
-               "WARN: fname:20: The version pattern \"[0-9]*,openssh-[0-9]*}\" should not contain a hyphen.\n"+ // XXX
-               "WARN: fname:21: Dependency patterns of the form pkgbase>=1.0 don't need the \"{,nb*}\" extension.\n")
+       t.CheckOutputLines(
+               "WARN: fname:1: Unknown dependency pattern \"Perl\".",
+               "WARN: fname:3: Please use \"perl5-[0-9]*\" instead of \"perl5-*\".",
+               "WARN: fname:5: Only [0-9]* is allowed in the numeric part of a dependency.",
+               "WARN: fname:5: The version pattern \"[5.10-5.22]*\" should not contain a hyphen.",
+               "WARN: fname:6: Unknown dependency pattern \"py-docs\".",
+               "WARN: fname:10: Please use \"5.22{,nb*}\" instead of \"5.22\" as the version pattern.",
+               "WARN: fname:11: Please use \"5.*\" instead of \"5*\" as the version pattern.",
+               "WARN: fname:12: The version pattern \"2.0-[0-9]*\" should not contain a hyphen.",
+               "WARN: fname:20: The version pattern \"[0-9]*,openssh-[0-9]*}\" should not contain a hyphen.", // XXX
+               "WARN: fname:21: Dependency patterns of the form pkgbase>=1.0 don't need the \"{,nb*}\" extension.")
 }
 
 func (s *Suite) Test_VartypeCheck_DependencyWithPath(c *check.C) {
-       s.Init(c)
-       s.CreateTmpFile("x11/alacarte/Makefile", "# empty\n")
-       s.CreateTmpFile("category/package/Makefile", "# empty\n")
-       G.globalData.Pkgsrcdir = s.tmpdir
-       G.CurrentDir = s.tmpdir + "/category/package"
+       t := s.Init(c)
+
+       t.SetupFileLines("x11/alacarte/Makefile",
+               "# empty")
+       t.SetupFileLines("category/package/Makefile",
+               "# empty")
+       G.globalData.Pkgsrcdir = t.TmpDir()
+       G.CurrentDir = t.TmpDir() + "/category/package"
        G.CurPkgsrcdir = "../.."
 
-       runVartypeChecks("DEPENDS", opAssignAppend, (*VartypeCheck).DependencyWithPath,
+       runVartypeChecks(t, "DEPENDS", opAssignAppend, (*VartypeCheck).DependencyWithPath,
                "Perl",
                "perl5>=5.22:../perl5",
                "perl5>=5.24:../../lang/perl5",
@@ -165,226 +179,263 @@ func (s *Suite) Test_VartypeCheck_Depend
                "broken>:../../x11/alacarte",
                "gtk2+>=2.16:../../x11/alacarte")
 
-       c.Check(s.Output(), equals, ""+
-               "WARN: fname:1: Unknown dependency pattern with path \"Perl\".\n"+
-               "WARN: fname:2: Dependencies should have the form \"../../category/package\".\n"+
-               "ERROR: fname:3: \"../../lang/perl5\" does not exist.\n"+
-               "ERROR: fname:3: There is no package in \"lang/perl5\".\n"+
-               "WARN: fname:3: Please use USE_TOOLS+=perl:run instead of this dependency.\n"+
-               "WARN: fname:4: Unknown dependency pattern \"broken0.12.1\".\n"+
-               "WARN: fname:5: Unknown dependency pattern \"broken[0-9]*\".\n"+
-               "WARN: fname:6: Unknown dependency pattern with path \"broken[0-9]*../../x11/alacarte\".\n"+
-               "WARN: fname:7: Unknown dependency pattern \"broken>=\".\n"+
-               "WARN: fname:8: Unknown dependency pattern \"broken=0\".\n"+
-               "WARN: fname:9: Unknown dependency pattern \"broken=\".\n"+
-               "WARN: fname:10: Unknown dependency pattern \"broken-\".\n"+
-               "WARN: fname:11: Unknown dependency pattern \"broken>\".\n")
+       t.CheckOutputLines(
+               "WARN: fname:1: Unknown dependency pattern with path \"Perl\".",
+               "WARN: fname:2: Dependencies should have the form \"../../category/package\".",
+               "ERROR: fname:3: \"../../lang/perl5\" does not exist.",
+               "ERROR: fname:3: There is no package in \"lang/perl5\".",
+               "WARN: fname:3: Please use USE_TOOLS+=perl:run instead of this dependency.",
+               "WARN: fname:4: Unknown dependency pattern \"broken0.12.1\".",
+               "WARN: fname:5: Unknown dependency pattern \"broken[0-9]*\".",
+               "WARN: fname:6: Unknown dependency pattern with path \"broken[0-9]*../../x11/alacarte\".",
+               "WARN: fname:7: Unknown dependency pattern \"broken>=\".",
+               "WARN: fname:8: Unknown dependency pattern \"broken=0\".",
+               "WARN: fname:9: Unknown dependency pattern \"broken=\".",
+               "WARN: fname:10: Unknown dependency pattern \"broken-\".",
+               "WARN: fname:11: Unknown dependency pattern \"broken>\".")
 }
 
 func (s *Suite) Test_VartypeCheck_DistSuffix(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("EXTRACT_SUFX", opAssign, (*VartypeCheck).DistSuffix,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "EXTRACT_SUFX", opAssign, (*VartypeCheck).DistSuffix,
                ".tar.gz",
                ".tar.bz2")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "NOTE: fname:1: EXTRACT_SUFX is \".tar.gz\" by default, so this definition may be redundant.")
 }
 
 func (s *Suite) Test_VartypeCheck_EmulPlatform(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("EMUL_PLATFORM", opAssign, (*VartypeCheck).EmulPlatform,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "EMUL_PLATFORM", opAssign, (*VartypeCheck).EmulPlatform,
                "linux-i386",
                "nextbsd-8087",
                "${LINUX}")
 
-       s.CheckOutputLines(
-               "WARN: fname:2: \"nextbsd\" is not valid for the operating system part of EMUL_PLATFORM. Use one of { bitrig bsdos cygwin darwin dragonfly freebsd haiku hpux interix irix linux mirbsd 
netbsd openbsd osf1 solaris sunos } instead.",
-               "WARN: fname:2: \"8087\" is not valid for the hardware architecture part of EMUL_PLATFORM. Use one of { aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex 
dreamcast earm earmeb earmhf earmhfeb earmv4 earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 
m68000 m68k m88k mips mips64 mips64eb mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } instead.",
+       t.CheckOutputLines(
+               "WARN: fname:2: \"nextbsd\" is not valid for the operating system part of EMUL_PLATFORM. "+
+                       "Use one of "+
+                       "{ bitrig bsdos cygwin darwin dragonfly freebsd haiku hpux "+
+                       "interix irix linux mirbsd netbsd openbsd osf1 solaris sunos "+
+                       "} instead.",
+               "WARN: fname:2: \"8087\" is not valid for the hardware architecture part of EMUL_PLATFORM. "+
+                       "Use one of "+
+                       "{ aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex dreamcast "+
+                       "earm earmeb earmhf earmhfeb earmv4 earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf "+
+                       "earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 "+
+                       "i386 i586 i686 ia64 m68000 m68k m88k mips mips64 mips64eb mips64el mipseb mipsel mipsn32 "+
+                       "mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 "+
+                       "} instead.",
                "WARN: fname:3: \"${LINUX}\" is not a valid emulation platform.")
 }
 
 func (s *Suite) Test_VartypeCheck_Enum(c *check.C) {
-       s.Init(c)
-       runVartypeMatchChecks("JDK", enum("jdk1 jdk2 jdk4").checker,
+       t := s.Init(c)
+
+       runVartypeMatchChecks(t, "JDK", enum("jdk1 jdk2 jdk4").checker,
                "*",
                "jdk*",
                "sun-jdk*",
                "${JDKNAME}")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:3: The pattern \"sun-jdk*\" cannot match any of { jdk1 jdk2 jdk4 } for JDK.")
 }
 
 func (s *Suite) Test_VartypeCheck_FetchURL(c *check.C) {
-       s.Init(c)
-       s.RegisterMasterSite("MASTER_SITE_GNU", "http://ftp.gnu.org/pub/gnu/";)
-       s.RegisterMasterSite("MASTER_SITE_GITHUB", "https://github.com/";)
+       t := s.Init(c)
 
-       runVartypeChecks("MASTER_SITES", opAssign, (*VartypeCheck).FetchURL,
+       t.SetupMasterSite("MASTER_SITE_GNU", "http://ftp.gnu.org/pub/gnu/";)
+       t.SetupMasterSite("MASTER_SITE_GITHUB", "https://github.com/";)
+
+       runVartypeChecks(t, "MASTER_SITES", opAssign, (*VartypeCheck).FetchURL,
                "https://github.com/example/project/";,
                "http://ftp.gnu.org/pub/gnu/bison";, // Missing a slash at the end
                "${MASTER_SITE_GNU:=bison}",
                "${MASTER_SITE_INVALID:=subdir/}")
 
-       s.CheckOutputLines(
-               "WARN: fname:1: Please use ${MASTER_SITE_GITHUB:=example/} instead of \"https://github.com/example/project/\"; and run \""+confMake+" help topic=github\" for further tips.",
+       t.CheckOutputLines(
+               "WARN: fname:1: Please use ${MASTER_SITE_GITHUB:=example/} "+
+                       "instead of \"https://github.com/example/project/\"; "+
+                       "and run \""+confMake+" help topic=github\" for further tips.",
                "WARN: fname:2: Please use ${MASTER_SITE_GNU:=bison} instead of \"http://ftp.gnu.org/pub/gnu/bison\".";,
                "ERROR: fname:3: The subdirectory in MASTER_SITE_GNU must end with a slash.",
                "ERROR: fname:4: The site MASTER_SITE_INVALID does not exist.")
 
        // PR 46570, keyword gimp-fix-ca
-       runVartypeChecks("MASTER_SITES", opAssign, (*VartypeCheck).FetchURL,
+       runVartypeChecks(t, "MASTER_SITES", opAssign, (*VartypeCheck).FetchURL,
                "https://example.org/download.cgi?fname=fname&sha1=12341234";)
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 
-       runVartypeChecks("MASTER_SITES", opAssign, (*VartypeCheck).FetchURL,
+       runVartypeChecks(t, "MASTER_SITES", opAssign, (*VartypeCheck).FetchURL,
                "http://example.org/distfiles/";,
                "http://example.org/download?fname=distfile;version=1.0";,
                "http://example.org/download?fname=<distfile>;version=<version>")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:3: \"http://example.org/download?fname=<distfile>;version=<version>\" is not a valid URL.")
 }
 
 func (s *Suite) Test_VartypeCheck_Filename(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("FNAME", opAssign, (*VartypeCheck).Filename,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "FNAME", opAssign, (*VartypeCheck).Filename,
                "Filename with spaces.docx",
                "OS/2-manual.txt")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: \"Filename with spaces.docx\" is not a valid filename.",
                "WARN: fname:2: A filename should not contain a slash.")
 }
 
 func (s *Suite) Test_VartypeCheck_LdFlag(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("LDFLAGS", opAssignAppend, (*VartypeCheck).LdFlag,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "LDFLAGS", opAssignAppend, (*VartypeCheck).LdFlag,
                "-lc",
                "-L/usr/lib64",
                "`pkg-config pidgin --ldflags`",
                "-unknown")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:4: Unknown linker flag \"-unknown\".")
 }
 
 func (s *Suite) Test_VartypeCheck_License(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("LICENSE", opAssign, (*VartypeCheck).License,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "LICENSE", opAssign, (*VartypeCheck).License,
                "gnu-gpl-v2",
                "AND mit")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: License file /licenses/gnu-gpl-v2 does not exist.",
                "ERROR: fname:2: Parse error for license condition \"AND mit\".")
 
-       runVartypeChecks("LICENSE", opAssignAppend, (*VartypeCheck).License,
+       runVartypeChecks(t, "LICENSE", opAssignAppend, (*VartypeCheck).License,
                "gnu-gpl-v2",
                "AND mit")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: fname:1: Parse error for appended license condition \"gnu-gpl-v2\".",
                "WARN: fname:2: License file /licenses/mit does not exist.")
 }
 
 func (s *Suite) Test_VartypeCheck_MachineGnuPlatform(c *check.C) {
-       s.Init(c)
-       runVartypeMatchChecks("MACHINE_GNU_PLATFORM", (*VartypeCheck).MachineGnuPlatform,
+       t := s.Init(c)
+
+       runVartypeMatchChecks(t, "MACHINE_GNU_PLATFORM", (*VartypeCheck).MachineGnuPlatform,
                "x86_64-pc-cygwin",
                "Cygwin-*-amd64")
 
-       s.CheckOutputLines(
-               "WARN: fname:2: The pattern \"Cygwin\" cannot match any of { aarch64 aarch64_be alpha amd64 arc arm armeb armv4 armv4eb armv6 armv6eb armv7 armv7eb cobalt convex dreamcast hpcmips 
hpcsh hppa hppa64 i386 i486 ia64 m5407 m68010 m68k m88k mips mips64 mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh shle sparc sparc64 vax x86_64 } for the 
hardware architecture part of MACHINE_GNU_PLATFORM.",
-               "WARN: fname:2: The pattern \"amd64\" cannot match any of { bitrig bsdos cygwin darwin dragonfly freebsd haiku hpux interix irix linux mirbsd netbsd openbsd osf1 solaris sunos } for 
the operating system part of MACHINE_GNU_PLATFORM.")
+       t.CheckOutputLines(
+               "WARN: fname:2: The pattern \"Cygwin\" cannot match any of "+
+                       "{ aarch64 aarch64_be alpha amd64 arc arm armeb armv4 armv4eb armv6 armv6eb armv7 armv7eb "+
+                       "cobalt convex dreamcast hpcmips hpcsh hppa hppa64 i386 i486 ia64 m5407 m68010 m68k m88k "+
+                       "mips mips64 mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 "+
+                       "rs6000 s390 sh shle sparc sparc64 vax x86_64 "+
+                       "} for the hardware architecture part of MACHINE_GNU_PLATFORM.",
+               "WARN: fname:2: The pattern \"amd64\" cannot match any of "+
+                       "{ bitrig bsdos cygwin darwin dragonfly freebsd haiku hpux interix irix linux mirbsd "+
+                       "netbsd openbsd osf1 solaris sunos } "+
+                       "for the operating system part of MACHINE_GNU_PLATFORM.")
 }
 
 func (s *Suite) Test_VartypeCheck_MailAddress(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("MAINTAINER", opAssign, (*VartypeCheck).MailAddress,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "MAINTAINER", opAssign, (*VartypeCheck).MailAddress,
                "pkgsrc-users%netbsd.org@localhost")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: Please write \"NetBSD.org\" instead of \"netbsd.org\".")
 }
 
 func (s *Suite) Test_VartypeCheck_Message(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("SUBST_MESSAGE.id", opAssign, (*VartypeCheck).Message,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "SUBST_MESSAGE.id", opAssign, (*VartypeCheck).Message,
                "\"Correct paths\"",
                "Correct paths")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: SUBST_MESSAGE.id should not be quoted.")
 }
 
 func (s *Suite) Test_VartypeCheck_Option(c *check.C) {
-       s.Init(c)
+       t := s.Init(c)
+
        G.globalData.PkgOptions = map[string]string{
                "documented":   "Option description",
                "undocumented": "",
        }
 
-       runVartypeChecks("PKG_OPTIONS.pkgbase", opAssign, (*VartypeCheck).Option,
+       runVartypeChecks(t, "PKG_OPTIONS.pkgbase", opAssign, (*VartypeCheck).Option,
                "documented",
                "undocumented",
                "unknown")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:3: Unknown option \"unknown\".")
 }
 
 func (s *Suite) Test_VartypeCheck_Pathlist(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("PATH", opAssign, (*VartypeCheck).Pathlist,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "PATH", opAssign, (*VartypeCheck).Pathlist,
                "/usr/bin:/usr/sbin:.:${LOCALBASE}/bin")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: All components of PATH (in this case \".\") should be absolute paths.")
 }
 
 func (s *Suite) Test_VartypeCheck_Perms(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("CONF_FILES_PERMS", opAssignAppend, (*VartypeCheck).Perms,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "CONF_FILES_PERMS", opAssignAppend, (*VartypeCheck).Perms,
                "root",
                "${ROOT_USER}",
                "ROOT_USER",
                "${REAL_ROOT_USER}")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: fname:2: ROOT_USER must not be used in permission definitions. Use REAL_ROOT_USER instead.")
 }
 
 func (s *Suite) Test_VartypeCheck_PkgOptionsVar(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("PKG_OPTIONS_VAR.screen", opAssign, (*VartypeCheck).PkgOptionsVar,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "PKG_OPTIONS_VAR.screen", opAssign, (*VartypeCheck).PkgOptionsVar,
                "PKG_OPTIONS.${PKGBASE}",
                "PKG_OPTIONS.anypkgbase")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "ERROR: fname:1: PKGBASE must not be used in PKG_OPTIONS_VAR.")
 }
 
 func (s *Suite) Test_VartypeCheck_PkgRevision(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("PKGREVISION", opAssign, (*VartypeCheck).PkgRevision,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "PKGREVISION", opAssign, (*VartypeCheck).PkgRevision,
                "3a")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: PKGREVISION must be a positive integer number.",
                "ERROR: fname:1: PKGREVISION only makes sense directly in the package Makefile.")
 
-       runVartypeChecksFname("Makefile", "PKGREVISION", opAssign, (*VartypeCheck).PkgRevision,
+       runVartypeChecksFname(t, "Makefile", "PKGREVISION", opAssign, (*VartypeCheck).PkgRevision,
                "3")
 
-       s.CheckOutputEmpty()
+       t.CheckOutputEmpty()
 }
 
 func (s *Suite) Test_VartypeCheck_MachinePlatformPattern(c *check.C) {
-       s.Init(c)
-       runVartypeMatchChecks("ONLY_FOR_PLATFORM", (*VartypeCheck).MachinePlatformPattern,
+       t := s.Init(c)
+
+       runVartypeMatchChecks(t, "ONLY_FOR_PLATFORM", (*VartypeCheck).MachinePlatformPattern,
                "linux-i386",
                "nextbsd-5.0-8087",
                "netbsd-7.0-l*",
@@ -393,168 +444,197 @@ func (s *Suite) Test_VartypeCheck_Machin
                "FreeBSD-*",
                "${LINUX}")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: \"linux-i386\" is not a valid platform pattern.",
-               "WARN: fname:2: The pattern \"nextbsd\" cannot match any of { AIX BSDOS Bitrig Cygwin Darwin DragonFly FreeBSD FreeMiNT GNUkFreeBSD HPUX Haiku IRIX Interix Linux Minix MirBSD NetBSD 
OSF1 OpenBSD QNX SCO_SV SunOS UnixWare } for the operating system part of ONLY_FOR_PLATFORM.",
-               "WARN: fname:2: The pattern \"8087\" cannot match any of { aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex dreamcast earm earmeb earmhf earmhfeb earmv4 
earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 m68000 m68k m88k mips mips64 mips64eb mips64el 
mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } for the hardware architecture part of ONLY_FOR_PLATFORM.",
-               "WARN: fname:3: The pattern \"netbsd\" cannot match any of { AIX BSDOS Bitrig Cygwin Darwin DragonFly FreeBSD FreeMiNT GNUkFreeBSD HPUX Haiku IRIX Interix Linux Minix MirBSD NetBSD 
OSF1 OpenBSD QNX SCO_SV SunOS UnixWare } for the operating system part of ONLY_FOR_PLATFORM.",
-               "WARN: fname:3: The pattern \"l*\" cannot match any of { aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex dreamcast earm earmeb earmhf earmhfeb earmv4 earmv4eb 
earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 m68000 m68k m88k mips mips64 mips64eb mips64el mipseb 
mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } for the hardware architecture part of ONLY_FOR_PLATFORM.",
+               "WARN: fname:2: The pattern \"nextbsd\" cannot match any of "+
+                       "{ AIX BSDOS Bitrig Cygwin Darwin DragonFly FreeBSD FreeMiNT GNUkFreeBSD HPUX Haiku "+
+                       "IRIX Interix Linux Minix MirBSD NetBSD OSF1 OpenBSD QNX SCO_SV SunOS UnixWare "+
+                       "} for the operating system part of ONLY_FOR_PLATFORM.",
+               "WARN: fname:2: The pattern \"8087\" cannot match any of "+
+                       "{ aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex dreamcast "+
+                       "earm earmeb earmhf earmhfeb earmv4 earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf "+
+                       "earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 "+
+                       "i386 i586 i686 ia64 m68000 m68k m88k mips mips64 mips64eb mips64el mipseb mipsel mipsn32 "+
+                       "mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 "+
+                       "} for the hardware architecture part of ONLY_FOR_PLATFORM.",
+               "WARN: fname:3: The pattern \"netbsd\" cannot match any of "+
+                       "{ AIX BSDOS Bitrig Cygwin Darwin DragonFly FreeBSD FreeMiNT GNUkFreeBSD HPUX Haiku "+
+                       "IRIX Interix Linux Minix MirBSD NetBSD OSF1 OpenBSD QNX SCO_SV SunOS UnixWare "+
+                       "} for the operating system part of ONLY_FOR_PLATFORM.",
+               "WARN: fname:3: The pattern \"l*\" cannot match any of "+
+                       "{ aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex dreamcast "+
+                       "earm earmeb earmhf earmhfeb earmv4 earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf "+
+                       "earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 "+
+                       "i386 i586 i686 ia64 m68000 m68k m88k mips mips64 mips64eb mips64el mipseb mipsel mipsn32 "+
+                       "mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 "+
+                       "} for the hardware architecture part of ONLY_FOR_PLATFORM.",
                "WARN: fname:5: \"FreeBSD*\" is not a valid platform pattern.")
 }
 
 func (s *Suite) Test_VartypeCheck_PythonDependency(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("PYTHON_VERSIONED_DEPENDENCIES", opAssign, (*VartypeCheck).PythonDependency,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "PYTHON_VERSIONED_DEPENDENCIES", opAssign, (*VartypeCheck).PythonDependency,
                "cairo",
                "${PYDEP}",
                "cairo,X")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:2: Python dependencies should not contain variables.",
                "WARN: fname:3: Invalid Python dependency \"cairo,X\".")
 }
 
 func (s *Suite) Test_VartypeCheck_Restricted(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("NO_BIN_ON_CDROM", opAssign, (*VartypeCheck).Restricted,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "NO_BIN_ON_CDROM", opAssign, (*VartypeCheck).Restricted,
                "May only be distributed free of charge")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: The only valid value for NO_BIN_ON_CDROM is ${RESTRICTED}.")
 }
 
 func (s *Suite) Test_VartypeCheck_SedCommands(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("SUBST_SED.dummy", opAssign, (*VartypeCheck).SedCommands,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "SUBST_SED.dummy", opAssign, (*VartypeCheck).SedCommands,
                "s,@COMPILER@,gcc,g",
                "-e s,a,b, -e a,b,c,",
                "-e \"s,#,comment ,\"",
                "-e \"s,\\#,comment ,\"")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "NOTE: fname:1: Please always use \"-e\" in sed commands, even if there is only one substitution.",
                "NOTE: fname:2: Each sed command should appear in an assignment of its own.",
                "WARN: fname:3: The # character starts a comment.")
 }
 
 func (s *Suite) Test_VartypeCheck_ShellCommands(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("GENERATE_PLIST", opAssign, (*VartypeCheck).ShellCommands,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "GENERATE_PLIST", opAssign, (*VartypeCheck).ShellCommands,
                "echo bin/program",
                "echo bin/program;")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: This shell command list should end with a semicolon.")
 }
 
 func (s *Suite) Test_VartypeCheck_Stage(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("SUBST_STAGE.dummy", opAssign, (*VartypeCheck).Stage,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "SUBST_STAGE.dummy", opAssign, (*VartypeCheck).Stage,
                "post-patch",
                "post-modern",
                "pre-test")
 
-       s.CheckOutputLines(
-               "WARN: fname:2: Invalid stage name \"post-modern\". Use one of {pre,do,post}-{extract,patch,configure,build,test,install}.")
+       t.CheckOutputLines(
+               "WARN: fname:2: Invalid stage name \"post-modern\". " +
+                       "Use one of {pre,do,post}-{extract,patch,configure,build,test,install}.")
 }
 
 func (s *Suite) Test_VartypeCheck_VariableName(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("BUILD_DEFS", opAssign, (*VartypeCheck).VariableName,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "BUILD_DEFS", opAssign, (*VartypeCheck).VariableName,
                "VARBASE",
                "VarBase",
                "PKG_OPTIONS_VAR.pkgbase",
                "${INDIRECT}")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:2: \"VarBase\" is not a valid variable name.")
 }
 
 func (s *Suite) Test_VartypeCheck_Version(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("PERL5_REQD", opAssignAppend, (*VartypeCheck).Version,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "PERL5_REQD", opAssignAppend, (*VartypeCheck).Version,
                "0",
                "1.2.3.4.5.6",
                "4.1nb17",
                "4.1-SNAPSHOT",
                "4pre7")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:4: Invalid version number \"4.1-SNAPSHOT\".")
 }
 
 func (s *Suite) Test_VartypeCheck_Yes(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("APACHE_MODULE", opAssign, (*VartypeCheck).Yes,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "APACHE_MODULE", opAssign, (*VartypeCheck).Yes,
                "yes",
                "no",
                "${YESVAR}")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:2: APACHE_MODULE should be set to YES or yes.",
                "WARN: fname:3: APACHE_MODULE should be set to YES or yes.")
 
-       runVartypeMatchChecks("PKG_DEVELOPER", (*VartypeCheck).Yes,
+       runVartypeMatchChecks(t, "PKG_DEVELOPER", (*VartypeCheck).Yes,
                "yes",
                "no",
                "${YESVAR}")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:1: PKG_DEVELOPER should only be used in a \".if defined(...)\" conditional.",
                "WARN: fname:2: PKG_DEVELOPER should only be used in a \".if defined(...)\" conditional.",
                "WARN: fname:3: PKG_DEVELOPER should only be used in a \".if defined(...)\" conditional.")
 }
 
 func (s *Suite) Test_VartypeCheck_YesNo(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("GNU_CONFIGURE", opAssign, (*VartypeCheck).YesNo,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "GNU_CONFIGURE", opAssign, (*VartypeCheck).YesNo,
                "yes",
                "no",
                "ja",
                "${YESVAR}")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:3: GNU_CONFIGURE should be set to YES, yes, NO, or no.",
                "WARN: fname:4: GNU_CONFIGURE should be set to YES, yes, NO, or no.")
 }
 
 func (s *Suite) Test_VartypeCheck_YesNoIndirectly(c *check.C) {
-       s.Init(c)
-       runVartypeChecks("GNU_CONFIGURE", opAssign, (*VartypeCheck).YesNoIndirectly,
+       t := s.Init(c)
+
+       runVartypeChecks(t, "GNU_CONFIGURE", opAssign, (*VartypeCheck).YesNoIndirectly,
                "yes",
                "no",
                "ja",
                "${YESVAR}")
 
-       s.CheckOutputLines(
+       t.CheckOutputLines(
                "WARN: fname:3: GNU_CONFIGURE should be set to YES, yes, NO, or no.")
 }
 
-func runVartypeChecks(varname string, op MkOperator, checker func(*VartypeCheck), values ...string) {
+func runVartypeChecks(t *Tester, varname string, op MkOperator, checker func(*VartypeCheck), values ...string) {
        if !contains(op.String(), "=") {
                panic("runVartypeChecks needs an assignment operator")
        }
        for i, value := range values {
-               mkline := T.NewMkLine("fname", i+1, varname+op.String()+value)
+               mkline := t.NewMkLine("fname", i+1, varname+op.String()+value)
                valueNovar := mkline.WithoutMakeVariables(mkline.Value())
                vc := &VartypeCheck{mkline, mkline.Line, mkline.Varname(), mkline.Op(), mkline.Value(), valueNovar, "", false}
                checker(vc)
        }
 }
 
-func runVartypeMatchChecks(varname string, checker func(*VartypeCheck), values ...string) {
+func runVartypeMatchChecks(t *Tester, varname string, checker func(*VartypeCheck), values ...string) {
        for i, value := range values {
                text := fmt.Sprintf(".if ${%s:M%s} == \"\"", varname, value)
-               mkline := T.NewMkLine("fname", i+1, text)
+               mkline := t.NewMkLine("fname", i+1, text)
                valueNovar := mkline.WithoutMakeVariables(value)
                vc := &VartypeCheck{mkline, mkline.Line, varname, opUseMatch, value, valueNovar, "", false}
                checker(vc)
        }
 }
 
-func runVartypeChecksFname(fname, varname string, op MkOperator, checker func(*VartypeCheck), values ...string) {
+func runVartypeChecksFname(t *Tester, fname, varname string, op MkOperator, checker func(*VartypeCheck), values ...string) {
        for i, value := range values {
-               mkline := T.NewMkLine(fname, i+1, varname+op.String()+value)
+               mkline := t.NewMkLine(fname, i+1, varname+op.String()+value)
                valueNovar := mkline.WithoutMakeVariables(value)
                vc := &VartypeCheck{mkline, mkline.Line, varname, op, value, valueNovar, "", false}
                checker(vc)

Index: pkgsrc/pkgtools/pkglint/files/getopt/getopt.go
diff -u pkgsrc/pkgtools/pkglint/files/getopt/getopt.go:1.3 pkgsrc/pkgtools/pkglint/files/getopt/getopt.go:1.4
--- pkgsrc/pkgtools/pkglint/files/getopt/getopt.go:1.3  Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/getopt/getopt.go      Sat Jan 27 18:50:37 2018
@@ -143,7 +143,7 @@ optchar:
                                                *data = append(*data, argarg)
                                                return 0, nil
                                        } else if i+1 < len(args) {
-                                               *data = append(*data, argarg)
+                                               *data = append(*data, args[i+1])
                                                return 1, nil
                                        } else {
                                                return 0, optErr("option requires an argument: -" + string([]rune{optchar}))
Index: pkgsrc/pkgtools/pkglint/files/getopt/getopt_test.go
diff -u pkgsrc/pkgtools/pkglint/files/getopt/getopt_test.go:1.3 pkgsrc/pkgtools/pkglint/files/getopt/getopt_test.go:1.4
--- pkgsrc/pkgtools/pkglint/files/getopt/getopt_test.go:1.3     Sat Jan 13 23:56:14 2018
+++ pkgsrc/pkgtools/pkglint/files/getopt/getopt_test.go Sat Jan 27 18:50:37 2018
@@ -116,16 +116,18 @@ func (s *Suite) Test_Options_Parse_strin
 
        args, err := opts.Parse([]string{"progname",
                "-viincluded1",
-               "--include=included2",
-               "--include", "included3",
+               "-i", "included2",
+               "--include=included3",
+               "--include", "included4",
                "-eexcluded1",
-               "--exclude=excluded2",
-               "--exclude", "excluded3"})
+               "-e", "excluded2",
+               "--exclude=excluded3",
+               "--exclude", "excluded4"})
 
        c.Check(args, check.IsNil)
        c.Check(err, check.IsNil)
-       c.Check(includes, check.DeepEquals, []string{"included1", "included2", "included3"})
-       c.Check(excludes, check.DeepEquals, []string{"excluded1", "excluded2", "excluded3"})
+       c.Check(includes, check.DeepEquals, []string{"included1", "included2", "included3", "included4"})
+       c.Check(excludes, check.DeepEquals, []string{"excluded1", "excluded2", "excluded3", "excluded4"})
 
        args, err = opts.Parse([]string{"progname", "-i"})
 

Added files:

Index: pkgsrc/pkgtools/pkglint/files/mklines_varalign_test.go
diff -u /dev/null pkgsrc/pkgtools/pkglint/files/mklines_varalign_test.go:1.1
--- /dev/null   Sat Jan 27 18:50:37 2018
+++ pkgsrc/pkgtools/pkglint/files/mklines_varalign_test.go      Sat Jan 27 18:50:36 2018
@@ -0,0 +1,872 @@
+package main
+
+import "gopkg.in/check.v1"
+
+// VaralignTester reduces the amount of test code for aligning variable
+// assignments in Makefiles.
+//
+// The most interesting breakpoint for looking at these tests is
+// VaralignBlock.optimalWidth.
+type VaralignTester struct {
+       suite       *Suite
+       tester      *Tester
+       input       []string // The actual input lines
+       diagnostics []string // The expected diagnostics in default mode
+       autofixes   []string // The expected diagnostics in --autofix mode
+       fixed       []string // The expected fixed lines, with spaces instead of tabs
+       source      bool
+}
+
+func NewVaralignTester(s *Suite, c *check.C) *VaralignTester {
+       t := s.Init(c)
+
+       return &VaralignTester{suite: s, tester: t}
+}
+
+// Input remembers the input lines that are checked and possibly realigned.
+func (vt *VaralignTester) Input(lines ...string) { vt.input = lines }
+
+// Diagnostics remembers the expected diagnostics.
+func (vt *VaralignTester) Diagnostics(diagnostics ...string) { vt.diagnostics = diagnostics }
+
+// Autofixes remembers the expected diagnostics when pkglint is
+// run with the --autofix option.
+func (vt *VaralignTester) Autofixes(autofixes ...string) { vt.autofixes = autofixes }
+
+// Fixed remembers the expected fixed lines. To make the layout changes
+// clearly visible, tabs are replaced with spaces in these expected lines.
+// The fixed lines that have been written to the file are still using tabs.
+func (vt *VaralignTester) Fixed(lines ...string) { vt.fixed = lines }
+
+// Run is called after setting up the data and runs the varalign checks twice.
+// Once for getting the diagnostics and once for automatically fixing them.
+func (vt *VaralignTester) Run() {
+       vt.runDefault()
+       vt.runAutofix()
+}
+
+func (vt *VaralignTester) runDefault() {
+       cmdline := []string{"-Wall"}
+       if vt.source {
+               cmdline = append(cmdline, "--source")
+       }
+       vt.tester.SetupCommandLine(cmdline...)
+
+       lines := vt.tester.SetupFileLinesContinuation("Makefile", vt.input...)
+       mklines := NewMkLines(lines)
+
+       varalign := VaralignBlock{}
+       for _, mkline := range mklines.mklines {
+               varalign.Check(mkline)
+       }
+       varalign.Finish()
+
+       vt.tester.CheckOutputLines(vt.diagnostics...)
+}
+
+func (vt *VaralignTester) runAutofix() {
+       cmdline := []string{"-Wall", "--autofix"}
+       if vt.source {
+               cmdline = append(cmdline, "--source")
+       }
+       vt.tester.SetupCommandLine(cmdline...)
+
+       lines := vt.tester.SetupFileLinesContinuation("Makefile", vt.input...)
+
+       mklines := NewMkLines(lines)
+
+       var varalign VaralignBlock
+       for _, mkline := range mklines.mklines {
+               varalign.Check(mkline)
+       }
+       varalign.Finish()
+
+       vt.tester.CheckOutputLines(vt.autofixes...)
+
+       SaveAutofixChanges(mklines.lines)
+       vt.tester.CheckFileLinesDetab("Makefile", vt.fixed...)
+}
+
+// Generally, the value in variable assignments is aligned
+// at the next tab.
+func (s *Suite) Test_Varalign__one_var_tab(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "VAR=\tone tab")
+       vt.Diagnostics()
+       vt.Autofixes()
+       vt.Fixed(
+               "VAR=    one tab")
+       vt.Run()
+}
+
+// Having more tabs than necessary is allowed. This can be for aesthetic
+// reasons to align this paragraph with the others in the same file.
+func (s *Suite) Test_Varalign__one_var_tabs(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "VAR=\t\t\tseveral tabs")
+       vt.Diagnostics()
+       vt.Autofixes()
+       vt.Fixed(
+               "VAR=                    several tabs")
+       vt.Run()
+}
+
+// Indentations with a single space are only allowed in some very few
+// places, such as continuation lines or very long variable names.
+// In a single paragraph of its own, indentation with a single space
+// doesn't make sense, therefore it is replaced with a tab.
+func (s *Suite) Test_Varalign__one_var_space(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "VAR= indented with one space")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: This variable value should be aligned with tabs, not spaces, to column 9.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \" \" with \"\\t\".")
+       vt.Fixed(
+               "VAR=    indented with one space")
+       vt.Run()
+}
+
+// While indentation with a single space is allowed in a few cases,
+// indentation with several spaces is never allowed and is replaced
+// with tabs.
+func (s *Suite) Test_Varalign__one_var_spaces(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "VAR=   several spaces")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: This variable value should be aligned with tabs, not spaces, to column 9.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \"   \" with \"\\t\".")
+       vt.Fixed(
+               "VAR=    several spaces")
+       vt.Run()
+}
+
+// Inconsistently aligned lines for variables of the same length are
+// replaced with tabs, so that they nicely align.
+func (s *Suite) Test_Varalign__two_vars__spaces(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "VAR= indented with one space",
+               "VAR=  indented with two spaces")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: This variable value should be aligned with tabs, not spaces, to column 9.",
+               "NOTE: ~/Makefile:2: This variable value should be aligned with tabs, not spaces, to column 9.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \" \" with \"\\t\".",
+               "AUTOFIX: ~/Makefile:2: Replacing \"  \" with \"\\t\".")
+       vt.Fixed(
+               "VAR=    indented with one space",
+               "VAR=    indented with two spaces")
+       vt.Run()
+}
+
+// All variables in a block are aligned to the same depth.
+func (s *Suite) Test_Varalign__several_vars__spaces(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "GRP_A= value",
+               "GRP_AA= value",
+               "GRP_AAA= value",
+               "GRP_AAAA= value")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: This variable value should be aligned with tabs, not spaces, to column 17.",
+               "NOTE: ~/Makefile:2: This variable value should be aligned with tabs, not spaces, to column 17.",
+               "NOTE: ~/Makefile:3: This variable value should be aligned with tabs, not spaces, to column 17.",
+               "NOTE: ~/Makefile:4: This variable value should be aligned with tabs, not spaces, to column 17.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \" \" with \"\\t\\t\".",
+               "AUTOFIX: ~/Makefile:2: Replacing \" \" with \"\\t\\t\".",
+               "AUTOFIX: ~/Makefile:3: Replacing \" \" with \"\\t\".",
+               "AUTOFIX: ~/Makefile:4: Replacing \" \" with \"\\t\".")
+       vt.Fixed(
+               "GRP_A=          value",
+               "GRP_AA=         value",
+               "GRP_AAA=        value",
+               "GRP_AAAA=       value")
+       vt.Run()
+}
+
+// Continuation lines may be indented with a single space.
+func (s *Suite) Test_Varalign__continuation(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "VAR= \\",
+               "\tvalue")
+       vt.Diagnostics()
+       vt.Autofixes()
+       vt.Fixed(
+               "VAR= \\",
+               "        value")
+       vt.Run()
+}
+
+// To align these two lines, the first line needs more more tab.
+// The second line is further to the right but doesn't count as
+// an outlier since it is not far enough.
+// Adding one more tab to the indentation is generally considered ok.
+func (s *Suite) Test_Varalign__short_tab__long_space(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "BLOCK=\tindented with tab",
+               "BLOCK_LONGVAR= indented with space")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: This variable value should be aligned to column 17.",
+               "NOTE: ~/Makefile:2: This variable value should be aligned with tabs, not spaces, to column 17.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \"\\t\" with \"\\t\\t\".",
+               "AUTOFIX: ~/Makefile:2: Replacing \" \" with \"\\t\".")
+       vt.Fixed(
+               "BLOCK=          indented with tab",
+               "BLOCK_LONGVAR=  indented with space")
+       vt.Run()
+}
+
+// When the indentation differs, the indentation is adjusted to the
+// minimum necessary.
+func (s *Suite) Test_Varalign__short_long__tab(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "BLOCK=\tshort",
+               "BLOCK_LONGVAR=\tlong")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: This variable value should be aligned to column 17.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \"\\t\" with \"\\t\\t\".")
+       vt.Fixed(
+               "BLOCK=          short",
+               "BLOCK_LONGVAR=  long")
+       vt.Run()
+}
+
+// For differing indentation, it doesn't matter whether the indentation
+// is done with tabs or with spaces. It is aligned to the minimum
+// necessary depth.
+func (s *Suite) Test_Varalign__space_and_tab(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "VAR=    space",
+               "VAR=\ttab ${VAR}")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: Variable values should be aligned with tabs, not spaces.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \"    \" with \"\\t\".")
+       vt.Fixed(
+               "VAR=    space",
+               "VAR=    tab ${VAR}")
+       vt.Run()
+}
+
+// There must always be a visible space between the assignment operator
+// and the value.
+func (s *Suite) Test_Varalign__no_space_at_all(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "PKG_FAIL_REASON+=\"Message\"")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: This variable value should be aligned to column 25.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \"\" with \"\\t\".")
+       vt.Fixed(
+               "PKG_FAIL_REASON+=       \"Message\"")
+       vt.Run()
+}
+
+// Continuation lines without any content on the first line may use
+// a space for variable value alignment.
+// They are ignored when calculating the preferred alignment depth.
+func (s *Suite) Test_Varalign__continuation_lines(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "DISTFILES+=\tvalue",
+               "DISTFILES+= \\", // The continuation backslash must be aligned.
+               "\t\t\tvalue",    // The value is already aligned.
+               "DISTFILES+=\t\t\tvalue",
+               "DISTFILES+= value",
+               "",
+               "DISTFILES= \\",
+               "value")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:2--3: This variable value should be aligned with tabs, not spaces, to column 17.",
+               "NOTE: ~/Makefile:2--3: This line should be aligned with \"\\t\\t\".",
+               "NOTE: ~/Makefile:4: This variable value should be aligned to column 17.",
+               "NOTE: ~/Makefile:5: This variable value should be aligned with tabs, not spaces, to column 17.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:2: Replacing \" \" with \"\\t\".",
+               "AUTOFIX: ~/Makefile:3: Replacing indentation \"\\t\\t\\t\" with \"\\t\\t\".",
+               "AUTOFIX: ~/Makefile:4: Replacing \"\\t\\t\\t\" with \"\\t\".",
+               "AUTOFIX: ~/Makefile:5: Replacing \" \" with \"\\t\".")
+       vt.Fixed(
+               "DISTFILES+=     value",
+               "DISTFILES+=     \\",
+               "                value",
+               "DISTFILES+=     value",
+               "DISTFILES+=     value",
+               "",
+               "DISTFILES= \\",
+               "value")
+       vt.Run()
+}
+
+// Ensures that a wrong warning introduced in ccb56a5 is not logged.
+func (s *Suite) Test_Varalign__aligned_continuation(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "USE_TOOLS+=\t[ awk \\",
+               "\t\tsed")
+       vt.Diagnostics()
+       vt.Autofixes()
+       vt.Fixed(
+               "USE_TOOLS+=     [ awk \\",
+               "                sed")
+       vt.Run()
+}
+
+// Shell commands are assumed to be already nicely indented.
+// This particular example is not, but pkglint cannot decide this as of
+// version 5.5.2.
+func (s *Suite) Test_Varalign__shell_command(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "USE_BUILTIN.Xfixes=\tyes",
+               "USE_BUILTIN.Xfixes!=\t\t\t\t\t\t\t\\",
+               "\tif ${PKG_ADMIN} pmatch ...; then\t\t\t\t\t\\",
+               "\t\t:; else :; fi")
+       vt.Diagnostics()
+       vt.Autofixes()
+       vt.Fixed(
+               "USE_BUILTIN.Xfixes=     yes",
+               "USE_BUILTIN.Xfixes!=                                                    \\",
+               "        if ${PKG_ADMIN} pmatch ...; then                                        \\",
+               "                :; else :; fi")
+       vt.Run()
+}
+
+// The most common pattern for laying out continuation lines is to have all
+// values in the continuation lines, one value per line, all indented to the
+// same depth.
+// The depth is either a single tab or aligns with the other variables in the
+// paragraph.
+func (s *Suite) Test_Varalign__continuation_value_starts_in_second_line(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "WRKSRC=\t${WRKDIR}",
+               "DISTFILES=\tdistfile-1.0.0.tar.gz",
+               "SITES.distfile-1.0.0.tar.gz= \\",
+               "\t\t\t${MASTER_SITES_SOURCEFORGE} \\",
+               "\t\t\t${MASTER_SITES_GITHUB}")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: This variable value should be aligned to column 17.",
+               "NOTE: ~/Makefile:3--5: This line should be aligned with \"\\t\\t\".")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \"\\t\" with \"\\t\\t\".",
+               "AUTOFIX: ~/Makefile:4: Replacing indentation \"\\t\\t\\t\" with \"\\t\\t\".",
+               "AUTOFIX: ~/Makefile:5: Replacing indentation \"\\t\\t\\t\" with \"\\t\\t\".")
+       vt.Fixed(
+               "WRKSRC=         ${WRKDIR}",
+               "DISTFILES=      distfile-1.0.0.tar.gz",
+               "SITES.distfile-1.0.0.tar.gz= \\",
+               "                ${MASTER_SITES_SOURCEFORGE} \\",
+               "                ${MASTER_SITES_GITHUB}")
+       vt.Run()
+}
+
+// Another common pattern is to write the first value in the first line and
+// subsequent values indented to the same depth as the value in the first
+// line.
+func (s *Suite) Test_Varalign__continuation_value_starts_in_first_line(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "WRKSRC=\t${WRKDIR}",
+               "DISTFILES=\tdistfile-1.0.0.tar.gz",
+               "SITES.distfile-1.0.0.tar.gz=\t${MASTER_SITES_SOURCEFORGE} \\",
+               "\t\t\t\t${MASTER_SITES_GITHUB}")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: This variable value should be aligned to column 17.",
+               "NOTE: ~/Makefile:3--4: This line should be aligned with \"\\t\\t\".")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \"\\t\" with \"\\t\\t\".",
+               "AUTOFIX: ~/Makefile:4: Replacing indentation \"\\t\\t\\t\\t\" with \"\\t\\t\".")
+       vt.Fixed(
+               "WRKSRC=         ${WRKDIR}",
+               "DISTFILES=      distfile-1.0.0.tar.gz",
+               "SITES.distfile-1.0.0.tar.gz=    ${MASTER_SITES_SOURCEFORGE} \\",
+               "                ${MASTER_SITES_GITHUB}")
+       vt.Run()
+}
+
+// Continued lines that have mixed indentation are probably on purpose.
+// Their minimum indentation should be aligned to the indentation of the
+// other lines. The lines that are indented further should keep their
+// relative indentation depth, no matter if that is done with spaces or
+// with tabs.
+func (s *Suite) Test_Varalign__continuation_mixed_indentation_in_second_line(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "WRKSRC=\t${WRKDIR}",
+               "DISTFILES=\tdistfile-1.0.0.tar.gz",
+               "AWK_PROGRAM+= \\",
+               "\t\t\t\t  /search/ { \\",
+               "\t\t\t\t    action(); \\",
+               "\t\t\t\t  }")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: This variable value should be aligned to column 17.",
+               "NOTE: ~/Makefile:3--6: This variable value should be aligned with tabs, not spaces, to column 17.",
+               "NOTE: ~/Makefile:3--6: This line should be aligned with \"\\t\\t\".")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \"\\t\" with \"\\t\\t\".",
+               "AUTOFIX: ~/Makefile:3: Replacing \" \" with \"\\t\".",
+               "AUTOFIX: ~/Makefile:4: Replacing indentation \"\\t\\t\\t\\t  \" with \"\\t\\t\".",
+               "AUTOFIX: ~/Makefile:5: Replacing indentation \"\\t\\t\\t\\t    \" with \"\\t\\t  \".",
+               "AUTOFIX: ~/Makefile:6: Replacing indentation \"\\t\\t\\t\\t  \" with \"\\t\\t\".")
+       vt.Fixed(
+               "WRKSRC=         ${WRKDIR}",
+               "DISTFILES=      distfile-1.0.0.tar.gz",
+               "AWK_PROGRAM+=   \\",
+               "                /search/ { \\",
+               "                  action(); \\",
+               "                }")
+       vt.Run()
+}
+
+// Continuation lines may also start their values in the first line.
+func (s *Suite) Test_Varalign__continuation_mixed_indentation_in_first_line(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "WRKSRC=\t${WRKDIR}",
+               "DISTFILES=\tdistfile-1.0.0.tar.gz",
+               "AWK_PROGRAM+=\t\t\t  /search/ { \\",
+               "\t\t\t\t    action(); \\",
+               "\t\t\t\t  }")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: This variable value should be aligned to column 17.",
+               "NOTE: ~/Makefile:3--5: This variable value should be aligned with tabs, not spaces, to column 17.",
+               "NOTE: ~/Makefile:3--5: This line should be aligned with \"\\t\\t\".")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \"\\t\" with \"\\t\\t\".",
+               "AUTOFIX: ~/Makefile:3: Replacing \"\\t\\t\\t  \" with \"\\t\".",
+               "AUTOFIX: ~/Makefile:4: Replacing indentation \"\\t\\t\\t\\t    \" with \"\\t\\t  \".",
+               "AUTOFIX: ~/Makefile:5: Replacing indentation \"\\t\\t\\t\\t  \" with \"\\t\\t\".")
+       vt.Fixed(
+               "WRKSRC=         ${WRKDIR}",
+               "DISTFILES=      distfile-1.0.0.tar.gz",
+               "AWK_PROGRAM+=   /search/ { \\",
+               "                  action(); \\",
+               "                }")
+       vt.Run()
+}
+
+// When there is an outlier, no matter whether indented using space or tab,
+// fix the whole block to use the indentation of the second-longest line.
+// Since all of the remaining lines have the same indentation (in this case,
+// there is only 1 line at all), that existing indentation is used instead of
+// the minimum necessary, which would only be a single tab.
+func (s *Suite) Test_Varalign__tab_outlier(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "DISTFILES=\t\tvery-very-very-very-long-distfile-name",
+               "SITES.very-very-very-very-long-distfile-name=\t${MASTER_SITE_LOCAL}")
+       vt.Diagnostics()
+       vt.Autofixes()
+       vt.Fixed(
+               "DISTFILES=              very-very-very-very-long-distfile-name",
+               "SITES.very-very-very-very-long-distfile-name=   ${MASTER_SITE_LOCAL}")
+       vt.Run()
+}
+
+// The SITES.* definition is indented less than the other lines,
+// therefore the whole paragraph will be realigned to that depth.
+func (s *Suite) Test_Varalign__multiline(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "DIST_SUBDIR=            asc",
+               "DISTFILES=              ${DISTNAME}${EXTRACT_SUFX} frontiers.mp3 \\",
+               "                        machine_wars.mp3 time_to_strike.mp3",
+               ".for file in frontiers.mp3 machine_wars.mp3 time_to_strike.mp3",
+               "SITES.${file}=  http://asc-hq.org/";,
+               ".endfor",
+               "WRKSRC=                 ${WRKDIR}/${PKGNAME_NOREV}")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: This variable value should be aligned with tabs, not spaces, to column 17.",
+               "NOTE: ~/Makefile:2--3: This variable value should be aligned with tabs, not spaces, to column 17.",
+               "NOTE: ~/Makefile:2--3: This line should be aligned with \"\\t\\t\".",
+               "NOTE: ~/Makefile:5: Variable values should be aligned with tabs, not spaces.",
+               "NOTE: ~/Makefile:7: This variable value should be aligned with tabs, not spaces, to column 17.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \"            \" with \"\\t\".",
+               "AUTOFIX: ~/Makefile:2: Replacing \"              \" with \"\\t\".",
+               "AUTOFIX: ~/Makefile:3: Replacing indentation \"                        \" with \"\\t\\t\".",
+               "AUTOFIX: ~/Makefile:5: Replacing \"  \" with \"\\t\".",
+               "AUTOFIX: ~/Makefile:7: Replacing \"                 \" with \"\\t\\t\".")
+       vt.Fixed(
+               "DIST_SUBDIR=    asc",
+               "DISTFILES=      ${DISTNAME}${EXTRACT_SUFX} frontiers.mp3 \\",
+               "                machine_wars.mp3 time_to_strike.mp3",
+               ".for file in frontiers.mp3 machine_wars.mp3 time_to_strike.mp3",
+               "SITES.${file}=  http://asc-hq.org/";,
+               ".endfor",
+               "WRKSRC=         ${WRKDIR}/${PKGNAME_NOREV}")
+       vt.Run()
+}
+
+// The CDROM variables align exactly at a tab position, therefore they must
+// be indented by at least one more space. Since that one space is not
+// enough to count as an outlier, everything is indented by one more tab.
+func (s *Suite) Test_Varalign__single_space(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "RESTRICTED=\tDo not sell, do not rent",
+               "NO_BIN_ON_CDROM= ${RESTRICTED}",
+               "NO_BIN_ON_FTP=\t${RESTRICTED}",
+               "NO_SRC_ON_CDROM= ${RESTRICTED}",
+               "NO_SRC_ON_FTP=\t${RESTRICTED}")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: This variable value should be aligned to column 25.",
+               "NOTE: ~/Makefile:2: This variable value should be aligned with tabs, not spaces, to column 25.",
+               "NOTE: ~/Makefile:3: This variable value should be aligned to column 25.",
+               "NOTE: ~/Makefile:4: This variable value should be aligned with tabs, not spaces, to column 25.",
+               "NOTE: ~/Makefile:5: This variable value should be aligned to column 25.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \"\\t\" with \"\\t\\t\".",
+               "AUTOFIX: ~/Makefile:2: Replacing \" \" with \"\\t\".",
+               "AUTOFIX: ~/Makefile:3: Replacing \"\\t\" with \"\\t\\t\".",
+               "AUTOFIX: ~/Makefile:4: Replacing \" \" with \"\\t\".",
+               "AUTOFIX: ~/Makefile:5: Replacing \"\\t\" with \"\\t\\t\".")
+       vt.Fixed(
+               "RESTRICTED=             Do not sell, do not rent",
+               "NO_BIN_ON_CDROM=        ${RESTRICTED}",
+               "NO_BIN_ON_FTP=          ${RESTRICTED}",
+               "NO_SRC_ON_CDROM=        ${RESTRICTED}",
+               "NO_SRC_ON_FTP=          ${RESTRICTED}")
+       vt.Run()
+}
+
+// These variables all look nicely aligned, but they use spaces instead
+// of tabs for alignment. The spaces are replaced with tabs, making the
+// indentation a little deeper.
+func (s *Suite) Test_Varalign__only_space(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "DISTFILES+= space",
+               "DISTFILES+= space",
+               "",
+               "REPLACE_PYTHON+= *.py",
+               "REPLACE_PYTHON+= lib/*.py",
+               "REPLACE_PYTHON+= src/*.py")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: This variable value should be aligned with tabs, not spaces, to column 17.",
+               "NOTE: ~/Makefile:2: This variable value should be aligned with tabs, not spaces, to column 17.",
+               "NOTE: ~/Makefile:4: This variable value should be aligned with tabs, not spaces, to column 25.",
+               "NOTE: ~/Makefile:5: This variable value should be aligned with tabs, not spaces, to column 25.",
+               "NOTE: ~/Makefile:6: This variable value should be aligned with tabs, not spaces, to column 25.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \" \" with \"\\t\".",
+               "AUTOFIX: ~/Makefile:2: Replacing \" \" with \"\\t\".",
+               "AUTOFIX: ~/Makefile:4: Replacing \" \" with \"\\t\".",
+               "AUTOFIX: ~/Makefile:5: Replacing \" \" with \"\\t\".",
+               "AUTOFIX: ~/Makefile:6: Replacing \" \" with \"\\t\".")
+       vt.Fixed(
+               "DISTFILES+=     space",
+               "DISTFILES+=     space",
+               "",
+               "REPLACE_PYTHON+=        *.py",
+               "REPLACE_PYTHON+=        lib/*.py",
+               "REPLACE_PYTHON+=        src/*.py")
+       vt.Run()
+}
+
+// The indentation is deeper than necessary, but all lines agree on
+// the same column. Therefore this indentation depth is kept.
+func (s *Suite) Test_Varalign__mixed_tabs_and_spaces_same_column(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "DISTFILES+=             space",
+               "DISTFILES+=\t\ttab")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: Variable values should be aligned with tabs, not spaces.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \"             \" with \"\\t\\t\".")
+       vt.Fixed(
+               "DISTFILES+=             space",
+               "DISTFILES+=             tab")
+       vt.Run()
+}
+
+// Both lines are indented to the same column. This is a very simple case.
+func (s *Suite) Test_Varalign__outlier_1(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "V= value",
+               "V=\tvalue")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: This variable value should be aligned with tabs, not spaces, to column 9.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \" \" with \"\\t\".")
+       vt.Fixed(
+               "V=      value",
+               "V=      value")
+       vt.Run()
+}
+
+// A single space that ends at the same depth as a tab is replaced with a
+// tab, for consistency.
+func (s *Suite) Test_Varalign__outlier_2(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "V.0008= value",
+               "V=\tvalue")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: Variable values should be aligned with tabs, not spaces.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \" \" with \"\\t\".")
+       vt.Fixed(
+               "V.0008= value",
+               "V=      value")
+       vt.Run()
+}
+
+// A short line that is indented with spaces is aligned to a longer line
+// that is indented with tabs. This is because space-indented lines are
+// only special when their indentation is much deeper than the tab-indented
+// ones.
+func (s *Suite) Test_Varalign__outlier_3(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "V.00009= value",
+               "V=\tvalue")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: This variable value should be aligned with tabs, not spaces, to column 17.",
+               "NOTE: ~/Makefile:2: This variable value should be aligned to column 17.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \" \" with \"\\t\".",
+               "AUTOFIX: ~/Makefile:2: Replacing \"\\t\" with \"\\t\\t\".")
+       vt.Fixed(
+               "V.00009=        value",
+               "V=              value")
+       vt.Run()
+}
+
+// This space-indented line doesn't count as an outlier yet because it
+// is only a single tab away. The limit is two tabs.
+func (s *Suite) Test_Varalign__outlier_4(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "V.000000000016= value",
+               "V=\tvalue")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: Variable values should be aligned with tabs, not spaces.",
+               "NOTE: ~/Makefile:2: This variable value should be aligned to column 17.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \" \" with \"\\t\".",
+               "AUTOFIX: ~/Makefile:2: Replacing \"\\t\" with \"\\t\\t\".")
+       vt.Fixed(
+               "V.000000000016= value",
+               "V=              value")
+       vt.Run()
+}
+
+// This space-indented line is an outlier since it is far enough from the
+// tab-indented line. The latter would require 2 tabs to align to the former.
+func (s *Suite) Test_Varalign__outlier_5(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "V.0000000000017= value",
+               "V=\tvalue")
+       vt.Diagnostics()
+       vt.Autofixes()
+       vt.Fixed(
+               "V.0000000000017= value",
+               "V=      value")
+       vt.Run()
+}
+
+// Short space-indented lines are expanded to the tab-depth.
+func (s *Suite) Test_Varalign__outlier_6(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "V= value",
+               "V.000010=\tvalue")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: This variable value should be aligned with tabs, not spaces, to column 17.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \" \" with \"\\t\\t\".")
+       vt.Fixed(
+               "V=              value",
+               "V.000010=       value")
+       vt.Run()
+}
+
+// The long line is not an outlier, but very close. One more space, and
+// it would count.
+func (s *Suite) Test_Varalign__outlier_10(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "V.0000000000000000023= value", // Adjust from 23 to 24 (+ 1 tab)
+               "V.000010=\tvalue")             // Adjust from 16 to 24 (+ 1 tab)
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: This variable value should be aligned with tabs, not spaces, to column 25.",
+               "NOTE: ~/Makefile:2: This variable value should be aligned to column 25.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \" \" with \"\\t\".",
+               "AUTOFIX: ~/Makefile:2: Replacing \"\\t\" with \"\\t\\t\".")
+       vt.Fixed(
+               "V.0000000000000000023=  value",
+               "V.000010=               value")
+       vt.Run()
+}
+
+func (s *Suite) Test_Varalign__outlier_11(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "V.00000000000000000024= value", // Keep at 24 (space to tab)
+               "V.000010=\tvalue")              // Adjust from 16 to 24 (+ 1 tab)
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: Variable values should be aligned with tabs, not spaces.",
+               "NOTE: ~/Makefile:2: This variable value should be aligned to column 25.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \" \" with \"\\t\".",
+               "AUTOFIX: ~/Makefile:2: Replacing \"\\t\" with \"\\t\\t\".")
+       vt.Fixed(
+               "V.00000000000000000024= value",
+               "V.000010=               value")
+       vt.Run()
+}
+
+func (s *Suite) Test_Varalign__outlier_12(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "V.000000000000000000025= value", // Keep at 25 (outlier)
+               "V.000010=\tvalue")               // Keep at 16 (would require + 2 tabs)
+       vt.Diagnostics()
+       vt.Autofixes()
+       vt.Fixed(
+               "V.000000000000000000025= value",
+               "V.000010=       value")
+       vt.Run()
+}
+
+// When the lines are indented inconsistently, the indentation is reduced
+// to the required minimum.
+func (s *Suite) Test_Varalign__outlier_14(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "V.00008=\t\tvalue",     // Adjust from 24 to 16 (removes 1 tab)
+               "V.00008=\t\t\t\tvalue") // Adjust from 40 to 16 (removes 3 tabs)
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:1: This variable value should be aligned to column 17.",
+               "NOTE: ~/Makefile:2: This variable value should be aligned to column 17.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:1: Replacing \"\\t\\t\" with \"\\t\".",
+               "AUTOFIX: ~/Makefile:2: Replacing \"\\t\\t\\t\\t\" with \"\\t\".")
+       vt.Fixed(
+               "V.00008=        value",
+               "V.00008=        value")
+       vt.Run()
+}
+
+// The INSTALLATION_DIRS line is so long that it is considered an outlier,
+// since compared to the DIST line, it is at least two tabs away.
+// Pkglint before 2018-26-01 suggested that it "should be aligned to column 9",
+// which is not possible since the variable name is already longer.
+func (s *Suite) Test_MkLines__variable_alignment__long_short(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "INSTALLATION_DIRS=\tbin",
+               "DIST=\t${WRKSRC}/dist")
+       vt.Diagnostics()
+       vt.Autofixes()
+       vt.Fixed(
+               "INSTALLATION_DIRS=      bin",
+               "DIST=   ${WRKSRC}/dist")
+       vt.Run()
+}
+
+// Before 2018-01-26, pkglint wanted to replace the tab in the outlier with
+// a space. After this change, the space-indented line would not look like an
+// outlier anymore because the other values are aligned very close to the
+// outlier value. To fix this case, the indentation of the other lines needs
+// to be adjusted to the minimum required.
+func (s *Suite) Test_Varalign__tabbed_outlier(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               ".if !empty(PKG_OPTIONS:Minspircd-sqloper)",
+               "INSPIRCD_STORAGE_DRIVER?=\tmysql",
+               "MODULES+=\t\tm_sqloper.cpp m_sqlutils.cpp",
+               "HEADERS+=\t\tm_sqlutils.h",
+               ".endif")
+       vt.Diagnostics()
+       vt.Autofixes()
+       vt.Fixed(
+               ".if !empty(PKG_OPTIONS:Minspircd-sqloper)",
+               "INSPIRCD_STORAGE_DRIVER?=       mysql",
+               "MODULES+=               m_sqloper.cpp m_sqlutils.cpp",
+               "HEADERS+=               m_sqlutils.h",
+               ".endif")
+       vt.Run()
+}
+
+// When all continuation lines are indented exactly one tab more than the
+// initial line, this is intentional.
+func (s *Suite) Test_Varalign__indented_continuation_line(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "CONF_FILES_PERMS=\tsource \\",
+               "\t\t\t\tdestination \\",
+               "\t\t\t\tuser group 0644")
+       vt.Diagnostics()
+       vt.Autofixes()
+       vt.Fixed(
+               "CONF_FILES_PERMS=       source \\",
+               "                                destination \\",
+               "                                user group 0644")
+       vt.Run()
+}
+
+func (s *Suite) Test_Varalign__indented_continuation_line_in_paragraph(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "SUBST_CLASSES+=\t\tfix",
+               "SUBST_STAGE.fix=\tpost-patch",
+               "SUBST_SED.fix= \\",
+               "\t-e 's,1,one,g' \\",
+               "\t-e 's,2,two,g' \\",
+               "\t-e 's,3,three,g'")
+       vt.Diagnostics(
+               "NOTE: ~/Makefile:3--6: This variable value should be aligned with tabs, not spaces, to column 25.")
+       vt.Autofixes(
+               "AUTOFIX: ~/Makefile:3: Replacing \" \" with \"\\t\\t\".")
+       vt.Fixed(
+               "SUBST_CLASSES+=         fix",
+               "SUBST_STAGE.fix=        post-patch",
+               "SUBST_SED.fix=          \\",
+               "        -e 's,1,one,g' \\",
+               "        -e 's,2,two,g' \\",
+               "        -e 's,3,three,g'")
+       vt.Run()
+}
+
+// Up to 2018-01-27, it could happen that some source code was logged
+// without a corresponding diagnostic. This was unintented and confusing.
+func (s *Suite) Test_Varalign__bla(c *check.C) {
+       vt := NewVaralignTester(s, c)
+       vt.Input(
+               "MESSAGE_SUBST+=\t\tRUBY_DISTNAME=${RUBY_DISTNAME}",
+               "PLIST_SUBST+=\t\tRUBY_SHLIBVER=${RUBY_SHLIBVER:Q} \\",
+               "\t\t\tRUBY_SHLIBMAJOR=${RUBY_SHLIBMAJOR:Q} \\",
+               "\t\t\tRUBY_NOSHLIBMAJOR=${RUBY_NOSHLIBMAJOR} \\",
+               "\t\t\tRUBY_NAME=${RUBY_NAME:Q}")
+       vt.Diagnostics()
+       vt.Autofixes()
+       vt.Fixed(
+               "MESSAGE_SUBST+=         RUBY_DISTNAME=${RUBY_DISTNAME}",
+               "PLIST_SUBST+=           RUBY_SHLIBVER=${RUBY_SHLIBVER:Q} \\",
+               "                        RUBY_SHLIBMAJOR=${RUBY_SHLIBMAJOR:Q} \\",
+               "                        RUBY_NOSHLIBMAJOR=${RUBY_NOSHLIBMAJOR} \\",
+               "                        RUBY_NAME=${RUBY_NAME:Q}")
+       vt.source = true
+       vt.Run()
+}



Home | Main Index | Thread Index | Old Index