Files
SpacetimeDB/crates/lib/tests/serde.rs
Mario Montoya 82d5a4f6c0 Implement SpacetimeType for Result<T, E> (#3790)
# Description of Changes

Closes #3673 

*NOTE*: C++ part will be in another PR

# Expected complexity level and risk

2

Adding a new type touch everywhere

# Testing

- [x] Adding smoke and unit test

---------

Signed-off-by: Ryan <r.ekhoff@clockworklabs.io>
Co-authored-by: rekhoff <r.ekhoff@clockworklabs.io>
Co-authored-by: Phoebe Goldman <phoebe@goldman-tribe.org>
Co-authored-by: Jason Larabie <jason@clockworklabs.io>
2026-01-08 15:50:18 +00:00

138 lines
4.0 KiB
Rust

use spacetimedb_lib::de::serde::SerdeDeserializer;
use spacetimedb_lib::de::DeserializeSeed;
use spacetimedb_lib::{AlgebraicType, Identity, ProductType, ProductTypeElement, ProductValue, SumType};
use spacetimedb_sats::algebraic_value::de::ValueDeserializer;
use spacetimedb_sats::algebraic_value::ser::value_serialize;
use spacetimedb_sats::{satn::Satn, GroundSpacetimeType as _, SumTypeVariant, Typespace, WithTypespace};
macro_rules! de_json_snapshot {
($schema:expr, $json:expr) => {
let (schema, json) = (&$schema, &$json);
let value = de_json(schema, json).unwrap();
let value = WithTypespace::new(&EMPTY_TYPESPACE, schema)
.with_value(&value)
.to_satn_pretty();
let debug_expr = format!("de_json({})", json.trim());
insta::assert_snapshot!(insta::internals::AutoName, value, &debug_expr);
};
}
#[derive(
Debug,
PartialEq,
spacetimedb_sats::de::Deserialize,
spacetimedb_sats::ser::Serialize,
serde::Serialize,
serde::Deserialize,
)]
struct Sample {
identity: Identity,
}
#[test]
fn test_roundtrip() {
let original = Sample {
identity: Identity::__dummy(),
};
let s = value_serialize(&original);
let result: Sample = spacetimedb_sats::de::Deserialize::deserialize(ValueDeserializer::new(s)).unwrap();
assert_eq!(&original, &result);
let s = serde_json::ser::to_string(&original).unwrap();
let result: Sample = serde_json::from_str(&s).unwrap();
assert_eq!(&original, &result);
}
#[test]
fn test_roundtrip_ron() {
let original = Sample {
identity: Identity::__dummy(),
};
let s = value_serialize(&original);
let result: Sample = spacetimedb_sats::de::Deserialize::deserialize(ValueDeserializer::new(s)).unwrap();
assert_eq!(&original, &result);
let s = ron::to_string(&original).unwrap();
let result: Sample = ron::from_str(&s).unwrap();
assert_eq!(&original, &result);
}
#[test]
fn test_json_mappings() {
let schema = tuple([
("foo", AlgebraicType::U32),
("bar", AlgebraicType::bytes()),
("baz", AlgebraicType::array(AlgebraicType::String)),
(
"quux",
enumm([("Hash", AlgebraicType::bytes()), ("Unit", AlgebraicType::unit())]).into(),
),
("and_peggy", AlgebraicType::option(AlgebraicType::F64)),
(
"result",
AlgebraicType::result(AlgebraicType::U32, AlgebraicType::String),
),
("identity", Identity::get_type()),
]);
let data = r#"
{
"foo": 42,
"bar": "404040FFFF0A48656C6C6F",
"baz": ["heyyyyyy", "hooo"],
"quux": { "Hash": "54a3e6d2b0959deaacf102292b1cbd6fcbb8cf237f73306e27ed82c3153878aa" },
"and_peggy": { "some": 3.141592653589793238426 },
"result": { "ok": 1 },
"identity": ["0x0"]
}
"#; // all of those ^^^^^^ digits are from memory
de_json_snapshot!(schema, data);
let data = r#"
{
"foo": 5654,
"bar": [1, 15, 44],
"baz": ["it's 🥶°C"],
"quux": { "Unit": [] },
"and_peggy": null,
"result": { "err": "sorry" },
"identity": ["0x0"]
}
"#;
de_json_snapshot!(schema, data);
}
fn tuple<'a>(elems: impl IntoIterator<Item = (&'a str, AlgebraicType)>) -> ProductType {
ProductType {
elements: elems
.into_iter()
.map(|(name, ty)| ProductTypeElement::new_named(ty, name))
.collect(),
}
}
fn enumm<'a>(elems: impl IntoIterator<Item = (&'a str, AlgebraicType)>) -> SumType {
SumType {
variants: elems
.into_iter()
.map(|(name, ty)| SumTypeVariant::new_named(ty, name))
.collect(),
}
}
static EMPTY_TYPESPACE: Typespace = Typespace::new(Vec::new());
fn in_space<T>(x: &T) -> WithTypespace<'_, T> {
WithTypespace::new(&EMPTY_TYPESPACE, x)
}
fn de_json(schema: &ProductType, data: &str) -> serde_json::Result<ProductValue> {
let mut de = serde_json::Deserializer::from_str(data);
let val = in_space(schema)
.deserialize(SerdeDeserializer::new(&mut de))
.map_err(|e| e.0)?;
de.end()?;
Ok(val)
}