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

Annotation of pkgsrc/pkgtools/pkglint/files/mklines_test.go, Revision 1.41

1.33      rillig      1: package pkglint
1.1       rillig      2:
                      3: import (
1.14      rillig      4:        "gopkg.in/check.v1"
1.18      rillig      5:        "sort"
1.1       rillig      6: )
                      7:
1.7       rillig      8: func (s *Suite) Test_MkLines_Check__unusual_target(c *check.C) {
1.16      rillig      9:        t := s.Init(c)
                     10:
1.34      rillig     11:        t.SetUpVartypes()
                     12:        t.SetUpTool("cc", "CC", AtRunTime)
1.16      rillig     13:        mklines := t.NewMkLines("Makefile",
1.17      rillig     14:                MkRcsID,
1.1       rillig     15:                "",
                     16:                "echo: echo.c",
                     17:                "\tcc -o ${.TARGET} ${.IMPSRC}")
                     18:
                     19:        mklines.Check()
                     20:
1.16      rillig     21:        t.CheckOutputLines(
1.33      rillig     22:                "WARN: Makefile:3: Undeclared target \"echo\".")
1.1       rillig     23: }
1.4       rillig     24:
1.28      rillig     25: func (s *Suite) Test_MkLines__quoting_LDFLAGS_for_GNU_configure(c *check.C) {
1.16      rillig     26:        t := s.Init(c)
                     27:
1.34      rillig     28:        t.SetUpVartypes()
1.26      rillig     29:        G.Pkg = NewPackage(t.File("category/pkgbase"))
1.16      rillig     30:        mklines := t.NewMkLines("Makefile",
1.17      rillig     31:                MkRcsID,
1.4       rillig     32:                "GNU_CONFIGURE=\tyes",
                     33:                "CONFIGURE_ENV+=\tX_LIBS=${X11_LDFLAGS:Q}")
                     34:
                     35:        mklines.Check()
                     36:
1.16      rillig     37:        t.CheckOutputLines(
1.13      rillig     38:                "WARN: Makefile:3: Please use ${X11_LDFLAGS:M*:Q} instead of ${X11_LDFLAGS:Q}.")
1.4       rillig     39: }
                     40:
1.16      rillig     41: func (s *Suite) Test_MkLines__for_loop_multiple_variables(c *check.C) {
                     42:        t := s.Init(c)
1.4       rillig     43:
1.34      rillig     44:        t.SetUpVartypes()
                     45:        t.SetUpTool("echo", "ECHO", AtRunTime)
                     46:        t.SetUpTool("find", "FIND", AtRunTime)
                     47:        t.SetUpTool("pax", "PAX", AtRunTime)
1.16      rillig     48:        mklines := t.NewMkLines("Makefile", // From audio/squeezeboxserver
1.17      rillig     49:                MkRcsID,
1.4       rillig     50:                "",
1.32      rillig     51:                "SBS_COPY=\tsource target",
                     52:                "",
1.4       rillig     53:                ".for _list_ _dir_ in ${SBS_COPY}",
                     54:                "\tcd ${WRKSRC} && ${FIND} ${${_list_}} -type f ! -name '*.orig' 2>/dev/null "+
                     55:                        "| pax -rw -pm ${DESTDIR}${PREFIX}/${${_dir_}}",
                     56:                ".endfor")
                     57:
                     58:        mklines.Check()
                     59:
1.16      rillig     60:        t.CheckOutputLines(
1.32      rillig     61:                "WARN: Makefile:5: Variable names starting with an underscore (_list_) "+
                     62:                        "are reserved for internal pkgsrc use.",
                     63:                "WARN: Makefile:5: Variable names starting with an underscore (_dir_) "+
                     64:                        "are reserved for internal pkgsrc use.",
                     65:                "WARN: Makefile:6: The exitcode of \"${FIND}\" at the left of the | operator is ignored.")
1.4       rillig     66: }
                     67:
1.7       rillig     68: func (s *Suite) Test_MkLines__comparing_YesNo_variable_to_string(c *check.C) {
1.16      rillig     69:        t := s.Init(c)
                     70:
1.34      rillig     71:        t.SetUpVartypes()
1.16      rillig     72:        mklines := t.NewMkLines("databases/gdbm_compat/builtin.mk",
1.17      rillig     73:                MkRcsID,
1.4       rillig     74:                ".if ${USE_BUILTIN.gdbm} == \"no\"",
1.10      rillig     75:                ".endif",
                     76:                ".if ${USE_BUILTIN.gdbm:tu} == \"no\"", // Can never be true, since "no" is not uppercase.
1.4       rillig     77:                ".endif")
                     78:
                     79:        mklines.Check()
                     80:
1.16      rillig     81:        t.CheckOutputLines(
                     82:                "WARN: databases/gdbm_compat/builtin.mk:2: " +
1.32      rillig     83:                        "USE_BUILTIN.gdbm should be matched against \"[yY][eE][sS]\" or \"[nN][oO]\", " +
                     84:                        "not compared with \"no\".")
1.4       rillig     85: }
                     86:
1.7       rillig     87: func (s *Suite) Test_MkLines__varuse_sh_modifier(c *check.C) {
1.16      rillig     88:        t := s.Init(c)
                     89:
1.34      rillig     90:        t.SetUpVartypes()
                     91:        t.SetUpTool("sed", "SED", AfterPrefsMk)
1.16      rillig     92:        mklines := t.NewMkLines("lang/qore/module.mk",
1.17      rillig     93:                MkRcsID,
1.4       rillig     94:                "qore-version=\tqore --short-version | ${SED} -e s/-.*//",
                     95:                "PLIST_SUBST+=\tQORE_VERSION=\"${qore-version:sh}\"")
                     96:
1.40      rillig     97:        var vars2 []string
                     98:        mklines.mklines[1].ForEachUsed(func(varUse *MkVarUse, time vucTime) {
                     99:                vars2 = append(vars2, varUse.varname)
                    100:        })
1.4       rillig    101:
                    102:        c.Check(vars2, deepEquals, []string{"SED"})
                    103:
1.40      rillig    104:        var vars3 []string
                    105:        mklines.mklines[2].ForEachUsed(func(varUse *MkVarUse, time vucTime) {
                    106:                vars3 = append(vars3, varUse.varname)
                    107:        })
1.4       rillig    108:
1.32      rillig    109:        // qore-version, despite its unusual name, is a pretty normal Make variable.
1.4       rillig    110:        c.Check(vars3, deepEquals, []string{"qore-version"})
                    111:
                    112:        mklines.Check()
                    113:
1.16      rillig    114:        // No warnings about defined but not used or vice versa
                    115:        t.CheckOutputEmpty()
1.4       rillig    116: }
                    117:
1.31      rillig    118: // For parameterized variables, the "defined but not used" and
                    119: // the "used but not defined" checks are loosened a bit.
                    120: // When VAR.param1 is defined or used, VAR.param2 is also regarded
                    121: // as defined or used since often in pkgsrc, parameterized variables
                    122: // are not referred to by their exact names but by VAR.${param}.
1.7       rillig    123: func (s *Suite) Test_MkLines__varuse_parameterized(c *check.C) {
1.16      rillig    124:        t := s.Init(c)
                    125:
1.34      rillig    126:        t.SetUpVartypes()
1.16      rillig    127:        mklines := t.NewMkLines("converters/wv2/Makefile",
1.17      rillig    128:                MkRcsID,
1.4       rillig    129:                "CONFIGURE_ARGS+=\t\t${CONFIGURE_ARGS.${ICONV_TYPE}-iconv}",
                    130:                "CONFIGURE_ARGS.gnu-iconv=\t--with-libiconv=${BUILDLINK_PREFIX.iconv}")
                    131:
                    132:        mklines.Check()
                    133:
1.31      rillig    134:        // No warnings about CONFIGURE_ARGS.* being defined but not used or vice versa.
                    135:        t.CheckOutputLines(
                    136:                "WARN: converters/wv2/Makefile:2: ICONV_TYPE is used but not defined.")
1.4       rillig    137: }
                    138:
