use std::collections::BTreeMap;
use deser::ext::{Datetime, Number};
use deser::hints::Compact;
use deser::{Serialize, State};
use deser_value::{Value, from_value, to_value, value};
#[test]
fn test_json_round_trip() {
let input = r#"{"z":1,"a":[true,null,-1,1.5,"x"],"m":{"2":{}},"big":123456789012345678901234567890,"exact":0.10000000000000000001}"#;
let value: Value = deser_json::from_str(input).unwrap();
assert_eq!(
value["exact"]
.downcast_ext_value::<Number>()
.unwrap()
.as_str(),
"0.10000000000000000001"
);
assert_eq!(deser_json::to_string(&value).unwrap(), input);
assert_eq!(deser_json::to_string(&value.clone()).unwrap(), input);
}
#[test]
fn test_f32_precision() {
let value = to_value(&vec![0.1f32, 1.5]).unwrap();
assert_eq!(deser_json::to_string(&value).unwrap(), "[0.1,1.5]");
assert_eq!(deser_json::to_string(&value.clone()).unwrap(), "[0.1,1.5]");
assert_eq!(deser_yaml::to_string(&value).unwrap(), "- 0.1\n- 1.5\n");
let value = to_value(&vec![0.1f64]).unwrap();
assert_eq!(deser_json::to_string(&value).unwrap(), "[0.1]");
}
#[test]
fn test_toml_round_trip() {
let input = "title = \"x\"\nwhen = 1979-05-27T07:32:00Z\n\n[owner]\nname = \"Tom\"\n";
let value: Value = deser_toml::from_str(input).unwrap();
assert!(value["when"].downcast_ext::<Datetime>().is_some());
assert_eq!(deser_toml::to_string(&value).unwrap(), input);
assert_eq!(
deser_json::to_string(&value).unwrap(),
r#"{"title":"x","when":"1979-05-27T07:32:00Z","owner":{"name":"Tom"}}"#
);
}
#[test]
fn test_cbor_tags() {
let tagged = vec![
deser_cbor::Tagged::new(1234, "a"),
deser_cbor::Tagged::new(5678, "b"),
];
let bytes = deser_cbor::to_vec(&tagged).unwrap();
let value: Value = deser_cbor::from_slice(&bytes).unwrap();
assert_eq!(value, value!(["a", "b"]));
assert_eq!(deser_cbor::to_vec(&value).unwrap(), bytes);
assert_eq!(deser_cbor::to_vec(&value.clone()).unwrap(), bytes);
let back: Vec<deser_cbor::Tagged<String>> = from_value(&value).unwrap();
assert_eq!(back[0].tag, Some(1234));
assert_eq!(back[1].tag, Some(5678));
assert_eq!(
deser_cbor::to_vec(&to_value(&tagged).unwrap()).unwrap(),
bytes
);
}
#[test]
fn test_cbor_keys() {
let map = BTreeMap::from([(1u32, "one"), (2, "two")]);
let bytes = deser_cbor::to_vec(&map).unwrap();
let value: Value = deser_cbor::from_slice(&bytes).unwrap();
assert_eq!(value.as_map().unwrap().get(&1), Some(&value!("one")));
assert_eq!(deser_cbor::to_vec(&value).unwrap(), bytes);
let back: BTreeMap<u32, String> = from_value(&value).unwrap();
assert_eq!(back[&2], "two");
let bytes = deser_cbor::to_vec(&Value::bytes(*b"\x00\x01")).unwrap();
let value: Value = deser_cbor::from_slice(&bytes).unwrap();
assert_eq!(value.as_bytes(), Some(&b"\x00\x01"[..]));
}
#[test]
fn test_yaml_tags() {
let input = "a: !custom value\nb: [1, 2]\n";
let value: Value = deser_yaml::from_str(input).unwrap();
assert_eq!(value, value!({"a": "value", "b": [1, 2]}));
assert_eq!(deser_yaml::to_string(&value).unwrap(), input);
}
#[test]
fn test_yaml_plain_scalars() {
let value: Value = deser_yaml::from_str("version: 1.10\nport: 0x1F\nowner: ~\n").unwrap();
assert_eq!(value, value!({"version": 1.1, "port": 31, "owner": null}));
assert_eq!(value["port"].as_u64(), Some(31));
assert_eq!(value["version"].as_f64(), Some(1.1));
assert!(value["owner"].is_null());
assert_eq!(value["version"].as_str(), None);
assert_eq!(value["version"].name(), "float");
assert_eq!(
deser_json::to_string(&value).unwrap(),
r#"{"version":1.10,"port":31,"owner":null}"#
);
assert_eq!(
deser_yaml::to_string(&value).unwrap(),
"version: 1.10\nport: 0x1F\nowner: ~\n"
);
#[derive(deser::Deserialize, Debug, PartialEq)]
struct Config {
version: String,
port: u16,
owner: Option<String>,
}
assert_eq!(
from_value::<Config>(&value).unwrap(),
Config {
version: "1.10".into(),
port: 31,
owner: None,
}
);
let map: std::collections::BTreeMap<String, String> = deser_yaml::from_str("200: ok").unwrap();
assert_eq!(map["200"], "ok");
}
#[test]
fn test_hints() {
#[derive(Serialize)]
struct Config {
#[deser(as = Compact)]
point: BTreeMap<String, u32>,
}
let config = Config {
point: BTreeMap::from([("x".into(), 1), ("y".into(), 2)]),
};
let expected = deser_toml::to_string(&config).unwrap();
assert_eq!(expected, "point = { x = 1, y = 2 }\n");
let value = to_value(&config).unwrap();
assert_eq!(deser_toml::to_string(&value).unwrap(), expected);
#[derive(Serialize)]
struct Wrapper {
#[deser(as = Compact)]
value: Value,
}
let wrapper = Wrapper {
value: value!({"x": 1}),
};
assert_eq!(
deser_toml::to_string(&wrapper).unwrap(),
"value = { x = 1 }\n"
);
let mut value = value!({"x": 1});
value
.meta_mut()
.event_data_mut()
.insert(deser::hints::Layout::Expanded);
assert_eq!(
deser_toml::to_string(&Wrapper { value }).unwrap(),
"[value]\nx = 1\n"
);
}
#[test]
fn test_event_data_is_attached() {
#[derive(Debug, Default, Clone, PartialEq)]
struct Marker(u32);
let mut value = value!([1]);
value[0].meta_mut().event_data_mut().insert(Marker(42));
let mut markers = Vec::new();
deser::ser::SerializeDriver::new(&value)
.drive(|_, state: &mut State| {
markers.push(state.event::<Marker>().cloned());
Ok(())
})
.unwrap();
assert_eq!(markers, [None, Some(Marker(42)), None]);
struct Probe(Option<Marker>);
impl<'de> deser::de::Sink<'de> for Probe {
fn atom(&mut self, _atom: deser::Atom, state: &mut State) -> Result<(), deser::Error> {
self.0 = state.event::<Marker>().cloned();
Ok(())
}
}
let mut probe = Probe(None);
let mut driver =
deser::de::DeserializeDriver::from_fn(|_| deser::de::SinkHandle::to(&mut probe));
deser::de::Deserializer::drive(&mut deser_value::Deserializer::new(&value[0]), &mut driver)
.unwrap();
drop(driver);
assert_eq!(probe.0, Some(Marker(42)));
}
#[test]
fn test_lexical() {
use deser_value::{Kind, Map};
let mut map = Map::new();
map.insert(Kind::Lexical("port".into()), Kind::Lexical("8080".into()));
map.insert(Kind::Lexical("debug".into()), Kind::Lexical("true".into()));
let value = Value::from(Kind::Map(map));
assert_eq!(value["port"], "8080");
assert!(value["port"].is_str() && value["port"].is_lexical());
assert_eq!(value["port"], Value::from("8080"));
#[derive(Debug, deser::Deserialize, PartialEq)]
struct Config {
port: u16,
debug: bool,
}
assert_eq!(
from_value::<Config>(&value).unwrap(),
Config {
port: 8080,
debug: true
}
);
assert_eq!(
from_value::<Config>(&value.clone()).unwrap(),
Config {
port: 8080,
debug: true
}
);
assert!(to_value(&value).unwrap()["port"].is_lexical());
assert_eq!(
deser_json::to_string(&value).unwrap(),
r#"{"port":"8080","debug":"true"}"#
);
assert_eq!(
deser_yaml::to_string(&value).unwrap(),
"port: '8080'\ndebug: 'true'\n"
);
assert_eq!(
deser_toml::to_string(&value).unwrap(),
"port = \"8080\"\ndebug = \"true\"\n"
);
let cbor = deser_cbor::to_vec(&value).unwrap();
let back: Value = deser_cbor::from_slice(&cbor).unwrap();
assert_eq!(back, value);
assert!(!back["port"].is_lexical());
}
#[test]
fn test_repeated() {
use deser::de::DeserializeDriver;
use deser::{Atom, ContainerShape, Event};
let mut out = None::<Value>;
{
let mut driver = DeserializeDriver::new(&mut out);
for event in [
Event::MapStart({
let mut shape = ContainerShape::new();
shape.set_multimap(true);
shape
}),
Atom::Lexical("page".into()).into(),
Atom::Lexical("1".into()).into(),
Atom::Lexical("tag".into()).into(),
Atom::Lexical("x".into()).into(),
Atom::Lexical("page".into()).into(),
Atom::Lexical("2".into()).into(),
Event::MapEnd,
] {
driver.emit(event).unwrap();
}
}
let value = out.unwrap();
assert!(value.as_map().unwrap().is_multimap());
assert!(value["page"].as_seq().unwrap().is_repeated());
assert!(value.clone()["page"].as_seq().unwrap().is_repeated());
assert_eq!(value["tag"].as_str(), Some("x"));
#[derive(Debug, deser::Deserialize, PartialEq)]
struct Query {
page: u32,
tag: Vec<String>,
}
let err = from_value::<Query>(&value).unwrap_err();
assert_eq!(err.message(), "duplicate field `page`");
#[derive(Debug, deser::Deserialize, PartialEq)]
struct Pages {
page: Vec<u32>,
tag: Vec<String>,
}
assert_eq!(
from_value::<Pages>(&value).unwrap(),
Pages {
page: vec![1, 2],
tag: vec!["x".into()]
}
);
let mut out = None::<Value>;
let mut driver = DeserializeDriver::new(&mut out);
driver.emit(Event::map_start()).unwrap();
driver.emit("a").unwrap();
driver.emit(1u64).unwrap();
driver.emit("a").unwrap();
assert!(driver.emit(2u64).is_err());
}
#[test]
fn test_raw_values() {
use deser::ext::{ExtValue, RawFormat, RawInput};
use deser_json::RawJson;
let raw: RawJson = deser_json::from_str(r#"{"a": [1, 2]}"#).unwrap();
let value = deser_value::to_value(&raw).unwrap();
assert_eq!(value["a"][1], deser_value::Value::from(2u64));
let back: RawJson = deser_value::from_value(&value).unwrap();
assert_eq!(back.get(), r#"{"a":[1,2]}"#);
let input = unsafe { RawInput::new(&br#"{"a": [1, 2]}"#[..], deser_json::Json::info()) };
let value = deser_value::Value::from(ExtValue::borrowed_value::<RawInput>(&input));
assert_eq!(value["a"][0], deser_value::Value::from(1u64));
assert_eq!(deser_yaml::to_string(&value).unwrap(), "a:\n - 1\n - 2\n");
}
#[test]
fn test_cbor_declared_lengths_are_not_trusted() {
let array = [0x9b, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff];
assert!(deser_cbor::from_slice::<Value>(&array).is_err());
let map = [0xbb, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff];
assert!(deser_cbor::from_slice::<Value>(&map).is_err());
}