mirror of
https://github.com/lightbend/config.git
synced 2025-01-15 23:01:05 +08:00
add a bunch of small tests, fix related minor bugs
This brings code coverage up to a decent percentage
This commit is contained in:
parent
0ec572c8d9
commit
99d3c17fd0
@ -65,10 +65,18 @@ public final class Config {
|
||||
public static long parseDuration(String input,
|
||||
ConfigOrigin originForException, String pathForException) {
|
||||
String s = input.trim();
|
||||
String unitString = getUnits(s);
|
||||
String originalUnitString = getUnits(s);
|
||||
String unitString = originalUnitString;
|
||||
String numberString = s.substring(0, s.length() - unitString.length()).trim();
|
||||
TimeUnit units = null;
|
||||
|
||||
// this would be caught later anyway, but the error message
|
||||
// is more helpful if we check it here.
|
||||
if (numberString.length() == 0)
|
||||
throw new ConfigException.BadValue(originForException,
|
||||
pathForException, "No number in duration value '" + input
|
||||
+ "'");
|
||||
|
||||
if (unitString.length() > 2 && !unitString.endsWith("s"))
|
||||
unitString = unitString + "s";
|
||||
|
||||
@ -90,7 +98,8 @@ public final class Config {
|
||||
} else {
|
||||
throw new ConfigException.BadValue(originForException,
|
||||
pathForException, "Could not parse time unit '"
|
||||
+ unitString + "' (try ns, us, ms, s, m, d)");
|
||||
+ originalUnitString
|
||||
+ "' (try ns, us, ms, s, m, d)");
|
||||
}
|
||||
|
||||
try {
|
||||
@ -149,6 +158,14 @@ public final class Config {
|
||||
String numberString = s.substring(0,
|
||||
s.length() - unitStringMaybePlural.length())
|
||||
.trim();
|
||||
|
||||
// this would be caught later anyway, but the error message
|
||||
// is more helpful if we check it here.
|
||||
if (numberString.length() == 0)
|
||||
throw new ConfigException.BadValue(originForException,
|
||||
pathForException, "No number in size-in-bytes value '"
|
||||
+ input + "'");
|
||||
|
||||
MemoryUnit units = null;
|
||||
|
||||
// the short abbreviations are case-insensitive but you can't write the
|
||||
@ -165,7 +182,7 @@ public final class Config {
|
||||
} else {
|
||||
throw new ConfigException.BadValue(originForException,
|
||||
pathForException, "Could not parse size unit '"
|
||||
+ unitString + "' (try b, k, m, g)");
|
||||
+ unitStringMaybePlural + "' (try b, k, m, g)");
|
||||
}
|
||||
|
||||
try {
|
||||
|
@ -299,14 +299,16 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements
|
||||
|
||||
@Override
|
||||
public Long getMilliseconds(String path) {
|
||||
return TimeUnit.NANOSECONDS.toMillis(getNanoseconds(path));
|
||||
long ns = getNanoseconds(path);
|
||||
long ms = TimeUnit.NANOSECONDS.toMillis(ns);
|
||||
return ms;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getNanoseconds(String path) {
|
||||
Long ns = null;
|
||||
try {
|
||||
ns = getLong(path);
|
||||
ns = TimeUnit.MILLISECONDS.toNanos(getLong(path));
|
||||
} catch (ConfigException.WrongType e) {
|
||||
ConfigValue v = resolve(path, ConfigValueType.STRING, path);
|
||||
ns = Config.parseDuration((String) v.unwrapped(), v.origin(), path);
|
||||
@ -438,7 +440,8 @@ abstract class AbstractConfigObject extends AbstractConfigValue implements
|
||||
List<? extends ConfigValue> list = getList(path);
|
||||
for (ConfigValue v : list) {
|
||||
if (v.valueType() == ConfigValueType.NUMBER) {
|
||||
l.add(((Number) v.unwrapped()).longValue());
|
||||
l.add(TimeUnit.MILLISECONDS.toNanos(((Number) v.unwrapped())
|
||||
.longValue()));
|
||||
} else if (v.valueType() == ConfigValueType.STRING) {
|
||||
String s = (String) v.unwrapped();
|
||||
Long n = Config.parseDuration(s, v.origin(), path);
|
||||
|
@ -66,7 +66,11 @@ abstract class AbstractConfigValue implements ConfigValue {
|
||||
@Override
|
||||
public int hashCode() {
|
||||
// note that "origin" is deliberately NOT part of equality
|
||||
return this.unwrapped().hashCode();
|
||||
Object o = this.unwrapped();
|
||||
if (o == null)
|
||||
return 0;
|
||||
else
|
||||
return o.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1,7 +1,6 @@
|
||||
package com.typesafe.config.impl;
|
||||
|
||||
import com.typesafe.config.ConfigException;
|
||||
import com.typesafe.config.ConfigObject;
|
||||
import com.typesafe.config.ConfigOrigin;
|
||||
import com.typesafe.config.ConfigValueType;
|
||||
|
||||
@ -23,12 +22,9 @@ final class Tokens {
|
||||
public String toString() {
|
||||
String s = tokenType().name() + "(" + value.valueType().name()
|
||||
+ ")";
|
||||
if (value instanceof ConfigObject || value instanceof ConfigList) {
|
||||
return s;
|
||||
} else {
|
||||
|
||||
return s + "='" + value().unwrapped() + "'";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canEqual(Object other) {
|
||||
|
@ -17,7 +17,13 @@
|
||||
"c" : "c",
|
||||
"d" : "d",
|
||||
"concatenated" : null bar 42 baz true 3.14 hi,
|
||||
"number" : "57"
|
||||
"double" : "3.14",
|
||||
"number" : "57",
|
||||
"null" : "null",
|
||||
"true" : "true",
|
||||
"yes" : "yes",
|
||||
"false" : "false",
|
||||
"no" : "no"
|
||||
},
|
||||
|
||||
"arrays" : {
|
||||
@ -45,11 +51,15 @@
|
||||
|
||||
"durations" : {
|
||||
"second" : 1s,
|
||||
"secondsList" : [1s,2seconds,3 s]
|
||||
"secondsList" : [1s,2seconds,3 s, 4000],
|
||||
"secondAsNumber" : 1000,
|
||||
"halfSecond" : 0.5s
|
||||
},
|
||||
|
||||
"memsizes" : {
|
||||
"meg" : 1M,
|
||||
"megsList" : [1M, 1024K]
|
||||
"megsList" : [1M, 1024K, 1048576],
|
||||
"megAsNumber" : 1048576,
|
||||
"halfMeg" : 0.5M
|
||||
}
|
||||
}
|
||||
|
@ -7,17 +7,6 @@ import com.typesafe.config.ConfigException
|
||||
|
||||
class ConfigSubstitutionTest extends TestUtils {
|
||||
|
||||
private def subst(ref: String, style: SubstitutionStyle = SubstitutionStyle.PATH) = {
|
||||
val pieces = java.util.Collections.singletonList[Object](new Substitution(ref, style))
|
||||
new ConfigSubstitution(fakeOrigin(), pieces)
|
||||
}
|
||||
|
||||
private def substInString(ref: String, style: SubstitutionStyle = SubstitutionStyle.PATH) = {
|
||||
import scala.collection.JavaConverters._
|
||||
val pieces = List("start<", new Substitution(ref, style), ">end")
|
||||
new ConfigSubstitution(fakeOrigin(), pieces.asJava)
|
||||
}
|
||||
|
||||
private def resolveWithoutFallbacks(v: AbstractConfigObject) = {
|
||||
SubstitutionResolver.resolveWithoutFallbacks(v, v).asInstanceOf[AbstractConfigObject]
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import com.typesafe.config.ConfigObject
|
||||
import com.typesafe.config.ConfigException
|
||||
import java.util.concurrent.TimeUnit
|
||||
import scala.collection.JavaConverters._
|
||||
import com.typesafe.config.ConfigConfig
|
||||
|
||||
class ConfigTest extends TestUtils {
|
||||
|
||||
@ -141,7 +142,7 @@ class ConfigTest extends TestUtils {
|
||||
}
|
||||
|
||||
@Test
|
||||
def test01() {
|
||||
def test01Getting() {
|
||||
val conf = Config.load("test01")
|
||||
|
||||
// get all the primitive types
|
||||
@ -158,6 +159,11 @@ class ConfigTest extends TestUtils {
|
||||
// FIXME need to add a way to get a null
|
||||
//assertEquals(null, conf.getAny("nulls.null"))
|
||||
|
||||
// get stuff with getAny
|
||||
assertEquals(42L, conf.getAny("ints.fortyTwo"))
|
||||
assertEquals("abcd", conf.getAny("strings.abcd"))
|
||||
assertEquals(false, conf.getAny("booleans.falseAgain"))
|
||||
|
||||
// get empty array as any type of array
|
||||
assertEquals(Seq(), conf.getAnyList("arrays.empty").asScala)
|
||||
assertEquals(Seq(), conf.getIntList("arrays.empty").asScala)
|
||||
@ -184,6 +190,11 @@ class ConfigTest extends TestUtils {
|
||||
// plain getList should work
|
||||
assertEquals(Seq(intValue(1), intValue(2), intValue(3)), conf.getList("arrays.ofInt").asScala)
|
||||
assertEquals(Seq(stringValue("a"), stringValue("b"), stringValue("c")), conf.getList("arrays.ofString").asScala)
|
||||
}
|
||||
|
||||
@Test
|
||||
def test01Exceptions() {
|
||||
val conf = Config.load("test01")
|
||||
|
||||
// should throw Missing if key doesn't exist
|
||||
intercept[ConfigException.Missing] {
|
||||
@ -195,31 +206,145 @@ class ConfigTest extends TestUtils {
|
||||
conf.getInt("nulls.null")
|
||||
}
|
||||
|
||||
intercept[ConfigException.Null] {
|
||||
conf.getIntList("nulls.null")
|
||||
}
|
||||
|
||||
intercept[ConfigException.Null] {
|
||||
conf.getMilliseconds("nulls.null")
|
||||
}
|
||||
|
||||
intercept[ConfigException.Null] {
|
||||
conf.getNanoseconds("nulls.null")
|
||||
}
|
||||
|
||||
intercept[ConfigException.Null] {
|
||||
conf.getMemorySize("nulls.null")
|
||||
}
|
||||
|
||||
// should throw WrongType if key is wrong type and not convertible
|
||||
intercept[ConfigException.WrongType] {
|
||||
conf.getInt("booleans.trueAgain")
|
||||
}
|
||||
|
||||
intercept[ConfigException.WrongType] {
|
||||
conf.getBooleanList("arrays.ofInt")
|
||||
}
|
||||
|
||||
intercept[ConfigException.WrongType] {
|
||||
conf.getIntList("arrays.ofBoolean")
|
||||
}
|
||||
|
||||
intercept[ConfigException.WrongType] {
|
||||
conf.getObjectList("arrays.ofInt")
|
||||
}
|
||||
|
||||
intercept[ConfigException.WrongType] {
|
||||
conf.getMilliseconds("ints")
|
||||
}
|
||||
|
||||
intercept[ConfigException.WrongType] {
|
||||
conf.getNanoseconds("ints")
|
||||
}
|
||||
|
||||
intercept[ConfigException.WrongType] {
|
||||
conf.getMemorySize("ints")
|
||||
}
|
||||
|
||||
// should throw BadPath on various bad paths
|
||||
intercept[ConfigException.BadPath] {
|
||||
conf.getInt(".bad")
|
||||
}
|
||||
|
||||
intercept[ConfigException.BadPath] {
|
||||
conf.getInt("bad.")
|
||||
}
|
||||
|
||||
intercept[ConfigException.BadPath] {
|
||||
conf.getInt("bad..bad")
|
||||
}
|
||||
|
||||
// should throw BadValue on things that don't parse
|
||||
// as durations and sizes
|
||||
intercept[ConfigException.BadValue] {
|
||||
conf.getMilliseconds("strings.a")
|
||||
}
|
||||
|
||||
intercept[ConfigException.BadValue] {
|
||||
conf.getNanoseconds("strings.a")
|
||||
}
|
||||
|
||||
intercept[ConfigException.BadValue] {
|
||||
conf.getMemorySize("strings.a")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
def test01Conversions() {
|
||||
val conf = Config.load("test01")
|
||||
|
||||
// should convert numbers to string
|
||||
assertEquals("42", conf.getString("ints.fortyTwo"))
|
||||
assertEquals("42.1", conf.getString("floats.fortyTwoPointOne"))
|
||||
|
||||
// should convert string to number
|
||||
assertEquals(57, conf.getInt("strings.number"))
|
||||
assertEquals(3.14, conf.getDouble("strings.double"), 1e-6)
|
||||
|
||||
// should convert strings to boolean
|
||||
assertEquals(true, conf.getBoolean("strings.true"))
|
||||
assertEquals(true, conf.getBoolean("strings.yes"))
|
||||
assertEquals(false, conf.getBoolean("strings.false"))
|
||||
assertEquals(false, conf.getBoolean("strings.no"))
|
||||
|
||||
// converting some random string to boolean fails though
|
||||
intercept[ConfigException.WrongType] {
|
||||
conf.getBoolean("strings.abcd")
|
||||
}
|
||||
|
||||
// FIXME test convert string "null" to a null value
|
||||
|
||||
// should not convert strings to object or list
|
||||
intercept[ConfigException.WrongType] {
|
||||
conf.getObject("strings.a")
|
||||
}
|
||||
|
||||
intercept[ConfigException.WrongType] {
|
||||
conf.getList("strings.a")
|
||||
}
|
||||
|
||||
// should not convert object or list to string
|
||||
intercept[ConfigException.WrongType] {
|
||||
conf.getString("ints")
|
||||
}
|
||||
|
||||
intercept[ConfigException.WrongType] {
|
||||
conf.getString("arrays.ofInt")
|
||||
}
|
||||
|
||||
// should get durations
|
||||
def asNanos(secs: Int) = TimeUnit.SECONDS.toNanos(secs)
|
||||
assertEquals(1000L, conf.getMilliseconds("durations.second"))
|
||||
assertEquals(asNanos(1), conf.getNanoseconds("durations.second"))
|
||||
assertEquals(Seq(1000L, 2000L, 3000L),
|
||||
assertEquals(1000L, conf.getMilliseconds("durations.secondAsNumber"))
|
||||
assertEquals(asNanos(1), conf.getNanoseconds("durations.secondAsNumber"))
|
||||
assertEquals(Seq(1000L, 2000L, 3000L, 4000L),
|
||||
conf.getMillisecondsList("durations.secondsList").asScala)
|
||||
assertEquals(Seq(asNanos(1), asNanos(2), asNanos(3)),
|
||||
assertEquals(Seq(asNanos(1), asNanos(2), asNanos(3), asNanos(4)),
|
||||
conf.getNanosecondsList("durations.secondsList").asScala)
|
||||
assertEquals(500L, conf.getMilliseconds("durations.halfSecond"))
|
||||
|
||||
// should get size in bytes
|
||||
assertEquals(1024 * 1024L, conf.getMemorySize("memsizes.meg"))
|
||||
assertEquals(Seq(1024 * 1024L, 1024 * 1024L),
|
||||
assertEquals(1024 * 1024L, conf.getMemorySize("memsizes.megAsNumber"))
|
||||
assertEquals(Seq(1024 * 1024L, 1024 * 1024L, 1024L * 1024L),
|
||||
conf.getMemorySizeList("memsizes.megsList").asScala)
|
||||
assertEquals(512 * 1024L, conf.getMemorySize("memsizes.halfMeg"))
|
||||
}
|
||||
|
||||
@Test
|
||||
def test01MergingOtherFormats() {
|
||||
val conf = Config.load("test01")
|
||||
|
||||
// should have loaded stuff from .json
|
||||
assertEquals(1, conf.getInt("fromJson1"))
|
||||
@ -229,8 +354,18 @@ class ConfigTest extends TestUtils {
|
||||
assertEquals("abc", conf.getString("fromProps.abc"))
|
||||
assertEquals(1, conf.getInt("fromProps.one"))
|
||||
assertEquals(true, conf.getBoolean("fromProps.bool"))
|
||||
}
|
||||
|
||||
@Test
|
||||
def test01ToString() {
|
||||
val conf = Config.load("test01")
|
||||
|
||||
// toString() on conf objects doesn't throw (toString is just a debug string so not testing its result)
|
||||
conf.toString()
|
||||
}
|
||||
|
||||
@Test
|
||||
def test01LoadWithConfigConfig() {
|
||||
val conf = Config.load(new ConfigConfig("test01"))
|
||||
}
|
||||
}
|
||||
|
@ -3,6 +3,7 @@ package com.typesafe.config.impl
|
||||
import org.junit.Assert._
|
||||
import org.junit._
|
||||
import com.typesafe.config.ConfigValue
|
||||
import java.util.Collections
|
||||
|
||||
class ConfigValueTest extends TestUtils {
|
||||
|
||||
@ -75,4 +76,31 @@ class ConfigValueTest extends TestUtils {
|
||||
checkNotEqualObjects(a, differentRef)
|
||||
checkNotEqualObjects(a, differentStyle)
|
||||
}
|
||||
|
||||
@Test
|
||||
def configSubstitutionEquality() {
|
||||
val a = subst("foo")
|
||||
val sameAsA = subst("foo")
|
||||
val b = subst("bar")
|
||||
|
||||
checkEqualObjects(a, a)
|
||||
checkEqualObjects(a, sameAsA)
|
||||
checkNotEqualObjects(a, b)
|
||||
}
|
||||
|
||||
@Test
|
||||
def valuesToString() {
|
||||
// just check that these don't throw, the exact output
|
||||
// isn't super important since it's just for debugging
|
||||
intValue(10).toString()
|
||||
longValue(11).toString()
|
||||
doubleValue(3.14).toString()
|
||||
stringValue("hi").toString()
|
||||
nullValue().toString()
|
||||
boolValue(true).toString()
|
||||
(new SimpleConfigObject(fakeOrigin(), null, Collections.emptyMap[String, AbstractConfigValue]())).toString()
|
||||
(new ConfigList(fakeOrigin(), Collections.emptyList[AbstractConfigValue]())).toString()
|
||||
subst("a").toString()
|
||||
substInString("b").toString()
|
||||
}
|
||||
}
|
||||
|
@ -7,8 +7,9 @@ import java.io.Reader
|
||||
import java.io.StringReader
|
||||
import com.typesafe.config._
|
||||
import java.util.HashMap
|
||||
import java.util.Collections
|
||||
|
||||
class ParseTest extends TestUtils {
|
||||
class JsonTest extends TestUtils {
|
||||
|
||||
def parse(s: String): ConfigValue = {
|
||||
Parser.parse(SyntaxFlavor.JSON, new SimpleConfigOrigin("test json string"), s)
|
||||
@ -133,9 +134,13 @@ class ParseTest extends TestUtils {
|
||||
def validJsonWorks(): Unit = {
|
||||
// be sure we do the same thing as Lift when we build our JSON "DOM"
|
||||
for (valid <- whitespaceVariations(validJson)) {
|
||||
val liftAST = addOffendingJsonToException("lift", valid.test) {
|
||||
val liftAST = if (valid.liftBehaviorUnexpected) {
|
||||
new SimpleConfigObject(fakeOrigin(), null, Collections.emptyMap[String, AbstractConfigValue]())
|
||||
} else {
|
||||
addOffendingJsonToException("lift", valid.test) {
|
||||
fromJsonWithLiftParser(valid.test)
|
||||
}
|
||||
}
|
||||
val ourAST = addOffendingJsonToException("config-json", valid.test) {
|
||||
parse(valid.test)
|
||||
}
|
||||
|
@ -32,16 +32,43 @@ abstract trait TestUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private class NotEqualToAnythingElse {
|
||||
override def equals(other: Any) = {
|
||||
other match {
|
||||
case x: NotEqualToAnythingElse => true
|
||||
case _ => false
|
||||
}
|
||||
}
|
||||
|
||||
override def hashCode() = 971
|
||||
}
|
||||
|
||||
private object notEqualToAnything extends NotEqualToAnythingElse
|
||||
|
||||
private def checkNotEqualToRandomOtherThing(a: Any) {
|
||||
assertFalse(a.equals(notEqualToAnything))
|
||||
assertFalse(notEqualToAnything.equals(a))
|
||||
}
|
||||
|
||||
protected def checkNotEqualObjects(a: Any, b: Any) {
|
||||
assertFalse(a.equals(b))
|
||||
assertFalse(b.equals(a))
|
||||
// hashcode inequality isn't guaranteed, but
|
||||
// as long as it happens to work it might
|
||||
// detect a bug (if hashcodes are equal,
|
||||
// check if it's due to a bug or correct
|
||||
// before you remove this)
|
||||
assertFalse(a.hashCode() == b.hashCode())
|
||||
checkNotEqualToRandomOtherThing(a)
|
||||
checkNotEqualToRandomOtherThing(b)
|
||||
}
|
||||
|
||||
protected def checkEqualObjects(a: Any, b: Any) {
|
||||
assertTrue(a.equals(b))
|
||||
assertTrue(b.equals(a))
|
||||
assertTrue(a.hashCode() == b.hashCode())
|
||||
checkNotEqualToRandomOtherThing(a)
|
||||
checkNotEqualToRandomOtherThing(b)
|
||||
}
|
||||
|
||||
def fakeOrigin() = {
|
||||
@ -68,13 +95,20 @@ abstract trait TestUtils {
|
||||
"\"", // single quote by itself
|
||||
"{ \"foo\" : }", // no value in object
|
||||
"{ : 10 }", // no key in object
|
||||
"{ \"foo\" }", // no value or colon
|
||||
"{ \"a\" : [ }", // [ is not a valid value
|
||||
"{ \"foo\" : 10, }", // extra trailing comma
|
||||
"{ \"foo\" : 10, true }", // non-key after comma
|
||||
"{ foo : \"bar\" }", // no quotes on key
|
||||
"{ foo : bar }", // no quotes on key or value
|
||||
"[ 1, \\", // ends with backslash
|
||||
// these two problems are ignored by the lift tokenizer
|
||||
"[:\"foo\", \"bar\"]", // colon in an array; lift doesn't throw (tokenizer erases it)
|
||||
"[\"foo\" : \"bar\"]", // colon in an array another way, lift ignores (tokenizer erases it)
|
||||
"[ 10e3e3 ]", // two exponents. ideally this might parse to a number plus string "e3" but it's hard to implement.
|
||||
"[ 1-e3 ]", // malformed number but all chars can appear in a number
|
||||
"[ \"hello ]", // unterminated string
|
||||
"[ 1, 2, 3, ]", // array with empty element
|
||||
ParseTest(true, "{ \"foo\" , true }"), // comma instead of colon, lift is fine with this
|
||||
ParseTest(true, "{ \"foo\" : true \"bar\" : false }"), // missing comma between fields, lift fine with this
|
||||
"[ 10, }]", // array with } as an element
|
||||
@ -87,11 +121,16 @@ abstract trait TestUtils {
|
||||
"[]true", // trailing valid token after the root array
|
||||
"[${]", // unclosed substitution
|
||||
"[$]", // '$' by itself
|
||||
"[$ ]", // '$' by itself with spaces after
|
||||
"""${"foo""bar"}""", // multiple strings in substitution
|
||||
"""{ "a" : [1,2], "b" : y${a}z }""", // trying to interpolate an array in a string
|
||||
"""{ "a" : { "c" : 2 }, "b" : y${a}z }""", // trying to interpolate an object in a string
|
||||
ParseTest(false, true, "[${ foo.bar}]"), // substitution with leading spaces
|
||||
ParseTest(false, true, "[${foo.bar }]"), // substitution with trailing spaces
|
||||
ParseTest(false, true, "[${ \"foo.bar\"}]"), // substitution with leading spaces and quoted
|
||||
ParseTest(false, true, "[${\"foo.bar\" }]"), // substitution with trailing spaces and quoted
|
||||
"[${true}]", // substitution with unquoted true token
|
||||
"[ = ]", // = is not a valid token
|
||||
"") // empty document again, just for clean formatting of this list ;-)
|
||||
|
||||
// We'll automatically try each of these with whitespace modifications
|
||||
@ -130,6 +169,8 @@ abstract trait TestUtils {
|
||||
"[ ${foo} ]",
|
||||
"[ ${\"foo\"} ]",
|
||||
"[ ${foo.bar} ]",
|
||||
"[ abc xyz ${foo.bar} qrs tuv ]", // value concatenation
|
||||
"[ 1, 2, 3, blah ]",
|
||||
"[ ${\"foo.bar\"} ]")
|
||||
|
||||
protected val invalidJson = validConfInvalidJson ++ invalidJsonInvalidConf;
|
||||
@ -152,13 +193,16 @@ abstract trait TestUtils {
|
||||
if (t.whitespaceMatters) {
|
||||
return Seq(t)
|
||||
} else {
|
||||
for (v <- variations)
|
||||
yield ParseTest(t.liftBehaviorUnexpected, v(t.test))
|
||||
val withNonAscii = ParseTest(true,
|
||||
t.test.replace(" ", "\u2003")) // 2003 = em space, to test non-ascii whitespace
|
||||
Seq(withNonAscii) ++ (for (v <- variations)
|
||||
yield ParseTest(t.liftBehaviorUnexpected, v(t.test)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected def intValue(i: Int) = new ConfigInt(fakeOrigin(), i)
|
||||
protected def longValue(l: Long) = new ConfigLong(fakeOrigin(), l)
|
||||
protected def boolValue(b: Boolean) = new ConfigBoolean(fakeOrigin(), b)
|
||||
protected def nullValue() = new ConfigNull(fakeOrigin())
|
||||
protected def stringValue(s: String) = new ConfigString(fakeOrigin(), s)
|
||||
@ -168,4 +212,25 @@ abstract trait TestUtils {
|
||||
Parser.parse(SyntaxFlavor.CONF, new SimpleConfigOrigin("test string"), s).asInstanceOf[AbstractConfigObject]
|
||||
}
|
||||
|
||||
protected def subst(ref: String, style: SubstitutionStyle = SubstitutionStyle.PATH) = {
|
||||
val pieces = java.util.Collections.singletonList[Object](new Substitution(ref, style))
|
||||
new ConfigSubstitution(fakeOrigin(), pieces)
|
||||
}
|
||||
|
||||
protected def substInString(ref: String, style: SubstitutionStyle = SubstitutionStyle.PATH) = {
|
||||
import scala.collection.JavaConverters._
|
||||
val pieces = List("start<", new Substitution(ref, style), ">end")
|
||||
new ConfigSubstitution(fakeOrigin(), pieces.asJava)
|
||||
}
|
||||
|
||||
def tokenTrue = Tokens.newBoolean(fakeOrigin(), true)
|
||||
def tokenFalse = Tokens.newBoolean(fakeOrigin(), false)
|
||||
def tokenNull = Tokens.newNull(fakeOrigin())
|
||||
def tokenUnquoted(s: String) = Tokens.newUnquotedText(fakeOrigin(), s)
|
||||
def tokenKeySubstitution(s: String) = Tokens.newSubstitution(fakeOrigin(), s, SubstitutionStyle.KEY)
|
||||
def tokenPathSubstitution(s: String) = Tokens.newSubstitution(fakeOrigin(), s, SubstitutionStyle.PATH)
|
||||
def tokenString(s: String) = Tokens.newString(fakeOrigin(), s)
|
||||
def tokenDouble(d: Double) = Tokens.newDouble(fakeOrigin(), d)
|
||||
def tokenInt(i: Int) = Tokens.newInt(fakeOrigin(), i)
|
||||
def tokenLong(l: Long) = Tokens.newLong(fakeOrigin(), l)
|
||||
}
|
||||
|
@ -7,10 +7,78 @@ class TokenTest extends TestUtils {
|
||||
|
||||
@Test
|
||||
def tokenEquality() {
|
||||
// syntax tokens
|
||||
checkEqualObjects(Tokens.START, Tokens.START)
|
||||
checkNotEqualObjects(Tokens.START, Tokens.OPEN_CURLY)
|
||||
|
||||
checkEqualObjects(Tokens.newInt(fakeOrigin(), 42), Tokens.newInt(fakeOrigin(), 42))
|
||||
checkNotEqualObjects(Tokens.newInt(fakeOrigin(), 42), Tokens.newInt(fakeOrigin(), 43))
|
||||
// int
|
||||
checkEqualObjects(tokenInt(42), tokenInt(42))
|
||||
checkNotEqualObjects(tokenInt(42), tokenInt(43))
|
||||
|
||||
// long
|
||||
checkEqualObjects(tokenLong(42), tokenLong(42))
|
||||
checkNotEqualObjects(tokenLong(42), tokenLong(43))
|
||||
|
||||
// int and long mixed
|
||||
checkEqualObjects(tokenInt(42), tokenLong(42))
|
||||
checkNotEqualObjects(tokenInt(42), tokenLong(43))
|
||||
|
||||
// boolean
|
||||
checkEqualObjects(tokenTrue, tokenTrue)
|
||||
checkNotEqualObjects(tokenTrue, tokenFalse)
|
||||
|
||||
// double
|
||||
checkEqualObjects(tokenDouble(3.14), tokenDouble(3.14))
|
||||
checkNotEqualObjects(tokenDouble(3.14), tokenDouble(4.14))
|
||||
|
||||
// string
|
||||
checkEqualObjects(tokenString("foo"), tokenString("foo"))
|
||||
checkNotEqualObjects(tokenString("foo"), tokenString("bar"))
|
||||
|
||||
// unquoted
|
||||
checkEqualObjects(tokenUnquoted("foo"), tokenUnquoted("foo"))
|
||||
checkNotEqualObjects(tokenUnquoted("foo"), tokenUnquoted("bar"))
|
||||
|
||||
// key subst
|
||||
checkEqualObjects(tokenKeySubstitution("foo"), tokenKeySubstitution("foo"))
|
||||
checkNotEqualObjects(tokenKeySubstitution("foo"), tokenKeySubstitution("bar"))
|
||||
|
||||
// path subst
|
||||
checkEqualObjects(tokenPathSubstitution("foo"), tokenPathSubstitution("foo"))
|
||||
checkNotEqualObjects(tokenPathSubstitution("foo"), tokenPathSubstitution("bar"))
|
||||
|
||||
// key and path not equal
|
||||
checkNotEqualObjects(tokenKeySubstitution("foo"), tokenPathSubstitution("foo"))
|
||||
|
||||
// null
|
||||
checkEqualObjects(tokenNull, tokenNull)
|
||||
|
||||
// newline
|
||||
checkEqualObjects(Tokens.newLine(10), Tokens.newLine(10))
|
||||
checkNotEqualObjects(Tokens.newLine(10), Tokens.newLine(11))
|
||||
|
||||
// different types are not equal
|
||||
checkNotEqualObjects(tokenTrue, tokenInt(1))
|
||||
checkNotEqualObjects(tokenString("true"), tokenTrue)
|
||||
}
|
||||
|
||||
@Test
|
||||
def tokenToString() {
|
||||
// just be sure toString() doesn't throw, it's for debugging
|
||||
// so its exact output doesn't matter a lot
|
||||
tokenTrue.toString()
|
||||
tokenFalse.toString()
|
||||
tokenInt(42).toString()
|
||||
tokenLong(43).toString()
|
||||
tokenDouble(3.14).toString()
|
||||
tokenNull.toString()
|
||||
tokenUnquoted("foo").toString()
|
||||
tokenString("bar").toString()
|
||||
tokenKeySubstitution("a").toString()
|
||||
tokenPathSubstitution("b").toString()
|
||||
Tokens.newLine(10).toString()
|
||||
Tokens.START.toString()
|
||||
Tokens.END.toString()
|
||||
Tokens.COLON.toString()
|
||||
}
|
||||
}
|
||||
|
@ -10,17 +10,6 @@ import java.util.HashMap
|
||||
|
||||
class TokenizerTest extends TestUtils {
|
||||
|
||||
def tokenTrue = Tokens.newBoolean(fakeOrigin(), true)
|
||||
def tokenFalse = Tokens.newBoolean(fakeOrigin(), false)
|
||||
def tokenNull = Tokens.newNull(fakeOrigin())
|
||||
def tokenUnquoted(s: String) = Tokens.newUnquotedText(fakeOrigin(), s)
|
||||
def tokenKeySubstitution(s: String) = Tokens.newSubstitution(fakeOrigin(), s, SubstitutionStyle.KEY)
|
||||
def tokenPathSubstitution(s: String) = Tokens.newSubstitution(fakeOrigin(), s, SubstitutionStyle.PATH)
|
||||
def tokenString(s: String) = Tokens.newString(fakeOrigin(), s)
|
||||
def tokenDouble(d: Double) = Tokens.newDouble(fakeOrigin(), d)
|
||||
def tokenInt(i: Int) = Tokens.newInt(fakeOrigin(), i)
|
||||
def tokenLong(l: Long) = Tokens.newLong(fakeOrigin(), l)
|
||||
|
||||
def tokenize(origin: ConfigOrigin, input: Reader): java.util.Iterator[Token] = {
|
||||
Tokenizer.tokenize(origin, input)
|
||||
}
|
||||
@ -199,6 +188,7 @@ class TokenizerTest extends TestUtils {
|
||||
("1.2", 1.2),
|
||||
("1e6", 1e6),
|
||||
("1e-6", 1e-6),
|
||||
("1E-6", 1e-6), // capital E is allowed
|
||||
("-1", -1),
|
||||
("-1.2", -1.2))
|
||||
|
||||
|
@ -23,6 +23,18 @@ class UnitParserTest extends TestUtils {
|
||||
val result = Config.parseDuration(s, fakeOrigin(), "test")
|
||||
assertEquals(oneSecInNanos, result)
|
||||
}
|
||||
|
||||
// bad units
|
||||
val e = intercept[ConfigException.BadValue] {
|
||||
Config.parseDuration("100 dollars", fakeOrigin(), "test")
|
||||
}
|
||||
assertTrue(e.getMessage().contains("time unit"))
|
||||
|
||||
// bad number
|
||||
val e2 = intercept[ConfigException.BadValue] {
|
||||
Config.parseDuration("1 00 seconds", fakeOrigin(), "test")
|
||||
}
|
||||
assertTrue(e2.getMessage().contains("duration number"))
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -38,5 +50,17 @@ class UnitParserTest extends TestUtils {
|
||||
val result = Config.parseMemorySize(s, fakeOrigin(), "test")
|
||||
assertEquals(1024 * 1024, result)
|
||||
}
|
||||
|
||||
// bad units
|
||||
val e = intercept[ConfigException.BadValue] {
|
||||
Config.parseMemorySize("100 dollars", fakeOrigin(), "test")
|
||||
}
|
||||
assertTrue(e.getMessage().contains("size unit"))
|
||||
|
||||
// bad number
|
||||
val e2 = intercept[ConfigException.BadValue] {
|
||||
Config.parseMemorySize("1 00 bytes", fakeOrigin(), "test")
|
||||
}
|
||||
assertTrue(e2.getMessage().contains("size number"))
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user