Files
nats-server/conf/lex_test.go
Ivan Kozlovic 86d20aa5e6 [FIXED] Parsing of strings starting with numbers and K/G/etc.. suffix
If a configuration variable starts with numbers and has a character
that such as K/k/G/g/etc.. it would assume that it was a number
(expressed in Kb, Gb, etc..).

This PR checks that if the special characters are not the suffix,
that is, the variable does not end after those characters, then
the parsing will treat the whole thing as a string.

Resolves #3431

Signed-off-by: Ivan Kozlovic <ivan@synadia.com>
2022-09-02 18:15:04 -06:00

1596 lines
34 KiB
Go

package conf
import "testing"
// Test to make sure we get what we expect.
func expect(t *testing.T, lx *lexer, items []item) {
t.Helper()
for i := 0; i < len(items); i++ {
item := lx.nextItem()
_ = item.String()
if item.typ == itemEOF {
break
}
if item != items[i] {
t.Fatalf("Testing: '%s'\nExpected %q, received %q\n",
lx.input, items[i], item)
}
if item.typ == itemError {
break
}
}
}
func TestPlainValue(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemEOF, "", 1, 0},
}
lx := lex("foo")
expect(t, lx, expectedItems)
}
func TestSimpleKeyStringValues(t *testing.T) {
// Double quotes
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemString, "bar", 1, 7},
{itemEOF, "", 1, 0},
}
lx := lex("foo = \"bar\"")
expect(t, lx, expectedItems)
// Single quotes
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemString, "bar", 1, 7},
{itemEOF, "", 1, 0},
}
lx = lex("foo = 'bar'")
expect(t, lx, expectedItems)
// No spaces
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemString, "bar", 1, 5},
{itemEOF, "", 1, 0},
}
lx = lex("foo='bar'")
expect(t, lx, expectedItems)
// NL
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemString, "bar", 1, 5},
{itemEOF, "", 1, 0},
}
lx = lex("foo='bar'\r\n")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemString, "bar", 1, 6},
{itemEOF, "", 1, 0},
}
lx = lex("foo=\t'bar'\t")
expect(t, lx, expectedItems)
}
func TestComplexStringValues(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemString, "bar\\r\\n \\t", 1, 7},
{itemEOF, "", 2, 0},
}
lx := lex("foo = 'bar\\r\\n \\t'")
expect(t, lx, expectedItems)
}
func TestStringStartingWithNumber(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemString, "3xyz", 1, 6},
{itemEOF, "", 2, 0},
}
lx := lex(`foo = 3xyz`)
expect(t, lx, expectedItems)
lx = lex(`foo = 3xyz,`)
expect(t, lx, expectedItems)
lx = lex(`foo = 3xyz;`)
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 2, 9},
{itemString, "3xyz", 2, 15},
{itemEOF, "", 2, 0},
}
content := `
foo = 3xyz
`
lx = lex(content)
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "map", 2, 9},
{itemMapStart, "", 2, 14},
{itemKey, "foo", 3, 11},
{itemString, "3xyz", 3, 17},
{itemMapEnd, "", 3, 22},
{itemEOF, "", 2, 0},
}
content = `
map {
foo = 3xyz}
`
lx = lex(content)
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "map", 2, 9},
{itemMapStart, "", 2, 14},
{itemKey, "foo", 3, 11},
{itemString, "3xyz", 3, 17},
{itemMapEnd, "", 4, 10},
{itemEOF, "", 2, 0},
}
content = `
map {
foo = 3xyz;
}
`
lx = lex(content)
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "map", 2, 9},
{itemMapStart, "", 2, 14},
{itemKey, "foo", 3, 11},
{itemString, "3xyz", 3, 17},
{itemKey, "bar", 4, 11},
{itemString, "4wqs", 4, 17},
{itemMapEnd, "", 5, 10},
{itemEOF, "", 2, 0},
}
content = `
map {
foo = 3xyz,
bar = 4wqs
}
`
lx = lex(content)
expect(t, lx, expectedItems)
}
func TestBinaryString(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemString, "e", 1, 9},
{itemEOF, "", 1, 0},
}
lx := lex("foo = \\x65")
expect(t, lx, expectedItems)
}
func TestBinaryStringLatin1(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemString, "\xe9", 1, 9},
{itemEOF, "", 1, 0},
}
lx := lex("foo = \\xe9")
expect(t, lx, expectedItems)
}
func TestSimpleKeyIntegerValues(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemInteger, "123", 1, 6},
{itemEOF, "", 1, 0},
}
lx := lex("foo = 123")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemInteger, "123", 1, 4},
{itemEOF, "", 1, 0},
}
lx = lex("foo=123")
expect(t, lx, expectedItems)
lx = lex("foo=123\r\n")
expect(t, lx, expectedItems)
}
func TestSimpleKeyNegativeIntegerValues(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemInteger, "-123", 1, 6},
{itemEOF, "", 1, 0},
}
lx := lex("foo = -123")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemInteger, "-123", 1, 4},
{itemEOF, "", 1, 0},
}
lx = lex("foo=-123")
expect(t, lx, expectedItems)
lx = lex("foo=-123\r\n")
expect(t, lx, expectedItems)
}
func TestConvenientIntegerValues(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemInteger, "1k", 1, 6},
{itemEOF, "", 1, 0},
}
lx := lex("foo = 1k")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemInteger, "1K", 1, 6},
{itemEOF, "", 1, 0},
}
lx = lex("foo = 1K")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemInteger, "1m", 1, 6},
{itemEOF, "", 1, 0},
}
lx = lex("foo = 1m")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemInteger, "1M", 1, 6},
{itemEOF, "", 1, 0},
}
lx = lex("foo = 1M")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemInteger, "1g", 1, 6},
{itemEOF, "", 1, 0},
}
lx = lex("foo = 1g")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemInteger, "1G", 1, 6},
{itemEOF, "", 1, 0},
}
lx = lex("foo = 1G")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemInteger, "1MB", 1, 6},
{itemEOF, "", 1, 0},
}
lx = lex("foo = 1MB")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemInteger, "1Gb", 1, 6},
{itemEOF, "", 1, 0},
}
lx = lex("foo = 1Gb")
expect(t, lx, expectedItems)
// Negative versions
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemInteger, "-1m", 1, 6},
{itemEOF, "", 1, 0},
}
lx = lex("foo = -1m")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemInteger, "-1GB", 1, 6},
{itemEOF, "", 1, 0},
}
lx = lex("foo = -1GB ")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemString, "1Ghz", 1, 6},
{itemEOF, "", 1, 0},
}
lx = lex("foo = 1Ghz")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemString, "2Pie", 1, 6},
{itemEOF, "", 1, 0},
}
lx = lex("foo = 2Pie")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemString, "3Mbs", 1, 6},
{itemEOF, "", 1, 0},
}
lx = lex("foo = 3Mbs,")
expect(t, lx, expectedItems)
}
func TestSimpleKeyFloatValues(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemFloat, "22.2", 1, 6},
{itemEOF, "", 1, 0},
}
lx := lex("foo = 22.2")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemFloat, "22.2", 1, 4},
{itemEOF, "", 1, 0},
}
lx = lex("foo=22.2")
expect(t, lx, expectedItems)
lx = lex("foo=22.2\r\n")
expect(t, lx, expectedItems)
}
func TestBadBinaryStringEndingAfterZeroHexChars(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemError, "Expected two hexadecimal digits after '\\x', but hit end of line", 2, 1},
{itemEOF, "", 1, 0},
}
lx := lex("foo = xyz\\x\n")
expect(t, lx, expectedItems)
}
func TestBadBinaryStringEndingAfterOneHexChar(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemError, "Expected two hexadecimal digits after '\\x', but hit end of line", 2, 1},
{itemEOF, "", 1, 0},
}
lx := lex("foo = xyz\\xF\n")
expect(t, lx, expectedItems)
}
func TestBadBinaryStringWithZeroHexChars(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemError, "Expected two hexadecimal digits after '\\x', but got ']\"'", 1, 12},
{itemEOF, "", 1, 0},
}
lx := lex(`foo = "[\x]"`)
expect(t, lx, expectedItems)
}
func TestBadBinaryStringWithOneHexChar(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemError, "Expected two hexadecimal digits after '\\x', but got 'e]'", 1, 12},
{itemEOF, "", 1, 0},
}
lx := lex(`foo = "[\xe]"`)
expect(t, lx, expectedItems)
}
func TestBadFloatValues(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemError, "Floats must start with a digit", 1, 7},
{itemEOF, "", 1, 0},
}
lx := lex("foo = .2")
expect(t, lx, expectedItems)
}
func TestBadKey(t *testing.T) {
expectedItems := []item{
{itemError, "Unexpected key separator ':'", 1, 1},
{itemEOF, "", 1, 0},
}
lx := lex(" :foo = 22")
expect(t, lx, expectedItems)
}
func TestSimpleKeyBoolValues(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemBool, "true", 1, 6},
{itemEOF, "", 1, 0},
}
lx := lex("foo = true")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemBool, "true", 1, 4},
{itemEOF, "", 1, 0},
}
lx = lex("foo=true")
expect(t, lx, expectedItems)
lx = lex("foo=true\r\n")
expect(t, lx, expectedItems)
}
func TestComments(t *testing.T) {
expectedItems := []item{
{itemCommentStart, "", 1, 1},
{itemText, " This is a comment", 1, 1},
{itemEOF, "", 1, 0},
}
lx := lex("# This is a comment")
expect(t, lx, expectedItems)
lx = lex("# This is a comment\r\n")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemCommentStart, "", 1, 2},
{itemText, " This is a comment", 1, 2},
{itemEOF, "", 1, 0},
}
lx = lex("// This is a comment\r\n")
expect(t, lx, expectedItems)
}
func TestTopValuesWithComments(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemInteger, "123", 1, 6},
{itemCommentStart, "", 1, 12},
{itemText, " This is a comment", 1, 12},
{itemEOF, "", 1, 0},
}
lx := lex("foo = 123 // This is a comment")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemInteger, "123", 1, 4},
{itemCommentStart, "", 1, 12},
{itemText, " This is a comment", 1, 12},
{itemEOF, "", 1, 0},
}
lx = lex("foo=123 # This is a comment")
expect(t, lx, expectedItems)
}
func TestRawString(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemString, "bar", 1, 6},
{itemEOF, "", 1, 0},
}
lx := lex("foo = bar")
expect(t, lx, expectedItems)
lx = lex(`foo = bar' `)
expect(t, lx, expectedItems)
}
func TestDateValues(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemDatetime, "2016-05-04T18:53:41Z", 1, 6},
{itemEOF, "", 1, 0},
}
lx := lex("foo = 2016-05-04T18:53:41Z")
expect(t, lx, expectedItems)
}
func TestVariableValues(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemVariable, "bar", 1, 7},
{itemEOF, "", 1, 0},
}
lx := lex("foo = $bar")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemVariable, "bar", 1, 6},
{itemEOF, "", 1, 0},
}
lx = lex("foo =$bar")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemVariable, "bar", 1, 5},
{itemEOF, "", 1, 0},
}
lx = lex("foo $bar")
expect(t, lx, expectedItems)
}
func TestArrays(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemArrayStart, "", 1, 7},
{itemInteger, "1", 1, 7},
{itemInteger, "2", 1, 10},
{itemInteger, "3", 1, 13},
{itemString, "bar", 1, 17},
{itemArrayEnd, "", 1, 22},
{itemEOF, "", 1, 0},
}
lx := lex("foo = [1, 2, 3, 'bar']")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemArrayStart, "", 1, 7},
{itemInteger, "1", 1, 7},
{itemInteger, "2", 1, 9},
{itemInteger, "3", 1, 11},
{itemString, "bar", 1, 14},
{itemArrayEnd, "", 1, 19},
{itemEOF, "", 1, 0},
}
lx = lex("foo = [1,2,3,'bar']")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemArrayStart, "", 1, 7},
{itemInteger, "1", 1, 7},
{itemInteger, "2", 1, 10},
{itemInteger, "3", 1, 12},
{itemString, "bar", 1, 15},
{itemArrayEnd, "", 1, 20},
{itemEOF, "", 1, 0},
}
lx = lex("foo = [1, 2,3,'bar']")
expect(t, lx, expectedItems)
}
var mlArray = `
# top level comment
foo = [
1, # One
2, // Two
3 # Three
'bar' ,
"bar"
]
`
func TestMultilineArrays(t *testing.T) {
expectedItems := []item{
{itemCommentStart, "", 2, 2},
{itemText, " top level comment", 2, 2},
{itemKey, "foo", 3, 1},
{itemArrayStart, "", 3, 8},
{itemInteger, "1", 4, 2},
{itemCommentStart, "", 4, 6},
{itemText, " One", 4, 6},
{itemInteger, "2", 5, 2},
{itemCommentStart, "", 5, 7},
{itemText, " Two", 5, 7},
{itemInteger, "3", 6, 2},
{itemCommentStart, "", 6, 5},
{itemText, " Three", 6, 5},
{itemString, "bar", 7, 3},
{itemString, "bar", 8, 3},
{itemArrayEnd, "", 9, 2},
{itemEOF, "", 9, 0},
}
lx := lex(mlArray)
expect(t, lx, expectedItems)
}
var mlArrayNoSep = `
# top level comment
foo = [
1 // foo
2
3
'bar'
"bar"
]
`
func TestMultilineArraysNoSep(t *testing.T) {
expectedItems := []item{
{itemCommentStart, "", 2, 2},
{itemText, " top level comment", 2, 2},
{itemKey, "foo", 3, 1},
{itemArrayStart, "", 3, 8},
{itemInteger, "1", 4, 2},
{itemCommentStart, "", 4, 6},
{itemText, " foo", 4, 6},
{itemInteger, "2", 5, 2},
{itemInteger, "3", 6, 2},
{itemString, "bar", 7, 3},
{itemString, "bar", 8, 3},
{itemArrayEnd, "", 9, 2},
{itemEOF, "", 9, 0},
}
lx := lex(mlArrayNoSep)
expect(t, lx, expectedItems)
}
func TestSimpleMap(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemMapStart, "", 1, 7},
{itemKey, "ip", 1, 7},
{itemString, "127.0.0.1", 1, 11},
{itemKey, "port", 1, 23},
{itemInteger, "4242", 1, 30},
{itemMapEnd, "", 1, 35},
{itemEOF, "", 1, 0},
}
lx := lex("foo = {ip='127.0.0.1', port = 4242}")
expect(t, lx, expectedItems)
}
var mlMap = `
foo = {
ip = '127.0.0.1' # the IP
port= 4242 // the port
}
`
func TestMultilineMap(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 2, 1},
{itemMapStart, "", 2, 8},
{itemKey, "ip", 3, 3},
{itemString, "127.0.0.1", 3, 9},
{itemCommentStart, "", 3, 21},
{itemText, " the IP", 3, 21},
{itemKey, "port", 4, 3},
{itemInteger, "4242", 4, 9},
{itemCommentStart, "", 4, 16},
{itemText, " the port", 4, 16},
{itemMapEnd, "", 5, 2},
{itemEOF, "", 5, 0},
}
lx := lex(mlMap)
expect(t, lx, expectedItems)
}
var nestedMap = `
foo = {
host = {
ip = '127.0.0.1'
port= 4242
}
}
`
func TestNestedMaps(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 2, 1},
{itemMapStart, "", 2, 8},
{itemKey, "host", 3, 3},
{itemMapStart, "", 3, 11},
{itemKey, "ip", 4, 5},
{itemString, "127.0.0.1", 4, 11},
{itemKey, "port", 5, 5},
{itemInteger, "4242", 5, 11},
{itemMapEnd, "", 6, 4},
{itemMapEnd, "", 7, 2},
{itemEOF, "", 7, 0},
}
lx := lex(nestedMap)
expect(t, lx, expectedItems)
}
func TestQuotedKeys(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemInteger, "123", 1, 6},
{itemEOF, "", 1, 0},
}
lx := lex("foo : 123")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 1},
{itemInteger, "123", 1, 8},
{itemEOF, "", 1, 0},
}
lx = lex("'foo' : 123")
expect(t, lx, expectedItems)
lx = lex("\"foo\" : 123")
expect(t, lx, expectedItems)
}
func TestQuotedKeysWithSpace(t *testing.T) {
expectedItems := []item{
{itemKey, " foo", 1, 1},
{itemInteger, "123", 1, 9},
{itemEOF, "", 1, 0},
}
lx := lex("' foo' : 123")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, " foo", 1, 1},
{itemInteger, "123", 1, 9},
{itemEOF, "", 1, 0},
}
lx = lex("\" foo\" : 123")
expect(t, lx, expectedItems)
}
func TestColonKeySep(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemInteger, "123", 1, 6},
{itemEOF, "", 1, 0},
}
lx := lex("foo : 123")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemInteger, "123", 1, 4},
{itemEOF, "", 1, 0},
}
lx = lex("foo:123")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemInteger, "123", 1, 5},
{itemEOF, "", 1, 0},
}
lx = lex("foo: 123")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemInteger, "123", 1, 6},
{itemEOF, "", 1, 0},
}
lx = lex("foo: 123\r\n")
expect(t, lx, expectedItems)
}
func TestWhitespaceKeySep(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemInteger, "123", 1, 4},
{itemEOF, "", 1, 0},
}
lx := lex("foo 123")
expect(t, lx, expectedItems)
lx = lex("foo 123")
expect(t, lx, expectedItems)
lx = lex("foo\t123")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemInteger, "123", 1, 5},
{itemEOF, "", 1, 0},
}
lx = lex("foo\t\t123\r\n")
expect(t, lx, expectedItems)
}
var escString = `
foo = \t
bar = \r
baz = \n
q = \"
bs = \\
`
func TestEscapedString(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 2, 1},
{itemString, "\t", 2, 9},
{itemKey, "bar", 3, 1},
{itemString, "\r", 3, 9},
{itemKey, "baz", 4, 1},
{itemString, "\n", 4, 9},
{itemKey, "q", 5, 1},
{itemString, "\"", 5, 9},
{itemKey, "bs", 6, 1},
{itemString, "\\", 6, 9},
{itemEOF, "", 6, 0},
}
lx := lex(escString)
expect(t, lx, expectedItems)
}
func TestCompoundStringES(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemString, "\\end", 1, 8},
{itemEOF, "", 2, 0},
}
lx := lex(`foo = "\\end"`)
expect(t, lx, expectedItems)
}
func TestCompoundStringSE(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemString, "start\\", 1, 8},
{itemEOF, "", 2, 0},
}
lx := lex(`foo = "start\\"`)
expect(t, lx, expectedItems)
}
func TestCompoundStringEE(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemString, "Eq", 1, 12},
{itemEOF, "", 2, 0},
}
lx := lex(`foo = \x45\x71`)
expect(t, lx, expectedItems)
}
func TestCompoundStringSEE(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemString, "startEq", 1, 12},
{itemEOF, "", 2, 0},
}
lx := lex(`foo = start\x45\x71`)
expect(t, lx, expectedItems)
}
func TestCompoundStringSES(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemString, "start|end", 1, 9},
{itemEOF, "", 2, 0},
}
lx := lex(`foo = start\x7Cend`)
expect(t, lx, expectedItems)
}
func TestCompoundStringEES(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemString, "<>end", 1, 12},
{itemEOF, "", 2, 0},
}
lx := lex(`foo = \x3c\x3eend`)
expect(t, lx, expectedItems)
}
func TestCompoundStringESE(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemString, "<middle>", 1, 12},
{itemEOF, "", 2, 0},
}
lx := lex(`foo = \x3cmiddle\x3E`)
expect(t, lx, expectedItems)
}
func TestBadStringEscape(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemError, "Invalid escape character 'y'. Only the following escape characters are allowed: \\xXX, \\t, \\n, \\r, \\\", \\\\.", 1, 8},
{itemEOF, "", 2, 0},
}
lx := lex(`foo = \y`)
expect(t, lx, expectedItems)
}
func TestNonBool(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemString, "\\true", 1, 7},
{itemEOF, "", 2, 0},
}
lx := lex(`foo = \\true`)
expect(t, lx, expectedItems)
}
func TestNonVariable(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemString, "\\$var", 1, 7},
{itemEOF, "", 2, 0},
}
lx := lex(`foo = \\$var`)
expect(t, lx, expectedItems)
}
func TestEmptyStringDQ(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemString, "", 1, 7},
{itemEOF, "", 2, 0},
}
lx := lex(`foo = ""`)
expect(t, lx, expectedItems)
}
func TestEmptyStringSQ(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemString, "", 1, 7},
{itemEOF, "", 2, 0},
}
lx := lex(`foo = ''`)
expect(t, lx, expectedItems)
}
var nestedWhitespaceMap = `
foo {
host {
ip = '127.0.0.1'
port= 4242
}
}
`
func TestNestedWhitespaceMaps(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 2, 1},
{itemMapStart, "", 2, 7},
{itemKey, "host", 3, 3},
{itemMapStart, "", 3, 10},
{itemKey, "ip", 4, 5},
{itemString, "127.0.0.1", 4, 11},
{itemKey, "port", 5, 5},
{itemInteger, "4242", 5, 11},
{itemMapEnd, "", 6, 4},
{itemMapEnd, "", 7, 2},
{itemEOF, "", 7, 0},
}
lx := lex(nestedWhitespaceMap)
expect(t, lx, expectedItems)
}
var semicolons = `
foo = 123;
bar = 'baz';
baz = 'boo'
map {
id = 1;
}
`
func TestOptionalSemicolons(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 2, 1},
{itemInteger, "123", 2, 7},
{itemKey, "bar", 3, 1},
{itemString, "baz", 3, 8},
{itemKey, "baz", 4, 1},
{itemString, "boo", 4, 8},
{itemKey, "map", 5, 1},
{itemMapStart, "", 5, 6},
{itemKey, "id", 6, 2},
{itemInteger, "1", 6, 7},
{itemMapEnd, "", 7, 2},
{itemEOF, "", 8, 0},
}
lx := lex(semicolons)
expect(t, lx, expectedItems)
}
func TestSemicolonChaining(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemString, "1", 1, 5},
{itemKey, "bar", 1, 9},
{itemFloat, "2.2", 1, 13},
{itemKey, "baz", 1, 18},
{itemBool, "true", 1, 22},
{itemEOF, "", 1, 0},
}
lx := lex("foo='1'; bar=2.2; baz=true;")
expect(t, lx, expectedItems)
}
var noquotes = `
foo = 123
bar = baz
baz=boo
map {
id:one
id2 : onetwo
}
t true
f false
tstr "true"
tkey = two
fkey = five # This should be a string
`
func TestNonQuotedStrings(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 2, 1},
{itemInteger, "123", 2, 7},
{itemKey, "bar", 3, 1},
{itemString, "baz", 3, 7},
{itemKey, "baz", 4, 1},
{itemString, "boo", 4, 5},
{itemKey, "map", 5, 1},
{itemMapStart, "", 5, 6},
{itemKey, "id", 6, 2},
{itemString, "one", 6, 5},
{itemKey, "id2", 7, 2},
{itemString, "onetwo", 7, 8},
{itemMapEnd, "", 8, 2},
{itemKey, "t", 9, 1},
{itemBool, "true", 9, 3},
{itemKey, "f", 10, 1},
{itemBool, "false", 10, 3},
{itemKey, "tstr", 11, 1},
{itemString, "true", 11, 7},
{itemKey, "tkey", 12, 1},
{itemString, "two", 12, 8},
{itemKey, "fkey", 13, 1},
{itemString, "five", 13, 8},
{itemCommentStart, "", 13, 14},
{itemText, " This should be a string", 13, 14},
{itemEOF, "", 14, 0},
}
lx := lex(noquotes)
expect(t, lx, expectedItems)
}
var danglingquote = `
listen: "localhost:4242
http: localhost:8222
`
func TestDanglingQuotedString(t *testing.T) {
expectedItems := []item{
{itemKey, "listen", 2, 1},
{itemError, "Unexpected EOF.", 5, 1},
}
lx := lex(danglingquote)
expect(t, lx, expectedItems)
}
var keydanglingquote = `
foo = "
listen: "
http: localhost:8222
"
`
func TestKeyDanglingQuotedString(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 2, 1},
{itemString, "\nlisten: ", 3, 8},
{itemKey, "http", 5, 1},
{itemString, "localhost:8222", 5, 7},
{itemError, "Unexpected EOF.", 8, 1},
}
lx := lex(keydanglingquote)
expect(t, lx, expectedItems)
}
var danglingsquote = `
listen: 'localhost:4242
http: localhost:8222
`
func TestDanglingSingleQuotedString(t *testing.T) {
expectedItems := []item{
{itemKey, "listen", 2, 1},
{itemError, "Unexpected EOF.", 5, 1},
}
lx := lex(danglingsquote)
expect(t, lx, expectedItems)
}
var keydanglingsquote = `
foo = '
listen: '
http: localhost:8222
'
`
func TestKeyDanglingSingleQuotedString(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 2, 1},
{itemString, "\nlisten: ", 3, 8},
{itemKey, "http", 5, 1},
{itemString, "localhost:8222", 5, 7},
{itemError, "Unexpected EOF.", 8, 1},
}
lx := lex(keydanglingsquote)
expect(t, lx, expectedItems)
}
var mapdanglingbracket = `
listen = 4222
cluster = {
foo = bar
`
func TestMapDanglingBracket(t *testing.T) {
expectedItems := []item{
{itemKey, "listen", 2, 1},
{itemInteger, "4222", 2, 10},
{itemKey, "cluster", 4, 1},
{itemMapStart, "", 4, 12},
{itemKey, "foo", 6, 3},
{itemString, "bar", 6, 9},
{itemError, "Unexpected EOF processing map.", 8, 1},
}
lx := lex(mapdanglingbracket)
expect(t, lx, expectedItems)
}
var blockdanglingparens = `
listen = 4222
quote = (
foo = bar
`
func TestBlockDanglingParens(t *testing.T) {
expectedItems := []item{
{itemKey, "listen", 2, 1},
{itemInteger, "4222", 2, 10},
{itemKey, "quote", 4, 1},
{itemError, "Unexpected EOF processing block.", 8, 1},
}
lx := lex(blockdanglingparens)
expect(t, lx, expectedItems)
}
func TestMapQuotedKeys(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemMapStart, "", 1, 7},
{itemKey, "bar", 1, 8},
{itemInteger, "4242", 1, 15},
{itemMapEnd, "", 1, 20},
{itemEOF, "", 1, 0},
}
lx := lex("foo = {'bar' = 4242}")
expect(t, lx, expectedItems)
lx = lex("foo = {\"bar\" = 4242}")
expect(t, lx, expectedItems)
}
func TestSpecialCharsMapQuotedKeys(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemMapStart, "", 1, 7},
{itemKey, "bar-1.2.3", 1, 8},
{itemMapStart, "", 1, 22},
{itemKey, "port", 1, 23},
{itemInteger, "4242", 1, 28},
{itemMapEnd, "", 1, 34},
{itemMapEnd, "", 1, 35},
{itemEOF, "", 1, 0},
}
lx := lex("foo = {'bar-1.2.3' = { port:4242 }}")
expect(t, lx, expectedItems)
lx = lex("foo = {\"bar-1.2.3\" = { port:4242 }}")
expect(t, lx, expectedItems)
}
var mlnestedmap = `
systems {
allinone {
description: "This is a description."
}
}
`
func TestDoubleNestedMapsNewLines(t *testing.T) {
expectedItems := []item{
{itemKey, "systems", 2, 1},
{itemMapStart, "", 2, 10},
{itemKey, "allinone", 3, 3},
{itemMapStart, "", 3, 13},
{itemKey, "description", 4, 5},
{itemString, "This is a description.", 4, 19},
{itemMapEnd, "", 5, 4},
{itemMapEnd, "", 6, 2},
{itemEOF, "", 7, 0},
}
lx := lex(mlnestedmap)
expect(t, lx, expectedItems)
}
var blockexample = `
numbers (
1234567890
)
`
func TestBlockString(t *testing.T) {
expectedItems := []item{
{itemKey, "numbers", 2, 1},
{itemString, "\n1234567890\n", 4, 10},
}
lx := lex(blockexample)
expect(t, lx, expectedItems)
}
func TestBlockStringEOF(t *testing.T) {
expectedItems := []item{
{itemKey, "numbers", 2, 1},
{itemString, "\n1234567890\n", 4, 10},
}
blockbytes := []byte(blockexample[0 : len(blockexample)-1])
blockbytes = append(blockbytes, 0)
lx := lex(string(blockbytes))
expect(t, lx, expectedItems)
}
var mlblockexample = `
numbers (
12(34)56
(
7890
)
)
`
func TestBlockStringMultiLine(t *testing.T) {
expectedItems := []item{
{itemKey, "numbers", 2, 1},
{itemString, "\n 12(34)56\n (\n 7890\n )\n", 7, 10},
}
lx := lex(mlblockexample)
expect(t, lx, expectedItems)
}
func TestUnquotedIPAddr(t *testing.T) {
expectedItems := []item{
{itemKey, "listen", 1, 0},
{itemString, "127.0.0.1:4222", 1, 8},
{itemEOF, "", 1, 0},
}
lx := lex("listen: 127.0.0.1:4222")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "listen", 1, 0},
{itemString, "127.0.0.1", 1, 8},
{itemEOF, "", 1, 0},
}
lx = lex("listen: 127.0.0.1")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "listen", 1, 0},
{itemString, "apcera.me:80", 1, 8},
{itemEOF, "", 1, 0},
}
lx = lex("listen: apcera.me:80")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "listen", 1, 0},
{itemString, "nats.io:-1", 1, 8},
{itemEOF, "", 1, 0},
}
lx = lex("listen: nats.io:-1")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "listen", 1, 0},
{itemInteger, "-1", 1, 8},
{itemEOF, "", 1, 0},
}
lx = lex("listen: -1")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "listen", 1, 0},
{itemString, ":-1", 1, 8},
{itemEOF, "", 1, 0},
}
lx = lex("listen: :-1")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "listen", 1, 0},
{itemString, ":80", 1, 9},
{itemEOF, "", 1, 0},
}
lx = lex("listen = :80")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "listen", 1, 0},
{itemArrayStart, "", 1, 10},
{itemString, "localhost:4222", 1, 10},
{itemString, "localhost:4333", 1, 26},
{itemArrayEnd, "", 1, 41},
{itemEOF, "", 1, 0},
}
lx = lex("listen = [localhost:4222, localhost:4333]")
expect(t, lx, expectedItems)
}
var arrayOfMaps = `
authorization {
users = [
{user: alice, password: foo}
{user: bob, password: bar}
]
timeout: 0.5
}
`
func TestArrayOfMaps(t *testing.T) {
expectedItems := []item{
{itemKey, "authorization", 2, 1},
{itemMapStart, "", 2, 16},
{itemKey, "users", 3, 5},
{itemArrayStart, "", 3, 14},
{itemMapStart, "", 4, 8},
{itemKey, "user", 4, 8},
{itemString, "alice", 4, 14},
{itemKey, "password", 4, 21},
{itemString, "foo", 4, 31},
{itemMapEnd, "", 4, 35},
{itemMapStart, "", 5, 8},
{itemKey, "user", 5, 8},
{itemString, "bob", 5, 14},
{itemKey, "password", 5, 21},
{itemString, "bar", 5, 31},
{itemMapEnd, "", 5, 35},
{itemArrayEnd, "", 6, 6},
{itemKey, "timeout", 7, 5},
{itemFloat, "0.5", 7, 14},
{itemMapEnd, "", 8, 2},
{itemEOF, "", 9, 0},
}
lx := lex(arrayOfMaps)
expect(t, lx, expectedItems)
}
func TestInclude(t *testing.T) {
expectedItems := []item{
{itemInclude, "users.conf", 1, 9},
{itemEOF, "", 1, 0},
}
lx := lex("include \"users.conf\"")
expect(t, lx, expectedItems)
lx = lex("include 'users.conf'")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemInclude, "users.conf", 1, 8},
{itemEOF, "", 1, 0},
}
lx = lex("include users.conf")
expect(t, lx, expectedItems)
}
func TestMapInclude(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1, 0},
{itemMapStart, "", 1, 5},
{itemInclude, "users.conf", 1, 14},
{itemMapEnd, "", 1, 26},
{itemEOF, "", 1, 0},
}
lx := lex("foo { include users.conf }")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemMapStart, "", 1, 5},
{itemInclude, "users.conf", 1, 13},
{itemMapEnd, "", 1, 24},
{itemEOF, "", 1, 0},
}
lx = lex("foo {include users.conf}")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemMapStart, "", 1, 5},
{itemInclude, "users.conf", 1, 15},
{itemMapEnd, "", 1, 28},
{itemEOF, "", 1, 0},
}
lx = lex("foo { include 'users.conf' }")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1, 0},
{itemMapStart, "", 1, 5},
{itemInclude, "users.conf", 1, 15},
{itemMapEnd, "", 1, 27},
{itemEOF, "", 1, 0},
}
lx = lex("foo { include \"users.conf\"}")
expect(t, lx, expectedItems)
}
func TestJSONCompat(t *testing.T) {
for _, test := range []struct {
name string
input string
expected []item
}{
{
name: "should omit initial and final brackets at top level with a single item",
input: `
{
"http_port": 8223
}
`,
expected: []item{
{itemKey, "http_port", 3, 28},
{itemInteger, "8223", 3, 40},
},
},
{
name: "should omit trailing commas at top level with two items",
input: `
{
"http_port": 8223,
"port": 4223
}
`,
expected: []item{
{itemKey, "http_port", 3, 28},
{itemInteger, "8223", 3, 40},
{itemKey, "port", 4, 28},
{itemInteger, "4223", 4, 35},
},
},
{
name: "should omit trailing commas at top level with multiple items",
input: `
{
"http_port": 8223,
"port": 4223,
"max_payload": "5MB",
"debug": true,
"max_control_line": 1024
}
`,
expected: []item{
{itemKey, "http_port", 3, 28},
{itemInteger, "8223", 3, 40},
{itemKey, "port", 4, 28},
{itemInteger, "4223", 4, 35},
{itemKey, "max_payload", 5, 28},
{itemString, "5MB", 5, 43},
{itemKey, "debug", 6, 28},
{itemBool, "true", 6, 36},
{itemKey, "max_control_line", 7, 28},
{itemInteger, "1024", 7, 47},
},
},
{
name: "should support JSON not prettified",
input: `{"http_port": 8224,"port": 4224}
`,
expected: []item{
{itemKey, "http_port", 1, 2},
{itemInteger, "8224", 1, 14},
{itemKey, "port", 1, 20},
{itemInteger, "4224", 1, 27},
},
},
{
name: "should support JSON not prettified with final bracket after newline",
input: `{"http_port": 8225,"port": 4225
}
`,
expected: []item{
{itemKey, "http_port", 1, 2},
{itemInteger, "8225", 1, 14},
{itemKey, "port", 1, 20},
{itemInteger, "4225", 1, 27},
},
},
{
name: "should support uglified JSON with inner blocks",
input: `{"http_port": 8227,"port": 4227,"write_deadline": "1h","cluster": {"port": 6222,"routes": ["nats://127.0.0.1:4222","nats://127.0.0.1:4223","nats://127.0.0.1:4224"]}}
`,
expected: []item{
{itemKey, "http_port", 1, 2},
{itemInteger, "8227", 1, 14},
{itemKey, "port", 1, 20},
{itemInteger, "4227", 1, 27},
{itemKey, "write_deadline", 1, 33},
{itemString, "1h", 1, 51},
{itemKey, "cluster", 1, 56},
{itemMapStart, "", 1, 67},
{itemKey, "port", 1, 68},
{itemInteger, "6222", 1, 75},
{itemKey, "routes", 1, 81},
{itemArrayStart, "", 1, 91},
{itemString, "nats://127.0.0.1:4222", 1, 92},
{itemString, "nats://127.0.0.1:4223", 1, 116},
{itemString, "nats://127.0.0.1:4224", 1, 140},
{itemArrayEnd, "", 1, 163},
{itemMapEnd, "", 1, 164},
},
},
{
name: "should support prettified JSON with inner blocks",
input: `
{
"http_port": 8227,
"port": 4227,
"write_deadline": "1h",
"cluster": {
"port": 6222,
"routes": [
"nats://127.0.0.1:4222",
"nats://127.0.0.1:4223",
"nats://127.0.0.1:4224"
]
}
}
`,
expected: []item{
{itemKey, "http_port", 3, 28},
{itemInteger, "8227", 3, 40},
{itemKey, "port", 4, 28},
{itemInteger, "4227", 4, 35},
{itemKey, "write_deadline", 5, 28},
{itemString, "1h", 5, 46},
{itemKey, "cluster", 6, 28},
{itemMapStart, "", 6, 39},
{itemKey, "port", 7, 30},
{itemInteger, "6222", 7, 37},
{itemKey, "routes", 8, 30},
{itemArrayStart, "", 8, 40},
{itemString, "nats://127.0.0.1:4222", 9, 32},
{itemString, "nats://127.0.0.1:4223", 10, 32},
{itemString, "nats://127.0.0.1:4224", 11, 32},
{itemArrayEnd, "", 12, 30},
{itemMapEnd, "", 13, 28},
},
},
} {
t.Run(test.name, func(t *testing.T) {
lx := lex(test.input)
expect(t, lx, test.expected)
})
}
}