f4f2d9ce42
Changes since 21.4.0: Running 'pkglint doc/CHANGES-2021' now warns about issues for this single file. Previously, it was necessary to specify '-Cglobal' as well, but then pkglint also warned about issues in all other CHANGES files. Pkglint no longer warns about the characters '!' and '@' in GO_MODULES_FILES, since these are legitimate. Fixes PR pkg/56595. Small cleanups in the pkglint testing infrastructure.
421 lines
11 KiB
Go
421 lines
11 KiB
Go
package pkglint
|
|
|
|
import "gopkg.in/check.v1"
|
|
|
|
func (s *Suite) Test_Scope__no_tracing(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
scope := NewScope()
|
|
scope.Define("VAR.param", t.NewMkLine("fname.mk", 3, "VAR.param=\tvalue"))
|
|
t.DisableTracing()
|
|
|
|
t.CheckEquals(scope.IsDefinedSimilar("VAR.param"), true)
|
|
t.CheckEquals(scope.IsDefinedSimilar("VAR.other"), true)
|
|
t.CheckEquals(scope.IsDefinedSimilar("OTHER"), false)
|
|
}
|
|
|
|
func (s *Suite) Test_Scope__commented_varassign(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
mkline := t.NewMkLine("mk/defaults/mk.conf", 3, "#VAR=default")
|
|
scope := NewScope()
|
|
scope.Define("VAR", mkline)
|
|
|
|
t.CheckEquals(scope.IsDefined("VAR"), false)
|
|
t.CheckNil(scope.FirstDefinition("VAR"))
|
|
t.CheckNil(scope.LastDefinition("VAR"))
|
|
|
|
t.CheckEquals(scope.Mentioned("VAR"), mkline)
|
|
t.CheckEquals(scope.Commented("VAR"), mkline)
|
|
|
|
value, found, indeterminate := scope.LastValueFound("VAR")
|
|
t.CheckEquals(value, "")
|
|
t.CheckEquals(found, false)
|
|
t.CheckEquals(indeterminate, false)
|
|
}
|
|
|
|
func (s *Suite) Test_NewScope(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
scope := NewScope()
|
|
|
|
t.CheckNil(scope.names)
|
|
t.CheckNotNil(scope.vs)
|
|
t.CheckLen(scope.vs, 0)
|
|
}
|
|
|
|
func (s *Suite) Test_Scope_varnames(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
scope := NewScope()
|
|
mkline := t.NewMkLine("filename.mk", 3, "DEFINED=\t${USED}")
|
|
|
|
t.CheckNil(scope.varnames())
|
|
|
|
scope.Define("DEFINED", mkline)
|
|
scope.Use("USED", mkline, VucRunTime)
|
|
|
|
t.CheckDeepEquals(scope.varnames(), []string{"DEFINED", "USED"})
|
|
scope.varnames()[0] = "modified" // just to demonstrate the caching
|
|
t.CheckDeepEquals(scope.varnames(), []string{"modified", "USED"})
|
|
}
|
|
|
|
func (s *Suite) Test_Scope_create(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
scope := NewScope()
|
|
|
|
v1 := scope.create("VAR")
|
|
v2 := scope.create("VAR")
|
|
|
|
t.CheckEquals(v1, v2)
|
|
}
|
|
|
|
func (s *Suite) Test_Scope_Define(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
scope := NewScope()
|
|
|
|
test := func(line string, found, indeterminate bool, value string) {
|
|
mkline := t.NewMkLine("file.mk", 123, line)
|
|
scope.Define("BUILD_DIRS", mkline)
|
|
|
|
actualValue, actualFound, actualIndeterminate := scope.LastValueFound("BUILD_DIRS")
|
|
|
|
t.CheckDeepEquals(
|
|
[]interface{}{actualFound, actualIndeterminate, actualValue},
|
|
[]interface{}{found, indeterminate, value})
|
|
t.CheckEquals(scope.vs["BUILD_DIRS"].value, value)
|
|
}
|
|
|
|
test("BUILD_DIRS?=\tdefault",
|
|
true, false, "default")
|
|
|
|
test(
|
|
"BUILD_DIRS=\tone two three",
|
|
true, false, "one two three")
|
|
|
|
test(
|
|
"BUILD_DIRS+=\tfour",
|
|
true, false, "one two three four")
|
|
|
|
// Later default assignments do not have an effect.
|
|
test("BUILD_DIRS?=\tdefault",
|
|
true, false, "one two three four")
|
|
|
|
test("BUILD_DIRS!=\techo dynamic",
|
|
true, true, "")
|
|
|
|
// The shell assignment above sets the variable to an indeterminate
|
|
// value, after which all further default assignments are ignored.
|
|
test("BUILD_DIRS?=\tdefault after shell assignment",
|
|
true, true, "")
|
|
}
|
|
|
|
func (s *Suite) Test_Scope_def(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
mkline := t.NewMkLine("filename.mk", 3, "VAR=\tvalue")
|
|
scope := NewScope()
|
|
|
|
scope.def("VAR.param", mkline)
|
|
|
|
t.CheckNil(scope.FirstDefinition("VAR"))
|
|
t.CheckEquals(scope.FirstDefinition("VAR.param"), mkline)
|
|
t.CheckNil(scope.FirstDefinition("VAR.*"))
|
|
}
|
|
|
|
func (s *Suite) Test_Scope_Fallback(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
mkline := t.NewMkLine("filename.mk", 3, "VAR=\tvalue")
|
|
scope := NewScope()
|
|
scope.def("VAR.param", mkline)
|
|
|
|
scope.Fallback("FALLBACK", "fallback")
|
|
|
|
t.CheckEquals(scope.LastValue("VAR.param"), "value")
|
|
t.CheckEquals(scope.LastValue("FALLBACK"), "fallback")
|
|
t.CheckEquals(scope.LastValue("UNDEFINED"), "")
|
|
}
|
|
|
|
func (s *Suite) Test_Scope_Use(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
mkline := t.NewMkLine("filename.mk", 3, "VAR=\t${USED}")
|
|
scope := NewScope()
|
|
scope.Define("VAR", mkline)
|
|
scope.Use("USED", mkline, VucRunTime)
|
|
|
|
t.CheckEquals(scope.LastValue("VAR"), "${USED}")
|
|
t.CheckEquals(scope.LastValue("USED"), "")
|
|
}
|
|
|
|
func (s *Suite) Test_Scope_Mentioned(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
assigned := t.NewMkLine("filename.mk", 3, "VAR=\tvalue")
|
|
commented := t.NewMkLine("filename.mk", 4, "#COMMENTED=\tvalue")
|
|
documented := t.NewMkLine("filename.mk", 5, "# DOCUMENTED is a variable.")
|
|
|
|
scope := NewScope()
|
|
scope.Define("VAR", assigned)
|
|
scope.Define("COMMENTED", commented)
|
|
scope.Define("DOCUMENTED", documented)
|
|
|
|
t.CheckEquals(scope.Mentioned("VAR"), assigned)
|
|
t.CheckEquals(scope.Mentioned("COMMENTED"), commented)
|
|
t.CheckEquals(scope.Mentioned("DOCUMENTED"), documented)
|
|
t.CheckNil(scope.Mentioned("UNKNOWN"))
|
|
}
|
|
|
|
func (s *Suite) Test_Scope_IsDefined(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
scope := NewScope()
|
|
scope.Define("VAR.param", t.NewMkLine("file.mk", 1, "VAR.param=value"))
|
|
|
|
t.CheckEquals(scope.IsDefined("VAR.param"), true)
|
|
t.CheckEquals(scope.IsDefined("VAR.other"), false)
|
|
t.CheckEquals(scope.IsDefined("VARIABLE.*"), false)
|
|
}
|
|
|
|
func (s *Suite) Test_Scope_IsDefinedSimilar(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
scope := NewScope()
|
|
scope.Define("VAR.param", t.NewMkLine("file.mk", 1, "VAR.param=value"))
|
|
|
|
t.CheckEquals(scope.IsDefinedSimilar("VAR.param"), true)
|
|
t.CheckEquals(scope.IsDefinedSimilar("VAR.other"), true)
|
|
t.CheckEquals(scope.IsDefinedSimilar("VARIABLE.*"), false)
|
|
}
|
|
|
|
func (s *Suite) Test_Scope_IsUsed(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
scope := NewScope()
|
|
mkline := t.NewMkLine("file.mk", 1, "\techo ${VAR.param}")
|
|
scope.Use("VAR.param", mkline, VucRunTime)
|
|
|
|
t.CheckEquals(scope.IsUsed("VAR.param"), true)
|
|
t.CheckEquals(scope.IsUsed("VAR.other"), false)
|
|
t.CheckEquals(scope.IsUsed("VARIABLE.*"), false)
|
|
}
|
|
|
|
func (s *Suite) Test_Scope_IsUsedSimilar(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
scope := NewScope()
|
|
mkline := t.NewMkLine("file.mk", 1, "\techo ${VAR.param}")
|
|
scope.Use("VAR.param", mkline, VucRunTime)
|
|
|
|
t.CheckEquals(scope.IsUsedSimilar("VAR.param"), true)
|
|
t.CheckEquals(scope.IsUsedSimilar("VAR.other"), true)
|
|
t.CheckEquals(scope.IsUsedSimilar("VARIABLE.*"), false)
|
|
}
|
|
|
|
func (s *Suite) Test_Scope_IsUsedAtLoadTime(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
scope := NewScope()
|
|
mkline := t.NewMkLine("file.mk", 1, "\techo ${VAR.param}")
|
|
|
|
scope.Use("LOAD_TIME", mkline, VucLoadTime)
|
|
scope.Use("RUN_TIME", mkline, VucRunTime)
|
|
|
|
t.CheckEquals(scope.IsUsedAtLoadTime("LOAD_TIME"), true)
|
|
t.CheckEquals(scope.IsUsedAtLoadTime("RUN_TIME"), false)
|
|
t.CheckEquals(scope.IsUsedAtLoadTime("UNDEFINED"), false)
|
|
}
|
|
|
|
func (s *Suite) Test_Scope_FirstDefinition(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
mkline3 := t.NewMkLine("fname.mk", 3, "VAR=\tvalue")
|
|
mkline4 := t.NewMkLine("fname.mk", 4, ".if ${SNEAKY::=value}")
|
|
mkline5 := t.NewMkLine("fname.mk", 5, ".if ${USED}")
|
|
|
|
scope := NewScope()
|
|
scope.Define("VAR", mkline3)
|
|
scope.Define("SNEAKY", mkline4)
|
|
scope.Use("USED", mkline5, VucLoadTime)
|
|
|
|
t.CheckEquals(scope.FirstDefinition("VAR"), mkline3)
|
|
|
|
// This call returns nil because it's not a variable assignment
|
|
// and the calling code typically assumes a variable definition.
|
|
// These sneaky variables with implicit definition are an edge
|
|
// case that only few people actually know. It's better that way.
|
|
t.CheckNil(scope.FirstDefinition("SNEAKY"))
|
|
|
|
t.CheckNil(scope.FirstDefinition("USED"))
|
|
|
|
t.CheckOutputLines(
|
|
"ERROR: fname.mk:4: Assignment modifiers like \":=\" " +
|
|
"must not be used at all.")
|
|
}
|
|
|
|
func (s *Suite) Test_Scope_LastDefinition(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
mkline3 := t.NewMkLine("fname.mk", 3, "VAR=\tfirst")
|
|
mkline4 := t.NewMkLine("fname.mk", 4, "VAR=\t${USED}")
|
|
|
|
scope := NewScope()
|
|
scope.Define("VAR", mkline3)
|
|
scope.Define("VAR", mkline4)
|
|
scope.Use("USED", mkline4, VucRunTime)
|
|
|
|
t.CheckEquals(scope.LastDefinition("VAR"), mkline4)
|
|
t.CheckNil(scope.LastDefinition("UNDEFINED"))
|
|
t.CheckNil(scope.LastDefinition("USED"))
|
|
}
|
|
|
|
func (s *Suite) Test_Scope_Commented(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
assigned := t.NewMkLine("filename.mk", 3, "VAR=\tvalue")
|
|
commented := t.NewMkLine("filename.mk", 4, "#COMMENTED=\tvalue")
|
|
documented := t.NewMkLine("filename.mk", 5, "# DOCUMENTED is a variable.")
|
|
used := t.NewMkLine("filename.mk", 6, "ANY=\t${USED}")
|
|
|
|
scope := NewScope()
|
|
scope.Define("VAR", assigned)
|
|
scope.Define("COMMENTED", commented)
|
|
scope.Define("DOCUMENTED", documented)
|
|
scope.Use("USED", used, VucRunTime)
|
|
|
|
t.CheckNil(scope.Commented("VAR"))
|
|
t.CheckEquals(scope.Commented("COMMENTED"), commented)
|
|
t.CheckNil(scope.Commented("DOCUMENTED"))
|
|
t.CheckNil(scope.Commented("UNKNOWN"))
|
|
t.CheckNil(scope.Commented("USED"))
|
|
}
|
|
|
|
func (s *Suite) Test_Scope_FirstUse(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
mklines := t.NewMkLines("file.mk",
|
|
MkCvsID,
|
|
"VAR1=\t${USED}",
|
|
"VAR2=\t${USED}")
|
|
|
|
mklines.Check()
|
|
|
|
scope := mklines.allVars
|
|
t.CheckEquals(scope.FirstUse("USED"), mklines.mklines[1])
|
|
t.CheckNil(scope.FirstUse("UNUSED"))
|
|
|
|
t.CheckOutputLines(
|
|
"WARN: file.mk:2: VAR1 is defined but not used.",
|
|
"WARN: file.mk:2: USED is used but not defined.",
|
|
"WARN: file.mk:3: VAR2 is defined but not used.")
|
|
}
|
|
|
|
func (s *Suite) Test_Scope_LastValue(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
mklines := t.NewMkLines("file.mk",
|
|
MkCvsID,
|
|
"VAR=\tfirst",
|
|
"VAR=\tsecond",
|
|
".if 1",
|
|
"VAR=\tthird (conditional)",
|
|
".endif")
|
|
|
|
mklines.Check()
|
|
|
|
// TODO: At load time, use loadVars instead of allVars.
|
|
t.CheckEquals(mklines.allVars.LastValue("VAR"), "third (conditional)")
|
|
|
|
t.CheckOutputLines(
|
|
"WARN: file.mk:2: VAR is defined but not used.")
|
|
}
|
|
|
|
// Up to 2020-01-06, pkglint wrongly returned "one" as the variable value,
|
|
// even though Makefile.common is included before appending "two".
|
|
func (s *Suite) Test_Scope_LastValue__append_in_multiple_files(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
t.SetUpPackage("category/package",
|
|
".include \"Makefile.common\"",
|
|
"PLIST_VARS+=\ttwo",
|
|
"PLIST.two=\tyes")
|
|
t.Chdir("category/package")
|
|
t.CreateFileLines("PLIST",
|
|
PlistCvsID,
|
|
"${PLIST.one}${PLIST.two}bin/program")
|
|
t.CreateFileLines("Makefile.common",
|
|
MkCvsID,
|
|
"PLIST_VARS=\tone",
|
|
"PLIST.one=\tyes")
|
|
pkg := NewPackage(".")
|
|
t.FinishSetUp()
|
|
|
|
pkg.Check()
|
|
|
|
t.CheckEquals(pkg.vars.LastValue("PLIST_VARS"), "one two")
|
|
}
|
|
|
|
func (s *Suite) Test_Scope_LastValueFound(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
mklines := t.NewMkLines("file.mk",
|
|
MkCvsID,
|
|
"VAR=\tfirst",
|
|
"VAR=\tsecond",
|
|
".if 1",
|
|
"VAR=\tthird (conditional)",
|
|
".endif")
|
|
|
|
mklines.Check()
|
|
|
|
value, found, indeterminate := mklines.allVars.LastValueFound("VAR")
|
|
t.CheckEquals(value, "third (conditional)")
|
|
t.CheckEquals(found, true)
|
|
t.CheckEquals(indeterminate, false) // TODO: why?
|
|
|
|
t.CheckOutputLines(
|
|
"WARN: file.mk:2: VAR is defined but not used.")
|
|
}
|
|
|
|
// Scope.DefineAll copies only the variable definitions,
|
|
// but not the uses of variables.
|
|
func (s *Suite) Test_Scope_DefineAll(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
mkline := t.NewMkLine("filename.mk", 123, "VAR=\t${USED}")
|
|
|
|
src := NewScope()
|
|
src.Use("USED", mkline, VucRunTime)
|
|
|
|
dst := NewScope()
|
|
dst.DefineAll(&src)
|
|
|
|
t.CheckLen(dst.vs, 0)
|
|
|
|
src.Define("VAR", t.NewMkLine("file.mk", 1, "VAR=value"))
|
|
dst.DefineAll(&src)
|
|
|
|
t.CheckEquals(dst.IsDefined("VAR"), true)
|
|
}
|
|
|
|
func (s *Suite) Test_Scope_forEach(c *check.C) {
|
|
t := s.Init(c)
|
|
|
|
mkline := t.NewMkLine("filename.mk", 123, "VAR=\t${USED}")
|
|
|
|
scope := NewScope()
|
|
scope.Define("VAR", mkline)
|
|
scope.Use("USED", mkline, VucRunTime)
|
|
|
|
var result []string
|
|
scope.forEach(func(varname string, data *scopeVar) {
|
|
result = append(result, varname+"="+data.value)
|
|
})
|
|
|
|
t.CheckDeepEquals(result, []string{
|
|
"USED=",
|
|
"VAR=${USED}"})
|
|
}
|