Merge pull request #304 from fpringvaldsen/task/update-configdocumentparser

Update ConfigDocumentParser and various tests
This commit is contained in:
Havoc Pennington 2015-04-08 14:42:25 -04:00
commit 20dd869b51
3 changed files with 38 additions and 83 deletions

View File

@ -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);

View File

@ -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

View File

@ -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)