From b7b546dc838a9a902f178430790e755fe89fea09 Mon Sep 17 00:00:00 2001 From: "moandji.ezana" Date: Fri, 23 Jan 2015 15:17:50 +0200 Subject: [PATCH] Improved handling of bare and quoted keys --- src/main/java/com/moandjiezana/toml/Keys.java | 32 ++++++++++++++++ .../com/moandjiezana/toml/TomlParser.java | 30 ++++----------- .../com/moandjiezana/toml/BareKeysTest.java | 38 +++++++++++++++++-- .../toml/BurntSushiValidTest.java | 26 +++++++++++-- .../com/moandjiezana/toml/QuotedKeysTest.java | 22 +++++++++++ .../java/com/moandjiezana/toml/TomlTest.java | 27 ------------- .../burntsushi/valid/key-space-modified.json | 3 ++ .../burntsushi/valid/key-space-modified.toml | 1 + .../valid/key-special-chars-modified.json | 5 +++ .../valid/key-special-chars-modified.toml | 1 + .../valid/multiline-string-modified.json | 30 +++++++++++++++ .../valid/multiline-string-modified.toml | 23 +++++++++++ 12 files changed, 182 insertions(+), 56 deletions(-) create mode 100644 src/test/resources/com/moandjiezana/toml/burntsushi/valid/key-space-modified.json create mode 100644 src/test/resources/com/moandjiezana/toml/burntsushi/valid/key-space-modified.toml create mode 100644 src/test/resources/com/moandjiezana/toml/burntsushi/valid/key-special-chars-modified.json create mode 100644 src/test/resources/com/moandjiezana/toml/burntsushi/valid/key-special-chars-modified.toml create mode 100644 src/test/resources/com/moandjiezana/toml/burntsushi/valid/multiline-string-modified.json create mode 100644 src/test/resources/com/moandjiezana/toml/burntsushi/valid/multiline-string-modified.toml diff --git a/src/main/java/com/moandjiezana/toml/Keys.java b/src/main/java/com/moandjiezana/toml/Keys.java index 903653b..0b94672 100644 --- a/src/main/java/com/moandjiezana/toml/Keys.java +++ b/src/main/java/com/moandjiezana/toml/Keys.java @@ -25,6 +25,35 @@ class Keys { } } + static String getKey(String key) { + key = key.trim(); + + if (key.isEmpty()) { + return null; + } + + boolean quoted = false; + char[] chars = key.toCharArray(); + StringBuilder sb = new StringBuilder(key.length()); + + for (int i = 0; i < chars.length; i++) { + char c = chars[i]; + + if (c == '"' && (i == 0 || chars[i - 1] != '\\')) { + if (!quoted && i > 0 && chars [i - 1] != '.') { + return null; + } + quoted = !quoted; + } else if (!quoted && (ALLOWED_CHARS.indexOf(c) == -1)) { + return null; + } + + sb.append(c); + } + + return sb.toString(); + } + static Keys.Key[] split(String key) { List splitKey = new ArrayList(); StringBuilder current = new StringBuilder(); @@ -111,6 +140,9 @@ class Keys { for (int i = 1; i < chars.length; i++) { char c = chars[i]; if (c == '"' && chars[i - 1] != '\\') { + if (!quoted && i > 1 && chars [i - 1] != '.') { + break; + } quoted = !quoted; } else if (!quoted && c == ']') { terminated = true; diff --git a/src/main/java/com/moandjiezana/toml/TomlParser.java b/src/main/java/com/moandjiezana/toml/TomlParser.java index 0fb48e6..4b04bb7 100644 --- a/src/main/java/com/moandjiezana/toml/TomlParser.java +++ b/src/main/java/com/moandjiezana/toml/TomlParser.java @@ -36,7 +36,7 @@ class TomlParser { } if (isTableArray(line)) { - String tableName = getTableArrayName(line); + String tableName = Keys.getTableArrayName(line); if (tableName != null) { results.startTableArray(tableName); String afterTableName = line.substring(tableName.length() + 4); @@ -51,7 +51,7 @@ class TomlParser { } if (multiline.isNotMultiline() && isTable(line)) { - String tableName = getTableName(line); + String tableName = Keys.getTableName(line); if (tableName != null) { results.startTables(tableName); } else { @@ -140,14 +140,14 @@ class TomlParser { continue; } } else { - key = pair[0].trim(); + key = Keys.getKey(pair[0]); + if (key == null) { + results.errors.append("Invalid key name: " + pair[0] + "\n"); + continue; + } value = pair[1].trim(); } - if (!isKeyValid(key)) { - results.errors.append("Invalid key name: " + key + "\n"); - continue; - } Object convertedValue = VALUE_ANALYSIS.convert(value); @@ -169,26 +169,10 @@ class TomlParser { return line.startsWith("[["); } - private String getTableArrayName(String line) { - return Keys.getTableArrayName(line); - } - private boolean isTable(String line) { return line.startsWith("["); } - private String getTableName(String line) { - return Keys.getTableName(line); - } - - private boolean isKeyValid(String key) { - if (key.contains("#") || key.trim().isEmpty()) { - return false; - } - - return true; - } - private boolean isComment(String line) { if (line == null || line.isEmpty()) { return true; diff --git a/src/test/java/com/moandjiezana/toml/BareKeysTest.java b/src/test/java/com/moandjiezana/toml/BareKeysTest.java index 082ed02..57f18ad 100644 --- a/src/test/java/com/moandjiezana/toml/BareKeysTest.java +++ b/src/test/java/com/moandjiezana/toml/BareKeysTest.java @@ -10,7 +10,7 @@ public class BareKeysTest { public final ExpectedException exception = ExpectedException.none(); @Test - public void should_fail_when_characters_outside_accept_range_are_used() throws Exception { + public void should_fail_when_characters_outside_accept_range_are_used_in_table_name() throws Exception { exception.expect(IllegalStateException.class); exception.expectMessage("Invalid table definition: [~]"); @@ -18,16 +18,48 @@ public class BareKeysTest { } @Test - public void should_fail_on_sharp_sign_in_table_names() throws Exception { + public void should_fail_when_characters_outside_accept_range_are_used_in_key_name() throws Exception { + exception.expect(IllegalStateException.class); + + new Toml().parse("~ = 1"); + } + + @Test + public void should_fail_on_sharp_sign_in_table_name() throws Exception { exception.expect(IllegalStateException.class); new Toml().parse("[group#]\nkey=1"); } @Test - public void should_fail_on_spaces_in_table_names() throws Exception { + public void should_fail_on_spaces_in_table_name() throws Exception { exception.expect(IllegalStateException.class); new Toml().parse("[valid key]"); } + + @Test(expected = IllegalStateException.class) + public void should_fail_on_question_marks_in_key_name() throws Exception { + new Toml().parse("key?=true"); + } + + @Test(expected = IllegalStateException.class) + public void should_fail_on_empty_table_name() { + new Toml().parse("[]"); + } + + @Test(expected = IllegalStateException.class) + public void should_fail_on_nested_table_name_ending_with_empty_table_name() { + new Toml().parse("[a.]"); + } + + @Test(expected = IllegalStateException.class) + public void should_fail_on_nested_table_name_containing_empty_table_name() { + new Toml().parse("[a..b]"); + } + + @Test(expected = IllegalStateException.class) + public void should_fail_on_nested_table_name_starting_with_empty_table_name() { + new Toml().parse("[.b]"); + } } diff --git a/src/test/java/com/moandjiezana/toml/BurntSushiValidTest.java b/src/test/java/com/moandjiezana/toml/BurntSushiValidTest.java index 35b00a4..7fbd1b0 100644 --- a/src/test/java/com/moandjiezana/toml/BurntSushiValidTest.java +++ b/src/test/java/com/moandjiezana/toml/BurntSushiValidTest.java @@ -109,16 +109,26 @@ public class BurntSushiValidTest { run("key-equals-nospace"); } - @Test + @Test @Ignore public void key_space() throws Exception { run("key-space"); } @Test + public void key_space_modified() throws Exception { + run("key-space-modified"); + } + + @Test @Ignore public void key_special_chars() throws Exception { run("key-special-chars"); } + @Test + public void key_special_chars_modified() throws Exception { + run("key-special-chars-modified"); + } + @Test public void keys_with_dots() throws Exception { run("keys-with-dots"); @@ -134,11 +144,16 @@ public class BurntSushiValidTest { run("long-integer"); } - @Test + @Test @Ignore public void multiline_string() throws Exception { run("multiline-string"); } + @Test + public void multiline_string_modified() throws Exception { + run("multiline-string-modified"); + } + @Test public void raw_multiline_string() throws Exception { run("raw-multiline-string"); @@ -154,11 +169,16 @@ public class BurntSushiValidTest { run("string-empty"); } - @Test + @Test @Ignore public void string_escapes() throws Exception { run("string-escapes-modified"); } + @Test + public void string_escapes_modified() throws Exception { + run("string-escapes-modified"); + } + @Test public void string_simple() throws Exception { run("string-simple"); diff --git a/src/test/java/com/moandjiezana/toml/QuotedKeysTest.java b/src/test/java/com/moandjiezana/toml/QuotedKeysTest.java index 0e8402d..7b5f34c 100644 --- a/src/test/java/com/moandjiezana/toml/QuotedKeysTest.java +++ b/src/test/java/com/moandjiezana/toml/QuotedKeysTest.java @@ -81,6 +81,28 @@ public class QuotedKeysTest { assertEquals("type0", toml.getString("dog.\"ty\\\"pe\".\"na\\\"me\"")); } + @Test + public void should_support_fully_quoted_table_name() throws Exception { + Toml toml = new Toml().parse("[\"abc.def\"] \n key = 1"); + + assertEquals(1, toml.getLong("\"abc.def\".key").intValue()); + } + + @Test(expected = IllegalStateException.class) + public void should_fail_on_malformed_quoted_key() throws Exception { + new Toml().parse("k\"ey\" = 1"); + } + + @Test(expected = IllegalStateException.class) + public void should_fail_on_malformed_quoted_table() throws Exception { + new Toml().parse("[a\"bc\"]"); + } + + @Test(expected = IllegalStateException.class) + public void should_fail_on_malformed_quoted_nested_table() throws Exception { + new Toml().parse("[a.a\"bc\"]"); + } + private static class Quoted { String ʎǝʞ; diff --git a/src/test/java/com/moandjiezana/toml/TomlTest.java b/src/test/java/com/moandjiezana/toml/TomlTest.java index f6723f6..7f41d16 100644 --- a/src/test/java/com/moandjiezana/toml/TomlTest.java +++ b/src/test/java/com/moandjiezana/toml/TomlTest.java @@ -116,13 +116,6 @@ public class TomlTest { assertEquals(1, toml.getLong("a_a").intValue()); } - - @Test - public void should_support_question_marks_in_key_names() throws Exception { - Toml toml = new Toml().parse("key?=true"); - - assertTrue(toml.getBoolean("key?")); - } @Test public void should_support_dots_in_key_names() throws Exception { @@ -207,26 +200,6 @@ public class TomlTest { public void should_fail_when_illegal_characters_after_table() throws Exception { new Toml().parse("[error] if you didn't catch this, your parser is broken"); } - - @Test(expected = IllegalStateException.class) - public void should_fail_on_empty_table_name() { - new Toml().parse("[]"); - } - - @Test(expected = IllegalStateException.class) - public void should_fail_on_compound_table_name_ending_with_empty_table_name() { - new Toml().parse("[a.]"); - } - - @Test(expected = IllegalStateException.class) - public void should_fail_on_compound_table_name_containing_empty_table_name() { - new Toml().parse("[a..b]"); - } - - @Test(expected = IllegalStateException.class) - public void should_fail_on_compound_table_name_starting_with_empty_table_name() { - new Toml().parse("[.b]"); - } private File file(String file) { return new File(getClass().getResource(file + ".toml").getFile()); diff --git a/src/test/resources/com/moandjiezana/toml/burntsushi/valid/key-space-modified.json b/src/test/resources/com/moandjiezana/toml/burntsushi/valid/key-space-modified.json new file mode 100644 index 0000000..1e7a75b --- /dev/null +++ b/src/test/resources/com/moandjiezana/toml/burntsushi/valid/key-space-modified.json @@ -0,0 +1,3 @@ +{ + "ab": {"type": "integer", "value": "1"} +} diff --git a/src/test/resources/com/moandjiezana/toml/burntsushi/valid/key-space-modified.toml b/src/test/resources/com/moandjiezana/toml/burntsushi/valid/key-space-modified.toml new file mode 100644 index 0000000..00db10f --- /dev/null +++ b/src/test/resources/com/moandjiezana/toml/burntsushi/valid/key-space-modified.toml @@ -0,0 +1 @@ + ab = 1 diff --git a/src/test/resources/com/moandjiezana/toml/burntsushi/valid/key-special-chars-modified.json b/src/test/resources/com/moandjiezana/toml/burntsushi/valid/key-special-chars-modified.json new file mode 100644 index 0000000..a357b35 --- /dev/null +++ b/src/test/resources/com/moandjiezana/toml/burntsushi/valid/key-special-chars-modified.json @@ -0,0 +1,5 @@ +{ + "_-1234567890": { + "type": "integer", "value": "1" + } +} diff --git a/src/test/resources/com/moandjiezana/toml/burntsushi/valid/key-special-chars-modified.toml b/src/test/resources/com/moandjiezana/toml/burntsushi/valid/key-special-chars-modified.toml new file mode 100644 index 0000000..9d76736 --- /dev/null +++ b/src/test/resources/com/moandjiezana/toml/burntsushi/valid/key-special-chars-modified.toml @@ -0,0 +1 @@ +_-1234567890 = 1 diff --git a/src/test/resources/com/moandjiezana/toml/burntsushi/valid/multiline-string-modified.json b/src/test/resources/com/moandjiezana/toml/burntsushi/valid/multiline-string-modified.json new file mode 100644 index 0000000..075bf50 --- /dev/null +++ b/src/test/resources/com/moandjiezana/toml/burntsushi/valid/multiline-string-modified.json @@ -0,0 +1,30 @@ +{ + "multiline_empty_one": { + "type": "string", + "value": "" + }, + "multiline_empty_two": { + "type": "string", + "value": "" + }, + "multiline_empty_three": { + "type": "string", + "value": "" + }, + "multiline_empty_four": { + "type": "string", + "value": "" + }, + "equivalent_one": { + "type": "string", + "value": "The quick brown fox jumps over the lazy dog." + }, + "equivalent_two": { + "type": "string", + "value": "The quick brown fox jumps over the lazy dog." + }, + "equivalent_three": { + "type": "string", + "value": "The quick brown fox jumps over the lazy dog." + } +} diff --git a/src/test/resources/com/moandjiezana/toml/burntsushi/valid/multiline-string-modified.toml b/src/test/resources/com/moandjiezana/toml/burntsushi/valid/multiline-string-modified.toml new file mode 100644 index 0000000..15b1143 --- /dev/null +++ b/src/test/resources/com/moandjiezana/toml/burntsushi/valid/multiline-string-modified.toml @@ -0,0 +1,23 @@ +multiline_empty_one = """""" +multiline_empty_two = """ +""" +multiline_empty_three = """\ + """ +multiline_empty_four = """\ + \ + \ + """ + +equivalent_one = "The quick brown fox jumps over the lazy dog." +equivalent_two = """ +The quick brown \ + + + fox jumps over \ + the lazy dog.""" + +equivalent_three = """\ + The quick brown \ + fox jumps over \ + the lazy dog.\ + """