Fix single-line config bug

Previously, there was a bug wherein building out a config starting
from an empty ConfigDocument would cause the entire config to
exist on a single line. Fix this bug by modifying the addition
of new maps along a path to add multi-line maps instead of
single-line maps if the object is an empty root or if the
object being added to is a multi-line map.
This commit is contained in:
Preben Ingvaldsen 2015-06-29 17:01:29 -07:00
parent d7d0a51776
commit 398406378d
3 changed files with 20 additions and 17 deletions

View File

@ -121,6 +121,9 @@ final class ConfigNodeObject extends ConfigNodeComplexValue {
private Collection<AbstractConfigNode> indentation() {
boolean seenNewLine = false;
ArrayList<AbstractConfigNode> indentation = new ArrayList<AbstractConfigNode>();
if (children.isEmpty()) {
return indentation;
}
for (int i = 0; i < children.size(); i++) {
if (!seenNewLine) {
if (children.get(i) instanceof ConfigNodeSingleToken &&
@ -141,19 +144,18 @@ final class ConfigNodeObject extends ConfigNodeComplexValue {
}
if (indentation.isEmpty()) {
indentation.add(new ConfigNodeSingleToken(Tokens.newIgnoredWhitespace(null, " ")));
return indentation;
} else {
// Calculate the indentation of the ending curly-brace to get the indentation of the root object
AbstractConfigNode last = children.get(children.size() - 1);
if (last instanceof ConfigNodeSingleToken && ((ConfigNodeSingleToken) last).token() == Tokens.CLOSE_CURLY) {
AbstractConfigNode beforeLast = children.get(children.size() - 2);
String indent = "";
if (beforeLast instanceof ConfigNodeSingleToken &&
Tokens.isIgnoredWhitespace(((ConfigNodeSingleToken) beforeLast).token())) {
String indent = ((ConfigNodeSingleToken) beforeLast).token().tokenText();
indent += " ";
indentation.add(new ConfigNodeSingleToken(Tokens.newIgnoredWhitespace(null, indent)));
return indentation;
}
Tokens.isIgnoredWhitespace(((ConfigNodeSingleToken) beforeLast).token()))
indent = ((ConfigNodeSingleToken) beforeLast).token().tokenText();
indent += " ";
indentation.add(new ConfigNodeSingleToken(Tokens.newIgnoredWhitespace(null, indent)));
return indentation;
}
}
@ -173,7 +175,7 @@ final class ConfigNodeObject extends ConfigNodeComplexValue {
} else {
indentedValue = value;
}
boolean sameLine = !(indentation.get(0) instanceof ConfigNodeSingleToken &&
boolean sameLine = !(indentation.size() > 0 && indentation.get(0) instanceof ConfigNodeSingleToken &&
Tokens.isNewline(((ConfigNodeSingleToken) indentation.get(0)).token()));
// If the path is of length greater than one, see if the value needs to be added further down
@ -209,7 +211,10 @@ final class ConfigNodeObject extends ConfigNodeComplexValue {
// If the path is of length greater than one add the required new objects along the path
ArrayList<AbstractConfigNode> newObjectNodes = new ArrayList<AbstractConfigNode>();
newObjectNodes.add(new ConfigNodeSingleToken(Tokens.OPEN_CURLY));
newObjectNodes.add(new ConfigNodeSingleToken(Tokens.newIgnoredWhitespace(null, " ")));
if (indentation.isEmpty()) {
newObjectNodes.add(new ConfigNodeSingleToken(Tokens.newLine(null)));
}
newObjectNodes.addAll(indentation);
newObjectNodes.add(new ConfigNodeSingleToken(Tokens.CLOSE_CURLY));
ConfigNodeObject newObject = new ConfigNodeObject(newObjectNodes);
newNodes.add(newObject.addValueOnPath(desiredPath.subPath(1), indentedValue, flavor));

View File

@ -171,14 +171,14 @@ class ConfigDocumentTest extends TestUtils {
@Test
def configDocumentSetNewValueMultiLevelConf {
val origText = "a:b\nc:d"
val finalText = "a:b\nc:d\ne : { f : { g : 12 } }"
val finalText = "a:b\nc:d\ne : {\n f : {\n g : 12\n }\n}"
configDocumentReplaceConfTest(origText, finalText, "12", "e.f.g")
}
@Test
def configDocumentSetNewValueMultiLevelJson {
val origText = "{\"a\":\"b\",\n\"c\":\"d\"}"
val finalText = "{\"a\":\"b\",\n\"c\":\"d\",\n\"e\" : { \"f\" : { \"g\" : 12 } }}"
val finalText = "{\"a\":\"b\",\n\"c\":\"d\",\n \"e\" : {\n \"f\" : {\n \"g\" : 12\n }\n }}"
configDocumentReplaceJsonTest(origText, finalText, "12", "e.f.g")
}
@ -342,13 +342,13 @@ class ConfigDocumentTest extends TestUtils {
var configDocument = ConfigDocumentFactory.parseString(origText)
assertEquals("a {\n b: c\n e : f\n}", configDocument.withValueText("a.e", "f").render())
assertEquals("a {\n b: c\n d : { e : { f : g } }\n}", configDocument.withValueText("a.d.e.f", "g").render())
assertEquals("a {\n b: c\n d : {\n e : {\n f : g\n }\n }\n}", configDocument.withValueText("a.d.e.f", "g").render())
origText = "a {\n b: c\n}\n"
configDocument = ConfigDocumentFactory.parseString(origText)
assertEquals("a {\n b: c\n}\nd : e\n", configDocument.withValueText("d", "e").render())
assertEquals("a {\n b: c\n}\nd : { e : { f : g } }\n", configDocument.withValueText("d.e.f", "g").render())
assertEquals("a {\n b: c\n}\nd : {\n e : {\n f : g\n }\n}\n", configDocument.withValueText("d.e.f", "g").render())
}
@Test
@ -435,7 +435,7 @@ class ConfigDocumentTest extends TestUtils {
val origText = ""
val configDocument = ConfigDocumentFactory.parseString(origText)
assertEquals(" a : 1", configDocument.withValueText("a", "1").render)
assertEquals("a : 1", configDocument.withValueText("a", "1").render)
}
@Test
@ -447,7 +447,5 @@ class ConfigDocumentTest extends TestUtils {
assertEquals("{ a : {\n # hardcoded value\n \"a\" : 1,\n # hardcoded value\n \"b\" : 2\n } }",
configDocument.withValue("a", configVal).render)
}
}

View File

@ -212,7 +212,7 @@ class ConfigNodeTest extends TestUtils {
nodeCloseBrace))
assertEquals(origText, origNode.render())
val finalText = "foo : bar\nbaz : {\n\t\"abc.def\" : true\n\t//This is a comment about the below setting\n\n\tabc : {\n\t\t" +
"def : false\n\t\t\n\t\t\"this.does.not.exist@@@+$#\" : { end : doesnotexist }\n\t}\n}\n\nbaz.abc.ghi : randomunquotedString\n}"
"def : false\n\t\t\n\t\t\"this.does.not.exist@@@+$#\" : {\n\t\t end : doesnotexist\n\t\t}\n\t}\n}\n\nbaz.abc.ghi : randomunquotedString\n}"
//Can replace settings in nested maps
// Paths with quotes in the name are treated as a single Path, rather than multiple sub-paths