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

Annotation of pkgsrc/pkgtools/pkglint/files/util_test.go, Revision 1.37

1.19      rillig      1: package pkglint
1.1       rillig      2:
                      3: import (
1.30      rillig      4:        "errors"
1.9       rillig      5:        "gopkg.in/check.v1"
1.13      rillig      6:        "os"
1.6       rillig      7:        "testing"
1.13      rillig      8:        "time"
1.1       rillig      9: )
                     10:
1.35      rillig     11: func (s *Suite) Test_YesNoUnknown_String(c *check.C) {
                     12:        t := s.Init(c)
                     13:
                     14:        t.CheckEquals(yes.String(), "yes")
                     15:        t.CheckEquals(no.String(), "no")
                     16:        t.CheckEquals(unknown.String(), "unknown")
                     17: }
                     18:
                     19: func (s *Suite) Test_trimHspace(c *check.C) {
                     20:        t := s.Init(c)
                     21:
                     22:        t.CheckEquals(trimHspace("a b"), "a b")
                     23:        t.CheckEquals(trimHspace(" a b "), "a b")
                     24:        t.CheckEquals(trimHspace("\ta b\t"), "a b")
                     25:        t.CheckEquals(trimHspace(" \t a b\t \t"), "a b")
                     26: }
                     27:
                     28: func (s *Suite) Test_trimCommon(c *check.C) {
                     29:        t := s.Init(c)
                     30:
                     31:        test := func(a, b, trimmedA, trimmedB string) {
                     32:                ta, tb := trimCommon(a, b)
                     33:                t.CheckEquals(ta, trimmedA)
                     34:                t.CheckEquals(tb, trimmedB)
                     35:        }
                     36:
                     37:        test("", "",
                     38:                "", "")
                     39:
                     40:        test("equal", "equal",
                     41:                "", "")
                     42:
                     43:        test("prefixA", "prefixB",
                     44:                "A", "B")
                     45:
                     46:        test("ASuffix", "BSuffix",
                     47:                "A", "B")
                     48:
                     49:        test("PreMiddlePost", "PreCenterPost",
                     50:                "Middle", "Center")
                     51:
                     52:        test("", "b",
                     53:                "", "b")
                     54:
                     55:        test("a", "",
                     56:                "a", "")
                     57: }
                     58:
1.30      rillig     59: func (s *Suite) Test_assertNil(c *check.C) {
                     60:        t := s.Init(c)
                     61:
                     62:        assertNil(nil, "this is not an error")
                     63:
                     64:        t.ExpectPanic(
                     65:                func() { assertNil(errors.New("unexpected error"), "Oops") },
                     66:                "Pkglint internal error: Oops: unexpected error")
                     67: }
                     68:
1.31      rillig     69: func (s *Suite) Test_assertNotNil(c *check.C) {
                     70:        t := s.Init(c)
                     71:
                     72:        assertNotNil("this string is not nil")
                     73:
                     74:        t.ExpectPanic(
                     75:                func() { assertNotNil(nil) },
                     76:                "Pkglint internal error: unexpected nil pointer")
                     77:        t.ExpectPanic(
                     78:                func() { var ptr *string; assertNotNil(ptr) },
                     79:                "Pkglint internal error: unexpected nil pointer")
                     80: }
                     81:
1.35      rillig     82: func (s *Suite) Test_isEmptyDir(c *check.C) {
                     83:        t := s.Init(c)
                     84:
                     85:        t.CreateFileLines("CVS/Entries",
                     86:                "dummy")
                     87:        t.CreateFileLines("subdir/CVS/Entries",
                     88:                "dummy")
                     89:
                     90:        t.CheckEquals(isEmptyDir(t.File(".")), true)
                     91:        t.CheckEquals(isEmptyDir(t.File("CVS")), true)
1.37    ! rillig     92:
        !            93:        t.Chdir(".")
        !            94:
        !            95:        t.CheckEquals(isEmptyDir("."), true)
        !            96:        t.CheckEquals(isEmptyDir("CVS"), true)
1.35      rillig     97: }
                     98:
                     99: func (s *Suite) Test_isEmptyDir__and_getSubdirs(c *check.C) {
                    100:        t := s.Init(c)
                    101:
                    102:        t.CreateFileLines("CVS/Entries",
                    103:                "dummy")
                    104:
                    105:        if dir := t.File("."); true {
                    106:                t.CheckEquals(isEmptyDir(dir), true)
1.36      rillig    107:                t.CheckDeepEquals(getSubdirs(dir), []Path(nil))
1.35      rillig    108:
                    109:                t.CreateFileLines("somedir/file")
                    110:
                    111:                t.CheckEquals(isEmptyDir(dir), false)
1.36      rillig    112:                t.CheckDeepEquals(getSubdirs(dir), []Path{"somedir"})
1.35      rillig    113:        }
                    114:
                    115:        if absent := t.File("nonexistent"); true {
                    116:                t.CheckEquals(isEmptyDir(absent), true) // Counts as empty.
                    117:
                    118:                // The last group from the error message is localized, therefore the matching.
                    119:                t.ExpectFatalMatches(
                    120:                        func() { getSubdirs(absent) },
                    121:                        `FATAL: ~/nonexistent: Cannot be read: open ~/nonexistent: (.+)\n`)
                    122:        }
                    123: }
                    124:
                    125: func (s *Suite) Test_getSubdirs(c *check.C) {
                    126:        t := s.Init(c)
                    127:
                    128:        t.CreateFileLines("subdir/file")
                    129:        t.CreateFileLines("empty/file")
1.36      rillig    130:        c.Check(os.Remove(t.File("empty/file").String()), check.IsNil)
1.35      rillig    131:
1.36      rillig    132:        t.CheckDeepEquals(getSubdirs(t.File(".")), []Path{"subdir"})
1.35      rillig    133: }
                    134:
                    135: func (s *Suite) Test_isLocallyModified(c *check.C) {
1.32      rillig    136:        t := s.Init(c)
                    137:
1.35      rillig    138:        unmodified := t.CreateFileLines("unmodified")
                    139:        modTime := time.Unix(1136239445, 0).UTC()
                    140:
1.36      rillig    141:        err := os.Chtimes(unmodified.String(), modTime, modTime)
1.35      rillig    142:        c.Check(err, check.IsNil)
                    143:
1.36      rillig    144:        st, err := os.Lstat(unmodified.String())
1.35      rillig    145:        c.Check(err, check.IsNil)
                    146:
                    147:        // Make sure that the file system has second precision and accuracy.
                    148:        t.CheckDeepEquals(st.ModTime().UTC(), modTime)
                    149:
                    150:        modified := t.CreateFileLines("modified")
                    151:
                    152:        t.CreateFileLines("CVS/Entries",
                    153:                "/unmodified//"+modTime.Format(time.ANSIC)+"//",
                    154:                "/modified//"+modTime.Format(time.ANSIC)+"//",
                    155:                "/enoent//"+modTime.Format(time.ANSIC)+"//")
                    156:
                    157:        t.CheckEquals(isLocallyModified(unmodified), false)
                    158:        t.CheckEquals(isLocallyModified(modified), true)
                    159:        t.CheckEquals(isLocallyModified(t.File("enoent")), true)
                    160:        t.CheckEquals(isLocallyModified(t.File("not_mentioned")), false)
                    161:        t.CheckEquals(isLocallyModified(t.File("subdir/file")), false)
                    162:
                    163:        t.DisableTracing()
                    164:
                    165:        t.CheckEquals(isLocallyModified(t.File("unmodified")), false)
1.11      rillig    166: }
                    167:
