simuldb 0.12.3

Database with backend and format agnostic data storage for simulation results coupled with metadata
Documentation
use std::collections::BTreeMap;

use arbitrary::{Arbitrary, Result, Unstructured};
use log::info;
use serde::{Deserialize, Serialize};
use test_log::test;

use crate::{
    testutils::TestConfig,
    value::{de::from_value, ValueSerializer},
};

#[derive(Debug, Serialize, Deserialize, Arbitrary, PartialEq, Eq, PartialOrd, Ord)]
struct ComplexStruct {
    uint: u32,
    tuple: (u8, u16, u32, i8, i16, i32, i64, isize),
    optional_bool: Option<bool>,
    cplx_enum: ComplexEnum,
    map: BTreeMap<String, ComplexStruct>,
    vec: Vec<String>,
    string: String,
}

#[derive(Debug, Serialize, Deserialize, Arbitrary, Hash, PartialEq, Eq, PartialOrd, Ord)]
enum ComplexEnum {
    A,
    B(i64, u8),
    C {},
    D { a: u32, b: Box<ComplexEnum> },
}

fn serialize_complex_struct(u: &mut Unstructured<'_>) -> Result<()> {
    let s: ComplexStruct = u.arbitrary()?;
    let _value = s
        .serialize(ValueSerializer)
        .expect("Failed to serialize complex struct");
    Ok(())
}

#[test]
fn test_serialize_complex_struct() {
    let config = TestConfig::load().unwrap();
    arbtest::builder()
        .budget_ms(config.budget)
        .run(serialize_complex_struct);
}

fn arbitrary_json_value(u: &mut Unstructured<'_>) -> Result<serde_json::Value> {
    let v: crate::value::Value = u.arbitrary()?;
    Ok(serde_json::to_value(v).expect("Could not serialize value to JSON"))
}

fn json_value_round_trip(u: &mut Unstructured<'_>) -> Result<()> {
    let v: serde_json::Value = normalize(arbitrary_json_value(u)?);
    info!("Testing round trip for {v:#?}");
    let ser = v
        .serialize(ValueSerializer)
        .expect("Could not serialize value");
    info!("Serialized to {ser:?}");
    let v2: serde_json::Value = from_value(&ser).expect("Could not serialize value");
    info!("Got {v2:#?}");
    assert!(values_equal(&v, &v2));
    Ok(())
}

fn normalize(a: serde_json::Value) -> serde_json::Value {
    match a {
        serde_json::Value::Number(n) => serde_json::Value::Number(match n.as_i64() {
            Some(x) => x.into(),
            None => serde_json::value::Number::from_f64(n.as_f64().unwrap_or_default()).unwrap_or(
                serde_json::value::Number::from_f64(0.).expect("Failed to create number"),
            ),
        }),
        serde_json::Value::Array(x) => {
            serde_json::Value::Array(x.into_iter().map(normalize).collect())
        }
        serde_json::Value::Object(x) => {
            serde_json::Value::Object(x.into_iter().map(|(k, v)| (k, normalize(v))).collect())
        }
        _ => a,
    }
}

fn values_equal(a: &serde_json::Value, b: &serde_json::Value) -> bool {
    match (a, b) {
        (serde_json::Value::Number(n), serde_json::Value::Number(m)) => {
            if let (Some(x), Some(y)) = (n.as_i64(), m.as_i64()) {
                return x == y;
            }
            if let (Some(x), Some(y)) = (n.as_u64(), m.as_u64()) {
                return x == y;
            }
            if let (Some(x), Some(y)) = (n.as_f64(), m.as_f64()) {
                return x == y;
            }
            false
        }
        _ => a == b,
    }
}

#[test]
fn test_serde_json_round_trip() {
    let config = TestConfig::load().unwrap();
    arbtest::builder()
        .budget_ms(config.budget)
        .run(json_value_round_trip);
}

fn struct_round_trip(u: &mut Unstructured<'_>) -> Result<()> {
    let v: ComplexStruct = u.arbitrary()?;
    info!("Testing round trip for {v:#?}");
    let ser = v
        .serialize(ValueSerializer)
        .expect("Could not serialize value");
    info!("Serialized to {ser:#?}");
    let v2: ComplexStruct = from_value(&ser).expect("Could not serialize complex struct");
    info!("Got {v2:#?}");
    assert_eq!(&v, &v2);
    Ok(())
}

#[test]
fn test_struct_round_trip() {
    let config = TestConfig::load().unwrap();
    arbtest::builder()
        .budget_ms(config.budget)
        .run(struct_round_trip);
}