[BACK]Return to util_test.go CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / pkgsrc / pkgtools / pkglint / files

File: [cvs.NetBSD.org] / pkgsrc / pkgtools / pkglint / files / Attic / util_test.go (download)

Revision 1.17, Wed Nov 7 20:58:23 2018 UTC (5 years, 5 months ago) by rillig
Branch: MAIN
Changes since 1.16: +38 -12 lines

pkgtools/pkglint: update to 5.6.6

Changes since 5.6.5:

- Removed plist-clash since it had crashed unconditionally whenever it
  was called. This means that in the last 3 years, nobody can have
  used it in the originally intended way.

- Fixed interactions between the --source, --explain, --show-autofix,
  --autofix and --only options.

- Fixed "defined but not used" and "used but not defined" for variables
  from the pkgsrc infrastructure.

- Lots of small fixes and improvements found by the large pkglint code
  review (12% done).

package main

import (
	"gopkg.in/check.v1"
	"os"
	"runtime"
	"testing"
	"time"
)

func (s *Suite) Test_YesNoUnknown_String(c *check.C) {
	c.Check(yes.String(), equals, "yes")
	c.Check(no.String(), equals, "no")
	c.Check(unknown.String(), equals, "unknown")
}

func (s *Suite) Test_mkopSubst__middle(c *check.C) {
	c.Check(mkopSubst("pkgname", false, "kgna", false, "ri", ""), equals, "prime")
	c.Check(mkopSubst("pkgname", false, "pkgname", false, "replacement", ""), equals, "replacement")
	c.Check(mkopSubst("aaaaaaa", false, "a", false, "b", ""), equals, "baaaaaa")
}

func (s *Suite) Test_mkopSubst__left(c *check.C) {
	c.Check(mkopSubst("pkgname", true, "kgna", false, "ri", ""), equals, "pkgname")
	c.Check(mkopSubst("pkgname", true, "pkgname", false, "replacement", ""), equals, "replacement")
}

func (s *Suite) Test_mkopSubst__right(c *check.C) {
	c.Check(mkopSubst("pkgname", false, "kgna", true, "ri", ""), equals, "pkgname")
	c.Check(mkopSubst("pkgname", false, "pkgname", true, "replacement", ""), equals, "replacement")
}

func (s *Suite) Test_mkopSubst__left_and_right(c *check.C) {
	c.Check(mkopSubst("pkgname", true, "kgna", true, "ri", ""), equals, "pkgname")
	c.Check(mkopSubst("pkgname", false, "pkgname", false, "replacement", ""), equals, "replacement")
}

func (s *Suite) Test_mkopSubst__gflag(c *check.C) {
	c.Check(mkopSubst("aaaaa", false, "a", false, "b", "g"), equals, "bbbbb")
	c.Check(mkopSubst("aaaaa", true, "a", false, "b", "g"), equals, "baaaa")
	c.Check(mkopSubst("aaaaa", false, "a", true, "b", "g"), equals, "aaaab")
	c.Check(mkopSubst("aaaaa", true, "a", true, "b", "g"), equals, "aaaaa")
}

func (s *Suite) Test__regex_ReplaceFirst(c *check.C) {
	m, rest := G.res.ReplaceFirst("a+b+c+d", `(\w)(.)(\w)`, "X")

	c.Assert(m, check.NotNil)
	c.Check(m, check.DeepEquals, []string{"a+b", "a", "+", "b"})
	c.Check(rest, equals, "X+c+d")
}

func (s *Suite) Test_mustMatch(c *check.C) {
	c.Check(
		func() { mustMatch("aaa", `b`) },
		check.Panics,
		"mustMatch \"aaa\" \"b\"")
}

func (s *Suite) Test_shorten(c *check.C) {
	c.Check(shorten("aaaaa", 3), equals, "aaa...")
	c.Check(shorten("aaaaa", 5), equals, "aaaaa")
	c.Check(shorten("aaa", 5), equals, "aaa")
}

func (s *Suite) Test_tabWidth(c *check.C) {
	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) {
	c.Check(cleanpath("simple/path"), equals, "simple/path")
	c.Check(cleanpath("/absolute/path"), equals, "/absolute/path")
	c.Check(cleanpath("./././."), equals, ".")
	c.Check(cleanpath("./././"), equals, ".")
	c.Check(cleanpath("dir/../dir/../dir/../dir/subdir/../../Makefile"), equals, "dir/../dir/../dir/../Makefile")
	c.Check(cleanpath("dir/multi/././/file"), equals, "dir/multi/file")
	c.Check(cleanpath("111/222/../../333/444/../../555/666/../../777/888/9"), equals, "111/222/../../777/888/9")
	c.Check(cleanpath("1/2/3/../../4/5/6/../../7/8/9/../../../../10"), equals, "1/10")
	c.Check(cleanpath("cat/pkg.v1/../../cat/pkg.v2/Makefile"), equals, "cat/pkg.v1/../../cat/pkg.v2/Makefile")
	c.Check(cleanpath("dir/"), equals, "dir")
}