1.35      rillig    168: func (s *Suite) Test_tabWidth(c *check.C) {
1.32      rillig    169:        t := s.Init(c)
                    170:
1.35      rillig    171:        t.CheckEquals(tabWidth("12345"), 5)
                    172:        t.CheckEquals(tabWidth("\t"), 8)
                    173:        t.CheckEquals(tabWidth("123\t"), 8)
                    174:        t.CheckEquals(tabWidth("1234567\t"), 8)
                    175:        t.CheckEquals(tabWidth("12345678\t"), 16)
1.1       rillig    176: }
                    177:
1.35      rillig    178: // Since tabWidthAppend is used with logical lines (Line.Text) as well as with
                    179: // raw lines (RawLine.textnl or RawLine.orignl), and since the width only
                    180: // makes sense for a single line, better panic.
                    181: func (s *Suite) Test_tabWidthAppend__panic(c *check.C) {
1.32      rillig    182:        t := s.Init(c)
                    183:
1.35      rillig    184:        t.ExpectAssert(func() { tabWidthAppend(0, "\n") })
1.1       rillig    185: }
                    186:
1.35      rillig    187: func (s *Suite) Test_detab(c *check.C) {
1.32      rillig    188:        t := s.Init(c)
                    189:
1.35      rillig    190:        t.CheckEquals(detab(""), "")
                    191:        t.CheckEquals(detab("\t"), "        ")
                    192:        t.CheckEquals(detab("1234\t9"), "1234    9")
                    193:        t.CheckEquals(detab("1234567\t"), "1234567 ")
                    194:        t.CheckEquals(detab("12345678\t"), "12345678        ")
1.1       rillig    195: }
                    196:
1.35      rillig    197: func (s *Suite) Test_alignWith(c *check.C) {
1.32      rillig    198:        t := s.Init(c)
                    199:
1.35      rillig    200:        test := func(str, other, expected string) {
                    201:                t.CheckEquals(alignWith(str, other), expected)
                    202:        }
                    203:
                    204:        // At least one tab is _always_ added.
                    205:        test("", "", "\t")
                    206:
                    207:        test("VAR=", "1234567", "VAR=\t")
                    208:        test("VAR=", "12345678", "VAR=\t")
                    209:        test("VAR=", "123456789", "VAR=\t\t")
                    210:
                    211:        // At least one tab is added in any case,
                    212:        // even if the other string is shorter.
                    213:        test("1234567890=", "V=", "1234567890=\t")
1.1       rillig    214: }
                    215:
1.35      rillig    216: func (s *Suite) Test_indent(c *check.C) {
1.32      rillig    217:        t := s.Init(c)
                    218:
1.35      rillig    219:        test := func(width int, ind string) {
                    220:                actual := indent(width)
                    221:
                    222:                t.CheckEquals(actual, ind)
                    223:        }
                    224:
                    225:        test(0, "")
                    226:        test(1, " ")
                    227:        test(7, "       ")
                    228:        test(8, "\t")
                    229:        test(15, "\t       ")
                    230:        test(16, "\t\t")
                    231:        test(72, "\t\t\t\t\t\t\t\t\t")
1.1       rillig    232: }
                    233:
1.35      rillig    234: func (s *Suite) Test_alignmentAfter(c *check.C) {
1.32      rillig    235:        t := s.Init(c)
                    236:
1.35      rillig    237:        test := func(prefix string, width int, ind string) {
                    238:                actual := alignmentAfter(prefix, width)
                    239:
                    240:                t.CheckEquals(actual, ind)
                    241:        }
                    242:
                    243:        test("", 0, "")
                    244:        test("", 15, "\t       ")
                    245:
                    246:        test("  ", 5, "   ")
                    247:        test("      ", 10, "\t  ")
                    248:
                    249:        test("\t", 15, "       ")
                    250:        test(" \t", 15, "       ")
                    251:        test("       \t", 15, "       ")
                    252:        test("\t    ", 15, "   ")
                    253:
                    254:        test("    ", 16, "\t\t")
1.1       rillig    255:
1.35      rillig    256:        // The desired width must be at least the width of the prefix.
                    257:        t.ExpectAssert(func() { test("\t", 7, "") })
1.1       rillig    258: }
                    259:
1.13      rillig    260: func (s *Suite) Test_shorten(c *check.C) {
1.32      rillig    261:        t := s.Init(c)
                    262:
                    263:        t.CheckEquals(shorten("aaaaa", 3), "aaa...")
                    264:        t.CheckEquals(shorten("aaaaa", 5), "aaaaa")
                    265:        t.CheckEquals(shorten("aaa", 5), "aaa")
1.13      rillig    266: }
                    267:
1.35      rillig    268: func (s *Suite) Test_varnameBase(c *check.C) {
                    269:        t := s.Init(c)
                    270:
                    271:        t.CheckEquals(varnameBase("VAR"), "VAR")
                    272:        t.CheckEquals(varnameBase("VAR.param"), "VAR")
                    273:        t.CheckEquals(varnameBase(".CURDIR"), ".CURDIR")
                    274: }
                    275:
                    276: func (s *Suite) Test_varnameCanon(c *check.C) {
                    277:        t := s.Init(c)
                    278:
                    279:        t.CheckEquals(varnameCanon("VAR"), "VAR")
                    280:        t.CheckEquals(varnameCanon("VAR.param"), "VAR.*")
                    281:        t.CheckEquals(varnameCanon(".CURDIR"), ".CURDIR")
                    282: }
                    283:
                    284: func (s *Suite) Test_varnameParam(c *check.C) {
                    285:        t := s.Init(c)
                    286:
                    287:        t.CheckEquals(varnameParam("VAR"), "")
                    288:        t.CheckEquals(varnameParam("VAR.param"), "param")
                    289:        t.CheckEquals(varnameParam(".CURDIR"), "")
                    290: }
                    291:
                    292: func (s *Suite) Test_mkopSubst__middle(c *check.C) {
1.32      rillig    293:        t := s.Init(c)
                    294:
1.35      rillig    295:        t.CheckEquals(mkopSubst("pkgname", false, "kgna", false, "ri", ""), "prime")
                    296:        t.CheckEquals(mkopSubst("pkgname", false, "pkgname", false, "replacement", ""), "replacement")
                    297:        t.CheckEquals(mkopSubst("aaaaaaa", false, "a", false, "b", ""), "baaaaaa")
1.1       rillig    298: }
                    299:
1.35      rillig    300: func (s *Suite) Test_mkopSubst__left(c *check.C) {
1.33      rillig    301:        t := s.Init(c)
                    302:
1.35      rillig    303:        t.CheckEquals(mkopSubst("pkgname", true, "kgna", false, "ri", ""), "pkgname")
                    304:        t.CheckEquals(mkopSubst("pkgname", true, "pkgname", false, "replacement", ""), "replacement")
1.33      rillig    305: }
                    306:
