mirror of
https://github.com/lightbend/config.git
synced 2025-03-23 07:40:25 +08:00
Merge pull request #116 from typesafehub/wip/havocp-allow-unquoted-number-chars
Allow unquoted strings consisting entirely of number chars
This commit is contained in:
commit
b12a481cd9
1
HOCON.md
1
HOCON.md
@ -441,6 +441,7 @@ number-to-string library function).
|
||||
be a two-element path with `foo10` and `0` as the elements.
|
||||
- `foo"10.0"` is an unquoted then a quoted string which are
|
||||
concatenated, so this is a single-element path.
|
||||
- `1.2.3` is the three-element path with `1`,`2`,`3`
|
||||
|
||||
Unlike value concatenations, path expressions are _always_
|
||||
converted to a string, even if they are just a single value.
|
||||
|
@ -355,7 +355,15 @@ final class Tokenizer {
|
||||
return Tokens.newLong(lineOrigin, Long.parseLong(s), s);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
throw problem(s, "Invalid number: '" + s + "'", true /* suggestQuotes */, e);
|
||||
// not a number after all, see if it's an unquoted string.
|
||||
for (char u : s.toCharArray()) {
|
||||
if (notInUnquotedText.indexOf(u) >= 0)
|
||||
throw problem(asString(u), "Reserved character '" + asString(u)
|
||||
+ "' is not allowed outside quotes", true /* suggestQuotes */);
|
||||
}
|
||||
// no evil chars so we just decide this was a string and
|
||||
// not a number.
|
||||
return Tokens.newUnquotedText(lineOrigin, s);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -124,6 +124,7 @@ class ConfParserTest extends TestUtils {
|
||||
assertEquals(path("a b"), parsePath(" a b"))
|
||||
assertEquals(path("a", "b.c", "d"), parsePath("a.\"b.c\".d"))
|
||||
assertEquals(path("3", "14"), parsePath("3.14"))
|
||||
assertEquals(path("3", "14", "159"), parsePath("3.14.159"))
|
||||
assertEquals(path("a3", "14"), parsePath("a3.14"))
|
||||
assertEquals(path(""), parsePath("\"\""))
|
||||
assertEquals(path("a", "", "b"), parsePath("a.\"\".b"))
|
||||
@ -133,6 +134,9 @@ class ConfParserTest extends TestUtils {
|
||||
assertEquals(path("a-c"), parsePath("a-c"))
|
||||
assertEquals(path("a_c"), parsePath("a_c"))
|
||||
assertEquals(path("-"), parsePath("\"-\""))
|
||||
assertEquals(path("-"), parsePath("-"))
|
||||
assertEquals(path("-foo"), parsePath("-foo"))
|
||||
assertEquals(path("-10"), parsePath("-10"))
|
||||
|
||||
// here 10.0 is part of an unquoted string
|
||||
assertEquals(path("foo10", "0"), parsePath("foo10.0"))
|
||||
@ -140,6 +144,8 @@ class ConfParserTest extends TestUtils {
|
||||
assertEquals(path("10", "0foo"), parsePath("10.0foo"))
|
||||
// just a number
|
||||
assertEquals(path("10", "0"), parsePath("10.0"))
|
||||
// multiple-decimal number
|
||||
assertEquals(path("1", "2", "3", "4"), parsePath("1.2.3.4"))
|
||||
|
||||
for (invalid <- Seq("", " ", " \n \n ", "a.", ".b", "a..b", "a${b}c", "\"\".", ".\"\"")) {
|
||||
try {
|
||||
@ -152,11 +158,6 @@ class ConfParserTest extends TestUtils {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
intercept[ConfigException.Parse] {
|
||||
// this gets parsed as a number since it starts with '-'
|
||||
parsePath("-")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -339,11 +340,6 @@ class ConfParserTest extends TestUtils {
|
||||
lineNumberTest(2, "\n\"foo\"")
|
||||
lineNumberTest(3, "\n\n\"foo\"")
|
||||
|
||||
// newline in middle of number uses the line the number was on
|
||||
lineNumberTest(1, "1e\n")
|
||||
lineNumberTest(2, "\n1e\n")
|
||||
lineNumberTest(3, "\n\n1e\n")
|
||||
|
||||
// newlines in triple-quoted string should not hose up the numbering
|
||||
lineNumberTest(1, "a : \"\"\"foo\"\"\"}")
|
||||
lineNumberTest(2, "a : \"\"\"foo\n\"\"\"}")
|
||||
@ -813,4 +809,14 @@ class ConfParserTest extends TestUtils {
|
||||
val conf = ConfigFactory.parseString("foo= \uFEFFbar\uFEFF")
|
||||
assertEquals("bar", conf.getString("foo"))
|
||||
}
|
||||
|
||||
@Test
|
||||
def acceptMultiPeriodNumericPath() {
|
||||
val conf1 = ConfigFactory.parseString("0.1.2.3=foobar1")
|
||||
assertEquals("foobar1", conf1.getString("0.1.2.3"))
|
||||
val conf2 = ConfigFactory.parseString("0.1.2.3.ABC=foobar2")
|
||||
assertEquals("foobar2", conf2.getString("0.1.2.3.ABC"))
|
||||
val conf3 = ConfigFactory.parseString("ABC.0.1.2.3=foobar3")
|
||||
assertEquals("foobar3", conf3.getString("ABC.0.1.2.3"))
|
||||
}
|
||||
}
|
||||
|
@ -67,6 +67,9 @@ class PathTest extends TestUtils {
|
||||
RenderTest("\" foo \"", path(" foo ")),
|
||||
// trailing space only
|
||||
RenderTest("\"foo \"", path("foo ")))
|
||||
// numbers with decimal points
|
||||
RenderTest("1.2", path("1", "2"))
|
||||
RenderTest("1.2.3.4", path("1", "2", "3", "4"))
|
||||
|
||||
for (t <- tests) {
|
||||
assertEquals(t.expected, t.path.render())
|
||||
|
@ -342,8 +342,6 @@ abstract trait TestUtils {
|
||||
// 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
|
||||
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
|
||||
@ -380,6 +378,7 @@ abstract trait TestUtils {
|
||||
"[ += ]",
|
||||
"+= 10",
|
||||
"10 +=",
|
||||
"[ 10e+3e ]", // "+" not allowed in unquoted strings, and not a valid number
|
||||
ParseTest(true, "[ \"foo\nbar\" ]"), // unescaped newline in quoted string, lift doesn't care
|
||||
"[ # comment ]",
|
||||
"${ #comment }",
|
||||
@ -412,7 +411,8 @@ abstract trait TestUtils {
|
||||
"[ \"//comment\" ]", // quoted // comment
|
||||
// this long one is mostly to test rendering
|
||||
"""{ "foo" : { "bar" : "baz", "woo" : "w00t" }, "baz" : { "bar" : "baz", "woo" : [1,2,3,4], "w00t" : true, "a" : false, "b" : 3.14, "c" : null } }""",
|
||||
"{}")
|
||||
"{}",
|
||||
ParseTest(true, "[ 10e+3 ]")) // "+" in a number (lift doesn't handle)
|
||||
|
||||
private val validConfInvalidJson = List[ParseTest]("", // empty document
|
||||
" ", // empty document single space
|
||||
@ -504,7 +504,11 @@ abstract trait TestUtils {
|
||||
"a = [], a += b", // += operator with previous init
|
||||
"{ a = [], a += 10 }", // += in braces object with previous init
|
||||
"a += b", // += operator without previous init
|
||||
"{ a += 10 }") // += in braces object without previous init
|
||||
"{ a += 10 }", // += in braces object without previous init
|
||||
"[ 10e3e3 ]", // two exponents. this should parse to a number plus string "e3"
|
||||
"[ 1-e3 ]", // malformed number should end up as a string instead
|
||||
"[ 1.0.0 ]", // two decimals, should end up as a string
|
||||
"[ 1.0. ]") // trailing decimal should end up as a string
|
||||
|
||||
protected val invalidJson = validConfInvalidJson ++ invalidJsonInvalidConf;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user