// Relpath is called so often that handling the most common calls
// without file system IO makes sense.
func (s *Suite) Test_relpath__quick(c *check.C) {
	c.Check(relpath("some/dir", "some/dir/../.."), equals, "../..")
	c.Check(relpath("some/dir", "some/dir/./././../.."), equals, "../..")
	c.Check(relpath("some/dir", "some/dir/"), equals, ".")
	c.Check(relpath("some/dir", "some/directory"), equals, "../directory")
}

// This is not really an internal error but won't happen in practice anyway.
// Therefore using ExpectPanic instead of ExpectFatal is ok.
func (s *Suite) Test_relpath__failure_on_Windows(c *check.C) {
	t := s.Init(c)

	if runtime.GOOS == "windows" {
		t.ExpectPanic(
			func() { relpath("c:/", "d:/") },
			"Pkglint internal error: relpath \"c:/\" \"d:/\".")
	}
}

func (s *Suite) Test_abspath__on_Windows(c *check.C) {
	t := s.Init(c)

	if runtime.GOOS == "windows" {
		t.ExpectPanic(
			func() { abspath("file\u0000name") },
			"Pkglint internal error: abspath \"file\\x00name\".")
	}
}

func (s *Suite) Test_isEmptyDir__and_getSubdirs(c *check.C) {
	t := s.Init(c)

	t.CreateFileLines("CVS/Entries",
		"dummy")

	if dir := t.File("."); true {
		c.Check(isEmptyDir(dir), equals, true)
		c.Check(getSubdirs(dir), check.DeepEquals, []string(nil))

		t.CreateFileLines("somedir/file")

		c.Check(isEmptyDir(dir), equals, false)
		c.Check(getSubdirs(dir), check.DeepEquals, []string{"somedir"})
	}

	if absent := t.File("nonexistent"); true {
		c.Check(isEmptyDir(absent), equals, true) // Counts as empty.

		// The last group from the error message is localized, therefore the matching.
		t.ExpectFatalMatches(
			func() { getSubdirs(absent) },
			`FATAL: ~/nonexistent: Cannot be read: open ~/nonexistent: (.+)\n`)
	}
}

func (s *Suite) Test_isEmptyDir__empty_subdir(c *check.C) {
	t := s.Init(c)

	t.CreateFileLines("CVS/Entries",
		"dummy")
	t.CreateFileLines("subdir/CVS/Entries",
		"dummy")

	c.Check(isEmptyDir(t.File(".")), equals, true)
}

