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

Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.

Diff for /pkgsrc/pkgtools/pkglint/files/Attic/shell_test.go between version 1.33 and 1.34

version 1.33, 2018/11/07 20:58:23 version 1.34, 2018/12/02 01:57:48
Line 2  package main
Line 2  package main
   
 import (  import (
         "gopkg.in/check.v1"          "gopkg.in/check.v1"
           "strings"
 )  )
   
 func (s *Suite) Test_splitIntoShellTokens__line_continuation(c *check.C) {  func (s *Suite) Test_splitIntoShellTokens__line_continuation(c *check.C) {
Line 85  func (s *Suite) Test_splitIntoShellToken
Line 86  func (s *Suite) Test_splitIntoShellToken
         c.Check(rest, equals, "")          c.Check(rest, equals, "")
 }  }
   
   // Two shell variables, next to each other,
   // are two separate atoms but count as a single token.
   func (s *Suite) Test_splitIntoShellTokens__two_shell_variables(c *check.C) {
           code := "echo $$i$$j"
           words, rest := splitIntoShellTokens(dummyLine, code)
   
           c.Check(words, deepEquals, []string{"echo", "$$i$$j"})
           c.Check(rest, equals, "")
   }
   
 func (s *Suite) Test_splitIntoMkWords__semicolons(c *check.C) {  func (s *Suite) Test_splitIntoMkWords__semicolons(c *check.C) {
         words, rest := splitIntoMkWords(dummyLine, "word1 word2;;;")          words, rest := splitIntoMkWords(dummyLine, "word1 word2;;;")
   
Line 142  func (s *Suite) Test_ShellLine_CheckShel
Line 153  func (s *Suite) Test_ShellLine_CheckShel
         t.SetupTool("unzip", "UNZIP_CMD", AtRunTime)          t.SetupTool("unzip", "UNZIP_CMD", AtRunTime)
   
         checkShellCommandLine := func(shellCommand string) {          checkShellCommandLine := func(shellCommand string) {
                 G.Mk = t.NewMkLines("fileName",                  G.Mk = t.NewMkLines("filename",
                         "\t"+shellCommand)                          "\t"+shellCommand)
                 shline := NewShellLine(G.Mk.mklines[0])                  shline := NewShellLine(G.Mk.mklines[0])
   
Line 158  func (s *Suite) Test_ShellLine_CheckShel
Line 169  func (s *Suite) Test_ShellLine_CheckShel
         checkShellCommandLine("uname=`uname`; echo $$uname; echo; ${PREFIX}/bin/command")          checkShellCommandLine("uname=`uname`; echo $$uname; echo; ${PREFIX}/bin/command")
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName:1: Unknown shell command \"uname\".",                  "WARN: filename:1: Unknown shell command \"uname\".",
                 "WARN: fileName:1: Please switch to \"set -e\" mode before using a semicolon (after \"uname=`uname`\") to separate commands.",                  "WARN: filename:1: Please switch to \"set -e\" mode before using a semicolon (after \"uname=`uname`\") to separate commands.",
                 "WARN: fileName:1: Unknown shell command \"echo\".",                  "WARN: filename:1: Unknown shell command \"echo\".",
                 "WARN: fileName:1: Unknown shell command \"echo\".")                  "WARN: filename:1: Unknown shell command \"echo\".")
   
         t.SetupTool("echo", "", AtRunTime)          t.SetupTool("echo", "", AtRunTime)
         t.SetupVartypes()          t.SetupVartypes()
Line 169  func (s *Suite) Test_ShellLine_CheckShel
Line 180  func (s *Suite) Test_ShellLine_CheckShel
         checkShellCommandLine("echo ${PKGNAME:Q}") // vucQuotPlain          checkShellCommandLine("echo ${PKGNAME:Q}") // vucQuotPlain
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName:1: PKGNAME may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.",                  "WARN: filename:1: PKGNAME may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.",
                 "NOTE: fileName:1: The :Q operator isn't necessary for ${PKGNAME} here.")                  "NOTE: filename:1: The :Q operator isn't necessary for ${PKGNAME} here.")
   
         checkShellCommandLine("echo \"${CFLAGS:Q}\"") // vucQuotDquot          checkShellCommandLine("echo \"${CFLAGS:Q}\"") // vucQuotDquot
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName:1: Please don't use the :Q operator in double quotes.",                  "WARN: filename:1: Please don't use the :Q operator in double quotes.",
                 "WARN: fileName:1: CFLAGS may not be used in this file; "+                  "WARN: filename:1: CFLAGS may not be used in this file; "+
                         "it would be ok in Makefile, Makefile.common, options.mk, *.mk.",                          "it would be ok in Makefile, Makefile.common, options.mk, *.mk.",
                 "WARN: fileName:1: Please use ${CFLAGS:M*:Q} instead of ${CFLAGS:Q} "+                  "WARN: filename:1: Please use ${CFLAGS:M*:Q} instead of ${CFLAGS:Q} "+
                         "and make sure the variable appears outside of any quoting characters.")                          "and make sure the variable appears outside of any quoting characters.")
   
         checkShellCommandLine("echo '${COMMENT:Q}'") // vucQuotSquot          checkShellCommandLine("echo '${COMMENT:Q}'") // vucQuotSquot
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName:1: COMMENT may not be used in any file; it is a write-only variable.",                  "WARN: filename:1: COMMENT may not be used in any file; it is a write-only variable.",
                 "WARN: fileName:1: Please move ${COMMENT:Q} outside of any quoting characters.")                  "WARN: filename:1: Please move ${COMMENT:Q} outside of any quoting characters.")
   
         checkShellCommandLine("echo target=$@ exitcode=$$? '$$' \"\\$$\"")          checkShellCommandLine("echo target=$@ exitcode=$$? '$$' \"\\$$\"")
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName:1: Please use \"${.TARGET}\" instead of \"$@\".",                  "WARN: filename:1: Please use \"${.TARGET}\" instead of \"$@\".",
                 "WARN: fileName:1: The $? shell variable is often not available in \"set -e\" mode.")                  "WARN: filename:1: The $? shell variable is often not available in \"set -e\" mode.")
   
         checkShellCommandLine("echo $$@")          checkShellCommandLine("echo $$@")
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName:1: The $@ shell variable should only be used in double quotes.")                  "WARN: filename:1: The $@ shell variable should only be used in double quotes.")
   
         checkShellCommandLine("echo \"$$\"") // As seen by make(1); the shell sees: echo "$"          checkShellCommandLine("echo \"$$\"") // As seen by make(1); the shell sees: echo "$"
   
         t.CheckOutputLines(          // No warning about a possibly missed variable name.
                 "WARN: fileName:1: Unescaped $ or strange shell variable found.")          // This occurs only rarely, and typically as part of a regular expression
           // where it is used intentionally.
           t.CheckOutputEmpty()
   
         checkShellCommandLine("echo \"\\n\"")          checkShellCommandLine("echo \"\\n\"")
   