1.32      rillig    139: // When an ODE runtime loop is used to expand variables to shell commands,
                    140: // pkglint only understands that there is a variable that is executed as
                    141: // shell command.
                    142: //
                    143: // In this example, GCONF_SCHEMAS is a list of filenames, but pkglint doesn't know this
                    144: // because there is no built-in rule saying *_SCHEMAS are filenames.
                    145: // If the variable name had been GCONF_SCHEMA_FILES, pkglint would know.
                    146: //
                    147: // As of November 2018, pkglint sees GCONF_SCHEMAS as being the shell command.
                    148: // It doesn't expand the @s@ loop to see what really happens.
                    149: //
                    150: // If it did that, it could notice that GCONF_SCHEMAS expands to a single shell command,
                    151: // and in that command INSTALL_DATA is used as the command for the first time,
                    152: // and as a regular command line argument in all other times.
                    153: // This combination is strange enough to warrant a warning.
                    154: //
                    155: // The bug here is the missing semicolon just before the @}.
                    156: //
                    157: // Pkglint could offer to either add the missing semicolon.
                    158: // Or, if it knows what INSTALL_DATA does, it could simply say that INSTALL_DATA
                    159: // can handle multiple files in a single invocation.
1.7       rillig    160: func (s *Suite) Test_MkLines__loop_modifier(c *check.C) {
1.16      rillig    161:        t := s.Init(c)
                    162:
1.34      rillig    163:        t.SetUpVartypes()
1.16      rillig    164:        mklines := t.NewMkLines("chat/xchat/Makefile",
1.17      rillig    165:                MkRcsID,
1.4       rillig    166:                "GCONF_SCHEMAS=\tapps_xchat_url_handler.schemas",
                    167:                "post-install:",
1.32      rillig    168:                "\t${GCONF_SCHEMAS:@s@"+
                    169:                        "${INSTALL_DATA} ${WRKSRC}/src/common/dbus/${s} ${DESTDIR}${GCONF_SCHEMAS_DIR}/@}")
1.4       rillig    170:
                    171:        mklines.Check()
                    172:
1.18      rillig    173:        // Earlier versions of pkglint warned about a missing @ at the end.
                    174:        t.CheckOutputEmpty()
1.4       rillig    175: }
1.5       rillig    176:
1.7       rillig    177: func (s *Suite) Test_MkLines__PKG_SKIP_REASON_depending_on_OPSYS(c *check.C) {
1.16      rillig    178:        t := s.Init(c)
                    179:
1.34      rillig    180:        t.SetUpVartypes()
1.16      rillig    181:        mklines := t.NewMkLines("Makefile",
1.17      rillig    182:                MkRcsID,
1.5       rillig    183:                "PKG_SKIP_REASON+=\t\"Fails everywhere\"",
                    184:                ".if ${OPSYS} == \"Cygwin\"",
                    185:                "PKG_SKIP_REASON+=\t\"Fails on Cygwin\"",
                    186:                ".endif")
                    187:
                    188:        mklines.Check()
                    189:
1.16      rillig    190:        t.CheckOutputLines(
1.32      rillig    191:                "NOTE: Makefile:4: Consider setting NOT_FOR_PLATFORM instead of PKG_SKIP_REASON depending on ${OPSYS}.")
1.5       rillig    192: }
1.6       rillig    193:
1.33      rillig    194: func (s *Suite) Test_MkLines_Check__use_list_variable_as_part_of_word(c *check.C) {
1.16      rillig    195:        t := s.Init(c)
                    196:
1.34      rillig    197:        t.SetUpVartypes()
                    198:        t.SetUpTool("tr", "", AtRunTime)
1.16      rillig    199:        mklines := t.NewMkLines("converters/chef/Makefile",
1.17      rillig    200:                MkRcsID,
1.6       rillig    201:                "\tcd ${WRKSRC} && tr '\\r' '\\n' < ${DISTDIR}/${DIST_SUBDIR}/${DISTFILES} > chef.l")
                    202:
                    203:        mklines.Check()
                    204:
1.16      rillig    205:        t.CheckOutputLines(
1.13      rillig    206:                "WARN: converters/chef/Makefile:2: The list variable DISTFILES should not be embedded in a word.")
1.6       rillig    207: }
                    208:
1.7       rillig    209: func (s *Suite) Test_MkLines_Check__absolute_pathname_depending_on_OPSYS(c *check.C) {
1.16      rillig    210:        t := s.Init(c)
                    211:
1.34      rillig    212:        t.SetUpVartypes()
1.16      rillig    213:        mklines := t.NewMkLines("games/heretic2-demo/Makefile",
1.17      rillig    214:                MkRcsID,
1.6       rillig    215:                ".if ${OPSYS} == \"DragonFly\"",
1.33      rillig    216:                "TAR_CMD=\t/usr/bin/bsdtar",
1.6       rillig    217:                ".endif",
1.33      rillig    218:                "TAR_CMD=\t/usr/bin/bsdtar",
                    219:                "",
                    220:                "do-extract:",
                    221:                "\t${TAR_CMD}")
1.6       rillig    222:
                    223:        mklines.Check()
                    224:
1.33      rillig    225:        // No warning about an unknown shell command in line 3 since that line depends on OPSYS.
                    226:        // Shell commands that are specific to an operating system are probably defined
                    227:        // and used intentionally, so even commands that are not known tools are allowed.
1.16      rillig    228:        t.CheckOutputLines(
1.13      rillig    229:                "WARN: games/heretic2-demo/Makefile:5: Unknown shell command \"/usr/bin/bsdtar\".")
1.6       rillig    230: }
1.7       rillig    231:
1.30      rillig    232: func (s *Suite) Test_MkLines_CheckForUsedComment(c *check.C) {
1.16      rillig    233:        t := s.Init(c)
                    234:
1.34      rillig    235:        t.SetUpCommandLine("--show-autofix")
1.7       rillig    236:
1.33      rillig    237:        test := func(pkgpath string, lines []string, diagnostics []string) {
                    238:                mklines := t.NewMkLines("Makefile.common", lines...)
1.7       rillig    239:
1.33      rillig    240:                mklines.CheckForUsedComment(pkgpath)
1.7       rillig    241:
1.39      rillig    242:                t.CheckOutput(diagnostics)
1.33      rillig    243:        }
1.7       rillig    244:
1.33      rillig    245:        lines := func(lines ...string) []string { return lines }
                    246:        diagnostics := func(diagnostics ...string) []string { return diagnostics }
1.7       rillig    247:
1.33      rillig    248:        // This file is too short to be checked.
                    249:        test(
                    250:                "category/package",
                    251:                lines(),
                    252:                diagnostics())
                    253:
                    254:        // Still too short.
                    255:        test(
                    256:                "category/package",
                    257:                lines(
                    258:                        MkRcsID),
                    259:                diagnostics())
                    260:
                    261:        // Still too short.
                    262:        test(
                    263:                "category/package",
                    264:                lines(
                    265:                        MkRcsID,
                    266:                        ""),
                    267:                diagnostics())
                    268:
                    269:        // This file is correctly mentioned.
                    270:        test(
                    271:                "sysutils/mc",
                    272:                lines(
                    273:                        MkRcsID,
                    274:                        "",
                    275:                        "# used by sysutils/mc"),
                    276:                diagnostics())
                    277:
                    278:        // This file is not correctly mentioned, therefore the line is inserted.
                    279:        // TODO: Since the following line is of a different type, an additional empty line should be inserted.
                    280:        test(
                    281:                "category/package",
                    282:                lines(
                    283:                        MkRcsID,
                    284:                        "",
                    285:                        "VARNAME=\tvalue"),
                    286:                diagnostics(
                    287:                        "WARN: Makefile.common:2: Please add a line \"# used by category/package\" here.",
                    288:                        "AUTOFIX: Makefile.common:2: Inserting a line \"# used by category/package\" before this line."))
                    289:
                    290:        // The "used by" comments may either start in line 2 or in line 3.
                    291:        test(
                    292:                "category/package",
                    293:                lines(
                    294:                        MkRcsID,
                    295:                        "#",
                    296:                        "#"),
                    297:                diagnostics(
                    298:                        "WARN: Makefile.common:3: Please add a line \"# used by category/package\" here.",
                    299:                        "AUTOFIX: Makefile.common:3: Inserting a line \"# used by category/package\" before this line."))
1.7       rillig    300:
1.33      rillig    301:        // TODO: What if there is an introductory comment first? That should stay at the top of the file.
                    302:        // TODO: What if the "used by" comments appear in the second paragraph, preceded by only comments and empty lines?
1.15      rillig    303:
                    304:        c.Check(G.autofixAvailable, equals, true)
1.7       rillig    305: }
                    306:
