serde_hooks 0.1.1

Runtime hooks for serde
Documentation
use std::{cell::RefCell, collections::HashSet};

use serde::Serialize;
use serde_hooks::{ser, Path, StaticValue};

#[test]
fn test_seq_traversing() {
    #[derive(Serialize)]
    struct Outer {
        vec: Vec<i32>,
        nested: Vec<Vec<i32>>,
    }

    let outer = Outer {
        vec: vec![1, 2, 3],
        nested: vec![vec![4, 5], vec![6]],
    };

    struct Hooks {
        fields_to_expect: RefCell<HashSet<String>>,
    }
    impl ser::Hooks for Hooks {
        fn on_seq(&self, path: &Path, seq: &mut ser::SeqScope) {
            let path = path.borrow_str();
            self.fields_to_expect.borrow_mut().remove(path.as_str());

            match path.as_str() {
                "vec" => {
                    assert_eq!(seq.seq_len(), Some(3));
                }
                "nested" => {
                    assert_eq!(seq.seq_len(), Some(2));
                }
                "nested[0]" => {
                    assert_eq!(seq.seq_len(), Some(2));
                }
                "nested[1]" => {
                    assert_eq!(seq.seq_len(), Some(1));
                }
                _ => unreachable!("{path}"),
            }
        }
    }
    let hooks = Hooks {
        fields_to_expect: RefCell::new(
            ["vec", "nested", "nested[0]", "nested[1]"]
                .into_iter()
                .map(Into::into)
                .collect(),
        ),
    };

    serde_json::to_string(&ser::hook(&outer, &hooks)).unwrap();
    assert!(
        hooks.fields_to_expect.borrow().is_empty(),
        "following fields were expected, but not called back about {:?}",
        hooks.fields_to_expect.borrow()
    );
}

#[test]
fn test_seq_skip_element() {
    struct Hooks;
    impl ser::Hooks for Hooks {
        fn on_seq(&self, _path: &Path, seq: &mut ser::SeqScope) {
            seq.skip_element(1).skip_element(12345);
        }

        fn on_scope_error(&self, path: &Path, err: &mut ser::ErrorScope) {
            assert_eq!(path, "");
            assert_eq!(*err.error(), ser::HooksError::IndexNotFound(12345));
            err.ignore();
        }
    }

    let json = serde_json::to_string(&ser::hook(&vec![0i32, 1, 2], &Hooks)).unwrap();
    assert_eq!(json, "[0,2]");
}

#[test]
fn test_seq_retain_element() {
    struct Hooks;
    impl ser::Hooks for Hooks {
        fn on_seq(&self, _path: &Path, seq: &mut ser::SeqScope) {
            seq.retain_element(1)
                .retain_element(2)
                .retain_element(12345);
        }

        fn on_scope_error(&self, path: &Path, err: &mut ser::ErrorScope) {
            assert_eq!(path, "");
            assert_eq!(*err.error(), ser::HooksError::IndexNotFound(12345));
            err.ignore();
        }
    }

    let json = serde_json::to_string(&ser::hook(&vec![0i32, 1, 2, 3], &Hooks)).unwrap();
    assert_eq!(json, "[1,2]");
}

#[test]
fn test_seq_replace_value() {
    struct Hooks;
    impl ser::Hooks for Hooks {
        fn on_seq(&self, _path: &Path, seq: &mut ser::SeqScope) {
            seq.replace_value(1, -10i32)
                .replace_value(2, 'a')
                .replace_value(12345, "error");
        }

        fn on_scope_error(&self, path: &Path, err: &mut ser::ErrorScope) {
            assert_eq!(path, "");
            assert_eq!(*err.error(), ser::HooksError::IndexNotFound(12345));
            err.ignore();
        }
    }

    let json = serde_json::to_string(&ser::hook(&vec![0i32, 1, 2, 3], &Hooks)).unwrap();
    assert_eq!(json, "[0,-10,\"a\",3]");
}

#[test]
fn test_seq_replace_value_unserializable() {
    struct Hooks;
    impl ser::Hooks for Hooks {
        fn on_seq(&self, _path: &Path, seq: &mut ser::SeqScope) {
            seq.replace_value(1, StaticValue::NewtypeStruct("STRUCT"));
        }
    }

    let err = serde_json::to_string(&ser::hook(&vec![0i32, 1, 2, 3], &Hooks)).unwrap_err();
    assert_eq!(err.to_string(), "Error at path '[1]': value is not serializable: newtype STRUCT cannot be represented fully in Value");
}