Files
pkgsrc-ng/pkgtools/pkglint/files/shell_test.go
2016-11-18 22:39:22 +01:00

513 lines
19 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package main
import (
check "gopkg.in/check.v1"
)
func (s *Suite) Test_splitIntoShellTokens__line_continuation(c *check.C) {
words, rest := splitIntoShellTokens(dummyLine, "if true; then \\")
c.Check(words, check.DeepEquals, []string{"if", "true", ";", "then"})
c.Check(rest, equals, "\\")
c.Check(s.Output(), equals, "WARN: Pkglint parse error in ShTokenizer.ShAtom at \"\\\\\" (quoting=plain)\n")
}
func (s *Suite) Test_splitIntoShellTokens__dollar_slash(c *check.C) {
words, rest := splitIntoShellTokens(dummyLine, "pax -s /.*~$$//g")
c.Check(words, check.DeepEquals, []string{"pax", "-s", "/.*~$$//g"})
c.Check(rest, equals, "")
}
func (s *Suite) Test_splitIntoShellTokens__dollar_subshell(c *check.C) {
words, rest := splitIntoShellTokens(dummyLine, "id=$$(${AWK} '{print}' < ${WRKSRC}/idfile) && echo \"$$id\"")
c.Check(words, deepEquals, []string{"id=", "$$(", "${AWK}", "'{print}'", "<", "${WRKSRC}/idfile", ")", "&&", "echo", "\"$$id\""})
c.Check(rest, equals, "")
}
func (s *Suite) Test_splitIntoShellTokens__semicolons(c *check.C) {
words, rest := splitIntoShellTokens(dummyLine, "word1 word2;;;")
c.Check(words, deepEquals, []string{"word1", "word2", ";;", ";"})
c.Check(rest, equals, "")
}
func (s *Suite) Test_splitIntoShellTokens__whitespace(c *check.C) {
text := "\t${RUN} cd ${WRKSRC}&&(${ECHO} ${PERL5:Q};${ECHO})|${BASH} ./install"
words, rest := splitIntoShellTokens(dummyLine, text)
c.Check(words, deepEquals, []string{
"${RUN}",
"cd", "${WRKSRC}",
"&&", "(", "${ECHO}", "${PERL5:Q}", ";", "${ECHO}", ")",
"|", "${BASH}", "./install"})
c.Check(rest, equals, "")
}
func (s *Suite) Test_splitIntoShellTokens__varuse_with_embedded_space_and_other_vars(c *check.C) {
varuseWord := "${GCONF_SCHEMAS:@.s.@${INSTALL_DATA} ${WRKSRC}/src/common/dbus/${.s.} ${DESTDIR}${GCONF_SCHEMAS_DIR}/@}"
words, rest := splitIntoShellTokens(dummyLine, varuseWord)
c.Check(words, deepEquals, []string{varuseWord})
c.Check(rest, equals, "")
}
func (s *Suite) Test_splitIntoMkWords__semicolons(c *check.C) {
words, rest := splitIntoMkWords(dummyLine, "word1 word2;;;")
c.Check(words, deepEquals, []string{"word1", "word2;;;"})
c.Check(rest, equals, "")
}
func (s *Suite) Test_splitIntoShellTokens__varuse_with_embedded_space(c *check.C) {
words, rest := splitIntoShellTokens(dummyLine, "${VAR:S/ /_/g}")
c.Check(words, deepEquals, []string{"${VAR:S/ /_/g}"})
c.Check(rest, equals, "")
}
func (s *Suite) Test_splitIntoMkWords__varuse_with_embedded_space(c *check.C) {
words, rest := splitIntoMkWords(dummyLine, "${VAR:S/ /_/g}")
c.Check(words, deepEquals, []string{"${VAR:S/ /_/g}"})
c.Check(rest, equals, "")
}
func (s *Suite) Test_splitIntoShellTokens__redirect(c *check.C) {
words, rest := splitIntoShellTokens(dummyLine, "echo 1>output 2>>append 3>|clobber 4>&5 6<input >>append")
c.Check(words, deepEquals, []string{
"echo",
"1>", "output",
"2>>", "append",
"3>|", "clobber",
"4>&", "5",
"6<", "input",
">>", "append"})
c.Check(rest, equals, "")
words, rest = splitIntoShellTokens(dummyLine, "echo 1> output 2>> append 3>| clobber 4>& 5 6< input >> append")
c.Check(words, deepEquals, []string{
"echo",
"1>", "output",
"2>>", "append",
"3>|", "clobber",
"4>&", "5",
"6<", "input",
">>", "append"})
c.Check(rest, equals, "")
}
func (s *Suite) Test_ShellLine_CheckShellCommandLine(c *check.C) {
s.UseCommandLine(c, "-Wall")
G.Mk = s.NewMkLines("fname",
"# dummy")
shline := NewShellLine(G.Mk.mklines[0])
shline.CheckShellCommandLine("@# Comment")
c.Check(s.Output(), equals, "")
shline.CheckShellCommandLine("uname=`uname`; echo $$uname; echo")
c.Check(s.Output(), equals, ""+
"WARN: fname:1: Unknown shell command \"uname\".\n"+
"WARN: fname:1: Unknown shell command \"echo\".\n"+
"WARN: fname:1: Unknown shell command \"echo\".\n")
s.RegisterTool(&Tool{Name: "echo", Predefined: true})
G.Mk = s.NewMkLines("fname",
"# dummy")
G.globalData.InitVartypes()
shline.CheckShellCommandLine("echo ${PKGNAME:Q}") // vucQuotPlain
c.Check(s.Output(), equals, ""+
"WARN: fname:1: PKGNAME may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.\n"+
"NOTE: fname:1: The :Q operator isn't necessary for ${PKGNAME} here.\n")
shline.CheckShellCommandLine("echo \"${CFLAGS:Q}\"") // vucQuotDquot
c.Check(s.Output(), equals, ""+
"WARN: fname:1: Please don't use the :Q operator in double quotes.\n"+
"WARN: fname:1: CFLAGS may not be used in this file; it would be ok in Makefile, Makefile.common, options.mk, *.mk.\n"+
"WARN: fname:1: Please use ${CFLAGS:M*:Q} instead of ${CFLAGS:Q} and make sure the variable appears outside of any quoting characters.\n")
shline.CheckShellCommandLine("echo '${COMMENT:Q}'") // vucQuotSquot
c.Check(s.Output(), equals, ""+
"WARN: fname:1: COMMENT may not be used in any file; it is a write-only variable.\n"+
"WARN: fname:1: Please move ${COMMENT:Q} outside of any quoting characters.\n")
shline.CheckShellCommandLine("echo target=$@ exitcode=$$? '$$' \"\\$$\"")
c.Check(s.Output(), equals, ""+
"WARN: fname:1: Please use \"${.TARGET}\" instead of \"$@\".\n"+
"WARN: fname:1: The $? shell variable is often not available in \"set -e\" mode.\n")
shline.CheckShellCommandLine("echo $$@")
c.Check(s.Output(), equals, "WARN: fname:1: The $@ shell variable should only be used in double quotes.\n")
shline.CheckShellCommandLine("echo \"$$\"") // As seen by make(1); the shell sees: echo "$"
c.Check(s.Output(), equals, ""+
"WARN: fname:1: Pkglint parse error in ShTokenizer.ShAtom at \"$$\\\"\" (quoting=d)\n"+
"WARN: fname:1: Pkglint ShellLine.CheckShellCommand: parse error at [\"]\n")
shline.CheckShellCommandLine("echo \"\\n\"")
c.Check(s.Output(), equals, "")
shline.CheckShellCommandLine("${RUN} for f in *.c; do echo $${f%.c}; done")
c.Check(s.Output(), equals, "")
shline.CheckShellCommandLine("${RUN} echo $${variable+set}")
c.Check(s.Output(), equals, "")
// Based on mail/thunderbird/Makefile, rev. 1.159
shline.CheckShellCommandLine("${RUN} subdir=\"`unzip -c \"$$e\" install.rdf | awk '/re/ { print \"hello\" }'`\"")
c.Check(s.Output(), equals, ""+
"WARN: fname:1: The exitcode of the left-hand-side command of the pipe operator is ignored.\n"+
"WARN: fname:1: Unknown shell command \"unzip\".\n"+
"WARN: fname:1: Unknown shell command \"awk\".\n")
// From mail/thunderbird/Makefile, rev. 1.159
shline.CheckShellCommandLine("" +
"${RUN} for e in ${XPI_FILES}; do " +
" subdir=\"`${UNZIP_CMD} -c \"$$e\" install.rdf | awk '/^ <em:id>/ {sub(\".*<em:id>\",\"\");sub(\"</em:id>.*\",\"\");print;exit;}'`\" && " +
" ${MKDIR} \"${WRKDIR}/extensions/$$subdir\" && " +
" cd \"${WRKDIR}/extensions/$$subdir\" && " +
" ${UNZIP_CMD} -aqo $$e; " +
"done")
c.Check(s.Output(), equals, ""+
"WARN: fname:1: XPI_FILES is used but not defined. Spelling mistake?\n"+
"WARN: fname:1: The exitcode of the left-hand-side command of the pipe operator is ignored.\n"+
"WARN: fname:1: UNZIP_CMD is used but not defined. Spelling mistake?\n"+
"WARN: fname:1: Unknown shell command \"awk\".\n"+
"WARN: fname:1: Unknown shell command \"${MKDIR}\".\n"+
"WARN: fname:1: MKDIR is used but not defined. Spelling mistake?\n"+
"WARN: fname:1: UNZIP_CMD is used but not defined. Spelling mistake?\n")
// From x11/wxGTK28/Makefile
shline.CheckShellCommandLine("" +
"set -e; cd ${WRKSRC}/locale; " +
"for lang in *.po; do " +
" [ \"$${lang}\" = \"wxstd.po\" ] && continue; " +
" ${TOOLS_PATH.msgfmt} -c -o \"$${lang%.po}.mo\" \"$${lang}\"; " +
"done")
c.Check(s.Output(), equals, ""+
"WARN: fname:1: WRKSRC may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.\n"+
"WARN: fname:1: Unknown shell command \"[\".\n"+
"WARN: fname:1: Unknown shell command \"${TOOLS_PATH.msgfmt}\".\n")
shline.CheckShellCommandLine("@cp from to")
c.Check(s.Output(), equals, ""+
"WARN: fname:1: The shell command \"cp\" should not be hidden.\n"+
"WARN: fname:1: Unknown shell command \"cp\".\n")
shline.CheckShellCommandLine("${RUN} ${INSTALL_DATA_DIR} share/pkgbase ${PREFIX}/share/pkgbase")
c.Check(s.Output(), equals, ""+
"NOTE: fname:1: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= share/pkgbase\" instead of \"${INSTALL_DATA_DIR}\".\n"+
"WARN: fname:1: The INSTALL_*_DIR commands can only handle one directory at a time.\n")
// See PR 46570, item "1. It does not"
shline.CheckShellCommandLine("for x in 1 2 3; do echo \"$$x\" || exit 1; done")
c.Check(s.Output(), equals, "") // No warning about missing error checking.
}
func (s *Suite) Test_ShellLine_CheckShellCommandLine__nofix(c *check.C) {
s.UseCommandLine(c, "-Wall")
G.globalData.InitVartypes()
s.RegisterTool(&Tool{Name: "echo", Predefined: true})
G.Mk = s.NewMkLines("Makefile",
"\techo ${PKGNAME:Q}")
shline := NewShellLine(G.Mk.mklines[0])
c.Check(shline.line.raw[0].textnl, equals, "\techo ${PKGNAME:Q}\n")
c.Check(shline.line.raw[0].Lineno, equals, 1)
shline.CheckShellCommandLine("echo ${PKGNAME:Q}")
c.Check(s.Output(), equals, ""+
"NOTE: Makefile:1: The :Q operator isn't necessary for ${PKGNAME} here.\n")
}
func (s *Suite) Test_ShellLine_CheckShellCommandLine__show_autofix(c *check.C) {
s.UseCommandLine(c, "-Wall", "--show-autofix")
G.globalData.InitVartypes()
s.RegisterTool(&Tool{Name: "echo", Predefined: true})
G.Mk = s.NewMkLines("Makefile",
"\techo ${PKGNAME:Q}")
shline := NewShellLine(G.Mk.mklines[0])
shline.CheckShellCommandLine("echo ${PKGNAME:Q}")
c.Check(s.Output(), equals, ""+
"NOTE: Makefile:1: The :Q operator isn't necessary for ${PKGNAME} here.\n"+
"AUTOFIX: Makefile:1: Replacing \"${PKGNAME:Q}\" with \"${PKGNAME}\".\n")
}
func (s *Suite) Test_ShellLine_CheckShellCommandLine__autofix(c *check.C) {
s.UseCommandLine(c, "-Wall", "--autofix")
G.globalData.InitVartypes()
s.RegisterTool(&Tool{Name: "echo", Predefined: true})
G.Mk = s.NewMkLines("Makefile",
"\techo ${PKGNAME:Q}")
shline := NewShellLine(G.Mk.mklines[0])
shline.CheckShellCommandLine("echo ${PKGNAME:Q}")
c.Check(s.Output(), equals, ""+
"AUTOFIX: Makefile:1: Replacing \"${PKGNAME:Q}\" with \"${PKGNAME}\".\n")
}
func (s *Suite) Test_ShellLine_CheckShellCommandLine__implementation(c *check.C) {
s.UseCommandLine(c, "-Wall")
G.globalData.InitVartypes()
G.Mk = s.NewMkLines("fname",
"# dummy")
shline := NewShellLine(G.Mk.mklines[0])
// foobar="`echo \"foo bar\"`"
text := "foobar=\"`echo \\\"foo bar\\\"`\""
tokens, rest := splitIntoShellTokens(dummyLine, text)
c.Check(tokens, deepEquals, []string{text})
c.Check(rest, equals, "")
shline.CheckWord(text, false)
c.Check(s.Output(), equals, "WARN: fname:1: Unknown shell command \"echo\".\n")
shline.CheckShellCommandLine(text)
c.Check(s.Output(), equals, ""+ // No parse errors
"WARN: fname:1: Unknown shell command \"echo\".\n")
}
func (s *Suite) Test_ShellLine_CheckShelltext__dollar_without_variable(c *check.C) {
G.globalData.InitVartypes()
G.Mk = s.NewMkLines("fname",
"# dummy")
shline := NewShellLine(G.Mk.mklines[0])
s.RegisterTool(&Tool{Name: "pax", Varname: "PAX"})
G.Mk.tools["pax"] = true
shline.CheckShellCommandLine("pax -rwpp -s /.*~$$//g . ${DESTDIR}${PREFIX}")
c.Check(s.Output(), equals, "")
}
func (s *Suite) Test_ShellLine_CheckWord(c *check.C) {
s.UseCommandLine(c, "-Wall")
G.globalData.InitVartypes()
shline := NewShellLine(NewMkLine(NewLine("fname", 1, "# dummy", nil)))
shline.CheckWord("${${list}}", false)
c.Check(s.Output(), equals, "") // No warning for variables that are completely indirect.
shline.CheckWord("${SED_FILE.${id}}", false)
c.Check(s.Output(), equals, "") // No warning for variables that are partly indirect.
shline.CheckWord("\"$@\"", false)
c.Check(s.Output(), equals, "WARN: fname:1: Please use \"${.TARGET}\" instead of \"$@\".\n")
shline.CheckWord("${COMMENT:Q}", true)
c.Check(s.Output(), equals, "WARN: fname:1: COMMENT may not be used in any file; it is a write-only variable.\n")
shline.CheckWord("\"${DISTINFO_FILE:Q}\"", true)
c.Check(s.Output(), equals, ""+
"WARN: fname:1: DISTINFO_FILE may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.\n"+
"NOTE: fname:1: The :Q operator isn't necessary for ${DISTINFO_FILE} here.\n")
shline.CheckWord("embed${DISTINFO_FILE:Q}ded", true)
c.Check(s.Output(), equals, ""+
"WARN: fname:1: DISTINFO_FILE may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.\n"+
"NOTE: fname:1: The :Q operator isn't necessary for ${DISTINFO_FILE} here.\n")
shline.CheckWord("s,\\.,,", true)
c.Check(s.Output(), equals, "")
shline.CheckWord("\"s,\\.,,\"", true)
c.Check(s.Output(), equals, "")
}
func (s *Suite) Test_ShellLine_CheckWord__dollar_without_variable(c *check.C) {
shline := NewShellLine(NewMkLine(NewLine("fname", 1, "# dummy", nil)))
shline.CheckWord("/.*~$$//g", false) // Typical argument to pax(1).
c.Check(s.Output(), equals, "")
}
func (s *Suite) Test_ShellLine_CheckShellCommandLine__echo(c *check.C) {
s.UseCommandLine(c, "-Wall")
s.RegisterTool(&Tool{Name: "echo", Varname: "ECHO", MustUseVarForm: true, Predefined: true})
G.Mk = s.NewMkLines("fname",
"# dummy")
mkline := NewMkLine(NewLine("fname", 3, "# dummy", nil))
mkline.checkText("echo \"hello, world\"")
c.Check(s.Output(), equals, "")
NewShellLine(mkline).CheckShellCommandLine("echo \"hello, world\"")
c.Check(s.Output(), equals, ""+
"WARN: fname:3: Please use \"${ECHO}\" instead of \"echo\".\n")
}
func (s *Suite) Test_ShellLine_CheckShellCommandLine__shell_variables(c *check.C) {
text := "\tfor f in *.pl; do ${SED} s,@PREFIX@,${PREFIX}, < $f > $f.tmp && ${MV} $f.tmp $f; done"
shline := NewShellLine(NewMkLine(NewLine("Makefile", 3, text, nil)))
shline.CheckShellCommandLine(text)
c.Check(s.Output(), equals, ""+
"WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.\n"+
"WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.\n"+
"WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.\n"+
"WARN: Makefile:3: $f is ambiguous. Use ${f} if you mean a Makefile variable or $$f if you mean a shell variable.\n"+
"NOTE: Makefile:3: Please use the SUBST framework instead of ${SED} and ${MV}.\n")
shline.CheckShellCommandLine("install -c manpage.1 ${PREFIX}/man/man1/manpage.1")
c.Check(s.Output(), equals, "WARN: Makefile:3: Please use ${PKGMANDIR} instead of \"man\".\n")
shline.CheckShellCommandLine("cp init-script ${PREFIX}/etc/rc.d/service")
c.Check(s.Output(), equals, "WARN: Makefile:3: Please use the RCD_SCRIPTS mechanism to install rc.d scripts automatically to ${RCD_SCRIPTS_EXAMPLEDIR}.\n")
}
func (s *Suite) Test_ShellLine_checkCommandUse(c *check.C) {
G.Mk = s.NewMkLines("fname",
"# dummy")
G.Mk.target = "do-install"
shline := NewShellLine(NewMkLine(NewLine("fname", 1, "\tdummy", nil)))
shline.checkCommandUse("sed")
c.Check(s.Output(), equals, "WARN: fname:1: The shell command \"sed\" should not be used in the install phase.\n")
shline.checkCommandUse("cp")
c.Check(s.Output(), equals, "WARN: fname:1: ${CP} should not be used to install files.\n")
}
func (s *Suite) Test_splitIntoMkWords(c *check.C) {
url := "http://registry.gimp.org/file/fix-ca.c?action=download&id=9884&file="
words, rest := splitIntoShellTokens(dummyLine, url) // Doesnt really make sense
c.Check(words, check.DeepEquals, []string{"http://registry.gimp.org/file/fix-ca.c?action=download", "&", "id=9884", "&", "file="})
c.Check(rest, equals, "")
words, rest = splitIntoMkWords(dummyLine, url)
c.Check(words, check.DeepEquals, []string{"http://registry.gimp.org/file/fix-ca.c?action=download&id=9884&file="})
c.Check(rest, equals, "")
words, rest = splitIntoMkWords(dummyLine, "a b \"c c c\" d;;d;; \"e\"''`` 'rest")
c.Check(words, check.DeepEquals, []string{"a", "b", "\"c c c\"", "d;;d;;", "\"e\"''``"})
c.Check(rest, equals, "'rest")
}
func (s *Suite) Test_ShellLine_CheckShellCommandLine__sed_and_mv(c *check.C) {
shline := NewShellLine(NewMkLine(NewLine("Makefile", 85, "\t${RUN} ${SED} 's,#,// comment:,g' fname > fname.tmp; ${MV} fname.tmp fname", nil)))
shline.CheckShellCommandLine(shline.mkline.Shellcmd())
c.Check(s.Output(), equals, "NOTE: Makefile:85: Please use the SUBST framework instead of ${SED} and ${MV}.\n")
}
func (s *Suite) Test_ShellLine_CheckShellCommandLine__subshell(c *check.C) {
shline := NewShellLine(NewMkLine(NewLine("Makefile", 85, "\t${RUN} uname=$$(uname)", nil)))
shline.CheckShellCommandLine(shline.mkline.Shellcmd())
c.Check(s.Output(), equals, "WARN: Makefile:85: Invoking subshells via $(...) is not portable enough.\n")
}
func (s *Suite) Test_ShellLine_CheckShellCommandLine__install_dir(c *check.C) {
shline := NewShellLine(NewMkLine(NewLine("Makefile", 85, "\t${RUN} ${INSTALL_DATA_DIR} ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2", nil)))
shline.CheckShellCommandLine(shline.mkline.Shellcmd())
c.Check(s.Output(), equals, ""+
"NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL_DATA_DIR}\".\n"+
"NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL_DATA_DIR}\".\n"+
"WARN: Makefile:85: The INSTALL_*_DIR commands can only handle one directory at a time.\n")
shline.CheckShellCommandLine("${INSTALL_DATA_DIR} -d -m 0755 ${DESTDIR}${PREFIX}/share/examples/gdchart")
// No warning about multiple directories, since 0755 is an option, not an argument.
c.Check(s.Output(), equals, ""+
"NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= share/examples/gdchart\" instead of \"${INSTALL_DATA_DIR}\".\n")
shline.CheckShellCommandLine("${INSTALL_DATA_DIR} -d -m 0755 ${DESTDIR}${PREFIX}/dir1 ${PREFIX}/dir2")
c.Check(s.Output(), equals, ""+
"NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL_DATA_DIR}\".\n"+
"NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL_DATA_DIR}\".\n"+
"WARN: Makefile:85: The INSTALL_*_DIR commands can only handle one directory at a time.\n")
}
func (s *Suite) Test_ShellLine_CheckShellCommandLine__install_option_d(c *check.C) {
shline := NewShellLine(NewMkLine(NewLine("Makefile", 85, "\t${RUN} ${INSTALL} -d ${DESTDIR}${PREFIX}/dir1 ${DESTDIR}${PREFIX}/dir2", nil)))
shline.CheckShellCommandLine(shline.mkline.Shellcmd())
c.Check(s.Output(), equals, ""+
"NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir1\" instead of \"${INSTALL} -d\".\n"+
"NOTE: Makefile:85: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= dir2\" instead of \"${INSTALL} -d\".\n")
}
func (s *Suite) Test_ShellLine__shell_comment_with_line_continuation(c *check.C) {
tmpfile := s.CreateTmpFile(c, "Makefile", ""+
"# $"+"NetBSD$\n"+
"pre-install:\n"+
"\t"+"# comment\\\n"+
"\t"+"echo \"hello\"\n")
lines := LoadNonemptyLines(tmpfile, true)
NewMkLines(lines).Check()
c.Check(s.Output(), equals, "WARN: ~/Makefile:3--4: A shell comment does not stop at the end of line.\n")
}
func (s *Suite) Test_ShellLine_unescapeBackticks(c *check.C) {
shline := NewShellLine(NewMkLine(dummyLine))
// foobar="`echo \"foo bar\"`"
text := "foobar=\"`echo \\\"foo bar\\\"`\""
repl := NewPrefixReplacer(text)
repl.AdvanceStr("foobar=\"`")
backtCommand, newQuoting := shline.unescapeBackticks(text, repl, shqDquotBackt)
c.Check(backtCommand, equals, "echo \"foo bar\"")
c.Check(newQuoting, equals, shqDquot)
c.Check(repl.rest, equals, "\"")
}