1.32      rillig    307: func (s *Suite) Test_MkLines_collectDefinedVariables(c *check.C) {
1.27      rillig    308:        t := s.Init(c)
                    309:
1.34      rillig    310:        t.SetUpCommandLine("-Wall,no-space")
                    311:        t.SetUpPkgsrc()
1.27      rillig    312:        t.CreateFileLines("mk/tools/defaults.mk",
                    313:                "USE_TOOLS+=     autoconf autoconf213")
                    314:        mklines := t.NewMkLines("determine-defined-variables.mk",
                    315:                MkRcsID,
                    316:                "",
                    317:                "USE_TOOLS+=             autoconf213 autoconf",
                    318:                "",
                    319:                "OPSYSVARS+=             OSV",
                    320:                "OSV.NetBSD=             NetBSD-specific value",
                    321:                "",
                    322:                "SUBST_CLASSES+=         subst",
                    323:                "SUBST_STAGE.subst=      pre-configure",
                    324:                "SUBST_FILES.subst=      file",
                    325:                "SUBST_VARS.subst=       SUV",
                    326:                "SUV=                    value for substitution",
                    327:                "",
                    328:                "pre-configure:",
1.33      rillig    329:                "\t${RUN} autoreconf; autoheader-2.13",
1.27      rillig    330:                "\t${ECHO} ${OSV:Q}")
1.41    ! rillig    331:        t.FinishSetUp()
1.27      rillig    332:
                    333:        mklines.Check()
                    334:
                    335:        // The tools autoreconf and autoheader213 are known at this point because of the USE_TOOLS line.
                    336:        // The SUV variable is used implicitly by the SUBST framework, therefore no warning.
1.39      rillig    337:        // The OSV.NetBSD variable is used indirectly because OSV is declared
                    338:        // as being OPSYS-specific, therefore no warning.
1.38      rillig    339:        t.CheckOutputEmpty()
1.27      rillig    340: }
                    341:
1.32      rillig    342: func (s *Suite) Test_MkLines_collectDefinedVariables__BUILTIN_FIND_FILES_VAR(c *check.C) {
1.29      rillig    343:        t := s.Init(c)
                    344:
1.34      rillig    345:        t.SetUpCommandLine("-Wall,no-space")
                    346:        t.SetUpPackage("category/package")
1.29      rillig    347:        t.CreateFileLines("mk/buildlink3/bsd.builtin.mk",
                    348:                MkRcsID)
1.34      rillig    349:        mklines := t.SetUpFileMkLines("category/package/builtin.mk",
1.29      rillig    350:                MkRcsID,
                    351:                "",
                    352:                "BUILTIN_FIND_FILES_VAR:=        H_XFT2",
                    353:                "BUILTIN_FIND_FILES.H_XFT2=      ${X11BASE}/include/X11/Xft/Xft.h",
                    354:                "",
                    355:                ".include \"../../mk/buildlink3/bsd.builtin.mk\"",
                    356:                "",
                    357:                ".if ${H_XFT2:N__nonexistent__} && ${H_UNDEF:N__nonexistent__}",
                    358:                ".endif")
1.41    ! rillig    359:        t.FinishSetUp()
1.29      rillig    360:
                    361:        mklines.Check()
                    362:
                    363:        t.CheckOutputLines(
                    364:                "WARN: ~/category/package/builtin.mk:8: H_UNDEF is used but not defined.")
                    365: }
                    366:
1.32      rillig    367: func (s *Suite) Test_MkLines_collectUsedVariables__simple(c *check.C) {
1.16      rillig    368:        t := s.Init(c)
                    369:
1.38      rillig    370:        mklines := t.NewMkLines("filename.mk",
1.7       rillig    371:                "\t${VAR}")
                    372:        mkline := mklines.mklines[0]
                    373:
1.32      rillig    374:        mklines.collectUsedVariables()
1.7       rillig    375:
1.33      rillig    376:        c.Check(mklines.vars.used, deepEquals, map[string]MkLine{"VAR": mkline})
1.18      rillig    377:        c.Check(mklines.vars.FirstUse("VAR"), equals, mkline)
1.7       rillig    378: }
                    379:
1.32      rillig    380: func (s *Suite) Test_MkLines_collectUsedVariables__nested(c *check.C) {
1.16      rillig    381:        t := s.Init(c)
                    382:
1.31      rillig    383:        mklines := t.NewMkLines("filename.mk",
                    384:                MkRcsID,
                    385:                "",
                    386:                "LHS.${lparam}=\tRHS.${rparam}",
                    387:                "",
                    388:                "target:",
1.7       rillig    389:                "\t${outer.${inner}}")
1.31      rillig    390:        assignMkline := mklines.mklines[2]
                    391:        shellMkline := mklines.mklines[5]
1.7       rillig    392:
1.32      rillig    393:        mklines.collectUsedVariables()
1.7       rillig    394:
1.31      rillig    395:        c.Check(len(mklines.vars.used), equals, 5)
                    396:        c.Check(mklines.vars.FirstUse("lparam"), equals, assignMkline)
                    397:        c.Check(mklines.vars.FirstUse("rparam"), equals, assignMkline)
                    398:        c.Check(mklines.vars.FirstUse("inner"), equals, shellMkline)
                    399:        c.Check(mklines.vars.FirstUse("outer.*"), equals, shellMkline)
                    400:        c.Check(mklines.vars.FirstUse("outer.${inner}"), equals, shellMkline)
1.7       rillig    401: }
1.8       rillig    402:
1.28      rillig    403: func (s *Suite) Test_MkLines__private_tool_undefined(c *check.C) {
1.16      rillig    404:        t := s.Init(c)
                    405:
1.34      rillig    406:        t.SetUpVartypes()
1.38      rillig    407:        mklines := t.NewMkLines("filename.mk",
1.17      rillig    408:                MkRcsID,
1.8       rillig    409:                "",
1.31      rillig    410:                "\tmd5sum filename")
1.8       rillig    411:
                    412:        mklines.Check()
                    413:
1.16      rillig    414:        t.CheckOutputLines(
1.38      rillig    415:                "WARN: filename.mk:3: Unknown shell command \"md5sum\".")
1.8       rillig    416: }
                    417:
