mirror of
https://github.com/plexusorg/toml4j.git
synced 2025-08-03 19:16:30 +00:00
Improved comment handling and disallowed mixed arrays
This commit is contained in:
parent
d9e1ccc98a
commit
96016c02d2
7 changed files with 237 additions and 2 deletions
|
@ -153,7 +153,7 @@ class TomlParser extends BaseParser<Object> {
|
|||
|
||||
@SuppressNode
|
||||
Rule Comment() {
|
||||
return Sequence('#', ZeroOrMore(TestNot(NewLine()), ANY), FirstOf(NewLine(), EOI));
|
||||
return Sequence(ZeroOrMore(Whitespace()), '#', ZeroOrMore(TestNot(NewLine()), ANY), FirstOf(NewLine(), EOI));
|
||||
}
|
||||
|
||||
boolean addTableArray(String name) {
|
||||
|
@ -178,7 +178,12 @@ class TomlParser extends BaseParser<Object> {
|
|||
boolean pushList() {
|
||||
ArrayList<Object> list = new ArrayList<Object>();
|
||||
while (peek() != ArrayList.class) {
|
||||
list.add(0, pop());
|
||||
Object listItem = pop();
|
||||
if (list.isEmpty() || list.get(0).getClass().isAssignableFrom(listItem.getClass()) || listItem.getClass().isAssignableFrom(list.get(0).getClass())) {
|
||||
list.add(0, listItem);
|
||||
} else {
|
||||
results().errors.append("Attempt to create mixed array!");
|
||||
}
|
||||
}
|
||||
|
||||
poke(list);
|
||||
|
|
184
src/test/java/com/moandjiezana/toml/BurntSushiTest.java
Normal file
184
src/test/java/com/moandjiezana/toml/BurntSushiTest.java
Normal file
|
@ -0,0 +1,184 @@
|
|||
package com.moandjiezana.toml;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.lang.reflect.Type;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.TimeZone;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.GsonBuilder;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonObject;
|
||||
import com.google.gson.JsonPrimitive;
|
||||
import com.google.gson.JsonSerializationContext;
|
||||
import com.google.gson.JsonSerializer;
|
||||
|
||||
public class BurntSushiTest {
|
||||
|
||||
private InputStream inputToml;
|
||||
private InputStreamReader expectedJsonReader;
|
||||
|
||||
private static final Gson TEST_GSON = new GsonBuilder()
|
||||
.registerTypeAdapter(Boolean.class, serialize(Boolean.class))
|
||||
.registerTypeAdapter(String.class, serialize(String.class))
|
||||
.registerTypeAdapter(Date.class, new JsonSerializer<Date>() {
|
||||
@Override
|
||||
public JsonElement serialize(Date src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
DateFormat iso8601Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
|
||||
iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC"));
|
||||
return context.serialize(new Value("datetime", iso8601Format.format(src)));
|
||||
}
|
||||
})
|
||||
.registerTypeHierarchyAdapter(Number.class, new JsonSerializer<Number>() {
|
||||
@Override
|
||||
public JsonElement serialize(Number src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
String number = src.toString();
|
||||
String type = number.contains(".") ? "float" : "integer";
|
||||
|
||||
return context.serialize(new Value(type, number));
|
||||
}
|
||||
})
|
||||
.registerTypeHierarchyAdapter(List.class, new JsonSerializer<List<?>>() {
|
||||
@Override
|
||||
public JsonElement serialize(List<?> src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonArray array = new JsonArray();
|
||||
for (Object o : src) {
|
||||
array.add(context.serialize(o));
|
||||
}
|
||||
|
||||
if (!src.isEmpty() && src.get(0) instanceof Map) {
|
||||
return array;
|
||||
}
|
||||
|
||||
JsonObject object = new JsonObject();
|
||||
object.add("type", new JsonPrimitive("array"));
|
||||
object.add("value", array);
|
||||
|
||||
return object;
|
||||
}
|
||||
})
|
||||
.registerTypeAdapter(Value.class, new JsonSerializer<Value>() {
|
||||
@Override
|
||||
public JsonElement serialize(Value src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
JsonObject object = new JsonObject();
|
||||
object.add("type", new JsonPrimitive(src.type));
|
||||
object.add("value", new JsonPrimitive(src.value));
|
||||
|
||||
return object;
|
||||
}
|
||||
})
|
||||
.create();
|
||||
|
||||
@Test
|
||||
public void comments_everywhere() throws Exception {
|
||||
inputToml = getClass().getResourceAsStream("burntsushi/valid/comments_everywhere.toml");
|
||||
expectedJsonReader = new InputStreamReader(getClass().getResourceAsStream("burntsushi/valid/comments_everywhere.json"));
|
||||
JsonElement expectedJson = new Gson().fromJson(expectedJsonReader, JsonElement.class);
|
||||
|
||||
JsonElement actual = new Toml().parse(inputToml).to(JsonElement.class, TEST_GSON);
|
||||
|
||||
Assert.assertEquals(expectedJson, actual);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void key_special_chars() throws Exception {
|
||||
runValidTest("key-special-chars");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void table_array_implicit() throws Exception {
|
||||
runValidTest("table-array-implicit");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void array_mixed_types_ints_and_floats() throws Exception {
|
||||
runInvalidTest("array-mixed-types-ints-and-floats");
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() throws IOException {
|
||||
inputToml.close();
|
||||
if (expectedJsonReader != null) {
|
||||
expectedJsonReader.close();
|
||||
}
|
||||
}
|
||||
|
||||
private void runValidTest(String testName) {
|
||||
inputToml = getClass().getResourceAsStream("burntsushi/valid/" + testName + ".toml");
|
||||
expectedJsonReader = new InputStreamReader(getClass().getResourceAsStream("burntsushi/valid/" + testName + ".json"));
|
||||
JsonElement expectedJson = new Gson().fromJson(expectedJsonReader, JsonElement.class);
|
||||
|
||||
Toml toml = new Toml().parse(inputToml);
|
||||
JsonElement actual = toml.to(JsonElement.class, TEST_GSON);
|
||||
|
||||
Assert.assertEquals(expectedJson, actual);
|
||||
}
|
||||
|
||||
private void runInvalidTest(String testName) {
|
||||
inputToml = getClass().getResourceAsStream("burntsushi/invalid/" + testName + ".toml");
|
||||
|
||||
try {
|
||||
new Toml().parse(inputToml);
|
||||
Assert.fail("Should have rejected invalid input!");
|
||||
} catch (IllegalStateException e) {
|
||||
// success
|
||||
}
|
||||
}
|
||||
|
||||
private static class Value {
|
||||
public final String type;
|
||||
public final String value;
|
||||
|
||||
public Value(String type, String value) {
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> JsonSerializer<T> serialize(final Class<T> aClass) {
|
||||
return new JsonSerializer<T>() {
|
||||
@Override
|
||||
public JsonElement serialize(T src, Type typeOfSrc, JsonSerializationContext context) {
|
||||
return context.serialize(new Value(toTomlType(aClass), src.toString()));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static String toTomlType(Class<?> aClass) {
|
||||
if (aClass == String.class) {
|
||||
return "string";
|
||||
}
|
||||
|
||||
if (aClass == Float.class || aClass == Double.class) {
|
||||
return "float";
|
||||
}
|
||||
|
||||
if (Number.class.isAssignableFrom(aClass)) {
|
||||
return "integer";
|
||||
}
|
||||
|
||||
if (aClass == Date.class) {
|
||||
return "datetime";
|
||||
}
|
||||
|
||||
if (aClass == Boolean.class) {
|
||||
return "bool";
|
||||
}
|
||||
|
||||
return "array";
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
ints-and-floats = [1, 1.0]
|
|
@ -0,0 +1,12 @@
|
|||
{
|
||||
"group": {
|
||||
"answer": {"type": "integer", "value": "42"},
|
||||
"more": {
|
||||
"type": "array",
|
||||
"value": [
|
||||
{"type": "integer", "value": "42"},
|
||||
{"type": "integer", "value": "42"}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
# Top comment.
|
||||
# Top comment.
|
||||
# Top comment.
|
||||
|
||||
# [no-extraneous-groups-please]
|
||||
|
||||
[group] # Comment
|
||||
answer = 42 # Comment
|
||||
# no-extraneous-keys-please = 999
|
||||
# Inbetween comment.
|
||||
more = [ # Comment
|
||||
# What about multiple # comments?
|
||||
# Can you handle it?
|
||||
#
|
||||
# Evil.
|
||||
# Evil.
|
||||
42, 42, # Comments within arrays are fun.
|
||||
# What about multiple # comments?
|
||||
# Can you handle it?
|
||||
#
|
||||
# Evil.
|
||||
# Evil.
|
||||
# ] Did I fool you?
|
||||
] # Hopefully not.
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"albums": {
|
||||
"songs": [
|
||||
{"name": {"type": "string", "value": "Glory Days"}}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
[[albums.songs]]
|
||||
name = "Glory Days"
|
Loading…
Add table
Add a link
Reference in a new issue