pkgsrc/pkgtools/pkglint/files/textproc/lexer_test.go
rillig 0b4c862c88 pkgtools/pkglint: update to 19.3.0
Changes since 5.7.24:

* There is no need to ask the dummy MAINTAINER from url2pkg whether
  committing changes is ok.

* When autofixing a condition like !empty(PKGPATH:Mliteral), don't
  generate unnecessary parentheses around ${PKGPATH} == literal.

* In a _VARGROUPS section, the public variables should be listed
  before the private variables, to put important things first.

* When pkglint suggests to be run again with the -e, -fs or -F options,
  repeat the whole command line, to allow for copy-and-paste.

* The checks for PKGPATH are fixed and enhanced. It is not a relative
  path like in ../../category/package, but relative to the pkgsrc root.

* Unintended file globbing in sed commands such as s,.*,any, gets a
  warning.

* MASTER_SITES should normally end with a slash, in rare cases an
  equals sign or a colon are correct, too.

* Detect redundant directories in INSTALLATION_DIRS.
2019-10-01 21:37:59 +00:00

422 lines
12 KiB
Go

package textproc
import (
"gopkg.in/check.v1"
"netbsd.org/pkglint/intqa"
"regexp"
"strings"
"testing"
"unicode"
)
type Suite struct{}
var equals = check.Equals
func Test(t *testing.T) {
check.Suite(new(Suite))
check.TestingT(t)
}
func (s *Suite) Test_NewLexer(c *check.C) {
lexer := NewLexer("text")
c.Check(lexer.rest, equals, "text")
}
func (s *Suite) Test_Lexer_Rest__initial(c *check.C) {
lexer := NewLexer("text")
c.Check(lexer.Rest(), equals, "text")
}
func (s *Suite) Test_Lexer_Rest__end(c *check.C) {
lexer := NewLexer("")
c.Check(lexer.Rest(), equals, "")
}
func (s *Suite) Test_Lexer_EOF__initial(c *check.C) {
lexer := NewLexer("text")
c.Check(lexer.EOF(), equals, false)
}
func (s *Suite) Test_Lexer_EOF__end(c *check.C) {
lexer := NewLexer("")
c.Check(lexer.EOF(), equals, true)
}
func (s *Suite) Test_Lexer_PeekByte(c *check.C) {
lexer := NewLexer("text")
c.Check(lexer.PeekByte(), equals, int('t'))
c.Check(lexer.NextString("text"), equals, "text")
c.Check(lexer.PeekByte(), equals, -1)
}
func (s *Suite) Test_Lexer_TestByteSet(c *check.C) {
lexer := NewLexer("text")
c.Check(lexer.TestByteSet(Upper), equals, false)
c.Check(lexer.TestByteSet(Lower), equals, true)
c.Check(lexer.TestByteSet(NewByteSet("t")), equals, true)
c.Check(lexer.NextString("text"), equals, "text")
c.Check(lexer.TestByteSet(Upper), equals, false)
c.Check(lexer.TestByteSet(Lower), equals, false)
}
func (s *Suite) Test_Lexer_Skip(c *check.C) {
lexer := NewLexer("example text")
c.Check(lexer.Skip(7), equals, true)
c.Check(lexer.Rest(), equals, " text")
c.Check(lexer.Skip(0), equals, false)
c.Check(lexer.Rest(), equals, " text")
// Skipping a fixed number of bytes only makes sense when the
// lexer has examined every one of them before. Therefore no
// extra check is done here, and panicking here is intentional.
c.Check(
func() { lexer.Skip(6) },
check.PanicMatches,
`runtime error: slice bounds out of range.*`)
}
func (s *Suite) Test_Lexer_NextString(c *check.C) {
lexer := NewLexer("text")
c.Check(lexer.NextString("te"), equals, "te")
c.Check(lexer.NextString("st"), equals, "") // Did not match.
c.Check(lexer.NextString("xt"), equals, "xt")
}
func (s *Suite) Test_Lexer_SkipString(c *check.C) {
lexer := NewLexer("text")
c.Check(lexer.SkipString("te"), equals, true)
c.Check(lexer.SkipString("st"), equals, false)
c.Check(lexer.SkipString("xt"), equals, true)
}
func (s *Suite) Test_Lexer_SkipHspace(c *check.C) {
lexer := NewLexer("spaces \t \t and tabs\n\t ")
c.Check(lexer.NextString("spaces"), equals, "spaces")
c.Check(lexer.SkipHspace(), equals, true)
c.Check(lexer.Rest(), equals, "and tabs\n\t ")
c.Check(lexer.SkipHspace(), equals, false) // No space left.
c.Check(lexer.NextString("and tabs"), equals, "and tabs")
c.Check(lexer.SkipHspace(), equals, false) // Newline is not a horizontal space.
c.Check(lexer.NextString("\n"), equals, "\n")
c.Check(lexer.SkipHspace(), equals, true)
}
func (s *Suite) Test_Lexer_NextHspace(c *check.C) {
lexer := NewLexer("spaces \t \t and tabs\n\t ")
c.Check(lexer.NextString("spaces"), equals, "spaces")
c.Check(lexer.NextHspace(), equals, " \t \t ")
c.Check(lexer.NextHspace(), equals, "") // No space left.
c.Check(lexer.NextString("and tabs"), equals, "and tabs")
c.Check(lexer.NextHspace(), equals, "") // Newline is not a horizontal space.
c.Check(lexer.NextString("\n"), equals, "\n")
c.Check(lexer.NextHspace(), equals, "\t ")
}
func (s *Suite) Test_Lexer_SkipByte(c *check.C) {
lexer := NewLexer("byte")
c.Check(lexer.SkipByte('b'), equals, true)
c.Check(lexer.SkipByte('b'), equals, false) // The b is already chopped off.
c.Check(lexer.SkipByte('y'), equals, true)
c.Check(lexer.SkipByte('t'), equals, true)
c.Check(lexer.SkipByte('e'), equals, true)
c.Check(lexer.SkipByte(0), equals, false) // This is not a C string.
}
func (s *Suite) Test_Lexer_NextByte(c *check.C) {
lexer := NewLexer("byte")
c.Check(lexer.NextByte(), equals, byte('b'))
c.Check(lexer.NextByte(), equals, byte('y'))
c.Check(lexer.NextByte(), equals, byte('t'))
c.Check(lexer.NextByte(), equals, byte('e'))
c.Check(lexer.NextByte, check.PanicMatches, "^runtime error: index out of range.*")
}
func (s *Suite) Test_Lexer_NextBytesFunc(c *check.C) {
lexer := NewLexer("an alphanumerical string")
c.Check(lexer.NextBytesFunc(func(b byte) bool { return 'A' <= b && b <= 'Z' }), equals, "")
c.Check(lexer.NextBytesFunc(func(b byte) bool { return !unicode.IsSpace(rune(b)) }), equals, "an")
c.Check(lexer.NextHspace(), equals, " ")
c.Check(lexer.NextBytesFunc(func(b byte) bool { return 'a' <= b && b <= 'z' }), equals, "alphanumerical")
c.Check(lexer.NextBytesFunc(func(b byte) bool { return true }), equals, " string")
}
func (s *Suite) Test_Lexer_NextByteSet(c *check.C) {
lexer := NewLexer("an a\n")
c.Check(lexer.NextByteSet(Alnum), equals, int('a'))
c.Check(lexer.NextByteSet(Alnum), equals, int('n'))
c.Check(lexer.NextByteSet(Space), equals, int(' '))
c.Check(lexer.NextByteSet(Space), equals, -1)
c.Check(lexer.NextByteSet(Alnum), equals, int('a'))
c.Check(lexer.NextByteSet(Space), equals, int('\n'))
c.Check(lexer.NextByteSet(Alnum), equals, -1)
}
func (s *Suite) Test_Lexer_NextBytesSet(c *check.C) {
lexer := NewLexer("an alphanumerical 90_ \tstring\t\t \n")
c.Check(lexer.NextBytesSet(Alnum), equals, "an")
c.Check(lexer.NextBytesSet(Alnum), equals, "")
c.Check(lexer.NextBytesSet(Space), equals, " ")
c.Check(lexer.NextBytesSet(Alnum), equals, "alphanumerical")
c.Check(lexer.NextBytesSet(Space), equals, " ")
c.Check(lexer.NextBytesSet(AlnumU), equals, "90_")
c.Check(lexer.NextBytesSet(Space), equals, " \t")
c.Check(lexer.NextBytesSet(Alnum), equals, "string")
c.Check(lexer.NextBytesSet(Hspace), equals, "\t\t ")
c.Check(lexer.NextBytesSet(Space), equals, "\n")
}
func (s *Suite) Test_Lexer_SkipRegexp(c *check.C) {
lexer := NewLexer("an alphanumerical 90_ \tstring\t\t \n")
c.Check(lexer.SkipRegexp(regexp.MustCompile(`^\w+`)), equals, true)
c.Check(lexer.Rest(), equals, " alphanumerical 90_ \tstring\t\t \n")
c.Check(lexer.SkipRegexp(regexp.MustCompile(`^.+`)), equals, true)
c.Check(lexer.Rest(), equals, "\n")
c.Check(lexer.SkipRegexp(regexp.MustCompile(`^.+`)), equals, false)
// This call returns false since the matched string was empty.
c.Check(lexer.SkipRegexp(regexp.MustCompile(`^.*`)), equals, false)
c.Check(lexer.Rest(), equals, "\n")
}
func (s *Suite) Test_Lexer_SkipRegexp__panic(c *check.C) {
lexer := NewLexer("an alphanumerical 90_ \tstring\t\t \n")
c.Check(
func() { lexer.SkipRegexp(regexp.MustCompile(`\w+`)) },
check.Panics,
"Lexer.SkipRegexp: regular expression \"\\\\w+\" must have prefix \"^\".")
}
func (s *Suite) Test_Lexer_NextRegexp(c *check.C) {
lexer := NewLexer("an alphanumerical 90_ \tstring\t\t \n")
c.Check(lexer.NextRegexp(regexp.MustCompile(`^\w+`))[0], equals, "an")
c.Check(lexer.NextRegexp(regexp.MustCompile(`^[\w ]+`))[0], equals, " alphanumerical 90_ ")
c.Check(lexer.NextRegexp(regexp.MustCompile(`^.+`))[0], equals, "\tstring\t\t ")
c.Check(lexer.NextRegexp(regexp.MustCompile(`^.+`)), check.IsNil)
c.Check(lexer.NextRegexp(regexp.MustCompile(`^.*`))[0], equals, "")
c.Check(lexer.Rest(), equals, "\n")
}
func (s *Suite) Test_Lexer_NextRegexp__panic(c *check.C) {
lexer := NewLexer("an alphanumerical 90_ \tstring\t\t \n")
c.Check(
func() { lexer.NextRegexp(regexp.MustCompile(`\w+`)) },
check.Panics,
"Lexer.NextRegexp: regular expression \"\\\\w+\" must have prefix \"^\".")
}
func (s *Suite) Test_Lexer_Mark__beginning(c *check.C) {
lexer := NewLexer("text")
mark := lexer.Mark()
c.Check(lexer.NextString("text"), equals, "text")
c.Check(lexer.Rest(), equals, "")
lexer.Reset(mark)
c.Check(lexer.Rest(), equals, "text")
}
func (s *Suite) Test_Lexer_Mark__middle(c *check.C) {
lexer := NewLexer("text")
lexer.NextString("te")
mark := lexer.Mark()
c.Check(lexer.NextString("x"), equals, "x")
c.Check(lexer.Rest(), equals, "t")
lexer.Reset(mark)
c.Check(lexer.Rest(), equals, "xt")
}
// Demonstrates that multiple marks can be taken at the same time and that
// the lexer can be reset to any of them in any order.
func (s *Suite) Test_Lexer_Reset__multiple(c *check.C) {
lexer := NewLexer("text")
mark0 := lexer.Mark()
c.Check(lexer.NextString("te"), equals, "te")
mark2 := lexer.Mark()
c.Check(lexer.NextString("x"), equals, "x")
mark3 := lexer.Mark()
c.Check(lexer.NextString("t"), equals, "t")
mark4 := lexer.Mark()
c.Check(lexer.Rest(), equals, "")
lexer.Reset(mark0)
c.Check(lexer.Rest(), equals, "text")
lexer.Reset(mark3)
c.Check(lexer.Rest(), equals, "t")
lexer.Reset(mark2)
c.Check(lexer.Rest(), equals, "xt")
lexer.Reset(mark4)
c.Check(lexer.Rest(), equals, "")
}
func (s *Suite) Test_Lexer__NextString_then_EOF(c *check.C) {
lexer := NewLexer("text")
lexer.NextString("text")
c.Check(lexer.EOF(), equals, true)
}
func (s *Suite) Test_Lexer_Since(c *check.C) {
lexer := NewLexer("text")
mark := lexer.Mark()
c.Check(lexer.NextString("te"), equals, "te")
c.Check(lexer.NextString("st"), equals, "") // Did not match.
c.Check(lexer.Since(mark), equals, "te")
c.Check(lexer.NextString("xt"), equals, "xt")
c.Check(lexer.Since(mark), equals, "text")
}
func (s *Suite) Test_Lexer_Copy(c *check.C) {
lexer := NewLexer("text")
copied := lexer.Copy()
c.Check(copied.Rest(), equals, lexer.Rest())
copied.NextString("te")
c.Check(copied.Rest(), equals, "xt")
c.Check(lexer.Rest(), equals, "text") // The original is not yet affected.
}
func (s *Suite) Test_Lexer_Commit(c *check.C) {
lexer := NewLexer("text")
copied := lexer.Copy()
copied.NextString("te")
c.Check(lexer.Rest(), equals, "text") // The original is not yet affected.
lexer.Commit(copied)
c.Check(lexer.Rest(), equals, "xt")
}
func (s *Suite) Test_NewByteSet(c *check.C) {
set := NewByteSet("A-Za-z0-9_\xFC")
expected := "" +
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
"abcdefghijklmnopqrstuvwxyz" +
"0123456789_\xFC"
for i := 0; i < 256; i++ {
c.Check(
set.Contains(byte(i)),
equals,
strings.IndexByte(expected, byte(i)) != -1)
}
}
// Demonstrates how to specify a byte set that includes a hyphen,
// since that is also used for byte ranges.
// The hyphen must be written as ---, which is a range from hyphen to hyphen.
func (s *Suite) Test_NewByteSet__range_hyphen(c *check.C) {
set := NewByteSet("---a-z")
expected := "abcdefghijklmnopqrstuvwxyz-"
for i := 0; i < 256; i++ {
c.Check(
set.Contains(byte(i)),
equals,
strings.IndexByte(expected, byte(i)) != -1)
}
}
func (s *Suite) Test_ByteSet_Inverse(c *check.C) {
set := NewByteSet("A-Za-z0-9_\xFC")
inverse := set.Inverse()
for i := 0; i < 256; i++ {
c.Check(
inverse.Contains(byte(i)),
equals,
!set.Contains(byte(i)))
}
}
func (s *Suite) Test_ByteSet_Contains(c *check.C) {
set := NewByteSet("A-Za-z0-9_\xFC")
c.Check(set.Contains(0x00), equals, false)
c.Check(set.Contains('-'), equals, false)
c.Check(set.Contains('A'), equals, true)
c.Check(set.Contains('Z'), equals, true)
c.Check(set.Contains('['), equals, false)
c.Check(set.Contains(0xFC), equals, true)
c.Check(set.Contains(0xFD), equals, false)
}
func (s *Suite) Test__XPrint(c *check.C) {
set := XPrint
c.Check(set.Contains(0x00), equals, false)
c.Check(set.Contains(0x08), equals, false)
c.Check(set.Contains('\t'), equals, true)
c.Check(set.Contains('\n'), equals, true)
c.Check(set.Contains('\v'), equals, false)
c.Check(set.Contains(' '), equals, true)
c.Check(set.Contains('~'), equals, true)
c.Check(set.Contains(0x7F), equals, false)
c.Check(set.Contains(0xA0), equals, false)
}
func (s *Suite) Test__Alpha(c *check.C) {
set := Alpha
c.Check(set.Contains(0x00), equals, false)
c.Check(set.Contains('@'), equals, false)
c.Check(set.Contains('A'), equals, true)
c.Check(set.Contains('Z'), equals, true)
c.Check(set.Contains('`'), equals, false)
c.Check(set.Contains('a'), equals, true)
c.Check(set.Contains('z'), equals, true)
}
func (s *Suite) Test__test_names(c *check.C) {
ck := intqa.NewTestNameChecker(c)
ck.AllowCamelCaseDescriptions(
"NextString_then_EOF")
ck.ShowWarnings(false)
ck.Check()
}