diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:41 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:41:41 +0000 |
commit | 10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87 (patch) | |
tree | bdffd5d80c26cf4a7a518281a204be1ace85b4c1 /vendor/toml/tests | |
parent | Releasing progress-linux version 1.70.0+dfsg1-9~progress7.99u1. (diff) | |
download | rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.tar.xz rustc-10ee2acdd26a7f1298c6f6d6b7af9b469fe29b87.zip |
Merging upstream version 1.70.0+dfsg2.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/toml/tests')
-rw-r--r-- | vendor/toml/tests/decoder.rs | 67 | ||||
-rw-r--r-- | vendor/toml/tests/decoder_compliance.rs | 21 | ||||
-rw-r--r-- | vendor/toml/tests/encoder.rs | 81 | ||||
-rw-r--r-- | vendor/toml/tests/encoder_compliance.rs | 14 | ||||
-rw-r--r-- | vendor/toml/tests/testsuite/de_errors.rs | 460 | ||||
-rw-r--r-- | vendor/toml/tests/testsuite/display.rs | 116 | ||||
-rw-r--r-- | vendor/toml/tests/testsuite/display_tricky.rs | 55 | ||||
-rw-r--r-- | vendor/toml/tests/testsuite/enum_external_deserialize.rs | 320 | ||||
-rw-r--r-- | vendor/toml/tests/testsuite/float.rs | 80 | ||||
-rw-r--r-- | vendor/toml/tests/testsuite/formatting.rs | 54 | ||||
-rw-r--r-- | vendor/toml/tests/testsuite/macros.rs | 368 | ||||
-rw-r--r-- | vendor/toml/tests/testsuite/main.rs | 15 | ||||
-rw-r--r-- | vendor/toml/tests/testsuite/pretty.rs | 184 | ||||
-rw-r--r-- | vendor/toml/tests/testsuite/serde.rs | 1074 | ||||
-rw-r--r-- | vendor/toml/tests/testsuite/spanned.rs | 261 | ||||
-rw-r--r-- | vendor/toml/tests/testsuite/spanned_impls.rs | 41 | ||||
-rw-r--r-- | vendor/toml/tests/testsuite/tables_last.rs | 162 |
17 files changed, 3373 insertions, 0 deletions
diff --git a/vendor/toml/tests/decoder.rs b/vendor/toml/tests/decoder.rs new file mode 100644 index 000000000..fe6db3f5e --- /dev/null +++ b/vendor/toml/tests/decoder.rs @@ -0,0 +1,67 @@ +#![cfg(all(feature = "parse", feature = "display"))] + +#[derive(Copy, Clone)] +pub struct Decoder; + +impl toml_test_harness::Decoder for Decoder { + fn name(&self) -> &str { + "toml" + } + + fn decode(&self, data: &[u8]) -> Result<toml_test_harness::Decoded, toml_test_harness::Error> { + let data = std::str::from_utf8(data).map_err(toml_test_harness::Error::new)?; + let document = data + .parse::<toml::Value>() + .map_err(toml_test_harness::Error::new)?; + value_to_decoded(&document) + } +} + +fn value_to_decoded( + value: &toml::Value, +) -> Result<toml_test_harness::Decoded, toml_test_harness::Error> { + match value { + toml::Value::Integer(v) => Ok(toml_test_harness::Decoded::Value( + toml_test_harness::DecodedValue::from(*v), + )), + toml::Value::String(v) => Ok(toml_test_harness::Decoded::Value( + toml_test_harness::DecodedValue::from(v), + )), + toml::Value::Float(v) => Ok(toml_test_harness::Decoded::Value( + toml_test_harness::DecodedValue::from(*v), + )), + toml::Value::Datetime(v) => { + let value = v.to_string(); + let value = match (v.date.is_some(), v.time.is_some(), v.offset.is_some()) { + (true, true, true) => toml_test_harness::DecodedValue::Datetime(value), + (true, true, false) => toml_test_harness::DecodedValue::DatetimeLocal(value), + (true, false, false) => toml_test_harness::DecodedValue::DateLocal(value), + (false, true, false) => toml_test_harness::DecodedValue::TimeLocal(value), + _ => unreachable!("Unsupported case"), + }; + Ok(toml_test_harness::Decoded::Value(value)) + } + toml::Value::Boolean(v) => Ok(toml_test_harness::Decoded::Value( + toml_test_harness::DecodedValue::from(*v), + )), + toml::Value::Array(v) => { + let v: Result<_, toml_test_harness::Error> = v.iter().map(value_to_decoded).collect(); + Ok(toml_test_harness::Decoded::Array(v?)) + } + toml::Value::Table(v) => table_to_decoded(v), + } +} + +fn table_to_decoded( + value: &toml::value::Table, +) -> Result<toml_test_harness::Decoded, toml_test_harness::Error> { + let table: Result<_, toml_test_harness::Error> = value + .iter() + .map(|(k, v)| { + let k = k.to_owned(); + let v = value_to_decoded(v)?; + Ok((k, v)) + }) + .collect(); + Ok(toml_test_harness::Decoded::Table(table?)) +} diff --git a/vendor/toml/tests/decoder_compliance.rs b/vendor/toml/tests/decoder_compliance.rs new file mode 100644 index 000000000..5d4fc2a4d --- /dev/null +++ b/vendor/toml/tests/decoder_compliance.rs @@ -0,0 +1,21 @@ +mod decoder; + +#[cfg(all(feature = "parse", feature = "display"))] +fn main() { + let decoder = decoder::Decoder; + let mut harness = toml_test_harness::DecoderHarness::new(decoder); + harness + .ignore([ + "valid/spec/float-0.toml", + // Unreleased + "valid/string/escape-esc.toml", + "valid/string/hex-escape.toml", + "valid/datetime/no-seconds.toml", + "valid/inline-table/newline.toml", + ]) + .unwrap(); + harness.test(); +} + +#[cfg(not(all(feature = "parse", feature = "display")))] +fn main() {} diff --git a/vendor/toml/tests/encoder.rs b/vendor/toml/tests/encoder.rs new file mode 100644 index 000000000..eda62963c --- /dev/null +++ b/vendor/toml/tests/encoder.rs @@ -0,0 +1,81 @@ +#![cfg(all(feature = "parse", feature = "display"))] + +#[derive(Copy, Clone)] +pub struct Encoder; + +impl toml_test_harness::Encoder for Encoder { + fn name(&self) -> &str { + "toml" + } + + fn encode(&self, data: toml_test_harness::Decoded) -> Result<String, toml_test_harness::Error> { + let value = from_decoded(&data)?; + let s = toml::to_string(&value).map_err(toml_test_harness::Error::new)?; + Ok(s) + } +} + +fn from_decoded( + decoded: &toml_test_harness::Decoded, +) -> Result<toml::Value, toml_test_harness::Error> { + let value = match decoded { + toml_test_harness::Decoded::Value(value) => from_decoded_value(value)?, + toml_test_harness::Decoded::Table(value) => toml::Value::Table(from_table(value)?), + toml_test_harness::Decoded::Array(value) => toml::Value::Array(from_array(value)?), + }; + Ok(value) +} + +fn from_decoded_value( + decoded: &toml_test_harness::DecodedValue, +) -> Result<toml::Value, toml_test_harness::Error> { + match decoded { + toml_test_harness::DecodedValue::String(value) => Ok(toml::Value::String(value.clone())), + toml_test_harness::DecodedValue::Integer(value) => value + .parse::<i64>() + .map_err(toml_test_harness::Error::new) + .map(toml::Value::Integer), + toml_test_harness::DecodedValue::Float(value) => value + .parse::<f64>() + .map_err(toml_test_harness::Error::new) + .map(toml::Value::Float), + toml_test_harness::DecodedValue::Bool(value) => value + .parse::<bool>() + .map_err(toml_test_harness::Error::new) + .map(toml::Value::Boolean), + toml_test_harness::DecodedValue::Datetime(value) => value + .parse::<toml::value::Datetime>() + .map_err(toml_test_harness::Error::new) + .map(toml::Value::Datetime), + toml_test_harness::DecodedValue::DatetimeLocal(value) => value + .parse::<toml::value::Datetime>() + .map_err(toml_test_harness::Error::new) + .map(toml::Value::Datetime), + toml_test_harness::DecodedValue::DateLocal(value) => value + .parse::<toml::value::Datetime>() + .map_err(toml_test_harness::Error::new) + .map(toml::Value::Datetime), + toml_test_harness::DecodedValue::TimeLocal(value) => value + .parse::<toml::value::Datetime>() + .map_err(toml_test_harness::Error::new) + .map(toml::Value::Datetime), + } +} + +fn from_table( + decoded: &std::collections::HashMap<String, toml_test_harness::Decoded>, +) -> Result<toml::value::Table, toml_test_harness::Error> { + decoded + .iter() + .map(|(k, v)| { + let v = from_decoded(v)?; + Ok((k.to_owned(), v)) + }) + .collect() +} + +fn from_array( + decoded: &[toml_test_harness::Decoded], +) -> Result<toml::value::Array, toml_test_harness::Error> { + decoded.iter().map(from_decoded).collect() +} diff --git a/vendor/toml/tests/encoder_compliance.rs b/vendor/toml/tests/encoder_compliance.rs new file mode 100644 index 000000000..380724831 --- /dev/null +++ b/vendor/toml/tests/encoder_compliance.rs @@ -0,0 +1,14 @@ +mod decoder; +mod encoder; + +#[cfg(all(feature = "parse", feature = "display"))] +fn main() { + let encoder = encoder::Encoder; + let decoder = decoder::Decoder; + let mut harness = toml_test_harness::EncoderHarness::new(encoder, decoder); + harness.ignore(["valid/spec/float-0.toml"]).unwrap(); + harness.test(); +} + +#[cfg(not(all(feature = "parse", feature = "display")))] +fn main() {} diff --git a/vendor/toml/tests/testsuite/de_errors.rs b/vendor/toml/tests/testsuite/de_errors.rs new file mode 100644 index 000000000..b3630bd4e --- /dev/null +++ b/vendor/toml/tests/testsuite/de_errors.rs @@ -0,0 +1,460 @@ +use serde::{de, Deserialize}; +use std::fmt; + +macro_rules! bad { + ($toml:expr, $ty:ty, $msg:expr) => { + match toml::from_str::<$ty>($toml) { + Ok(s) => panic!("parsed to: {:#?}", s), + Err(e) => snapbox::assert_eq($msg, e.to_string()), + } + }; +} + +#[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() { + 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>, + "\ +TOML parse error at line 2, column 19 + | +2 | p_a = '' + | ^^ +invalid length 0, expected a non-empty string +" + ); + + // Missing field in table. + bad!( + " + p_a = 'a' + # ^ + ", + Parent<CasedString>, + "\ +TOML parse error at line 1, column 1 + | +1 | + | ^ +missing field `p_b` +" + ); + + // Invalid type in p_b. + bad!( + " + p_a = 'a' + p_b = 1 + # ^ + ", + Parent<CasedString>, + "\ +TOML parse error at line 3, column 19 + | +3 | p_b = 1 + | ^ +invalid type: integer `1`, expected a sequence +" + ); + + // Sub-table in Vec is missing a field. + bad!( + " + p_a = 'a' + p_b = [ + {c_a = 'a'} + # ^ + ] + ", + Parent<CasedString>, + "\ +TOML parse error at line 4, column 17 + | +4 | {c_a = 'a'} + | ^^^^^^^^^^^ +missing field `c_b` +" + ); + + // Sub-table in Vec has a field with a bad value. + bad!( + " + p_a = 'a' + p_b = [ + {c_a = 'a', c_b = '*'} + # ^ + ] + ", + Parent<CasedString>, + "\ +TOML parse error at line 4, column 35 + | +4 | {c_a = 'a', c_b = '*'} + | ^^^ +invalid value: string \"*\", expected all lowercase or all uppercase +" + ); + + // 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>, + "\ +TOML parse error at line 5, column 17 + | +5 | {c_a = 'aa'} + | ^^^^^^^^^^^^ +missing field `c_b` +" + ); + + // 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>, + "\ +TOML parse error at line 5, column 17 + | +5 | {c_a = 'aa'}, + | ^^^^^^^^^^^^ +missing field `c_b` +" + ); + + // 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>, + "\ +TOML parse error at line 5, column 36 + | +5 | {c_a = 'aa', c_b = 1}, + | ^ +invalid type: integer `1`, expected a string +" + ); + + // Sub-table in the middle of a Vec has an extra field. + 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>, + "\ +TOML parse error at line 5, column 42 + | +5 | {c_a = 'aa', c_b = 'bb', c_d = 'd'}, + | ^^^ +unknown field `c_d`, expected `c_a` or `c_b` +" + ); + + // 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>, + "\ +TOML parse error at line 6, column 13 + | +6 | [[p_b]] + | ^^^^^^^^^^^^^^^^^^^ +missing field `c_b` +" + ); + + // 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>, + "\ +TOML parse error at line 8, column 19 + | +8 | c_b = '*' + | ^^^ +invalid value: string \"*\", expected all lowercase or all uppercase +" + ); + + // Sub-table in the middle of a Vec has an extra field. + 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>, + "\ +TOML parse error at line 8, column 13 + | +8 | c_d = 'dd' # unknown field + | ^^^ +unknown field `c_d`, expected `c_a` or `c_b` +" + ); +} + +#[test] +fn serde_derive_deserialize_errors() { + bad!( + " + p_a = '' + # ^ + ", + Parent<String>, + "\ +TOML parse error at line 1, column 1 + | +1 | + | ^ +missing field `p_b` +" + ); + + bad!( + " + p_a = '' + p_b = [ + {c_a = ''} + # ^ + ] + ", + Parent<String>, + "\ +TOML parse error at line 4, column 17 + | +4 | {c_a = ''} + | ^^^^^^^^^^ +missing field `c_b` +" + ); + + bad!( + " + p_a = '' + p_b = [ + {c_a = '', c_b = 1} + # ^ + ] + ", + Parent<String>, + "\ +TOML parse error at line 4, column 34 + | +4 | {c_a = '', c_b = 1} + | ^ +invalid type: integer `1`, expected a string +" + ); + + // FIXME: This location could be better. + bad!( + " + p_a = '' + p_b = [ + {c_a = '', c_b = '', c_d = ''}, + # ^ + ] + ", + Parent<String>, + "\ +TOML parse error at line 4, column 38 + | +4 | {c_a = '', c_b = '', c_d = ''}, + | ^^^ +unknown field `c_d`, expected `c_a` or `c_b` +" + ); + + bad!( + " + p_a = 'a' + p_b = [ + {c_a = '', c_b = 1, c_d = ''}, + # ^ + ] + ", + Parent<String>, + "\ +TOML parse error at line 4, column 34 + | +4 | {c_a = '', c_b = 1, c_d = ''}, + | ^ +invalid type: integer `1`, expected a string +" + ); +} + +#[test] +fn error_handles_crlf() { + bad!( + "\r\n\ + [t1]\r\n\ + [t2]\r\n\ + a = 1\r\n\ + a = 2\r\n\ + ", + toml::Value, + "\ +TOML parse error at line 5, column 1 + | +5 | a = 2 + | ^ +duplicate key `a` in table `t2` +" + ); + + // Should be the same as above. + bad!( + "\n\ + [t1]\n\ + [t2]\n\ + a = 1\n\ + a = 2\n\ + ", + toml::Value, + "\ +TOML parse error at line 5, column 1 + | +5 | a = 2 + | ^ +duplicate key `a` in table `t2` +" + ); +} diff --git a/vendor/toml/tests/testsuite/display.rs b/vendor/toml/tests/testsuite/display.rs new file mode 100644 index 000000000..7430fac82 --- /dev/null +++ b/vendor/toml/tests/testsuite/display.rs @@ -0,0 +1,116 @@ +use toml::map::Map; +use toml::Value::{Array, Boolean, Float, Integer, String, Table}; + +macro_rules! map( ($($k:expr => $v:expr),*) => ({ + let mut _m = Map::new(); + $(_m.insert($k.to_string(), $v);)* + _m +}) ); + +#[test] +fn simple_show() { + assert_eq!(String("foo".to_string()).to_string(), "\"foo\""); + assert_eq!(Integer(10).to_string(), "10"); + assert_eq!(Float(10.0).to_string(), "10.0"); + assert_eq!(Float(2.4).to_string(), "2.4"); + assert_eq!(Boolean(true).to_string(), "true"); + assert_eq!(Array(vec![]).to_string(), "[]"); + assert_eq!(Array(vec![Integer(1), Integer(2)]).to_string(), "[1, 2]"); +} + +#[test] +fn table() { + assert_eq!(map! {}.to_string(), ""); + assert_eq!( + map! { + "test" => Integer(2), + "test2" => Integer(3) } + .to_string(), + "test = 2\ntest2 = 3\n" + ); + assert_eq!( + map! { + "test" => Integer(2), + "test2" => Table(map! { + "test" => String("wut".to_string()) + }) + } + .to_string(), + "test = 2\n\ + \n\ + [test2]\n\ + test = \"wut\"\n" + ); + assert_eq!( + map! { + "test" => Integer(2), + "test2" => Table(map! { + "test" => String("wut".to_string()) + }) + } + .to_string(), + "test = 2\n\ + \n\ + [test2]\n\ + test = \"wut\"\n" + ); + assert_eq!( + map! { + "test" => Integer(2), + "test2" => Array(vec![Table(map! { + "test" => String("wut".to_string()) + })]) + } + .to_string(), + "test = 2\n\ + \n\ + [[test2]]\n\ + test = \"wut\"\n" + ); + #[cfg(feature = "preserve_order")] + assert_eq!( + map! { + "foo.bar" => Integer(2), + "foo\"bar" => Integer(2) + } + .to_string(), + "\"foo.bar\" = 2\n\ + \"foo\\\"bar\" = 2\n" + ); + assert_eq!( + map! { + "test" => Integer(2), + "test2" => Array(vec![Table(map! { + "test" => Array(vec![Integer(2)]) + })]) + } + .to_string(), + "test = 2\n\ + \n\ + [[test2]]\n\ + test = [2]\n" + ); + let table = map! { + "test" => Integer(2), + "test2" => Array(vec![Table(map! { + "test" => Array(vec![Array(vec![Integer(2), Integer(3)]), + Array(vec![String("foo".to_string()), String("bar".to_string())])]) + })]) + }; + assert_eq!( + table.to_string(), + "test = 2\n\ + \n\ + [[test2]]\n\ + test = [[2, 3], [\"foo\", \"bar\"]]\n" + ); + assert_eq!( + map! { + "test" => Array(vec![Integer(2)]), + "test2" => Integer(2) + } + .to_string(), + "test = [2]\n\ + test2 = 2\n" + ); +} diff --git a/vendor/toml/tests/testsuite/display_tricky.rs b/vendor/toml/tests/testsuite/display_tricky.rs new file mode 100644 index 000000000..379ae9138 --- /dev/null +++ b/vendor/toml/tests/testsuite/display_tricky.rs @@ -0,0 +1,55 @@ +use serde::Deserialize; +use serde::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 = toml::from_str::<Recipe>( + r#" + name = "testing" + description = "example" + modules = [] + + [[packages]] + name = "base" + "#, + ) + .unwrap(); + toml::to_string(&recipe_works).unwrap(); + + let recipe_fails = toml::from_str::<Recipe>( + r#" + name = "testing" + description = "example" + packages = [] + + [[modules]] + name = "base" + "#, + ) + .unwrap(); + + let recipe_toml = toml::Table::try_from(recipe_fails).unwrap(); + recipe_toml.to_string(); +} diff --git a/vendor/toml/tests/testsuite/enum_external_deserialize.rs b/vendor/toml/tests/testsuite/enum_external_deserialize.rs new file mode 100644 index 000000000..6e0c2f768 --- /dev/null +++ b/vendor/toml/tests/testsuite/enum_external_deserialize.rs @@ -0,0 +1,320 @@ +use serde::Deserialize; + +#[derive(Debug, Deserialize, PartialEq)] +struct OuterStruct { + inner: TheEnum, +} + +#[derive(Debug, Deserialize, PartialEq)] +enum TheEnum { + Plain, + Tuple(i64, bool), + NewType(String), + Struct { value: i64 }, +} + +#[derive(Debug, Deserialize, PartialEq)] +struct Val { + val: TheEnum, +} + +#[derive(Debug, Deserialize, PartialEq)] +struct Multi { + enums: Vec<TheEnum>, +} + +fn value_from_str<T>(s: &'_ str) -> Result<T, toml::de::Error> +where + T: serde::de::DeserializeOwned, +{ + T::deserialize(toml::de::ValueDeserializer::new(s)) +} + +#[test] +fn invalid_variant_returns_error_with_good_message_string() { + let error = value_from_str::<TheEnum>("\"NonExistent\"").unwrap_err(); + snapbox::assert_eq( + r#"unknown variant `NonExistent`, expected one of `Plain`, `Tuple`, `NewType`, `Struct` +"#, + error.to_string(), + ); + + let error = toml::from_str::<Val>("val = \"NonExistent\"").unwrap_err(); + snapbox::assert_eq( + r#"TOML parse error at line 1, column 7 + | +1 | val = "NonExistent" + | ^^^^^^^^^^^^^ +unknown variant `NonExistent`, expected one of `Plain`, `Tuple`, `NewType`, `Struct` +"#, + error.to_string(), + ); +} + +#[test] +fn invalid_variant_returns_error_with_good_message_inline_table() { + let error = value_from_str::<TheEnum>("{ NonExistent = {} }").unwrap_err(); + snapbox::assert_eq( + r#"unknown variant `NonExistent`, expected one of `Plain`, `Tuple`, `NewType`, `Struct` +"#, + error.to_string(), + ); + + let error = toml::from_str::<Val>("val = { NonExistent = {} }").unwrap_err(); + snapbox::assert_eq( + r#"TOML parse error at line 1, column 9 + | +1 | val = { NonExistent = {} } + | ^^^^^^^^^^^ +unknown variant `NonExistent`, expected one of `Plain`, `Tuple`, `NewType`, `Struct` +"#, + error.to_string(), + ); +} + +#[test] +fn extra_field_returns_expected_empty_table_error() { + let error = value_from_str::<TheEnum>("{ Plain = { extra_field = 404 } }").unwrap_err(); + snapbox::assert_eq( + r#"expected empty table +"#, + error.to_string(), + ); + + let error = toml::from_str::<Val>("val = { Plain = { extra_field = 404 } }").unwrap_err(); + snapbox::assert_eq( + r#"TOML parse error at line 1, column 17 + | +1 | val = { Plain = { extra_field = 404 } } + | ^^^^^^^^^^^^^^^^^^^^^ +expected empty table +"#, + error.to_string(), + ); +} + +#[test] +fn extra_field_returns_expected_empty_table_error_struct_variant() { + let error = value_from_str::<TheEnum>("{ Struct = { value = 123, extra_0 = 0, extra_1 = 1 } }") + .unwrap_err(); + + snapbox::assert_eq( + r#"unexpected keys in table: extra_0, extra_1, available keys: value +"#, + error.to_string(), + ); + + let error = + toml::from_str::<Val>("val = { Struct = { value = 123, extra_0 = 0, extra_1 = 1 } }") + .unwrap_err(); + + snapbox::assert_eq( + r#"TOML parse error at line 1, column 33 + | +1 | val = { Struct = { value = 123, extra_0 = 0, extra_1 = 1 } } + | ^^^^^^^ +unexpected keys in table: extra_0, extra_1, available keys: value +"#, + error.to_string(), + ); +} + +mod enum_unit { + use super::*; + + #[test] + fn from_str() { + assert_eq!(TheEnum::Plain, value_from_str("\"Plain\"").unwrap()); + + assert_eq!( + Val { + val: TheEnum::Plain + }, + toml::from_str("val = \"Plain\"").unwrap() + ); + } + + #[test] + fn from_inline_table() { + assert_eq!(TheEnum::Plain, value_from_str("{ Plain = {} }").unwrap()); + assert_eq!( + Val { + val: TheEnum::Plain + }, + toml::from_str("val = { Plain = {} }").unwrap() + ); + } + + #[test] + fn from_std_table() { + assert_eq!(TheEnum::Plain, toml::from_str("[Plain]\n").unwrap()); + } +} + +mod enum_tuple { + use super::*; + + #[test] + fn from_inline_table() { + assert_eq!( + TheEnum::Tuple(-123, true), + value_from_str("{ Tuple = { 0 = -123, 1 = true } }").unwrap() + ); + assert_eq!( + Val { + val: TheEnum::Tuple(-123, true) + }, + toml::from_str("val = { Tuple = { 0 = -123, 1 = true } }").unwrap() + ); + } + + #[test] + fn from_std_table() { + assert_eq!( + TheEnum::Tuple(-123, true), + toml::from_str( + r#"[Tuple] + 0 = -123 + 1 = true + "# + ) + .unwrap() + ); + } +} + +mod enum_newtype { + use super::*; + + #[test] + fn from_inline_table() { + assert_eq!( + TheEnum::NewType("value".to_string()), + value_from_str(r#"{ NewType = "value" }"#).unwrap() + ); + assert_eq!( + Val { + val: TheEnum::NewType("value".to_string()), + }, + toml::from_str(r#"val = { NewType = "value" }"#).unwrap() + ); + } + + #[test] + fn from_std_table() { + assert_eq!( + TheEnum::NewType("value".to_string()), + toml::from_str(r#"NewType = "value""#).unwrap() + ); + assert_eq!( + Val { + val: TheEnum::NewType("value".to_string()), + }, + toml::from_str( + r#"[val] + NewType = "value" + "# + ) + .unwrap() + ); + } +} + +mod enum_struct { + use super::*; + + #[test] + fn from_inline_table() { + assert_eq!( + TheEnum::Struct { value: -123 }, + value_from_str("{ Struct = { value = -123 } }").unwrap() + ); + assert_eq!( + Val { + val: TheEnum::Struct { value: -123 } + }, + toml::from_str("val = { Struct = { value = -123 } }").unwrap() + ); + } + + #[test] + fn from_std_table() { + assert_eq!( + TheEnum::Struct { value: -123 }, + toml::from_str( + r#"[Struct] + value = -123 + "# + ) + .unwrap() + ); + } + + #[test] + fn from_nested_std_table() { + assert_eq!( + OuterStruct { + inner: TheEnum::Struct { value: -123 } + }, + toml::from_str( + r#"[inner.Struct] + value = -123 + "# + ) + .unwrap() + ); + } +} + +mod enum_array { + use super::*; + + #[test] + fn from_inline_tables() { + let toml_str = r#" + enums = [ + { Plain = {} }, + { Tuple = { 0 = -123, 1 = true } }, + { NewType = "value" }, + { Struct = { value = -123 } } + ]"#; + assert_eq!( + Multi { + enums: vec![ + TheEnum::Plain, + TheEnum::Tuple(-123, true), + TheEnum::NewType("value".to_string()), + TheEnum::Struct { value: -123 }, + ] + }, + toml::from_str(toml_str).unwrap() + ); + } + + #[test] + fn from_std_table() { + let toml_str = r#"[[enums]] + Plain = {} + + [[enums]] + Tuple = { 0 = -123, 1 = true } + + [[enums]] + NewType = "value" + + [[enums]] + Struct = { value = -123 } + "#; + assert_eq!( + Multi { + enums: vec![ + TheEnum::Plain, + TheEnum::Tuple(-123, true), + TheEnum::NewType("value".to_string()), + TheEnum::Struct { value: -123 }, + ] + }, + toml::from_str(toml_str).unwrap() + ); + } +} diff --git a/vendor/toml/tests/testsuite/float.rs b/vendor/toml/tests/testsuite/float.rs new file mode 100644 index 000000000..d00813471 --- /dev/null +++ b/vendor/toml/tests/testsuite/float.rs @@ -0,0 +1,80 @@ +use serde::Deserialize; +use serde::Serialize; +use toml::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 = toml::from_str( + r" + # 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()); + + 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 = 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 +" + ); + + toml::from_str::<Value>(&s).expect("roundtrip"); + }}; +} + +#[test] +fn float_inf() { + float_inf_tests!(f32); + float_inf_tests!(f64); +} diff --git a/vendor/toml/tests/testsuite/formatting.rs b/vendor/toml/tests/testsuite/formatting.rs new file mode 100644 index 000000000..8240d1d30 --- /dev/null +++ b/vendor/toml/tests/testsuite/formatting.rs @@ -0,0 +1,54 @@ +use serde::Deserialize; +use serde::Serialize; +use toml::to_string; + +#[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')); +} diff --git a/vendor/toml/tests/testsuite/macros.rs b/vendor/toml/tests/testsuite/macros.rs new file mode 100644 index 000000000..510070510 --- /dev/null +++ b/vendor/toml/tests/testsuite/macros.rs @@ -0,0 +1,368 @@ +use std::f64; + +use toml::toml; + +macro_rules! table { + ($($key:expr => $value:expr,)*) => {{ + // https://github.com/rust-lang/rust/issues/60643 + #[allow(unused_mut)] + let mut table = toml::value::Table::new(); + $( + table.insert($key.to_string(), $value.into()); + )* + toml::Value::Table(table) + }}; +} + +macro_rules! array { + ($($element:expr,)*) => {{ + // https://github.com/rust-lang/rust/issues/60643 + #![allow(clippy::vec_init_then_push)] + #[allow(unused_mut)] + let mut array = toml::value::Array::new(); + $( + array.push($element.into()); + )* + toml::Value::Array(array) + }}; +} + +macro_rules! datetime { + ($s:tt) => { + $s.parse::<toml::value::Datetime>().unwrap() + }; +} + +#[test] +fn test_cargo_toml() { + // Simple sanity check of: + // + // - Ordinary tables + // - Inline tables + // - Inline arrays + // - String values + // - Table keys containing hyphen + // - Table headers containing hyphen + let actual = toml! { + [package] + name = "toml" + version = "0.4.5" + authors = ["Alex Crichton <alex@alexcrichton.com>"] + + [badges] + travis-ci = { repository = "alexcrichton/toml-rs" } + + [dependencies] + serde = "1.0" + + [dev-dependencies] + serde_derive = "1.0" + serde_json = "1.0" + }; + + let expected = table! { + "package" => table! { + "name" => "toml".to_owned(), + "version" => "0.4.5".to_owned(), + "authors" => array! { + "Alex Crichton <alex@alexcrichton.com>".to_owned(), + }, + }, + "badges" => table! { + "travis-ci" => table! { + "repository" => "alexcrichton/toml-rs".to_owned(), + }, + }, + "dependencies" => table! { + "serde" => "1.0".to_owned(), + }, + "dev-dependencies" => table! { + "serde_derive" => "1.0".to_owned(), + "serde_json" => "1.0".to_owned(), + }, + }; + + assert_eq!(toml::Value::Table(actual), expected); +} + +#[test] +fn test_array() { + // Copied from the TOML spec. + let actual = toml! { + [[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 expected = table! { + "fruit" => array! { + table! { + "name" => "apple", + "physical" => table! { + "color" => "red", + "shape" => "round", + }, + "variety" => array! { + table! { + "name" => "red delicious", + }, + table! { + "name" => "granny smith", + }, + }, + }, + table! { + "name" => "banana", + "variety" => array! { + table! { + "name" => "plantain", + }, + }, + }, + }, + }; + + assert_eq!(toml::Value::Table(actual), expected); +} + +#[test] +fn test_number() { + #![allow(clippy::unusual_byte_groupings)] // Verify the macro with odd formatting + + let actual = toml! { + positive = 1 + negative = -1 + table = { positive = 1, negative = -1 } + array = [ 1, -1 ] + neg_zero = -0 + pos_zero = +0 + float = 1.618 + + sf1 = inf + sf2 = +inf + sf3 = -inf + sf7 = +0.0 + sf8 = -0.0 + + hex = 0xa_b_c + oct = 0o755 + bin = 0b11010110 + }; + + let expected = table! { + "positive" => 1, + "negative" => -1, + "table" => table! { + "positive" => 1, + "negative" => -1, + }, + "array" => array! { + 1, + -1, + }, + "neg_zero" => -0, + "pos_zero" => 0, + "float" => 1.618, + "sf1" => f64::INFINITY, + "sf2" => f64::INFINITY, + "sf3" => f64::NEG_INFINITY, + "sf7" => 0.0, + "sf8" => -0.0, + "hex" => 2748, + "oct" => 493, + "bin" => 214, + }; + + assert_eq!(toml::Value::Table(actual), expected); +} + +#[test] +fn test_nan() { + let actual = toml! { + sf4 = nan + sf5 = +nan + sf6 = -nan + }; + assert!(actual["sf4"].as_float().unwrap().is_nan()); + assert!(actual["sf5"].as_float().unwrap().is_nan()); + assert!(actual["sf6"].as_float().unwrap().is_nan()); +} + +#[test] +fn test_datetime() { + let actual = toml! { + // Copied from the TOML spec. + odt1 = 1979-05-27T07:32:00Z + odt2 = 1979-05-27T00:32:00-07:00 + odt3 = 1979-05-27T00:32:00.999999-07:00 + odt4 = 1979-05-27 07:32:00Z + ldt1 = 1979-05-27T07:32:00 + ldt2 = 1979-05-27T00:32:00.999999 + ld1 = 1979-05-27 + lt1 = 07:32:00 + lt2 = 00:32:00.999999 + + table = { + odt1 = 1979-05-27T07:32:00Z, + odt2 = 1979-05-27T00:32:00-07:00, + odt3 = 1979-05-27T00:32:00.999999-07:00, + odt4 = 1979-05-27 07:32:00Z, + ldt1 = 1979-05-27T07:32:00, + ldt2 = 1979-05-27T00:32:00.999999, + ld1 = 1979-05-27, + lt1 = 07:32:00, + lt2 = 00:32:00.999999, + } + + array = [ + 1979-05-27T07:32:00Z, + 1979-05-27T00:32:00-07:00, + 1979-05-27T00:32:00.999999-07:00, + 1979-05-27 07:32:00Z, + 1979-05-27T07:32:00, + 1979-05-27T00:32:00.999999, + 1979-05-27, + 07:32:00, + 00:32:00.999999, + ] + }; + + let expected = table! { + "odt1" => datetime!("1979-05-27T07:32:00Z"), + "odt2" => datetime!("1979-05-27T00:32:00-07:00"), + "odt3" => datetime!("1979-05-27T00:32:00.999999-07:00"), + "odt4" => datetime!("1979-05-27 07:32:00Z"), + "ldt1" => datetime!("1979-05-27T07:32:00"), + "ldt2" => datetime!("1979-05-27T00:32:00.999999"), + "ld1" => datetime!("1979-05-27"), + "lt1" => datetime!("07:32:00"), + "lt2" => datetime!("00:32:00.999999"), + + "table" => table! { + "odt1" => datetime!("1979-05-27T07:32:00Z"), + "odt2" => datetime!("1979-05-27T00:32:00-07:00"), + "odt3" => datetime!("1979-05-27T00:32:00.999999-07:00"), + "odt4" => datetime!("1979-05-27 07:32:00Z"), + "ldt1" => datetime!("1979-05-27T07:32:00"), + "ldt2" => datetime!("1979-05-27T00:32:00.999999"), + "ld1" => datetime!("1979-05-27"), + "lt1" => datetime!("07:32:00"), + "lt2" => datetime!("00:32:00.999999"), + }, + + "array" => array! { + datetime!("1979-05-27T07:32:00Z"), + datetime!("1979-05-27T00:32:00-07:00"), + datetime!("1979-05-27T00:32:00.999999-07:00"), + datetime!("1979-05-27 07:32:00Z"), + datetime!("1979-05-27T07:32:00"), + datetime!("1979-05-27T00:32:00.999999"), + datetime!("1979-05-27"), + datetime!("07:32:00"), + datetime!("00:32:00.999999"), + }, + }; + + assert_eq!(toml::Value::Table(actual), expected); +} + +// This test requires rustc >= 1.20. +#[test] +fn test_quoted_key() { + let actual = toml! { + "quoted" = true + table = { "quoted" = true } + + [target."cfg(windows)".dependencies] + winapi = "0.2.8" + }; + + let expected = table! { + "quoted" => true, + "table" => table! { + "quoted" => true, + }, + "target" => table! { + "cfg(windows)" => table! { + "dependencies" => table! { + "winapi" => "0.2.8", + }, + }, + }, + }; + + assert_eq!(toml::Value::Table(actual), expected); +} + +#[test] +fn test_empty() { + let actual = toml! { + empty_inline_table = {} + empty_inline_array = [] + + [empty_table] + + [[empty_array]] + }; + + let expected = table! { + "empty_inline_table" => table! {}, + "empty_inline_array" => array! {}, + "empty_table" => table! {}, + "empty_array" => array! { + table! {}, + }, + }; + + assert_eq!(toml::Value::Table(actual), expected); +} + +#[test] +fn test_dotted_keys() { + let actual = toml! { + a.b = 123 + a.c = 1979-05-27T07:32:00Z + [table] + a.b.c = 1 + a . b . d = 2 + in = { type.name = "cat", type.color = "blue" } + }; + + let expected = table! { + "a" => table! { + "b" => 123, + "c" => datetime!("1979-05-27T07:32:00Z"), + }, + "table" => table! { + "a" => table! { + "b" => table! { + "c" => 1, + "d" => 2, + }, + }, + "in" => table! { + "type" => table! { + "name" => "cat", + "color" => "blue", + }, + }, + }, + }; + + assert_eq!(toml::Value::Table(actual), expected); +} diff --git a/vendor/toml/tests/testsuite/main.rs b/vendor/toml/tests/testsuite/main.rs new file mode 100644 index 000000000..14737878f --- /dev/null +++ b/vendor/toml/tests/testsuite/main.rs @@ -0,0 +1,15 @@ +#![recursion_limit = "256"] +#![cfg(all(feature = "parse", feature = "display"))] + +mod de_errors; +mod display; +mod display_tricky; +mod enum_external_deserialize; +mod float; +mod formatting; +mod macros; +mod pretty; +mod serde; +mod spanned; +mod spanned_impls; +mod tables_last; diff --git a/vendor/toml/tests/testsuite/pretty.rs b/vendor/toml/tests/testsuite/pretty.rs new file mode 100644 index 000000000..3ae772b4f --- /dev/null +++ b/vendor/toml/tests/testsuite/pretty.rs @@ -0,0 +1,184 @@ +use serde::ser::Serialize; +use snapbox::assert_eq; + +const NO_PRETTY: &str = "\ +[example] +array = [\"item 1\", \"item 2\"] +empty = [] +oneline = \"this has no newlines.\" +text = ''' + +this is the first line\\nthis is the second line +''' +"; + +#[test] +fn no_pretty() { + let toml = NO_PRETTY; + let value: toml::Value = toml::from_str(toml).unwrap(); + let mut result = String::with_capacity(128); + value.serialize(toml::Serializer::new(&mut result)).unwrap(); + assert_eq(toml, &result); +} + +const PRETTY_STD: &str = "\ +[example] +array = [ + \"item 1\", + \"item 2\", +] +empty = [] +one = [\"one\"] +oneline = \"this has no newlines.\" +text = \"\"\" +this is the first line +this is the second line +\"\"\" +"; + +#[test] +fn pretty_std() { + let toml = PRETTY_STD; + let value: toml::Value = toml::from_str(toml).unwrap(); + let mut result = String::with_capacity(128); + value + .serialize(toml::Serializer::pretty(&mut result)) + .unwrap(); + assert_eq(toml, &result); +} + +const PRETTY_TRICKY: &str = r##"[example] +f = "\f" +glass = """ +Nothing too unusual, except that I can eat glass in: +- Greek: Μπορώ να φάω σπασμένα γυαλιά χωρίς να πάθω τίποτα. +- Polish: Mogę jeść szkło, i mi nie szkodzi. +- Hindi: मैं काँच खा सकता हूँ, मुझे उस से कोई पीडा नहीं होती. +- Japanese: 私はガラスを食べられます。それは私を傷つけません。 +""" +r = "\r" +r_newline = """ +\r +""" +single = "this is a single line but has '' cuz it's tricky" +single_tricky = "single line with ''' in it" +tabs = """ +this is pretty standard +\texcept for some \ttabs right here +""" +text = """ +this is the first line. +This has a ''' in it and \"\"\" cuz it's tricky yo +Also ' and \" because why not +this is the fourth line +""" +"##; + +#[test] +fn pretty_tricky() { + let toml = PRETTY_TRICKY; + let value: toml::Value = toml::from_str(toml).unwrap(); + let mut result = String::with_capacity(128); + value + .serialize(toml::Serializer::pretty(&mut result)) + .unwrap(); + assert_eq(toml, &result); +} + +const PRETTY_TABLE_ARRAY: &str = r##"[[array]] +key = "foo" + +[[array]] +key = "bar" + +[abc] +doc = "this is a table" + +[example] +single = "this is a single line string" +"##; + +#[test] +fn pretty_table_array() { + let toml = PRETTY_TABLE_ARRAY; + let value: toml::Value = toml::from_str(toml).unwrap(); + let mut result = String::with_capacity(128); + value + .serialize(toml::Serializer::pretty(&mut result)) + .unwrap(); + assert_eq(toml, &result); +} + +const TABLE_ARRAY: &str = r##"[[array]] +key = "foo" + +[[array]] +key = "bar" + +[abc] +doc = "this is a table" + +[example] +single = "this is a single line string" +"##; + +#[test] +fn table_array() { + let toml = TABLE_ARRAY; + let value: toml::Value = toml::from_str(toml).unwrap(); + let mut result = String::with_capacity(128); + value.serialize(toml::Serializer::new(&mut result)).unwrap(); + assert_eq(toml, &result); +} + +const PRETTY_EMPTY_TABLE: &str = r#"[example] +"#; + +#[test] +fn pretty_empty_table() { + let toml = PRETTY_EMPTY_TABLE; + let value: toml::Value = toml::from_str(toml).unwrap(); + let mut result = String::with_capacity(128); + value.serialize(toml::Serializer::new(&mut result)).unwrap(); + assert_eq(toml, &result); +} + +#[test] +fn error_includes_key() { + #[derive(Debug, serde::Serialize, serde::Deserialize)] + struct Package { + name: String, + version: String, + authors: Vec<String>, + profile: Profile, + } + + #[derive(Debug, serde::Serialize, serde::Deserialize)] + struct Profile { + dev: Dev, + } + + #[derive(Debug, serde::Serialize, serde::Deserialize)] + struct Dev { + debug: U32OrBool, + } + + #[derive(Clone, Debug, serde::Deserialize, serde::Serialize, Eq, PartialEq)] + #[serde(untagged, expecting = "expected a boolean or an integer")] + pub enum U32OrBool { + U32(u32), + Bool(bool), + } + + let raw = r#"name = "foo" +version = "0.0.0" +authors = [] + +[profile.dev] +debug = true +"#; + + let pkg: Package = toml::from_str(raw).unwrap(); + let pretty = toml::to_string_pretty(&pkg).unwrap(); + assert_eq(raw, pretty); +} diff --git a/vendor/toml/tests/testsuite/serde.rs b/vendor/toml/tests/testsuite/serde.rs new file mode 100644 index 000000000..3b9f65a4a --- /dev/null +++ b/vendor/toml/tests/testsuite/serde.rs @@ -0,0 +1,1074 @@ +use serde::Deserialize; +use serde::Deserializer; +use serde::Serialize; +use std::collections::BTreeMap; + +use toml::map::Map; +use toml::Table; +use toml::Value; + +macro_rules! t { + ($e:expr) => { + match $e { + Ok(t) => t, + Err(e) => panic!("{} failed with {}", stringify!($e), e), + } + }; +} + +macro_rules! equivalent { + ($literal:expr, $toml:expr,) => {{ + let toml = $toml; + let literal = $literal; + + // In/out of Value is equivalent + println!("try_from"); + assert_eq!(t!(Table::try_from(literal.clone())), toml); + println!("try_into"); + assert_eq!(literal, t!(toml.clone().try_into())); + + // Through a string equivalent + println!("to_string"); + snapbox::assert_eq(t!(toml::to_string(&toml)), t!(toml::to_string(&literal))); + println!("literal, from_str(toml)"); + assert_eq!(literal, t!(toml::from_str(&t!(toml::to_string(&toml))))); + println!("toml, from_str(toml)"); + assert_eq!(toml, t!(toml::from_str(&t!(toml::to_string(&toml))))); + }}; +} + +macro_rules! error { + ($ty:ty, $toml:expr, $msg_parse:expr, $msg_decode:expr) => {{ + println!("attempting parsing"); + match toml::from_str::<$ty>(&$toml.to_string()) { + Ok(_) => panic!("successful"), + Err(e) => snapbox::assert_eq($msg_parse, e.to_string()), + } + + println!("attempting toml decoding"); + match $toml.try_into::<$ty>() { + Ok(_) => panic!("successful"), + Err(e) => snapbox::assert_eq($msg_decode, e.to_string()), + } + }}; +} + +macro_rules! map( ($($k:ident: $v:expr),*) => ({ + let mut _m = Map::new(); + $(_m.insert(stringify!($k).to_string(), t!(Value::try_from($v)));)* + _m +}) ); + +#[test] +fn smoke() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Foo { + a: isize, + } + + equivalent!(Foo { a: 2 }, map! { a: Value::Integer(2) },); +} + +#[test] +fn smoke_hyphen() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Foo { + a_b: isize, + } + + equivalent! { + Foo { a_b: 2 }, + map! { a_b: Value::Integer(2)}, + } + + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Foo2 { + #[serde(rename = "a-b")] + a_b: isize, + } + + let mut m = Map::new(); + m.insert("a-b".to_string(), Value::Integer(2)); + equivalent! { + Foo2 { a_b: 2 }, + m, + } +} + +#[test] +fn nested() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Foo { + a: isize, + b: Bar, + } + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Bar { + a: String, + } + + equivalent! { + Foo { a: 2, b: Bar { a: "test".to_string() } }, + map! { + a: Value::Integer(2), + b: map! { + a: Value::String("test".to_string()) + } + }, + } +} + +#[test] +fn application_decode_error() { + #[derive(PartialEq, Debug)] + struct Range10(usize); + impl<'de> serde::Deserialize<'de> for Range10 { + fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Range10, D::Error> { + let x: usize = serde::Deserialize::deserialize(d)?; + if x > 10 { + Err(serde::de::Error::custom("more than 10")) + } else { + Ok(Range10(x)) + } + } + } + let d_good = Value::Integer(5); + let d_bad1 = Value::String("not an isize".to_string()); + let d_bad2 = Value::Integer(11); + + assert_eq!(Range10(5), d_good.try_into().unwrap()); + + let err1: Result<Range10, _> = d_bad1.try_into(); + assert!(err1.is_err()); + let err2: Result<Range10, _> = d_bad2.try_into(); + assert!(err2.is_err()); +} + +#[test] +fn array() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Foo { + a: Vec<isize>, + } + + equivalent! { + Foo { a: vec![1, 2, 3, 4] }, + map! { + a: Value::Array(vec![ + Value::Integer(1), + Value::Integer(2), + Value::Integer(3), + Value::Integer(4) + ]) + }, + }; +} + +#[test] +fn inner_structs_with_options() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Foo { + a: Option<Box<Foo>>, + b: Bar, + } + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Bar { + a: String, + b: f64, + } + + equivalent! { + Foo { + a: Some(Box::new(Foo { + a: None, + b: Bar { a: "foo".to_string(), b: 4.5 }, + })), + b: Bar { a: "bar".to_string(), b: 1.0 }, + }, + map! { + a: map! { + b: map! { + a: Value::String("foo".to_string()), + b: Value::Float(4.5) + } + }, + b: map! { + a: Value::String("bar".to_string()), + b: Value::Float(1.0) + } + }, + } +} + +#[test] +#[cfg(feature = "preserve_order")] +fn hashmap() { + use std::collections::HashSet; + + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Foo { + set: HashSet<char>, + map: BTreeMap<String, isize>, + } + + equivalent! { + Foo { + set: { + let mut s = HashSet::new(); + s.insert('a'); + s + }, + map: { + let mut m = BTreeMap::new(); + m.insert("bar".to_string(), 4); + m.insert("foo".to_string(), 10); + m + } + }, + map! { + set: Value::Array(vec![Value::String("a".to_string())]), + map: map! { + bar: Value::Integer(4), + foo: Value::Integer(10) + } + }, + } +} + +#[test] +fn table_array() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Foo { + a: Vec<Bar>, + } + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Bar { + a: isize, + } + + equivalent! { + Foo { a: vec![Bar { a: 1 }, Bar { a: 2 }] }, + map! { + a: Value::Array(vec![ + Value::Table(map!{ a: Value::Integer(1) }), + Value::Table(map!{ a: Value::Integer(2) }), + ]) + }, + } +} + +#[test] +fn type_errors() { + #[derive(Deserialize)] + #[allow(dead_code)] + struct Foo { + bar: isize, + } + + error! { + Foo, + map! { + bar: Value::String("a".to_string()) + }, + r#"TOML parse error at line 1, column 7 + | +1 | bar = "a" + | ^^^ +invalid type: string "a", expected isize +"#, + "invalid type: string \"a\", expected isize\nin `bar`\n" + } + + #[derive(Deserialize)] + #[allow(dead_code)] + struct Bar { + foo: Foo, + } + + error! { + Bar, + map! { + foo: map! { + bar: Value::String("a".to_string()) + } + }, + r#"TOML parse error at line 2, column 7 + | +2 | bar = "a" + | ^^^ +invalid type: string "a", expected isize +"#, + "invalid type: string \"a\", expected isize\nin `foo.bar`\n" + } +} + +#[test] +fn missing_errors() { + #[derive(Serialize, Deserialize, PartialEq, Debug)] + struct Foo { + bar: isize, + } + + error! { + Foo, + map! { }, + r#"TOML parse error at line 1, column 1 + | +1 | + | ^ +missing field `bar` +"#, + "missing field `bar`\n" + } +} + +#[test] +fn parse_enum() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Foo { + a: E, + } + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + #[serde(untagged)] + enum E { + Bar(isize), + Baz(String), + Last(Foo2), + } + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Foo2 { + test: String, + } + + equivalent! { + Foo { a: E::Bar(10) }, + map! { a: Value::Integer(10) }, + } + + equivalent! { + Foo { a: E::Baz("foo".to_string()) }, + map! { a: Value::String("foo".to_string()) }, + } + + equivalent! { + Foo { a: E::Last(Foo2 { test: "test".to_string() }) }, + map! { a: map! { test: Value::String("test".to_string()) } }, + } +} + +#[test] +fn parse_enum_string() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Foo { + a: Sort, + } + + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + #[serde(rename_all = "lowercase")] + enum Sort { + Asc, + Desc, + } + + equivalent! { + Foo { a: Sort::Desc }, + map! { a: Value::String("desc".to_string()) }, + } +} + +#[test] +#[cfg(feature = "preserve_order")] +fn map_key_unit_variants() { + #[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, PartialOrd, Ord)] + enum Sort { + #[serde(rename = "ascending")] + Asc, + Desc, + } + + let mut map = BTreeMap::new(); + map.insert(Sort::Asc, 1); + map.insert(Sort::Desc, 2); + + equivalent! { + map, + map! { ascending: Value::Integer(1), Desc: Value::Integer(2) }, + } +} + +// #[test] +// fn unused_fields() { +// #[derive(Serialize, Deserialize, PartialEq, Debug)] +// struct Foo { a: isize } +// +// let v = Foo { a: 2 }; +// let mut d = Decoder::new(Table(map! { +// a, Integer(2), +// b, Integer(5) +// })); +// assert_eq!(v, t!(Deserialize::deserialize(&mut d))); +// +// assert_eq!(d.toml, Some(Table(map! { +// b, Integer(5) +// }))); +// } +// +// #[test] +// fn unused_fields2() { +// #[derive(Serialize, Deserialize, PartialEq, Debug)] +// struct Foo { a: Bar } +// #[derive(Serialize, Deserialize, PartialEq, Debug)] +// struct Bar { a: isize } +// +// let v = Foo { a: Bar { a: 2 } }; +// let mut d = Decoder::new(Table(map! { +// a, Table(map! { +// a, Integer(2), +// b, Integer(5) +// }) +// })); +// assert_eq!(v, t!(Deserialize::deserialize(&mut d))); +// +// assert_eq!(d.toml, Some(Table(map! { +// a, Table(map! { +// b, Integer(5) +// }) +// }))); +// } +// +// #[test] +// fn unused_fields3() { +// #[derive(Serialize, Deserialize, PartialEq, Debug)] +// struct Foo { a: Bar } +// #[derive(Serialize, Deserialize, PartialEq, Debug)] +// struct Bar { a: isize } +// +// let v = Foo { a: Bar { a: 2 } }; +// let mut d = Decoder::new(Table(map! { +// a, Table(map! { +// a, Integer(2) +// }) +// })); +// assert_eq!(v, t!(Deserialize::deserialize(&mut d))); +// +// assert_eq!(d.toml, None); +// } +// +// #[test] +// fn unused_fields4() { +// #[derive(Serialize, Deserialize, PartialEq, Debug)] +// struct Foo { a: BTreeMap<String, String> } +// +// let v = Foo { a: map! { a, "foo".to_string() } }; +// let mut d = Decoder::new(Table(map! { +// a, Table(map! { +// a, Value::String("foo".to_string()) +// }) +// })); +// assert_eq!(v, t!(Deserialize::deserialize(&mut d))); +// +// assert_eq!(d.toml, None); +// } +// +// #[test] +// fn unused_fields5() { +// #[derive(Serialize, Deserialize, PartialEq, Debug)] +// struct Foo { a: Vec<String> } +// +// let v = Foo { a: vec!["a".to_string()] }; +// let mut d = Decoder::new(Table(map! { +// a, Array(vec![Value::String("a".to_string())]) +// })); +// assert_eq!(v, t!(Deserialize::deserialize(&mut d))); +// +// assert_eq!(d.toml, None); +// } +// +// #[test] +// fn unused_fields6() { +// #[derive(Serialize, Deserialize, PartialEq, Debug)] +// struct Foo { a: Option<Vec<String>> } +// +// let v = Foo { a: Some(vec![]) }; +// let mut d = Decoder::new(Table(map! { +// a, Array(vec![]) +// })); +// assert_eq!(v, t!(Deserialize::deserialize(&mut d))); +// +// assert_eq!(d.toml, None); +// } +// +// #[test] +// fn unused_fields7() { +// #[derive(Serialize, Deserialize, PartialEq, Debug)] +// struct Foo { a: Vec<Bar> } +// #[derive(Serialize, Deserialize, PartialEq, Debug)] +// struct Bar { a: isize } +// +// let v = Foo { a: vec![Bar { a: 1 }] }; +// let mut d = Decoder::new(Table(map! { +// a, Array(vec![Table(map! { +// a, Integer(1), +// b, Integer(2) +// })]) +// })); +// assert_eq!(v, t!(Deserialize::deserialize(&mut d))); +// +// assert_eq!(d.toml, Some(Table(map! { +// a, Array(vec![Table(map! { +// b, Integer(2) +// })]) +// }))); +// } + +#[test] +fn empty_arrays() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Foo { + a: Vec<Bar>, + } + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Bar; + + equivalent! { + Foo { a: vec![] }, + map! {a: Value::Array(Vec::new())}, + } +} + +#[test] +fn empty_arrays2() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Foo { + a: Option<Vec<Bar>>, + } + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Bar; + + equivalent! { + Foo { a: None }, + map! {}, + } + + equivalent! { + Foo { a: Some(vec![]) }, + map! { a: Value::Array(vec![]) }, + } +} + +#[test] +fn extra_keys() { + #[derive(Serialize, Deserialize)] + struct Foo { + a: isize, + } + + let toml = map! { a: Value::Integer(2), b: Value::Integer(2) }; + assert!(toml.clone().try_into::<Foo>().is_ok()); + assert!(toml::from_str::<Foo>(&toml.to_string()).is_ok()); +} + +#[test] +fn newtypes() { + #[derive(Deserialize, Serialize, PartialEq, Debug, Clone)] + struct A { + b: B, + } + + #[derive(Deserialize, Serialize, PartialEq, Debug, Clone)] + struct B(u32); + + equivalent! { + A { b: B(2) }, + map! { b: Value::Integer(2) }, + } +} + +#[test] +fn newtypes2() { + #[derive(Deserialize, Serialize, PartialEq, Debug, Clone)] + struct A { + b: B, + } + + #[derive(Deserialize, Serialize, PartialEq, Debug, Clone)] + struct B(Option<C>); + + #[derive(Deserialize, Serialize, PartialEq, Debug, Clone)] + struct C { + x: u32, + y: u32, + z: u32, + } + + equivalent! { + A { b: B(Some(C { x: 0, y: 1, z: 2 })) }, + map! { + b: map! { + x: Value::Integer(0), + y: Value::Integer(1), + z: Value::Integer(2) + } + }, + } +} + +#[derive(Debug, Default, PartialEq, Serialize, Deserialize)] +struct CanBeEmpty { + a: Option<String>, + b: Option<String>, +} + +#[test] +fn table_structs_empty() { + let text = "[bar]\n\n[baz]\n\n[bazv]\na = \"foo\"\n\n[foo]\n"; + let value: BTreeMap<String, CanBeEmpty> = toml::from_str(text).unwrap(); + let mut expected: BTreeMap<String, CanBeEmpty> = BTreeMap::new(); + expected.insert("bar".to_string(), CanBeEmpty::default()); + expected.insert("baz".to_string(), CanBeEmpty::default()); + expected.insert( + "bazv".to_string(), + CanBeEmpty { + a: Some("foo".to_string()), + b: None, + }, + ); + expected.insert("foo".to_string(), CanBeEmpty::default()); + assert_eq!(value, expected); + snapbox::assert_eq(text, toml::to_string(&value).unwrap()); +} + +#[test] +fn fixed_size_array() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Entity { + pos: [i32; 2], + } + + equivalent! { + Entity { pos: [1, 2] }, + map! { + pos: Value::Array(vec![ + Value::Integer(1), + Value::Integer(2), + ]) + }, + } +} + +#[test] +fn homogeneous_tuple() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Collection { + elems: (i64, i64, i64), + } + + equivalent! { + Collection { elems: (0, 1, 2) }, + map! { + elems: Value::Array(vec![ + Value::Integer(0), + Value::Integer(1), + Value::Integer(2), + ]) + }, + } +} + +#[test] +fn homogeneous_tuple_struct() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Object(Vec<String>, Vec<String>, Vec<String>); + + equivalent! { + map! { + obj: Object(vec!["foo".to_string()], vec![], vec!["bar".to_string(), "baz".to_string()]) + }, + map! { + obj: Value::Array(vec![ + Value::Array(vec![ + Value::String("foo".to_string()), + ]), + Value::Array(vec![]), + Value::Array(vec![ + Value::String("bar".to_string()), + Value::String("baz".to_string()), + ]), + ]) + }, + } +} + +#[test] +fn json_interoperability() { + #[derive(Serialize, Deserialize)] + struct Foo { + any: toml::Value, + } + + let _foo: Foo = serde_json::from_str( + r#" + {"any":1} + "#, + ) + .unwrap(); +} + +#[test] +fn error_includes_key() { + #[derive(Debug, Serialize, Deserialize)] + struct Package { + name: String, + version: String, + authors: Vec<String>, + profile: Profile, + } + + #[derive(Debug, Serialize, Deserialize)] + struct Profile { + dev: Dev, + } + + #[derive(Debug, Serialize, Deserialize)] + struct Dev { + debug: U32OrBool, + } + + #[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] + #[serde(untagged, expecting = "expected a boolean or an integer")] + pub enum U32OrBool { + U32(u32), + Bool(bool), + } + + let res: Result<Package, _> = toml::from_str( + r#" +[package] +name = "foo" +version = "0.0.0" +authors = [] + +[profile.dev] +debug = 'a' +"#, + ); + let err = res.unwrap_err(); + snapbox::assert_eq( + r#"TOML parse error at line 8, column 9 + | +8 | debug = 'a' + | ^^^ +expected a boolean or an integer +"#, + err.to_string(), + ); + + let res: Result<Package, _> = toml::from_str( + r#" +[package] +name = "foo" +version = "0.0.0" +authors = [] + +[profile] +dev = { debug = 'a' } +"#, + ); + let err = res.unwrap_err(); + snapbox::assert_eq( + r#"TOML parse error at line 8, column 17 + | +8 | dev = { debug = 'a' } + | ^^^ +expected a boolean or an integer +"#, + err.to_string(), + ); +} + +#[test] +fn newline_key_value() { + #[derive(Debug, Serialize, Deserialize)] + struct Package { + name: String, + } + + let package = Package { + name: "foo".to_owned(), + }; + let raw = toml::to_string_pretty(&package).unwrap(); + snapbox::assert_eq( + r#"name = "foo" +"#, + raw, + ); +} + +#[test] +fn newline_table() { + #[derive(Debug, Serialize, Deserialize)] + struct Manifest { + package: Package, + } + + #[derive(Debug, Serialize, Deserialize)] + struct Package { + name: String, + } + + let package = Manifest { + package: Package { + name: "foo".to_owned(), + }, + }; + let raw = toml::to_string_pretty(&package).unwrap(); + snapbox::assert_eq( + r#"[package] +name = "foo" +"#, + raw, + ); +} + +#[test] +fn newline_dotted_table() { + #[derive(Debug, Serialize, Deserialize)] + struct Manifest { + profile: Profile, + } + + #[derive(Debug, Serialize, Deserialize)] + struct Profile { + dev: Dev, + } + + #[derive(Debug, Serialize, Deserialize)] + struct Dev { + debug: U32OrBool, + } + + #[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] + #[serde(untagged, expecting = "expected a boolean or an integer")] + pub enum U32OrBool { + U32(u32), + Bool(bool), + } + + let package = Manifest { + profile: Profile { + dev: Dev { + debug: U32OrBool::Bool(true), + }, + }, + }; + let raw = toml::to_string_pretty(&package).unwrap(); + snapbox::assert_eq( + r#"[profile.dev] +debug = true +"#, + raw, + ); +} + +#[test] +fn newline_mixed_tables() { + #[derive(Debug, Serialize, Deserialize)] + struct Manifest { + cargo_features: Vec<String>, + package: Package, + profile: Profile, + } + + #[derive(Debug, Serialize, Deserialize)] + struct Package { + name: String, + version: String, + authors: Vec<String>, + } + + #[derive(Debug, Serialize, Deserialize)] + struct Profile { + dev: Dev, + } + + #[derive(Debug, Serialize, Deserialize)] + struct Dev { + debug: U32OrBool, + } + + #[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] + #[serde(untagged, expecting = "expected a boolean or an integer")] + pub enum U32OrBool { + U32(u32), + Bool(bool), + } + + let package = Manifest { + cargo_features: vec![], + package: Package { + name: "foo".to_owned(), + version: "1.0.0".to_owned(), + authors: vec![], + }, + profile: Profile { + dev: Dev { + debug: U32OrBool::Bool(true), + }, + }, + }; + let raw = toml::to_string_pretty(&package).unwrap(); + snapbox::assert_eq( + r#"cargo_features = [] + +[package] +name = "foo" +version = "1.0.0" +authors = [] + +[profile.dev] +debug = true +"#, + raw, + ); +} + +#[test] +fn integer_min() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Foo { + a_b: i64, + } + + equivalent! { + Foo { a_b: i64::MIN }, + map! { a_b: Value::Integer(i64::MIN) }, + } +} + +#[test] +fn integer_too_big() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Foo { + a_b: u64, + } + + let native = Foo { a_b: u64::MAX }; + let err = Table::try_from(native.clone()).unwrap_err(); + snapbox::assert_eq("u64 value was too large", err.to_string()); + let err = toml::to_string(&native).unwrap_err(); + snapbox::assert_eq("out-of-range value for u64 type", err.to_string()); +} + +#[test] +fn integer_max() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Foo { + a_b: i64, + } + + equivalent! { + Foo { a_b: i64::MAX }, + map! { a_b: Value::Integer(i64::MAX) }, + } +} + +#[test] +fn float_min() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Foo { + a_b: f64, + } + + equivalent! { + Foo { a_b: f64::MIN }, + map! { a_b: Value::Float(f64::MIN) }, + } +} + +#[test] +fn float_max() { + #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] + struct Foo { + a_b: f64, + } + + equivalent! { + Foo { a_b: f64::MAX }, + map! { a_b: Value::Float(f64::MAX) }, + } +} + +#[test] +fn unsupported_root_type() { + let native = "value"; + let err = toml::to_string_pretty(&native).unwrap_err(); + snapbox::assert_eq("unsupported rust type", err.to_string()); +} + +#[test] +fn unsupported_nested_type() { + #[derive(Debug, Serialize, Deserialize)] + struct Foo { + unused: (), + } + + let native = Foo { unused: () }; + let err = toml::to_string_pretty(&native).unwrap_err(); + snapbox::assert_eq("unsupported unit type", err.to_string()); +} + +#[test] +fn table_type_enum_regression_issue_388() { + #[derive(Deserialize)] + struct DataFile { + #[allow(dead_code)] + data: Compare, + } + + #[derive(Deserialize)] + enum Compare { + Gt(u32), + } + + let dotted_table = r#" + data.Gt = 5 + "#; + assert!(toml::from_str::<DataFile>(dotted_table).is_ok()); + + let inline_table = r#" + data = { Gt = 5 } + "#; + assert!(toml::from_str::<DataFile>(inline_table).is_ok()); +} + +#[test] +fn serialize_datetime_issue_333() { + use toml::{to_string, value::Date, value::Datetime}; + + #[derive(Serialize)] + struct Struct { + date: Datetime, + } + + let toml = to_string(&Struct { + date: Datetime { + date: Some(Date { + year: 2022, + month: 1, + day: 1, + }), + time: None, + offset: None, + }, + }) + .unwrap(); + assert_eq!(toml, "date = 2022-01-01\n"); +} + +#[test] +fn datetime_offset_issue_496() { + let original = "value = 1911-01-01T10:11:12-00:36\n"; + let toml = original.parse::<toml::Table>().unwrap(); + let output = toml.to_string(); + snapbox::assert_eq(original, output); +} diff --git a/vendor/toml/tests/testsuite/spanned.rs b/vendor/toml/tests/testsuite/spanned.rs new file mode 100644 index 000000000..760c73aab --- /dev/null +++ b/vendor/toml/tests/testsuite/spanned.rs @@ -0,0 +1,261 @@ +#![allow(renamed_and_removed_lints)] +#![allow(clippy::blacklisted_name)] + +use std::collections::HashMap; +use std::fmt::Debug; + +use serde::Deserialize; +use toml::value::Datetime; +use toml::Spanned; + +/// A set of good datetimes. +pub fn good_datetimes() -> Vec<&'static str> { + vec![ + "1997-09-09T09:09:09Z", + "1997-09-09T09:09:09+09:09", + "1997-09-09T09:09:09-09:09", + "1997-09-09T09:09:09", + "1997-09-09", + "09:09:09", + "1997-09-09T09:09:09.09Z", + "1997-09-09T09:09:09.09+09:09", + "1997-09-09T09:09:09.09-09:09", + "1997-09-09T09:09:09.09", + "09:09:09.09", + ] +} + +#[test] +fn test_spanned_field() { + #[derive(Deserialize)] + struct Foo<T> { + foo: Spanned<T>, + } + + #[derive(Deserialize)] + struct BareFoo<T> { + foo: T, + } + + fn good<T>(s: &str, expected: &str, end: Option<usize>) + where + T: serde::de::DeserializeOwned + Debug + PartialEq, + { + let foo: Foo<T> = toml::from_str(s).unwrap(); + + assert_eq!(6, foo.foo.span().start); + if let Some(end) = end { + assert_eq!(end, foo.foo.span().end); + } else { + assert_eq!(s.len(), foo.foo.span().end); + } + assert_eq!(expected, &s[foo.foo.span()]); + + // Test for Spanned<> at the top level + let foo_outer: Spanned<BareFoo<T>> = toml::from_str(s).unwrap(); + + assert_eq!(0, foo_outer.span().start); + assert_eq!(s.len(), foo_outer.span().end); + assert_eq!(foo.foo.into_inner(), foo_outer.into_inner().foo); + } + + good::<String>("foo = \"foo\"", "\"foo\"", None); + good::<u32>("foo = 42", "42", None); + // leading plus + good::<u32>("foo = +42", "+42", None); + // table + good::<HashMap<String, u32>>( + "foo = {\"foo\" = 42, \"bar\" = 42}", + "{\"foo\" = 42, \"bar\" = 42}", + None, + ); + // array + good::<Vec<u32>>("foo = [0, 1, 2, 3, 4]", "[0, 1, 2, 3, 4]", None); + // datetime + good::<String>( + "foo = \"1997-09-09T09:09:09Z\"", + "\"1997-09-09T09:09:09Z\"", + None, + ); + + for expected in good_datetimes() { + let s = format!("foo = {}", expected); + good::<Datetime>(&s, expected, None); + } + // ending at something other than the absolute end + good::<u32>("foo = 42\nnoise = true", "42", Some(8)); +} + +#[test] +fn test_inner_spanned_table() { + #[derive(Deserialize)] + struct Foo { + foo: Spanned<HashMap<Spanned<String>, Spanned<String>>>, + } + + fn good(s: &str, zero: bool) { + let foo: Foo = toml::from_str(s).unwrap(); + + if zero { + assert_eq!(foo.foo.span().start, 0); + assert_eq!(foo.foo.span().end, 73); + } else { + assert_eq!(foo.foo.span().start, s.find('{').unwrap()); + assert_eq!(foo.foo.span().end, s.find('}').unwrap() + 1); + } + for (k, v) in foo.foo.as_ref().iter() { + assert_eq!(&s[k.span().start..k.span().end], k.as_ref()); + assert_eq!(&s[(v.span().start + 1)..(v.span().end - 1)], v.as_ref()); + } + } + + good( + "\ + [foo] + a = 'b' + bar = 'baz' + c = 'd' + e = \"f\" + ", + true, + ); + + good( + " + foo = { a = 'b', bar = 'baz', c = 'd', e = \"f\" }", + false, + ); +} + +#[test] +fn test_outer_spanned_table() { + #[derive(Deserialize)] + struct Foo { + foo: HashMap<Spanned<String>, Spanned<String>>, + } + + fn good(s: &str) { + let foo: Foo = toml::from_str(s).unwrap(); + + for (k, v) in foo.foo.iter() { + assert_eq!(&s[k.span().start..k.span().end], k.as_ref()); + assert_eq!(&s[(v.span().start + 1)..(v.span().end - 1)], v.as_ref()); + } + } + + good( + " + [foo] + a = 'b' + bar = 'baz' + c = 'd' + e = \"f\" + ", + ); + + good( + " + foo = { a = 'b', bar = 'baz', c = 'd', e = \"f\" } + ", + ); +} + +#[test] +fn test_spanned_nested() { + #[derive(Deserialize)] + struct Foo { + foo: HashMap<Spanned<String>, HashMap<Spanned<String>, Spanned<String>>>, + } + + fn good(s: &str) { + let foo: Foo = toml::from_str(s).unwrap(); + + for (k, v) in foo.foo.iter() { + assert_eq!(&s[k.span().start..k.span().end], k.as_ref()); + for (n_k, n_v) in v.iter() { + assert_eq!(&s[n_k.span().start..n_k.span().end], n_k.as_ref()); + assert_eq!( + &s[(n_v.span().start + 1)..(n_v.span().end - 1)], + n_v.as_ref() + ); + } + } + } + + good( + " + [foo.a] + a = 'b' + c = 'd' + e = \"f\" + [foo.bar] + baz = 'true' + ", + ); + + good( + " + [foo] + foo = { a = 'b', bar = 'baz', c = 'd', e = \"f\" } + bazz = {} + g = { h = 'i' } + ", + ); +} + +#[test] +fn test_spanned_array() { + #[derive(Deserialize)] + struct Foo { + foo: Vec<Spanned<HashMap<Spanned<String>, Spanned<String>>>>, + } + + let toml = "\ + [[foo]] + a = 'b' + bar = 'baz' + c = 'd' + e = \"f\" + [[foo]] + a = 'c' + bar = 'baz' + c = 'g' + e = \"h\" + "; + let foo_list: Foo = toml::from_str(toml).unwrap(); + + for (foo, expected) in foo_list.foo.iter().zip([0..75, 84..159]) { + assert_eq!(foo.span(), expected); + for (k, v) in foo.as_ref().iter() { + assert_eq!(&toml[k.span().start..k.span().end], k.as_ref()); + assert_eq!(&toml[(v.span().start + 1)..(v.span().end - 1)], v.as_ref()); + } + } +} + +#[test] +fn deny_unknown_fields() { + #[derive(Debug, serde::Deserialize)] + #[serde(deny_unknown_fields)] + struct Example { + #[allow(dead_code)] + real: u32, + } + + let error = toml::from_str::<Example>( + r#"# my comment +# bla bla bla +fake = 1"#, + ) + .unwrap_err(); + snapbox::assert_eq( + "\ +TOML parse error at line 3, column 1 + | +3 | fake = 1 + | ^^^^ +unknown field `fake`, expected `real` +", + error.to_string(), + ); +} diff --git a/vendor/toml/tests/testsuite/spanned_impls.rs b/vendor/toml/tests/testsuite/spanned_impls.rs new file mode 100644 index 000000000..5e866f92a --- /dev/null +++ b/vendor/toml/tests/testsuite/spanned_impls.rs @@ -0,0 +1,41 @@ +use std::cmp::{Ord, Ordering, PartialOrd}; + +use serde::Deserialize; +use toml::{from_str, Spanned}; + +#[test] +fn test_spans_impls() { + #[derive(Deserialize)] + struct Foo { + bar: Spanned<bool>, + baz: Spanned<String>, + } + let f: Foo = from_str( + " + bar = true + baz = \"yes\" + ", + ) + .unwrap(); + let g: Foo = from_str( + " + baz = \"yes\" + bar = true + ", + ) + .unwrap(); + assert!(f.bar.span() != g.bar.span()); + assert!(f.baz.span() != g.baz.span()); + + // test that eq still holds + assert_eq!(f.bar, g.bar); + assert_eq!(f.baz, g.baz); + + // test that Ord returns equal order + assert_eq!(f.bar.cmp(&g.bar), Ordering::Equal); + assert_eq!(f.baz.cmp(&g.baz), Ordering::Equal); + + // test that PartialOrd returns equal order + assert_eq!(f.bar.partial_cmp(&g.bar), Some(Ordering::Equal)); + assert_eq!(f.baz.partial_cmp(&g.baz), Some(Ordering::Equal)); +} diff --git a/vendor/toml/tests/testsuite/tables_last.rs b/vendor/toml/tests/testsuite/tables_last.rs new file mode 100644 index 000000000..b0035579d --- /dev/null +++ b/vendor/toml/tests/testsuite/tables_last.rs @@ -0,0 +1,162 @@ +use std::collections::HashMap; + +use serde::Deserialize; +use serde::Serialize; + +#[test] +fn always_works() { + // Ensure this works without the removed "toml::ser::tables_last" + #[derive(Serialize)] + struct A { + vals: HashMap<&'static str, Value>, + } + + #[derive(Serialize)] + #[serde(untagged)] + enum Value { + Map(HashMap<&'static str, &'static str>), + Int(i32), + } + + let mut a = A { + vals: HashMap::new(), + }; + a.vals.insert("foo", Value::Int(0)); + + let mut sub = HashMap::new(); + sub.insert("foo", "bar"); + a.vals.insert("bar", Value::Map(sub)); + + toml::to_string(&a).unwrap(); +} + +#[test] +fn vec_of_vec_issue_387() { + #[derive(Deserialize, Serialize, Debug)] + struct Glyph { + components: Vec<Component>, + contours: Vec<Contour>, + } + + #[derive(Deserialize, Serialize, Debug)] + struct Point { + x: f64, + y: f64, + pt_type: String, + } + + type Contour = Vec<Point>; + + #[derive(Deserialize, Serialize, Debug)] + struct Component { + base: String, + transform: (f64, f64, f64, f64, f64, f64), + } + + let comp1 = Component { + base: "b".to_string(), + transform: (1.0, 0.0, 0.0, 1.0, 0.0, 0.0), + }; + let comp2 = Component { + base: "c".to_string(), + transform: (1.0, 0.0, 0.0, 1.0, 0.0, 0.0), + }; + let components = vec![comp1, comp2]; + + let contours = vec![ + vec![ + Point { + x: 3.0, + y: 4.0, + pt_type: "line".to_string(), + }, + Point { + x: 5.0, + y: 6.0, + pt_type: "line".to_string(), + }, + ], + vec![ + Point { + x: 0.0, + y: 0.0, + pt_type: "move".to_string(), + }, + Point { + x: 7.0, + y: 9.0, + pt_type: "offcurve".to_string(), + }, + Point { + x: 8.0, + y: 10.0, + pt_type: "offcurve".to_string(), + }, + Point { + x: 11.0, + y: 12.0, + pt_type: "curve".to_string(), + }, + ], + ]; + let g1 = Glyph { + contours, + components, + }; + + let s = toml::to_string_pretty(&g1).unwrap(); + let _g2: Glyph = toml::from_str(&s).unwrap(); +} + +#[test] +fn vec_order_issue_356() { + #[derive(Serialize, Deserialize)] + struct Outer { + v1: Vec<Inner>, + v2: Vec<Inner>, + } + + #[derive(Serialize, Deserialize)] + struct Inner {} + + let outer = Outer { + v1: vec![Inner {}], + v2: vec![], + }; + let s = toml::to_string_pretty(&outer).unwrap(); + let _o: Outer = toml::from_str(&s).unwrap(); +} + +#[test] +fn values_before_tables_issue_403() { + #[derive(Serialize, Deserialize)] + struct A { + a: String, + b: String, + } + + #[derive(Serialize, Deserialize)] + struct B { + a: String, + b: Vec<String>, + } + + #[derive(Serialize, Deserialize)] + struct C { + a: A, + b: Vec<String>, + c: Vec<B>, + } + toml::to_string(&C { + a: A { + a: "aa".to_string(), + b: "ab".to_string(), + }, + b: vec!["b".to_string()], + c: vec![B { + a: "cba".to_string(), + b: vec!["cbb".to_string()], + }], + }) + .unwrap(); +} |