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

Annotation of pkgsrc/pkgtools/pkglint/files/mklinechecker_test.go, Revision 1.9

1.1       rillig      1: package main
                      2:
                      3: import "gopkg.in/check.v1"
                      4:
                      5: func (s *Suite) Test_MkLineChecker_CheckVartype__simple_type(c *check.C) {
1.5       rillig      6:        t := s.Init(c)
                      7:
                      8:        t.SetupCommandLine("-Wtypes")
1.9     ! rillig      9:        t.SetupVartypes()
1.5       rillig     10:        mkline := t.NewMkLine("fname", 1, "COMMENT=\tA nice package")
1.1       rillig     11:
1.9     ! rillig     12:        vartype1 := G.Pkgsrc.vartypes["COMMENT"]
1.1       rillig     13:        c.Assert(vartype1, check.NotNil)
                     14:        c.Check(vartype1.guessed, equals, false)
                     15:
1.2       rillig     16:        vartype := mkline.VariableType("COMMENT")
1.1       rillig     17:
                     18:        c.Assert(vartype, check.NotNil)
                     19:        c.Check(vartype.basicType.name, equals, "Comment")
                     20:        c.Check(vartype.guessed, equals, false)
                     21:        c.Check(vartype.kindOfList, equals, lkNone)
                     22:
                     23:        MkLineChecker{mkline}.CheckVartype("COMMENT", opAssign, "A nice package", "")
                     24:
1.5       rillig     25:        t.CheckOutputLines(
                     26:                "WARN: fname:1: COMMENT should not begin with \"A\".")
1.1       rillig     27: }
                     28:
                     29: func (s *Suite) Test_MkLineChecker_CheckVartype(c *check.C) {
1.5       rillig     30:        t := s.Init(c)
                     31:
1.9     ! rillig     32:        t.SetupVartypes()
1.5       rillig     33:        mkline := t.NewMkLine("fname", 1, "DISTNAME=gcc-${GCC_VERSION}")
1.1       rillig     34:
                     35:        MkLineChecker{mkline}.CheckVartype("DISTNAME", opAssign, "gcc-${GCC_VERSION}", "")
1.5       rillig     36:
                     37:        t.CheckOutputEmpty()
1.1       rillig     38: }
                     39:
                     40: // Pkglint once interpreted all lists as consisting of shell tokens,