1.39      rillig    418: // Tools that are defined by a package by adding to TOOLS_CREATE can
                    419: // be used without adding them to USE_TOOLS again.
1.28      rillig    420: func (s *Suite) Test_MkLines__private_tool_defined(c *check.C) {
1.16      rillig    421:        t := s.Init(c)
                    422:
1.34      rillig    423:        t.SetUpVartypes()
1.38      rillig    424:        mklines := t.NewMkLines("filename.mk",
1.17      rillig    425:                MkRcsID,
1.8       rillig    426:                "TOOLS_CREATE+=\tmd5sum",
                    427:                "",
1.31      rillig    428:                "\tmd5sum filename")
1.8       rillig    429:
                    430:        mklines.Check()
                    431:
1.39      rillig    432:        t.CheckOutputEmpty()
1.8       rillig    433: }
1.9       rillig    434:
1.28      rillig    435: func (s *Suite) Test_MkLines_Check__indentation(c *check.C) {
1.16      rillig    436:        t := s.Init(c)
                    437:
1.34      rillig    438:        t.SetUpVartypes()
1.16      rillig    439:        mklines := t.NewMkLines("options.mk",
1.17      rillig    440:                MkRcsID,
1.9       rillig    441:                ". if !defined(GUARD_MK)",
                    442:                ". if ${OPSYS} == ${OPSYS}",
                    443:                ".   for i in ${FILES}",
                    444:                ".     if !defined(GUARD2_MK)",
                    445:                ".     else",
                    446:                ".     endif",
                    447:                ".   endfor",
                    448:                ".   if ${COND1}",
                    449:                ".   elif ${COND2}",
                    450:                ".   else ${COND3}",
                    451:                ".   endif",
                    452:                ". endif",
                    453:                ". endif",
                    454:                ". endif")
                    455:
                    456:        mklines.Check()
                    457:
1.27      rillig    458:        t.CheckOutputLines(
1.16      rillig    459:                "NOTE: options.mk:2: This directive should be indented by 0 spaces.",
1.29      rillig    460:                "WARN: options.mk:2: GUARD_MK is used but not defined.",
1.16      rillig    461:                "NOTE: options.mk:3: This directive should be indented by 0 spaces.",
                    462:                "NOTE: options.mk:4: This directive should be indented by 2 spaces.",
1.29      rillig    463:                "WARN: options.mk:4: FILES is used but not defined.",
1.16      rillig    464:                "NOTE: options.mk:5: This directive should be indented by 4 spaces.",
1.29      rillig    465:                "WARN: options.mk:5: GUARD2_MK is used but not defined.",
1.16      rillig    466:                "NOTE: options.mk:6: This directive should be indented by 4 spaces.",
                    467:                "NOTE: options.mk:7: This directive should be indented by 4 spaces.",
                    468:                "NOTE: options.mk:8: This directive should be indented by 2 spaces.",
                    469:                "NOTE: options.mk:9: This directive should be indented by 2 spaces.",
1.29      rillig    470:                "WARN: options.mk:9: COND1 is used but not defined.",
1.16      rillig    471:                "NOTE: options.mk:10: This directive should be indented by 2 spaces.",
1.29      rillig    472:                "WARN: options.mk:10: COND2 is used but not defined.",
1.16      rillig    473:                "NOTE: options.mk:11: This directive should be indented by 2 spaces.",
1.22      rillig    474:                "ERROR: options.mk:11: \".else\" does not take arguments. If you meant \"else if\", use \".elif\".",
1.16      rillig    475:                "NOTE: options.mk:12: This directive should be indented by 2 spaces.",
                    476:                "NOTE: options.mk:13: This directive should be indented by 0 spaces.",
                    477:                "NOTE: options.mk:14: This directive should be indented by 0 spaces.",
1.20      rillig    478:                "NOTE: options.mk:15: This directive should be indented by 0 spaces.",
                    479:                "ERROR: options.mk:15: Unmatched .endif.")
1.9       rillig    480: }
1.14      rillig    481:
1.30      rillig    482: // The .include directives do not need to be indented. They have the
                    483: // syntactical form of directives but cannot be nested in a single file.
                    484: // Therefore they may be either indented at the correct indentation depth
                    485: // or not indented at all.
                    486: func (s *Suite) Test_MkLines_Check__indentation_include(c *check.C) {
                    487:        t := s.Init(c)
                    488:
1.34      rillig    489:        t.SetUpVartypes()
1.30      rillig    490:        t.CreateFileLines("included.mk")
1.34      rillig    491:        mklines := t.SetUpFileMkLines("module.mk",
1.30      rillig    492:                MkRcsID,
                    493:                "",
                    494:                ".if ${PKGPATH} == \"category/package\"",
                    495:                ".include \"included.mk\"",
                    496:                ". include \"included.mk\"",
                    497:                ".  include \"included.mk\"",
                    498:                ".    include \"included.mk\"",
                    499:                ".endif")
                    500:
                    501:        mklines.Check()
                    502:
                    503:        t.CheckOutputLines(
                    504:                "NOTE: ~/module.mk:5: This directive should be indented by 2 spaces.",
                    505:                "NOTE: ~/module.mk:7: This directive should be indented by 2 spaces.")
                    506: }
                    507:
1.33      rillig    508: func (s *Suite) Test_MkLines_Check__unfinished_directives(c *check.C) {
1.27      rillig    509:        t := s.Init(c)
                    510:
1.34      rillig    511:        t.SetUpVartypes()
1.27      rillig    512:        mklines := t.NewMkLines("opsys.mk",
                    513:                MkRcsID,
                    514:                "",
                    515:                ".for i in 1 2 3 4 5",
                    516:                ".  if ${OPSYS} == NetBSD",
1.29      rillig    517:                ".    if ${MACHINE_ARCH} == x86_64",
1.27      rillig    518:                ".      if ${OS_VERSION:M8.*}")
                    519:
                    520:        mklines.Check()
                    521:
                    522:        t.CheckOutputLines(
1.30      rillig    523:                "ERROR: opsys.mk:EOF: .if from line 6 must be closed.",
                    524:                "ERROR: opsys.mk:EOF: .if from line 5 must be closed.",
                    525:                "ERROR: opsys.mk:EOF: .if from line 4 must be closed.",
                    526:                "ERROR: opsys.mk:EOF: .for from line 3 must be closed.")
1.27      rillig    527: }
                    528:
1.33      rillig    529: func (s *Suite) Test_MkLines_Check__unbalanced_directives(c *check.C) {
                    530:        t := s.Init(c)
                    531:
1.34      rillig    532:        t.SetUpVartypes()
1.33      rillig    533:        mklines := t.NewMkLines("opsys.mk",
                    534:                MkRcsID,
                    535:                "",
                    536:                ".for i in 1 2 3 4 5",
                    537:                ".  if ${OPSYS} == NetBSD",
                    538:                ".  endfor",
                    539:                ".endif")
                    540:
                    541:        mklines.Check()
                    542:
                    543:        // As of November 2018 pkglint doesn't find that the inner .if is closed by an .endfor.
                    544:        // This is checked by bmake, though.
                    545:        //
                    546:        // As soon as pkglint starts to analyze .if/.for as regular statements
                    547:        // like in most programming languages, it will find this inconsistency, too.
                    548:        t.CheckOutputEmpty()
                    549: }
                    550:
1.29      rillig    551: func (s *Suite) Test_MkLines_Check__incomplete_subst_at_end(c *check.C) {
                    552:        t := s.Init(c)
                    553:
1.34      rillig    554:        t.SetUpVartypes()
1.29      rillig    555:        mklines := t.NewMkLines("subst.mk",
                    556:                MkRcsID,
                    557:                "",
                    558:                "SUBST_CLASSES+=\tclass")
                    559:
                    560:        mklines.Check()
                    561:
                    562:        t.CheckOutputLines(
                    563:                "WARN: subst.mk:EOF: Incomplete SUBST block: SUBST_STAGE.class missing.",
                    564:                "WARN: subst.mk:EOF: Incomplete SUBST block: SUBST_FILES.class missing.",
                    565:                "WARN: subst.mk:EOF: Incomplete SUBST block: SUBST_SED.class, SUBST_VARS.class or SUBST_FILTER_CMD.class missing.")
                    566: }
                    567:
1.25      rillig    568: // Demonstrates how to define your own make(1) targets for creating
                    569: // files in the current directory. The pkgsrc-wip category Makefile
                    570: // does this, while all other categories don't need any custom code.
1.28      rillig    571: func (s *Suite) Test_MkLines__wip_category_Makefile(c *check.C) {
1.16      rillig    572:        t := s.Init(c)
                    573:
1.34      rillig    574:        t.SetUpCommandLine("-Wall", "--explain")
                    575:        t.SetUpVartypes()
                    576:        t.SetUpTool("rm", "RM", AtRunTime)
1.25      rillig    577:        t.CreateFileLines("mk/misc/category.mk")
1.34      rillig    578:        mklines := t.SetUpFileMkLines("wip/Makefile",
1.17      rillig    579:                MkRcsID,
1.14      rillig    580:                "",
                    581:                "COMMENT=\tWIP pkgsrc packages",
                    582:                "",
                    583:                "SUBDIR+=\taaa",
                    584:                "SUBDIR+=\tzzz",
                    585:                "",
                    586:                "${.CURDIR}/PKGDB:",
                    587:                "\t${RM} -f ${.CURDIR}/PKGDB",
                    588:                "",
                    589:                "${.CURDIR}/INDEX:",
                    590:                "\t${RM} -f ${.CURDIR}/INDEX",
                    591:                "",
1.25      rillig    592:                "clean-tmpdir:",
                    593:                "\t${RUN} rm -rf tmpdir",
                    594:                "",
                    595:                ".include \"../mk/misc/category.mk\"")
1.14      rillig    596:
                    597:        mklines.Check()
                    598:
1.16      rillig    599:        t.CheckOutputLines(
1.33      rillig    600:                "WARN: ~/wip/Makefile:14: Undeclared target \"clean-tmpdir\".",
1.25      rillig    601:                "",
1.33      rillig    602:                "\tTo define a custom target in a package, declare it like this:",
1.31      rillig    603:                "",
1.25      rillig    604:                "\t\t.PHONY: my-target",
1.31      rillig    605:                "",
1.33      rillig    606:                "\tTo define a custom target that creates a file (should be rarely",
                    607:                "\tneeded), declare it like this:",
1.31      rillig    608:                "",
1.30      rillig    609:                "\t\t${.CURDIR}/my-file:",
1.25      rillig    610:                "")
1.14      rillig    611: }
1.18      rillig    612:
1.32      rillig    613: func (s *Suite) Test_MkLines_collectDocumentedVariables(c *check.C) {
1.18      rillig    614:        t := s.Init(c)
                    615:
1.34      rillig    616:        t.SetUpVartypes()
                    617:        t.SetUpTool("rm", "RM", AtRunTime)
1.18      rillig    618:        mklines := t.NewMkLines("Makefile",
                    619:                MkRcsID,
                    620:                "#",
1.27      rillig    621:                "# Copyright 2000-2018",
                    622:                "#",
                    623:                "# This whole comment is ignored, until the next empty line.",
1.33      rillig    624:                "# Since it contains the word \"copyright\", it's probably legalese",
                    625:                "# instead of documentation.",
1.27      rillig    626:                "",
1.18      rillig    627:                "# User-settable variables:",
                    628:                "#",
                    629:                "# PKG_DEBUG_LEVEL",
                    630:                "#\tHow verbose should pkgsrc be when running shell commands?",
                    631:                "#",
                    632:                "#\t* 0:\tdon't show most shell ...",
                    633:                "",
                    634:                "# PKG_VERBOSE",
                    635:                "#\tWhen this variable is defined, pkgsrc gets a bit more verbose",
                    636:                "#\t(i.e. \"-v\" option is passed to some commands ...",
                    637:                "",
                    638:                "# VARIABLE",
                    639:                "#\tA paragraph of a single line is not enough to be recognized as \"relevant\".",
                    640:                "",
1.38      rillig    641:                "# PARAGRAPH",
                    642:                "#\tA paragraph may end in a",
                    643:                "#\tPARA_END_VARNAME.",
                    644:                "",
1.18      rillig    645:                "# VARBASE1.<param1>",
                    646:                "# VARBASE2.*",
                    647:                "# VARBASE3.${id}")
                    648:
                    649:        // The variables that appear in the documentation are marked as
1.33      rillig    650:        // both used and defined, to prevent the "defined but not used" warnings.
1.32      rillig    651:        mklines.collectDocumentedVariables()
1.18      rillig    652:
                    653:        var varnames []string
                    654:        for varname, mkline := range mklines.vars.used {
1.33      rillig    655:                varnames = append(varnames, sprintf("%s (line %s)", varname, mkline.Linenos()))
1.18      rillig    656:        }
                    657:        sort.Strings(varnames)
                    658:
                    659:        expected := []string{
1.38      rillig    660:                "PARAGRAPH (line 23)",
1.33      rillig    661:                "PKG_DEBUG_LEVEL (line 11)",
                    662:                "PKG_VERBOSE (line 16)",
1.38      rillig    663:                "VARBASE1.* (line 27)",
                    664:                "VARBASE2.* (line 28)",
                    665:                "VARBASE3.* (line 29)"}
1.18      rillig    666:        c.Check(varnames, deepEquals, expected)
                    667: }
1.21      rillig    668:
                    669: func (s *Suite) Test_MkLines__shell_command_indentation(c *check.C) {
                    670:        t := s.Init(c)
                    671:
1.34      rillig    672:        t.SetUpVartypes()
1.21      rillig    673:        mklines := t.NewMkLines("Makefile",
                    674:                MkRcsID,
                    675:                "#",
                    676:                "pre-configure:",
                    677:                "\tcd 'indented correctly'",
                    678:                "\t\tcd 'indented needlessly'",
                    679:                "\tcd 'indented correctly' \\",
                    680:                "\t\t&& cd 'with indented continuation'")
                    681:
                    682:        mklines.Check()
                    683:
                    684:        t.CheckOutputLines(
                    685:                "NOTE: Makefile:5: Shell programs should be indented with a single tab.")
                    686: }
                    687:
                    688: func (s *Suite) Test_MkLines__unknown_options(c *check.C) {
                    689:        t := s.Init(c)
                    690:
1.34      rillig    691:        t.SetUpVartypes()
                    692:        t.SetUpOption("known", "")
1.21      rillig    693:        mklines := t.NewMkLines("options.mk",
                    694:                MkRcsID,
                    695:                "#",
                    696:                "PKG_OPTIONS_VAR=\tPKG_OPTIONS.pkgbase",
                    697:                "PKG_SUPPORTED_OPTIONS=\tknown unknown",
                    698:                "PKG_SUGGESTED_OPTIONS=\tknown unknown")
                    699:
                    700:        mklines.Check()
                    701:
                    702:        t.CheckOutputLines(
                    703:                "WARN: options.mk:4: Unknown option \"unknown\".")
                    704: }