1.35      rillig    307: func (s *Suite) Test_mkopSubst__right(c *check.C) {
1.32      rillig    308:        t := s.Init(c)
                    309:
1.35      rillig    310:        t.CheckEquals(mkopSubst("pkgname", false, "kgna", true, "ri", ""), "pkgname")
                    311:        t.CheckEquals(mkopSubst("pkgname", false, "pkgname", true, "replacement", ""), "replacement")
                    312: }
                    313:
                    314: func (s *Suite) Test_mkopSubst__left_and_right(c *check.C) {
                    315:        t := s.Init(c)
1.24      rillig    316:
1.35      rillig    317:        t.CheckEquals(mkopSubst("pkgname", true, "kgna", true, "ri", ""), "pkgname")
                    318:        t.CheckEquals(mkopSubst("pkgname", false, "pkgname", false, "replacement", ""), "replacement")
                    319: }
1.21      rillig    320:
1.35      rillig    321: func (s *Suite) Test_mkopSubst__gflag(c *check.C) {
                    322:        t := s.Init(c)
1.24      rillig    323:
1.35      rillig    324:        t.CheckEquals(mkopSubst("aaaaa", false, "a", false, "b", "g"), "bbbbb")
                    325:        t.CheckEquals(mkopSubst("aaaaa", true, "a", false, "b", "g"), "baaaa")
                    326:        t.CheckEquals(mkopSubst("aaaaa", false, "a", true, "b", "g"), "aaaab")
                    327:        t.CheckEquals(mkopSubst("aaaaa", true, "a", true, "b", "g"), "aaaaa")
                    328: }
1.21      rillig    329:
1.35      rillig    330: func (s *Suite) Test__regex_ReplaceFirst(c *check.C) {
                    331:        t := s.Init(c)
1.21      rillig    332:
1.35      rillig    333:        m, rest := G.res.ReplaceFirst("a+b+c+d", `(\w)(.)(\w)`, "X")
1.24      rillig    334:
1.35      rillig    335:        c.Assert(m, check.NotNil)
                    336:        t.CheckDeepEquals(m, []string{"a+b", "a", "+", "b"})
                    337:        t.CheckEquals(rest, "X+c+d")
1.24      rillig    338: }
                    339:
1.35      rillig    340: func (s *Suite) Test_cleanpath(c *check.C) {
                    341:        t := s.Init(c)
                    342:
1.36      rillig    343:        test := func(from, to Path) {
1.35      rillig    344:                t.CheckEquals(cleanpath(from), to)
                    345:        }
                    346:
                    347:        test("simple/path", "simple/path")
                    348:        test("/absolute/path", "/absolute/path")
                    349:
                    350:        // Single dot components are removed, unless it's the only component of the path.
                    351:        test("./././.", ".")
                    352:        test("./././", ".")
                    353:        test("dir/multi/././/file", "dir/multi/file")
                    354:        test("dir/", "dir")
                    355:
                    356:        test("dir/", "dir")
                    357:
                    358:        // Components like aa/bb/../.. are removed, but not in the initial part of the path,
                    359:        // and only if they are not followed by another "..".
                    360:        test("dir/../dir/../dir/../dir/subdir/../../Makefile", "dir/../dir/../dir/../Makefile")
                    361:        test("111/222/../../333/444/../../555/666/../../777/888/9", "111/222/../../777/888/9")
                    362:        test("1/2/3/../../4/5/6/../../7/8/9/../../../../10", "1/2/3/../../4/7/8/9/../../../../10")
                    363:        test("cat/pkg.v1/../../cat/pkg.v2/Makefile", "cat/pkg.v1/../../cat/pkg.v2/Makefile")
                    364:        test("aa/../../../../../a/b/c/d", "aa/../../../../../a/b/c/d")
                    365:        test("aa/bb/../../../../a/b/c/d", "aa/bb/../../../../a/b/c/d")
                    366:        test("aa/bb/cc/../../../a/b/c/d", "aa/bb/cc/../../../a/b/c/d")
                    367:        test("aa/bb/cc/dd/../../a/b/c/d", "aa/bb/a/b/c/d")
                    368:        test("aa/bb/cc/dd/ee/../a/b/c/d", "aa/bb/cc/dd/ee/../a/b/c/d")
                    369:        test("../../../../../a/b/c/d", "../../../../../a/b/c/d")
                    370:        test("aa/../../../../a/b/c/d", "aa/../../../../a/b/c/d")
                    371:        test("aa/bb/../../../a/b/c/d", "aa/bb/../../../a/b/c/d")
                    372:        test("aa/bb/cc/../../a/b/c/d", "aa/bb/cc/../../a/b/c/d")
                    373:        test("aa/bb/cc/dd/../a/b/c/d", "aa/bb/cc/dd/../a/b/c/d")
                    374:        test("aa/../cc/../../a/b/c/d", "aa/../cc/../../a/b/c/d")
                    375:
                    376:        // The initial 2 components of the path are typically category/package, when
                    377:        // pkglint is called from the pkgsrc top-level directory.
                    378:        // This path serves as the context and therefore is always kept.
                    379:        test("aa/bb/../../cc/dd/../../ee/ff", "aa/bb/../../ee/ff")
                    380:        test("aa/bb/../../cc/dd/../..", "aa/bb/../..")
                    381:        test("aa/bb/cc/dd/../..", "aa/bb")
                    382:        test("aa/bb/../../cc/dd/../../ee/ff/buildlink3.mk", "aa/bb/../../ee/ff/buildlink3.mk")
                    383:        test("./aa/bb/../../cc/dd/../../ee/ff/buildlink3.mk", "aa/bb/../../ee/ff/buildlink3.mk")
                    384:
                    385:        test("../.", "..")
                    386:        test("../././././././.", "..")
                    387:        test(".././././././././", "..")
                    388: }
                    389:
1.31      rillig    390: func (s *Suite) Test_pathContains(c *check.C) {
                    391:        t := s.Init(c)
                    392:
                    393:        test := func(haystack, needle string, expected bool) {
                    394:                actual := pathContains(haystack, needle)
1.32      rillig    395:                t.CheckEquals(actual, expected)
1.31      rillig    396:        }
                    397:
                    398:        testPanic := func(haystack, needle string) {
                    399:                t.c.Check(
                    400:                        func() { _ = pathContains(haystack, needle) },
                    401:                        check.PanicMatches,
1.32      rillig    402:                        `runtime error: index out of range.*`)
1.31      rillig    403:        }
                    404:
                    405:        testPanic("", "")
                    406:        testPanic("a", "")
                    407:        testPanic("a/b/c", "")
                    408:
                    409:        test("a", "a", true)
                    410:        test("a", "b", false)
                    411:        test("a", "A", false)
                    412:        test("a/b/c", "a", true)
                    413:        test("a/b/c", "b", true)
                    414:        test("a/b/c", "c", true)
                    415:        test("a/b/c", "a/b", true)
                    416:        test("a/b/c", "b/c", true)
                    417:        test("a/b/c", "a/b/c", true)
                    418:        test("aa/bb/cc", "a/b", false)
                    419:        test("aa/bb/cc", "a/bb", false)
                    420:        test("aa/bb/cc", "aa/b", false)
                    421:        test("aa/bb/cc", "aa/bb", true)
                    422:        test("aa/bb/cc", "a", false)
                    423:        test("aa/bb/cc", "b", false)
                    424:        test("aa/bb/cc", "c", false)
                    425: }
                    426:
                    427: func (s *Suite) Test_pathContainsDir(c *check.C) {
                    428:        t := s.Init(c)
                    429:
1.36      rillig    430:        test := func(haystack, needle Path, expected bool) {
1.31      rillig    431:                actual := pathContainsDir(haystack, needle)
1.32      rillig    432:                t.CheckEquals(actual, expected)
1.31      rillig    433:        }
                    434:
1.36      rillig    435:        testPanic := func(haystack, needle Path) {
1.31      rillig    436:                t.c.Check(
                    437:                        func() { _ = pathContainsDir(haystack, needle) },
                    438:                        check.PanicMatches,
1.32      rillig    439:                        `^runtime error: index out of range.*`)
1.31      rillig    440:        }
                    441:
                    442:        testPanic("", "")
                    443:        testPanic("a", "")
                    444:        testPanic("a/b/c", "")
                    445:
                    446:        test("a", "a", false)
                    447:        test("a", "b", false)
                    448:        test("a", "A", false)
                    449:        test("a/b/c", "a", true)
                    450:        test("a/b/c", "b", true)
                    451:        test("a/b/c", "c", false)
                    452:        test("a/b/c", "a/b", true)
                    453:        test("a/b/c", "b/c", false)
                    454:        test("a/b/c", "a/b/c", false)
                    455:        test("aa/bb/cc", "a/b", false)
                    456:        test("aa/bb/cc", "a/bb", false)
                    457:        test("aa/bb/cc", "aa/b", false)
                    458:        test("aa/bb/cc", "aa/bb", true)
                    459:        test("aa/bb/cc", "a", false)
                    460:        test("aa/bb/cc", "b", false)
                    461:        test("aa/bb/cc", "c", false)
                    462: }
                    463:
1.17      rillig    464: const reMkIncludeBenchmark = `^\.([\t ]*)(s?include)[\t ]+\"([^\"]+)\"[\t ]*(?:#.*)?$`
                    465: const reMkIncludeBenchmarkPositive = `^\.([\t ]*)(s?include)[\t ]+\"(.+)\"[\t ]*(?:#.*)?$`
1.6       rillig    466:
                    467: func Benchmark_match3_buildlink3(b *testing.B) {
                    468:        for i := 0; i < b.N; i++ {
                    469:                match3(".include \"../../category/package/buildlink3.mk\"", reMkIncludeBenchmark)
                    470:        }
                    471: }
                    472:
                    473: func Benchmark_match3_bsd_pkg_mk(b *testing.B) {
                    474:        for i := 0; i < b.N; i++ {
                    475:                match3(".include \"../../mk/bsd.pkg.mk\"", reMkIncludeBenchmark)
                    476:        }
                    477: }
                    478:
1.14      rillig    479: func Benchmark_match3_same_dir(b *testing.B) {
1.6       rillig    480:        for i := 0; i < b.N; i++ {
                    481:                match3(".include \"options.mk\"", reMkIncludeBenchmark)
                    482:        }
                    483: }
                    484:
                    485: func Benchmark_match3_bsd_pkg_mk_comment(b *testing.B) {
                    486:        for i := 0; i < b.N; i++ {
                    487:                match3(".include \"../../mk/bsd.pkg.mk\"          # infrastructure     ", reMkIncludeBenchmark)
                    488:        }
                    489: }
                    490:
                    491: func Benchmark_match3_buildlink3_positive(b *testing.B) {
                    492:        for i := 0; i < b.N; i++ {
                    493:                match3(".include \"../../category/package/buildlink3.mk\"", reMkIncludeBenchmarkPositive)
                    494:        }
                    495: }
                    496:
                    497: func Benchmark_match3_bsd_pkg_mk_positive(b *testing.B) {
                    498:        for i := 0; i < b.N; i++ {
                    499:                match3(".include \"../../mk/bsd.pkg.mk\"", reMkIncludeBenchmarkPositive)
                    500:        }
                    501: }
                    502:
1.14      rillig    503: func Benchmark_match3_same_dir_positive(b *testing.B) {
1.6       rillig    504:        for i := 0; i < b.N; i++ {
                    505:                match3(".include \"options.mk\"", reMkIncludeBenchmarkPositive)
                    506:        }
                    507: }
                    508:
                    509: func Benchmark_match3_bsd_pkg_mk_comment_positive(b *testing.B) {
                    510:        for i := 0; i < b.N; i++ {
                    511:                match3(".include \"../../mk/bsd.pkg.mk\"          # infrastructure     ", reMkIncludeBenchmarkPositive)
                    512:        }
                    513: }
                    514:
                    515: func Benchmark_match3_explicit(b *testing.B) {
                    516:        for i := 0; i < b.N; i++ {
                    517:                MatchMkInclude(".include \"../../mk/bsd.pkg.mk\"          # infrastructure     ")
                    518:        }
                    519: }
1.9       rillig    520:
                    521: func emptyToNil(slice []string) []string {
                    522:        if len(slice) == 0 {
                    523:                return nil
                    524:        }
                    525:        return slice
                    526: }
1.10      rillig    527:
1.35      rillig    528: func (s *Suite) Test_hasAlnumPrefix(c *check.C) {
1.27      rillig    529:        t := s.Init(c)
                    530:
1.35      rillig    531:        t.CheckEquals(hasAlnumPrefix(""), false)
                    532:        t.CheckEquals(hasAlnumPrefix("A"), true)
                    533:        t.CheckEquals(hasAlnumPrefix(","), false)
1.32      rillig    534: }
                    535:
1.35      rillig    536: func (s *Suite) Test_Once(c *check.C) {
1.32      rillig    537:        t := s.Init(c)
                    538:
1.35      rillig    539:        var once Once
1.32      rillig    540:
1.35      rillig    541:        t.CheckEquals(once.FirstTime("str"), true)
                    542:        t.CheckEquals(once.FirstTime("str"), false)
                    543:        t.CheckEquals(once.FirstTimeSlice("str"), false)
                    544:        t.CheckEquals(once.FirstTimeSlice("str", "str2"), true)
                    545:        t.CheckEquals(once.FirstTimeSlice("str", "str2"), false)
                    546: }
1.32      rillig    547:
1.35      rillig    548: func (s *Suite) Test_Once__trace(c *check.C) {
                    549:        t := s.Init(c)
1.32      rillig    550:
1.35      rillig    551:        var once Once
                    552:        once.Trace = true
1.32      rillig    553:
1.35      rillig    554:        t.CheckEquals(once.FirstTime("str"), true)
                    555:        t.CheckEquals(once.FirstTime("str"), false)
                    556:        t.CheckEquals(once.FirstTimeSlice("str"), false)
                    557:        t.CheckEquals(once.FirstTimeSlice("str", "str2"), true)
                    558:        t.CheckEquals(once.FirstTimeSlice("str", "str2"), false)
1.32      rillig    559:
1.35      rillig    560:        t.CheckOutputLines(
                    561:                "FirstTime: str",
                    562:                "FirstTime: str, str2")
1.32      rillig    563: }
                    564:
1.35      rillig    565: func (s *Suite) Test_Scope__no_tracing(c *check.C) {
1.13      rillig    566:        t := s.Init(c)
                    567:
1.35      rillig    568:        scope := NewScope()
                    569:        scope.Define("VAR.param", t.NewMkLine("fname.mk", 3, "VAR.param=\tvalue"))
                    570:        t.DisableTracing()
1.13      rillig    571:
1.35      rillig    572:        t.CheckEquals(scope.IsDefinedSimilar("VAR.param"), true)
                    573:        t.CheckEquals(scope.IsDefinedSimilar("VAR.other"), true)
                    574:        t.CheckEquals(scope.IsDefinedSimilar("OTHER"), false)
                    575: }
1.13      rillig    576:
1.35      rillig    577: func (s *Suite) Test_Scope__commented_varassign(c *check.C) {
                    578:        t := s.Init(c)
1.13      rillig    579:
1.35      rillig    580:        mkline := t.NewMkLine("mk/defaults/mk.conf", 3, "#VAR=default")
                    581:        scope := NewScope()
                    582:        scope.Define("VAR", mkline)
1.13      rillig    583:
1.35      rillig    584:        t.CheckEquals(scope.IsDefined("VAR"), false)
                    585:        t.Check(scope.FirstDefinition("VAR"), check.IsNil)
                    586:        t.Check(scope.LastDefinition("VAR"), check.IsNil)
1.13      rillig    587:
1.35      rillig    588:        t.CheckEquals(scope.Mentioned("VAR"), mkline)
                    589:        t.CheckEquals(scope.Commented("VAR"), mkline)
1.13      rillig    590:
1.35      rillig    591:        value, found := scope.LastValueFound("VAR")
                    592:        t.CheckEquals(value, "")
                    593:        t.CheckEquals(found, false)
1.13      rillig    594: }
                    595:
1.23      rillig    596: func (s *Suite) Test_Scope_Define(c *check.C) {
                    597:        t := s.Init(c)
                    598:
                    599:        scope := NewScope()
                    600:        scope.Define("BUILD_DIRS", t.NewMkLine("file.mk", 121, "BUILD_DIRS=\tone two three"))
                    601:
1.32      rillig    602:        t.CheckEquals(scope.LastValue("BUILD_DIRS"), "one two three")
1.23      rillig    603:
                    604:        scope.Define("BUILD_DIRS", t.NewMkLine("file.mk", 123, "BUILD_DIRS+=\tfour"))
                    605:
1.32      rillig    606:        t.CheckEquals(scope.LastValue("BUILD_DIRS"), "one two three four")
1.23      rillig    607:
                    608:        // Later default assignments do not have an effect.
                    609:        scope.Define("BUILD_DIRS", t.NewMkLine("file.mk", 123, "BUILD_DIRS?=\tdefault"))
                    610:
1.32      rillig    611:        t.CheckEquals(scope.LastValue("BUILD_DIRS"), "one two three four")
1.23      rillig    612: }
                    613:
1.35      rillig    614: func (s *Suite) Test_Scope_Mentioned(c *check.C) {
1.13      rillig    615:        t := s.Init(c)
                    616:
1.35      rillig    617:        assigned := t.NewMkLine("filename.mk", 3, "VAR=\tvalue")
                    618:        commented := t.NewMkLine("filename.mk", 4, "#COMMENTED=\tvalue")
                    619:        documented := t.NewMkLine("filename.mk", 5, "# DOCUMENTED is a variable.")
                    620:
1.13      rillig    621:        scope := NewScope()
1.35      rillig    622:        scope.Define("VAR", assigned)
                    623:        scope.Define("COMMENTED", commented)
                    624:        scope.Define("DOCUMENTED", documented)
1.13      rillig    625:
1.35      rillig    626:        t.CheckEquals(scope.Mentioned("VAR"), assigned)
                    627:        t.CheckEquals(scope.Mentioned("COMMENTED"), commented)
                    628:        t.CheckEquals(scope.Mentioned("DOCUMENTED"), documented)
                    629:        t.Check(scope.Mentioned("UNKNOWN"), check.IsNil)
1.13      rillig    630: }
                    631:
1.35      rillig    632: func (s *Suite) Test_Scope_IsDefined(c *check.C) {
1.13      rillig    633:        t := s.Init(c)
                    634:
                    635:        scope := NewScope()
1.35      rillig    636:        scope.Define("VAR.param", t.NewMkLine("file.mk", 1, "VAR.param=value"))
                    637:
                    638:        t.CheckEquals(scope.IsDefined("VAR.param"), true)
                    639:        t.CheckEquals(scope.IsDefined("VAR.other"), false)
                    640:        t.CheckEquals(scope.IsDefined("VARIABLE.*"), false)
1.13      rillig    641:
1.35      rillig    642:        t.CheckEquals(scope.IsDefinedSimilar("VAR.param"), true)
                    643:        t.CheckEquals(scope.IsDefinedSimilar("VAR.other"), true)
                    644:        t.CheckEquals(scope.IsDefinedSimilar("VARIABLE.*"), false)
1.13      rillig    645: }
                    646:
1.35      rillig    647: func (s *Suite) Test_Scope_IsUsed(c *check.C) {
1.13      rillig    648:        t := s.Init(c)
                    649:
1.35      rillig    650:        scope := NewScope()
                    651:        mkline := t.NewMkLine("file.mk", 1, "\techo ${VAR.param}")
                    652:        scope.Use("VAR.param", mkline, VucRunTime)
1.13      rillig    653:
1.35      rillig    654:        t.CheckEquals(scope.IsUsed("VAR.param"), true)
                    655:        t.CheckEquals(scope.IsUsed("VAR.other"), false)
                    656:        t.CheckEquals(scope.IsUsed("VARIABLE.*"), false)
                    657:
                    658:        t.CheckEquals(scope.IsUsedSimilar("VAR.param"), true)
                    659:        t.CheckEquals(scope.IsUsedSimilar("VAR.other"), true)
                    660:        t.CheckEquals(scope.IsUsedSimilar("VARIABLE.*"), false)
1.13      rillig    661: }
                    662:
1.21      rillig    663: func (s *Suite) Test_Scope_FirstDefinition(c *check.C) {
                    664:        t := s.Init(c)
                    665:
                    666:        mkline1 := t.NewMkLine("fname.mk", 3, "VAR=\tvalue")
1.23      rillig    667:        mkline2 := t.NewMkLine("fname.mk", 3, ".if ${SNEAKY::=value}")
1.21      rillig    668:
                    669:        scope := NewScope()
                    670:        scope.Define("VAR", mkline1)
                    671:        scope.Define("SNEAKY", mkline2)
                    672:
1.32      rillig    673:        t.CheckEquals(scope.FirstDefinition("VAR"), mkline1)
1.21      rillig    674:
                    675:        // This call returns nil because it's not a variable assignment
                    676:        // and the calling code typically assumes a variable definition.
                    677:        // These sneaky variables with implicit definition are an edge
                    678:        // case that only few people actually know. It's better that way.
                    679:        t.Check(scope.FirstDefinition("SNEAKY"), check.IsNil)
                    680: }
                    681:
1.35      rillig    682: func (s *Suite) Test_Scope_Commented(c *check.C) {
                    683:        t := s.Init(c)
                    684:
                    685:        assigned := t.NewMkLine("filename.mk", 3, "VAR=\tvalue")
                    686:        commented := t.NewMkLine("filename.mk", 4, "#COMMENTED=\tvalue")
                    687:        documented := t.NewMkLine("filename.mk", 5, "# DOCUMENTED is a variable.")
                    688:
                    689:        scope := NewScope()
                    690:        scope.Define("VAR", assigned)
                    691:        scope.Define("COMMENTED", commented)
                    692:        scope.Define("DOCUMENTED", documented)
                    693:
                    694:        t.Check(scope.Commented("VAR"), check.IsNil)
                    695:        t.CheckEquals(scope.Commented("COMMENTED"), commented)
                    696:        t.Check(scope.Commented("DOCUMENTED"), check.IsNil)
                    697:        t.Check(scope.Commented("UNKNOWN"), check.IsNil)
                    698: }
                    699:
1.23      rillig    700: func (s *Suite) Test_Scope_LastValue(c *check.C) {
                    701:        t := s.Init(c)
                    702:
                    703:        mklines := t.NewMkLines("file.mk",
1.31      rillig    704:                MkCvsID,
1.23      rillig    705:                "VAR=\tfirst",
                    706:                "VAR=\tsecond",
                    707:                ".if 1",
                    708:                "VAR=\tthird (conditional)",
                    709:                ".endif")
                    710:
                    711:        mklines.Check()
                    712:
1.32      rillig    713:        t.CheckEquals(mklines.vars.LastValue("VAR"), "third (conditional)")
1.23      rillig    714:
                    715:        t.CheckOutputLines(
                    716:                "WARN: file.mk:2: VAR is defined but not used.")
                    717: }
                    718:
1.35      rillig    719: func (s *Suite) Test_Scope_DefineAll(c *check.C) {
1.21      rillig    720:        t := s.Init(c)
                    721:
1.35      rillig    722:        src := NewScope()
1.21      rillig    723:
1.35      rillig    724:        dst := NewScope()
                    725:        dst.DefineAll(src)
1.21      rillig    726:
1.35      rillig    727:        c.Check(dst.firstDef, check.HasLen, 0)
                    728:        c.Check(dst.lastDef, check.HasLen, 0)
                    729:        c.Check(dst.used, check.HasLen, 0)
1.28      rillig    730:
1.35      rillig    731:        src.Define("VAR", t.NewMkLine("file.mk", 1, "VAR=value"))
                    732:        dst.DefineAll(src)
1.28      rillig    733:
1.35      rillig    734:        t.CheckEquals(dst.IsDefined("VAR"), true)
1.28      rillig    735: }
                    736:
1.13      rillig    737: func (s *Suite) Test_naturalLess(c *check.C) {
1.32      rillig    738:        t := s.Init(c)
1.21      rillig    739:
1.32      rillig    740:        var elements = []string{
                    741:                "",
                    742:                // Numbers are always considered smaller than other characters.
                    743:                "0", "000", "0000", "5", "7", "00011", "12", "00012", "000111",
                    744:                "!", "a", "a0", "a ", "aa", "ab", "b"}
1.21      rillig    745:
1.32      rillig    746:        test := func(i int, ie string, j int, je string) {
                    747:                actual := naturalLess(ie, je)
                    748:                expected := i < j
                    749:                if actual != expected {
                    750:                        t.CheckDeepEquals(
                    751:                                []interface{}{i, ie, j, je, actual},
                    752:                                []interface{}{i, ie, j, je, expected})
                    753:                }
                    754:        }
1.21      rillig    755:
1.32      rillig    756:        for i, ie := range elements {
                    757:                for j, je := range elements {
                    758:                        test(i, ie, j, je)
                    759:                }
                    760:        }
1.14      rillig    761: }
                    762:
                    763: func (s *Suite) Test_FileCache(c *check.C) {
                    764:        t := s.Init(c)
                    765:
1.18      rillig    766:        t.EnableTracingToLog()
                    767:
1.14      rillig    768:        cache := NewFileCache(3)
                    769:
                    770:        lines := t.NewLines("Makefile",
1.31      rillig    771:                MkCvsID,
1.14      rillig    772:                "# line 2")
                    773:
                    774:        c.Check(cache.Get("Makefile", 0), check.IsNil)
1.32      rillig    775:        t.CheckEquals(cache.hits, 0)
                    776:        t.CheckEquals(cache.misses, 1)
1.14      rillig    777:
                    778:        cache.Put("Makefile", 0, lines)
                    779:        c.Check(cache.Get("Makefile", MustSucceed|LogErrors), check.IsNil) // Wrong LoadOptions.
                    780:
                    781:        linesFromCache := cache.Get("Makefile", 0)
1.36      rillig    782:        t.CheckEquals(linesFromCache.Filename, NewPath("Makefile"))
1.17      rillig    783:        c.Check(linesFromCache.Lines, check.HasLen, 2)
1.36      rillig    784:        t.CheckEquals(linesFromCache.Lines[0].Filename, NewPath("Makefile"))
1.14      rillig    785:
                    786:        // Cache keys are normalized using path.Clean.
                    787:        linesFromCache2 := cache.Get("./Makefile", 0)
1.36      rillig    788:        t.CheckEquals(linesFromCache2.Filename, NewPath("./Makefile"))
1.17      rillig    789:        c.Check(linesFromCache2.Lines, check.HasLen, 2)
1.36      rillig    790:        t.CheckEquals(linesFromCache2.Lines[0].Filename, NewPath("./Makefile"))
1.14      rillig    791:
                    792:        cache.Put("file1.mk", 0, lines)
                    793:        cache.Put("file2.mk", 0, lines)
                    794:
                    795:        // Now the cache is full. All three entries can be retrieved.
                    796:        c.Check(cache.Get("Makefile", 0), check.NotNil)
                    797:        c.Check(cache.Get("file1.mk", 0), check.NotNil)
                    798:        c.Check(cache.Get("file2.mk", 0), check.NotNil)
                    799:
                    800:        // Adding another entry removes all entries with minimum count,
                    801:        // which currently are file1.mk and file2.mk.
                    802:        // Makefile is still in the cache because it was accessed once.
                    803:        cache.Put("file3.mk", 0, lines)
                    804:
                    805:        c.Check(cache.Get("Makefile", 0), check.NotNil)
                    806:        c.Check(cache.Get("file1.mk", 0), check.IsNil)
                    807:        c.Check(cache.Get("file2.mk", 0), check.IsNil)
                    808:        c.Check(cache.Get("file3.mk", 0), check.NotNil)
                    809:
                    810:        cache.Evict("Makefile")
                    811:
                    812:        c.Check(cache.Get("Makefile", 0), check.IsNil)
                    813:        c.Check(cache.table, check.HasLen, 1)
                    814:        c.Check(cache.mapping, check.HasLen, 1)
1.32      rillig    815:        t.CheckEquals(cache.hits, 7)
                    816:        t.CheckEquals(cache.misses, 5)
1.17      rillig    817:
                    818:        t.CheckOutputLines(
1.18      rillig    819:                "TRACE:   FileCache \"Makefile\" with count 4.",
                    820:                "TRACE:   FileCache \"file1.mk\" with count 2.",
                    821:                "TRACE:   FileCache \"file2.mk\" with count 2.",
                    822:                "TRACE:   FileCache.Evict \"file2.mk\" with count 2.",
                    823:                "TRACE:   FileCache.Evict \"file1.mk\" with count 2.",
                    824:                "TRACE:   FileCache.Halve \"Makefile\" with count 4.")
1.17      rillig    825: }
                    826:
1.29      rillig    827: func (s *Suite) Test_FileCache_removeOldEntries__branch_coverage(c *check.C) {
                    828:        t := s.Init(c)
                    829:
                    830:        t.EnableTracingToLog()
                    831:        G.Testing = false
                    832:
                    833:        lines := t.NewLines("filename.mk",
1.31      rillig    834:                MkCvsID)
1.29      rillig    835:        cache := NewFileCache(3)
                    836:        cache.Put("filename1.mk", 0, lines)
                    837:        cache.Put("filename2.mk", 0, lines)
                    838:        cache.Get("filename2.mk", 0)
                    839:        cache.Get("filename2.mk", 0)
                    840:        cache.Put("filename3.mk", 0, lines)
                    841:        cache.Put("filename4.mk", 0, lines)
                    842:
                    843:        t.CheckOutputLines(
                    844:                "TRACE:   FileCache.Evict \"filename3.mk\" with count 1.",
                    845:                "TRACE:   FileCache.Evict \"filename1.mk\" with count 1.",
                    846:                "TRACE:   FileCache.Halve \"filename2.mk\" with count 3.")
                    847: }
                    848:
1.30      rillig    849: func (s *Suite) Test_FileCache_removeOldEntries__no_tracing(c *check.C) {
                    850:        t := s.Init(c)
                    851:
                    852:        t.DisableTracing()
                    853:
                    854:        lines := t.NewLines("filename.mk",
1.31      rillig    855:                MkCvsID)
1.30      rillig    856:        cache := NewFileCache(3)
                    857:        cache.Put("filename1.mk", 0, lines)
                    858:        cache.Put("filename2.mk", 0, lines)
                    859:        cache.Get("filename2.mk", 0)
                    860:        cache.Get("filename2.mk", 0)
                    861:        cache.Put("filename3.mk", 0, lines)
                    862:        cache.Put("filename4.mk", 0, lines)
                    863:
                    864:        t.CheckOutputEmpty()
                    865: }
                    866:
                    867: // Covers the newLen > 0 condition.
                    868: func (s *Suite) Test_FileCache_removeOldEntries__zero_capacity(c *check.C) {
                    869:        t := s.Init(c)
                    870:
                    871:        lines := t.NewLines("filename.mk",
1.31      rillig    872:                MkCvsID)
1.30      rillig    873:        cache := NewFileCache(1)
                    874:        cache.Put("filename1.mk", 0, lines)
                    875:
                    876:        // This call removes all existing entries from the cache,
                    877:        // as the cache's capacity is only 1.
                    878:        cache.Put("filename2.mk", 0, lines)
                    879: }
                    880:
                    881: func (s *Suite) Test_FileCache_Evict__sort(c *check.C) {
                    882:        t := s.Init(c)
                    883:
                    884:        lines := t.NewLines("filename.mk",
1.31      rillig    885:                MkCvsID)
1.30      rillig    886:        cache := NewFileCache(10)
                    887:        cache.Put("filename0.mk", 0, lines)
                    888:        cache.Put("filename1.mk", 0, lines)
                    889:        cache.Put("filename2.mk", 0, lines)
                    890:        cache.Put("filename3.mk", 0, lines)
                    891:        cache.Put("filename4.mk", 0, lines)
                    892:        cache.Put("filename5.mk", 0, lines)
                    893:        cache.Put("filename6.mk", 0, lines)
                    894:        cache.Put("filename7.mk", 0, lines)
                    895:        cache.Put("filename8.mk", 0, lines)
                    896:        cache.Put("filename9.mk", 0, lines)
                    897:
                    898:        cache.Evict("filename5.mk")
                    899:
                    900:        t.Check(cache.table, check.HasLen, 9)
                    901:        t.Check(cache.Get("filename5.mk", 0), check.IsNil)
                    902:        t.Check(cache.Get("filename6.mk", 0), check.NotNil)
                    903: }
                    904:
1.34      rillig    905: func (s *Suite) Test_bmakeHelp(c *check.C) {
1.32      rillig    906:        t := s.Init(c)
                    907:
1.34      rillig    908:        t.CheckEquals(bmakeHelp("subst"), confMake+" help topic=subst")
1.13      rillig    909: }
1.18      rillig    910:
                    911: func (s *Suite) Test_wrap(c *check.C) {
1.32      rillig    912:        t := s.Init(c)
1.18      rillig    913:
                    914:        wrapped := wrap(20,
                    915:                "See the pkgsrc guide, section \"Package components, Makefile\":",
                    916:                "https://www.NetBSD.org/doc/pkgsrc/pkgsrc.html#components.Makefile.",
                    917:                "",
                    918:                "For more information, ask on the tech-pkg@NetBSD.org mailing list.",
                    919:                "",
                    920:                "\tpreformatted line 1",
                    921:                "\tpreformatted line 2",
                    922:                "",
                    923:                "    intentionally indented",
                    924:                "*   itemization",
                    925:                "",
                    926:                "Normal",
                    927:                "text",
                    928:                "continues",
                    929:                "here",
                    930:                "with",
                    931:                "linebreaks.",
                    932:                "",
1.22      rillig    933:                "Sentence one.  Sentence two.",
                    934:                "",
                    935:                "A\tB\tC\tD",
                    936:                "E\tveryVeryVeryVeryVeryVeryVeryVeryLong")
1.18      rillig    937:
                    938:        expected := []string{
                    939:                "See the pkgsrc",
                    940:                "guide, section",
                    941:                "\"Package components,",
                    942:                "Makefile\":",
                    943:                "https://www.NetBSD.org/doc/pkgsrc/pkgsrc.html#components.Makefile.",
                    944:                "",
                    945:                "For more",
                    946:                "information, ask on",
                    947:                "the",
                    948:                "tech-pkg@NetBSD.org",
                    949:                "mailing list.",
                    950:                "",
                    951:                "\tpreformatted line 1",
                    952:                "\tpreformatted line 2",
                    953:                "",
                    954:                "    intentionally indented",
                    955:                "*   itemization",
                    956:                "",
                    957:                "Normal text",
                    958:                "continues here with",
                    959:                "linebreaks.",
                    960:                "",
                    961:                "Sentence one.",
1.22      rillig    962:                "Sentence two.",
                    963:                "",
                    964:                "A\tB\tC\tD E",
                    965:                "veryVeryVeryVeryVeryVeryVeryVeryLong"}
1.18      rillig    966:
1.32      rillig    967:        t.CheckDeepEquals(wrapped, expected)
1.18      rillig    968: }
                    969:
                    970: func (s *Suite) Test_escapePrintable(c *check.C) {
1.32      rillig    971:        t := s.Init(c)
                    972:
                    973:        t.CheckEquals(escapePrintable(""), "")
                    974:        t.CheckEquals(escapePrintable("ASCII only~\n\t"), "ASCII only~\n\t")
                    975:        t.CheckEquals(escapePrintable("Beep \u0007 control \u001F"), "Beep <U+0007> control <U+001F>")
                    976:        t.CheckEquals(escapePrintable("Bad \xFF character"), "Bad <0xFF> character")
                    977:        t.CheckEquals(escapePrintable("Unicode \uFFFD replacement"), "Unicode <U+FFFD> replacement")
1.18      rillig    978: }
1.22      rillig    979:
                    980: func (s *Suite) Test_stringSliceLess(c *check.C) {
1.32      rillig    981:        t := s.Init(c)
                    982:
1.22      rillig    983:        var elements = [][][]string{
                    984:                {nil, {}},
                    985:                {{"a"}},
                    986:                {{"a", "a"}},
                    987:                {{"a", "b"}},
                    988:                {{"b"}},
                    989:                {{"b", "a"}}}
                    990:
                    991:        test := func(i int, iElement []string, j int, jElement []string) {
                    992:                actual := stringSliceLess(iElement, jElement)
                    993:                expected := i < j
                    994:                if actual != expected {
1.32      rillig    995:                        t.CheckDeepEquals(
1.22      rillig    996:                                []interface{}{i, iElement, j, jElement, actual},
                    997:                                []interface{}{i, iElement, j, jElement, expected})
                    998:                }
                    999:        }
                   1000:
                   1001:        for i, iElements := range elements {
                   1002:                for j, jElements := range elements {
                   1003:                        for _, iElement := range iElements {
                   1004:                                for _, jElement := range jElements {
                   1005:                                        test(i, iElement, j, jElement)
                   1006:                                }
                   1007:                        }
                   1008:                }
                   1009:        }
                   1010: }
                   1011:
                   1012: func (s *Suite) Test_joinSkipEmpty(c *check.C) {
                   1013:        t := s.Init(c)
                   1014:
1.32      rillig   1015:        t.CheckDeepEquals(
1.22      rillig   1016:                joinSkipEmpty(", ", "", "one", "", "", "two", "", "three"),
                   1017:                "one, two, three")
                   1018: }
                   1019:
                   1020: func (s *Suite) Test_joinSkipEmptyCambridge(c *check.C) {
                   1021:        t := s.Init(c)
                   1022:
1.32      rillig   1023:        t.CheckDeepEquals(
1.22      rillig   1024:                joinSkipEmptyCambridge("and", "", "one", "", "", "two", "", "three"),
                   1025:                "one, two and three")
                   1026:
1.32      rillig   1027:        t.CheckDeepEquals(
1.22      rillig   1028:                joinSkipEmptyCambridge("and", "", "one", "", ""),
                   1029:                "one")
                   1030: }
                   1031:
                   1032: func (s *Suite) Test_joinSkipEmptyOxford(c *check.C) {
                   1033:        t := s.Init(c)
                   1034:
1.32      rillig   1035:        t.CheckDeepEquals(
1.22      rillig   1036:                joinSkipEmptyOxford("and", "", "one", "", "", "two", "", "three"),
                   1037:                "one, two, and three")
                   1038: }
                   1039:
1.31      rillig   1040: func (s *Suite) Test_newPathMatcher(c *check.C) {
                   1041:        t := s.Init(c)
                   1042:
                   1043:        test := func(pattern string, matchType pathMatchType, matchPattern string) {
1.32      rillig   1044:                t.CheckEquals(*newPathMatcher(pattern), pathMatcher{matchType, matchPattern, pattern})
1.31      rillig   1045:        }
                   1046:
                   1047:        testPanic := func(pattern string) {
                   1048:                t.ExpectPanic(
                   1049:                        func() { _ = newPathMatcher(pattern) },
                   1050:                        "Pkglint internal error")
                   1051:        }
                   1052:
                   1053:        testPanic("*.[0123456]")
                   1054:        testPanic("file.???")
                   1055:        testPanic("*.???")
                   1056:        test("", pmExact, "")
                   1057:        test("exact", pmExact, "exact")
                   1058:        test("*.mk", pmSuffix, ".mk")
                   1059:        test("Makefile.*", pmPrefix, "Makefile.")
                   1060:        testPanic("*.*")
                   1061:        testPanic("**")
                   1062:        testPanic("a*b")
                   1063:        testPanic("[")
                   1064:        testPanic("malformed[")
                   1065: }
                   1066:
                   1067: func (s *Suite) Test_pathMatcher_matches(c *check.C) {
1.32      rillig   1068:        t := s.Init(c)
1.31      rillig   1069:
                   1070:        test := func(pattern string, subject string, expected bool) {
                   1071:                matcher := newPathMatcher(pattern)
1.32      rillig   1072:                t.CheckEquals(matcher.matches(subject), expected)
1.31      rillig   1073:        }
                   1074:
                   1075:        test("", "", true)
                   1076:        test("", "any", false)
                   1077:        test("exact", "exact", true)
                   1078:        test("exact", "different", false)
                   1079:
                   1080:        test("*.mk", "filename.mk", true)
                   1081:        test("*.mk", "filename.txt", false)
                   1082:        test("*.mk", "filename.mkx", false)
                   1083:        test("*.mk", ".mk", true)
                   1084:
                   1085:        test("Makefile.*", "Makefile", false)
                   1086:        test("Makefile.*", "Makefile.", true)
                   1087:        test("Makefile.*", "Makefile.txt", true)
                   1088:        test("Makefile.*", "makefile.txt", false)
                   1089: }
                   1090:
1.22      rillig   1091: func (s *Suite) Test_StringInterner(c *check.C) {
                   1092:        t := s.Init(c)
                   1093:
                   1094:        si := NewStringInterner()
                   1095:
1.32      rillig   1096:        t.CheckEquals(si.Intern(""), "")
                   1097:        t.CheckEquals(si.Intern("Hello"), "Hello")
                   1098:        t.CheckEquals(si.Intern("Hello, world"), "Hello, world")
                   1099:        t.CheckEquals(si.Intern("Hello, world"[0:5]), "Hello")
1.22      rillig   1100: }
1.34      rillig   1101:
                   1102: func (s *Suite) Test_shquote(c *check.C) {
                   1103:        t := s.Init(c)
                   1104:
                   1105:        test := func(in, out string) {
                   1106:                t.CheckEquals(shquote(in), out)
                   1107:        }
                   1108:
                   1109:        test("", "''")
                   1110:        test("'", "''\\'''")
                   1111:        test("simple", "simple")
                   1112:        test("~", "'~'")
                   1113: }

CVSweb <webmaster@jp.NetBSD.org>