mirror of
https://github.com/lightbend/config.git
synced 2025-03-17 04:40:41 +08:00
Add ConfigDocument tests
Add ConfigDocument tests that parse a String or a file, ensure that the original text can be rendered, and test value replacement.
This commit is contained in:
parent
c44ef1c6f7
commit
639a3eae5b
38
config/src/main/java/com/typesafe/config/ConfigDocument.java
Normal file
38
config/src/main/java/com/typesafe/config/ConfigDocument.java
Normal file
@ -0,0 +1,38 @@
|
||||
package com.typesafe.config;
|
||||
|
||||
/**
|
||||
* An object parsed from the original input text, which can be used to
|
||||
* replace individual values and exactly render the original text of the
|
||||
* input.
|
||||
*
|
||||
* <p>
|
||||
* Because this object is immutable, it is safe to use from multiple threads and
|
||||
* there's no need for "defensive copies."
|
||||
*
|
||||
* <p>
|
||||
* <em>Do not implement interface {@code ConfigNode}</em>; it should only be
|
||||
* implemented by the config library. Arbitrary implementations will not work
|
||||
* because the library internals assume a specific concrete implementation.
|
||||
* Also, this interface is likely to grow new methods over time, so third-party
|
||||
* implementations will break.
|
||||
*/
|
||||
public interface ConfigDocument {
|
||||
/**
|
||||
* Returns a new ConfigDocument that is a copy of the current ConfigDocument,
|
||||
* but with the desired value set at the desired path. If the path exists, it will
|
||||
* remove all duplicates before the final occurrence of the path, and replace the value
|
||||
* at the final occurrence of the path. If the path does not exist, it will be added.
|
||||
*
|
||||
* @param path the path at which to set the desired value
|
||||
* @param newValue the value to set at the desired path
|
||||
* @return a copy of the ConfigDocument with the desired value at the desired path
|
||||
*/
|
||||
ConfigDocument setValue(String path, String newValue);
|
||||
|
||||
/**
|
||||
* The original text of the input, modified if necessary with
|
||||
* any replaced or added values.
|
||||
* @return the modified original text
|
||||
*/
|
||||
String render();
|
||||
}
|
@ -0,0 +1,63 @@
|
||||
package com.typesafe.config;
|
||||
|
||||
import com.typesafe.config.impl.ConfigImpl;
|
||||
import com.typesafe.config.impl.Parseable;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* Factory for automatically creating a ConfigDocument from a given input. Currently
|
||||
* only supports files and strings.
|
||||
*/
|
||||
public final class ConfigDocumentFactory {
|
||||
|
||||
/**
|
||||
* Parses a file into a ConfigDocument instance.
|
||||
*
|
||||
* @param file
|
||||
* the file to parse
|
||||
* @param options
|
||||
* parse options to control how the file is interpreted
|
||||
* @return the parsed configuration
|
||||
* @throws ConfigException on IO or parse errors
|
||||
*/
|
||||
public static ConfigDocument parseFile(File file, ConfigParseOptions options) {
|
||||
return Parseable.newFile(file, options).parseConfigDocument();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a file into a ConfigDocument instance as with
|
||||
* {@link #parseFile(File,ConfigParseOptions)} but always uses the
|
||||
* default parse options.
|
||||
*
|
||||
* @param file
|
||||
* the file to parse
|
||||
* @return the parsed configuration
|
||||
* @throws ConfigException on IO or parse errors
|
||||
*/
|
||||
public static ConfigDocument parseFile(File file) {
|
||||
return parseFile(file, ConfigParseOptions.defaults());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string which should be valid HOCON or JSON.
|
||||
*
|
||||
* @param s string to parse
|
||||
* @param options parse options
|
||||
* @return the parsed configuration
|
||||
*/
|
||||
public static ConfigDocument parseString(String s, ConfigParseOptions options) {
|
||||
return Parseable.newString(s, options).parseConfigDocument();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a string (which should be valid HOCON or JSON). Uses the
|
||||
* default parse options.
|
||||
*
|
||||
* @param s string to parse
|
||||
* @return the parsed configuration
|
||||
*/
|
||||
public static ConfigDocument parseString(String s) {
|
||||
return parseString(s, ConfigParseOptions.defaults());
|
||||
}
|
||||
}
|
@ -11,16 +11,21 @@ import com.typesafe.config.ConfigSyntax;
|
||||
import com.typesafe.config.ConfigValueType;
|
||||
|
||||
final class ConfigDocumentParser {
|
||||
static AbstractConfigNodeValue parse(Iterator<Token> tokens, ConfigParseOptions options) {
|
||||
static ConfigNodeComplexValue parse(Iterator<Token> tokens, ConfigParseOptions options) {
|
||||
ParseContext context = new ParseContext(options.getSyntax(), tokens);
|
||||
return context.parse();
|
||||
}
|
||||
|
||||
static AbstractConfigNodeValue parse(Iterator<Token> tokens) {
|
||||
static ConfigNodeComplexValue parse(Iterator<Token> tokens) {
|
||||
ParseContext context = new ParseContext(ConfigSyntax.CONF, tokens);
|
||||
return context.parse();
|
||||
}
|
||||
|
||||
static AbstractConfigNodeValue parseValue(Iterator<Token> tokens, ConfigParseOptions options) {
|
||||
ParseContext context = new ParseContext(options.getSyntax(), tokens);
|
||||
return context.parseSingleValue();
|
||||
}
|
||||
|
||||
static private final class ParseContext {
|
||||
private int lineNumber;
|
||||
final private Stack<Token> buffer;
|
||||
@ -625,5 +630,31 @@ final class ConfigDocumentParser {
|
||||
+ t);
|
||||
}
|
||||
}
|
||||
|
||||
// Parse a given input stream into a single value node. Used when doing a replace inside a ConfigDocument.
|
||||
AbstractConfigNodeValue parseSingleValue() {
|
||||
Token t = nextToken();
|
||||
if (t == Tokens.START) {
|
||||
// OK
|
||||
} else {
|
||||
throw new ConfigException.BugOrBroken(
|
||||
"token stream did not begin with START, had " + t);
|
||||
}
|
||||
|
||||
t = nextToken();
|
||||
while (Tokens.isIgnoredWhitespace(t) || Tokens.isNewline(t) || isUnquotedWhitespace(t)) {
|
||||
t = nextToken();
|
||||
}
|
||||
if (t == Tokens.END) {
|
||||
throw parseError("Empty value");
|
||||
}
|
||||
if (flavor == ConfigSyntax.JSON) {
|
||||
return parseValue(t);
|
||||
} else {
|
||||
putBack(t);
|
||||
ArrayList<AbstractConfigNode> nodes = new ArrayList();
|
||||
return consolidateValues(nodes);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,10 @@
|
||||
package com.typesafe.config.impl;
|
||||
|
||||
import com.typesafe.config.ConfigException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
final class ConfigNodeObject extends ConfigNodeComplexValue {
|
||||
ConfigNodeObject(Collection<AbstractConfigNode> children) {
|
||||
@ -47,17 +50,33 @@ final class ConfigNodeObject extends ConfigNodeComplexValue {
|
||||
|
||||
// If the desired Path did not exist, add it
|
||||
if (node.render().equals(render())) {
|
||||
boolean startsWithBrace = super.children.get(0) instanceof ConfigNodeSingleToken &&
|
||||
((ConfigNodeSingleToken) super.children.get(0)).token() == Tokens.OPEN_CURLY;
|
||||
ArrayList<AbstractConfigNode> childrenCopy = new ArrayList<AbstractConfigNode>(super.children);
|
||||
ArrayList<AbstractConfigNode> newNodes = new ArrayList();
|
||||
newNodes.add(new ConfigNodeSingleToken(Tokens.newLine(null)));
|
||||
if (startsWithBrace)
|
||||
newNodes.add(new ConfigNodeSingleToken(Tokens.newIgnoredWhitespace(null, "\t")));
|
||||
newNodes.add(desiredPath);
|
||||
newNodes.add(new ConfigNodeSingleToken(Tokens.newIgnoredWhitespace(null, " ")));
|
||||
newNodes.add(new ConfigNodeSingleToken(Tokens.COLON));
|
||||
newNodes.add(new ConfigNodeSingleToken(Tokens.newIgnoredWhitespace(null, " ")));
|
||||
newNodes.add(value);
|
||||
newNodes.add(new ConfigNodeSingleToken(Tokens.newLine(null)));
|
||||
childrenCopy.add(new ConfigNodeField(newNodes));
|
||||
node = new ConfigNodeObject(childrenCopy);
|
||||
|
||||
if (startsWithBrace) {
|
||||
for (int i = childrenCopy.size() - 1; i >= 0; i--) {
|
||||
if (childrenCopy.get(i) instanceof ConfigNodeSingleToken &&
|
||||
((ConfigNodeSingleToken) childrenCopy.get(i)).token == Tokens.CLOSE_CURLY) {
|
||||
childrenCopy.add(i, new ConfigNodeField(newNodes));
|
||||
return new ConfigNodeObject(childrenCopy);
|
||||
}
|
||||
}
|
||||
throw new ConfigException.BugOrBroken("Object had an opening brace, but no closing brace");
|
||||
} else {
|
||||
childrenCopy.add(new ConfigNodeField(newNodes));
|
||||
node = new ConfigNodeObject(childrenCopy);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
@ -16,4 +16,6 @@ final class ConfigNodeSingleToken extends AbstractConfigNode{
|
||||
protected Collection<Token> tokens() {
|
||||
return Collections.singletonList(token);
|
||||
}
|
||||
|
||||
protected Token token() { return token; }
|
||||
}
|
@ -19,19 +19,9 @@ import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Properties;
|
||||
import java.util.*;
|
||||
|
||||
import com.typesafe.config.ConfigException;
|
||||
import com.typesafe.config.ConfigIncludeContext;
|
||||
import com.typesafe.config.ConfigObject;
|
||||
import com.typesafe.config.ConfigOrigin;
|
||||
import com.typesafe.config.ConfigParseOptions;
|
||||
import com.typesafe.config.ConfigParseable;
|
||||
import com.typesafe.config.ConfigSyntax;
|
||||
import com.typesafe.config.ConfigValue;
|
||||
import com.typesafe.config.*;
|
||||
|
||||
/**
|
||||
* Internal implementation detail, not ABI stable, do not touch.
|
||||
@ -199,6 +189,38 @@ public abstract class Parseable implements ConfigParseable {
|
||||
}
|
||||
}
|
||||
|
||||
final ConfigDocument parseDocument(ConfigParseOptions baseOptions) {
|
||||
// note that we are NOT using our "initialOptions",
|
||||
// but using the ones from the passed-in options. The idea is that
|
||||
// callers can get our original options and then parse with different
|
||||
// ones if they want.
|
||||
ConfigParseOptions options = fixupOptions(baseOptions);
|
||||
|
||||
// passed-in options can override origin
|
||||
ConfigOrigin origin;
|
||||
if (options.getOriginDescription() != null)
|
||||
origin = SimpleConfigOrigin.newSimple(options.getOriginDescription());
|
||||
else
|
||||
origin = initialOrigin;
|
||||
return parseDocument(origin, options);
|
||||
}
|
||||
|
||||
final private ConfigDocument parseDocument(ConfigOrigin origin,
|
||||
ConfigParseOptions finalOptions) {
|
||||
try {
|
||||
return rawParseDocument(origin, finalOptions);
|
||||
} catch (IOException e) {
|
||||
if (finalOptions.getAllowMissing()) {
|
||||
return new SimpleConfigDocument(new ConfigNodeObject(new ArrayList<AbstractConfigNode>()), finalOptions);
|
||||
} else {
|
||||
trace("exception loading " + origin.description() + ": " + e.getClass().getName()
|
||||
+ ": " + e.getMessage());
|
||||
throw new ConfigException.IO(origin,
|
||||
e.getClass().getName() + ": " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// this is parseValue without post-processing the IOException or handling
|
||||
// options.getAllowMissing()
|
||||
protected AbstractConfigValue rawParseValue(ConfigOrigin origin, ConfigParseOptions finalOptions)
|
||||
@ -236,10 +258,47 @@ public abstract class Parseable implements ConfigParseable {
|
||||
}
|
||||
}
|
||||
|
||||
// this is parseValue without post-processing the IOException or handling
|
||||
// options.getAllowMissing()
|
||||
protected ConfigDocument rawParseDocument(ConfigOrigin origin, ConfigParseOptions finalOptions)
|
||||
throws IOException {
|
||||
Reader reader = reader(finalOptions);
|
||||
|
||||
// after reader() we will have loaded the Content-Type.
|
||||
ConfigSyntax contentType = contentType();
|
||||
|
||||
ConfigParseOptions optionsWithContentType;
|
||||
if (contentType != null) {
|
||||
if (ConfigImpl.traceLoadsEnabled() && finalOptions.getSyntax() != null)
|
||||
trace("Overriding syntax " + finalOptions.getSyntax()
|
||||
+ " with Content-Type which specified " + contentType);
|
||||
|
||||
optionsWithContentType = finalOptions.setSyntax(contentType);
|
||||
} else {
|
||||
optionsWithContentType = finalOptions;
|
||||
}
|
||||
|
||||
try {
|
||||
return rawParseDocument(reader, origin, optionsWithContentType);
|
||||
} finally {
|
||||
reader.close();
|
||||
}
|
||||
}
|
||||
|
||||
private ConfigDocument rawParseDocument(Reader reader, ConfigOrigin origin,
|
||||
ConfigParseOptions finalOptions) throws IOException {
|
||||
Iterator<Token> tokens = Tokenizer.tokenize(origin, reader, finalOptions.getSyntax());
|
||||
return new SimpleConfigDocument(ConfigDocumentParser.parse(tokens, finalOptions), finalOptions);
|
||||
}
|
||||
|
||||
public ConfigObject parse() {
|
||||
return forceParsedToObject(parseValue(options()));
|
||||
}
|
||||
|
||||
public ConfigDocument parseConfigDocument() {
|
||||
return parseDocument(options());
|
||||
}
|
||||
|
||||
AbstractConfigValue parseValue() {
|
||||
return parseValue(options());
|
||||
}
|
||||
|
@ -0,0 +1,36 @@
|
||||
package com.typesafe.config.impl;
|
||||
|
||||
import com.typesafe.config.ConfigDocument;
|
||||
import com.typesafe.config.ConfigException;
|
||||
import com.typesafe.config.ConfigParseOptions;
|
||||
import com.typesafe.config.ConfigValue;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.Iterator;
|
||||
|
||||
final class SimpleConfigDocument implements ConfigDocument {
|
||||
private ConfigNodeComplexValue configNodeTree;
|
||||
private ConfigParseOptions parseOptions;
|
||||
|
||||
SimpleConfigDocument(ConfigNodeComplexValue parsedNode, ConfigParseOptions parseOptions) {
|
||||
configNodeTree = parsedNode;
|
||||
this.parseOptions = parseOptions;
|
||||
}
|
||||
|
||||
public ConfigDocument setValue(String path, String newValue) {
|
||||
if (configNodeTree instanceof ConfigNodeArray) {
|
||||
throw new ConfigException.Generic("The ConfigDocument had an array at the root level, and values cannot be replaced inside an array.");
|
||||
}
|
||||
SimpleConfigOrigin origin = SimpleConfigOrigin.newSimple("single value parsing");
|
||||
StringReader reader = new StringReader(newValue);
|
||||
Iterator<Token> tokens = Tokenizer.tokenize(origin, reader, parseOptions.getSyntax());
|
||||
AbstractConfigNodeValue parsedValue = ConfigDocumentParser.parseValue(tokens, parseOptions);
|
||||
reader.close();
|
||||
|
||||
return new SimpleConfigDocument(((ConfigNodeObject)configNodeTree).setValueOnPath(path, parsedValue), parseOptions);
|
||||
}
|
||||
|
||||
public String render() {
|
||||
return configNodeTree.render();
|
||||
}
|
||||
}
|
@ -24,6 +24,44 @@ class ConfigDocumentParserTest extends TestUtils {
|
||||
assertTrue(exceptionThrown)
|
||||
}
|
||||
|
||||
private def parseSimpleValueTest(origText: String, finalText: String = null) {
|
||||
val expectedRenderedText = if (finalText == null) origText else finalText
|
||||
val node = ConfigDocumentParser.parseValue(tokenize(origText), ConfigParseOptions.defaults())
|
||||
assertEquals(expectedRenderedText, node.render())
|
||||
assertTrue(node.isInstanceOf[AbstractConfigNodeValue])
|
||||
|
||||
val nodeJSON = ConfigDocumentParser.parseValue(tokenize(origText), ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON))
|
||||
assertEquals(expectedRenderedText, nodeJSON.render())
|
||||
assertTrue(nodeJSON.isInstanceOf[AbstractConfigNodeValue])
|
||||
}
|
||||
|
||||
private def parseComplexValueTest(origText: String) {
|
||||
val node = ConfigDocumentParser.parseValue(tokenize(origText), ConfigParseOptions.defaults())
|
||||
assertEquals(origText, node.render())
|
||||
assertTrue(node.isInstanceOf[AbstractConfigNodeValue])
|
||||
|
||||
val nodeJSON = ConfigDocumentParser.parseValue(tokenize(origText), ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON))
|
||||
assertEquals(origText, nodeJSON.render())
|
||||
assertTrue(nodeJSON.isInstanceOf[AbstractConfigNodeValue])
|
||||
}
|
||||
|
||||
private def parseSingleValueInvalidJSONTest(origText: String, containsMessage: String) {
|
||||
val node = ConfigDocumentParser.parseValue(tokenize(origText), ConfigParseOptions.defaults())
|
||||
assertEquals(origText, node.render())
|
||||
|
||||
var exceptionThrown = false
|
||||
try {
|
||||
ConfigDocumentParser.parse(tokenize(origText), ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON))
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
exceptionThrown = true
|
||||
assertTrue(e.isInstanceOf[ConfigException])
|
||||
assertTrue(e.getMessage.contains(containsMessage))
|
||||
}
|
||||
assertTrue(exceptionThrown)
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
def parseSuccess {
|
||||
parseTest("foo:bar")
|
||||
@ -184,4 +222,37 @@ class ConfigDocumentParserTest extends TestUtils {
|
||||
parseJSONFailuresTest("", "Empty document")
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
def parseSingleValues() {
|
||||
// Parse simple values
|
||||
parseSimpleValueTest("123")
|
||||
parseSimpleValueTest("123.456")
|
||||
parseSimpleValueTest(""""a string"""")
|
||||
parseSimpleValueTest("true")
|
||||
parseSimpleValueTest("false")
|
||||
parseSimpleValueTest("null")
|
||||
|
||||
// Parse Simple Value throws out trailing and leading whitespace
|
||||
parseSimpleValueTest(" 123", "123")
|
||||
parseSimpleValueTest("123 ", "123")
|
||||
parseSimpleValueTest(" 123 ", "123")
|
||||
|
||||
// Can parse complex values
|
||||
parseComplexValueTest("""{"a": "b"}""")
|
||||
parseComplexValueTest("""["a","b","c"]""")
|
||||
|
||||
parseSingleValueInvalidJSONTest("unquotedtext", "Token not allowed in valid JSON")
|
||||
parseSingleValueInvalidJSONTest("${a.b}", "Substitutions (${} syntax) not allowed in JSON")
|
||||
|
||||
// Check that concatenations are handled by CONF parsing
|
||||
var origText = "123 456 unquotedtext abc"
|
||||
var node = ConfigDocumentParser.parseValue(tokenize(origText), ConfigParseOptions.defaults())
|
||||
assertEquals(origText, node.render())
|
||||
|
||||
// Check that concatenations in JSON will only return the first value passed in
|
||||
origText = "123 456 789"
|
||||
node = ConfigDocumentParser.parseValue(tokenize(origText), ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON))
|
||||
assertEquals("123", node.render())
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,186 @@
|
||||
package com.typesafe.config.impl
|
||||
|
||||
import java.io.{BufferedReader, FileReader}
|
||||
import java.nio.charset.StandardCharsets
|
||||
import java.nio.file.{Paths, Files}
|
||||
|
||||
import com.typesafe.config.{ConfigException, ConfigSyntax, ConfigParseOptions, ConfigDocumentFactory}
|
||||
import org.junit.Assert._
|
||||
import org.junit.Test
|
||||
|
||||
class ConfigDocumentTest extends TestUtils {
|
||||
private def configDocumentReplaceJsonTest(origText: String, finalText: String, newValue: String, replacePath: String) {
|
||||
val configDocument = ConfigDocumentFactory.parseString(origText, ConfigParseOptions.defaults().setSyntax(ConfigSyntax.JSON))
|
||||
assertEquals(origText, configDocument.render())
|
||||
val newDocument = configDocument.setValue(replacePath, newValue)
|
||||
assertTrue(newDocument.isInstanceOf[SimpleConfigDocument])
|
||||
assertEquals(finalText, newDocument.render())
|
||||
}
|
||||
|
||||
private def configDocumentReplaceConfTest(origText: String, finalText: String, newValue: String, replacePath: String) {
|
||||
val configDocument = ConfigDocumentFactory.parseString(origText)
|
||||
assertEquals(origText, configDocument.render())
|
||||
val newDocument = configDocument.setValue(replacePath, newValue)
|
||||
assertTrue(newDocument.isInstanceOf[SimpleConfigDocument])
|
||||
assertEquals(finalText, newDocument.render())
|
||||
}
|
||||
|
||||
@Test
|
||||
def configDocumentReplace() {
|
||||
// Can handle parsing/replacement with a very simple map
|
||||
configDocumentReplaceConfTest("""{"a":1}""", """{"a":2}""", "2", "a")
|
||||
configDocumentReplaceJsonTest("""{"a":1}""", """{"a":2}""", "2", "a")
|
||||
|
||||
// Can handle parsing/replacement with a map without surrounding braces
|
||||
configDocumentReplaceConfTest("a: b\nc = d", "a: b\nc = 12", "12", "c")
|
||||
|
||||
// Can handle parsing/replacement with a complicated map
|
||||
var origText =
|
||||
"""{
|
||||
"a":123,
|
||||
"b": 123.456,
|
||||
"c": true,
|
||||
"d": false,
|
||||
"e": null,
|
||||
"f": "a string",
|
||||
"g": [1,2,3,4,5],
|
||||
"h": {
|
||||
"a": 123,
|
||||
"b": {
|
||||
"a": 12
|
||||
},
|
||||
"c": [1, 2, 3, {"a": "b"}, [1,2,3]]
|
||||
}
|
||||
}"""
|
||||
var finalText =
|
||||
"""{
|
||||
"a":123,
|
||||
"b": 123.456,
|
||||
"c": true,
|
||||
"d": false,
|
||||
"e": null,
|
||||
"f": "a string",
|
||||
"g": [1,2,3,4,5],
|
||||
"h": {
|
||||
"a": 123,
|
||||
"b": {
|
||||
"a": "i am now a string"
|
||||
},
|
||||
"c": [1, 2, 3, {"a": "b"}, [1,2,3]]
|
||||
}
|
||||
}"""
|
||||
configDocumentReplaceConfTest(origText, finalText, """"i am now a string"""", "h.b.a")
|
||||
configDocumentReplaceJsonTest(origText, finalText, """"i am now a string"""", "h.b.a")
|
||||
|
||||
|
||||
// Can handle replacing values with maps
|
||||
finalText =
|
||||
"""{
|
||||
"a":123,
|
||||
"b": 123.456,
|
||||
"c": true,
|
||||
"d": false,
|
||||
"e": null,
|
||||
"f": "a string",
|
||||
"g": [1,2,3,4,5],
|
||||
"h": {
|
||||
"a": 123,
|
||||
"b": {
|
||||
"a": {"a":"b", "c":"d"}
|
||||
},
|
||||
"c": [1, 2, 3, {"a": "b"}, [1,2,3]]
|
||||
}
|
||||
}"""
|
||||
configDocumentReplaceConfTest(origText, finalText, """{"a":"b", "c":"d"}""", "h.b.a")
|
||||
configDocumentReplaceJsonTest(origText, finalText, """{"a":"b", "c":"d"}""", "h.b.a")
|
||||
|
||||
// Can handle replacing values with arrays
|
||||
finalText =
|
||||
"""{
|
||||
"a":123,
|
||||
"b": 123.456,
|
||||
"c": true,
|
||||
"d": false,
|
||||
"e": null,
|
||||
"f": "a string",
|
||||
"g": [1,2,3,4,5],
|
||||
"h": {
|
||||
"a": 123,
|
||||
"b": {
|
||||
"a": [1,2,3,4,5]
|
||||
},
|
||||
"c": [1, 2, 3, {"a": "b"}, [1,2,3]]
|
||||
}
|
||||
}"""
|
||||
configDocumentReplaceConfTest(origText, finalText, "[1,2,3,4,5]", "h.b.a")
|
||||
configDocumentReplaceJsonTest(origText, finalText, "[1,2,3,4,5]", "h.b.a")
|
||||
|
||||
finalText =
|
||||
"""{
|
||||
"a":123,
|
||||
"b": 123.456,
|
||||
"c": true,
|
||||
"d": false,
|
||||
"e": null,
|
||||
"f": "a string",
|
||||
"g": [1,2,3,4,5],
|
||||
"h": {
|
||||
"a": 123,
|
||||
"b": {
|
||||
"a": this is a concatenation 123 456 {a:b} [1,2,3] {a: this is another 123 concatenation null true}
|
||||
},
|
||||
"c": [1, 2, 3, {"a": "b"}, [1,2,3]]
|
||||
}
|
||||
}"""
|
||||
configDocumentReplaceConfTest(origText, finalText,
|
||||
"this is a concatenation 123 456 {a:b} [1,2,3] {a: this is another 123 concatenation null true}", "h.b.a")
|
||||
}
|
||||
|
||||
@Test
|
||||
def configDocumentSetNewValueBraceRoot {
|
||||
val origText = "{\n\t\"a\":\"b\",\n\t\"c\":\"d\"\n}"
|
||||
val finalText = "{\n\t\"a\":\"b\",\n\t\"c\":\"d\"\n\n\t\"e\" : \"f\"\n}"
|
||||
configDocumentReplaceConfTest(origText, finalText, "\"f\"", "\"e\"")
|
||||
configDocumentReplaceJsonTest(origText, finalText, "\"f\"", "\"e\"")
|
||||
}
|
||||
|
||||
@Test
|
||||
def configDocumentSetNewValueNoBraces {
|
||||
val origText = "\"a\":\"b\",\n\"c\":\"d\"\n"
|
||||
val finalText = "\"a\":\"b\",\n\"c\":\"d\"\n\n\"e\" : \"f\"\n"
|
||||
configDocumentReplaceConfTest(origText, finalText, "\"f\"", "\"e\"")
|
||||
}
|
||||
|
||||
@Test
|
||||
def configDocumentReplaceFailure {
|
||||
// Attempting a replace on a ConfigDocument parsed from an array throws an error
|
||||
val origText = "[1, 2, 3, 4, 5]"
|
||||
val document = ConfigDocumentFactory.parseString(origText)
|
||||
var exceptionThrown = false
|
||||
try {
|
||||
document.setValue("a", "1")
|
||||
} catch {
|
||||
case e: Exception =>
|
||||
exceptionThrown = true
|
||||
assertTrue(e.isInstanceOf[ConfigException])
|
||||
assertTrue(e.getMessage.contains("ConfigDocument had an array at the root level"))
|
||||
}
|
||||
assertTrue(exceptionThrown)
|
||||
}
|
||||
|
||||
@Test
|
||||
def configDocumentFileParse {
|
||||
val configDocument = ConfigDocumentFactory.parseFile(resourceFile("/test03.conf"))
|
||||
val fileReader = new BufferedReader(new FileReader("config/src/test/resources/test03.conf"))
|
||||
var line = fileReader.readLine()
|
||||
var sb = new StringBuilder()
|
||||
while (line != null) {
|
||||
sb.append(line)
|
||||
sb.append("\n")
|
||||
line = fileReader.readLine()
|
||||
}
|
||||
fileReader.close()
|
||||
val fileText = sb.toString()
|
||||
assertEquals(fileText, configDocument.render())
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user