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