[BACK]Return to mkline_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/mkline_test.go between version 1.55 and 1.56

version 1.55, 2019/04/03 21:49:51 version 1.56, 2019/04/20 17:43:24
Line 1 
Line 1 
 package pkglint  package pkglint
   
 import "gopkg.in/check.v1"  import (
           "gopkg.in/check.v1"
           "strings"
   )
   
 func (s *Suite) Test_NewMkLine__varassign(c *check.C) {  func (s *Suite) Test_MkLineParser_Parse__varassign(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         mkline := t.NewMkLine("test.mk", 101,          mkline := t.NewMkLine("test.mk", 101,
Line 17  func (s *Suite) Test_NewMkLine__varassig
Line 20  func (s *Suite) Test_NewMkLine__varassig
         c.Check(mkline.VarassignComment(), equals, "# varassign comment")          c.Check(mkline.VarassignComment(), equals, "# varassign comment")
 }  }
   
 func (s *Suite) Test_NewMkLine__varassign_space_around_operator(c *check.C) {  func (s *Suite) Test_MkLineParser_Parse__varassign_space_around_operator(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         t.SetUpCommandLine("--show-autofix", "--source")          t.SetUpCommandLine("--show-autofix", "--source")
Line 31  func (s *Suite) Test_NewMkLine__varassig
Line 34  func (s *Suite) Test_NewMkLine__varassig
                 "+\tpkgbase= package")                  "+\tpkgbase= package")
 }  }
   
 func (s *Suite) Test_NewMkLine__shellcmd(c *check.C) {  func (s *Suite) Test_MkLineParser_Parse__shellcmd(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         mkline := t.NewMkLine("test.mk", 101,          mkline := t.NewMkLine("test.mk", 101,
Line 41  func (s *Suite) Test_NewMkLine__shellcmd
Line 44  func (s *Suite) Test_NewMkLine__shellcmd
         c.Check(mkline.ShellCommand(), equals, "shell command # shell comment")          c.Check(mkline.ShellCommand(), equals, "shell command # shell comment")
 }  }
   
 func (s *Suite) Test_NewMkLine__comment(c *check.C) {  func (s *Suite) Test_MkLineParser_Parse__comment(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         mkline := t.NewMkLine("test.mk", 101,          mkline := t.NewMkLine("test.mk", 101,
Line 50  func (s *Suite) Test_NewMkLine__comment(
Line 53  func (s *Suite) Test_NewMkLine__comment(
         c.Check(mkline.IsComment(), equals, true)          c.Check(mkline.IsComment(), equals, true)
 }  }
   
 func (s *Suite) Test_NewMkLine__empty(c *check.C) {  func (s *Suite) Test_MkLineParser_Parse__empty(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         mkline := t.NewMkLine("test.mk", 101, "")          mkline := t.NewMkLine("test.mk", 101, "")
Line 58  func (s *Suite) Test_NewMkLine__empty(c 
Line 61  func (s *Suite) Test_NewMkLine__empty(c 
         c.Check(mkline.IsEmpty(), equals, true)          c.Check(mkline.IsEmpty(), equals, true)
 }  }
   
 func (s *Suite) Test_NewMkLine__directive(c *check.C) {  func (s *Suite) Test_MkLineParser_Parse__directive(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         mkline := t.NewMkLine("test.mk", 101,          mkline := t.NewMkLine("test.mk", 101,
Line 71  func (s *Suite) Test_NewMkLine__directiv
Line 74  func (s *Suite) Test_NewMkLine__directiv
         c.Check(mkline.DirectiveComment(), equals, "directive comment")          c.Check(mkline.DirectiveComment(), equals, "directive comment")
 }  }
   
 func (s *Suite) Test_NewMkLine__include(c *check.C) {  func (s *Suite) Test_MkLineParser_Parse__include(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         mkline := t.NewMkLine("test.mk", 101,          mkline := t.NewMkLine("test.mk", 101,
Line 85  func (s *Suite) Test_NewMkLine__include(
Line 88  func (s *Suite) Test_NewMkLine__include(
         c.Check(mkline.IsSysinclude(), equals, false)          c.Check(mkline.IsSysinclude(), equals, false)
 }  }
   
 func (s *Suite) Test_NewMkLine__sysinclude(c *check.C) {  func (s *Suite) Test_MkLineParser_Parse__sysinclude(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         mkline := t.NewMkLine("test.mk", 101,          mkline := t.NewMkLine("test.mk", 101,
Line 99  func (s *Suite) Test_NewMkLine__sysinclu
Line 102  func (s *Suite) Test_NewMkLine__sysinclu
         c.Check(mkline.IsInclude(), equals, false)          c.Check(mkline.IsInclude(), equals, false)
 }  }
   
 func (s *Suite) Test_NewMkLine__dependency(c *check.C) {  func (s *Suite) Test_MkLineParser_Parse__dependency(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         mkline := t.NewMkLine("test.mk", 101,          mkline := t.NewMkLine("test.mk", 101,
Line 110  func (s *Suite) Test_NewMkLine__dependen
Line 113  func (s *Suite) Test_NewMkLine__dependen
         c.Check(mkline.Sources(), equals, "source1 source2")          c.Check(mkline.Sources(), equals, "source1 source2")
 }  }
   
 func (s *Suite) Test_NewMkLine__dependency_space(c *check.C) {  func (s *Suite) Test_MkLineParser_Parse__dependency_space(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         mkline := t.NewMkLine("test.mk", 101,          mkline := t.NewMkLine("test.mk", 101,
Line 122  func (s *Suite) Test_NewMkLine__dependen
Line 125  func (s *Suite) Test_NewMkLine__dependen
                 "NOTE: test.mk:101: Space before colon in dependency line.")                  "NOTE: test.mk:101: Space before colon in dependency line.")
 }  }
   
 func (s *Suite) Test_NewMkLine__varassign_append(c *check.C) {  func (s *Suite) Test_MkLineParser_Parse__varassign_append(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         mkline := t.NewMkLine("test.mk", 101,          mkline := t.NewMkLine("test.mk", 101,
Line 134  func (s *Suite) Test_NewMkLine__varassig
Line 137  func (s *Suite) Test_NewMkLine__varassig
         c.Check(mkline.Varparam(), equals, "")          c.Check(mkline.Varparam(), equals, "")
 }  }
   
 func (s *Suite) Test_NewMkLine__merge_conflict(c *check.C) {  func (s *Suite) Test_MkLineParser_Parse__merge_conflict(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         mkline := t.NewMkLine("test.mk", 101,          mkline := t.NewMkLine("test.mk", 101,
Line 151  func (s *Suite) Test_NewMkLine__merge_co
Line 154  func (s *Suite) Test_NewMkLine__merge_co
         c.Check(mkline.IsSysinclude(), equals, false)          c.Check(mkline.IsSysinclude(), equals, false)
 }  }
   
 func (s *Suite) Test_NewMkLine__autofix_space_after_varname(c *check.C) {  func (s *Suite) Test_MkLineParser_Parse__autofix_space_after_varname(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         t.SetUpCommandLine("-Wspace")          t.SetUpCommandLine("-Wspace")
Line 187  func (s *Suite) Test_NewMkLine__autofix_
Line 190  func (s *Suite) Test_NewMkLine__autofix_
                 "pkgbase := pkglint")                  "pkgbase := pkglint")
 }  }
   
 func (s *Suite) Test_NewMkLine__varname_with_hash(c *check.C) {  func (s *Suite) Test_MkLineParser_Parse__varname_with_hash(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         mkline := t.NewMkLine("Makefile", 123, "VARNAME.#=\tvalue")          mkline := t.NewMkLine("Makefile", 123, "VARNAME.#=\tvalue")
Line 208  func (s *Suite) Test_NewMkLine__varname_
Line 211  func (s *Suite) Test_NewMkLine__varname_
 //  //
 // To check that bmake parses them the same, set a breakpoint after the t.NewMkLines  // To check that bmake parses them the same, set a breakpoint after the t.NewMkLines
 // and look in t.tmpdir for the location of the file. Then run bmake with that file.  // and look in t.tmpdir for the location of the file. Then run bmake with that file.
 func (s *Suite) Test_NewMkLine__escaped_hash_in_value(c *check.C) {  func (s *Suite) Test_MkLineParser_Parse__escaped_hash_in_value(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         mklines := t.SetUpFileMkLines("Makefile",          mklines := t.SetUpFileMkLines("Makefile",
Line 278  func (s *Suite) Test_VarUseContext_Strin
Line 281  func (s *Suite) Test_VarUseContext_Strin
         vartype := G.Pkgsrc.VariableType(nil, "PKGNAME")          vartype := G.Pkgsrc.VariableType(nil, "PKGNAME")
         vuc := VarUseContext{vartype, vucTimeUnknown, VucQuotBackt, false}          vuc := VarUseContext{vartype, vucTimeUnknown, VucQuotBackt, false}
   
         c.Check(vuc.String(), equals, "(Pkgname time:unknown quoting:backt wordpart:false)")          c.Check(vuc.String(), equals, "(Pkgname (package-settable) time:unknown quoting:backt wordpart:false)")
 }  }
   
 // In variable assignments, a plain '#' introduces a line comment, unless  // In variable assignments, a plain '#' introduces a line comment, unless
 // it is escaped by a backslash. In shell commands, on the other hand, it  // it is escaped by a backslash. In shell commands, on the other hand, it
 // is interpreted literally.  // is interpreted literally.
 func (s *Suite) Test_NewMkLine__number_sign(c *check.C) {  func (s *Suite) Test_MkLineParser_Parse__number_sign(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         mklineVarassignEscaped := t.NewMkLine("filename.mk", 1, "SED_CMD=\t's,\\#,hash,g'")          mklineVarassignEscaped := t.NewMkLine("filename.mk", 1, "SED_CMD=\t's,\\#,hash,g'")
Line 309  func (s *Suite) Test_NewMkLine__number_s
Line 312  func (s *Suite) Test_NewMkLine__number_s
                 "WARN: filename.mk:1: The # character starts a Makefile comment.")                  "WARN: filename.mk:1: The # character starts a Makefile comment.")
 }  }
   
 func (s *Suite) Test_NewMkLine__varassign_leading_space(c *check.C) {  func (s *Suite) Test_MkLineParser_Parse__varassign_leading_space(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         _ = t.NewMkLine("rubyversion.mk", 427, " _RUBYVER=\t2.15")          _ = t.NewMkLine("rubyversion.mk", 427, " _RUBYVER=\t2.15")
Line 327  func (s *Suite) Test_NewMkLine__varassig
Line 330  func (s *Suite) Test_NewMkLine__varassig
 // be able to parse and check the infrastructure files as well.  // be able to parse and check the infrastructure files as well.
 //  //
 // See Pkgsrc.loadUntypedVars.  // See Pkgsrc.loadUntypedVars.
 func (s *Suite) Test_NewMkLine__infrastructure(c *check.C) {  func (s *Suite) Test_MkLineParser_Parse__infrastructure(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         mklines := t.NewMkLines("infra.mk",          mklines := t.NewMkLines("infra.mk",
Line 413  func (s *Suite) Test_MkLine_VariableNeed
Line 416  func (s *Suite) Test_MkLine_VariableNeed
         MkLineChecker{nil, mkline}.checkVarassign()          MkLineChecker{nil, mkline}.checkVarassign()
   
         t.CheckOutputLines(          t.CheckOutputLines(
                 "WARN: builtin.mk:3: PKG_ADMIN should not be used at load time in any file.",  
                 "NOTE: builtin.mk:3: The :Q operator isn't necessary for ${BUILTIN_PKG.Xfixes} here.")                  "NOTE: builtin.mk:3: The :Q operator isn't necessary for ${BUILTIN_PKG.Xfixes} here.")
 }  }
   
Line 841  func (s *Suite) Test_MkLine_VariableNeed
Line 843  func (s *Suite) Test_MkLine_VariableNeed
                 "\tname in which the variable is used or defined. The rules for PATH",                  "\tname in which the variable is used or defined. The rules for PATH",
                 "\tare:",                  "\tare:",
                 "",                  "",
                 "\t* in buildlink3.mk, it should not be accessed at all",                  "\t* in any file, it may be used at load time, or used",
                 "\t* in any file, it may be used",  
                 "",                  "",
                 "\tIf these rules seem to be incorrect, please ask on the",                  "\tIf these rules seem to be incorrect, please ask on the",
                 "\ttech-pkg@NetBSD.org mailing list.",                  "\ttech-pkg@NetBSD.org mailing list.",
Line 867  func (s *Suite) Test_MkLine_VariableNeed
Line 868  func (s *Suite) Test_MkLine_VariableNeed
                 "",                  "",
                 "\tIf these rules seem to be incorrect, please ask on the",                  "\tIf these rules seem to be incorrect, please ask on the",
                 "\ttech-pkg@NetBSD.org mailing list.",                  "\ttech-pkg@NetBSD.org mailing list.",
                 "",  
                 "WARN: ~/Makefile:6: PATH should not be used at load time in any file.",  
                 "",  
                 "\tMany variables, especially lists of something, get their values",  
                 "\tincrementally. Therefore it is generally unsafe to rely on their",  
                 "\tvalue until it is clear that it will never change again. This point",  
                 "\tis reached when the whole package Makefile is loaded and execution",  
                 "\tof the shell commands starts; in some cases earlier.",  
                 "",  
                 "\tAdditionally, when using the \":=\" operator, each $$ is replaced with",  
                 "\ta single $, so variables that have references to shell variables or",  
                 "\tregular expressions are modified in a subtle way.",  
                 "",  
                 "\tThe allowed actions for a variable are determined based on the file",  
                 "\tname in which the variable is used or defined. The rules for PATH",  
                 "\tare:",  
                 "",  
                 "\t* in buildlink3.mk, it should not be accessed at all",  
                 "\t* in any file, it may be used",  
                 "",  
                 "\tIf these rules seem to be incorrect, please ask on the",  
                 "\ttech-pkg@NetBSD.org mailing list.",  
                 "")                  "")
   
         // Just for branch coverage.          // Just for branch coverage.
Line 1142  func (s *Suite) Test_MkLine_ValueFields_
Line 1121  func (s *Suite) Test_MkLine_ValueFields_
 func (s *Suite) Test_MkLine_ValueTokens(c *check.C) {  func (s *Suite) Test_MkLine_ValueTokens(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         testTokens := func(value string, expected ...*MkToken) {          text := func(text string) *MkToken { return &MkToken{text, nil} }
           varUseText := func(text string, varname string, modifiers ...string) *MkToken {
                   return &MkToken{text, NewMkVarUse(varname, modifiers...)}
           }
           tokens := func(tokens ...*MkToken) []*MkToken { return tokens }
           test := func(value string, expected []*MkToken, diagnostics ...string) {
                 mkline := t.NewMkLine("Makefile", 1, "PATH=\t"+value)                  mkline := t.NewMkLine("Makefile", 1, "PATH=\t"+value)
                 tokens, _ := mkline.ValueTokens()                  actualTokens, _ := mkline.ValueTokens()
                 c.Check(tokens, deepEquals, expected)                  c.Check(actualTokens, deepEquals, expected)
                   t.CheckOutput(diagnostics)
         }          }
   
         testTokens("#empty",          t.Use(text, varUseText, tokens, test)
                 []*MkToken(nil)...)  
   
         testTokens("value",          test("#empty",
                 &MkToken{"value", nil})                  tokens())
   
         testTokens("value ${VAR} rest",          test("value",
                 &MkToken{"value ", nil},                  tokens(text("value")))
                 &MkToken{"${VAR}", NewMkVarUse("VAR")},  
                 &MkToken{" rest", nil})  
   
         testTokens("value ${UNFINISHED",          test("value ${VAR} rest",
                 &MkToken{"value ", nil})                  tokens(
                           text("value "),
                           varUseText("${VAR}", "VAR"),
                           text(" rest")))
   
           test("value # comment",
                   tokens(
                           text("value")))
   
           test("value ${UNFINISHED",
                   tokens(
                           text("value "),
                           varUseText("${UNFINISHED", "UNFINISHED")),
   
                   "WARN: Makefile:1: Missing closing \"}\" for \"UNFINISHED\".")
 }  }
   
 func (s *Suite) Test_MkLine_ValueTokens__caching(c *check.C) {  func (s *Suite) Test_MkLine_ValueTokens__caching(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
           tokens := func(tokens ...*MkToken) []*MkToken { return tokens }
   
         mkline := t.NewMkLine("Makefile", 1, "PATH=\tvalue ${UNFINISHED")          mkline := t.NewMkLine("Makefile", 1, "PATH=\tvalue ${UNFINISHED")
         tokens, rest := mkline.ValueTokens()          valueTokens, rest := mkline.ValueTokens()
   
         c.Check(tokens, deepEquals, []*MkToken{{"value ", nil}})          c.Check(valueTokens, deepEquals,
         c.Check(rest, equals, "${UNFINISHED")                  tokens(
                           &MkToken{"value ", nil},
                           &MkToken{"${UNFINISHED", NewMkVarUse("UNFINISHED")}))
           c.Check(rest, equals, "")
           t.CheckOutputLines(
                   "WARN: Makefile:1: Missing closing \"}\" for \"UNFINISHED\".")
   
         tokens2, rest2 := mkline.ValueTokens() // This time the slice is taken from the cache.          // This time the slice is taken from the cache.
           tokens2, rest2 := mkline.ValueTokens()
   
         // In Go, it's not possible to compare slices for reference equality.          c.Check(&tokens2[0], equals, &valueTokens[0])
         c.Check(tokens2, deepEquals, tokens)  
         c.Check(rest2, equals, rest)          c.Check(rest2, equals, rest)
 }  }
   
 func (s *Suite) Test_MkLine_ValueTokens__caching_parse_error(c *check.C) {  func (s *Suite) Test_MkLine_ValueTokens__caching_parse_error(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
           tokens := func(tokens ...*MkToken) []*MkToken { return tokens }
           varuseText := func(text, varname string, modifiers ...string) *MkToken {
                   return &MkToken{Text: text, Varuse: NewMkVarUse(varname, modifiers...)}
           }
   
         mkline := t.NewMkLine("Makefile", 1, "PATH=\t${UNFINISHED")          mkline := t.NewMkLine("Makefile", 1, "PATH=\t${UNFINISHED")
         tokens, rest := mkline.ValueTokens()          valueTokens, rest := mkline.ValueTokens()
   
         c.Check(tokens, check.IsNil)          c.Check(valueTokens, deepEquals, tokens(varuseText("${UNFINISHED", "UNFINISHED")))
         c.Check(rest, equals, "${UNFINISHED")          c.Check(rest, equals, "")
           t.CheckOutputLines(
                   "WARN: Makefile:1: Missing closing \"}\" for \"UNFINISHED\".")
   
         tokens2, rest2 := mkline.ValueTokens() // This time the slice is taken from the cache.          // This time the slice is taken from the cache.
           tokens2, rest2 := mkline.ValueTokens()
   
         // In Go, it's not possible to compare slices for reference equality.          c.Check(&tokens2[0], equals, &valueTokens[0])
         c.Check(tokens2, deepEquals, tokens)  
         c.Check(rest2, equals, rest)          c.Check(rest2, equals, rest)
 }  }
   
Line 1266  func (s *Suite) Test_MkLine_ResolveVarsI
Line 1276  func (s *Suite) Test_MkLine_ResolveVarsI
                 "WARN: ~/multimedia/totem/bla.mk:2: "+                  "WARN: ~/multimedia/totem/bla.mk:2: "+
                         "The variable BUILDLINK_PKGSRCDIR.totem should not be given a default value in this file; "+                          "The variable BUILDLINK_PKGSRCDIR.totem should not be given a default value in this file; "+
                         "it would be ok in buildlink3.mk.",                          "it would be ok in buildlink3.mk.",
                 "ERROR: ~/multimedia/totem/bla.mk:2: There is no package in \"multimedia/totem\".")                  "ERROR: ~/multimedia/totem/bla.mk:2: Relative path \"../../multimedia/totem/Makefile\" does not exist.")
 }  }
   
 func (s *Suite) Test_MatchVarassign(c *check.C) {  func (s *Suite) Test_MkLineParser_MatchVarassign(c *check.C) {
         s.Init(c)          t := s.Init(c)
   
         test := func(text string, commented bool, varname, spaceAfterVarname, op, align, value, spaceAfterValue, comment string) {          test := func(text string, commented bool, varname, spaceAfterVarname, op, align, value, spaceAfterValue, comment string, diagnostics ...string) {
                 m, actual := MatchVarassign(text)                  line := t.NewLine("filename.mk", 123, text)
                   data := MkLineParser{}.split(line, text)
                   m, actual := MkLineParser{}.MatchVarassign(line, text, data)
                 if !m {                  if !m {
                         c.Errorf("Text %q doesn't match variable assignment", text)                          c.Errorf("Text %q doesn't match variable assignment", text)
                         return                          return
Line 1295  func (s *Suite) Test_MatchVarassign(c *c
Line 1307  func (s *Suite) Test_MatchVarassign(c *c
                         comment:           comment,                          comment:           comment,
                 }                  }
                 c.Check(*actual, deepEquals, expected)                  c.Check(*actual, deepEquals, expected)
                   t.CheckOutput(diagnostics)
         }          }
   
         testInvalid := func(text string) {          testInvalid := func(text string, diagnostics ...string) {
                 m, _ := MatchVarassign(text)                  line := t.NewLine("filename.mk", 123, text)
                   data := MkLineParser{}.split(nil, text)
                   m, _ := MkLineParser{}.MatchVarassign(line, text, data)
                 if m {                  if m {
                         c.Errorf("Text %q matches variable assignment but shouldn't.", text)                          c.Errorf("Text %q matches variable assignment but shouldn't.", text)
                 }                  }
                   t.CheckOutput(diagnostics)
         }          }
   
         test("C++=c11", false, "C+", "", "+=", "C++=", "c11", "", "")          test("C++=c11", false, "C+", "", "+=", "C++=", "c11", "", "")
Line 1396  func (s *Suite) Test_MatchVarassign(c *c
Line 1412  func (s *Suite) Test_MatchVarassign(c *c
                 "# none")                  "# none")
   
         test("EGDIRS=\t${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d",          test("EGDIRS=\t${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d",
   
                 false,                  false,
                 "EGDIRS",                  "EGDIRS",
                 "",                  "",
Line 1403  func (s *Suite) Test_MatchVarassign(c *c
Line 1420  func (s *Suite) Test_MatchVarassign(c *c
                 "EGDIRS=\t",                  "EGDIRS=\t",
                 "${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d",                  "${EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d",
                 "",                  "",
                 "")                  "",
   
                   "WARN: filename.mk:123: Missing closing \"}\" for \"EGDIR/pam.d\".",
                   "WARN: filename.mk:123: Invalid part \"/pam.d\" after variable name \"EGDIR\".",
                   "WARN: filename.mk:123: Missing closing \"}\" for \"EGDIR/dbus-1/system.d ${EGDIR/pam.d\".",
                   "WARN: filename.mk:123: Invalid part \"/dbus-1/system.d ${EGDIR/pam.d\" after variable name \"EGDIR\".",
                   "WARN: filename.mk:123: Missing closing \"}\" for \"EGDIR/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d\".",
                   "WARN: filename.mk:123: Invalid part \"/apparmor.d ${EGDIR/dbus-1/system.d ${EGDIR/pam.d\" after variable name \"EGDIR\".")
   
         test("VAR:=\t${VAR:M-*:[\\#]}",          test("VAR:=\t${VAR:M-*:[\\#]}",
                 false,                  false,
Line 1414  func (s *Suite) Test_MatchVarassign(c *c
Line 1438  func (s *Suite) Test_MatchVarassign(c *c
                 "${VAR:M-*:[#]}",                  "${VAR:M-*:[#]}",
                 "",                  "",
                 "")                  "")
   
           test("#VAR=value",
                   true, "VAR", "", "=", "#VAR=", "value", "", "")
   
           testInvalid("# VAR=value")
           testInvalid("#\tVAR=value")
           testInvalid(MkRcsID)
 }  }
   
 func (s *Suite) Test_NewMkOperator(c *check.C) {  func (s *Suite) Test_NewMkOperator(c *check.C) {
Line 1532  func (s *Suite) Test_Indentation_Varname
Line 1563  func (s *Suite) Test_Indentation_Varname
                 ".    include \"../../category/other/buildlink3.mk\"",                  ".    include \"../../category/other/buildlink3.mk\"",
                 ".  endif",                  ".  endif",
                 ".endif")                  ".endif")
           t.FinishSetUp()
   
         G.Check(t.File("category/package"))          G.Check(t.File("category/package"))
   
Line 1590  func (s *Suite) Test_MkLine_ForEachUsed(
Line 1622  func (s *Suite) Test_MkLine_ForEachUsed(
                 "run <",                  "run <",
                 "run @",                  "run @",
                 "run x"})                  "run x"})
           t.CheckOutputLines(
                   "WARN: Makefile:12: Please use curly braces {} instead of round parentheses () for ROUND_PARENTHESES.",
                   "WARN: Makefile:14: $x is ambiguous. Use ${x} if you mean a Make variable or $$x if you mean a shell variable.")
 }  }
   
 func (s *Suite) Test_MkLine_UnquoteShell(c *check.C) {  func (s *Suite) Test_MkLine_UnquoteShell(c *check.C) {
Line 1621  func (s *Suite) Test_MkLine_UnquoteShell
Line 1656  func (s *Suite) Test_MkLine_UnquoteShell
         test("`", "`")          test("`", "`")
 }  }
   
 func (s *Suite) Test_unescapeMkComment(c *check.C) {  func (s *Suite) Test_MkLineParser_unescapeComment(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         test := func(text string, main, comment string) {          test := func(text string, main, comment string) {
                 aMain, aComment := unescapeMkComment(text)                  aMain, aComment := MkLineParser{}.unescapeComment(text)
                 t.Check(                  t.Check(
                         []interface{}{text, aMain, aComment},                          []interface{}{text, aMain, aComment},
                         deepEquals,                          deepEquals,
Line 1741  func (s *Suite) Test_unescapeMkComment(c
Line 1776  func (s *Suite) Test_unescapeMkComment(c
                 "#comment")                  "#comment")
 }  }
   
 func (s *Suite) Test_splitMkLine(c *check.C) {  func (s *Suite) Test_MkLineParser_split(c *check.C) {
         t := s.Init(c)          t := s.Init(c)
   
         varuse := func(varname string, modifiers ...string) *MkToken {          varuse := func(varname string, modifiers ...string) *MkToken {
                 text := "${" + varname                  var text strings.Builder
                   text.WriteString("${")
                   text.WriteString(varname)
                 for _, modifier := range modifiers {                  for _, modifier := range modifiers {
                         text += ":" + modifier                          text.WriteString(":")
                           text.WriteString(modifier)
                 }                  }
                 text += "}"                  text.WriteString("}")
                 return &MkToken{Text: text, Varuse: NewMkVarUse(varname, modifiers...)}                  return &MkToken{Text: text.String(), Varuse: NewMkVarUse(varname, modifiers...)}
         }          }
         varuseText := func(text, varname string, modifiers ...string) *MkToken {          varuseText := func(text, varname string, modifiers ...string) *MkToken {
                 return &MkToken{Text: text, Varuse: NewMkVarUse(varname, modifiers...)}                  return &MkToken{Text: text, Varuse: NewMkVarUse(varname, modifiers...)}
Line 1761  func (s *Suite) Test_splitMkLine(c *chec
Line 1799  func (s *Suite) Test_splitMkLine(c *chec
         tokens := func(tokens ...*MkToken) []*MkToken {          tokens := func(tokens ...*MkToken) []*MkToken {
                 return tokens                  return tokens
         }          }
         _, _, _, _ = text, varuse, varuseText, tokens  
   
         test := func(text string, main string, tokens []*MkToken, rest string, spaceBeforeComment string, hasComment bool, comment string) {          test := func(text string, data mkLineSplitResult, diagnostics ...string) {
                 aMain, aTokens, aRest, aSpaceBeforeComment, aHasComment, aComment := splitMkLine(text)                  line := t.NewLine("filename.mk", 123, text)
                 t.Check(                  actualData := MkLineParser{}.split(line, text)
                         []interface{}{text, aTokens, aMain, aRest, aSpaceBeforeComment, aHasComment, aComment},  
                         deepEquals,                  t.CheckOutput(diagnostics)
                         []interface{}{text, tokens, main, rest, spaceBeforeComment, hasComment, comment})                  t.Check([]interface{}{text, actualData}, deepEquals, []interface{}{text, data})
         }          }
   
         test("",          t.Use(text, varuse, varuseText, tokens)
                 "",  
                 tokens(),          test(
                 "",  
                 "",                  "",
                 false,                  mkLineSplitResult{})
                 "")  
         test("text",          test(
                 "text",                  "text",
                 tokens(text("text")),                  mkLineSplitResult{
                 "",                          main:   "text",
                 "",                          tokens: tokens(text("text")),
                 false,                  })
                 "")  
           // Leading space is always kept.
           test(
                   " text",
                   mkLineSplitResult{
                           main:   " text",
                           tokens: tokens(text(" text")),
                   })
   
           // Trailing space does not end up in the tokens since it is usually
           // ignored.
           test(
                   "text\t",
                   mkLineSplitResult{
                           main:               "text",
                           tokens:             tokens(text("text")),
                           spaceBeforeComment: "\t",
                   })
   
           test(
                   "text\t# intended comment",
                   mkLineSplitResult{
                           main:               "text",
                           tokens:             tokens(text("text")),
                           spaceBeforeComment: "\t",
                           hasComment:         true,
                           comment:            " intended comment",
                   })
   
           // Trailing space is saved in a separate field to detect accidental
           // unescaped # in the middle of a word, like the URL fragment in this
           // example.
           test(
                   "url#fragment",
                   mkLineSplitResult{
                           main:       "url",
                           tokens:     tokens(text("url")),
                           hasComment: true,
                           comment:    "fragment",
                   })
   
         // The leading space from the comment is preserved to make parsing as exact          // The leading space from the comment is preserved to make parsing as exact
         // as possible.          // as possible.
Line 1792  func (s *Suite) Test_splitMkLine(c *chec
Line 1867  func (s *Suite) Test_splitMkLine(c *chec
         // The difference between "#defined" and "# defined" is relevant in a few          // The difference between "#defined" and "# defined" is relevant in a few
         // cases, such as the API documentation of the infrastructure files.          // cases, such as the API documentation of the infrastructure files.
         test("# comment",          test("# comment",
                 "",                  mkLineSplitResult{
                 tokens(),                          hasComment: true,
                 "",                          comment:    " comment",
                 "",                  })
                 true,  
                 " comment")  
         test("#\tcomment",          test("#\tcomment",
                 "",                  mkLineSplitResult{
                 tokens(),                          hasComment: true,
                 "",                          comment:    "\tcomment",
                 "",                  })
                 true,  
                 "\tcomment")  
         test("#   comment",          test("#   comment",
                 "",                  mkLineSplitResult{
                 tokens(),                          hasComment: true,
                 "",                          comment:    "   comment",
                 "",                  })
                 true,  
                 "   comment")  
   
         // Other than in the shell, # also starts a comment in the middle of a word.          // Other than in the shell, # also starts a comment in the middle of a word.
         test("COMMENT=\tThe C# compiler",          test("COMMENT=\tThe C# compiler",
                 "COMMENT=\tThe C",                  mkLineSplitResult{
                 tokens(text("COMMENT=\tThe C")),                          main:       "COMMENT=\tThe C",
                 "",                          tokens:     tokens(text("COMMENT=\tThe C")),
                 "",                          hasComment: true,
                 true,                          comment:    " compiler",
                 " compiler")                  })
   
         test("COMMENT=\tThe C\\# compiler",          test("COMMENT=\tThe C\\# compiler",
                 "COMMENT=\tThe C# compiler",                  mkLineSplitResult{
                 tokens(text("COMMENT=\tThe C# compiler")),                          main:       "COMMENT=\tThe C# compiler",
                 "",                          tokens:     tokens(text("COMMENT=\tThe C# compiler")),
                 "",                          hasComment: false,
                 false,                          comment:    "",
                 "")                  })
   
         test("${TARGET}: ${SOURCES} # comment",          test("${TARGET}: ${SOURCES} # comment",
                 "${TARGET}: ${SOURCES}",                  mkLineSplitResult{
                 tokens(varuse("TARGET"), text(": "), varuse("SOURCES"), text(" ")),                          main:               "${TARGET}: ${SOURCES}",
                 "",                          tokens:             tokens(varuse("TARGET"), text(": "), varuse("SOURCES")),
                 " ",                          spaceBeforeComment: " ",
                 true,                          hasComment:         true,
                 " comment")                          comment:            " comment",
                   })
   
         // A # starts a comment, except if it immediately follows a [.          // A # starts a comment, except if it immediately follows a [.
         // This is done so that the length modifier :[#] can be written without          // This is done so that the length modifier :[#] can be written without
         // escaping the #.          // escaping the #.
         test("VAR=\t${OTHER:[#]} # comment",          test("VAR=\t${OTHER:[#]} # comment",
                 "VAR=\t${OTHER:[#]}",                  mkLineSplitResult{
                 tokens(text("VAR=\t"), varuse("OTHER", "[#]"), text(" ")),                          main:               "VAR=\t${OTHER:[#]}",
                 "",                          tokens:             tokens(text("VAR=\t"), varuse("OTHER", "[#]")),
                 " ",                          spaceBeforeComment: " ",
                 true,                          hasComment:         true,
                 " comment")                          comment:            " comment",
                   })
   
         // The # in the :[#] modifier may be escaped or not. Both forms are equivalent.          // The # in the :[#] modifier may be escaped or not. Both forms are equivalent.
         test("VAR:=\t${VAR:M-*:[\\#]}",          test("VAR:=\t${VAR:M-*:[\\#]}",
                 "VAR:=\t${VAR:M-*:[#]}",                  mkLineSplitResult{
                 tokens(text("VAR:=\t"), varuse("VAR", "M-*", "[#]")),                          main:   "VAR:=\t${VAR:M-*:[#]}",
                 "",                          tokens: tokens(text("VAR:=\t"), varuse("VAR", "M-*", "[#]")),
                 "",                  })
                 false,  
                 "")  
   
         // A backslash always escapes the next character, be it a # for a comment          // A backslash always escapes the next character, be it a # for a comment
         // or something else. This makes it difficult to write a literal \# in a          // or something else. This makes it difficult to write a literal \# in a
         // Makefile, but that's an edge case anyway.          // Makefile, but that's an edge case anyway.
         test("VAR0=\t#comment",          test("VAR0=\t#comment",
                 "VAR0=",                  mkLineSplitResult{
                 tokens(text("VAR0=\t")),                          main:   "VAR0=",
                 "",                          tokens: tokens(text("VAR0=")),
                 // Later, when converting this result into a proper variable assignment,                          // Later, when converting this result into a proper variable assignment,
                 // this "space before comment" is reclassified as "space before the value",                          // this "space before comment" is reclassified as "space before the value",
                 // in order to align the "#comment" with the other variable values.                          // in order to align the "#comment" with the other variable values.
                 "\t",                          spaceBeforeComment: "\t",
                 true,                          hasComment:         true,
                 "comment")                          comment:            "comment",
                   })
   
         test("VAR1=\t\\#no-comment",          test("VAR1=\t\\#no-comment",
                 "VAR1=\t#no-comment",                  mkLineSplitResult{
                 tokens(text("VAR1=\t#no-comment")),                          main:   "VAR1=\t#no-comment",
                 "",                          tokens: tokens(text("VAR1=\t#no-comment")),
                 "",                  })
                 false,  
                 "")  
         test("VAR2=\t\\\\#comment",          test("VAR2=\t\\\\#comment",
                 "VAR2=\t\\\\",                  mkLineSplitResult{
                 tokens(text("VAR2=\t\\\\")),                          main:       "VAR2=\t\\\\",
                 "",                          tokens:     tokens(text("VAR2=\t\\\\")),
                 "",                          hasComment: true,
                 true,                          comment:    "comment",
                 "comment")                  })
   
         // The backslash is only removed when it escapes a comment.          // The backslash is only removed when it escapes a comment.
         // In particular, it cannot be used to escape a dollar that starts a          // In particular, it cannot be used to escape a dollar that starts a
         // variable use.          // variable use.
         test("VAR0=\t$T",          test("VAR0=\t$T",
                 "VAR0=\t$T",                  mkLineSplitResult{
                 tokens(text("VAR0=\t"), varuseText("$T", "T")),                          main:   "VAR0=\t$T",
                 "",                          tokens: tokens(text("VAR0=\t"), varuseText("$T", "T")),
                 "",                  },
                 false,                  "WARN: filename.mk:123: $T is ambiguous. Use ${T} if you mean a Make variable or $$T if you mean a shell variable.")
                 "")  
         test("VAR1=\t\\$T",          test("VAR1=\t\\$T",
                 "VAR1=\t\\$T",                  mkLineSplitResult{
                 tokens(text("VAR1=\t\\"), varuseText("$T", "T")),                          main:   "VAR1=\t\\$T",
                 "",                          tokens: tokens(text("VAR1=\t\\"), varuseText("$T", "T")),
                 "",                  },
                 false,                  "WARN: filename.mk:123: $T is ambiguous. Use ${T} if you mean a Make variable or $$T if you mean a shell variable.")
                 "")  
         test("VAR2=\t\\\\$T",          test("VAR2=\t\\\\$T",
                 "VAR2=\t\\\\$T",                  mkLineSplitResult{
                 tokens(text("VAR2=\t\\\\"), varuseText("$T", "T")),                          main:   "VAR2=\t\\\\$T",
                 "",                          tokens: tokens(text("VAR2=\t\\\\"), varuseText("$T", "T")),
                 "",                  },
                 false,                  "WARN: filename.mk:123: $T is ambiguous. Use ${T} if you mean a Make variable or $$T if you mean a shell variable.")
                 "")  
   
         // To escape a dollar, write it twice.          // To escape a dollar, write it twice.
         test("$$shellvar $${shellvar} \\${MKVAR} [] \\x",          test("$$shellvar $${shellvar} \\${MKVAR} [] \\x",
                 "$$shellvar $${shellvar} \\${MKVAR} [] \\x",                  mkLineSplitResult{
                 tokens(text("$$shellvar $${shellvar} \\"), varuse("MKVAR"), text(" [] \\x")),                          main:   "$$shellvar $${shellvar} \\${MKVAR} [] \\x",
                 "",                          tokens: tokens(text("$$shellvar $${shellvar} \\"), varuse("MKVAR"), text(" [] \\x")),
                 "",                  })
                 false,  
                 "")  
   
         // Parse errors are recorded in the rest return value.          // Parse errors are recorded in the rest return value.
         test("${UNCLOSED",          test("${UNCLOSED",
                 "",                  mkLineSplitResult{
                 tokens(),                          main:   "${UNCLOSED",
                 "${UNCLOSED",                          tokens: tokens(varuseText("${UNCLOSED", "UNCLOSED")),
                 "",                  },
                 false,                  "WARN: filename.mk:123: Missing closing \"}\" for \"UNCLOSED\".")
                 "")  
   
         // Even if there is a parse error in the main part,          // Even if there is a parse error in the main part,
         // the comment is extracted.          // the comment is extracted.
         test("text before ${UNCLOSED# comment",          test("text before ${UNCLOSED# comment",
                 "text before ",                  mkLineSplitResult{
                 tokens(text("text before ")),                          main: "text before ${UNCLOSED",
                 "${UNCLOSED",                          tokens: tokens(
                 "",                                  text("text before "),
                 true,                                  varuseText("${UNCLOSED", "UNCLOSED")),
                 " comment")                          hasComment: true,
                           comment:    " comment",
                   },
                   "WARN: filename.mk:123: Missing closing \"}\" for \"UNCLOSED\".")
   
         // Even in case of parse errors, the space before the comment is parsed          // Even in case of parse errors, the space before the comment is parsed
         // correctly.          // correctly.
         test("text before ${UNCLOSED # comment",          test("text before ${UNCLOSED # comment",
                 "text before ",                  mkLineSplitResult{
                 tokens(text("text before ")),                          main: "text before ${UNCLOSED",
                 "${UNCLOSED",                          tokens: tokens(
                 " ",                                  text("text before "),
                 true,                                  // It's a bit inconsistent that the varname includes the space
                 " comment")                                  // but the text doesn't; anyway, it's an edge case.
                                   varuseText("${UNCLOSED", "UNCLOSED ")),
                           spaceBeforeComment: " ",
                           hasComment:         true,
                           comment:            " comment",
                   },
                   "WARN: filename.mk:123: Missing closing \"}\" for \"UNCLOSED \".",
                   "WARN: filename.mk:123: Invalid part \" \" after variable name \"UNCLOSED\".")
   
         // The dollar-space refers to a normal Make variable named " ".          // The dollar-space refers to a normal Make variable named " ".
         // The lonely dollar at the very end refers to the variable named "",          // The lonely dollar at the very end refers to the variable named "",
Line 1957  func (s *Suite) Test_splitMkLine(c *chec
Line 2036  func (s *Suite) Test_splitMkLine(c *chec
         //  variable name, mainly because the empty variable name is not visible          //  variable name, mainly because the empty variable name is not visible
         //  outside of the bmake debugging mode.          //  outside of the bmake debugging mode.
         test("Lonely $ character $",          test("Lonely $ character $",
                 "Lonely $ character ",                  mkLineSplitResult{
                 tokens(                          main: "Lonely $ character $",
                         text("Lonely "),                          tokens: tokens(
                         varuseText("$ " /* instead of "${ }" */, " "),                                  text("Lonely "),
                         text("character ")),                                  varuseText("$ " /* instead of "${ }" */, " "),
                 "$",                                  text("character "),
                 "",                                  text("$")),
                 false,                  })
                 "")  
   
         // The character [ prevents the following # from starting a comment, even          // The character [ prevents the following # from starting a comment, even
         // outside of variable modifiers.          // outside of variable modifiers.
         test("COMMENT=\t[#] $$\\# $$# comment",          test("COMMENT=\t[#] $$\\# $$# comment",
                 "COMMENT=\t[#] $$# $$",                  mkLineSplitResult{
                 tokens(text("COMMENT=\t[#] $$# $$")),                          main:       "COMMENT=\t[#] $$# $$",
                 "",                          tokens:     tokens(text("COMMENT=\t[#] $$# $$")),
                 "",                          hasComment: true,
                 true,                          comment:    " comment",
                 " comment")                  })
   
         test("VAR2=\t\\\\#comment",          test("VAR2=\t\\\\#comment",
                 "VAR2=\t\\\\",                  mkLineSplitResult{
                 tokens(text("VAR2=\t\\\\")),                          main:       "VAR2=\t\\\\",
                 "",                          tokens:     tokens(text("VAR2=\t\\\\")),
                 "",                          hasComment: true,
                 true,                          comment:    "comment",
                 "comment")                  })
   
           // At this stage, MkLine.split doesn't know that empty(...) takes
           // a variable use. Instead it just sees ordinary characters and
           // other uses of variables.
           test(".if empty(${VAR.${tool}}:C/\\:.*$//:M${pattern})",
                   mkLineSplitResult{
                           main: ".if empty(${VAR.${tool}}:C/\\:.*$//:M${pattern})",
                           tokens: tokens(
                                   text(".if empty("),
                                   varuse("VAR.${tool}"),
                                   text(":C/\\:.*"),
                                   text("$"),
                                   text("//:M"),
                                   varuse("pattern"),
                                   text(")")),
                   })
 }  }
   
 func (s *Suite) Test_matchMkDirective(c *check.C) {  func (s *Suite) Test_MkLineParser_parseDirective(c *check.C) {
           t := s.Init(c)
   
           test := func(input, expectedIndent, expectedDirective, expectedArgs, expectedComment string, diagnostics ...string) {
                   line := t.NewLine("filename.mk", 123, input)
                   data := MkLineParser{}.split(line, input)
                   mkline := MkLineParser{}.parseDirective(line, data)
                   if !c.Check(mkline, check.NotNil) {
                           return
                   }
   
         test := func(input, expectedIndent, expectedDirective, expectedArgs, expectedComment string) {  
                 m, indent, directive, args, comment := matchMkDirective(input)  
                 c.Check(                  c.Check(
                         []interface{}{m, indent, directive, args, comment},                          []interface{}{mkline.Indent(), mkline.Directive(), mkline.Args(), mkline.DirectiveComment()},
                         deepEquals,                          deepEquals,
                         []interface{}{true, expectedIndent, expectedDirective, expectedArgs, expectedComment})                          []interface{}{expectedIndent, expectedDirective, expectedArgs, expectedComment})
         }                  t.CheckOutput(diagnostics)
   
         testFail := func(input string) {  
                 m, indent, directive, args, comment := matchMkDirective(input)  
                 if m {  
                         c.Errorf("The line %q could be parsed as directive (%q, %q, %q, %q) but shouldn't.",  
                                 indent, directive, args, comment)  
                 }  
         }          }
   
         test(".if ${VAR} == value",          test(".if ${VAR} == value",
                 "", "if", "${VAR} == value", "")                  "", "if", "${VAR} == value", "")
   
         test(".\tendif # comment",          test(".\tendif # comment",
                 "\t", "endif", "", " comment")                  "\t", "endif", "", "comment")
   
         test(".if ${VAR} == \"#\"",          test(".if ${VAR} == \"#\"",
                 "", "if", "${VAR} == \"", "\"")                  "", "if", "${VAR} == \"", "\"")
Line 2019  func (s *Suite) Test_matchMkDirective(c 
Line 2113  func (s *Suite) Test_matchMkDirective(c 
         test(".if ${VAR} == \\",          test(".if ${VAR} == \\",
                 "", "if", "${VAR} == \\", "")                  "", "if", "${VAR} == \\", "")
   
         // Unclosed variable          test(".if ${VAR",
         testFail(".if ${VAR")                  "", "if", "${VAR", "",
                   "WARN: filename.mk:123: Missing closing \"}\" for \"VAR\".")
 }  }
   
 func (s *Suite) Test_MatchMkInclude(c *check.C) {  func (s *Suite) Test_MatchMkInclude(c *check.C) {

Legend:
Removed from v.1.55  
changed lines
  Added in v.1.56

CVSweb <webmaster@jp.NetBSD.org>