Line 219  func (s *Suite) Test_ShellLine_CheckShel
Line 232  func (s *Suite) Test_ShellLine_CheckShel
         checkShellCommandLine("${RUN} subdir=\"`unzip -c \"$$e\" install.rdf | awk '/re/ { print \"hello\" }'`\"")          checkShellCommandLine("${RUN} subdir=\"`unzip -c \"$$e\" install.rdf | awk '/re/ { print \"hello\" }'`\"")
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName:1: The exitcode of \"unzip\" at the left of the | operator is ignored.")                  "WARN: filename:1: Double quotes inside backticks inside double quotes are error prone.",
                   "WARN: filename:1: The exitcode of \"unzip\" at the left of the | operator is ignored.")
   
         // From mail/thunderbird/Makefile, rev. 1.159          // From mail/thunderbird/Makefile, rev. 1.159
         checkShellCommandLine("" +          checkShellCommandLine("" +
Line 232  func (s *Suite) Test_ShellLine_CheckShel
Line 246  func (s *Suite) Test_ShellLine_CheckShel
                 "done")                  "done")
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName:1: XPI_FILES is used but not defined.",                  "WARN: filename:1: XPI_FILES is used but not defined.",
                 "WARN: fileName:1: The exitcode of \"${UNZIP_CMD}\" at the left of the | operator is ignored.")                  "WARN: filename:1: Double quotes inside backticks inside double quotes are error prone.",
                   "WARN: filename:1: The exitcode of \"${UNZIP_CMD}\" at the left of the | operator is ignored.")
   
         // From x11/wxGTK28/Makefile          // From x11/wxGTK28/Makefile
         checkShellCommandLine("" +          checkShellCommandLine("" +
Line 244  func (s *Suite) Test_ShellLine_CheckShel
Line 259  func (s *Suite) Test_ShellLine_CheckShel
                 "done")                  "done")
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName:1: WRKSRC may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.",                  "WARN: filename:1: WRKSRC may not be used in this file; it would be ok in Makefile, Makefile.*, *.mk.",
                 "WARN: fileName:1: Unknown shell command \"[\".",                  "WARN: filename:1: Unknown shell command \"[\".",
                 "WARN: fileName:1: Unknown shell command \"${TOOLS_PATH.msgfmt}\".")                  "WARN: filename:1: Unknown shell command \"${TOOLS_PATH.msgfmt}\".")
   
         checkShellCommandLine("@cp from to")          checkShellCommandLine("@cp from to")
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName:1: The shell command \"cp\" should not be hidden.")                  "WARN: filename:1: The shell command \"cp\" should not be hidden.")
   
         checkShellCommandLine("-cp from to")          checkShellCommandLine("-cp from to")
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName:1: Using a leading \"-\" to suppress errors is deprecated.")                  "WARN: filename:1: Using a leading \"-\" to suppress errors is deprecated.")
   
         checkShellCommandLine("-${MKDIR} deeply/nested/subdir")          checkShellCommandLine("-${MKDIR} deeply/nested/subdir")
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "NOTE: fileName:1: You don't need to use \"-\" before \"${MKDIR} deeply/nested/subdir\".",                  "NOTE: filename:1: You don't need to use \"-\" before \"${MKDIR} deeply/nested/subdir\".",
                 "WARN: fileName:1: Using a leading \"-\" to suppress errors is deprecated.")                  "WARN: filename:1: Using a leading \"-\" to suppress errors is deprecated.")
   
         G.Pkg = NewPackage(t.File("category/pkgbase"))          G.Pkg = NewPackage(t.File("category/pkgbase"))
         G.Pkg.Plist.Dirs["share/pkgbase"] = true          G.Pkg.Plist.Dirs["share/pkgbase"] = true