1.5       rillig     41: // splitting this URL at the ampersand.
1.1       rillig     42: func (s *Suite) Test_MkLineChecker_checkVarassign__URL_with_shell_special_characters(c *check.C) {
1.5       rillig     43:        t := s.Init(c)
                     44:
1.1       rillig     45:        G.Pkg = NewPackage("graphics/gimp-fix-ca")
1.9     ! rillig     46:        t.SetupVartypes()
1.5       rillig     47:        mkline := t.NewMkLine("fname", 10, "MASTER_SITES=http://registry.gimp.org/file/fix-ca.c?action=download&id=9884&file=")
1.1       rillig     48:
                     49:        MkLineChecker{mkline}.checkVarassign()
                     50:
1.5       rillig     51:        t.CheckOutputEmpty()
1.1       rillig     52: }
                     53:
                     54: func (s *Suite) Test_MkLineChecker_Check__conditions(c *check.C) {
1.5       rillig     55:        t := s.Init(c)
                     56:
                     57:        t.SetupCommandLine("-Wtypes")
1.9     ! rillig     58:        t.SetupVartypes()
1.1       rillig     59:
1.5       rillig     60:        MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(PKGSRC_COMPILER:Mmycc)")}.CheckCond()
1.1       rillig     61:
1.5       rillig     62:        t.CheckOutputLines(
                     63:                "WARN: fname:1: The pattern \"mycc\" cannot match any of " +
                     64:                        "{ ccache ccc clang distcc f2c gcc hp icc ido " +
                     65:                        "mipspro mipspro-ucode pcc sunpro xlc } for PKGSRC_COMPILER.")
1.1       rillig     66:
1.5       rillig     67:        MkLineChecker{t.NewMkLine("fname", 1, ".elif ${A} != ${B}")}.CheckCond()
1.1       rillig     68:
1.5       rillig     69:        t.CheckOutputEmpty()
1.1       rillig     70:
1.5       rillig     71:        MkLineChecker{t.NewMkLine("fname", 1, ".if ${HOMEPAGE} == \"mailto:someone@example.org\"")}.CheckCond()
1.1       rillig     72:
1.5       rillig     73:        t.CheckOutputLines(
1.2       rillig     74:                "WARN: fname:1: \"mailto:someone@example.org\" is not a valid URL.")
1.1       rillig     75:
1.5       rillig     76:        MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(PKGSRC_RUN_TEST:M[Y][eE][sS])")}.CheckCond()
1.1       rillig     77:
1.5       rillig     78:        t.CheckOutputLines(
1.2       rillig     79:                "WARN: fname:1: PKGSRC_RUN_TEST should be matched against \"[yY][eE][sS]\" or \"[nN][oO]\", not \"[Y][eE][sS]\".")
1.1       rillig     80:
1.5       rillig     81:        MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(IS_BUILTIN.Xfixes:M[yY][eE][sS])")}.CheckCond()
1.1       rillig     82:
1.5       rillig     83:        t.CheckOutputEmpty()
1.1       rillig     84:
1.5       rillig     85:        MkLineChecker{t.NewMkLine("fname", 1, ".if !empty(${IS_BUILTIN.Xfixes:M[yY][eE][sS]})")}.CheckCond()
1.1       rillig     86:
1.5       rillig     87:        t.CheckOutputLines(
1.2       rillig     88:                "WARN: fname:1: The empty() function takes a variable name as parameter, not a variable expression.")
1.1       rillig     89:
1.5       rillig     90:        MkLineChecker{t.NewMkLine("fname", 1, ".if ${EMUL_PLATFORM} == \"linux-x386\"")}.CheckCond()
1.1       rillig     91:
1.5       rillig     92:        t.CheckOutputLines(
                     93:                "WARN: fname:1: " +
                     94:                        "\"x386\" is not valid for the hardware architecture part of EMUL_PLATFORM. " +
                     95:                        "Use one of " +
                     96:                        "{ aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex " +
                     97:                        "dreamcast earm earmeb earmhf earmhfeb earmv4 earmv4eb earmv5 earmv5eb earmv6 earmv6eb " +
                     98:                        "earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 " +
                     99:                        "i386 i586 i686 ia64 m68000 m68k m88k mips mips64 mips64eb mips64el mipseb mipsel mipsn32 " +
                    100:                        "mlrisc ns32k pc532 pmax powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 " +
                    101:                        "} instead.")
                    102:
                    103:        MkLineChecker{t.NewMkLine("fname", 1, ".if ${EMUL_PLATFORM:Mlinux-x386}")}.CheckCond()
                    104:
                    105:        t.CheckOutputLines(
                    106:                "WARN: fname:1: " +
                    107:                        "The pattern \"x386\" cannot match any of { aarch64 aarch64eb alpha amd64 arc arm arm26 " +
                    108:                        "arm32 cobalt coldfire convex dreamcast earm earmeb earmhf earmhfeb earmv4 earmv4eb " +
                    109:                        "earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb earmv7 earmv7eb earmv7hf " +
                    110:                        "earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 m68000 m68k m88k " +
                    111:                        "mips mips64 mips64eb mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax powerpc powerpc64 " +
                    112:                        "rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 } " +
                    113:                        "for the hardware architecture part of EMUL_PLATFORM.")
                    114:
                    115:        MkLineChecker{t.NewMkLine("fname", 98, ".if ${MACHINE_PLATFORM:MUnknownOS-*-*} || ${MACHINE_ARCH:Mx86}")}.CheckCond()
                    116:
                    117:        t.CheckOutputLines(
                    118:                "WARN: fname:98: "+
                    119:                        "The pattern \"UnknownOS\" cannot match any of "+
                    120:                        "{ AIX BSDOS Bitrig Cygwin Darwin DragonFly FreeBSD FreeMiNT GNUkFreeBSD HPUX Haiku "+
                    121:                        "IRIX Interix Linux Minix MirBSD NetBSD OSF1 OpenBSD QNX SCO_SV SunOS UnixWare "+
                    122:                        "} for the operating system part of MACHINE_PLATFORM.",
                    123:                "WARN: fname:98: "+
                    124:                        "The pattern \"x86\" cannot match any of "+
                    125:                        "{ aarch64 aarch64eb alpha amd64 arc arm arm26 arm32 cobalt coldfire convex dreamcast earm "+
                    126:                        "earmeb earmhf earmhfeb earmv4 earmv4eb earmv5 earmv5eb earmv6 earmv6eb earmv6hf earmv6hfeb "+
                    127:                        "earmv7 earmv7eb earmv7hf earmv7hfeb evbarm hpcmips hpcsh hppa hppa64 i386 i586 i686 ia64 "+
                    128:                        "m68000 m68k m88k mips mips64 mips64eb mips64el mipseb mipsel mipsn32 mlrisc ns32k pc532 pmax "+
                    129:                        "powerpc powerpc64 rs6000 s390 sh3eb sh3el sparc sparc64 vax x86_64 "+
                    130:                        "} for MACHINE_ARCH.")
1.1       rillig    131: }
                    132:
                    133: func (s *Suite) Test_MkLineChecker_checkVarassign(c *check.C) {
1.5       rillig    134:        t := s.Init(c)
                    135:
1.9     ! rillig    136:        t.SetupVartypes()
1.1       rillig    137:
1.5       rillig    138:        G.Mk = t.NewMkLines("Makefile",
1.7       rillig    139:                MkRcsID,
1.1       rillig    140:                "ac_cv_libpari_libs+=\t-L${BUILDLINK_PREFIX.pari}/lib") // From math/clisp-pari/Makefile, rev. 1.8
                    141:
                    142:        MkLineChecker{G.Mk.mklines[1]}.checkVarassign()
                    143:
1.5       rillig    144:        t.CheckOutputLines(
1.2       rillig    145:                "WARN: Makefile:2: ac_cv_libpari_libs is defined but not used. Spelling mistake?")
1.1       rillig    146: }
                    147:
                    148: func (s *Suite) Test_MkLineChecker_checkVarassignDefPermissions(c *check.C) {
1.5       rillig    149:        t := s.Init(c)
                    150:
                    151:        t.SetupCommandLine("-Wall")
1.9     ! rillig    152:        t.SetupVartypes()
1.5       rillig    153:        mkline := t.NewMkLine("options.mk", 2, "PKG_DEVELOPER?=\tyes")
1.1       rillig    154:
                    155:        MkLineChecker{mkline}.checkVarassignDefPermissions()
                    156:
1.5       rillig    157:        t.CheckOutputLines(
1.2       rillig    158:                "WARN: options.mk:2: The variable PKG_DEVELOPER may not be given a default value by any package.")
1.1       rillig    159: }
                    160:
                    161: func (s *Suite) Test_MkLineChecker_CheckVarusePermissions(c *check.C) {
1.5       rillig    162:        t := s.Init(c)
                    163:
                    164:        t.SetupCommandLine("-Wall")
1.9     ! rillig    165:        t.SetupVartypes()
1.5       rillig    166:        mklines := t.NewMkLines("options.mk",
1.7       rillig    167:                MkRcsID,
1.1       rillig    168:                "COMMENT=\t${GAMES_USER}",
                    169:                "COMMENT:=\t${PKGBASE}",
                    170:                "PYPKGPREFIX=${PKGBASE}")
1.9     ! rillig    171:        G.Pkgsrc.UserDefinedVars = map[string]MkLine{
1.1       rillig    172:                "GAMES_USER": mklines.mklines[0],
                    173:        }
                    174:
                    175:        mklines.Check()
                    176:
1.5       rillig    177:        t.CheckOutputLines(
1.2       rillig    178:                "WARN: options.mk:3: PKGBASE should not be evaluated at load time.",
                    179:                "WARN: options.mk:4: The variable PYPKGPREFIX may not be set in this file; it would be ok in pyversion.mk.",
                    180:                "WARN: options.mk:4: PKGBASE should not be evaluated indirectly at load time.",
                    181:                "NOTE: options.mk:4: This variable value should be aligned to column 17.")
1.1       rillig    182: }
                    183:
                    184: func (s *Suite) Test_MkLineChecker_CheckVarusePermissions__load_time(c *check.C) {
1.5       rillig    185:        t := s.Init(c)
                    186:
                    187:        t.SetupCommandLine("-Wall")
1.9     ! rillig    188:        t.SetupVartypes()
1.5       rillig    189:        mklines := t.NewMkLines("options.mk",
1.7       rillig    190:                MkRcsID,
1.1       rillig    191:                "WRKSRC:=${.CURDIR}")
                    192:
                    193:        mklines.Check()
                    194:
1.5       rillig    195:        // Don't warn that ".CURDIR should not be evaluated at load time."
                    196:        t.CheckOutputLines(
                    197:                "NOTE: options.mk:2: This variable value should be aligned to column 17.")
1.1       rillig    198: }
                    199:
                    200: func (s *Suite) Test_MkLineChecker_WarnVaruseLocalbase(c *check.C) {
1.5       rillig    201:        t := s.Init(c)
                    202:
                    203:        mkline := t.NewMkLine("options.mk", 56, "PKGNAME=${LOCALBASE}")
1.1       rillig    204:
                    205:        MkLineChecker{mkline}.WarnVaruseLocalbase()
                    206:
1.5       rillig    207:        t.CheckOutputLines(
1.8       rillig    208:                "WARN: options.mk:56: Please use PREFIX instead of LOCALBASE.")
1.1       rillig    209: }
                    210:
                    211: func (s *Suite) Test_MkLineChecker_CheckRelativePkgdir(c *check.C) {
1.5       rillig    212:        t := s.Init(c)
                    213:
                    214:        mkline := t.NewMkLine("Makefile", 46, "# dummy")
1.1       rillig    215:
                    216:        MkLineChecker{mkline}.CheckRelativePkgdir("../pkgbase")
                    217:
1.5       rillig    218:        t.CheckOutputLines(
1.2       rillig    219:                "ERROR: Makefile:46: \"../pkgbase\" does not exist.",
                    220:                "WARN: Makefile:46: \"../pkgbase\" is not a valid relative package directory.")
1.1       rillig    221: }
                    222:
                    223: // PR pkg/46570, item 2
                    224: func (s *Suite) Test_MkLineChecker__unclosed_varuse(c *check.C) {
1.5       rillig    225:        t := s.Init(c)
                    226:
1.8       rillig    227:        mklines := t.NewMkLines("Makefile",
                    228:                MkRcsID,
                    229:                "EGDIRS=${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d")
1.1       rillig    230:
1.8       rillig    231:        mklines.Check()
1.1       rillig    232:
1.5       rillig    233:        t.CheckOutputLines(
1.8       rillig    234:                "WARN: Makefile:2: Unclosed Make variable starting at \"${EGDIR/apparmor.d $...\"",
                    235:                "WARN: Makefile:2: EGDIRS is defined but not used. Spelling mistake?",
                    236:                "WARN: Makefile:2: Pkglint parse error in MkLine.Tokenize at "+
                    237:                        "\"${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d\".")
1.1       rillig    238: }
                    239:
                    240: func (s *Suite) Test_MkLineChecker__Varuse_Modifier_L(c *check.C) {
1.5       rillig    241:        t := s.Init(c)
                    242:
                    243:        t.SetupCommandLine("-Wall")
1.9     ! rillig    244:        t.SetupVartypes()
1.5       rillig    245:        G.Mk = t.NewMkLines("x11/xkeyboard-config/Makefile",
1.1       rillig    246:                "FILES_SUBST+=XKBCOMP_SYMLINK=${${XKBBASE}/xkbcomp:L:Q}")
                    247:
                    248:        MkLineChecker{G.Mk.mklines[0]}.Check()
                    249:
1.5       rillig    250:        // Don't warn that ${XKBBASE}/xkbcomp is used but not defined.
                    251:        t.CheckOutputEmpty()
1.1       rillig    252: }
                    253:
                    254: func (s *Suite) Test_MkLineChecker_CheckCond__comparison_with_shell_command(c *check.C) {
1.5       rillig    255:        t := s.Init(c)
                    256:
                    257:        t.SetupCommandLine("-Wall")
1.9     ! rillig    258:        t.SetupVartypes()
1.5       rillig    259:        G.Mk = t.NewMkLines("security/openssl/Makefile",
1.7       rillig    260:                MkRcsID,
1.1       rillig    261:                ".if ${PKGSRC_COMPILER} == \"gcc\" && ${CC} == \"cc\"",
                    262:                ".endif")
                    263:
                    264:        G.Mk.Check()
                    265:
                    266:        // Don't warn about unknown shell command "cc".
1.5       rillig    267:        t.CheckOutputLines(
1.2       rillig    268:                "WARN: security/openssl/Makefile:2: Use ${PKGSRC_COMPILER:Mgcc} instead of the == operator.")
1.1       rillig    269: }
                    270:
                    271: func (s *Suite) Test_MkLine_CheckCond_comparing_PKGSRC_COMPILER_with_eqeq(c *check.C) {
1.5       rillig    272:        t := s.Init(c)
                    273:
                    274:        t.SetupCommandLine("-Wall")
1.9     ! rillig    275:        t.SetupVartypes()
1.5       rillig    276:        G.Mk = t.NewMkLines("audio/pulseaudio/Makefile",
1.7       rillig    277:                MkRcsID,
1.1       rillig    278:                ".if ${OPSYS} == \"Darwin\" && ${PKGSRC_COMPILER} == \"clang\"",
                    279:                ".endif")
                    280:
                    281:        G.Mk.Check()
                    282:
1.5       rillig    283:        t.CheckOutputLines(
1.2       rillig    284:                "WARN: audio/pulseaudio/Makefile:2: Use ${PKGSRC_COMPILER:Mclang} instead of the == operator.")
1.1       rillig    285: }
                    286:
                    287: func (s *Suite) Test_MkLineChecker_CheckVartype__CFLAGS_with_backticks(c *check.C) {
1.5       rillig    288:        t := s.Init(c)
                    289:
                    290:        t.SetupCommandLine("-Wall")
1.9     ! rillig    291:        t.SetupVartypes()
1.5       rillig    292:        G.Mk = t.NewMkLines("chat/pidgin-icb/Makefile",
1.7       rillig    293:                MkRcsID,
1.1       rillig    294:                "CFLAGS+=\t`pkg-config pidgin --cflags`")
                    295:        mkline := G.Mk.mklines[1]
                    296:
1.3       rillig    297:        words, rest := splitIntoMkWords(mkline.Line, mkline.Value())
1.1       rillig    298:
                    299:        c.Check(words, deepEquals, []string{"`pkg-config pidgin --cflags`"})
                    300:        c.Check(rest, equals, "")
                    301:
                    302:        MkLineChecker{G.Mk.mklines[1]}.CheckVartype("CFLAGS", opAssignAppend, "`pkg-config pidgin --cflags`", "")
                    303:
1.5       rillig    304:        // No warning about "`pkg-config" being an unknown CFlag.
                    305:        t.CheckOutputEmpty()
1.1       rillig    306: }
                    307:
                    308: // See PR 46570, Ctrl+F "4. Shell quoting".
                    309: // Pkglint is correct, since the shell sees this definition for
                    310: // CPPFLAGS as three words, not one word.
                    311: func (s *Suite) Test_MkLineChecker_CheckVartype_CFLAGS(c *check.C) {
1.5       rillig    312:        t := s.Init(c)
                    313:
1.9     ! rillig    314:        t.SetupVartypes()
1.5       rillig    315:        mklines := t.NewMkLines("Makefile",
1.7       rillig    316:                MkRcsID,
1.1       rillig    317:                "CPPFLAGS.SunOS+=\t-DPIPECOMMAND=\\\"/usr/sbin/sendmail -bs %s\\\"")
                    318:
                    319:        mklines.Check()
                    320:
1.5       rillig    321:        t.CheckOutputLines(
1.2       rillig    322:                "WARN: Makefile:2: Unknown compiler flag \"-bs\".",
                    323:                "WARN: Makefile:2: Compiler flag \"%s\\\\\\\"\" should start with a hyphen.")
1.1       rillig    324: }
1.6       rillig    325:
                    326: // Up to 2018-01-28, pkglint applied the autofix also to the continuation
                    327: // lines, which is incorrect. It replaced the dot in "4.*" with spaces.
                    328: func (s *Suite) Test_MkLineChecker_checkDirectiveIndentation_autofix(c *check.C) {
                    329:        t := s.Init(c)
                    330:
                    331:        t.SetupCommandLine("-Wall", "--autofix")
1.9     ! rillig    332:        t.SetupVartypes()
1.6       rillig    333:        lines := t.SetupFileLinesContinuation("options.mk",
1.7       rillig    334:                MkRcsID,
1.6       rillig    335:                ".if ${PKGNAME} == pkgname",
                    336:                ".if \\",
                    337:                "   ${PLATFORM:MNetBSD-4.*}",
                    338:                ".endif",
                    339:                ".endif")
                    340:        mklines := NewMkLines(lines)
                    341:
                    342:        mklines.Check()
                    343:
                    344:        t.CheckOutputLines(
                    345:                "AUTOFIX: ~/options.mk:3: Replacing \".\" with \".  \".",
                    346:                "AUTOFIX: ~/options.mk:5: Replacing \".\" with \".  \".")
                    347:
                    348:        t.CheckFileLines("options.mk",
1.7       rillig    349:                MkRcsID,
1.6       rillig    350:                ".if ${PKGNAME} == pkgname",
                    351:                ".  if \\",
                    352:                "   ${PLATFORM:MNetBSD-4.*}",
                    353:                ".  endif",
                    354:                ".endif")
                    355: }
