use std::{borrow::Cow, collections::HashMap};
use crate::utils::{read_asset_file, test_vdf_deserialization, BoxedResult, Container};
use insta::{assert_debug_snapshot, assert_snapshot};
use keyvalues_serde::{
from_str, from_str_raw, from_str_with_key, to_string, to_string_with_key, to_writer,
to_writer_with_key, Error,
};
use pretty_assertions::assert_eq;
use serde::Deserialize;
#[test]
fn snapshot_writing() -> BoxedResult<()> {
let name_base = "snapshot_writing";
let vdf_struct = Container::new(123);
let mut buf = Vec::new();
to_writer(&mut buf, &vdf_struct)?;
assert_snapshot!(
format!("{}-to_writer", name_base),
std::str::from_utf8(&buf)?
);
buf.clear();
to_writer_with_key(&mut buf, &vdf_struct, "Custom")?;
assert_snapshot!(
format!("{}-to_writer_with_key", name_base),
std::str::from_utf8(&buf)?
);
Ok(())
}
#[test]
fn hashmap_top_level() -> BoxedResult<()> {
let val = HashMap::from([(0, "Foo"), (1, "Bar"), (2, "Baz")]);
let vdf_text = read_asset_file("hashmap_top_level.vdf")?;
test_vdf_deserialization(&vdf_text, &val)?;
let val_text = to_string_with_key(&val, "Key")?;
assert_eq!(vdf_text, val_text, "Failed serializing");
Ok(())
}
#[test]
fn check_deserialization_key() -> BoxedResult<()> {
let vdf_text = read_asset_file("hashmap_top_level.vdf")?;
let (_, key): (HashMap<u64, String>, Cow<str>) = from_str_with_key(&vdf_text)?;
assert_eq!(key, "Key", "Incorrect deserialization key");
Ok(())
}
#[test]
fn non_finite_float_serialization_failure() {
let vdf = Container::new(f32::NAN);
if let Err(Error::NonFiniteFloat(f)) = to_string(&vdf) {
assert!(f.is_nan());
} else {
unreachable!("Serialization should fail with NaN float");
}
}
#[test]
fn non_finite_float_deserialization_failure() -> BoxedResult<()> {
let vdf_text = read_asset_file("subnormal_float.vdf")?;
if let Err(Error::NonFiniteFloat(f)) = from_str::<Container<f32>>(&vdf_text) {
assert!(f.is_infinite());
} else {
unreachable!("Deserialization should fail with inf float");
}
Ok(())
}
#[test]
fn non_normal_but_finite_float_serialization() -> BoxedResult<()> {
let vdf_text = read_asset_file("zero_float.vdf")?;
let vdf: Container<f32> = from_str(&vdf_text)?;
assert_eq!(vdf, Container::new(0.0f32));
Ok(())
}
#[test]
fn extract_only_some_members() -> BoxedResult<()> {
let vdf_text = read_asset_file("multiple_members.vdf")?;
let vdf: Container<String> = from_str(&vdf_text)?;
assert_eq!(vdf, Container::new(String::from("Value")));
Ok(())
}
#[derive(Deserialize, Debug)]
#[allow(dead_code)]
struct AnyHolder {
#[serde(flatten)]
foo: StructureDefinedType,
}
#[derive(Deserialize, Debug)]
#[allow(dead_code)]
struct StructureDefinedType {
inner: String,
#[serde(rename = "str key")]
str_key: String,
#[serde(rename = "obj key")]
obj_key: HashMap<String, String>,
#[serde(rename = "seq key")]
seq_key: Vec<String>,
}
#[test]
fn deserialize_any_values() -> BoxedResult<()> {
let vdf_text = read_asset_file("multiple_members.vdf")?;
let any_holder: AnyHolder = from_str(&vdf_text)?;
assert_debug_snapshot!("deserialize_any_values", any_holder);
Ok(())
}
#[test]
fn borrowed_escaped_string() -> BoxedResult<()> {
let vdf_text = read_asset_file("escaped_string.vdf")?;
let vdf: Container<Cow<str>> = from_str(&vdf_text)?;
assert_eq!(vdf, Container::new(Cow::from("tab\tseparated")));
Ok(())
}
#[test]
fn raw_escaped_string() -> BoxedResult<()> {
let vdf_text = read_asset_file("raw_string.vdf")?;
let vdf: RawString = from_str_raw(&vdf_text)?;
assert_eq!(vdf.unescaped_str_key, vec!["str\\a\\bvalue"]);
Ok(())
}
#[derive(Deserialize, Debug, PartialEq)]
struct RawString {
#[serde(rename = "str\\key")]
pub unescaped_str_key: Vec<String>,
}
#[derive(Deserialize, Debug, PartialEq)]
struct BorrowedString<'a> {
#[serde(borrow)]
inner: Cow<'a, str>,
}
#[test]
fn borrowed_string_is_borrowed() -> BoxedResult<()> {
let vdf_text = read_asset_file("string_container.vdf")?;
let vdf: BorrowedString = from_str(&vdf_text)?;
assert!(matches!(vdf.inner, Cow::Borrowed(_)));
Ok(())
}