Line 271  func (s *Suite) Test_ShellLine_CheckShel
Line 286  func (s *Suite) Test_ShellLine_CheckShel
         checkShellCommandLine("${RUN} ${INSTALL_DATA_DIR} share/pkgbase ${PREFIX}/share/pkgbase")          checkShellCommandLine("${RUN} ${INSTALL_DATA_DIR} share/pkgbase ${PREFIX}/share/pkgbase")
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "NOTE: fileName:1: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= share/pkgbase\" "+                  "NOTE: filename:1: You can use AUTO_MKDIRS=yes or \"INSTALLATION_DIRS+= share/pkgbase\" "+
                         "instead of \"${INSTALL_DATA_DIR}\".",                          "instead of \"${INSTALL_DATA_DIR}\".",
                 "WARN: fileName:1: The INSTALL_*_DIR commands can only handle one directory at a time.")                  "WARN: filename:1: The INSTALL_*_DIR commands can only handle one directory at a time.")
   
         // A directory that is not found in the PLIST.          // A directory that is not found in the PLIST.
         checkShellCommandLine("${RUN} ${INSTALL_DATA_DIR} ${PREFIX}/share/other")          checkShellCommandLine("${RUN} ${INSTALL_DATA_DIR} ${PREFIX}/share/other")
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "NOTE: fileName:1: You can use \"INSTALLATION_DIRS+= share/other\" instead of \"${INSTALL_DATA_DIR}\".")                  "NOTE: filename:1: You can use \"INSTALLATION_DIRS+= share/other\" instead of \"${INSTALL_DATA_DIR}\".")
   
         G.Pkg = nil          G.Pkg = nil
   
