mirror of
https://github.com/plexusorg/toml4j.git
synced 2024-12-28 19:24:15 +00:00
Improved handling of bare and quoted keys
This commit is contained in:
parent
f804c99534
commit
b7b546dc83
12 changed files with 182 additions and 56 deletions
|
@ -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<Key> splitKey = new ArrayList<Key>();
|
||||
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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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 ʎǝʞ;
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"ab": {"type": "integer", "value": "1"}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
ab = 1
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"_-1234567890": {
|
||||
"type": "integer", "value": "1"
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
_-1234567890 = 1
|
|
@ -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."
|
||||
}
|
||||
}
|
|
@ -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.\
|
||||
"""
|
Loading…
Reference in a new issue