1.22      rillig    705:
1.25      rillig    706: func (s *Suite) Test_MkLines_Check__PLIST_VARS(c *check.C) {
                    707:        t := s.Init(c)
                    708:
1.34      rillig    709:        t.SetUpCommandLine("-Wno-space")
                    710:        t.SetUpVartypes()
                    711:        t.SetUpOption("both", "")
                    712:        t.SetUpOption("only-added", "")
                    713:        t.SetUpOption("only-defined", "")
1.32      rillig    714:        t.CreateFileLines("mk/bsd.options.mk")
1.25      rillig    715:
1.34      rillig    716:        mklines := t.SetUpFileMkLines("category/package/options.mk",
1.25      rillig    717:                MkRcsID,
                    718:                "",
                    719:                "PKG_OPTIONS_VAR=        PKG_OPTIONS.pkg",
                    720:                "PKG_SUPPORTED_OPTIONS=  both only-added only-defined",
                    721:                "PKG_SUGGESTED_OPTIONS=  # none",
                    722:                "",
                    723:                ".include \"../../mk/bsd.options.mk\"",
                    724:                "",
                    725:                "PLIST_VARS+=            both only-added",
                    726:                "",
                    727:                ".if !empty(PKG_OPTIONS:Mboth)",
                    728:                "PLIST.both=             yes",
                    729:                ".endif",
                    730:                "",
                    731:                ".if !empty(PKG_OPTIONS:Monly-defined)",
                    732:                "PLIST.only-defined=     yes",
                    733:                ".endif")
                    734:
                    735:        mklines.Check()
                    736:
                    737:        t.CheckOutputLines(
1.32      rillig    738:                "WARN: ~/category/package/options.mk:9: \"only-added\" is added to PLIST_VARS, but PLIST.only-added is not defined in this file.",
                    739:                "WARN: ~/category/package/options.mk:16: PLIST.only-defined is defined, but \"only-defined\" is not added to PLIST_VARS in this file.")
1.25      rillig    740: }
                    741:
                    742: func (s *Suite) Test_MkLines_Check__PLIST_VARS_indirect(c *check.C) {
                    743:        t := s.Init(c)
                    744:
1.34      rillig    745:        t.SetUpCommandLine("-Wno-space")
                    746:        t.SetUpVartypes()
                    747:        t.SetUpOption("option1", "")
                    748:        t.SetUpOption("option2", "")
1.25      rillig    749:
1.34      rillig    750:        mklines := t.SetUpFileMkLines("module.mk",
1.25      rillig    751:                MkRcsID,
                    752:                "",
                    753:                "MY_PLIST_VARS=  option1 option2",
                    754:                "PLIST_VARS+=    ${MY_PLIST_VARS}",
                    755:                ".for option in option3",
                    756:                "PLIST_VARS+=    ${option}",
                    757:                ".endfor",
                    758:                "",
                    759:                ".if 0",
                    760:                "PLIST.option1=  yes",
                    761:                ".endif",
                    762:                "",
                    763:                ".if 1",
                    764:                "PLIST.option2=  yes",
                    765:                ".endif")
                    766:
                    767:        mklines.Check()
                    768:
1.33      rillig    769:        // As of November 2018, pkglint doesn't analyze the .if 0 block.
                    770:        // Therefore it doesn't know that the option1 block will never match because of the 0.
                    771:        // This is ok though since it could be a temporary workaround from the package maintainer.
                    772:        //
                    773:        // As of November 2018, pkglint doesn't analyze the .for loop.
                    774:        // Therefore it doesn't know that an .if block for option3 is missing.
                    775:        t.CheckOutputEmpty()
                    776: }
                    777:
                    778: func (s *Suite) Test_MkLines_Check__PLIST_VARS_indirect_2(c *check.C) {
                    779:        t := s.Init(c)
                    780:
1.34      rillig    781:        t.SetUpCommandLine("-Wno-space")
                    782:        t.SetUpVartypes()
                    783:        t.SetUpOption("a", "")
                    784:        t.SetUpOption("b", "")
                    785:        t.SetUpOption("c", "")
1.33      rillig    786:
                    787:        mklines := t.NewMkLines("module.mk",
                    788:                MkRcsID,
                    789:                "",
                    790:                "PKG_SUPPORTED_OPTIONS=  a b c",
                    791:                "PLIST_VARS+=            ${PKG_SUPPORTED_OPTIONS:S,a,,g}",
                    792:                "",
                    793:                "PLIST_VARS+=            only-added",
                    794:                "",
                    795:                "PLIST.only-defined=     yes")
                    796:
                    797:        mklines.Check()
                    798:
                    799:        // If the PLIST_VARS contain complex expressions that involve other variables,
                    800:        // it becomes too difficult for pkglint to decide whether the IDs can still match.
                    801:        // Therefore, in such a case, no diagnostics are logged at all.
1.25      rillig    802:        t.CheckOutputEmpty()
                    803: }
                    804:
1.32      rillig    805: func (s *Suite) Test_MkLines_collectElse(c *check.C) {
1.25      rillig    806:        t := s.Init(c)
                    807:
1.34      rillig    808:        t.SetUpCommandLine("-Wno-space")
                    809:        t.SetUpVartypes()
1.25      rillig    810:
                    811:        mklines := t.NewMkLines("module.mk",
                    812:                MkRcsID,
                    813:                "",
                    814:                ".if 0",
                    815:                ".endif",
                    816:                "",
                    817:                ".if 0",
                    818:                ".else",
                    819:                ".endif",
                    820:                "",
                    821:                ".if 0",
                    822:                ".elif 0",
                    823:                ".endif")
                    824:
                    825:        mklines.collectElse()
                    826:
                    827:        c.Check(mklines.mklines[2].HasElseBranch(), equals, false)
                    828:        c.Check(mklines.mklines[5].HasElseBranch(), equals, true)
                    829:        c.Check(mklines.mklines[9].HasElseBranch(), equals, false)
                    830: }
                    831:
                    832: func (s *Suite) Test_MkLines_Check__defined_and_used_variables(c *check.C) {
                    833:        t := s.Init(c)
                    834:
1.34      rillig    835:        t.SetUpCommandLine("-Wno-space")
                    836:        t.SetUpVartypes()
1.25      rillig    837:
                    838:        mklines := t.NewMkLines("module.mk",
                    839:                MkRcsID,
                    840:                "",
                    841:                ".for lang in de fr",
                    842:                "PLIST_VARS+=            ${lang}",
                    843:                ".endif",
                    844:                "",
                    845:                ".for language in de fr",
                    846:                "PLIST.${language}=      yes",
                    847:                ".endif",
                    848:                "",
                    849:                "PLIST.other=            yes")
                    850:
                    851:        mklines.Check()
                    852:
                    853:        // If there are variable involved in the definition of PLIST_VARS or PLIST.*,
                    854:        // it becomes too difficult for pkglint to decide whether the IDs can still match.
                    855:        // Therefore, in such a case, no diagnostics are logged at all.
                    856:        t.CheckOutputEmpty()
                    857: }
                    858:
1.27      rillig    859: func (s *Suite) Test_MkLines_Check__hacks_mk(c *check.C) {
                    860:        t := s.Init(c)
                    861:
1.34      rillig    862:        t.SetUpCommandLine("-Wall,no-space")
                    863:        t.SetUpVartypes()
1.27      rillig    864:        mklines := t.NewMkLines("hacks.mk",
                    865:                MkRcsID,
                    866:                "",
                    867:                "PKGNAME?=       pkgbase-1.0")
                    868:
                    869:        mklines.Check()
                    870:
                    871:        // No warning about including bsd.prefs.mk before using the ?= operator.
1.38      rillig    872:        // This is because the hacks.mk files are included implicitly by the
                    873:        // pkgsrc infrastructure right after bsd.prefs.mk.
1.27      rillig    874:        t.CheckOutputEmpty()
                    875: }