Line 293  func (s *Suite) Test_ShellLine_CheckShel
Line 308  func (s *Suite) Test_ShellLine_CheckShel
         t := s.Init(c)          t := s.Init(c)
   
         checkShellCommandLine := func(shellCommand string) {          checkShellCommandLine := func(shellCommand string) {
                 G.Mk = t.NewMkLines("fileName",                  G.Mk = t.NewMkLines("filename",
                         "\t"+shellCommand)                          "\t"+shellCommand)
   
                 G.Mk.ForEach(func(mkline MkLine) {                  G.Mk.ForEach(func(mkline MkLine) {
Line 305  func (s *Suite) Test_ShellLine_CheckShel
Line 320  func (s *Suite) Test_ShellLine_CheckShel
         checkShellCommandLine("${STRIP} executable")          checkShellCommandLine("${STRIP} executable")
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName:1: Unknown shell command \"${STRIP}\".",                  "WARN: filename:1: Unknown shell command \"${STRIP}\".",
                 "WARN: fileName:1: STRIP is used but not defined.")                  "WARN: filename:1: STRIP is used but not defined.")
   
         t.SetupVartypes()          t.SetupVartypes()
   
Line 363  func (s *Suite) Test_ShellProgramChecker
Line 378  func (s *Suite) Test_ShellProgramChecker
                 "\t cat | right-side",                  "\t cat | right-side",
                 "\t cat | echo | right-side",                  "\t cat | echo | right-side",
                 "\t echo | cat | right-side",                  "\t echo | cat | right-side",
                 "\t sed s,s,s, fileName | right-side",                  "\t sed s,s,s, filename | right-side",
                 "\t sed s,s,s < input | right-side",                  "\t sed s,s,s < input | right-side",
                 "\t ./unknown | right-side",                  "\t ./unknown | right-side",
                 "\t var=value | right-side",                  "\t var=value | right-side",
Line 404  func (s *Suite) Test_ShellLine_CheckShel
Line 419  func (s *Suite) Test_ShellLine_CheckShel
         t := s.Init(c)          t := s.Init(c)
   
         t.SetupVartypes()          t.SetupVartypes()
         G.Mk = t.NewMkLines("fileName",          G.Mk = t.NewMkLines("filename",
                 "# dummy")                  "# dummy")
         shline := NewShellLine(G.Mk.mklines[0])          shline := NewShellLine(G.Mk.mklines[0])
   
Line 419  func (s *Suite) Test_ShellLine_CheckShel
Line 434  func (s *Suite) Test_ShellLine_CheckShel
         G.Mk.ForEach(func(mkline MkLine) { shline.CheckWord(text, false, RunTime) })          G.Mk.ForEach(func(mkline MkLine) { shline.CheckWord(text, false, RunTime) })
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName:1: Unknown shell command \"echo\".")                  "WARN: filename:1: Unknown shell command \"echo\".")
   
         G.Mk.ForEach(func(mkline MkLine) { shline.CheckShellCommandLine(text) })          G.Mk.ForEach(func(mkline MkLine) { shline.CheckShellCommandLine(text) })
   
         // No parse errors          // No parse errors
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName:1: Unknown shell command \"echo\".")                  "WARN: filename:1: Unknown shell command \"echo\".")
 }  }
   
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__dollar_without_variable(c *check.C) {  func (s *Suite) Test_ShellLine_CheckShellCommandLine__dollar_without_variable(c *check.C) {
Line 433  func (s *Suite) Test_ShellLine_CheckShel
Line 448  func (s *Suite) Test_ShellLine_CheckShel
   
         t.SetupVartypes()          t.SetupVartypes()
         t.SetupTool("pax", "", AtRunTime)          t.SetupTool("pax", "", AtRunTime)
         G.Mk = t.NewMkLines("fileName",          G.Mk = t.NewMkLines("filename",
                 "# dummy")                  "# dummy")
         shline := NewShellLine(G.Mk.mklines[0])          shline := NewShellLine(G.Mk.mklines[0])
   
Line 457  func (s *Suite) Test_ShellLine_CheckWord
Line 472  func (s *Suite) Test_ShellLine_CheckWord
   
         checkWord("${${list}}", false)          checkWord("${${list}}", false)
   
         t.CheckOutputEmpty() // No warning for variables that are completely indirect.          // No warning for the outer variable since it is completely indirect.
           // The inner variable ${list} must still be defined, though.
           t.CheckOutputLines(
                   "WARN: dummy.mk:1: list is used but not defined.",
                   "WARN: dummy.mk:1: list is used but not defined.")
   
         checkWord("${SED_FILE.${id}}", false)          checkWord("${SED_FILE.${id}}", false)
   
         t.CheckOutputEmpty() // No warning for variables that are partly indirect.          // No warning for variables that are partly indirect.
           t.CheckOutputLines(
                   "WARN: dummy.mk:1: id is used but not defined.")
   
         // The unquoted $@ takes a different code path in pkglint than the quoted $@.          // The unquoted $@ takes a different code path in pkglint than the quoted $@.
         checkWord("$@", false)          checkWord("$@", false)
Line 508  func (s *Suite) Test_ShellLine_CheckWord
Line 529  func (s *Suite) Test_ShellLine_CheckWord
 func (s *Suite) Test_ShellLine_CheckWord__dollar_without_variable(c *check.C) {  func (s *Suite) Test_ShellLine_CheckWord__dollar_without_variable(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         shline := t.NewShellLine("fileName", 1, "# dummy")          shline := t.NewShellLine("filename", 1, "# dummy")
   
         shline.CheckWord("/.*~$$//g", false, RunTime) // Typical argument to pax(1).          shline.CheckWord("/.*~$$//g", false, RunTime) // Typical argument to pax(1).
   
Line 519  func (s *Suite) Test_ShellLine_CheckWord
Line 540  func (s *Suite) Test_ShellLine_CheckWord
         t := s.Init(c)          t := s.Init(c)
   
         t.SetupTool("find", "FIND", AtRunTime)          t.SetupTool("find", "FIND", AtRunTime)
         shline := t.NewShellLine("fileName", 1, "\tfind . -exec rm -rf {} \\+")          shline := t.NewShellLine("filename", 1, "\tfind . -exec rm -rf {} \\+")
   
         shline.CheckShellCommandLine(shline.mkline.ShellCommand())          shline.CheckShellCommandLine(shline.mkline.ShellCommand())
   
         // FIXME: A backslash before any other character than "\` keeps its original meaning.          // A backslash before any other character than " \ ` is discarded by the parser.
         t.CheckOutputLines(          t.CheckOutputEmpty()
                 "WARN: fileName:1: Pkglint parse error in ShellLine.CheckWord at \"\\\\+\" (quoting=plain), rest: \\+")  
 }  }
   
 func (s *Suite) Test_ShellLine_CheckWord__squot_dollar(c *check.C) {  func (s *Suite) Test_ShellLine_CheckWord__squot_dollar(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         shline := t.NewShellLine("fileName", 1, "\t'$")          shline := t.NewShellLine("filename", 1, "\t'$")
   
         shline.CheckWord(shline.mkline.ShellCommand(), false, RunTime)          shline.CheckWord(shline.mkline.ShellCommand(), false, RunTime)
   
         // FIXME: Should be parsed correctly. Make passes the dollar through (probably),          // FIXME: Should be parsed correctly. Make passes the dollar through (probably),
         // and the shell parser should complain about the unfinished string literal.          // and the shell parser should complain about the unfinished string literal.
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName:1: Pkglint parse error in ShellLine.CheckWord at \"'$\" (quoting=s), rest: $")                  "WARN: filename:1: Pkglint parse error in ShTokenizer.ShAtom at \"$\" (quoting=s).",
                   "WARN: filename:1: Pkglint parse error in ShellLine.CheckWord at \"'$\" (quoting=s), rest: $")
 }  }
   
 func (s *Suite) Test_ShellLine_CheckWord__dquot_dollar(c *check.C) {  func (s *Suite) Test_ShellLine_CheckWord__dquot_dollar(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         shline := t.NewShellLine("fileName", 1, "\t\"$")          shline := t.NewShellLine("filename", 1, "\t\"$")
   
         shline.CheckWord(shline.mkline.ShellCommand(), false, RunTime)          shline.CheckWord(shline.mkline.ShellCommand(), false, RunTime)
   
         // FIXME: Should be parsed correctly. Make passes the dollar through (probably),          // FIXME: Should be parsed correctly. Make passes the dollar through (probably),
         // and the shell parser should complain about the unfinished string literal.          // and the shell parser should complain about the unfinished string literal.
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName:1: Pkglint parse error in ShellLine.CheckWord at \"\\\"$\" (quoting=d), rest: $")                  "WARN: filename:1: Pkglint parse error in ShTokenizer.ShAtom at \"$\" (quoting=d).",
                   "WARN: filename:1: Pkglint parse error in ShellLine.CheckWord at \"\\\"$\" (quoting=d), rest: $")
 }  }
   
 func (s *Suite) Test_ShellLine_CheckWord__dollar_subshell(c *check.C) {  func (s *Suite) Test_ShellLine_CheckWord__dollar_subshell(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         shline := t.NewShellLine("fileName", 1, "\t$$(echo output)")          shline := t.NewShellLine("filename", 1, "\t$$(echo output)")
   
         shline.CheckWord(shline.mkline.ShellCommand(), false, RunTime)          shline.CheckWord(shline.mkline.ShellCommand(), false, RunTime)
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName:1: Invoking subshells via $(...) is not portable enough.")                  "WARN: filename:1: Invoking subshells via $(...) is not portable enough.")
 }  }
   
 func (s *Suite) Test_ShellLine_CheckWord__PKGMANDIR(c *check.C) {  func (s *Suite) Test_ShellLine_CheckWord__PKGMANDIR(c *check.C) {
Line 585  func (s *Suite) Test_ShellLine_CheckWord
Line 607  func (s *Suite) Test_ShellLine_CheckWord
 func (s *Suite) Test_ShellLine_unescapeBackticks__unfinished(c *check.C) {  func (s *Suite) Test_ShellLine_unescapeBackticks__unfinished(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         mklines := t.NewMkLines("fileName.mk",          mklines := t.NewMkLines("filename.mk",
                 MkRcsID,                  MkRcsID,
                 "",                  "",
                 "pre-configure:",                  "pre-configure:",
Line 599  func (s *Suite) Test_ShellLine_unescapeB
Line 621  func (s *Suite) Test_ShellLine_unescapeB
   
         // FIXME: Mention the unfinished backquote.          // FIXME: Mention the unfinished backquote.
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName.mk:4: Pkglint ShellLine.CheckShellCommand: parse error at []string{\"\"}",                  "WARN: filename.mk:4: Pkglint ShellLine.CheckShellCommand: parse error at []string{\"\"}",
                 "WARN: fileName.mk:5: Pkglint ShellLine.CheckShellCommand: parse error at []string{\"echo\"}")                  "WARN: filename.mk:5: Pkglint ShellLine.CheckShellCommand: parse error at []string{\"echo\"}")
 }  }
   
 func (s *Suite) Test_ShellLine_unescapeBackticks__unfinished_direct(c *check.C) {  func (s *Suite) Test_ShellLine_unescapeBackticks__unfinished_direct(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
           mkline := t.NewMkLine("dummy.mk", 123, "\t# shell command")
   
         // This call is unrealistic. It doesn't happen in practice, and this          // This call is unrealistic. It doesn't happen in practice, and this
         // direct, forcing test is only to reach the code coverage.          // direct, forcing test is only to reach the code coverage.
         NewShellLine(dummyMkLine).unescapeBackticks(          atoms := []*ShAtom{
                 "dummy",                  NewShAtom(shtText, "`", shqBackt)}
                 G.NewPrefixReplacer(""),          NewShellLine(mkline).
                 shqBackt)                  unescapeBackticks(&atoms, shqBackt)
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "ERROR: Unfinished backquotes: ")                  "ERROR: dummy.mk:123: Unfinished backticks after \"\".")
 }  }
   
 func (s *Suite) Test_ShellLine_variableNeedsQuoting(c *check.C) {  func (s *Suite) Test_ShellLine_variableNeedsQuoting(c *check.C) {
   
           test := func(shVarname string, expected bool) {
                   c.Check((*ShellLine).variableNeedsQuoting(nil, shVarname), equals, expected)
           }
   
           test("#", false) // A length is always an integer.
           test("?", false) // The exit code is always an integer.
           test("$", false) // The PID is always an integer.
   
           // In most cases, file and directory names don't contain special characters,
           // and if they do, the package will probably not build. Therefore pkglint
           // doesn't require them to be quoted, but doing so does not hurt.
           test("d", false)    // Typically used for directories.
           test("f", false)    // Typically used for files.
           test("i", false)    // Typically used for literal values without special characters.
           test("id", false)   // Identifiers usually don't use special characters.
           test("dir", false)  // See d above.
           test("file", false) // See f above.
           test("src", false)  // Typically used when copying files or directories.
           test("dst", false)  // Typically used when copying files or directories.
   
           test("bindir", false) // A typical GNU-style directory.
           test("mandir", false) // A typical GNU-style directory.
           test("prefix", false) //
   
           test("bindirs", true) // A list of directories is typically separated by spaces.
           test("var", true)     // Other variables are unknown, so they should be quoted.
           test("0", true)       // The program name may contain special characters when given as full path.
           test("1", true)       // Command line arguments can be arbitrary strings.
   }
   
   func (s *Suite) Test_ShellLine_variableNeedsQuoting__integration(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         t.SetupVartypes()          t.SetupVartypes()
         t.SetupTool("cp", "", AtRunTime)          t.SetupTool("cp", "", AtRunTime)
         mklines := t.NewMkLines("fileName.mk",          mklines := t.NewMkLines("filename.mk",
                 MkRcsID,                  MkRcsID,
                 "",                  "",
                 // It's a bit silly to use shell variables in CONFIGURE_ARGS,                  // It's a bit silly to use shell variables in CONFIGURE_ARGS,
Line 636  func (s *Suite) Test_ShellLine_variableN
Line 692  func (s *Suite) Test_ShellLine_variableN
         // Quoting check is currently disabled for real shell commands.          // Quoting check is currently disabled for real shell commands.
         // See ShellLine.CheckShellCommand, spc.checkWord.          // See ShellLine.CheckShellCommand, spc.checkWord.
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName.mk:3: Unquoted shell variable \"target\".")                  "WARN: filename.mk:3: Unquoted shell variable \"target\".")
 }  }
   
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__echo(c *check.C) {  func (s *Suite) Test_ShellLine_CheckShellCommandLine__echo(c *check.C) {
Line 644  func (s *Suite) Test_ShellLine_CheckShel
Line 700  func (s *Suite) Test_ShellLine_CheckShel
   
         echo := t.SetupTool("echo", "ECHO", AtRunTime)          echo := t.SetupTool("echo", "ECHO", AtRunTime)
         echo.MustUseVarForm = true          echo.MustUseVarForm = true
         G.Mk = t.NewMkLines("fileName",          G.Mk = t.NewMkLines("filename",
                 "# dummy")                  "# dummy")
         mkline := t.NewMkLine("fileName", 3, "# dummy")          mkline := t.NewMkLine("filename", 3, "# dummy")
   
         MkLineChecker{mkline}.checkText("echo \"hello, world\"")          MkLineChecker{mkline}.checkText("echo \"hello, world\"")
   
Line 655  func (s *Suite) Test_ShellLine_CheckShel
Line 711  func (s *Suite) Test_ShellLine_CheckShel
         NewShellLine(mkline).CheckShellCommandLine("echo \"hello, world\"")          NewShellLine(mkline).CheckShellCommandLine("echo \"hello, world\"")
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName:3: Please use \"${ECHO}\" instead of \"echo\".")                  "WARN: filename:3: Please use \"${ECHO}\" instead of \"echo\".")
 }  }
   
 func (s *Suite) Test_ShellLine_CheckShellCommandLine__shell_variables(c *check.C) {  func (s *Suite) Test_ShellLine_CheckShellCommandLine__shell_variables(c *check.C) {
Line 697  func (s *Suite) Test_ShellLine_CheckShel
Line 753  func (s *Suite) Test_ShellLine_CheckShel
 func (s *Suite) Test_ShellLine_checkInstallCommand(c *check.C) {  func (s *Suite) Test_ShellLine_checkInstallCommand(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         G.Mk = t.NewMkLines("fileName",          G.Mk = t.NewMkLines("filename",
                 "# dummy")                  "# dummy")
         G.Mk.target = "do-install"          G.Mk.target = "do-install"
   
         shline := t.NewShellLine("fileName", 1, "\tdummy")          shline := t.NewShellLine("filename", 1, "\tdummy")
   
         shline.checkInstallCommand("sed")          shline.checkInstallCommand("sed")
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName:1: The shell command \"sed\" should not be used in the install phase.")                  "WARN: filename:1: The shell command \"sed\" should not be used in the install phase.")
   
         shline.checkInstallCommand("cp")          shline.checkInstallCommand("cp")
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: fileName:1: ${CP} should not be used to install files.")                  "WARN: filename:1: ${CP} should not be used to install files.")
 }  }
   
 func (s *Suite) Test_splitIntoMkWords(c *check.C) {  func (s *Suite) Test_splitIntoMkWords(c *check.C) {
Line 739  func (s *Suite) Test_ShellLine_CheckShel
Line 795  func (s *Suite) Test_ShellLine_CheckShel
         t.SetupVartypes()          t.SetupVartypes()
         t.SetupTool("sed", "SED", AtRunTime)          t.SetupTool("sed", "SED", AtRunTime)
         t.SetupTool("mv", "MV", AtRunTime)          t.SetupTool("mv", "MV", AtRunTime)
         shline := t.NewShellLine("Makefile", 85, "\t${RUN} ${SED} 's,#,// comment:,g' fileName > fileName.tmp; ${MV} fileName.tmp fileName")          shline := t.NewShellLine("Makefile", 85, "\t${RUN} ${SED} 's,#,// comment:,g' filename > filename.tmp; ${MV} filename.tmp filename")
   
         shline.CheckShellCommandLine(shline.mkline.ShellCommand())          shline.CheckShellCommandLine(shline.mkline.ShellCommand())
   
Line 813  func (s *Suite) Test_ShellLine__shell_co
Line 869  func (s *Suite) Test_ShellLine__shell_co
                 "WARN: ~/Makefile:3--4: A shell comment does not stop at the end of line.")                  "WARN: ~/Makefile:3--4: A shell comment does not stop at the end of line.")
 }  }
   
   func (s *Suite) Test_ShellLine_checkWordQuoting(c *check.C) {
           t := s.Init(c)
   
           t.SetupVartypes()
           t.SetupTool("grep", "GREP", AtRunTime)
   
           test := func(lineno int, input string) {
                   shline := t.NewShellLine("module.mk", lineno, "\t"+input)
   
                   shline.checkWordQuoting(shline.mkline.ShellCommand(), true, RunTime)
           }
   
           test(101, "socklen=`${GREP} 'expr' ${WRKSRC}/config.h`")
   
           test(102, "s,$$from,$$to,")
   
           // This variable is typically defined by GNU Configure,
           // which cannot handle directories with special characters.
           // Therefore using it unquoted is considered safe.
           test(103, "${PREFIX}/$$bindir/program")
   
           test(104, "$$@")
   
           // TODO: Add separate tests for "set +e" and "set -e".
           test(105, "$$?")
   
           test(106, "$$(cat /bin/true)")
   
           test(107, "\"$$\"")
   
           test(108, "$$$$")
   
           // TODO: The $ variable in line 108 doesn't need quoting.
           t.CheckOutputLines(
                   "WARN: module.mk:102: Unquoted shell variable \"from\".",
                   "WARN: module.mk:102: Unquoted shell variable \"to\".",
                   "WARN: module.mk:104: The $@ shell variable should only be used in double quotes.",
                   "WARN: module.mk:105: The $? shell variable is often not available in \"set -e\" mode.",
                   "WARN: module.mk:106: Invoking subshells via $(...) is not portable enough.")
   }
   
 func (s *Suite) Test_ShellLine_unescapeBackticks(c *check.C) {  func (s *Suite) Test_ShellLine_unescapeBackticks(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         shline := t.NewShellLine("dummy.mk", 13, "# dummy")          test := func(lineno int, input string, expectedOutput string, expectedRest string) {
         // foobar="`echo \"foo   bar\" "\ " "three"`"                  shline := t.NewShellLine("dummy.mk", lineno, "# dummy")
         text := "foobar=\"`echo \\\"foo   bar\\\" \"\\ \" \"three\"`\""  
         repl := G.NewPrefixReplacer(text)                  tok := NewShTokenizer(nil, input, false)
         repl.AdvanceStr("foobar=\"`")                  atoms := tok.ShAtoms()
   
         backtCommand, newQuoting := shline.unescapeBackticks(text, repl, shqDquotBackt)                  // Set up the correct quoting mode for the test by skipping
                   // uninteresting atoms at the beginning.
                   q := shqPlain
                   for atoms[0].MkText != "`" {
                           q = atoms[0].Quoting
                           atoms = atoms[1:]
                   }
                   c.Check(tok.Rest(), equals, "")
   
                   backtCommand := shline.unescapeBackticks(&atoms, q)
   
                   var actualRest strings.Builder
                   for _, atom := range atoms {
                           actualRest.WriteString(atom.MkText)
                   }
   
         c.Check(backtCommand, equals, "echo \"foo   bar\" \"\\ \" \"three\"")                  c.Check(backtCommand, equals, expectedOutput)
         c.Check(newQuoting, equals, shqDquot)                  c.Check(actualRest.String(), equals, expectedRest)
         c.Check(repl.Rest(), equals, "\"")          }
   
           // The 1xx test cases are in shqPlain mode.
   
           test(100, "`echo`end", "echo", "end")
           test(101, "`echo $$var`end", "echo $$var", "end")
           test(102, "``end", "", "end")
           test(103, "`echo \"hello\"`end", "echo \"hello\"", "end")
           test(104, "`echo 'hello'`end", "echo 'hello'", "end")
           test(105, "`echo '\\\\\\\\'`end", "echo '\\\\'", "end")
   
           // Only the characters " $ ` \ are unescaped. All others stay the same.
           test(120, "`echo '\\n'`end", "echo '\\n'", "end")
           test(121, "\tsocklen=`${GREP} 'expr' ${WRKSRC}/config.h`", "${GREP} 'expr' ${WRKSRC}/config.h", "")
   
           // TODO: Add more details regarding which backslash is meant.
           t.CheckOutputLines(
                   "WARN: dummy.mk:120: Backslashes should be doubled inside backticks.")
   
           // The 2xx test cases are in shqDquot mode.
   
           test(200, "\"`echo`\"", "echo", "\"")
           test(201, "\"`echo \"\"`\"", "echo \"\"", "\"")
   
           t.CheckOutputLines(
                   "WARN: dummy.mk:201: Double quotes inside backticks inside double quotes are error prone.")
   
           // varname="`echo \"one   two\" "\ " "three"`"
           test(202,
                   "varname=\"`echo \\\"one   two\\\" \"\\ \" \"three\"`\"",
                   "echo \"one   two\" \"\\ \" \"three\"",
                   "\"")
   
           // TODO: Add more details regarding which backslash and backtick is meant.
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: dummy.mk:13: Backslashes should be doubled inside backticks.")                  "WARN: dummy.mk:202: Backslashes should be doubled inside backticks.",
                   "WARN: dummy.mk:202: Double quotes inside backticks inside double quotes are error prone.",
                   "WARN: dummy.mk:202: Double quotes inside backticks inside double quotes are error prone.")
 }  }
   
 func (s *Suite) Test_ShellLine_unescapeBackticks__dquotBacktDquot(c *check.C) {  func (s *Suite) Test_ShellLine_unescapeBackticks__dquotBacktDquot(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         mkline := t.NewMkLine("dummy.mk", 13, "\t var=\"`\"\"`\"")          t.SetupTool("echo", "", AtRunTime)
           mkline := t.NewMkLine("dummy.mk", 13, "\t var=\"`echo \"\"`\"")
   
         MkLineChecker{mkline}.Check()          MkLineChecker{mkline}.Check()
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: dummy.mk:13: Double quotes inside backticks inside double quotes are error prone.",  
                 "WARN: dummy.mk:13: Double quotes inside backticks inside double quotes are error prone.")                  "WARN: dummy.mk:13: Double quotes inside backticks inside double quotes are error prone.")
 }  }
   
