Files
nats-server/conf/lex_test.go
Waldemar Quevedo c45d2f5b8b Improve compatibility with JSON in config parser
The configuration format from the server is almost already a superset
of JSON with exception of two cases:

1) trailing commas from values at the top level (although they are
   supported inside of maps)

2) initial and final brackets on the top level section.

This change relaxes the two cases above to just skip those tokens so
that the config syntax can also support valid JSON objects for
configuring the server which might be helpful when generating it
programmatically.
2018-03-21 01:03:41 -07:00

1201 lines
26 KiB
Go

package conf
import "testing"
// Test to make sure we get what we expect.
func expect(t *testing.T, lx *lexer, items []item) {
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},
{itemEOF, "", 1},
}
lx := lex("foo")
expect(t, lx, expectedItems)
}
func TestSimpleKeyStringValues(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemString, "bar", 1},
{itemEOF, "", 1},
}
// Double quotes
lx := lex("foo = \"bar\"")
expect(t, lx, expectedItems)
// Single quotes
lx = lex("foo = 'bar'")
expect(t, lx, expectedItems)
// No spaces
lx = lex("foo='bar'")
expect(t, lx, expectedItems)
// NL
lx = lex("foo='bar'\r\n")
expect(t, lx, expectedItems)
lx = lex("foo=\t'bar'\t")
expect(t, lx, expectedItems)
}
func TestComplexStringValues(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemString, "bar\\r\\n \\t", 1},
{itemEOF, "", 2},
}
lx := lex("foo = 'bar\\r\\n \\t'")
expect(t, lx, expectedItems)
}
func TestBinaryString(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemString, "e", 1},
{itemEOF, "", 1},
}
lx := lex("foo = \\x65")
expect(t, lx, expectedItems)
}
func TestBinaryStringLatin1(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemString, "\xe9", 1},
{itemEOF, "", 1},
}
lx := lex("foo = \\xe9")
expect(t, lx, expectedItems)
}
func TestSimpleKeyIntegerValues(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemInteger, "123", 1},
{itemEOF, "", 1},
}
lx := lex("foo = 123")
expect(t, lx, expectedItems)
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},
{itemInteger, "-123", 1},
{itemEOF, "", 1},
}
lx := lex("foo = -123")
expect(t, lx, expectedItems)
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},
{itemInteger, "1k", 1},
{itemEOF, "", 1},
}
lx := lex("foo = 1k")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1},
{itemInteger, "1K", 1},
{itemEOF, "", 1},
}
lx = lex("foo = 1K")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1},
{itemInteger, "1m", 1},
{itemEOF, "", 1},
}
lx = lex("foo = 1m")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1},
{itemInteger, "1M", 1},
{itemEOF, "", 1},
}
lx = lex("foo = 1M")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1},
{itemInteger, "1g", 1},
{itemEOF, "", 1},
}
lx = lex("foo = 1g")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1},
{itemInteger, "1G", 1},
{itemEOF, "", 1},
}
lx = lex("foo = 1G")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1},
{itemInteger, "1MB", 1},
{itemEOF, "", 1},
}
lx = lex("foo = 1MB")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1},
{itemInteger, "1Gb", 1},
{itemEOF, "", 1},
}
lx = lex("foo = 1Gb")
expect(t, lx, expectedItems)
// Negative versions
expectedItems = []item{
{itemKey, "foo", 1},
{itemInteger, "-1m", 1},
{itemEOF, "", 1},
}
lx = lex("foo = -1m")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "foo", 1},
{itemInteger, "-1GB", 1},
{itemEOF, "", 1},
}
lx = lex("foo = -1GB ")
expect(t, lx, expectedItems)
}
func TestSimpleKeyFloatValues(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemFloat, "22.2", 1},
{itemEOF, "", 1},
}
lx := lex("foo = 22.2")
expect(t, lx, expectedItems)
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},
{itemError, "Expected two hexadecimal digits after '\\x', but hit end of line", 2},
{itemEOF, "", 1},
}
lx := lex("foo = xyz\\x\n")
expect(t, lx, expectedItems)
}
func TestBadBinaryStringEndingAfterOneHexChar(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemError, "Expected two hexadecimal digits after '\\x', but hit end of line", 2},
{itemEOF, "", 1},
}
lx := lex("foo = xyz\\xF\n")
expect(t, lx, expectedItems)
}
func TestBadBinaryStringWithZeroHexChars(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemError, "Expected two hexadecimal digits after '\\x', but got ']\"'", 1},
{itemEOF, "", 1},
}
lx := lex(`foo = "[\x]"`)
expect(t, lx, expectedItems)
}
func TestBadBinaryStringWithOneHexChar(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemError, "Expected two hexadecimal digits after '\\x', but got 'e]'", 1},
{itemEOF, "", 1},
}
lx := lex(`foo = "[\xe]"`)
expect(t, lx, expectedItems)
}
func TestBadFloatValues(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemError, "Floats must start with a digit", 1},
{itemEOF, "", 1},
}
lx := lex("foo = .2")
expect(t, lx, expectedItems)
}
func TestBadKey(t *testing.T) {
expectedItems := []item{
{itemError, "Unexpected key separator ':'", 1},
{itemEOF, "", 1},
}
lx := lex(" :foo = 22")
expect(t, lx, expectedItems)
}
func TestSimpleKeyBoolValues(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemBool, "true", 1},
{itemEOF, "", 1},
}
lx := lex("foo = true")
expect(t, lx, expectedItems)
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},
{itemText, " This is a comment", 1},
{itemEOF, "", 1},
}
lx := lex("# This is a comment")
expect(t, lx, expectedItems)
lx = lex("# This is a comment\r\n")
expect(t, lx, expectedItems)
lx = lex("// This is a comment\r\n")
expect(t, lx, expectedItems)
}
func TestTopValuesWithComments(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemInteger, "123", 1},
{itemCommentStart, "", 1},
{itemText, " This is a comment", 1},
{itemEOF, "", 1},
}
lx := lex("foo = 123 // This is a comment")
expect(t, lx, expectedItems)
lx = lex("foo=123 # This is a comment")
expect(t, lx, expectedItems)
}
func TestRawString(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemString, "bar", 1},
{itemEOF, "", 1},
}
lx := lex("foo = bar")
expect(t, lx, expectedItems)
lx = lex(`foo = bar' `) //'single-quote for emacs TODO: Remove me
expect(t, lx, expectedItems)
}
func TestDateValues(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemDatetime, "2016-05-04T18:53:41Z", 1},
{itemEOF, "", 1},
}
lx := lex("foo = 2016-05-04T18:53:41Z")
expect(t, lx, expectedItems)
}
func TestVariableValues(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemVariable, "bar", 1},
{itemEOF, "", 1},
}
lx := lex("foo = $bar")
expect(t, lx, expectedItems)
lx = lex("foo =$bar")
expect(t, lx, expectedItems)
lx = lex("foo $bar")
expect(t, lx, expectedItems)
}
func TestArrays(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemArrayStart, "", 1},
{itemInteger, "1", 1},
{itemInteger, "2", 1},
{itemInteger, "3", 1},
{itemString, "bar", 1},
{itemArrayEnd, "", 1},
{itemEOF, "", 1},
}
lx := lex("foo = [1, 2, 3, 'bar']")
expect(t, lx, expectedItems)
lx = lex("foo = [1,2,3,'bar']")
expect(t, lx, expectedItems)
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},
{itemText, " top level comment", 2},
{itemKey, "foo", 3},
{itemArrayStart, "", 3},
{itemInteger, "1", 4},
{itemCommentStart, "", 4},
{itemText, " One", 4},
{itemInteger, "2", 5},
{itemCommentStart, "", 5},
{itemText, " Two", 5},
{itemInteger, "3", 6},
{itemCommentStart, "", 6},
{itemText, " Three", 6},
{itemString, "bar", 7},
{itemString, "bar", 8},
{itemArrayEnd, "", 9},
{itemEOF, "", 9},
}
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},
{itemText, " top level comment", 2},
{itemKey, "foo", 3},
{itemArrayStart, "", 3},
{itemInteger, "1", 4},
{itemCommentStart, "", 4},
{itemText, " foo", 4},
{itemInteger, "2", 5},
{itemInteger, "3", 6},
{itemString, "bar", 7},
{itemString, "bar", 8},
{itemArrayEnd, "", 9},
{itemEOF, "", 9},
}
lx := lex(mlArrayNoSep)
expect(t, lx, expectedItems)
}
func TestSimpleMap(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemMapStart, "", 1},
{itemKey, "ip", 1},
{itemString, "127.0.0.1", 1},
{itemKey, "port", 1},
{itemInteger, "4242", 1},
{itemMapEnd, "", 1},
{itemEOF, "", 1},
}
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},
{itemMapStart, "", 2},
{itemKey, "ip", 3},
{itemString, "127.0.0.1", 3},
{itemCommentStart, "", 3},
{itemText, " the IP", 3},
{itemKey, "port", 4},
{itemInteger, "4242", 4},
{itemCommentStart, "", 4},
{itemText, " the port", 4},
{itemMapEnd, "", 5},
{itemEOF, "", 5},
}
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},
{itemMapStart, "", 2},
{itemKey, "host", 3},
{itemMapStart, "", 3},
{itemKey, "ip", 4},
{itemString, "127.0.0.1", 4},
{itemKey, "port", 5},
{itemInteger, "4242", 5},
{itemMapEnd, "", 6},
{itemMapEnd, "", 7},
{itemEOF, "", 5},
}
lx := lex(nestedMap)
expect(t, lx, expectedItems)
}
func TestQuotedKeys(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemInteger, "123", 1},
{itemEOF, "", 1},
}
lx := lex("foo : 123")
expect(t, lx, expectedItems)
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},
{itemInteger, "123", 1},
{itemEOF, "", 1},
}
lx := lex("' foo' : 123")
expect(t, lx, expectedItems)
lx = lex("\" foo\" : 123")
expect(t, lx, expectedItems)
}
func TestColonKeySep(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemInteger, "123", 1},
{itemEOF, "", 1},
}
lx := lex("foo : 123")
expect(t, lx, expectedItems)
lx = lex("foo:123")
expect(t, lx, expectedItems)
lx = lex("foo: 123")
expect(t, lx, expectedItems)
lx = lex("foo: 123\r\n")
expect(t, lx, expectedItems)
}
func TestWhitespaceKeySep(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemInteger, "123", 1},
{itemEOF, "", 1},
}
lx := lex("foo 123")
expect(t, lx, expectedItems)
lx = lex("foo 123")
expect(t, lx, expectedItems)
lx = lex("foo\t123")
expect(t, lx, expectedItems)
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},
{itemString, "\t", 2},
{itemKey, "bar", 3},
{itemString, "\r", 3},
{itemKey, "baz", 4},
{itemString, "\n", 4},
{itemKey, "q", 5},
{itemString, "\"", 5},
{itemKey, "bs", 6},
{itemString, "\\", 6},
{itemEOF, "", 6},
}
lx := lex(escString)
expect(t, lx, expectedItems)
}
func TestCompoundStringES(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemString, "\\end", 1},
{itemEOF, "", 2},
}
lx := lex(`foo = "\\end"`)
expect(t, lx, expectedItems)
}
func TestCompoundStringSE(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemString, "start\\", 1},
{itemEOF, "", 2},
}
lx := lex(`foo = "start\\"`)
expect(t, lx, expectedItems)
}
func TestCompoundStringEE(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemString, "Eq", 1},
{itemEOF, "", 2},
}
lx := lex(`foo = \x45\x71`)
expect(t, lx, expectedItems)
}
func TestCompoundStringSEE(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemString, "startEq", 1},
{itemEOF, "", 2},
}
lx := lex(`foo = start\x45\x71`)
expect(t, lx, expectedItems)
}
func TestCompoundStringSES(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemString, "start|end", 1},
{itemEOF, "", 2},
}
lx := lex(`foo = start\x7Cend`)
expect(t, lx, expectedItems)
}
func TestCompoundStringEES(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemString, "<>end", 1},
{itemEOF, "", 2},
}
lx := lex(`foo = \x3c\x3eend`)
expect(t, lx, expectedItems)
}
func TestCompoundStringESE(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemString, "<middle>", 1},
{itemEOF, "", 2},
}
lx := lex(`foo = \x3cmiddle\x3E`)
expect(t, lx, expectedItems)
}
func TestBadStringEscape(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemError, "Invalid escape character 'y'. Only the following escape characters are allowed: \\xXX, \\t, \\n, \\r, \\\", \\\\.", 1},
{itemEOF, "", 2},
}
lx := lex(`foo = \y`)
expect(t, lx, expectedItems)
}
func TestNonBool(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemString, "\\true", 1},
{itemEOF, "", 2},
}
lx := lex(`foo = \\true`)
expect(t, lx, expectedItems)
}
func TestNonVariable(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemString, "\\$var", 1},
{itemEOF, "", 2},
}
lx := lex(`foo = \\$var`)
expect(t, lx, expectedItems)
}
func TestEmptyStringDQ(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemString, "", 1},
{itemEOF, "", 2},
}
lx := lex(`foo = ""`)
expect(t, lx, expectedItems)
}
func TestEmptyStringSQ(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemString, "", 1},
{itemEOF, "", 2},
}
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},
{itemMapStart, "", 2},
{itemKey, "host", 3},
{itemMapStart, "", 3},
{itemKey, "ip", 4},
{itemString, "127.0.0.1", 4},
{itemKey, "port", 5},
{itemInteger, "4242", 5},
{itemMapEnd, "", 6},
{itemMapEnd, "", 7},
{itemEOF, "", 5},
}
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},
{itemInteger, "123", 2},
{itemKey, "bar", 3},
{itemString, "baz", 3},
{itemKey, "baz", 4},
{itemString, "boo", 4},
{itemKey, "map", 5},
{itemMapStart, "", 5},
{itemKey, "id", 6},
{itemInteger, "1", 6},
{itemMapEnd, "", 7},
{itemEOF, "", 5},
}
lx := lex(semicolons)
expect(t, lx, expectedItems)
}
func TestSemicolonChaining(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemString, "1", 1},
{itemKey, "bar", 1},
{itemFloat, "2.2", 1},
{itemKey, "baz", 1},
{itemBool, "true", 1},
{itemEOF, "", 1},
}
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},
{itemInteger, "123", 2},
{itemKey, "bar", 3},
{itemString, "baz", 3},
{itemKey, "baz", 4},
{itemString, "boo", 4},
{itemKey, "map", 5},
{itemMapStart, "", 5},
{itemKey, "id", 6},
{itemString, "one", 6},
{itemKey, "id2", 7},
{itemString, "onetwo", 7},
{itemMapEnd, "", 8},
{itemKey, "t", 9},
{itemBool, "true", 9},
{itemKey, "f", 10},
{itemBool, "false", 10},
{itemKey, "tstr", 11},
{itemString, "true", 11},
{itemKey, "tkey", 12},
{itemString, "two", 12},
{itemKey, "fkey", 13},
{itemString, "five", 13},
{itemCommentStart, "", 13},
{itemText, " This should be a string", 13},
{itemEOF, "", 14},
}
lx := lex(noquotes)
expect(t, lx, expectedItems)
}
func TestMapQuotedKeys(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemMapStart, "", 1},
{itemKey, "bar", 1},
{itemInteger, "4242", 1},
{itemMapEnd, "", 1},
{itemEOF, "", 1},
}
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},
{itemMapStart, "", 1},
{itemKey, "bar-1.2.3", 1},
{itemMapStart, "", 1},
{itemKey, "port", 1},
{itemInteger, "4242", 1},
{itemMapEnd, "", 1},
{itemMapEnd, "", 1},
{itemEOF, "", 1},
}
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},
{itemMapStart, "", 2},
{itemKey, "allinone", 3},
{itemMapStart, "", 3},
{itemKey, "description", 4},
{itemString, "This is a description.", 4},
{itemMapEnd, "", 5},
{itemMapEnd, "", 6},
{itemEOF, "", 7},
}
lx := lex(mlnestedmap)
expect(t, lx, expectedItems)
}
var blockexample = `
numbers (
1234567890
)
`
func TestBlockString(t *testing.T) {
expectedItems := []item{
{itemKey, "numbers", 2},
{itemString, "\n1234567890\n", 4},
}
lx := lex(blockexample)
expect(t, lx, expectedItems)
}
func TestBlockStringEOF(t *testing.T) {
expectedItems := []item{
{itemKey, "numbers", 2},
{itemString, "\n1234567890\n", 4},
}
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},
{itemString, "\n 12(34)56\n (\n 7890\n )\n", 7},
}
lx := lex(mlblockexample)
expect(t, lx, expectedItems)
}
func TestUnquotedIPAddr(t *testing.T) {
expectedItems := []item{
{itemKey, "listen", 1},
{itemString, "127.0.0.1:4222", 1},
{itemEOF, "", 1},
}
lx := lex("listen: 127.0.0.1:4222")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "listen", 1},
{itemString, "127.0.0.1", 1},
{itemEOF, "", 1},
}
lx = lex("listen: 127.0.0.1")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "listen", 1},
{itemString, "apcera.me:80", 1},
{itemEOF, "", 1},
}
lx = lex("listen: apcera.me:80")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "listen", 1},
{itemString, ":80", 1},
{itemEOF, "", 1},
}
lx = lex("listen = :80")
expect(t, lx, expectedItems)
expectedItems = []item{
{itemKey, "listen", 1},
{itemArrayStart, "", 1},
{itemString, "localhost:4222", 1},
{itemString, "localhost:4333", 1},
{itemArrayEnd, "", 1},
{itemEOF, "", 1},
}
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},
{itemMapStart, "", 2},
{itemKey, "users", 3},
{itemArrayStart, "", 3},
{itemMapStart, "", 4},
{itemKey, "user", 4},
{itemString, "alice", 4},
{itemKey, "password", 4},
{itemString, "foo", 4},
{itemMapEnd, "", 4},
{itemMapStart, "", 5},
{itemKey, "user", 5},
{itemString, "bob", 5},
{itemKey, "password", 5},
{itemString, "bar", 5},
{itemMapEnd, "", 5},
{itemArrayEnd, "", 6},
{itemKey, "timeout", 7},
{itemFloat, "0.5", 7},
{itemMapEnd, "", 8},
{itemEOF, "", 9},
}
lx := lex(arrayOfMaps)
expect(t, lx, expectedItems)
}
func TestInclude(t *testing.T) {
expectedItems := []item{
{itemInclude, "users.conf", 1},
{itemEOF, "", 1},
}
lx := lex("include \"users.conf\"")
expect(t, lx, expectedItems)
lx = lex("include 'users.conf'")
expect(t, lx, expectedItems)
lx = lex("include users.conf")
expect(t, lx, expectedItems)
}
func TestMapInclude(t *testing.T) {
expectedItems := []item{
{itemKey, "foo", 1},
{itemMapStart, "", 1},
{itemInclude, "users.conf", 1},
{itemMapEnd, "", 1},
{itemEOF, "", 1},
}
lx := lex("foo { include users.conf }")
expect(t, lx, expectedItems)
lx = lex("foo {include users.conf}")
expect(t, lx, expectedItems)
lx = lex("foo { include 'users.conf' }")
expect(t, lx, expectedItems)
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},
{itemInteger, "8223", 3},
},
},
{
name: "should omit trailing commas at top level with two items",
input: `
{
"http_port": 8223,
"port": 4223
}
`,
expected: []item{
{itemKey, "http_port", 3},
{itemInteger, "8223", 3},
{itemKey, "port", 4},
{itemInteger, "4223", 4},
},
},
{
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},
{itemInteger, "8223", 3},
{itemKey, "port", 4},
{itemInteger, "4223", 4},
{itemKey, "max_payload", 5},
{itemString, "5MB", 5},
{itemKey, "debug", 6},
{itemBool, "true", 6},
{itemKey, "max_control_line", 7},
{itemInteger, "1024", 7},
},
},
{
name: "should support JSON not prettified",
input: `{"http_port": 8224,"port": 4224}
`,
expected: []item{
{itemKey, "http_port", 1},
{itemInteger, "8224", 1},
{itemKey, "port", 1},
{itemInteger, "4224", 1},
},
},
{
name: "should support JSON not prettified with final bracket after newline",
input: `{"http_port": 8225,"port": 4225
}
`,
expected: []item{
{itemKey, "http_port", 1},
{itemInteger, "8225", 1},
{itemKey, "port", 1},
{itemInteger, "4225", 1},
},
},
{
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},
{itemInteger, "8227", 1},
{itemKey, "port", 1},
{itemInteger, "4227", 1},
{itemKey, "write_deadline", 1},
{itemString, "1h", 1},
{itemKey, "cluster", 1},
{itemMapStart, "", 1},
{itemKey, "port", 1},
{itemInteger, "6222", 1},
{itemKey, "routes", 1},
{itemArrayStart, "", 1},
{itemString, "nats://127.0.0.1:4222", 1},
{itemString, "nats://127.0.0.1:4223", 1},
{itemString, "nats://127.0.0.1:4224", 1},
{itemArrayEnd, "", 1},
{itemMapEnd, "", 1},
},
},
{
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},
{itemInteger, "8227", 3},
{itemKey, "port", 4},
{itemInteger, "4227", 4},
{itemKey, "write_deadline", 5},
{itemString, "1h", 5},
{itemKey, "cluster", 6},
{itemMapStart, "", 6},
{itemKey, "port", 7},
{itemInteger, "6222", 7},
{itemKey, "routes", 8},
{itemArrayStart, "", 8},
{itemString, "nats://127.0.0.1:4222", 9},
{itemString, "nats://127.0.0.1:4223", 10},
{itemString, "nats://127.0.0.1:4224", 11},
{itemArrayEnd, "", 12},
{itemMapEnd, "", 13},
},
},
} {
t.Run(test.name, func(t *testing.T) {
lx := lex(test.input)
expect(t, lx, test.expected)
})
}
}