mirror of
https://github.com/lightbend/config.git
synced 2025-02-16 06:10:31 +08:00
Merge pull request #304 from fpringvaldsen/task/update-configdocumentparser
Update ConfigDocumentParser and various tests
This commit is contained in:
commit
20dd869b51
@ -15,7 +15,8 @@ final class ConfigDocumentParser {
|
||||
}
|
||||
|
||||
static AbstractConfigNodeValue parseValue(Iterator<Token> tokens, ConfigOrigin origin, ConfigParseOptions options) {
|
||||
ParseContext context = new ParseContext(options.getSyntax(), origin, tokens);
|
||||
ConfigSyntax syntax = options.getSyntax() == null ? ConfigSyntax.CONF : options.getSyntax();
|
||||
ParseContext context = new ParseContext(syntax, origin, tokens);
|
||||
return context.parseSingleValue();
|
||||
}
|
||||
|
||||
@ -171,7 +172,7 @@ final class ConfigDocumentParser {
|
||||
for (AbstractConfigNode node : values) {
|
||||
if (node instanceof AbstractConfigNodeValue)
|
||||
value = (AbstractConfigNodeValue)node;
|
||||
else if (node == null)
|
||||
else if (value == null)
|
||||
nodes.add(node);
|
||||
else
|
||||
putBack((new ArrayList<Token>(node.tokens())).get(0));
|
||||
@ -183,7 +184,7 @@ final class ConfigDocumentParser {
|
||||
// any leading/trailing whitespace
|
||||
for (int i = values.size() - 1; i >= 0; i--) {
|
||||
if (values.get(i) instanceof ConfigNodeSingleToken) {
|
||||
putBack((new ArrayList<Token>(values.get(i).tokens())).get(0));
|
||||
putBack(((ConfigNodeSingleToken) values.get(i)).token());
|
||||
values.remove(i);
|
||||
} else {
|
||||
break;
|
||||
@ -497,7 +498,6 @@ final class ConfigDocumentParser {
|
||||
AbstractConfigNodeValue nextValue = consolidateValues(children);
|
||||
if (nextValue != null) {
|
||||
children.add(nextValue);
|
||||
nextValue = null;
|
||||
} else {
|
||||
t = nextTokenCollectingWhitespace(children);
|
||||
|
||||
@ -510,7 +510,6 @@ final class ConfigDocumentParser {
|
||||
|| Tokens.isSubstitution(t)) {
|
||||
nextValue = parseValue(t);
|
||||
children.add(nextValue);
|
||||
nextValue = null;
|
||||
} else {
|
||||
throw parseError("List should have ] or a first element after the open [, instead had token: "
|
||||
+ t
|
||||
@ -543,7 +542,6 @@ final class ConfigDocumentParser {
|
||||
nextValue = consolidateValues(children);
|
||||
if (nextValue != null) {
|
||||
children.add(nextValue);
|
||||
nextValue = null;
|
||||
} else {
|
||||
t = nextTokenCollectingWhitespace(children);
|
||||
if (Tokens.isValue(t) || t == Tokens.OPEN_CURLY
|
||||
@ -551,7 +549,6 @@ final class ConfigDocumentParser {
|
||||
|| Tokens.isSubstitution(t)) {
|
||||
nextValue = parseValue(t);
|
||||
children.add(nextValue);
|
||||
nextValue = null;
|
||||
} else if (flavor != ConfigSyntax.JSON && t == Tokens.CLOSE_SQUARE) {
|
||||
// we allow one trailing comma
|
||||
putBack(t);
|
||||
|
@ -13,65 +13,48 @@ class ConfigDocumentParserTest extends TestUtils {
|
||||
|
||||
private def parseJSONFailuresTest(origText: String, containsMessage: String) {
|
||||
var exceptionThrown = false
|
||||
try {
|
||||
val e = intercept[ConfigException] {
|
||||
ConfigDocumentParser.parse(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON))
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
exceptionThrown = true
|
||||
assertTrue(e.isInstanceOf[ConfigException])
|
||||
assertTrue(e.getMessage.contains(containsMessage))
|
||||
}
|
||||
assertTrue(exceptionThrown)
|
||||
assertTrue(e.getMessage.contains(containsMessage))
|
||||
}
|
||||
|
||||
private def parseSimpleValueTest(origText: String, finalText: String = null) {
|
||||
val expectedRenderedText = if (finalText == null) origText else finalText
|
||||
val node = ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults())
|
||||
assertEquals(expectedRenderedText, node.render())
|
||||
assertTrue(node.isInstanceOf[AbstractConfigNodeValue])
|
||||
assertTrue(node.isInstanceOf[ConfigNodeSimpleValue])
|
||||
|
||||
val nodeJSON = ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON))
|
||||
assertEquals(expectedRenderedText, nodeJSON.render())
|
||||
assertTrue(nodeJSON.isInstanceOf[AbstractConfigNodeValue])
|
||||
assertTrue(nodeJSON.isInstanceOf[ConfigNodeSimpleValue])
|
||||
}
|
||||
|
||||
private def parseComplexValueTest(origText: String) {
|
||||
val node = ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults())
|
||||
assertEquals(origText, node.render())
|
||||
assertTrue(node.isInstanceOf[AbstractConfigNodeValue])
|
||||
assertTrue(node.isInstanceOf[ConfigNodeComplexValue])
|
||||
|
||||
val nodeJSON = ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON))
|
||||
assertEquals(origText, nodeJSON.render())
|
||||
assertTrue(nodeJSON.isInstanceOf[AbstractConfigNodeValue])
|
||||
assertTrue(nodeJSON.isInstanceOf[ConfigNodeComplexValue])
|
||||
}
|
||||
|
||||
private def parseSingleValueInvalidJSONTest(origText: String, containsMessage: String) {
|
||||
val node = ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults())
|
||||
assertEquals(origText, node.render())
|
||||
|
||||
var exceptionThrown = false
|
||||
try {
|
||||
ConfigDocumentParser.parse(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON))
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
exceptionThrown = true
|
||||
assertTrue(e.isInstanceOf[ConfigException])
|
||||
assertTrue(e.getMessage.contains(containsMessage))
|
||||
val e = intercept[ConfigException] {
|
||||
ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON))
|
||||
}
|
||||
assertTrue(exceptionThrown)
|
||||
assertTrue(e.getMessage.contains(containsMessage))
|
||||
}
|
||||
|
||||
private def parseLeadingTrailingFailure(toReplace: String) {
|
||||
var exceptionThrown = false
|
||||
try {
|
||||
val e = intercept[ConfigException] {
|
||||
ConfigDocumentParser.parseValue(tokenize(toReplace), fakeOrigin(), ConfigParseOptions.defaults())
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
exceptionThrown = true
|
||||
assertTrue(e.isInstanceOf[ConfigException])
|
||||
assertTrue(e.getMessage.contains("The value from setValue cannot have leading or trailing newlines, whitespace, or comments"))
|
||||
}
|
||||
assertTrue(exceptionThrown)
|
||||
assertTrue(e.getMessage.contains("The value from setValue cannot have leading or trailing newlines, whitespace, or comments"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -212,7 +195,7 @@ class ConfigDocumentParserTest extends TestUtils {
|
||||
parseJSONFailuresTest("""{ "foo": 123 456 789 } """, "Expecting close brace } or a comma")
|
||||
|
||||
// JSON must begin with { or [
|
||||
parseJSONFailuresTest(""""a": 123, "b": 456"""", "Document must have an object or array at root")
|
||||
parseJSONFailuresTest(""""a": 123, "b": 456""", "Document must have an object or array at root")
|
||||
|
||||
// JSON does not support unquoted text
|
||||
parseJSONFailuresTest("""{"foo": unquotedtext}""", "Token not allowed in valid JSON")
|
||||
@ -255,22 +238,14 @@ class ConfigDocumentParserTest extends TestUtils {
|
||||
parseComplexValueTest("""["a","b","c"]""")
|
||||
|
||||
// Check that concatenations are handled by CONF parsing
|
||||
var origText = "123 456 unquotedtext abc"
|
||||
var origText = "123 456 \"abc\""
|
||||
var node = ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults())
|
||||
assertEquals(origText, node.render())
|
||||
|
||||
// Check that concatenations in JSON will throw an error
|
||||
origText = "123 456 789"
|
||||
var exceptionThrown = false
|
||||
try {
|
||||
node = ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON))
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
exceptionThrown = true
|
||||
assertTrue(e.isInstanceOf[ConfigException])
|
||||
assertTrue(e.getMessage.contains("Parsing JSON and the value set in setValue was either a concatenation or had trailing whitespace, newlines, or comments"))
|
||||
}
|
||||
assertTrue(exceptionThrown)
|
||||
// Check that keys with no separators and object values are handled by CONF parsing
|
||||
origText = """{"foo" { "bar" : 12 } }"""
|
||||
node = ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults())
|
||||
assertEquals(origText, node.render())
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -291,17 +266,14 @@ class ConfigDocumentParserTest extends TestUtils {
|
||||
parseSingleValueInvalidJSONTest("${a.b}", "Substitutions (${} syntax) not allowed in JSON")
|
||||
|
||||
// Check that concatenations in JSON will throw an error
|
||||
val origText = "123 456 789"
|
||||
var exceptionThrown = false
|
||||
try {
|
||||
val node = ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON))
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
exceptionThrown = true
|
||||
assertTrue(e.isInstanceOf[ConfigException])
|
||||
assertTrue(e.getMessage.contains("Parsing JSON and the value set in setValue was either a concatenation or had trailing whitespace, newlines, or comments"))
|
||||
}
|
||||
assertTrue(exceptionThrown)
|
||||
var origText = "123 456 \"abc\""
|
||||
var e = intercept[ConfigException] { ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON)) }
|
||||
assertTrue(e.getMessage.contains("Parsing JSON and the value set in setValue was either a concatenation or had trailing whitespace, newlines, or comments"))
|
||||
|
||||
// Check that keys with no separators and object values in JSON will throw an error
|
||||
origText = """{"foo" { "bar" : 12 } }"""
|
||||
e = intercept[ConfigException] { ConfigDocumentParser.parseValue(tokenize(origText), fakeOrigin(), ConfigParseOptions.defaults().setSyntax((ConfigSyntax.JSON))) }
|
||||
assertTrue(e.getMessage.contains("""Key '"foo"' may not be followed by token: '{'"""))
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -252,7 +252,7 @@ class ConfigDocumentTest extends TestUtils {
|
||||
|
||||
@Test
|
||||
def configDocumentArrayFailures {
|
||||
// Attempting a replace on a ConfigDocument parsed from an array throws an error
|
||||
// Attempting certain methods on a ConfigDocument parsed from an array throws an error
|
||||
val origText = "[1, 2, 3, 4, 5]"
|
||||
val document = ConfigDocumentFactory.parseString(origText)
|
||||
|
||||
@ -272,16 +272,9 @@ class ConfigDocumentTest extends TestUtils {
|
||||
// will fail
|
||||
val origText = "{\"foo\": \"bar\", \"baz\": \"qux\"}"
|
||||
val document = ConfigDocumentFactory.parseString(origText, ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON))
|
||||
var exceptionThrown = false
|
||||
try {
|
||||
document.setValue("foo", "unquoted")
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
exceptionThrown = true
|
||||
assertTrue(e.isInstanceOf[ConfigException])
|
||||
assertTrue(e.getMessage.contains("Token not allowed in valid JSON"))
|
||||
}
|
||||
assertTrue(exceptionThrown)
|
||||
|
||||
val e = intercept[ConfigException] { document.setValue("foo", "unquoted") }
|
||||
assertTrue(e.getMessage.contains("Token not allowed in valid JSON"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -290,16 +283,9 @@ class ConfigDocumentTest extends TestUtils {
|
||||
// fail
|
||||
val origText = "{\"foo\": \"bar\", \"baz\": \"qux\"}"
|
||||
val document = ConfigDocumentFactory.parseString(origText, ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON))
|
||||
var exceptionThrown = false
|
||||
try {
|
||||
document.setValue("foo", "1 2 3 concatenation")
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
exceptionThrown = true
|
||||
assertTrue(e.isInstanceOf[ConfigException])
|
||||
assertTrue(e.getMessage.contains("Parsing JSON and the value set in setValue was either a concatenation or had trailing whitespace, newlines, or comments"))
|
||||
}
|
||||
assertTrue(exceptionThrown)
|
||||
|
||||
val e = intercept[ConfigException] { document.setValue("foo", "1 2 3 concatenation") }
|
||||
assertTrue(e.getMessage.contains("Parsing JSON and the value set in setValue was either a concatenation or had trailing whitespace, newlines, or comments"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -427,7 +413,7 @@ class ConfigDocumentTest extends TestUtils {
|
||||
}
|
||||
|
||||
@Test
|
||||
def configDocumentIndentationValueWithIncludeTest {
|
||||
def configDocumentIndentationValueWithInclude {
|
||||
val origText = "a {\n b {\n c : 22\n }\n}"
|
||||
val configDocument = ConfigDocumentFactory.parseString(origText)
|
||||
|
||||
@ -436,7 +422,7 @@ class ConfigDocumentTest extends TestUtils {
|
||||
}
|
||||
|
||||
@Test
|
||||
def configDocumentIndentationBadedOnIncludeNode {
|
||||
def configDocumentIndentationBasedOnIncludeNode {
|
||||
val origText = "a : b\n include \"foo\"\n"
|
||||
val configDocument = ConfigDocumentFactory.parseString(origText)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user