feat: add display UI with splash screen, dashboard, and RSSI sparkline
Implement full SSD1306 OLED display support: - Splash screen on boot (1.5s) with project name, version, board - Dashboard showing radio state, config, counters, RSSI/SNR - RSSI history sparkline (64-sample ring buffer, 2px-wide bars) - DisplayOn/DisplayOff host commands routed via dedicated channel - Pure render functions against generic DrawTarget (no hardware coupling) - Display on/off control bypasses radio task entirely Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
17624 files changed
+4564928
-38
No files matched your search
Vendored
+1
@@ -0,0 +1 @@
|
||||
Tests are from https://github.com/BurntSushi/toml-test
|
||||
Vendored
+142
@@ -0,0 +1,142 @@
|
||||
use serde_json::Value;
|
||||
|
||||
macro_rules! bad {
|
||||
($toml:expr, $msg:expr) => {
|
||||
match basic_toml::from_str::<Value>($toml) {
|
||||
Ok(s) => panic!("parsed to: {:#?}", s),
|
||||
Err(e) => assert_eq!(e.to_string(), $msg),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn times() {
|
||||
fn multi_bad(s: &str, msg: &str) {
|
||||
bad!(s, msg);
|
||||
bad!(&s.replace('T', " "), msg);
|
||||
bad!(&s.replace('T', "t"), msg);
|
||||
bad!(&s.replace('Z', "z"), msg);
|
||||
}
|
||||
|
||||
multi_bad(
|
||||
"foo = 1997-09-09T09:09:09Z",
|
||||
"invalid number at line 1 column 7",
|
||||
);
|
||||
multi_bad(
|
||||
"foo = 1997-09-09T09:09:09+09:09",
|
||||
"invalid number at line 1 column 7",
|
||||
);
|
||||
multi_bad(
|
||||
"foo = 1997-09-09T09:09:09-09:09",
|
||||
"invalid number at line 1 column 7",
|
||||
);
|
||||
multi_bad(
|
||||
"foo = 1997-09-09T09:09:09",
|
||||
"invalid number at line 1 column 7",
|
||||
);
|
||||
multi_bad("foo = 1997-09-09", "invalid number at line 1 column 7");
|
||||
bad!("foo = 1997-09-09 ", "invalid number at line 1 column 7");
|
||||
bad!(
|
||||
"foo = 1997-09-09 # comment",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
multi_bad("foo = 09:09:09", "invalid number at line 1 column 8");
|
||||
multi_bad(
|
||||
"foo = 1997-09-09T09:09:09.09Z",
|
||||
"invalid number at line 1 column 7",
|
||||
);
|
||||
multi_bad(
|
||||
"foo = 1997-09-09T09:09:09.09+09:09",
|
||||
"invalid number at line 1 column 7",
|
||||
);
|
||||
multi_bad(
|
||||
"foo = 1997-09-09T09:09:09.09-09:09",
|
||||
"invalid number at line 1 column 7",
|
||||
);
|
||||
multi_bad(
|
||||
"foo = 1997-09-09T09:09:09.09",
|
||||
"invalid number at line 1 column 7",
|
||||
);
|
||||
multi_bad("foo = 09:09:09.09", "invalid number at line 1 column 8");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad_times() {
|
||||
bad!("foo = 199-09-09", "invalid number at line 1 column 7");
|
||||
bad!("foo = 199709-09", "invalid number at line 1 column 7");
|
||||
bad!("foo = 1997-9-09", "invalid number at line 1 column 7");
|
||||
bad!("foo = 1997-09-9", "invalid number at line 1 column 7");
|
||||
bad!(
|
||||
"foo = 1997-09-0909:09:09",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = 1997-09-09T09:09:09.",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = T",
|
||||
"invalid TOML value, did you mean to use a quoted string? at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = T.",
|
||||
"invalid TOML value, did you mean to use a quoted string? at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = TZ",
|
||||
"invalid TOML value, did you mean to use a quoted string? at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = 1997-09-09T09:09:09.09+",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = 1997-09-09T09:09:09.09+09",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = 1997-09-09T09:09:09.09+09:9",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = 1997-09-09T09:09:09.09+0909",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = 1997-09-09T09:09:09.09-",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = 1997-09-09T09:09:09.09-09",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = 1997-09-09T09:09:09.09-09:9",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = 1997-09-09T09:09:09.09-0909",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
|
||||
bad!(
|
||||
"foo = 1997-00-09T09:09:09.09Z",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = 1997-09-00T09:09:09.09Z",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = 1997-09-09T30:09:09.09Z",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = 1997-09-09T12:69:09.09Z",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = 1997-09-09T12:09:69.09Z",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
}
|
||||
Vendored
+354
@@ -0,0 +1,354 @@
|
||||
#![allow(
|
||||
clippy::elidable_lifetime_names,
|
||||
clippy::needless_lifetimes,
|
||||
clippy::too_many_lines
|
||||
)]
|
||||
|
||||
use serde::{de, Deserialize};
|
||||
use std::fmt;
|
||||
|
||||
macro_rules! bad {
|
||||
($toml:expr, $ty:ty, $msg:expr) => {
|
||||
match basic_toml::from_str::<$ty>($toml) {
|
||||
Ok(s) => panic!("parsed to: {:#?}", s),
|
||||
Err(e) => assert_eq!(e.to_string(), $msg),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq)]
|
||||
struct Parent<T> {
|
||||
p_a: T,
|
||||
p_b: Vec<Child<T>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct Child<T> {
|
||||
c_a: T,
|
||||
c_b: T,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
enum CasedString {
|
||||
Lowercase(String),
|
||||
Uppercase(String),
|
||||
}
|
||||
|
||||
impl<'de> de::Deserialize<'de> for CasedString {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: de::Deserializer<'de>,
|
||||
{
|
||||
struct CasedStringVisitor;
|
||||
|
||||
impl<'de> de::Visitor<'de> for CasedStringVisitor {
|
||||
type Value = CasedString;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
formatter.write_str("a string")
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, s: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
if s.is_empty() {
|
||||
Err(de::Error::invalid_length(0, &"a non-empty string"))
|
||||
} else if s.chars().all(|x| x.is_ascii_lowercase()) {
|
||||
Ok(CasedString::Lowercase(s.to_string()))
|
||||
} else if s.chars().all(|x| x.is_ascii_uppercase()) {
|
||||
Ok(CasedString::Uppercase(s.to_string()))
|
||||
} else {
|
||||
Err(de::Error::invalid_value(
|
||||
de::Unexpected::Str(s),
|
||||
&"all lowercase or all uppercase",
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_any(CasedStringVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn custom_errors() {
|
||||
basic_toml::from_str::<Parent<CasedString>>(
|
||||
"
|
||||
p_a = 'a'
|
||||
p_b = [{c_a = 'a', c_b = 'c'}]
|
||||
",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
// Custom error at p_b value.
|
||||
bad!(
|
||||
"
|
||||
p_a = ''
|
||||
# ^
|
||||
",
|
||||
Parent<CasedString>,
|
||||
"invalid length 0, expected a non-empty string for key `p_a` at line 2 column 19"
|
||||
);
|
||||
|
||||
// Missing field in table.
|
||||
bad!(
|
||||
"
|
||||
p_a = 'a'
|
||||
# ^
|
||||
",
|
||||
Parent<CasedString>,
|
||||
"missing field `p_b` at line 1 column 1"
|
||||
);
|
||||
|
||||
// Invalid type in p_b.
|
||||
bad!(
|
||||
"
|
||||
p_a = 'a'
|
||||
p_b = 1
|
||||
# ^
|
||||
",
|
||||
Parent<CasedString>,
|
||||
"invalid type: integer `1`, expected a sequence for key `p_b` at line 3 column 19"
|
||||
);
|
||||
|
||||
// Sub-table in Vec is missing a field.
|
||||
bad!(
|
||||
"
|
||||
p_a = 'a'
|
||||
p_b = [
|
||||
{c_a = 'a'}
|
||||
# ^
|
||||
]
|
||||
",
|
||||
Parent<CasedString>,
|
||||
"missing field `c_b` for key `p_b` at line 4 column 17"
|
||||
);
|
||||
|
||||
// Sub-table in Vec has a field with a bad value.
|
||||
bad!(
|
||||
"
|
||||
p_a = 'a'
|
||||
p_b = [
|
||||
{c_a = 'a', c_b = '*'}
|
||||
# ^
|
||||
]
|
||||
",
|
||||
Parent<CasedString>,
|
||||
"invalid value: string \"*\", expected all lowercase or all uppercase for key `p_b` at line 4 column 35"
|
||||
);
|
||||
|
||||
// Sub-table in Vec is missing a field.
|
||||
bad!(
|
||||
"
|
||||
p_a = 'a'
|
||||
p_b = [
|
||||
{c_a = 'a', c_b = 'b'},
|
||||
{c_a = 'aa'}
|
||||
# ^
|
||||
]
|
||||
",
|
||||
Parent<CasedString>,
|
||||
"missing field `c_b` for key `p_b` at line 5 column 17"
|
||||
);
|
||||
|
||||
// Sub-table in the middle of a Vec is missing a field.
|
||||
bad!(
|
||||
"
|
||||
p_a = 'a'
|
||||
p_b = [
|
||||
{c_a = 'a', c_b = 'b'},
|
||||
{c_a = 'aa'},
|
||||
# ^
|
||||
{c_a = 'aaa', c_b = 'bbb'},
|
||||
]
|
||||
",
|
||||
Parent<CasedString>,
|
||||
"missing field `c_b` for key `p_b` at line 5 column 17"
|
||||
);
|
||||
|
||||
// Sub-table in the middle of a Vec has a field with a bad value.
|
||||
bad!(
|
||||
"
|
||||
p_a = 'a'
|
||||
p_b = [
|
||||
{c_a = 'a', c_b = 'b'},
|
||||
{c_a = 'aa', c_b = 1},
|
||||
# ^
|
||||
{c_a = 'aaa', c_b = 'bbb'},
|
||||
]
|
||||
",
|
||||
Parent<CasedString>,
|
||||
"invalid type: integer `1`, expected a string for key `p_b` at line 5 column 36"
|
||||
);
|
||||
|
||||
// Sub-table in the middle of a Vec has an extra field.
|
||||
// FIXME: This location could be better.
|
||||
bad!(
|
||||
"
|
||||
p_a = 'a'
|
||||
p_b = [
|
||||
{c_a = 'a', c_b = 'b'},
|
||||
{c_a = 'aa', c_b = 'bb', c_d = 'd'},
|
||||
# ^
|
||||
{c_a = 'aaa', c_b = 'bbb'},
|
||||
{c_a = 'aaaa', c_b = 'bbbb'},
|
||||
]
|
||||
",
|
||||
Parent<CasedString>,
|
||||
"unknown field `c_d`, expected `c_a` or `c_b` for key `p_b` at line 5 column 17"
|
||||
);
|
||||
|
||||
// Sub-table in the middle of a Vec is missing a field.
|
||||
// FIXME: This location is pretty off.
|
||||
bad!(
|
||||
"
|
||||
p_a = 'a'
|
||||
[[p_b]]
|
||||
c_a = 'a'
|
||||
c_b = 'b'
|
||||
[[p_b]]
|
||||
c_a = 'aa'
|
||||
# c_b = 'bb' # <- missing field
|
||||
[[p_b]]
|
||||
c_a = 'aaa'
|
||||
c_b = 'bbb'
|
||||
[[p_b]]
|
||||
# ^
|
||||
c_a = 'aaaa'
|
||||
c_b = 'bbbb'
|
||||
",
|
||||
Parent<CasedString>,
|
||||
"missing field `c_b` for key `p_b` at line 12 column 13"
|
||||
);
|
||||
|
||||
// Sub-table in the middle of a Vec has a field with a bad value.
|
||||
bad!(
|
||||
"
|
||||
p_a = 'a'
|
||||
[[p_b]]
|
||||
c_a = 'a'
|
||||
c_b = 'b'
|
||||
[[p_b]]
|
||||
c_a = 'aa'
|
||||
c_b = '*'
|
||||
# ^
|
||||
[[p_b]]
|
||||
c_a = 'aaa'
|
||||
c_b = 'bbb'
|
||||
",
|
||||
Parent<CasedString>,
|
||||
"invalid value: string \"*\", expected all lowercase or all uppercase for key `p_b.c_b` at line 8 column 19"
|
||||
);
|
||||
|
||||
// Sub-table in the middle of a Vec has an extra field.
|
||||
// FIXME: This location is pretty off.
|
||||
bad!(
|
||||
"
|
||||
p_a = 'a'
|
||||
[[p_b]]
|
||||
c_a = 'a'
|
||||
c_b = 'b'
|
||||
[[p_b]]
|
||||
c_a = 'aa'
|
||||
c_d = 'dd' # unknown field
|
||||
[[p_b]]
|
||||
c_a = 'aaa'
|
||||
c_b = 'bbb'
|
||||
[[p_b]]
|
||||
# ^
|
||||
c_a = 'aaaa'
|
||||
c_b = 'bbbb'
|
||||
",
|
||||
Parent<CasedString>,
|
||||
"unknown field `c_d`, expected `c_a` or `c_b` for key `p_b` at line 12 column 13"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serde_derive_deserialize_errors() {
|
||||
bad!(
|
||||
"
|
||||
p_a = ''
|
||||
# ^
|
||||
",
|
||||
Parent<String>,
|
||||
"missing field `p_b` at line 1 column 1"
|
||||
);
|
||||
|
||||
bad!(
|
||||
"
|
||||
p_a = ''
|
||||
p_b = [
|
||||
{c_a = ''}
|
||||
# ^
|
||||
]
|
||||
",
|
||||
Parent<String>,
|
||||
"missing field `c_b` for key `p_b` at line 4 column 17"
|
||||
);
|
||||
|
||||
bad!(
|
||||
"
|
||||
p_a = ''
|
||||
p_b = [
|
||||
{c_a = '', c_b = 1}
|
||||
# ^
|
||||
]
|
||||
",
|
||||
Parent<String>,
|
||||
"invalid type: integer `1`, expected a string for key `p_b` at line 4 column 34"
|
||||
);
|
||||
|
||||
// FIXME: This location could be better.
|
||||
bad!(
|
||||
"
|
||||
p_a = ''
|
||||
p_b = [
|
||||
{c_a = '', c_b = '', c_d = ''},
|
||||
# ^
|
||||
]
|
||||
",
|
||||
Parent<String>,
|
||||
"unknown field `c_d`, expected `c_a` or `c_b` for key `p_b` at line 4 column 17"
|
||||
);
|
||||
|
||||
bad!(
|
||||
"
|
||||
p_a = 'a'
|
||||
p_b = [
|
||||
{c_a = '', c_b = 1, c_d = ''},
|
||||
# ^
|
||||
]
|
||||
",
|
||||
Parent<String>,
|
||||
"invalid type: integer `1`, expected a string for key `p_b` at line 4 column 34"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn error_handles_crlf() {
|
||||
bad!(
|
||||
"\r\n\
|
||||
[t1]\r\n\
|
||||
[t2]\r\n\
|
||||
a = 1\r\n\
|
||||
. = 2\r\n\
|
||||
",
|
||||
serde_json::Value,
|
||||
"expected a table key, found a period at line 5 column 1"
|
||||
);
|
||||
|
||||
// Should be the same as above.
|
||||
bad!(
|
||||
"\n\
|
||||
[t1]\n\
|
||||
[t2]\n\
|
||||
a = 1\n\
|
||||
. = 2\n\
|
||||
",
|
||||
serde_json::Value,
|
||||
"expected a table key, found a period at line 5 column 1"
|
||||
);
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Recipe {
|
||||
pub name: String,
|
||||
pub description: Option<String>,
|
||||
#[serde(default)]
|
||||
pub modules: Vec<Modules>,
|
||||
#[serde(default)]
|
||||
pub packages: Vec<Packages>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Modules {
|
||||
pub name: String,
|
||||
pub version: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Packages {
|
||||
pub name: String,
|
||||
pub version: Option<String>,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn both_ends() {
|
||||
let recipe_works = basic_toml::from_str::<Recipe>(
|
||||
r#"
|
||||
name = "testing"
|
||||
description = "example"
|
||||
modules = []
|
||||
|
||||
[[packages]]
|
||||
name = "base"
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
basic_toml::to_string(&recipe_works).unwrap();
|
||||
|
||||
let recipe_fails = basic_toml::from_str::<Recipe>(
|
||||
r#"
|
||||
name = "testing"
|
||||
description = "example"
|
||||
packages = []
|
||||
|
||||
[[modules]]
|
||||
name = "base"
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
let err = basic_toml::to_string(&recipe_fails).unwrap_err();
|
||||
assert_eq!(err.to_string(), "values must be emitted before tables");
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
#![allow(clippy::wildcard_imports)]
|
||||
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq)]
|
||||
struct Struct {
|
||||
value: Enum,
|
||||
}
|
||||
|
||||
#[derive(Debug, Deserialize, PartialEq)]
|
||||
enum Enum {
|
||||
Variant,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unknown_variant() {
|
||||
let error = basic_toml::from_str::<Struct>("value = \"NonExistent\"").unwrap_err();
|
||||
|
||||
assert_eq!(
|
||||
error.to_string(),
|
||||
"unknown variant `NonExistent`, expected `Variant` for key `value` at line 1 column 1"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn from_str() {
|
||||
let s = basic_toml::from_str::<Struct>("value = \"Variant\"").unwrap();
|
||||
|
||||
assert_eq!(Enum::Variant, s.value);
|
||||
}
|
||||
Vendored
+81
@@ -0,0 +1,81 @@
|
||||
#![allow(clippy::float_cmp)]
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
#[rustfmt::skip] // appears to be a bug in rustfmt to make this converge...
|
||||
macro_rules! float_inf_tests {
|
||||
($ty:ty) => {{
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct S {
|
||||
sf1: $ty,
|
||||
sf2: $ty,
|
||||
sf3: $ty,
|
||||
sf4: $ty,
|
||||
sf5: $ty,
|
||||
sf6: $ty,
|
||||
sf7: $ty,
|
||||
sf8: $ty,
|
||||
}
|
||||
let inf: S = basic_toml::from_str(
|
||||
"
|
||||
# infinity
|
||||
sf1 = inf # positive infinity
|
||||
sf2 = +inf # positive infinity
|
||||
sf3 = -inf # negative infinity
|
||||
|
||||
# not a number
|
||||
sf4 = nan # actual sNaN/qNaN encoding is implementation specific
|
||||
sf5 = +nan # same as `nan`
|
||||
sf6 = -nan # valid, actual encoding is implementation specific
|
||||
|
||||
# zero
|
||||
sf7 = +0.0
|
||||
sf8 = -0.0
|
||||
",
|
||||
)
|
||||
.expect("Parse infinities.");
|
||||
|
||||
assert!(inf.sf1.is_infinite());
|
||||
assert!(inf.sf1.is_sign_positive());
|
||||
assert!(inf.sf2.is_infinite());
|
||||
assert!(inf.sf2.is_sign_positive());
|
||||
assert!(inf.sf3.is_infinite());
|
||||
assert!(inf.sf3.is_sign_negative());
|
||||
|
||||
assert!(inf.sf4.is_nan());
|
||||
assert!(inf.sf4.is_sign_positive());
|
||||
assert!(inf.sf5.is_nan());
|
||||
assert!(inf.sf5.is_sign_positive());
|
||||
assert!(inf.sf6.is_nan());
|
||||
assert!(inf.sf6.is_sign_negative()); // NOTE: but serializes to just `nan`
|
||||
|
||||
assert_eq!(inf.sf7, 0.0);
|
||||
assert!(inf.sf7.is_sign_positive());
|
||||
assert_eq!(inf.sf8, 0.0);
|
||||
assert!(inf.sf8.is_sign_negative());
|
||||
|
||||
let s = basic_toml::to_string(&inf).unwrap();
|
||||
assert_eq!(
|
||||
s,
|
||||
"\
|
||||
sf1 = inf
|
||||
sf2 = inf
|
||||
sf3 = -inf
|
||||
sf4 = nan
|
||||
sf5 = nan
|
||||
sf6 = nan
|
||||
sf7 = 0.0
|
||||
sf8 = -0.0
|
||||
"
|
||||
);
|
||||
|
||||
basic_toml::from_str::<Value>(&s).expect("roundtrip");
|
||||
}};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn float_inf() {
|
||||
float_inf_tests!(f32);
|
||||
float_inf_tests!(f64);
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
use basic_toml::to_string;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||
struct User {
|
||||
pub name: String,
|
||||
pub surname: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||
struct Users {
|
||||
pub user: Vec<User>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)]
|
||||
struct TwoUsers {
|
||||
pub user0: User,
|
||||
pub user1: User,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_unnecessary_newlines_array() {
|
||||
assert!(!to_string(&Users {
|
||||
user: vec![
|
||||
User {
|
||||
name: "John".to_string(),
|
||||
surname: "Doe".to_string(),
|
||||
},
|
||||
User {
|
||||
name: "Jane".to_string(),
|
||||
surname: "Dough".to_string(),
|
||||
},
|
||||
],
|
||||
})
|
||||
.unwrap()
|
||||
.starts_with('\n'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn no_unnecessary_newlines_table() {
|
||||
assert!(!to_string(&TwoUsers {
|
||||
user0: User {
|
||||
name: "John".to_string(),
|
||||
surname: "Doe".to_string(),
|
||||
},
|
||||
user1: User {
|
||||
name: "Jane".to_string(),
|
||||
surname: "Dough".to_string(),
|
||||
},
|
||||
})
|
||||
.unwrap()
|
||||
.starts_with('\n'));
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"ints-and-floats": {
|
||||
"type": "array",
|
||||
"value": [
|
||||
{
|
||||
"type": "integer",
|
||||
"value": "1"
|
||||
},
|
||||
{
|
||||
"type": "float",
|
||||
"value": "1.1"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
use serde_json::Value;
|
||||
|
||||
macro_rules! bad {
|
||||
($toml:expr, $msg:expr) => {
|
||||
match basic_toml::from_str::<Value>($toml) {
|
||||
Ok(s) => panic!("parsed to: {:#?}", s),
|
||||
Err(e) => assert_eq!(e.to_string(), $msg),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad() {
|
||||
bad!("a = 01", "invalid number at line 1 column 6");
|
||||
bad!("a = 1__1", "invalid number at line 1 column 5");
|
||||
bad!("a = 1_", "invalid number at line 1 column 5");
|
||||
bad!("''", "expected an equals, found eof at line 1 column 3");
|
||||
bad!("a = 9e99999", "invalid number at line 1 column 5");
|
||||
|
||||
bad!(
|
||||
"a = \"\u{7f}\"",
|
||||
"invalid character in string: `\\u{7f}` at line 1 column 6"
|
||||
);
|
||||
bad!(
|
||||
"a = '\u{7f}'",
|
||||
"invalid character in string: `\\u{7f}` at line 1 column 6"
|
||||
);
|
||||
|
||||
bad!("a = -0x1", "invalid number at line 1 column 5");
|
||||
bad!("a = 0x-1", "invalid number at line 1 column 7");
|
||||
|
||||
// Dotted keys.
|
||||
bad!(
|
||||
"a.b.c = 1
|
||||
a.b = 2
|
||||
",
|
||||
"duplicate key: `b` for key `a` at line 2 column 12"
|
||||
);
|
||||
bad!(
|
||||
"a = 1
|
||||
a.b = 2",
|
||||
"dotted key attempted to extend non-table type at line 1 column 5"
|
||||
);
|
||||
bad!(
|
||||
"a = {k1 = 1, k1.name = \"joe\"}",
|
||||
"dotted key attempted to extend non-table type at line 1 column 11"
|
||||
);
|
||||
}
|
||||
Vendored
+226
@@ -0,0 +1,226 @@
|
||||
use serde_json::Value;
|
||||
|
||||
macro_rules! bad {
|
||||
($toml:expr, $msg:expr) => {
|
||||
match basic_toml::from_str::<Value>($toml) {
|
||||
Ok(s) => panic!("parsed to: {:#?}", s),
|
||||
Err(e) => assert_eq!(e.to_string(), $msg),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! test( ($name:ident, $s:expr, $msg:expr) => (
|
||||
#[test]
|
||||
fn $name() { bad!($s, $msg); }
|
||||
) );
|
||||
|
||||
test!(
|
||||
datetime_malformed_no_leads,
|
||||
include_str!("invalid/datetime-malformed-no-leads.toml"),
|
||||
"invalid number at line 1 column 12"
|
||||
);
|
||||
test!(
|
||||
datetime_malformed_no_secs,
|
||||
include_str!("invalid/datetime-malformed-no-secs.toml"),
|
||||
"invalid number at line 1 column 11"
|
||||
);
|
||||
test!(
|
||||
datetime_malformed_no_t,
|
||||
include_str!("invalid/datetime-malformed-no-t.toml"),
|
||||
"invalid number at line 1 column 8"
|
||||
);
|
||||
test!(
|
||||
datetime_malformed_with_milli,
|
||||
include_str!("invalid/datetime-malformed-with-milli.toml"),
|
||||
"invalid number at line 1 column 14"
|
||||
);
|
||||
test!(
|
||||
duplicate_key_table,
|
||||
include_str!("invalid/duplicate-key-table.toml"),
|
||||
"duplicate key: `type` for key `fruit` at line 4 column 8"
|
||||
);
|
||||
test!(
|
||||
duplicate_keys,
|
||||
include_str!("invalid/duplicate-keys.toml"),
|
||||
"duplicate key: `dupe` at line 2 column 1"
|
||||
);
|
||||
test!(
|
||||
duplicate_table,
|
||||
include_str!("invalid/duplicate-table.toml"),
|
||||
"redefinition of table `dependencies` for key `dependencies` at line 7 column 1"
|
||||
);
|
||||
test!(
|
||||
duplicate_tables,
|
||||
include_str!("invalid/duplicate-tables.toml"),
|
||||
"redefinition of table `a` for key `a` at line 2 column 1"
|
||||
);
|
||||
test!(
|
||||
empty_implicit_table,
|
||||
include_str!("invalid/empty-implicit-table.toml"),
|
||||
"expected a table key, found a period at line 1 column 10"
|
||||
);
|
||||
test!(
|
||||
empty_table,
|
||||
include_str!("invalid/empty-table.toml"),
|
||||
"expected a table key, found a right bracket at line 1 column 2"
|
||||
);
|
||||
test!(
|
||||
float_no_leading_zero,
|
||||
include_str!("invalid/float-no-leading-zero.toml"),
|
||||
"expected a value, found a period at line 1 column 10"
|
||||
);
|
||||
test!(
|
||||
float_no_suffix,
|
||||
include_str!("invalid/float-no-suffix.toml"),
|
||||
"invalid number at line 1 column 5"
|
||||
);
|
||||
test!(
|
||||
float_no_trailing_digits,
|
||||
include_str!("invalid/float-no-trailing-digits.toml"),
|
||||
"invalid number at line 1 column 12"
|
||||
);
|
||||
test!(
|
||||
key_after_array,
|
||||
include_str!("invalid/key-after-array.toml"),
|
||||
"expected newline, found an identifier at line 1 column 14"
|
||||
);
|
||||
test!(
|
||||
key_after_table,
|
||||
include_str!("invalid/key-after-table.toml"),
|
||||
"expected newline, found an identifier at line 1 column 11"
|
||||
);
|
||||
test!(
|
||||
key_empty,
|
||||
include_str!("invalid/key-empty.toml"),
|
||||
"expected a table key, found an equals at line 1 column 2"
|
||||
);
|
||||
test!(
|
||||
key_hash,
|
||||
include_str!("invalid/key-hash.toml"),
|
||||
"expected an equals, found a comment at line 1 column 2"
|
||||
);
|
||||
test!(
|
||||
key_newline,
|
||||
include_str!("invalid/key-newline.toml"),
|
||||
"expected an equals, found a newline at line 1 column 2"
|
||||
);
|
||||
test!(
|
||||
key_open_bracket,
|
||||
include_str!("invalid/key-open-bracket.toml"),
|
||||
"expected a right bracket, found an equals at line 1 column 6"
|
||||
);
|
||||
test!(
|
||||
key_single_open_bracket,
|
||||
include_str!("invalid/key-single-open-bracket.toml"),
|
||||
"expected a table key, found eof at line 1 column 2"
|
||||
);
|
||||
test!(
|
||||
key_space,
|
||||
include_str!("invalid/key-space.toml"),
|
||||
"expected an equals, found an identifier at line 1 column 3"
|
||||
);
|
||||
test!(
|
||||
key_start_bracket,
|
||||
include_str!("invalid/key-start-bracket.toml"),
|
||||
"expected a right bracket, found an equals at line 2 column 6"
|
||||
);
|
||||
test!(
|
||||
key_two_equals,
|
||||
include_str!("invalid/key-two-equals.toml"),
|
||||
"expected a value, found an equals at line 1 column 6"
|
||||
);
|
||||
test!(
|
||||
string_bad_byte_escape,
|
||||
include_str!("invalid/string-bad-byte-escape.toml"),
|
||||
"invalid escape character in string: `x` at line 1 column 13"
|
||||
);
|
||||
test!(
|
||||
string_bad_escape,
|
||||
include_str!("invalid/string-bad-escape.toml"),
|
||||
"invalid escape character in string: `a` at line 1 column 42"
|
||||
);
|
||||
test!(
|
||||
string_bad_line_ending_escape,
|
||||
include_str!("invalid/string-bad-line-ending-escape.toml"),
|
||||
"invalid escape character in string: ` ` at line 2 column 79"
|
||||
);
|
||||
test!(
|
||||
string_byte_escapes,
|
||||
include_str!("invalid/string-byte-escapes.toml"),
|
||||
"invalid escape character in string: `x` at line 1 column 12"
|
||||
);
|
||||
test!(
|
||||
string_no_close,
|
||||
include_str!("invalid/string-no-close.toml"),
|
||||
"newline in string found at line 1 column 42"
|
||||
);
|
||||
test!(
|
||||
table_array_implicit,
|
||||
include_str!("invalid/table-array-implicit.toml"),
|
||||
"table redefined as array for key `albums` at line 13 column 1"
|
||||
);
|
||||
test!(
|
||||
table_array_malformed_bracket,
|
||||
include_str!("invalid/table-array-malformed-bracket.toml"),
|
||||
"expected a right bracket, found a newline at line 1 column 10"
|
||||
);
|
||||
test!(
|
||||
table_array_malformed_empty,
|
||||
include_str!("invalid/table-array-malformed-empty.toml"),
|
||||
"expected a table key, found a right bracket at line 1 column 3"
|
||||
);
|
||||
test!(
|
||||
table_empty,
|
||||
include_str!("invalid/table-empty.toml"),
|
||||
"expected a table key, found a right bracket at line 1 column 2"
|
||||
);
|
||||
test!(
|
||||
table_nested_brackets_close,
|
||||
include_str!("invalid/table-nested-brackets-close.toml"),
|
||||
"expected newline, found an identifier at line 1 column 4"
|
||||
);
|
||||
test!(
|
||||
table_nested_brackets_open,
|
||||
include_str!("invalid/table-nested-brackets-open.toml"),
|
||||
"expected a right bracket, found a left bracket at line 1 column 3"
|
||||
);
|
||||
test!(
|
||||
table_whitespace,
|
||||
include_str!("invalid/table-whitespace.toml"),
|
||||
"expected a right bracket, found an identifier at line 1 column 10"
|
||||
);
|
||||
test!(
|
||||
table_with_pound,
|
||||
include_str!("invalid/table-with-pound.toml"),
|
||||
"expected a right bracket, found a comment at line 1 column 5"
|
||||
);
|
||||
test!(
|
||||
text_after_array_entries,
|
||||
include_str!("invalid/text-after-array-entries.toml"),
|
||||
"invalid TOML value, did you mean to use a quoted string? at line 2 column 46"
|
||||
);
|
||||
test!(
|
||||
text_after_integer,
|
||||
include_str!("invalid/text-after-integer.toml"),
|
||||
"expected newline, found an identifier at line 1 column 13"
|
||||
);
|
||||
test!(
|
||||
text_after_string,
|
||||
include_str!("invalid/text-after-string.toml"),
|
||||
"expected newline, found an identifier at line 1 column 41"
|
||||
);
|
||||
test!(
|
||||
text_after_table,
|
||||
include_str!("invalid/text-after-table.toml"),
|
||||
"expected newline, found an identifier at line 1 column 9"
|
||||
);
|
||||
test!(
|
||||
text_before_array_separator,
|
||||
include_str!("invalid/text-before-array-separator.toml"),
|
||||
"expected a right bracket, found an identifier at line 2 column 46"
|
||||
);
|
||||
test!(
|
||||
text_in_array,
|
||||
include_str!("invalid/text-in-array.toml"),
|
||||
"invalid TOML value, did you mean to use a quoted string? at line 3 column 3"
|
||||
);
|
||||
@@ -0,0 +1 @@
|
||||
no-leads = 1987-7-05T17:45:00Z
|
||||
@@ -0,0 +1 @@
|
||||
no-secs = 1987-07-05T17:45Z
|
||||
@@ -0,0 +1 @@
|
||||
no-t = 1987-07-0517:45:00Z
|
||||
@@ -0,0 +1 @@
|
||||
with-milli = 1987-07-5T17:45:00.12Z
|
||||
@@ -0,0 +1,5 @@
|
||||
[fruit]
|
||||
type = "apple"
|
||||
|
||||
[fruit.type]
|
||||
apple = "yes"
|
||||
@@ -0,0 +1,2 @@
|
||||
dupe = false
|
||||
dupe = true
|
||||
@@ -0,0 +1,8 @@
|
||||
[dependencies.openssl-sys]
|
||||
version = "0.5.2"
|
||||
|
||||
[dependencies]
|
||||
libc = "0.1"
|
||||
|
||||
[dependencies]
|
||||
bitflags = "0.1.1"
|
||||
@@ -0,0 +1,2 @@
|
||||
[a]
|
||||
[a]
|
||||
@@ -0,0 +1 @@
|
||||
[naughty..naughty]
|
||||
@@ -0,0 +1 @@
|
||||
[]
|
||||
@@ -0,0 +1,2 @@
|
||||
answer = .12345
|
||||
neganswer = -.12345
|
||||
@@ -0,0 +1 @@
|
||||
a = 1.2f
|
||||
@@ -0,0 +1,2 @@
|
||||
answer = 1.
|
||||
neganswer = -1.
|
||||
@@ -0,0 +1 @@
|
||||
[[agencies]] owner = "S Cjelli"
|
||||
@@ -0,0 +1 @@
|
||||
[history] guard = "sleeping"
|
||||
@@ -0,0 +1 @@
|
||||
= 1
|
||||
@@ -0,0 +1 @@
|
||||
a# = 1
|
||||
@@ -0,0 +1,2 @@
|
||||
a
|
||||
= 1
|
||||
@@ -0,0 +1 @@
|
||||
[abc = 1
|
||||
@@ -0,0 +1 @@
|
||||
[
|
||||
@@ -0,0 +1 @@
|
||||
a b = 1
|
||||
@@ -0,0 +1,3 @@
|
||||
[a]
|
||||
[xyz = 5
|
||||
[b]
|
||||
@@ -0,0 +1 @@
|
||||
key= = 1
|
||||
@@ -0,0 +1 @@
|
||||
naughty = "\xAg"
|
||||
@@ -0,0 +1 @@
|
||||
invalid-escape = "This string has a bad \a escape character."
|
||||
@@ -0,0 +1,3 @@
|
||||
invalid-escape = """\
|
||||
This string has a non whitespace-character after the line ending escape. \ a
|
||||
"""
|
||||
@@ -0,0 +1 @@
|
||||
answer = "\x33"
|
||||
@@ -0,0 +1 @@
|
||||
no-ending-quote = "One time, at band camp
|
||||
@@ -0,0 +1,14 @@
|
||||
# This test is a bit tricky. It should fail because the first use of
|
||||
# `[[albums.songs]]` without first declaring `albums` implies that `albums`
|
||||
# must be a table. The alternative would be quite weird. Namely, it wouldn't
|
||||
# comply with the TOML spec: "Each double-bracketed sub-table will belong to
|
||||
# the most *recently* defined table element *above* it."
|
||||
#
|
||||
# This is in contrast to the *valid* test, table-array-implicit where
|
||||
# `[[albums.songs]]` works by itself, so long as `[[albums]]` isn't declared
|
||||
# later. (Although, `[albums]` could be.)
|
||||
[[albums.songs]]
|
||||
name = "Glory Days"
|
||||
|
||||
[[albums]]
|
||||
name = "Born in the USA"
|
||||
@@ -0,0 +1,2 @@
|
||||
[[albums]
|
||||
name = "Born to Run"
|
||||
@@ -0,0 +1,2 @@
|
||||
[[]]
|
||||
name = "Born to Run"
|
||||
@@ -0,0 +1 @@
|
||||
[]
|
||||
@@ -0,0 +1,2 @@
|
||||
[a]b]
|
||||
zyx = 42
|
||||
@@ -0,0 +1,2 @@
|
||||
[a[b]
|
||||
zyx = 42
|
||||
@@ -0,0 +1 @@
|
||||
[invalid key]
|
||||
@@ -0,0 +1,2 @@
|
||||
[key#group]
|
||||
answer = 42
|
||||
@@ -0,0 +1,4 @@
|
||||
array = [
|
||||
"Is there life after an array separator?", No
|
||||
"Entry"
|
||||
]
|
||||
@@ -0,0 +1 @@
|
||||
answer = 42 the ultimate answer?
|
||||
@@ -0,0 +1 @@
|
||||
string = "Is there life after strings?" No.
|
||||
@@ -0,0 +1 @@
|
||||
[error] this shouldn't be here
|
||||
@@ -0,0 +1,4 @@
|
||||
array = [
|
||||
"Is there life before an array separator?" No,
|
||||
"Entry"
|
||||
]
|
||||
@@ -0,0 +1,5 @@
|
||||
array = [
|
||||
"Entry 1",
|
||||
I don't belong,
|
||||
"Entry 2",
|
||||
]
|
||||
Vendored
+687
@@ -0,0 +1,687 @@
|
||||
#![allow(clippy::let_underscore_untyped, clippy::uninlined_format_args)]
|
||||
|
||||
use serde_json::{json, Value};
|
||||
|
||||
macro_rules! bad {
|
||||
($toml:expr, $msg:expr) => {
|
||||
match basic_toml::from_str::<Value>($toml) {
|
||||
Ok(s) => panic!("parsed to: {:#?}", s),
|
||||
Err(e) => assert_eq!(e.to_string(), $msg),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn crlf() {
|
||||
let toml = "\
|
||||
[project]\r\n\
|
||||
\r\n\
|
||||
name = \"splay\"\r\n\
|
||||
version = \"0.1.0\"\r\n\
|
||||
authors = [\"alex@crichton.co\"]\r\n\
|
||||
\r\n\
|
||||
[[lib]]\r\n\
|
||||
\r\n\
|
||||
path = \"lib.rs\"\r\n\
|
||||
name = \"splay\"\r\n\
|
||||
description = \"\"\"\
|
||||
A Rust implementation of a TAR file reader and writer. This library does not\r\n\
|
||||
currently handle compression, but it is abstract over all I/O readers and\r\n\
|
||||
writers. Additionally, great lengths are taken to ensure that the entire\r\n\
|
||||
contents are never required to be entirely resident in memory all at once.\r\n\
|
||||
\"\"\"\
|
||||
";
|
||||
basic_toml::from_str::<Value>(toml).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fun_with_strings() {
|
||||
let toml = r#"
|
||||
bar = "\U00000000"
|
||||
key1 = "One\nTwo"
|
||||
key2 = """One\nTwo"""
|
||||
key3 = """
|
||||
One
|
||||
Two"""
|
||||
|
||||
key4 = "The quick brown fox jumps over the lazy dog."
|
||||
key5 = """
|
||||
The quick brown \
|
||||
|
||||
|
||||
fox jumps over \
|
||||
the lazy dog."""
|
||||
key6 = """\
|
||||
The quick brown \
|
||||
fox jumps over \
|
||||
the lazy dog.\
|
||||
"""
|
||||
# What you see is what you get.
|
||||
winpath = 'C:\Users\nodejs\templates'
|
||||
winpath2 = '\\ServerX\admin$\system32\'
|
||||
quoted = 'Tom "Dubs" Preston-Werner'
|
||||
regex = '<\i\c*\s*>'
|
||||
|
||||
regex2 = '''I [dw]on't need \d{2} apples'''
|
||||
lines = '''
|
||||
The first newline is
|
||||
trimmed in raw strings.
|
||||
All other whitespace
|
||||
is preserved.
|
||||
'''
|
||||
"#;
|
||||
let table: Value = basic_toml::from_str(toml).unwrap();
|
||||
assert_eq!(table["bar"], json!("\0"));
|
||||
assert_eq!(table["key1"], json!("One\nTwo"));
|
||||
assert_eq!(table["key2"], json!("One\nTwo"));
|
||||
assert_eq!(table["key3"], json!("One\nTwo"));
|
||||
|
||||
let msg = "The quick brown fox jumps over the lazy dog.";
|
||||
assert_eq!(table["key4"], json!(msg));
|
||||
assert_eq!(table["key5"], json!(msg));
|
||||
assert_eq!(table["key6"], json!(msg));
|
||||
|
||||
assert_eq!(table["winpath"], json!(r"C:\Users\nodejs\templates"));
|
||||
assert_eq!(table["winpath2"], json!(r"\\ServerX\admin$\system32\"));
|
||||
assert_eq!(table["quoted"], json!(r#"Tom "Dubs" Preston-Werner"#));
|
||||
assert_eq!(table["regex"], json!(r"<\i\c*\s*>"));
|
||||
assert_eq!(table["regex2"], json!(r"I [dw]on't need \d{2} apples"));
|
||||
assert_eq!(
|
||||
table["lines"],
|
||||
json!(
|
||||
"The first newline is\n\
|
||||
trimmed in raw strings.\n\
|
||||
All other whitespace\n\
|
||||
is preserved.\n"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn tables_in_arrays() {
|
||||
let toml = "
|
||||
[[foo]]
|
||||
#…
|
||||
[foo.bar]
|
||||
#…
|
||||
|
||||
[[foo]] # ...
|
||||
#…
|
||||
[foo.bar]
|
||||
#...
|
||||
";
|
||||
let table: Value = basic_toml::from_str(toml).unwrap();
|
||||
table["foo"][0]["bar"].as_object().unwrap();
|
||||
table["foo"][1]["bar"].as_object().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_table() {
|
||||
let toml = "
|
||||
[foo]";
|
||||
let table: Value = basic_toml::from_str(toml).unwrap();
|
||||
table["foo"].as_object().unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fruit() {
|
||||
let toml = r#"
|
||||
[[fruit]]
|
||||
name = "apple"
|
||||
|
||||
[fruit.physical]
|
||||
color = "red"
|
||||
shape = "round"
|
||||
|
||||
[[fruit.variety]]
|
||||
name = "red delicious"
|
||||
|
||||
[[fruit.variety]]
|
||||
name = "granny smith"
|
||||
|
||||
[[fruit]]
|
||||
name = "banana"
|
||||
|
||||
[[fruit.variety]]
|
||||
name = "plantain"
|
||||
"#;
|
||||
let table: Value = basic_toml::from_str(toml).unwrap();
|
||||
assert_eq!(table["fruit"][0]["name"], json!("apple"));
|
||||
assert_eq!(table["fruit"][0]["physical"]["color"], json!("red"));
|
||||
assert_eq!(table["fruit"][0]["physical"]["shape"], json!("round"));
|
||||
assert_eq!(
|
||||
table["fruit"][0]["variety"][0]["name"],
|
||||
json!("red delicious")
|
||||
);
|
||||
assert_eq!(
|
||||
table["fruit"][0]["variety"][1]["name"],
|
||||
json!("granny smith")
|
||||
);
|
||||
assert_eq!(table["fruit"][1]["name"], json!("banana"));
|
||||
assert_eq!(table["fruit"][1]["variety"][0]["name"], json!("plantain"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn stray_cr() {
|
||||
bad!("\r", "unexpected character found: `\\r` at line 1 column 1");
|
||||
bad!(
|
||||
"a = [ \r ]",
|
||||
"unexpected character found: `\\r` at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"a = \"\"\"\r\"\"\"",
|
||||
"invalid character in string: `\\r` at line 1 column 8"
|
||||
);
|
||||
bad!(
|
||||
"a = \"\"\"\\ \r \"\"\"",
|
||||
"invalid escape character in string: ` ` at line 1 column 9"
|
||||
);
|
||||
bad!(
|
||||
"a = '''\r'''",
|
||||
"invalid character in string: `\\r` at line 1 column 8"
|
||||
);
|
||||
bad!(
|
||||
"a = '\r'",
|
||||
"invalid character in string: `\\r` at line 1 column 6"
|
||||
);
|
||||
bad!(
|
||||
"a = \"\r\"",
|
||||
"invalid character in string: `\\r` at line 1 column 6"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn blank_literal_string() {
|
||||
let table: Value = basic_toml::from_str("foo = ''").unwrap();
|
||||
assert_eq!(table["foo"], json!(""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn many_blank() {
|
||||
let table: Value = basic_toml::from_str("foo = \"\"\"\n\n\n\"\"\"").unwrap();
|
||||
assert_eq!(table["foo"], json!("\n\n"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn literal_eats_crlf() {
|
||||
let toml = "
|
||||
foo = \"\"\"\\\r\n\"\"\"
|
||||
bar = \"\"\"\\\r\n \r\n \r\n a\"\"\"
|
||||
";
|
||||
let table: Value = basic_toml::from_str(toml).unwrap();
|
||||
assert_eq!(table["foo"], json!(""));
|
||||
assert_eq!(table["bar"], json!("a"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn string_no_newline() {
|
||||
bad!("a = \"\n\"", "newline in string found at line 1 column 6");
|
||||
bad!("a = '\n'", "newline in string found at line 1 column 6");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad_leading_zeros() {
|
||||
bad!("a = 00", "invalid number at line 1 column 6");
|
||||
bad!("a = -00", "invalid number at line 1 column 7");
|
||||
bad!("a = +00", "invalid number at line 1 column 7");
|
||||
bad!("a = 00.0", "invalid number at line 1 column 6");
|
||||
bad!("a = -00.0", "invalid number at line 1 column 7");
|
||||
bad!("a = +00.0", "invalid number at line 1 column 7");
|
||||
bad!(
|
||||
"a = 9223372036854775808",
|
||||
"invalid number at line 1 column 5"
|
||||
);
|
||||
bad!(
|
||||
"a = -9223372036854775809",
|
||||
"invalid number at line 1 column 5"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad_floats() {
|
||||
bad!("a = 0.", "invalid number at line 1 column 7");
|
||||
bad!("a = 0.e", "invalid number at line 1 column 7");
|
||||
bad!("a = 0.E", "invalid number at line 1 column 7");
|
||||
bad!("a = 0.0E", "invalid number at line 1 column 5");
|
||||
bad!("a = 0.0e", "invalid number at line 1 column 5");
|
||||
bad!("a = 0.0e-", "invalid number at line 1 column 9");
|
||||
bad!("a = 0.0e+", "invalid number at line 1 column 5");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn floats() {
|
||||
macro_rules! t {
|
||||
($actual:expr, $expected:expr) => {{
|
||||
let f = format!("foo = {}", $actual);
|
||||
println!("{}", f);
|
||||
let a: Value = basic_toml::from_str(&f).unwrap();
|
||||
assert_eq!(a["foo"], json!($expected));
|
||||
}};
|
||||
}
|
||||
|
||||
t!("1.0", 1.0);
|
||||
t!("1.0e0", 1.0);
|
||||
t!("1.0e+0", 1.0);
|
||||
t!("1.0e-0", 1.0);
|
||||
t!("1E-0", 1.0);
|
||||
t!("1.001e-0", 1.001);
|
||||
t!("2e10", 2e10);
|
||||
t!("2e+10", 2e10);
|
||||
t!("2e-10", 2e-10);
|
||||
t!("2_0.0", 20.0);
|
||||
t!("2_0.0_0e1_0", 20.0e10);
|
||||
t!("2_0.1_0e1_0", 20.1e10);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bare_key_names() {
|
||||
let toml = "
|
||||
foo = 3
|
||||
foo_3 = 3
|
||||
foo_-2--3--r23f--4-f2-4 = 3
|
||||
_ = 3
|
||||
- = 3
|
||||
8 = 8
|
||||
\"a\" = 3
|
||||
\"!\" = 3
|
||||
\"a^b\" = 3
|
||||
\"\\\"\" = 3
|
||||
\"character encoding\" = \"value\"
|
||||
'ʎǝʞ' = \"value\"
|
||||
";
|
||||
let a: Value = basic_toml::from_str(toml).unwrap();
|
||||
let _ = &a["foo"];
|
||||
let _ = &a["-"];
|
||||
let _ = &a["_"];
|
||||
let _ = &a["8"];
|
||||
let _ = &a["foo_3"];
|
||||
let _ = &a["foo_-2--3--r23f--4-f2-4"];
|
||||
let _ = &a["a"];
|
||||
let _ = &a["!"];
|
||||
let _ = &a["\""];
|
||||
let _ = &a["character encoding"];
|
||||
let _ = &a["ʎǝʞ"];
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad_keys() {
|
||||
bad!(
|
||||
"key\n=3",
|
||||
"expected an equals, found a newline at line 1 column 4"
|
||||
);
|
||||
bad!(
|
||||
"key=\n3",
|
||||
"expected a value, found a newline at line 1 column 5"
|
||||
);
|
||||
bad!(
|
||||
"key|=3",
|
||||
"unexpected character found: `|` at line 1 column 4"
|
||||
);
|
||||
bad!(
|
||||
"=3",
|
||||
"expected a table key, found an equals at line 1 column 1"
|
||||
);
|
||||
bad!(
|
||||
"\"\"|=3",
|
||||
"unexpected character found: `|` at line 1 column 3"
|
||||
);
|
||||
bad!("\"\n\"|=3", "newline in string found at line 1 column 2");
|
||||
bad!(
|
||||
"\"\r\"|=3",
|
||||
"invalid character in string: `\\r` at line 1 column 2"
|
||||
);
|
||||
bad!(
|
||||
"''''''=3",
|
||||
"multiline strings are not allowed for key at line 1 column 1"
|
||||
);
|
||||
bad!(
|
||||
"\"\"\"\"\"\"=3",
|
||||
"multiline strings are not allowed for key at line 1 column 1"
|
||||
);
|
||||
bad!(
|
||||
"'''key'''=3",
|
||||
"multiline strings are not allowed for key at line 1 column 1"
|
||||
);
|
||||
bad!(
|
||||
"\"\"\"key\"\"\"=3",
|
||||
"multiline strings are not allowed for key at line 1 column 1"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad_table_names() {
|
||||
bad!(
|
||||
"[]",
|
||||
"expected a table key, found a right bracket at line 1 column 2"
|
||||
);
|
||||
bad!(
|
||||
"[.]",
|
||||
"expected a table key, found a period at line 1 column 2"
|
||||
);
|
||||
bad!(
|
||||
"[a.]",
|
||||
"expected a table key, found a right bracket at line 1 column 4"
|
||||
);
|
||||
bad!("[!]", "unexpected character found: `!` at line 1 column 2");
|
||||
bad!("[\"\n\"]", "newline in string found at line 1 column 3");
|
||||
bad!(
|
||||
"[a.b]\n[a.\"b\"]",
|
||||
"redefinition of table `a.b` for key `a.b` at line 2 column 1"
|
||||
);
|
||||
bad!("[']", "unterminated string at line 1 column 2");
|
||||
bad!("[''']", "unterminated string at line 1 column 2");
|
||||
bad!(
|
||||
"['''''']",
|
||||
"multiline strings are not allowed for key at line 1 column 2"
|
||||
);
|
||||
bad!(
|
||||
"['''foo''']",
|
||||
"multiline strings are not allowed for key at line 1 column 2"
|
||||
);
|
||||
bad!(
|
||||
"[\"\"\"bar\"\"\"]",
|
||||
"multiline strings are not allowed for key at line 1 column 2"
|
||||
);
|
||||
bad!("['\n']", "newline in string found at line 1 column 3");
|
||||
bad!("['\r\n']", "newline in string found at line 1 column 3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn table_names() {
|
||||
let toml = "
|
||||
[a.\"b\"]
|
||||
[\"f f\"]
|
||||
[\"f.f\"]
|
||||
[\"\\\"\"]
|
||||
['a.a']
|
||||
['\"\"']
|
||||
";
|
||||
let a: Value = basic_toml::from_str(toml).unwrap();
|
||||
println!("{:?}", a);
|
||||
let _ = &a["a"]["b"];
|
||||
let _ = &a["f f"];
|
||||
let _ = &a["f.f"];
|
||||
let _ = &a["\""];
|
||||
let _ = &a["\"\""];
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_bare_numeral() {
|
||||
bad!("4", "expected an equals, found eof at line 1 column 2");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inline_tables() {
|
||||
basic_toml::from_str::<Value>("a = {}").unwrap();
|
||||
basic_toml::from_str::<Value>("a = {b=1}").unwrap();
|
||||
basic_toml::from_str::<Value>("a = { b = 1 }").unwrap();
|
||||
basic_toml::from_str::<Value>("a = {a=1,b=2}").unwrap();
|
||||
basic_toml::from_str::<Value>("a = {a=1,b=2,c={}}").unwrap();
|
||||
|
||||
bad!(
|
||||
"a = {a=1,}",
|
||||
"expected a table key, found a right brace at line 1 column 10"
|
||||
);
|
||||
bad!(
|
||||
"a = {,}",
|
||||
"expected a table key, found a comma at line 1 column 6"
|
||||
);
|
||||
bad!(
|
||||
"a = {a=1,a=1}",
|
||||
"duplicate key: `a` for key `a` at line 1 column 10"
|
||||
);
|
||||
bad!(
|
||||
"a = {\n}",
|
||||
"expected a table key, found a newline at line 1 column 6"
|
||||
);
|
||||
bad!(
|
||||
"a = {",
|
||||
"expected a table key, found eof at line 1 column 6"
|
||||
);
|
||||
|
||||
basic_toml::from_str::<Value>("a = {a=[\n]}").unwrap();
|
||||
basic_toml::from_str::<Value>("a = {\"a\"=[\n]}").unwrap();
|
||||
basic_toml::from_str::<Value>("a = [\n{},\n{},\n]").unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn number_underscores() {
|
||||
macro_rules! t {
|
||||
($actual:expr, $expected:expr) => {{
|
||||
let f = format!("foo = {}", $actual);
|
||||
let table: Value = basic_toml::from_str(&f).unwrap();
|
||||
assert_eq!(table["foo"], json!($expected));
|
||||
}};
|
||||
}
|
||||
|
||||
t!("1_0", 10);
|
||||
t!("1_0_0", 100);
|
||||
t!("1_000", 1000);
|
||||
t!("+1_000", 1000);
|
||||
t!("-1_000", -1000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad_underscores() {
|
||||
bad!("foo = 0_", "invalid number at line 1 column 7");
|
||||
bad!("foo = 0__0", "invalid number at line 1 column 7");
|
||||
bad!(
|
||||
"foo = __0",
|
||||
"invalid TOML value, did you mean to use a quoted string? at line 1 column 7"
|
||||
);
|
||||
bad!("foo = 1_0_", "invalid number at line 1 column 7");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad_unicode_codepoint() {
|
||||
bad!(
|
||||
"foo = \"\\uD800\"",
|
||||
"invalid escape value: `55296` at line 1 column 9"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad_strings() {
|
||||
bad!(
|
||||
"foo = \"\\uxx\"",
|
||||
"invalid hex escape character in string: `x` at line 1 column 10"
|
||||
);
|
||||
bad!(
|
||||
"foo = \"\\u\"",
|
||||
"invalid hex escape character in string: `\\\"` at line 1 column 10"
|
||||
);
|
||||
bad!("foo = \"\\", "unterminated string at line 1 column 7");
|
||||
bad!("foo = '", "unterminated string at line 1 column 7");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn empty_string() {
|
||||
let table: Value = basic_toml::from_str::<Value>("foo = \"\"").unwrap();
|
||||
assert_eq!(table["foo"], json!(""));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn booleans() {
|
||||
let table: Value = basic_toml::from_str("foo = true").unwrap();
|
||||
assert_eq!(table["foo"], json!(true));
|
||||
|
||||
let table: Value = basic_toml::from_str("foo = false").unwrap();
|
||||
assert_eq!(table["foo"], json!(false));
|
||||
|
||||
bad!(
|
||||
"foo = true2",
|
||||
"invalid TOML value, did you mean to use a quoted string? at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = false2",
|
||||
"invalid TOML value, did you mean to use a quoted string? at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = t1",
|
||||
"invalid TOML value, did you mean to use a quoted string? at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = f2",
|
||||
"invalid TOML value, did you mean to use a quoted string? at line 1 column 7"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad_nesting() {
|
||||
bad!(
|
||||
"
|
||||
a = [2]
|
||||
[[a]]
|
||||
b = 5
|
||||
",
|
||||
"duplicate key: `a` at line 3 column 11"
|
||||
);
|
||||
bad!(
|
||||
"
|
||||
a = 1
|
||||
[a.b]
|
||||
",
|
||||
"duplicate key: `a` at line 3 column 10"
|
||||
);
|
||||
bad!(
|
||||
"
|
||||
a = []
|
||||
[a.b]
|
||||
",
|
||||
"duplicate key: `a` at line 3 column 10"
|
||||
);
|
||||
bad!(
|
||||
"
|
||||
a = []
|
||||
[[a.b]]
|
||||
",
|
||||
"duplicate key: `a` at line 3 column 11"
|
||||
);
|
||||
bad!(
|
||||
"
|
||||
[a]
|
||||
b = { c = 2, d = {} }
|
||||
[a.b]
|
||||
c = 2
|
||||
",
|
||||
"duplicate key: `b` for key `a` at line 4 column 12"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad_table_redefine() {
|
||||
bad!(
|
||||
"
|
||||
[a]
|
||||
foo=\"bar\"
|
||||
[a.b]
|
||||
foo=\"bar\"
|
||||
[a]
|
||||
",
|
||||
"redefinition of table `a` for key `a` at line 6 column 9"
|
||||
);
|
||||
bad!(
|
||||
"
|
||||
[a]
|
||||
foo=\"bar\"
|
||||
b = { foo = \"bar\" }
|
||||
[a]
|
||||
",
|
||||
"redefinition of table `a` for key `a` at line 5 column 9"
|
||||
);
|
||||
bad!(
|
||||
"
|
||||
[a]
|
||||
b = {}
|
||||
[a.b]
|
||||
",
|
||||
"duplicate key: `b` for key `a` at line 4 column 12"
|
||||
);
|
||||
|
||||
bad!(
|
||||
"
|
||||
[a]
|
||||
b = {}
|
||||
[a]
|
||||
",
|
||||
"redefinition of table `a` for key `a` at line 4 column 9"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn datetimes() {
|
||||
bad!(
|
||||
"foo = 2016-09-09T09:09:09Z",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = 2016-09-09T09:09:09.1Z",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = 2016-09-09T09:09:09.2+10:00",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = 2016-09-09T09:09:09.123456789-02:00",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = 2016-09-09T09:09:09.Z",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = 2016-9-09T09:09:09Z",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = 2016-09-09T09:09:09+2:00",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = 2016-09-09T09:09:09-2:00",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
bad!(
|
||||
"foo = 2016-09-09T09:09:09Z-2:00",
|
||||
"invalid number at line 1 column 7"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn require_newline_after_value() {
|
||||
bad!("0=0r=false", "invalid number at line 1 column 3");
|
||||
bad!(
|
||||
r#"
|
||||
0=""o=""m=""r=""00="0"q="""0"""e="""0"""
|
||||
"#,
|
||||
"expected newline, found an identifier at line 2 column 5"
|
||||
);
|
||||
bad!(
|
||||
r#"
|
||||
[[0000l0]]
|
||||
0="0"[[0000l0]]
|
||||
0="0"[[0000l0]]
|
||||
0="0"l="0"
|
||||
"#,
|
||||
"expected newline, found a left bracket at line 3 column 6"
|
||||
);
|
||||
bad!(
|
||||
r#"
|
||||
0=[0]00=[0,0,0]t=["0","0","0"]s=[1000-00-00T00:00:00Z,2000-00-00T00:00:00Z]
|
||||
"#,
|
||||
"expected newline, found an identifier at line 2 column 6"
|
||||
);
|
||||
bad!(
|
||||
"
|
||||
0=0r0=0r=false
|
||||
",
|
||||
"invalid number at line 2 column 3"
|
||||
);
|
||||
bad!(
|
||||
"
|
||||
0=0r0=0r=falsefal=false
|
||||
",
|
||||
"invalid number at line 2 column 3"
|
||||
);
|
||||
}
|
||||
Vendored
+190
@@ -0,0 +1,190 @@
|
||||
#![allow(
|
||||
clippy::elidable_lifetime_names,
|
||||
clippy::let_underscore_untyped,
|
||||
clippy::manual_range_contains,
|
||||
clippy::needless_lifetimes,
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::type_complexity
|
||||
)]
|
||||
|
||||
#[path = "../src/tokens.rs"]
|
||||
#[allow(dead_code)]
|
||||
mod tokens;
|
||||
|
||||
use crate::tokens::{Error, Token, Tokenizer};
|
||||
use std::borrow::Cow;
|
||||
|
||||
fn err(input: &str, err: Error) {
|
||||
let mut t = Tokenizer::new(input);
|
||||
let token = t.next().unwrap_err();
|
||||
assert_eq!(token, err);
|
||||
assert!(t.next().unwrap().is_none());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn literal_strings() {
|
||||
fn t(input: &str, val: &str, multiline: bool) {
|
||||
let mut t = Tokenizer::new(input);
|
||||
let (_, token) = t.next().unwrap().unwrap();
|
||||
assert_eq!(
|
||||
token,
|
||||
Token::String {
|
||||
src: input,
|
||||
val: Cow::Borrowed(val),
|
||||
multiline,
|
||||
}
|
||||
);
|
||||
assert!(t.next().unwrap().is_none());
|
||||
}
|
||||
|
||||
t("''", "", false);
|
||||
t("''''''", "", true);
|
||||
t("'''\n'''", "", true);
|
||||
t("'a'", "a", false);
|
||||
t("'\"a'", "\"a", false);
|
||||
t("''''a'''", "'a", true);
|
||||
t("'''\n'a\n'''", "'a\n", true);
|
||||
t("'''a\n'a\r\n'''", "a\n'a\n", true);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn basic_strings() {
|
||||
fn t(input: &str, val: &str, multiline: bool) {
|
||||
let mut t = Tokenizer::new(input);
|
||||
let (_, token) = t.next().unwrap().unwrap();
|
||||
assert_eq!(
|
||||
token,
|
||||
Token::String {
|
||||
src: input,
|
||||
val: Cow::Borrowed(val),
|
||||
multiline,
|
||||
}
|
||||
);
|
||||
assert!(t.next().unwrap().is_none());
|
||||
}
|
||||
|
||||
t(r#""""#, "", false);
|
||||
t(r#""""""""#, "", true);
|
||||
t(r#""a""#, "a", false);
|
||||
t(r#""""a""""#, "a", true);
|
||||
t(r#""\t""#, "\t", false);
|
||||
t(r#""\u0000""#, "\0", false);
|
||||
t(r#""\U00000000""#, "\0", false);
|
||||
t(r#""\U000A0000""#, "\u{A0000}", false);
|
||||
t(r#""\\t""#, "\\t", false);
|
||||
t("\"\t\"", "\t", false);
|
||||
t("\"\"\"\n\t\"\"\"", "\t", true);
|
||||
t("\"\"\"\\\n\"\"\"", "", true);
|
||||
t(
|
||||
"\"\"\"\\\n \t \t \\\r\n \t \n \t \r\n\"\"\"",
|
||||
"",
|
||||
true,
|
||||
);
|
||||
t(r#""\r""#, "\r", false);
|
||||
t(r#""\n""#, "\n", false);
|
||||
t(r#""\b""#, "\u{8}", false);
|
||||
t(r#""a\fa""#, "a\u{c}a", false);
|
||||
t(r#""\"a""#, "\"a", false);
|
||||
t("\"\"\"\na\"\"\"", "a", true);
|
||||
t("\"\"\"\n\"\"\"", "", true);
|
||||
t(r#""""a\"""b""""#, "a\"\"\"b", true);
|
||||
err(r#""\a"#, Error::InvalidEscape(2, 'a'));
|
||||
err("\"\\\n", Error::InvalidEscape(2, '\n'));
|
||||
err("\"\\\r\n", Error::InvalidEscape(2, '\n'));
|
||||
err("\"\\", Error::UnterminatedString(0));
|
||||
err("\"\u{0}", Error::InvalidCharInString(1, '\u{0}'));
|
||||
err(r#""\U00""#, Error::InvalidHexEscape(5, '"'));
|
||||
err(r#""\U00"#, Error::UnterminatedString(0));
|
||||
err(r#""\uD800"#, Error::InvalidEscapeValue(2, 0xd800));
|
||||
err(r#""\UFFFFFFFF"#, Error::InvalidEscapeValue(2, 0xffff_ffff));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keylike() {
|
||||
fn t(input: &str) {
|
||||
let mut t = Tokenizer::new(input);
|
||||
let (_, token) = t.next().unwrap().unwrap();
|
||||
assert_eq!(token, Token::Keylike(input));
|
||||
assert!(t.next().unwrap().is_none());
|
||||
}
|
||||
t("foo");
|
||||
t("0bar");
|
||||
t("bar0");
|
||||
t("1234");
|
||||
t("a-b");
|
||||
t("a_B");
|
||||
t("-_-");
|
||||
t("___");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn all() {
|
||||
fn t(input: &str, expected: &[((usize, usize), Token, &str)]) {
|
||||
let mut tokens = Tokenizer::new(input);
|
||||
let mut actual: Vec<((usize, usize), Token, &str)> = Vec::new();
|
||||
while let Some((span, token)) = tokens.next().unwrap() {
|
||||
actual.push((span.into(), token, &input[span.start..span.end]));
|
||||
}
|
||||
for (a, b) in actual.iter().zip(expected) {
|
||||
assert_eq!(a, b);
|
||||
}
|
||||
assert_eq!(actual.len(), expected.len());
|
||||
}
|
||||
|
||||
t(
|
||||
" a ",
|
||||
&[
|
||||
((0, 1), Token::Whitespace(" "), " "),
|
||||
((1, 2), Token::Keylike("a"), "a"),
|
||||
((2, 3), Token::Whitespace(" "), " "),
|
||||
],
|
||||
);
|
||||
|
||||
t(
|
||||
" a\t [[]] \t [] {} , . =\n# foo \r\n#foo \n ",
|
||||
&[
|
||||
((0, 1), Token::Whitespace(" "), " "),
|
||||
((1, 2), Token::Keylike("a"), "a"),
|
||||
((2, 4), Token::Whitespace("\t "), "\t "),
|
||||
((4, 5), Token::LeftBracket, "["),
|
||||
((5, 6), Token::LeftBracket, "["),
|
||||
((6, 7), Token::RightBracket, "]"),
|
||||
((7, 8), Token::RightBracket, "]"),
|
||||
((8, 11), Token::Whitespace(" \t "), " \t "),
|
||||
((11, 12), Token::LeftBracket, "["),
|
||||
((12, 13), Token::RightBracket, "]"),
|
||||
((13, 14), Token::Whitespace(" "), " "),
|
||||
((14, 15), Token::LeftBrace, "{"),
|
||||
((15, 16), Token::RightBrace, "}"),
|
||||
((16, 17), Token::Whitespace(" "), " "),
|
||||
((17, 18), Token::Comma, ","),
|
||||
((18, 19), Token::Whitespace(" "), " "),
|
||||
((19, 20), Token::Period, "."),
|
||||
((20, 21), Token::Whitespace(" "), " "),
|
||||
((21, 22), Token::Equals, "="),
|
||||
((22, 23), Token::Newline, "\n"),
|
||||
((23, 29), Token::Comment("# foo "), "# foo "),
|
||||
((29, 31), Token::Newline, "\r\n"),
|
||||
((31, 36), Token::Comment("#foo "), "#foo "),
|
||||
((36, 37), Token::Newline, "\n"),
|
||||
((37, 38), Token::Whitespace(" "), " "),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bare_cr_bad() {
|
||||
err("\r", Error::Unexpected(0, '\r'));
|
||||
err("'\n", Error::NewlineInString(1));
|
||||
err("'\u{0}", Error::InvalidCharInString(1, '\u{0}'));
|
||||
err("'", Error::UnterminatedString(0));
|
||||
err("\u{0}", Error::Unexpected(0, '\u{0}'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn bad_comment() {
|
||||
let mut t = Tokenizer::new("#\u{0}");
|
||||
t.next().unwrap().unwrap();
|
||||
assert_eq!(t.next(), Err(Error::Unexpected(1, '\u{0}')));
|
||||
assert!(t.next().unwrap().is_none());
|
||||
}
|
||||
Vendored
+368
@@ -0,0 +1,368 @@
|
||||
#![allow(
|
||||
clippy::match_like_matches_macro,
|
||||
clippy::needless_pass_by_value,
|
||||
clippy::uninlined_format_args
|
||||
)]
|
||||
|
||||
use serde_json::{json, Value};
|
||||
|
||||
fn to_json(toml: Value) -> Value {
|
||||
fn doit(s: &str, json: Value) -> Value {
|
||||
json!({ "type": s, "value": json })
|
||||
}
|
||||
|
||||
match toml {
|
||||
Value::Null => unreachable!(),
|
||||
Value::String(s) => doit("string", Value::String(s)),
|
||||
Value::Number(n) => {
|
||||
let repr = n.to_string();
|
||||
if repr.contains('.') {
|
||||
let float: f64 = repr.parse().unwrap();
|
||||
let mut repr = format!("{:.15}", float);
|
||||
repr.truncate(repr.trim_end_matches('0').len());
|
||||
if repr.ends_with('.') {
|
||||
repr.push('0');
|
||||
}
|
||||
doit("float", Value::String(repr))
|
||||
} else {
|
||||
doit("integer", Value::String(repr))
|
||||
}
|
||||
}
|
||||
Value::Bool(b) => doit("bool", Value::String(format!("{}", b))),
|
||||
Value::Array(arr) => {
|
||||
let is_table = match arr.first() {
|
||||
Some(&Value::Object(_)) => true,
|
||||
_ => false,
|
||||
};
|
||||
let json = Value::Array(arr.into_iter().map(to_json).collect());
|
||||
if is_table {
|
||||
json
|
||||
} else {
|
||||
doit("array", json)
|
||||
}
|
||||
}
|
||||
Value::Object(table) => {
|
||||
let mut map = serde_json::Map::new();
|
||||
for (k, v) in table {
|
||||
map.insert(k, to_json(v));
|
||||
}
|
||||
Value::Object(map)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn run(toml_raw: &str, json_raw: &str) {
|
||||
println!("parsing:\n{}", toml_raw);
|
||||
let toml: Value = basic_toml::from_str(toml_raw).unwrap();
|
||||
let json: Value = serde_json::from_str(json_raw).unwrap();
|
||||
|
||||
// Assert toml == json
|
||||
let toml_json = to_json(toml.clone());
|
||||
assert!(
|
||||
json == toml_json,
|
||||
"expected\n{}\ngot\n{}\n",
|
||||
serde_json::to_string_pretty(&json).unwrap(),
|
||||
serde_json::to_string_pretty(&toml_json).unwrap()
|
||||
);
|
||||
|
||||
// Assert round trip
|
||||
println!("round trip parse: {}", toml);
|
||||
let toml2: Value = basic_toml::from_str(&basic_toml::to_string(&toml).unwrap()).unwrap();
|
||||
assert_eq!(toml, toml2);
|
||||
}
|
||||
|
||||
macro_rules! test( ($name:ident, $toml:expr, $json:expr) => (
|
||||
#[test]
|
||||
fn $name() { run($toml, $json); }
|
||||
) );
|
||||
|
||||
test!(
|
||||
array_empty,
|
||||
include_str!("valid/array-empty.toml"),
|
||||
include_str!("valid/array-empty.json")
|
||||
);
|
||||
test!(
|
||||
array_nospaces,
|
||||
include_str!("valid/array-nospaces.toml"),
|
||||
include_str!("valid/array-nospaces.json")
|
||||
);
|
||||
test!(
|
||||
arrays_hetergeneous,
|
||||
include_str!("valid/arrays-hetergeneous.toml"),
|
||||
include_str!("valid/arrays-hetergeneous.json")
|
||||
);
|
||||
#[cfg(any())]
|
||||
test!(
|
||||
arrays,
|
||||
include_str!("valid/arrays.toml"),
|
||||
include_str!("valid/arrays.json")
|
||||
);
|
||||
test!(
|
||||
arrays_nested,
|
||||
include_str!("valid/arrays-nested.toml"),
|
||||
include_str!("valid/arrays-nested.json")
|
||||
);
|
||||
test!(
|
||||
array_mixed_types_ints_and_floats,
|
||||
include_str!("valid/array-mixed-types-ints-and-floats.toml"),
|
||||
include_str!("valid/array-mixed-types-ints-and-floats.json")
|
||||
);
|
||||
test!(
|
||||
array_mixed_types_arrays_and_ints,
|
||||
include_str!("valid/array-mixed-types-arrays-and-ints.toml"),
|
||||
include_str!("valid/array-mixed-types-arrays-and-ints.json")
|
||||
);
|
||||
test!(
|
||||
array_mixed_types_strings_and_ints,
|
||||
include_str!("valid/array-mixed-types-strings-and-ints.toml"),
|
||||
include_str!("valid/array-mixed-types-strings-and-ints.json")
|
||||
);
|
||||
test!(
|
||||
empty,
|
||||
include_str!("valid/empty.toml"),
|
||||
include_str!("valid/empty.json")
|
||||
);
|
||||
test!(
|
||||
bool,
|
||||
include_str!("valid/bool.toml"),
|
||||
include_str!("valid/bool.json")
|
||||
);
|
||||
test!(
|
||||
comments_everywhere,
|
||||
include_str!("valid/comments-everywhere.toml"),
|
||||
include_str!("valid/comments-everywhere.json")
|
||||
);
|
||||
#[cfg(any())]
|
||||
test!(
|
||||
datetime,
|
||||
include_str!("valid/datetime.toml"),
|
||||
include_str!("valid/datetime.json")
|
||||
);
|
||||
#[cfg(any())]
|
||||
test!(
|
||||
example,
|
||||
include_str!("valid/example.toml"),
|
||||
include_str!("valid/example.json")
|
||||
);
|
||||
test!(
|
||||
float,
|
||||
include_str!("valid/float.toml"),
|
||||
include_str!("valid/float.json")
|
||||
);
|
||||
#[cfg(any())]
|
||||
test!(
|
||||
implicit_and_explicit_after,
|
||||
include_str!("valid/implicit-and-explicit-after.toml"),
|
||||
include_str!("valid/implicit-and-explicit-after.json")
|
||||
);
|
||||
#[cfg(any())]
|
||||
test!(
|
||||
implicit_and_explicit_before,
|
||||
include_str!("valid/implicit-and-explicit-before.toml"),
|
||||
include_str!("valid/implicit-and-explicit-before.json")
|
||||
);
|
||||
test!(
|
||||
implicit_groups,
|
||||
include_str!("valid/implicit-groups.toml"),
|
||||
include_str!("valid/implicit-groups.json")
|
||||
);
|
||||
test!(
|
||||
integer,
|
||||
include_str!("valid/integer.toml"),
|
||||
include_str!("valid/integer.json")
|
||||
);
|
||||
test!(
|
||||
key_equals_nospace,
|
||||
include_str!("valid/key-equals-nospace.toml"),
|
||||
include_str!("valid/key-equals-nospace.json")
|
||||
);
|
||||
test!(
|
||||
key_space,
|
||||
include_str!("valid/key-space.toml"),
|
||||
include_str!("valid/key-space.json")
|
||||
);
|
||||
test!(
|
||||
key_special_chars,
|
||||
include_str!("valid/key-special-chars.toml"),
|
||||
include_str!("valid/key-special-chars.json")
|
||||
);
|
||||
test!(
|
||||
key_with_pound,
|
||||
include_str!("valid/key-with-pound.toml"),
|
||||
include_str!("valid/key-with-pound.json")
|
||||
);
|
||||
test!(
|
||||
key_empty,
|
||||
include_str!("valid/key-empty.toml"),
|
||||
include_str!("valid/key-empty.json")
|
||||
);
|
||||
test!(
|
||||
long_float,
|
||||
include_str!("valid/long-float.toml"),
|
||||
include_str!("valid/long-float.json")
|
||||
);
|
||||
test!(
|
||||
long_integer,
|
||||
include_str!("valid/long-integer.toml"),
|
||||
include_str!("valid/long-integer.json")
|
||||
);
|
||||
test!(
|
||||
multiline_string,
|
||||
include_str!("valid/multiline-string.toml"),
|
||||
include_str!("valid/multiline-string.json")
|
||||
);
|
||||
test!(
|
||||
raw_multiline_string,
|
||||
include_str!("valid/raw-multiline-string.toml"),
|
||||
include_str!("valid/raw-multiline-string.json")
|
||||
);
|
||||
test!(
|
||||
raw_string,
|
||||
include_str!("valid/raw-string.toml"),
|
||||
include_str!("valid/raw-string.json")
|
||||
);
|
||||
test!(
|
||||
string_empty,
|
||||
include_str!("valid/string-empty.toml"),
|
||||
include_str!("valid/string-empty.json")
|
||||
);
|
||||
test!(
|
||||
string_escapes,
|
||||
include_str!("valid/string-escapes.toml"),
|
||||
include_str!("valid/string-escapes.json")
|
||||
);
|
||||
test!(
|
||||
string_simple,
|
||||
include_str!("valid/string-simple.toml"),
|
||||
include_str!("valid/string-simple.json")
|
||||
);
|
||||
test!(
|
||||
string_with_pound,
|
||||
include_str!("valid/string-with-pound.toml"),
|
||||
include_str!("valid/string-with-pound.json")
|
||||
);
|
||||
test!(
|
||||
table_array_implicit,
|
||||
include_str!("valid/table-array-implicit.toml"),
|
||||
include_str!("valid/table-array-implicit.json")
|
||||
);
|
||||
test!(
|
||||
table_array_many,
|
||||
include_str!("valid/table-array-many.toml"),
|
||||
include_str!("valid/table-array-many.json")
|
||||
);
|
||||
test!(
|
||||
table_array_nest,
|
||||
include_str!("valid/table-array-nest.toml"),
|
||||
include_str!("valid/table-array-nest.json")
|
||||
);
|
||||
test!(
|
||||
table_array_one,
|
||||
include_str!("valid/table-array-one.toml"),
|
||||
include_str!("valid/table-array-one.json")
|
||||
);
|
||||
test!(
|
||||
table_empty,
|
||||
include_str!("valid/table-empty.toml"),
|
||||
include_str!("valid/table-empty.json")
|
||||
);
|
||||
test!(
|
||||
table_sub_empty,
|
||||
include_str!("valid/table-sub-empty.toml"),
|
||||
include_str!("valid/table-sub-empty.json")
|
||||
);
|
||||
test!(
|
||||
table_multi_empty,
|
||||
include_str!("valid/table-multi-empty.toml"),
|
||||
include_str!("valid/table-multi-empty.json")
|
||||
);
|
||||
test!(
|
||||
table_whitespace,
|
||||
include_str!("valid/table-whitespace.toml"),
|
||||
include_str!("valid/table-whitespace.json")
|
||||
);
|
||||
test!(
|
||||
table_with_pound,
|
||||
include_str!("valid/table-with-pound.toml"),
|
||||
include_str!("valid/table-with-pound.json")
|
||||
);
|
||||
test!(
|
||||
unicode_escape,
|
||||
include_str!("valid/unicode-escape.toml"),
|
||||
include_str!("valid/unicode-escape.json")
|
||||
);
|
||||
test!(
|
||||
unicode_literal,
|
||||
include_str!("valid/unicode-literal.toml"),
|
||||
include_str!("valid/unicode-literal.json")
|
||||
);
|
||||
#[cfg(any())]
|
||||
test!(
|
||||
hard_example,
|
||||
include_str!("valid/hard_example.toml"),
|
||||
include_str!("valid/hard_example.json")
|
||||
);
|
||||
#[cfg(any())]
|
||||
test!(
|
||||
example2,
|
||||
include_str!("valid/example2.toml"),
|
||||
include_str!("valid/example2.json")
|
||||
);
|
||||
#[cfg(any())]
|
||||
test!(
|
||||
example3,
|
||||
include_str!("valid/example-v0.3.0.toml"),
|
||||
include_str!("valid/example-v0.3.0.json")
|
||||
);
|
||||
#[cfg(any())]
|
||||
test!(
|
||||
example4,
|
||||
include_str!("valid/example-v0.4.0.toml"),
|
||||
include_str!("valid/example-v0.4.0.json")
|
||||
);
|
||||
#[cfg(any())]
|
||||
test!(
|
||||
example_bom,
|
||||
include_str!("valid/example-bom.toml"),
|
||||
include_str!("valid/example.json")
|
||||
);
|
||||
|
||||
#[cfg(any())]
|
||||
test!(
|
||||
datetime_truncate,
|
||||
include_str!("valid/datetime-truncate.toml"),
|
||||
include_str!("valid/datetime-truncate.json")
|
||||
);
|
||||
test!(
|
||||
key_quote_newline,
|
||||
include_str!("valid/key-quote-newline.toml"),
|
||||
include_str!("valid/key-quote-newline.json")
|
||||
);
|
||||
test!(
|
||||
table_array_nest_no_keys,
|
||||
include_str!("valid/table-array-nest-no-keys.toml"),
|
||||
include_str!("valid/table-array-nest-no-keys.json")
|
||||
);
|
||||
test!(
|
||||
dotted_keys,
|
||||
include_str!("valid/dotted-keys.toml"),
|
||||
include_str!("valid/dotted-keys.json")
|
||||
);
|
||||
|
||||
test!(
|
||||
quote_surrounded_value,
|
||||
include_str!("valid/quote-surrounded-value.toml"),
|
||||
include_str!("valid/quote-surrounded-value.json")
|
||||
);
|
||||
|
||||
test!(
|
||||
float_exponent,
|
||||
include_str!("valid/float-exponent.toml"),
|
||||
include_str!("valid/float-exponent.json")
|
||||
);
|
||||
|
||||
test!(
|
||||
string_delim_end,
|
||||
include_str!("valid/string-delim-end.toml"),
|
||||
include_str!("valid/string-delim-end.json")
|
||||
);
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"thevoid": { "type": "array", "value": [
|
||||
{"type": "array", "value": [
|
||||
{"type": "array", "value": [
|
||||
{"type": "array", "value": [
|
||||
{"type": "array", "value": []}
|
||||
]}
|
||||
]}
|
||||
]}
|
||||
]}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
thevoid = [[[[[]]]]]
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"arrays-and-ints": {
|
||||
"type": "array",
|
||||
"value": [
|
||||
{"type": "integer", "value": "1"},
|
||||
{"type": "array", "value": [
|
||||
{ "type": "string", "value":"Arrays are not integers."}
|
||||
]}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
arrays-and-ints = [1, ["Arrays are not integers."]]
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ints-and-floats": {
|
||||
"type": "array",
|
||||
"value": [
|
||||
{"type": "integer", "value": "1"},
|
||||
{"type": "float", "value": "1.1"}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
ints-and-floats = [1, 1.1]
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"strings-and-ints": {
|
||||
"type": "array",
|
||||
"value": [
|
||||
{"type": "string", "value": "hi"},
|
||||
{"type": "integer", "value": "42"}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
strings-and-ints = ["hi", 42]
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"ints": {
|
||||
"type": "array",
|
||||
"value": [
|
||||
{"type": "integer", "value": "1"},
|
||||
{"type": "integer", "value": "2"},
|
||||
{"type": "integer", "value": "3"}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
ints = [1,2,3]
|
||||
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"mixed": {
|
||||
"type": "array",
|
||||
"value": [
|
||||
{"type": "array", "value": [
|
||||
{"type": "integer", "value": "1"},
|
||||
{"type": "integer", "value": "2"}
|
||||
]},
|
||||
{"type": "array", "value": [
|
||||
{"type": "string", "value": "a"},
|
||||
{"type": "string", "value": "b"}
|
||||
]},
|
||||
{"type": "array", "value": [
|
||||
{"type": "float", "value": "1.1"},
|
||||
{"type": "float", "value": "2.1"}
|
||||
]}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
mixed = [[1, 2], ["a", "b"], [1.1, 2.1]]
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"nest": {
|
||||
"type": "array",
|
||||
"value": [
|
||||
{"type": "array", "value": [
|
||||
{"type": "string", "value": "a"}
|
||||
]},
|
||||
{"type": "array", "value": [
|
||||
{"type": "string", "value": "b"}
|
||||
]}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
nest = [["a"], ["b"]]
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"ints": {
|
||||
"type": "array",
|
||||
"value": [
|
||||
{"type": "integer", "value": "1"},
|
||||
{"type": "integer", "value": "2"},
|
||||
{"type": "integer", "value": "3"}
|
||||
]
|
||||
},
|
||||
"floats": {
|
||||
"type": "array",
|
||||
"value": [
|
||||
{"type": "float", "value": "1.1"},
|
||||
{"type": "float", "value": "2.1"},
|
||||
{"type": "float", "value": "3.1"}
|
||||
]
|
||||
},
|
||||
"strings": {
|
||||
"type": "array",
|
||||
"value": [
|
||||
{"type": "string", "value": "a"},
|
||||
{"type": "string", "value": "b"},
|
||||
{"type": "string", "value": "c"}
|
||||
]
|
||||
},
|
||||
"dates": {
|
||||
"type": "array",
|
||||
"value": [
|
||||
{"type": "datetime", "value": "1987-07-05T17:45:00Z"},
|
||||
{"type": "datetime", "value": "1979-05-27T07:32:00Z"},
|
||||
{"type": "datetime", "value": "2006-06-01T11:00:00Z"}
|
||||
]
|
||||
}
|
||||
}
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
ints = [1, 2, 3]
|
||||
floats = [1.1, 2.1, 3.1]
|
||||
strings = ["a", "b", "c"]
|
||||
dates = [
|
||||
1987-07-05T17:45:00Z,
|
||||
1979-05-27T07:32:00Z,
|
||||
2006-06-01T11:00:00Z,
|
||||
]
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"f": {"type": "bool", "value": "false"},
|
||||
"t": {"type": "bool", "value": "true"}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
t = true
|
||||
f = false
|
||||
@@ -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
|
||||
# In between 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,6 @@
|
||||
{
|
||||
"bestdayever": {
|
||||
"type": "datetime",
|
||||
"value": "1987-07-05T17:45:00.123456789Z"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
bestdayever = 1987-07-05T17:45:00.123456789012345Z
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"bestdayever": {"type": "datetime", "value": "1987-07-05T17:45:00Z"}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
bestdayever = 1987-07-05T17:45:00Z
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"a": {
|
||||
"b": {
|
||||
"type": "integer",
|
||||
"value": "123"
|
||||
}
|
||||
},
|
||||
"table": {
|
||||
"a": {
|
||||
"b": {
|
||||
"c": {
|
||||
"type": "integer",
|
||||
"value": "1"
|
||||
},
|
||||
"d": {
|
||||
"type": "integer",
|
||||
"value": "2"
|
||||
}
|
||||
}
|
||||
},
|
||||
"in": {
|
||||
"type": {
|
||||
"color": {
|
||||
"type": "string",
|
||||
"value": "blue"
|
||||
},
|
||||
"name": {
|
||||
"type": "string",
|
||||
"value": "cat"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
a.b = 123
|
||||
|
||||
[table]
|
||||
a.b.c = 1
|
||||
a . b . d = 2
|
||||
|
||||
in = { type.name = "cat", type.color = "blue" }
|
||||
+1
@@ -0,0 +1 @@
|
||||
{}
|
||||
Whitespace-only changes.
@@ -0,0 +1,5 @@
|
||||
best-day-ever = 1987-07-05T17:45:00Z
|
||||
|
||||
[numtheory]
|
||||
boring = false
|
||||
perfection = [6, 28, 496]
|
||||
@@ -0,0 +1 @@
|
||||
{"Array":{"key1":{"type":"array","value":[{"type":"integer","value":"1"},{"type":"integer","value":"2"},{"type":"integer","value":"3"}]},"key2":{"type":"array","value":[{"type":"string","value":"red"},{"type":"string","value":"yellow"},{"type":"string","value":"green"}]},"key3":{"type":"array","value":[{"type":"array","value":[{"type":"integer","value":"1"},{"type":"integer","value":"2"}]},{"type":"array","value":[{"type":"integer","value":"3"},{"type":"integer","value":"4"},{"type":"integer","value":"5"}]}]},"key4":{"type":"array","value":[{"type":"array","value":[{"type":"integer","value":"1"},{"type":"integer","value":"2"}]},{"type":"array","value":[{"type":"string","value":"a"},{"type":"string","value":"b"},{"type":"string","value":"c"}]}]},"key5":{"type":"array","value":[{"type":"integer","value":"1"},{"type":"integer","value":"2"},{"type":"integer","value":"3"}]},"key6":{"type":"array","value":[{"type":"integer","value":"1"},{"type":"integer","value":"2"}]}},"Booleans":{"False":{"type":"bool","value":"false"},"True":{"type":"bool","value":"true"}},"Datetime":{"key1":{"type":"datetime","value":"1979-05-27T07:32:00Z"}},"Float":{"both":{},"exponent":{},"fractional":{"key1":{"type":"float","value":"1.0"},"key2":{"type":"float","value":"3.1415"},"key3":{"type":"float","value":"-0.01"}}},"Integer":{"key1":{"type":"integer","value":"99"},"key2":{"type":"integer","value":"42"},"key3":{"type":"integer","value":"0"},"key4":{"type":"integer","value":"-17"}},"String":{"Literal":{"Multiline":{"lines":{"type":"string","value":"The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n"},"regex2":{"type":"string","value":"I [dw]on't need \\d{2} apples"}},"quoted":{"type":"string","value":"Tom \"Dubs\" Preston-Werner"},"regex":{"type":"string","value":"\u003c\\i\\c*\\s*\u003e"},"winpath":{"type":"string","value":"C:\\Users\\nodejs\\templates"},"winpath2":{"type":"string","value":"\\\\ServerX\\admin$\\system32\\"}},"Multiline":{"key1":{"type":"string","value":"One\nTwo"},"key2":{"type":"string","value":"One\nTwo"},"key3":{"type":"string","value":"One\nTwo"}},"Multilined":{"Singleline":{"key1":{"type":"string","value":"The quick brown fox jumps over the lazy dog."},"key2":{"type":"string","value":"The quick brown fox jumps over the lazy dog."},"key3":{"type":"string","value":"The quick brown fox jumps over the lazy dog."}}},"basic":{"type":"string","value":"I'm a string. \"You can quote me\". Name\u0009José\nLocation\u0009SF."}},"Table":{"key":{"type":"string","value":"value"}},"dog":{"tater":{"type":{"type":"string","value":"pug"}}},"fruit":[{"name":{"type":"string","value":"apple"},"physical":{"color":{"type":"string","value":"red"},"shape":{"type":"string","value":"round"}},"variety":[{"name":{"type":"string","value":"red delicious"}},{"name":{"type":"string","value":"granny smith"}}]},{"name":{"type":"string","value":"banana"},"variety":[{"name":{"type":"string","value":"plantain"}}]}],"products":[{"name":{"type":"string","value":"Hammer"},"sku":{"type":"integer","value":"738594937"}},{},{"color":{"type":"string","value":"gray"},"name":{"type":"string","value":"Nail"},"sku":{"type":"integer","value":"284758393"}}],"x":{"y":{"z":{"w":{}}}}}
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
# Comment
|
||||
# I am a comment. Hear me roar. Roar.
|
||||
|
||||
# Table
|
||||
# Tables (also known as hash tables or dictionaries) are collections of key/value pairs.
|
||||
# They appear in square brackets on a line by themselves.
|
||||
|
||||
[Table]
|
||||
|
||||
key = "value" # Yeah, you can do this.
|
||||
|
||||
# Nested tables are denoted by table names with dots in them. Name your tables whatever crap you please, just don't use #, ., [ or ].
|
||||
|
||||
[dog.tater]
|
||||
type = "pug"
|
||||
|
||||
# You don't need to specify all the super-tables if you don't want to. TOML knows how to do it for you.
|
||||
|
||||
# [x] you
|
||||
# [x.y] don't
|
||||
# [x.y.z] need these
|
||||
[x.y.z.w] # for this to work
|
||||
|
||||
# String
|
||||
# There are four ways to express strings: basic, multi-line basic, literal, and multi-line literal.
|
||||
# All strings must contain only valid UTF-8 characters.
|
||||
|
||||
[String]
|
||||
basic = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF."
|
||||
|
||||
[String.Multiline]
|
||||
|
||||
# The following strings are byte-for-byte equivalent:
|
||||
key1 = "One\nTwo"
|
||||
key2 = """One\nTwo"""
|
||||
key3 = """
|
||||
One
|
||||
Two"""
|
||||
|
||||
[String.Multilined.Singleline]
|
||||
|
||||
# The following strings are byte-for-byte equivalent:
|
||||
key1 = "The quick brown fox jumps over the lazy dog."
|
||||
|
||||
key2 = """
|
||||
The quick brown \
|
||||
|
||||
|
||||
fox jumps over \
|
||||
the lazy dog."""
|
||||
|
||||
key3 = """\
|
||||
The quick brown \
|
||||
fox jumps over \
|
||||
the lazy dog.\
|
||||
"""
|
||||
|
||||
[String.Literal]
|
||||
|
||||
# What you see is what you get.
|
||||
winpath = 'C:\Users\nodejs\templates'
|
||||
winpath2 = '\\ServerX\admin$\system32\'
|
||||
quoted = 'Tom "Dubs" Preston-Werner'
|
||||
regex = '<\i\c*\s*>'
|
||||
|
||||
|
||||
[String.Literal.Multiline]
|
||||
|
||||
regex2 = '''I [dw]on't need \d{2} apples'''
|
||||
lines = '''
|
||||
The first newline is
|
||||
trimmed in raw strings.
|
||||
All other whitespace
|
||||
is preserved.
|
||||
'''
|
||||
|
||||
# Integer
|
||||
# Integers are whole numbers. Positive numbers may be prefixed with a plus sign.
|
||||
# Negative numbers are prefixed with a minus sign.
|
||||
|
||||
[Integer]
|
||||
key1 = +99
|
||||
key2 = 42
|
||||
key3 = 0
|
||||
key4 = -17
|
||||
|
||||
# Float
|
||||
# A float consists of an integer part (which may be prefixed with a plus or minus sign)
|
||||
# followed by a fractional part and/or an exponent part.
|
||||
|
||||
[Float.fractional]
|
||||
|
||||
# fractional
|
||||
key1 = +1.0
|
||||
key2 = 3.1415
|
||||
key3 = -0.01
|
||||
|
||||
[Float.exponent]
|
||||
|
||||
# exponent
|
||||
#key1 = 5e+22
|
||||
#key2 = 1e6
|
||||
#key3 = -2E-2
|
||||
|
||||
[Float.both]
|
||||
|
||||
# both
|
||||
#key = 6.626e-34
|
||||
|
||||
# Boolean
|
||||
# Booleans are just the tokens you're used to. Always lowercase.
|
||||
|
||||
[Booleans]
|
||||
True = true
|
||||
False = false
|
||||
|
||||
# Datetime
|
||||
# Datetimes are RFC 3339 dates.
|
||||
|
||||
[Datetime]
|
||||
key1 = 1979-05-27T07:32:00Z
|
||||
#key2 = 1979-05-27T00:32:00-07:00
|
||||
#key3 = 1979-05-27T00:32:00.999999-07:00
|
||||
|
||||
# Array
|
||||
# Arrays are square brackets with other primitives inside. Whitespace is ignored. Elements are separated by commas. Data types may not be mixed.
|
||||
|
||||
[Array]
|
||||
key1 = [ 1, 2, 3 ]
|
||||
key2 = [ "red", "yellow", "green" ]
|
||||
key3 = [ [ 1, 2 ], [3, 4, 5] ]
|
||||
key4 = [ [ 1, 2 ], ["a", "b", "c"] ] # this is ok
|
||||
|
||||
#Arrays can also be multiline. So in addition to ignoring whitespace, arrays also ignore newlines between the brackets.
|
||||
# Terminating commas are ok before the closing bracket.
|
||||
|
||||
key5 = [
|
||||
1, 2, 3
|
||||
]
|
||||
key6 = [
|
||||
1,
|
||||
2, # this is ok
|
||||
]
|
||||
|
||||
# Array of Tables
|
||||
# These can be expressed by using a table name in double brackets.
|
||||
# Each table with the same double bracketed name will be an element in the array.
|
||||
# The tables are inserted in the order encountered.
|
||||
|
||||
[[products]]
|
||||
name = "Hammer"
|
||||
sku = 738594937
|
||||
|
||||
[[products]]
|
||||
|
||||
[[products]]
|
||||
name = "Nail"
|
||||
sku = 284758393
|
||||
color = "gray"
|
||||
|
||||
|
||||
# You can create nested arrays of tables as well.
|
||||
|
||||
[[fruit]]
|
||||
name = "apple"
|
||||
|
||||
[fruit.physical]
|
||||
color = "red"
|
||||
shape = "round"
|
||||
|
||||
[[fruit.variety]]
|
||||
name = "red delicious"
|
||||
|
||||
[[fruit.variety]]
|
||||
name = "granny smith"
|
||||
|
||||
[[fruit]]
|
||||
name = "banana"
|
||||
|
||||
[[fruit.variety]]
|
||||
name = "plantain"
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
{"array":{"key1":{"type":"array","value":[{"type":"integer","value":"1"},{"type":"integer","value":"2"},{"type":"integer","value":"3"}]},"key2":{"type":"array","value":[{"type":"string","value":"red"},{"type":"string","value":"yellow"},{"type":"string","value":"green"}]},"key3":{"type":"array","value":[{"type":"array","value":[{"type":"integer","value":"1"},{"type":"integer","value":"2"}]},{"type":"array","value":[{"type":"integer","value":"3"},{"type":"integer","value":"4"},{"type":"integer","value":"5"}]}]},"key4":{"type":"array","value":[{"type":"array","value":[{"type":"integer","value":"1"},{"type":"integer","value":"2"}]},{"type":"array","value":[{"type":"string","value":"a"},{"type":"string","value":"b"},{"type":"string","value":"c"}]}]},"key5":{"type":"array","value":[{"type":"integer","value":"1"},{"type":"integer","value":"2"},{"type":"integer","value":"3"}]},"key6":{"type":"array","value":[{"type":"integer","value":"1"},{"type":"integer","value":"2"}]}},"boolean":{"False":{"type":"bool","value":"false"},"True":{"type":"bool","value":"true"}},"datetime":{},"float":{"both":{},"exponent":{},"fractional":{"key1":{"type":"float","value":"1.0"},"key2":{"type":"float","value":"3.1415"},"key3":{"type":"float","value":"-0.01"}},"underscores":{}},"fruit":[{"name":{"type":"string","value":"apple"},"physical":{"color":{"type":"string","value":"red"},"shape":{"type":"string","value":"round"}},"variety":[{"name":{"type":"string","value":"red delicious"}},{"name":{"type":"string","value":"granny smith"}}]},{"name":{"type":"string","value":"banana"},"variety":[{"name":{"type":"string","value":"plantain"}}]}],"integer":{"key1":{"type":"integer","value":"99"},"key2":{"type":"integer","value":"42"},"key3":{"type":"integer","value":"0"},"key4":{"type":"integer","value":"-17"},"underscores":{"key1":{"type":"integer","value":"1000"},"key2":{"type":"integer","value":"5349221"},"key3":{"type":"integer","value":"12345"}}},"products":[{"name":{"type":"string","value":"Hammer"},"sku":{"type":"integer","value":"738594937"}},{},{"color":{"type":"string","value":"gray"},"name":{"type":"string","value":"Nail"},"sku":{"type":"integer","value":"284758393"}}],"string":{"basic":{"basic":{"type":"string","value":"I'm a string. \"You can quote me\". Name\u0009José\nLocation\u0009SF."}},"literal":{"multiline":{"lines":{"type":"string","value":"The first newline is\ntrimmed in raw strings.\n All other whitespace\n is preserved.\n"},"regex2":{"type":"string","value":"I [dw]on't need \\d{2} apples"}},"quoted":{"type":"string","value":"Tom \"Dubs\" Preston-Werner"},"regex":{"type":"string","value":"\u003c\\i\\c*\\s*\u003e"},"winpath":{"type":"string","value":"C:\\Users\\nodejs\\templates"},"winpath2":{"type":"string","value":"\\\\ServerX\\admin$\\system32\\"}},"multiline":{"continued":{"key1":{"type":"string","value":"The quick brown fox jumps over the lazy dog."},"key2":{"type":"string","value":"The quick brown fox jumps over the lazy dog."},"key3":{"type":"string","value":"The quick brown fox jumps over the lazy dog."}},"key1":{"type":"string","value":"One\nTwo"},"key2":{"type":"string","value":"One\nTwo"},"key3":{"type":"string","value":"One\nTwo"}}},"table":{"inline":{"name":{"first":{"type":"string","value":"Tom"},"last":{"type":"string","value":"Preston-Werner"}},"point":{"x":{"type":"integer","value":"1"},"y":{"type":"integer","value":"2"}}},"key":{"type":"string","value":"value"},"subtable":{"key":{"type":"string","value":"another value"}}},"x":{"y":{"z":{"w":{}}}}}
|
||||
+236
@@ -0,0 +1,236 @@
|
||||
################################################################################
|
||||
## Comment
|
||||
|
||||
# Speak your mind with the hash symbol. They go from the symbol to the end of
|
||||
# the line.
|
||||
|
||||
|
||||
################################################################################
|
||||
## Table
|
||||
|
||||
# Tables (also known as hash tables or dictionaries) are collections of
|
||||
# key/value pairs. They appear in square brackets on a line by themselves.
|
||||
|
||||
[table]
|
||||
|
||||
key = "value" # Yeah, you can do this.
|
||||
|
||||
# Nested tables are denoted by table names with dots in them. Name your tables
|
||||
# whatever crap you please, just don't use #, ., [ or ].
|
||||
|
||||
[table.subtable]
|
||||
|
||||
key = "another value"
|
||||
|
||||
# You don't need to specify all the super-tables if you don't want to. TOML
|
||||
# knows how to do it for you.
|
||||
|
||||
# [x] you
|
||||
# [x.y] don't
|
||||
# [x.y.z] need these
|
||||
[x.y.z.w] # for this to work
|
||||
|
||||
|
||||
################################################################################
|
||||
## Inline Table
|
||||
|
||||
# Inline tables provide a more compact syntax for expressing tables. They are
|
||||
# especially useful for grouped data that can otherwise quickly become verbose.
|
||||
# Inline tables are enclosed in curly braces `{` and `}`. No newlines are
|
||||
# allowed between the curly braces unless they are valid within a value.
|
||||
|
||||
[table.inline]
|
||||
|
||||
name = { first = "Tom", last = "Preston-Werner" }
|
||||
point = { x = 1, y = 2 }
|
||||
|
||||
|
||||
################################################################################
|
||||
## String
|
||||
|
||||
# There are four ways to express strings: basic, multi-line basic, literal, and
|
||||
# multi-line literal. All strings must contain only valid UTF-8 characters.
|
||||
|
||||
[string.basic]
|
||||
|
||||
basic = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF."
|
||||
|
||||
[string.multiline]
|
||||
|
||||
# The following strings are byte-for-byte equivalent:
|
||||
key1 = "One\nTwo"
|
||||
key2 = """One\nTwo"""
|
||||
key3 = """
|
||||
One
|
||||
Two"""
|
||||
|
||||
[string.multiline.continued]
|
||||
|
||||
# The following strings are byte-for-byte equivalent:
|
||||
key1 = "The quick brown fox jumps over the lazy dog."
|
||||
|
||||
key2 = """
|
||||
The quick brown \
|
||||
|
||||
|
||||
fox jumps over \
|
||||
the lazy dog."""
|
||||
|
||||
key3 = """\
|
||||
The quick brown \
|
||||
fox jumps over \
|
||||
the lazy dog.\
|
||||
"""
|
||||
|
||||
[string.literal]
|
||||
|
||||
# What you see is what you get.
|
||||
winpath = 'C:\Users\nodejs\templates'
|
||||
winpath2 = '\\ServerX\admin$\system32\'
|
||||
quoted = 'Tom "Dubs" Preston-Werner'
|
||||
regex = '<\i\c*\s*>'
|
||||
|
||||
|
||||
[string.literal.multiline]
|
||||
|
||||
regex2 = '''I [dw]on't need \d{2} apples'''
|
||||
lines = '''
|
||||
The first newline is
|
||||
trimmed in raw strings.
|
||||
All other whitespace
|
||||
is preserved.
|
||||
'''
|
||||
|
||||
|
||||
################################################################################
|
||||
## Integer
|
||||
|
||||
# Integers are whole numbers. Positive numbers may be prefixed with a plus sign.
|
||||
# Negative numbers are prefixed with a minus sign.
|
||||
|
||||
[integer]
|
||||
|
||||
key1 = +99
|
||||
key2 = 42
|
||||
key3 = 0
|
||||
key4 = -17
|
||||
|
||||
[integer.underscores]
|
||||
|
||||
# For large numbers, you may use underscores to enhance readability. Each
|
||||
# underscore must be surrounded by at least one digit.
|
||||
key1 = 1_000
|
||||
key2 = 5_349_221
|
||||
key3 = 1_2_3_4_5 # valid but inadvisable
|
||||
|
||||
|
||||
################################################################################
|
||||
## Float
|
||||
|
||||
# A float consists of an integer part (which may be prefixed with a plus or
|
||||
# minus sign) followed by a fractional part and/or an exponent part.
|
||||
|
||||
[float.fractional]
|
||||
|
||||
key1 = +1.0
|
||||
key2 = 3.1415
|
||||
key3 = -0.01
|
||||
|
||||
[float.exponent]
|
||||
|
||||
[float.both]
|
||||
|
||||
[float.underscores]
|
||||
|
||||
|
||||
################################################################################
|
||||
## Boolean
|
||||
|
||||
# Booleans are just the tokens you're used to. Always lowercase.
|
||||
|
||||
[boolean]
|
||||
|
||||
True = true
|
||||
False = false
|
||||
|
||||
|
||||
################################################################################
|
||||
## Datetime
|
||||
|
||||
# Datetimes are RFC 3339 dates.
|
||||
|
||||
[datetime]
|
||||
|
||||
#key1 = 1979-05-27T07:32:00Z
|
||||
#key2 = 1979-05-27T00:32:00-07:00
|
||||
#key3 = 1979-05-27T00:32:00.999999-07:00
|
||||
|
||||
|
||||
################################################################################
|
||||
## Array
|
||||
|
||||
# Arrays are square brackets with other primitives inside. Whitespace is
|
||||
# ignored. Elements are separated by commas. Since 2019-11-06 data types can be
|
||||
# mixed.
|
||||
|
||||
[array]
|
||||
|
||||
key1 = [ 1, 2, 3 ]
|
||||
key2 = [ "red", "yellow", "green" ]
|
||||
key3 = [ [ 1, 2 ], [3, 4, 5] ]
|
||||
key4 = [ [ 1, 2 ], ["a", "b", "c"] ] # this is ok
|
||||
|
||||
# Arrays can also be multiline. So in addition to ignoring whitespace, arrays
|
||||
# also ignore newlines between the brackets. Terminating commas are ok before
|
||||
# the closing bracket.
|
||||
|
||||
key5 = [
|
||||
1, 2, 3
|
||||
]
|
||||
key6 = [
|
||||
1,
|
||||
2, # this is ok
|
||||
]
|
||||
|
||||
|
||||
################################################################################
|
||||
## Array of Tables
|
||||
|
||||
# These can be expressed by using a table name in double brackets. Each table
|
||||
# with the same double bracketed name will be an element in the array. The
|
||||
# tables are inserted in the order encountered.
|
||||
|
||||
[[products]]
|
||||
|
||||
name = "Hammer"
|
||||
sku = 738594937
|
||||
|
||||
[[products]]
|
||||
|
||||
[[products]]
|
||||
|
||||
name = "Nail"
|
||||
sku = 284758393
|
||||
color = "gray"
|
||||
|
||||
|
||||
# You can create nested arrays of tables as well.
|
||||
|
||||
[[fruit]]
|
||||
name = "apple"
|
||||
|
||||
[fruit.physical]
|
||||
color = "red"
|
||||
shape = "round"
|
||||
|
||||
[[fruit.variety]]
|
||||
name = "red delicious"
|
||||
|
||||
[[fruit.variety]]
|
||||
name = "granny smith"
|
||||
|
||||
[[fruit]]
|
||||
name = "banana"
|
||||
|
||||
[[fruit.variety]]
|
||||
name = "plantain"
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"best-day-ever": {"type": "datetime", "value": "1987-07-05T17:45:00Z"},
|
||||
"numtheory": {
|
||||
"boring": {"type": "bool", "value": "false"},
|
||||
"perfection": {
|
||||
"type": "array",
|
||||
"value": [
|
||||
{"type": "integer", "value": "6"},
|
||||
{"type": "integer", "value": "28"},
|
||||
{"type": "integer", "value": "496"}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
best-day-ever = 1987-07-05T17:45:00Z
|
||||
|
||||
[numtheory]
|
||||
boring = false
|
||||
perfection = [6, 28, 496]
|
||||
+1
@@ -0,0 +1 @@
|
||||
{"clients":{"data":{"type":"array","value":[{"type":"array","value":[{"type":"string","value":"gamma"},{"type":"string","value":"delta"}]},{"type":"array","value":[{"type":"integer","value":"1"},{"type":"integer","value":"2"}]}]},"hosts":{"type":"array","value":[{"type":"string","value":"alpha"},{"type":"string","value":"omega"}]}},"database":{"connection_max":{"type":"integer","value":"5000"},"enabled":{"type":"bool","value":"true"},"ports":{"type":"array","value":[{"type":"integer","value":"8001"},{"type":"integer","value":"8001"},{"type":"integer","value":"8002"}]},"server":{"type":"string","value":"192.168.1.1"}},"owner":{"bio":{"type":"string","value":"GitHub Cofounder \u0026 CEO\nLikes tater tots and beer."},"dob":{"type":"datetime","value":"1979-05-27T07:32:00Z"},"name":{"type":"string","value":"Tom Preston-Werner"},"organization":{"type":"string","value":"GitHub"}},"products":[{"name":{"type":"string","value":"Hammer"},"sku":{"type":"integer","value":"738594937"}},{"color":{"type":"string","value":"gray"},"name":{"type":"string","value":"Nail"},"sku":{"type":"integer","value":"284758393"}}],"servers":{"alpha":{"dc":{"type":"string","value":"eqdc10"},"ip":{"type":"string","value":"10.0.0.1"}},"beta":{"country":{"type":"string","value":"中国"},"dc":{"type":"string","value":"eqdc10"},"ip":{"type":"string","value":"10.0.0.2"}}},"title":{"type":"string","value":"TOML Example"}}
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
# This is a TOML document. Boom.
|
||||
|
||||
title = "TOML Example"
|
||||
|
||||
[owner]
|
||||
name = "Tom Preston-Werner"
|
||||
organization = "GitHub"
|
||||
bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
|
||||
dob = 1979-05-27T07:32:00Z # First class dates? Why not?
|
||||
|
||||
[database]
|
||||
server = "192.168.1.1"
|
||||
ports = [ 8001, 8001, 8002 ]
|
||||
connection_max = 5000
|
||||
enabled = true
|
||||
|
||||
[servers]
|
||||
|
||||
# You can indent as you please. Tabs or spaces. TOML don't care.
|
||||
[servers.alpha]
|
||||
ip = "10.0.0.1"
|
||||
dc = "eqdc10"
|
||||
|
||||
[servers.beta]
|
||||
ip = "10.0.0.2"
|
||||
dc = "eqdc10"
|
||||
country = "中国" # This should be parsed as UTF-8
|
||||
|
||||
[clients]
|
||||
data = [ ["gamma", "delta"], [1, 2] ] # just an update to make sure parsers support it
|
||||
|
||||
# Line breaks are OK when inside arrays
|
||||
hosts = [
|
||||
"alpha",
|
||||
"omega"
|
||||
]
|
||||
|
||||
# Products
|
||||
|
||||
[[products]]
|
||||
name = "Hammer"
|
||||
sku = 738594937
|
||||
|
||||
[[products]]
|
||||
name = "Nail"
|
||||
sku = 284758393
|
||||
color = "gray"
|
||||
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"lower": {"type": "float", "value": "300.0"},
|
||||
"upper": {"type": "float", "value": "300.0"},
|
||||
"neg": {"type": "float", "value": "0.03"},
|
||||
"pos": {"type": "float", "value": "300.0"},
|
||||
"zero": {"type": "float", "value": "3.0"},
|
||||
"pointlower": {"type": "float", "value": "310.0"},
|
||||
"pointupper": {"type": "float", "value": "310.0"},
|
||||
"prefix-zero-exp": {"type": "float", "value": "1000000.0"},
|
||||
"prefix-zero-exp-plus": {"type": "float", "value": "1000000.0"}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
lower = 3e2
|
||||
upper = 3E2
|
||||
neg = 3e-2
|
||||
pos = 3E+2
|
||||
zero = 3e0
|
||||
pointlower = 3.1e2
|
||||
pointupper = 3.1E2
|
||||
prefix-zero-exp = 1e06
|
||||
prefix-zero-exp-plus = 1e+06
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"pi": {"type": "float", "value": "3.14"},
|
||||
"negpi": {"type": "float", "value": "-3.14"}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
pi = 3.14
|
||||
negpi = -3.14
|
||||
@@ -0,0 +1 @@
|
||||
{"the":{"hard":{"another_test_string":{"type":"string","value":" Same thing, but with a string #"},"bit#":{"multi_line_array":{"type":"array","value":[{"type":"string","value":"]"}]},"what?":{"type":"string","value":"You don't think some user won't do that?"}},"harder_test_string":{"type":"string","value":" And when \"'s are in the string, along with # \""},"test_array":{"type":"array","value":[{"type":"string","value":"] "},{"type":"string","value":" # "}]},"test_array2":{"type":"array","value":[{"type":"string","value":"Test #11 ]proved that"},{"type":"string","value":"Experiment #9 was a success"}]}},"test_string":{"type":"string","value":"You'll hate me after this - #"}}}
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
# Test file for TOML
|
||||
# Only this one tries to emulate a TOML file written by a user of the kind of parser writers probably hate
|
||||
# This part you'll really hate
|
||||
|
||||
[the]
|
||||
test_string = "You'll hate me after this - #" # " Annoying, isn't it?
|
||||
|
||||
[the.hard]
|
||||
test_array = [ "] ", " # "] # ] There you go, parse this!
|
||||
test_array2 = [ "Test #11 ]proved that", "Experiment #9 was a success" ]
|
||||
# You didn't think it'd as easy as chucking out the last #, did you?
|
||||
another_test_string = " Same thing, but with a string #"
|
||||
harder_test_string = " And when \"'s are in the string, along with # \"" # "and comments are there too"
|
||||
# Things will get harder
|
||||
|
||||
[the.hard."bit#"]
|
||||
"what?" = "You don't think some user won't do that?"
|
||||
multi_line_array = [
|
||||
"]",
|
||||
# ] Oh yes I did
|
||||
]
|
||||
|
||||
# Each of the following keygroups/key value pairs should produce an error. Uncomment to them to test
|
||||
|
||||
#[error] if you didn't catch this, your parser is broken
|
||||
#string = "Anything other than tabs, spaces and newline after a keygroup or key value pair has ended should produce an error unless it is a comment" like this
|
||||
#array = [
|
||||
# "This might most likely happen in multiline arrays",
|
||||
# Like here,
|
||||
# "or here,
|
||||
# and here"
|
||||
# ] End of array comment, forgot the #
|
||||
#number = 3.14 pi <--again forgot the #
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"a": {
|
||||
"better": {"type": "integer", "value": "43"},
|
||||
"b": {
|
||||
"c": {
|
||||
"answer": {"type": "integer", "value": "42"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
[a.b.c]
|
||||
answer = 42
|
||||
|
||||
[a]
|
||||
better = 43
|
||||
Loaded 100 of 17624 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user