1.29      rillig    876:
1.30      rillig    877: func (s *Suite) Test_MkLines_Check__MASTER_SITE_in_HOMEPAGE(c *check.C) {
                    878:        t := s.Init(c)
                    879:
1.34      rillig    880:        t.SetUpMasterSite("MASTER_SITE_GITHUB", "https://github.com/")
                    881:        t.SetUpVartypes()
1.40      rillig    882:        mklines := t.NewMkLines("devel/catch/Makefile",
1.30      rillig    883:                MkRcsID,
                    884:                "HOMEPAGE=\t${MASTER_SITE_GITHUB:=philsquared/Catch/}",
                    885:                "HOMEPAGE=\t${MASTER_SITE_GITHUB}",
                    886:                "HOMEPAGE=\t${MASTER_SITES}",
                    887:                "HOMEPAGE=\t${MASTER_SITES}${GITHUB_PROJECT}")
                    888:
1.40      rillig    889:        mklines.Check()
1.30      rillig    890:
                    891:        t.CheckOutputLines(
1.31      rillig    892:                "WARN: devel/catch/Makefile:2: HOMEPAGE should not be defined in terms of MASTER_SITEs. "+
                    893:                        "Use https://github.com/philsquared/Catch/ directly.",
                    894:                "WARN: devel/catch/Makefile:3: HOMEPAGE should not be defined in terms of MASTER_SITEs. "+
                    895:                        "Use https://github.com/ directly.",
1.30      rillig    896:                "WARN: devel/catch/Makefile:4: HOMEPAGE should not be defined in terms of MASTER_SITEs.",
                    897:                "WARN: devel/catch/Makefile:5: HOMEPAGE should not be defined in terms of MASTER_SITEs.")
                    898: }
                    899:
1.33      rillig    900: func (s *Suite) Test_MkLines_Check__VERSION_as_word_part_in_MASTER_SITES(c *check.C) {
1.30      rillig    901:        t := s.Init(c)
                    902:
1.34      rillig    903:        t.SetUpVartypes()
1.30      rillig    904:        mklines := t.NewMkLines("geography/viking/Makefile",
                    905:                MkRcsID,
                    906:                "MASTER_SITES=\t${MASTER_SITE_SOURCEFORGE:=viking/}${VERSION}/")
                    907:
                    908:        mklines.Check()
                    909:
                    910:        t.CheckOutputLines(
                    911:                "WARN: geography/viking/Makefile:2: "+
                    912:                        "The list variable MASTER_SITE_SOURCEFORGE should not be embedded in a word.",
                    913:                "WARN: geography/viking/Makefile:2: VERSION is used but not defined.")
                    914: }
                    915:
                    916: func (s *Suite) Test_MkLines_Check__shell_command_as_word_part_in_ENV_list(c *check.C) {
                    917:        t := s.Init(c)
                    918:
1.34      rillig    919:        t.SetUpVartypes()
1.30      rillig    920:        mklines := t.NewMkLines("x11/lablgtk1/Makefile",
                    921:                MkRcsID,
                    922:                "CONFIGURE_ENV+=\tCC=${CC}")
                    923:
                    924:        mklines.Check()
                    925:
                    926:        t.CheckOutputLines(
                    927:                "WARN: x11/lablgtk1/Makefile:2: Please use ${CC:Q} instead of ${CC}.")
                    928: }
                    929:
                    930: func (s *Suite) Test_MkLines_Check__extra_warnings(c *check.C) {
                    931:        t := s.Init(c)
                    932:
1.34      rillig    933:        t.SetUpCommandLine("-Wextra")
                    934:        t.SetUpVartypes()
1.30      rillig    935:        G.Pkg = NewPackage(t.File("category/pkgbase"))
1.40      rillig    936:        mklines := t.NewMkLines("options.mk",
1.30      rillig    937:                MkRcsID,
1.38      rillig    938:                "",
1.30      rillig    939:                ".for word in ${PKG_FAIL_REASON}",
                    940:                "CONFIGURE_ARGS+=\t--sharedir=${PREFIX}/share/kde",
                    941:                "COMMENT=\t# defined",
                    942:                ".endfor",
                    943:                "GAMES_USER?=pkggames",
                    944:                "GAMES_GROUP?=pkggames",
                    945:                "PLIST_SUBST+= CONDITIONAL=${CONDITIONAL}",
                    946:                "CONDITIONAL=\"@comment\"",
                    947:                "BUILD_DIRS=\t${WRKSRC}/../build")
                    948:
1.40      rillig    949:        mklines.Check()
1.30      rillig    950:
                    951:        t.CheckOutputLines(
1.31      rillig    952:                "NOTE: options.mk:5: Please use \"# empty\", \"# none\" or \"# yes\" instead of \"# defined\".",
1.30      rillig    953:                "WARN: options.mk:7: Please include \"../../mk/bsd.prefs.mk\" before using \"?=\".",
                    954:                "WARN: options.mk:11: Building the package should take place entirely inside ${WRKSRC}, not \"${WRKSRC}/..\".",
                    955:                "NOTE: options.mk:11: You can use \"../build\" instead of \"${WRKSRC}/../build\".")
                    956: }
                    957:
1.33      rillig    958: // Ensures that during MkLines.ForEach, the conditional variables in
                    959: // MkLines.Indentation are correctly updated for each line.
1.29      rillig    960: func (s *Suite) Test_MkLines_ForEach__conditional_variables(c *check.C) {
                    961:        t := s.Init(c)
                    962:
1.34      rillig    963:        t.SetUpCommandLine("-Wall,no-space")
                    964:        t.SetUpVartypes()
1.29      rillig    965:        mklines := t.NewMkLines("conditional.mk",
                    966:                MkRcsID,
                    967:                "",
                    968:                ".if defined(PKG_DEVELOPER)",
                    969:                "DEVELOPER=\tyes",
                    970:                ".endif",
                    971:                "",
                    972:                ".if ${USE_TOOLS:Mgettext}",
                    973:                "USES_GETTEXT=\tyes",
                    974:                ".endif")
                    975:
                    976:        seenDeveloper := false
                    977:        seenUsesGettext := false
                    978:
                    979:        mklines.ForEach(func(mkline MkLine) {
                    980:                if mkline.IsVarassign() {
                    981:                        switch mkline.Varname() {
                    982:                        case "DEVELOPER":
                    983:                                c.Check(mklines.indentation.IsConditional(), equals, true)
                    984:                                seenDeveloper = true
                    985:                        case "USES_GETTEXT":
                    986:                                c.Check(mklines.indentation.IsConditional(), equals, true)
                    987:                                seenUsesGettext = true
                    988:                        }
                    989:                }
                    990:        })
                    991:
                    992:        c.Check(seenDeveloper, equals, true)
                    993:        c.Check(seenUsesGettext, equals, true)
                    994: }
