aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/de.rs208
-rw-r--r--test-suite/tests/datetime.rs56
-rw-r--r--test-suite/tests/de-errors.rs63
-rw-r--r--test-suite/tests/invalid-misc.rs7
-rw-r--r--test-suite/tests/invalid.rs10
-rw-r--r--test-suite/tests/parser.rs37
-rw-r--r--test-suite/tests/serde.rs4
7 files changed, 260 insertions, 125 deletions
diff --git a/src/de.rs b/src/de.rs
index f65492d..aa2a41b 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -29,7 +29,7 @@ where
{
match str::from_utf8(bytes) {
Ok(s) => from_str(s),
- Err(e) => Err(Error::custom(e.to_string())),
+ Err(e) => Err(Error::custom(None, e.to_string())),
}
}
@@ -87,6 +87,7 @@ struct ErrorInner {
kind: ErrorKind,
line: Option<usize>,
col: usize,
+ at: Option<usize>,
message: String,
key: Vec<String>,
}
@@ -209,7 +210,7 @@ impl<'de, 'b> de::Deserializer<'de> for &'b mut Deserializer<'de> {
{
let mut tables = self.tables()?;
- visitor.visit_map(MapVisitor {
+ let res = visitor.visit_map(MapVisitor {
values: Vec::new().into_iter(),
next_value: None,
depth: 0,
@@ -219,6 +220,17 @@ impl<'de, 'b> de::Deserializer<'de> for &'b mut Deserializer<'de> {
tables: &mut tables,
array: false,
de: self,
+ });
+ res.map_err(|mut err| {
+ // Errors originating from this library (toml), have an offset
+ // attached to them already. Other errors, like those originating
+ // from serde (like "missing field") or from a custom deserializer,
+ // do not have offsets on them. Here, we do a best guess at their
+ // location, by attributing them to the "current table" (the last
+ // item in `tables`).
+ err.fix_offset(|| tables.last().map(|table| table.at));
+ err.fix_linecol(|at| self.to_linecol(at));
+ err
})
}
@@ -237,14 +249,17 @@ impl<'de, 'b> de::Deserializer<'de> for &'b mut Deserializer<'de> {
E::String(val) => visitor.visit_enum(val.into_deserializer()),
E::InlineTable(values) => {
if values.len() != 1 {
- Err(Error::from_kind(ErrorKind::Wanted {
- expected: "exactly 1 element",
- found: if values.is_empty() {
- "zero elements"
- } else {
- "more than 1 element"
+ Err(Error::from_kind(
+ Some(value.start),
+ ErrorKind::Wanted {
+ expected: "exactly 1 element",
+ found: if values.is_empty() {
+ "zero elements"
+ } else {
+ "more than 1 element"
+ },
},
- }))
+ ))
} else {
visitor.visit_enum(InlineTableDeserializer {
values: values.into_iter(),
@@ -256,10 +271,13 @@ impl<'de, 'b> de::Deserializer<'de> for &'b mut Deserializer<'de> {
name: name.expect("Expected table header to be passed."),
value: value,
}),
- e @ _ => Err(Error::from_kind(ErrorKind::Wanted {
- expected: "string or table",
- found: e.type_name(),
- })),
+ e @ _ => Err(Error::from_kind(
+ Some(value.start),
+ ErrorKind::Wanted {
+ expected: "string or table",
+ found: e.type_name(),
+ },
+ )),
}
}
@@ -556,7 +574,8 @@ impl<'de> de::Deserializer<'de> for ValueDeserializer<'de> {
where
V: de::Visitor<'de>,
{
- match self.value.e {
+ let start = self.value.start;
+ let res = match self.value.e {
E::Integer(i) => visitor.visit_i64(i),
E::Boolean(b) => visitor.visit_bool(b),
E::Float(f) => visitor.visit_f64(f),
@@ -578,7 +597,12 @@ impl<'de> de::Deserializer<'de> for ValueDeserializer<'de> {
next_value: None,
})
}
- }
+ };
+ res.map_err(|mut err| {
+ // Attribute the error to whatever value returned the error.
+ err.fix_offset(|| Some(start));
+ err
+ })
}
fn deserialize_struct<V>(
@@ -615,13 +639,16 @@ impl<'de> de::Deserializer<'de> for ValueDeserializer<'de> {
.collect::<Vec<Cow<'de, str>>>();
if !extra_fields.is_empty() {
- return Err(Error::from_kind(ErrorKind::UnexpectedKeys {
- keys: extra_fields
- .iter()
- .map(|k| k.to_string())
- .collect::<Vec<_>>(),
- available: fields,
- }));
+ return Err(Error::from_kind(
+ Some(self.value.start),
+ ErrorKind::UnexpectedKeys {
+ keys: extra_fields
+ .iter()
+ .map(|k| k.to_string())
+ .collect::<Vec<_>>(),
+ available: fields,
+ },
+ ));
}
}
_ => {}
@@ -664,14 +691,17 @@ impl<'de> de::Deserializer<'de> for ValueDeserializer<'de> {
E::String(val) => visitor.visit_enum(val.into_deserializer()),
E::InlineTable(values) => {
if values.len() != 1 {
- Err(Error::from_kind(ErrorKind::Wanted {
- expected: "exactly 1 element",
- found: if values.is_empty() {
- "zero elements"
- } else {
- "more than 1 element"
+ Err(Error::from_kind(
+ Some(self.value.start),
+ ErrorKind::Wanted {
+ expected: "exactly 1 element",
+ found: if values.is_empty() {
+ "zero elements"
+ } else {
+ "more than 1 element"
+ },
},
- }))
+ ))
} else {
visitor.visit_enum(InlineTableDeserializer {
values: values.into_iter(),
@@ -679,10 +709,13 @@ impl<'de> de::Deserializer<'de> for ValueDeserializer<'de> {
})
}
}
- e @ _ => Err(Error::from_kind(ErrorKind::Wanted {
- expected: "string or inline table",
- found: e.type_name(),
- })),
+ e @ _ => Err(Error::from_kind(
+ Some(self.value.start),
+ ErrorKind::Wanted {
+ expected: "string or inline table",
+ found: e.type_name(),
+ },
+ )),
}
}
@@ -860,10 +893,13 @@ impl<'de> de::EnumAccess<'de> for InlineTableDeserializer<'de> {
let (key, value) = match self.values.next() {
Some(pair) => pair,
None => {
- return Err(Error::from_kind(ErrorKind::Wanted {
- expected: "table with exactly 1 entry",
- found: "empty table",
- }))
+ return Err(Error::from_kind(
+ None, // FIXME: How do we get an offset here?
+ ErrorKind::Wanted {
+ expected: "table with exactly 1 entry",
+ found: "empty table",
+ },
+ ));
}
};
@@ -886,13 +922,19 @@ impl<'de> de::VariantAccess<'de> for TableEnumDeserializer<'de> {
if values.len() == 0 {
Ok(())
} else {
- Err(Error::from_kind(ErrorKind::ExpectedEmptyTable))
+ Err(Error::from_kind(
+ Some(self.value.start),
+ ErrorKind::ExpectedEmptyTable,
+ ))
}
}
- e @ _ => Err(Error::from_kind(ErrorKind::Wanted {
- expected: "table",
- found: e.type_name(),
- })),
+ e @ _ => Err(Error::from_kind(
+ Some(self.value.start),
+ ErrorKind::Wanted {
+ expected: "table",
+ found: e.type_name(),
+ },
+ )),
}
}
@@ -914,10 +956,13 @@ impl<'de> de::VariantAccess<'de> for TableEnumDeserializer<'de> {
.enumerate()
.map(|(index, (key, value))| match key.parse::<usize>() {
Ok(key_index) if key_index == index => Ok(value),
- Ok(_) | Err(_) => Err(Error::from_kind(ErrorKind::ExpectedTupleIndex {
- expected: index,
- found: key.to_string(),
- })),
+ Ok(_) | Err(_) => Err(Error::from_kind(
+ Some(value.start),
+ ErrorKind::ExpectedTupleIndex {
+ expected: index,
+ found: key.to_string(),
+ },
+ )),
})
// Fold all values into a `Vec`, or return the first error.
.fold(Ok(Vec::with_capacity(len)), |result, value_result| {
@@ -941,13 +986,19 @@ impl<'de> de::VariantAccess<'de> for TableEnumDeserializer<'de> {
visitor,
)
} else {
- Err(Error::from_kind(ErrorKind::ExpectedTuple(len)))
+ Err(Error::from_kind(
+ Some(self.value.start),
+ ErrorKind::ExpectedTuple(len),
+ ))
}
}
- e @ _ => Err(Error::from_kind(ErrorKind::Wanted {
- expected: "table",
- found: e.type_name(),
- })),
+ e @ _ => Err(Error::from_kind(
+ Some(self.value.start),
+ ErrorKind::Wanted {
+ expected: "table",
+ found: e.type_name(),
+ },
+ )),
}
}
@@ -1195,17 +1246,20 @@ impl<'a> Deserializer<'a> {
/// structures (tuple, newtype, struct) must be represented as a table.
fn string_or_table(&mut self) -> Result<(Value<'a>, Option<Cow<'a, str>>), Error> {
match self.peek()? {
- Some((_, Token::LeftBracket)) => {
+ Some((span, Token::LeftBracket)) => {
let tables = self.tables()?;
if tables.len() != 1 {
- return Err(Error::from_kind(ErrorKind::Wanted {
- expected: "exactly 1 table",
- found: if tables.is_empty() {
- "zero tables"
- } else {
- "more than 1 table"
+ return Err(Error::from_kind(
+ Some(span.start),
+ ErrorKind::Wanted {
+ expected: "exactly 1 table",
+ found: if tables.is_empty() {
+ "zero tables"
+ } else {
+ "more than 1 table"
+ },
},
- }));
+ ));
}
let table = tables
@@ -1710,10 +1764,8 @@ impl<'a> Deserializer<'a> {
}
fn error(&self, at: usize, kind: ErrorKind) -> Error {
- let mut err = Error::from_kind(kind);
- let (line, col) = self.to_linecol(at);
- err.inner.line = Some(line);
- err.inner.col = col;
+ let mut err = Error::from_kind(Some(at), kind);
+ err.fix_linecol(|at| self.to_linecol(at));
err
}
@@ -1740,24 +1792,26 @@ impl Error {
self.inner.line.map(|line| (line, self.inner.col))
}
- fn from_kind(kind: ErrorKind) -> Error {
+ fn from_kind(at: Option<usize>, kind: ErrorKind) -> Error {
Error {
inner: Box::new(ErrorInner {
kind: kind,
line: None,
col: 0,
+ at,
message: String::new(),
key: Vec::new(),
}),
}
}
- fn custom(s: String) -> Error {
+ fn custom(at: Option<usize>, s: String) -> Error {
Error {
inner: Box::new(ErrorInner {
kind: ErrorKind::Custom,
line: None,
col: 0,
+ at,
message: s,
key: Vec::new(),
}),
@@ -1770,6 +1824,28 @@ impl Error {
pub fn add_key_context(&mut self, key: &str) {
self.inner.key.insert(0, key.to_string());
}
+
+ fn fix_offset<F>(&mut self, f: F) -> ()
+ where
+ F: FnOnce() -> Option<usize>,
+ {
+ // An existing offset is always better positioned than anything we
+ // might want to add later.
+ if self.inner.at.is_none() {
+ self.inner.at = f();
+ }
+ }
+
+ fn fix_linecol<F>(&mut self, f: F) -> ()
+ where
+ F: FnOnce(usize) -> (usize, usize),
+ {
+ if let Some(at) = self.inner.at {
+ let (line, col) = f(at);
+ self.inner.line = Some(line);
+ self.inner.col = col;
+ }
+ }
}
impl fmt::Display for Error {
@@ -1885,7 +1961,7 @@ impl error::Error for Error {
impl de::Error for Error {
fn custom<T: fmt::Display>(msg: T) -> Error {
- Error::custom(msg.to_string())
+ Error::custom(None, msg.to_string())
}
}
diff --git a/test-suite/tests/datetime.rs b/test-suite/tests/datetime.rs
index 4855f54..74b5939 100644
--- a/test-suite/tests/datetime.rs
+++ b/test-suite/tests/datetime.rs
@@ -42,75 +42,93 @@ fn times() {
#[test]
fn bad_times() {
- bad!("foo = 199-09-09", "failed to parse datetime for key `foo`");
- bad!("foo = 199709-09", "failed to parse datetime for key `foo`");
- bad!("foo = 1997-9-09", "failed to parse datetime for key `foo`");
- bad!("foo = 1997-09-9", "failed to parse datetime for key `foo`");
+ bad!(
+ "foo = 199-09-09",
+ "failed to parse datetime for key `foo` at line 1 column 7"
+ );
+ bad!(
+ "foo = 199709-09",
+ "failed to parse datetime for key `foo` at line 1 column 7"
+ );
+ bad!(
+ "foo = 1997-9-09",
+ "failed to parse datetime for key `foo` at line 1 column 7"
+ );
+ bad!(
+ "foo = 1997-09-9",
+ "failed to parse datetime for key `foo` at line 1 column 7"
+ );
bad!(
"foo = 1997-09-0909:09:09",
- "failed to parse datetime for key `foo`"
+ "failed to parse datetime for key `foo` at line 1 column 7"
);
bad!(
"foo = 1997-09-09T09:09:09.",
"invalid date at line 1 column 7"
);
- bad!("foo = T", "failed to parse datetime for key `foo`");
+ bad!(
+ "foo = T",
+ "failed to parse datetime for key `foo` at line 1 column 7"
+ );
bad!(
"foo = T.",
"expected newline, found a period at line 1 column 8"
);
- bad!("foo = TZ", "failed to parse datetime for key `foo`");
+ bad!(
+ "foo = TZ",
+ "failed to parse datetime for key `foo` at line 1 column 7"
+ );
bad!(
"foo = 1997-09-09T09:09:09.09+",
"invalid date at line 1 column 7"
);
bad!(
"foo = 1997-09-09T09:09:09.09+09",
- "failed to parse datetime for key `foo`"
+ "failed to parse datetime for key `foo` at line 1 column 7"
);
bad!(
"foo = 1997-09-09T09:09:09.09+09:9",
- "failed to parse datetime for key `foo`"
+ "failed to parse datetime for key `foo` at line 1 column 7"
);
bad!(
"foo = 1997-09-09T09:09:09.09+0909",
- "failed to parse datetime for key `foo`"
+ "failed to parse datetime for key `foo` at line 1 column 7"
);
bad!(
"foo = 1997-09-09T09:09:09.09-",
- "failed to parse datetime for key `foo`"
+ "failed to parse datetime for key `foo` at line 1 column 7"
);
bad!(
"foo = 1997-09-09T09:09:09.09-09",
- "failed to parse datetime for key `foo`"
+ "failed to parse datetime for key `foo` at line 1 column 7"
);
bad!(
"foo = 1997-09-09T09:09:09.09-09:9",
- "failed to parse datetime for key `foo`"
+ "failed to parse datetime for key `foo` at line 1 column 7"
);
bad!(
"foo = 1997-09-09T09:09:09.09-0909",
- "failed to parse datetime for key `foo`"
+ "failed to parse datetime for key `foo` at line 1 column 7"
);
bad!(
"foo = 1997-00-09T09:09:09.09Z",
- "failed to parse datetime for key `foo`"
+ "failed to parse datetime for key `foo` at line 1 column 7"
);
bad!(
"foo = 1997-09-00T09:09:09.09Z",
- "failed to parse datetime for key `foo`"
+ "failed to parse datetime for key `foo` at line 1 column 7"
);
bad!(
"foo = 1997-09-09T30:09:09.09Z",
- "failed to parse datetime for key `foo`"
+ "failed to parse datetime for key `foo` at line 1 column 7"
);
bad!(
"foo = 1997-09-09T12:69:09.09Z",
- "failed to parse datetime for key `foo`"
+ "failed to parse datetime for key `foo` at line 1 column 7"
);
bad!(
"foo = 1997-09-09T12:09:69.09Z",
- "failed to parse datetime for key `foo`"
+ "failed to parse datetime for key `foo` at line 1 column 7"
);
}
diff --git a/test-suite/tests/de-errors.rs b/test-suite/tests/de-errors.rs
index d2e8f64..7cceb7b 100644
--- a/test-suite/tests/de-errors.rs
+++ b/test-suite/tests/de-errors.rs
@@ -83,18 +83,20 @@ fn custom_errors() {
bad!(
"
p_a = ''
+ # ^
",
Parent<CasedString>,
- "invalid length 0, expected a non-empty string for key `p_a`"
+ "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`"
+ "missing field `p_b` at line 1 column 1"
);
// Invalid type in p_b.
@@ -102,9 +104,10 @@ fn custom_errors() {
"
p_a = 'a'
p_b = 1
+ # ^
",
Parent<CasedString>,
- "invalid type: integer `1`, expected a sequence for key `p_b`"
+ "invalid type: integer `1`, expected a sequence for key `p_b` at line 3 column 19"
);
// Sub-table in Vec is missing a field.
@@ -113,10 +116,11 @@ fn custom_errors() {
p_a = 'a'
p_b = [
{c_a = 'a'}
+ # ^
]
",
Parent<CasedString>,
- "missing field `c_b` for key `p_b`"
+ "missing field `c_b` for key `p_b` at line 4 column 17"
);
// Sub-table in Vec has a field with a bad value.
@@ -125,10 +129,11 @@ fn custom_errors() {
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`"
+ "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.
@@ -138,10 +143,11 @@ fn custom_errors() {
p_b = [
{c_a = 'a', c_b = 'b'},
{c_a = 'aa'}
+ # ^
]
",
Parent<CasedString>,
- "missing field `c_b` for key `p_b`"
+ "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.
@@ -151,11 +157,12 @@ fn custom_errors() {
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`"
+ "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.
@@ -165,28 +172,33 @@ fn custom_errors() {
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`"
+ "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`" // FIX ME
+ "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'
@@ -195,12 +207,17 @@ fn custom_errors() {
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`"
+ "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.
@@ -213,15 +230,17 @@ fn custom_errors() {
[[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`"
+ "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'
@@ -234,9 +253,13 @@ fn custom_errors() {
[[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`"
+ "unknown field `c_d`, expected `c_a` or `c_b` for key `p_b` at line 12 column 13"
);
}
@@ -245,9 +268,10 @@ fn serde_derive_deserialize_errors() {
bad!(
"
p_a = ''
+ # ^
",
Parent<String>,
- "missing field `p_b`"
+ "missing field `p_b` at line 1 column 1"
);
bad!(
@@ -255,10 +279,11 @@ fn serde_derive_deserialize_errors() {
p_a = ''
p_b = [
{c_a = ''}
+ # ^
]
",
Parent<String>,
- "missing field `c_b` for key `p_b`"
+ "missing field `c_b` for key `p_b` at line 4 column 17"
);
bad!(
@@ -266,21 +291,24 @@ fn serde_derive_deserialize_errors() {
p_a = ''
p_b = [
{c_a = '', c_b = 1}
+ # ^
]
",
Parent<String>,
- "invalid type: integer `1`, expected a string for key `p_b`"
+ "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`" // FIX ME
+ "unknown field `c_d`, expected `c_a` or `c_b` for key `p_b` at line 4 column 17"
);
bad!(
@@ -288,9 +316,10 @@ fn serde_derive_deserialize_errors() {
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`"
+ "invalid type: integer `1`, expected a string for key `p_b` at line 4 column 34"
);
}
diff --git a/test-suite/tests/invalid-misc.rs b/test-suite/tests/invalid-misc.rs
index f18012a..cea0801 100644
--- a/test-suite/tests/invalid-misc.rs
+++ b/test-suite/tests/invalid-misc.rs
@@ -27,14 +27,17 @@ fn bad() {
);
bad!("a = -0x1", "invalid number at line 1 column 5");
- bad!("a = 0x-1", "failed to parse datetime for key `a`");
+ bad!(
+ "a = 0x-1",
+ "failed to parse datetime for key `a` at line 1 column 5"
+ );
// Dotted keys.
bad!(
"a.b.c = 1
a.b = 2
",
- "duplicate key: `b` for key `a`"
+ "duplicate key: `b` for key `a` at line 1 column 9"
);
bad!(
"a = 1
diff --git a/test-suite/tests/invalid.rs b/test-suite/tests/invalid.rs
index bfde2d4..3312629 100644
--- a/test-suite/tests/invalid.rs
+++ b/test-suite/tests/invalid.rs
@@ -32,7 +32,7 @@ test!(
test!(
datetime_malformed_no_leads,
include_str!("invalid/datetime-malformed-no-leads.toml"),
- "failed to parse datetime for key `no-leads`"
+ "failed to parse datetime for key `no-leads` at line 1 column 12"
);
test!(
datetime_malformed_no_secs,
@@ -42,22 +42,22 @@ test!(
test!(
datetime_malformed_no_t,
include_str!("invalid/datetime-malformed-no-t.toml"),
- "failed to parse datetime for key `no-t`"
+ "failed to parse datetime for key `no-t` at line 1 column 8"
);
test!(
datetime_malformed_with_milli,
include_str!("invalid/datetime-malformed-with-milli.toml"),
- "failed to parse datetime for key `with-milli`"
+ "failed to parse datetime for key `with-milli` at line 1 column 14"
);
test!(
duplicate_key_table,
include_str!("invalid/duplicate-key-table.toml"),
- "duplicate key: `type` for key `fruit`"
+ "duplicate key: `type` for key `fruit` at line 4 column 1"
);
test!(
duplicate_keys,
include_str!("invalid/duplicate-keys.toml"),
- "duplicate key: `dupe`"
+ "duplicate key: `dupe` at line 1 column 1"
);
test!(
duplicate_table,
diff --git a/test-suite/tests/parser.rs b/test-suite/tests/parser.rs
index 1a684c5..012bd65 100644
--- a/test-suite/tests/parser.rs
+++ b/test-suite/tests/parser.rs
@@ -453,7 +453,10 @@ fn inline_tables() {
"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`");
+ bad!(
+ "a = {a=1,a=1}",
+ "duplicate key: `a` for key `a` at line 1 column 5"
+ );
bad!(
"a = {\n}",
"expected a table key, found a newline at line 1 column 6"
@@ -533,9 +536,15 @@ fn booleans() {
let table = "foo = false".parse::<Value>().unwrap();
assert_eq!(table["foo"].as_bool(), Some(false));
- bad!("foo = true2", "failed to parse datetime for key `foo`");
+ bad!(
+ "foo = true2",
+ "failed to parse datetime for key `foo` at line 1 column 7"
+ );
bad!("foo = false2", "invalid number at line 1 column 7");
- bad!("foo = t1", "failed to parse datetime for key `foo`");
+ bad!(
+ "foo = t1",
+ "failed to parse datetime for key `foo` at line 1 column 7"
+ );
bad!("foo = f2", "invalid number at line 1 column 7");
}
@@ -547,28 +556,28 @@ fn bad_nesting() {
[[a]]
b = 5
",
- "duplicate key: `a`"
+ "duplicate key: `a` at line 3 column 9"
);
bad!(
"
a = 1
[a.b]
",
- "duplicate key: `a`"
+ "duplicate key: `a` at line 3 column 9"
);
bad!(
"
a = []
[a.b]
",
- "duplicate key: `a`"
+ "duplicate key: `a` at line 3 column 9"
);
bad!(
"
a = []
[[a.b]]
",
- "duplicate key: `a`"
+ "duplicate key: `a` at line 3 column 9"
);
bad!(
"
@@ -577,7 +586,7 @@ fn bad_nesting() {
[a.b]
c = 2
",
- "duplicate key: `b` for key `a`"
+ "duplicate key: `b` for key `a` at line 4 column 9"
);
}
@@ -608,7 +617,7 @@ fn bad_table_redefine() {
b = {}
[a.b]
",
- "duplicate key: `b` for key `a`"
+ "duplicate key: `b` for key `a` at line 4 column 9"
);
bad!(
@@ -637,23 +646,23 @@ fn datetimes() {
t!("2016-09-09T09:09:09.123456789-02:00");
bad!(
"foo = 2016-09-09T09:09:09.Z",
- "failed to parse datetime for key `foo`"
+ "failed to parse datetime for key `foo` at line 1 column 7"
);
bad!(
"foo = 2016-9-09T09:09:09Z",
- "failed to parse datetime for key `foo`"
+ "failed to parse datetime for key `foo` at line 1 column 7"
);
bad!(
"foo = 2016-09-09T09:09:09+2:00",
- "failed to parse datetime for key `foo`"
+ "failed to parse datetime for key `foo` at line 1 column 7"
);
bad!(
"foo = 2016-09-09T09:09:09-2:00",
- "failed to parse datetime for key `foo`"
+ "failed to parse datetime for key `foo` at line 1 column 7"
);
bad!(
"foo = 2016-09-09T09:09:09Z-2:00",
- "failed to parse datetime for key `foo`"
+ "failed to parse datetime for key `foo` at line 1 column 7"
);
}
diff --git a/test-suite/tests/serde.rs b/test-suite/tests/serde.rs
index 95b8bc4..56172bd 100644
--- a/test-suite/tests/serde.rs
+++ b/test-suite/tests/serde.rs
@@ -273,7 +273,7 @@ fn type_errors() {
Table(map! {
bar: Value::String("a".to_string())
}),
- "invalid type: string \"a\", expected isize for key `bar`",
+ "invalid type: string \"a\", expected isize for key `bar` at line 1 column 7",
"invalid type: string \"a\", expected isize for key `bar`"
}
@@ -290,7 +290,7 @@ fn type_errors() {
bar: Value::String("a".to_string())
})
}),
- "invalid type: string \"a\", expected isize for key `foo.bar`",
+ "invalid type: string \"a\", expected isize for key `foo.bar` at line 2 column 7",
"invalid type: string \"a\", expected isize for key `foo.bar`"
}
}