add a bunch of small tests, fix related minor bugs

This brings code coverage up to a decent percentage
This commit is contained in:
Havoc Pennington 2011-11-09 16:42:58 -05:00
parent 0ec572c8d9
commit 99d3c17fd0
13 changed files with 383 additions and 49 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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