1.30      rillig    995:
1.32      rillig    996: // At 2018-12-02, pkglint had resolved ${MY_PLIST_VARS} into a single word,
                    997: // whereas the correct behavior is to resolve it into two words.
                    998: // It had produced warnings about mismatched PLIST_VARS IDs.
                    999: func (s *Suite) Test_MkLines_checkVarassignPlist__indirect(c *check.C) {
                   1000:        t := s.Init(c)
                   1001:
1.34      rillig   1002:        t.SetUpVartypes()
                   1003:        mklines := t.SetUpFileMkLines("plist.mk",
1.32      rillig   1004:                MkRcsID,
                   1005:                "",
                   1006:                "MY_PLIST_VARS=\tvar1 var2",
                   1007:                "PLIST_VARS+=\t${MY_PLIST_VARS}",
                   1008:                "",
                   1009:                "PLIST.var1=\tyes",
                   1010:                "PLIST.var2=\tyes")
                   1011:
                   1012:        mklines.Check()
                   1013:
                   1014:        t.CheckOutputEmpty()
                   1015: }
                   1016:
                   1017: func (s *Suite) Test_VaralignBlock_Process__autofix(c *check.C) {
1.30      rillig   1018:        t := s.Init(c)
                   1019:
1.34      rillig   1020:        t.SetUpCommandLine("-Wspace", "--show-autofix")
1.30      rillig   1021:
1.31      rillig   1022:        mklines := t.NewMkLines("file.mk",
1.30      rillig   1023:                "VAR=   value",    // Indentation 7, fixed to 8.
                   1024:                "",                //
                   1025:                "VAR=    value",   // Indentation 8, fixed to 8.
                   1026:                "",                //
                   1027:                "VAR=     value",  // Indentation 9, fixed to 8.
                   1028:                "",                //
                   1029:                "VAR= \tvalue",    // Mixed indentation 8, fixed to 8.
                   1030:                "",                //
                   1031:                "VAR=   \tvalue",  // Mixed indentation 8, fixed to 8.
                   1032:                "",                //
                   1033:                "VAR=    \tvalue", // Mixed indentation 16, fixed to 16.
                   1034:                "",                //
                   1035:                "VAR=\tvalue")     // Already aligned with tabs only, left unchanged.
                   1036:
1.31      rillig   1037:        var varalign VaralignBlock
                   1038:        for _, line := range mklines.mklines {
1.32      rillig   1039:                varalign.Process(line)
1.30      rillig   1040:        }
                   1041:        varalign.Finish()
                   1042:
                   1043:        t.CheckOutputLines(
                   1044:                "NOTE: file.mk:1: This variable value should be aligned with tabs, not spaces, to column 9.",
                   1045:                "AUTOFIX: file.mk:1: Replacing \"   \" with \"\\t\".",
                   1046:                "NOTE: file.mk:3: Variable values should be aligned with tabs, not spaces.",
                   1047:                "AUTOFIX: file.mk:3: Replacing \"    \" with \"\\t\".",
                   1048:                "NOTE: file.mk:5: This variable value should be aligned with tabs, not spaces, to column 9.",
                   1049:                "AUTOFIX: file.mk:5: Replacing \"     \" with \"\\t\".",
                   1050:                "NOTE: file.mk:7: Variable values should be aligned with tabs, not spaces.",
                   1051:                "AUTOFIX: file.mk:7: Replacing \" \\t\" with \"\\t\".",
                   1052:                "NOTE: file.mk:9: Variable values should be aligned with tabs, not spaces.",
                   1053:                "AUTOFIX: file.mk:9: Replacing \"   \\t\" with \"\\t\".",
                   1054:                "NOTE: file.mk:11: Variable values should be aligned with tabs, not spaces.",
                   1055:                "AUTOFIX: file.mk:11: Replacing \"    \\t\" with \"\\t\\t\".")
                   1056: }
                   1057:
1.31      rillig   1058: // When the lines of a paragraph are inconsistently aligned,
                   1059: // they are realigned to the minimum required width.
1.32      rillig   1060: func (s *Suite) Test_VaralignBlock_Process__reduce_indentation(c *check.C) {
1.30      rillig   1061:        t := s.Init(c)
                   1062:
                   1063:        mklines := t.NewMkLines("file.mk",
                   1064:                "VAR= \tvalue",
                   1065:                "VAR=    \tvalue",
                   1066:                "VAR=\t\t\t\tvalue",
                   1067:                "",
                   1068:                "VAR=\t\t\tneedlessly", // Nothing to be fixed here, since it looks good.
                   1069:                "VAR=\t\t\tdeep",
                   1070:                "VAR=\t\t\tindentation")
                   1071:
1.31      rillig   1072:        var varalign VaralignBlock
1.30      rillig   1073:        for _, mkline := range mklines.mklines {
1.32      rillig   1074:                varalign.Process(mkline)
1.30      rillig   1075:        }
                   1076:        varalign.Finish()
                   1077:
                   1078:        t.CheckOutputLines(
                   1079:                "NOTE: file.mk:1: Variable values should be aligned with tabs, not spaces.",
                   1080:                "NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 9.",
                   1081:                "NOTE: file.mk:3: This variable value should be aligned to column 9.")
                   1082: }
                   1083:
1.31      rillig   1084: // For every variable assignment, there is at least one space or tab between the variable
                   1085: // name and the value. Even if it is the longest line, and even if the value would start
                   1086: // exactly at a tab stop.
1.32      rillig   1087: func (s *Suite) Test_VaralignBlock_Process__longest_line_no_space(c *check.C) {
1.30      rillig   1088:        t := s.Init(c)
                   1089:
1.34      rillig   1090:        t.SetUpCommandLine("-Wspace")
1.30      rillig   1091:        mklines := t.NewMkLines("file.mk",
                   1092:                "SUBST_CLASSES+= aaaaaaaa",
                   1093:                "SUBST_STAGE.aaaaaaaa= pre-configure",
                   1094:                "SUBST_FILES.aaaaaaaa= *.pl",
1.31      rillig   1095:                "SUBST_FILTER_CMD.aaaaaa=cat")
1.30      rillig   1096:
1.31      rillig   1097:        var varalign VaralignBlock
1.30      rillig   1098:        for _, mkline := range mklines.mklines {
1.32      rillig   1099:                varalign.Process(mkline)
1.30      rillig   1100:        }
                   1101:        varalign.Finish()
                   1102:
                   1103:        t.CheckOutputLines(
                   1104:                "NOTE: file.mk:1: This variable value should be aligned with tabs, not spaces, to column 33.",
                   1105:                "NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 33.",
                   1106:                "NOTE: file.mk:3: This variable value should be aligned with tabs, not spaces, to column 33.",
                   1107:                "NOTE: file.mk:4: This variable value should be aligned to column 33.")
                   1108: }
                   1109:
1.32      rillig   1110: func (s *Suite) Test_VaralignBlock_Process__only_spaces(c *check.C) {
1.30      rillig   1111:        t := s.Init(c)
                   1112:
1.34      rillig   1113:        t.SetUpCommandLine("-Wspace")
1.30      rillig   1114:        mklines := t.NewMkLines("file.mk",
                   1115:                "SUBST_CLASSES+= aaaaaaaa",
                   1116:                "SUBST_STAGE.aaaaaaaa= pre-configure",
                   1117:                "SUBST_FILES.aaaaaaaa= *.pl",
                   1118:                "SUBST_FILTER_CMD.aaaaaaaa= cat")
                   1119:
1.31      rillig   1120:        var varalign VaralignBlock
1.30      rillig   1121:        for _, mkline := range mklines.mklines {
1.32      rillig   1122:                varalign.Process(mkline)
1.30      rillig   1123:        }
                   1124:        varalign.Finish()
                   1125:
                   1126:        t.CheckOutputLines(
                   1127:                "NOTE: file.mk:1: This variable value should be aligned with tabs, not spaces, to column 33.",
                   1128:                "NOTE: file.mk:2: This variable value should be aligned with tabs, not spaces, to column 33.",
                   1129:                "NOTE: file.mk:3: This variable value should be aligned with tabs, not spaces, to column 33.",
                   1130:                "NOTE: file.mk:4: This variable value should be aligned with tabs, not spaces, to column 33.")
                   1131: }

CVSweb <webmaster@jp.NetBSD.org>