1.7       rillig    356:
                    357: func (s *Suite) Test_MkLineChecker_CheckVaruseShellword(c *check.C) {
                    358:        t := s.Init(c)
                    359:
                    360:        t.SetupCommandLine("-Wall")
1.9     ! rillig    361:        t.SetupVartypes()
1.7       rillig    362:        lines := t.SetupFileLinesContinuation("options.mk",
                    363:                MkRcsID,
                    364:                "GOPATH=\t${WRKDIR}",
                    365:                "do-build:",
                    366:                "\tcd ${WRKSRC} && GOPATH=${GOPATH} PATH=${PATH} :")
                    367:        mklines := NewMkLines(lines)
                    368:
                    369:        mklines.Check()
                    370:
                    371:        // For WRKSRC and GOPATH, no quoting is necessary since pkgsrc directories by
                    372:        // definition don't contain special characters. Therefore they don't need the
                    373:        // :Q, not even when used as part of a shell word.
                    374:
                    375:        // For PATH, the quoting is necessary because it may contain directories outside
                    376:        // of pkgsrc, and these may contain special characters.
                    377:
                    378:        t.CheckOutputLines(
                    379:                "WARN: ~/options.mk:4: The variable PATH should be quoted as part of a shell word.")
                    380: }
1.9     ! rillig    381:
        !           382: // The ${VARNAME:=suffix} should only be used with lists.
        !           383: // It typically appears in MASTER_SITE definitions.
        !           384: func (s *Suite) Test_MkLineChecker_CheckVaruse_eq_nonlist(c *check.C) {
        !           385:        t := s.Init(c)
        !           386:
        !           387:        t.SetupCommandLine("-Wall")
        !           388:        t.SetupVartypes()
        !           389:        t.SetupMasterSite("MASTER_SITE_GITHUB", "https://github.com/")
        !           390:        lines := t.SetupFileLinesContinuation("options.mk",
        !           391:                MkRcsID,
        !           392:                "WRKSRC=\t\t${WRKDIR:=/subdir}",
        !           393:                "MASTER_SITES=\t${MASTER_SITE_GITHUB:=organization/}")
        !           394:        mklines := NewMkLines(lines)
        !           395:
        !           396:        mklines.Check()
        !           397:
        !           398:        t.CheckOutputLines(
        !           399:                "WARN: ~/options.mk:2: The :from=to modifier should only be used with lists.")
        !           400: }

CVSweb <webmaster@jp.NetBSD.org>