Line 1157  func (s *Suite) Test_ShellProgramChecker
Line 1302  func (s *Suite) Test_ShellProgramChecker
   
         t.SetupVartypes()          t.SetupVartypes()
         t.SetupTool("echo", "", AtRunTime)          t.SetupTool("echo", "", AtRunTime)
           t.SetupTool("env", "", AtRunTime)
         t.SetupTool("grep", "GREP", AtRunTime)          t.SetupTool("grep", "GREP", AtRunTime)
         t.SetupTool("sed", "", AtRunTime)          t.SetupTool("sed", "", AtRunTime)
         t.SetupTool("touch", "", AtRunTime)          t.SetupTool("touch", "", AtRunTime)
Line 1178  func (s *Suite) Test_ShellProgramChecker
Line 1324  func (s *Suite) Test_ShellProgramChecker
                 "\techo 'starting'; echo 'done.'",                  "\techo 'starting'; echo 'done.'",
                 "\techo 'logging' > log; echo 'done.'",                  "\techo 'logging' > log; echo 'done.'",
                 "\techo 'to stderr' 1>&2; echo 'done.'",                  "\techo 'to stderr' 1>&2; echo 'done.'",
                 "\techo 'hello' | tr -d 'aeiou'")                  "\techo 'hello' | tr -d 'aeiou'",
                   "\tenv | grep '^PATH='")
   
         mklines.Check()          mklines.Check()
   

Legend:
Removed from v.1.33  
changed lines
  Added in v.1.34

CVSweb <webmaster@jp.NetBSD.org>