func (s *Suite) Test__PrefixReplacer_Since(c *check.C) {
	repl := G.NewPrefixReplacer("hello, world")
	mark := repl.Mark()
	repl.AdvanceRegexp(`^\w+`)
	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 = `^\.([\t ]*)(s?include)[\t ]+\"([^\"]+)\"[\t ]*(?:#.*)?$`
const reMkIncludeBenchmarkPositive = `^\.([\t ]*)(s?include)[\t ]+\"(.+)\"[\t ]*(?:#.*)?$`

func Benchmark_match3_buildlink3(b *testing.B) {
	for i := 0; i < b.N; i++ {
		match3(".include \"../../category/package/buildlink3.mk\"", reMkIncludeBenchmark)
	}
}

func Benchmark_match3_bsd_pkg_mk(b *testing.B) {
	for i := 0; i < b.N; i++ {
		match3(".include \"../../mk/bsd.pkg.mk\"", reMkIncludeBenchmark)
	}
}

func Benchmark_match3_same_dir(b *testing.B) {
	for i := 0; i < b.N; i++ {
		match3(".include \"options.mk\"", reMkIncludeBenchmark)
	}
}

func Benchmark_match3_bsd_pkg_mk_comment(b *testing.B) {
	for i := 0; i < b.N; i++ {
		match3(".include \"../../mk/bsd.pkg.mk\"          # infrastructure     ", reMkIncludeBenchmark)
	}
}

func Benchmark_match3_buildlink3_positive(b *testing.B) {
	for i := 0; i < b.N; i++ {
		match3(".include \"../../category/package/buildlink3.mk\"", reMkIncludeBenchmarkPositive)
	}
}

func Benchmark_match3_bsd_pkg_mk_positive(b *testing.B) {
	for i := 0; i < b.N; i++ {
		match3(".include \"../../mk/bsd.pkg.mk\"", reMkIncludeBenchmarkPositive)
	}
}

func Benchmark_match3_same_dir_positive(b *testing.B) {
	for i := 0; i < b.N; i++ {
		match3(".include \"options.mk\"", reMkIncludeBenchmarkPositive)
	}
}

func Benchmark_match3_bsd_pkg_mk_comment_positive(b *testing.B) {
	for i := 0; i < b.N; i++ {
		match3(".include \"../../mk/bsd.pkg.mk\"          # infrastructure     ", reMkIncludeBenchmarkPositive)
	}
}

func Benchmark_match3_explicit(b *testing.B) {
	for i := 0; i < b.N; i++ {
		MatchMkInclude(".include \"../../mk/bsd.pkg.mk\"          # infrastructure     ")
	}
}

func emptyToNil(slice []string) []string {
	if len(slice) == 0 {
		return nil
	}
	return slice
}

func (s *Suite) Test_isLocallyModified(c *check.C) {
	t := s.Init(c)

	unmodified := t.CreateFileLines("unmodified")
	modTime := time.Unix(1136239445, 0)

	err := os.Chtimes(unmodified, modTime, modTime)
	c.Check(err, check.IsNil)

	st, err := os.Lstat(unmodified)
	c.Check(err, check.IsNil)

	// Make sure that the file system has second precision and accuracy.
	c.Check(st.ModTime(), check.DeepEquals, modTime)

	modified := t.CreateFileLines("modified")

	t.CreateFileLines("CVS/Entries",
		"/unmodified//"+modTime.Format(time.ANSIC)+"//",
		"/modified//"+modTime.Format(time.ANSIC)+"//",
		"/enoent//"+modTime.Format(time.ANSIC)+"//")

	c.Check(isLocallyModified(unmodified), equals, false)
	c.Check(isLocallyModified(modified), equals, true)
	c.Check(isLocallyModified(t.File("enoent")), equals, true)
	c.Check(isLocallyModified(t.File("not_mentioned")), equals, false)
	c.Check(isLocallyModified(t.File("subdir/file")), equals, false)
}

func (s *Suite) Test_Scope_Defined(c *check.C) {
	t := s.Init(c)

	scope := NewScope()
	scope.Define("VAR.param", t.NewMkLine("file.mk", 1, "VAR.param=value"))

	c.Check(scope.Defined("VAR.param"), equals, true)
	c.Check(scope.Defined("VAR.other"), equals, false)
	c.Check(scope.Defined("VARIABLE.*"), equals, false)

	c.Check(scope.DefinedSimilar("VAR.param"), equals, true)
	c.Check(scope.DefinedSimilar("VAR.other"), equals, true)
	c.Check(scope.DefinedSimilar("VARIABLE.*"), equals, false)
}

func (s *Suite) Test_Scope_Used(c *check.C) {
	t := s.Init(c)

	scope := NewScope()
	scope.Use("VAR.param", t.NewMkLine("file.mk", 1, "\techo ${VAR.param}"))

	c.Check(scope.Used("VAR.param"), equals, true)
	c.Check(scope.Used("VAR.other"), equals, false)
	c.Check(scope.Used("VARIABLE.*"), equals, false)

	c.Check(scope.UsedSimilar("VAR.param"), equals, true)
	c.Check(scope.UsedSimilar("VAR.other"), equals, true)
	c.Check(scope.UsedSimilar("VARIABLE.*"), equals, false)
}

func (s *Suite) Test_Scope_DefineAll(c *check.C) {
	t := s.Init(c)

	src := NewScope()

	dst := NewScope()
	dst.DefineAll(src)

	c.Check(dst.defined, check.HasLen, 0)
	c.Check(dst.used, check.HasLen, 0)

	src.Define("VAR", t.NewMkLine("file.mk", 1, "VAR=value"))
	dst.DefineAll(src)

	c.Check(dst.Defined("VAR"), equals, true)
}

func (s *Suite) Test_naturalLess(c *check.C) {
	c.Check(naturalLess("0", "a"), equals, true)
	c.Check(naturalLess("a", "0"), equals, false)
	c.Check(naturalLess("000", "0000"), equals, true)
	c.Check(naturalLess("0000", "000"), equals, false)
	c.Check(naturalLess("000", "000"), equals, false)
	c.Check(naturalLess("00011", "000111"), equals, true)
	c.Check(naturalLess("00011", "00012"), equals, true)
}

func (s *Suite) Test_varnameBase(c *check.C) {
	c.Check(varnameBase("VAR"), equals, "VAR")
	c.Check(varnameBase("VAR.param"), equals, "VAR")
	c.Check(varnameBase(".CURDIR"), equals, ".CURDIR")
}

func (s *Suite) Test_varnameParam(c *check.C) {
	c.Check(varnameParam("VAR"), equals, "")
	c.Check(varnameParam("VAR.param"), equals, "param")
	c.Check(varnameParam(".CURDIR"), equals, "")
}

func (s *Suite) Test_varnameCanon(c *check.C) {
	c.Check(varnameCanon("VAR"), equals, "VAR")
	c.Check(varnameCanon("VAR.param"), equals, "VAR.*")
	c.Check(varnameCanon(".CURDIR"), equals, ".CURDIR")
}

func (s *Suite) Test_isalnum(c *check.C) {
	c.Check(isalnum(""), equals, true)
	c.Check(isalnum("/"), equals, false)
	c.Check(isalnum("0"), equals, true)
	c.Check(isalnum("9"), equals, true)
	c.Check(isalnum(":"), equals, false)
	c.Check(isalnum("@"), equals, false)
	c.Check(isalnum("A"), equals, true)
	c.Check(isalnum("Z"), equals, true)
	c.Check(isalnum("["), equals, false)
	c.Check(isalnum("_"), equals, true)
	c.Check(isalnum("`"), equals, false)
	c.Check(isalnum("a"), equals, true)
	c.Check(isalnum("z"), equals, true)
	c.Check(isalnum("{"), equals, false)
	c.Check(isalnum("Hello_world005"), equals, true)
	c.Check(isalnum("Hello,world005"), equals, false)
}

func (s *Suite) Test_FileCache(c *check.C) {
	t := s.Init(c)

	cache := NewFileCache(3)

	lines := t.NewLines("Makefile",
		MkRcsID,
		"# line 2")

	c.Check(cache.Get("Makefile", 0), check.IsNil)
	c.Check(cache.hits, equals, 0)
	c.Check(cache.misses, equals, 1)

	cache.Put("Makefile", 0, lines)
	c.Check(cache.Get("Makefile", MustSucceed|LogErrors), check.IsNil) // Wrong LoadOptions.

	linesFromCache := cache.Get("Makefile", 0)
	c.Check(linesFromCache.FileName, equals, "Makefile")
	c.Check(linesFromCache.Lines, check.HasLen, 2)
	c.Check(linesFromCache.Lines[0].FileName, equals, "Makefile")

	// Cache keys are normalized using path.Clean.
	linesFromCache2 := cache.Get("./Makefile", 0)
	c.Check(linesFromCache2.FileName, equals, "./Makefile")
	c.Check(linesFromCache2.Lines, check.HasLen, 2)
	c.Check(linesFromCache2.Lines[0].FileName, equals, "./Makefile")

	cache.Put("file1.mk", 0, lines)
	cache.Put("file2.mk", 0, lines)

	// Now the cache is full. All three entries can be retrieved.
	c.Check(cache.Get("Makefile", 0), check.NotNil)
	c.Check(cache.Get("file1.mk", 0), check.NotNil)
	c.Check(cache.Get("file2.mk", 0), check.NotNil)

	// Adding another entry removes all entries with minimum count,
	// which currently are file1.mk and file2.mk.
	// Makefile is still in the cache because it was accessed once.
	cache.Put("file3.mk", 0, lines)

	c.Check(cache.Get("Makefile", 0), check.NotNil)
	c.Check(cache.Get("file1.mk", 0), check.IsNil)
	c.Check(cache.Get("file2.mk", 0), check.IsNil)
	c.Check(cache.Get("file3.mk", 0), check.NotNil)

	cache.Evict("Makefile")

	c.Check(cache.Get("Makefile", 0), check.IsNil)
	c.Check(cache.table, check.HasLen, 1)
	c.Check(cache.mapping, check.HasLen, 1)
	c.Check(cache.hits, equals, 7)
	c.Check(cache.misses, equals, 5)

	t.CheckOutputLines(
		"FileCache \"Makefile\" with count 4.",
		"FileCache \"file1.mk\" with count 2.",
		"FileCache \"file2.mk\" with count 2.",
		"FileCache.Evict \"file2.mk\" with count 2.",
		"FileCache.Evict \"file1.mk\" with count 2.",
		"FileCache.Halve \"Makefile\" with count 4.")
}

func (s *Suite) Test_makeHelp(c *check.C) {
	c.Check(makeHelp("subst"), equals, confMake+" help topic=subst")
}