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>