Skip to content

Commit

Permalink
test: Unify the serialisation tests (#730)
Browse files Browse the repository at this point in the history
The tests all checked something different after the serialization
rountrip.
This adds a check function to tests hugrs after the rondtrip.

Also drops the `metadata_hugr_ser` test, which was a duplicate from
`weighted_hugr_ser`.
  • Loading branch information
aborgna-q authored Dec 1, 2023
1 parent a69246b commit aede3bc
Showing 1 changed file with 44 additions and 68 deletions.
112 changes: 44 additions & 68 deletions src/hugr/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,7 @@ pub mod test {
use crate::types::{FunctionType, Type};
use crate::OutgoingPort;
use itertools::Itertools;
use portgraph::LinkView;
use portgraph::{
multiportgraph::MultiPortGraph, Hierarchy, LinkMut, PortMut, PortView, UnmanagedDenseMap,
};
Expand All @@ -277,11 +278,47 @@ pub mod test {
assert_eq!(ser_roundtrip(&hg), hg);
}

/// Serialize and deserialize a value.
pub fn ser_roundtrip<T: Serialize + serde::de::DeserializeOwned>(g: &T) -> T {
let v = rmp_serde::to_vec_named(g).unwrap();
rmp_serde::from_slice(&v[..]).unwrap()
}

/// Serialize and deserialize a HUGR, and check that the result is the same as the original.
///
/// Returns the deserialized HUGR.
pub fn check_hugr_roundtrip(hugr: &Hugr) -> Hugr {
let new_hugr: Hugr = ser_roundtrip(hugr);

// Original HUGR, with canonicalized node indices
//
// The internal port indices may still be different.
let mut h_canon = hugr.clone();
h_canon.canonicalize_nodes(|_, _| {});

assert_eq!(new_hugr.root, h_canon.root);
assert_eq!(new_hugr.hierarchy, h_canon.hierarchy);
assert_eq!(new_hugr.op_types, h_canon.op_types);
assert_eq!(new_hugr.metadata, h_canon.metadata);

// Check that the graphs are equivalent up to port renumbering.
let new_graph = &new_hugr.graph;
let old_graph = &h_canon.graph;
assert_eq!(new_graph.node_count(), old_graph.node_count());
assert_eq!(new_graph.port_count(), old_graph.port_count());
assert_eq!(new_graph.link_count(), old_graph.link_count());
for n in old_graph.nodes_iter() {
assert_eq!(new_graph.num_inputs(n), old_graph.num_inputs(n));
assert_eq!(new_graph.num_outputs(n), old_graph.num_outputs(n));
assert_eq!(
new_graph.output_neighbours(n).collect_vec(),
old_graph.output_neighbours(n).collect_vec()
);
}

new_hugr
}

/// Generate an optype for a node with a matching amount of inputs and outputs.
fn gen_optype(g: &MultiPortGraph, node: portgraph::NodeIndex) -> OpType {
let inputs = g.num_inputs(node);
Expand Down Expand Up @@ -323,18 +360,15 @@ pub mod test {
op_types[n] = NodeType::new_pure(gen_optype(&g, n));
}

let hg = Hugr {
let hugr = Hugr {
graph: g,
hierarchy: h,
root,
op_types,
metadata: Default::default(),
};

let v = rmp_serde::to_vec_named(&hg).unwrap();

let newhg = rmp_serde::from_slice(&v[..]).unwrap();
assert_eq!(hg, newhg);
check_hugr_roundtrip(&hugr);
}

#[test]
Expand Down Expand Up @@ -368,44 +402,7 @@ pub mod test {
module_builder.finish_prelude_hugr().unwrap()
};

let ser_hugr: SerHugrV0 = (&hugr).try_into().unwrap();
// HUGR internal structures are not preserved across serialization, so
// test equality on SerHugrV0 instead.
assert_eq!(ser_roundtrip(&ser_hugr), ser_hugr);
}

#[test]
fn metadata_hugr_ser() {
let hugr = {
let mut module_builder = ModuleBuilder::new();
let t_row = vec![Type::new_sum(vec![NAT, QB])];
let mut f_build = module_builder
.define_function("main", FunctionType::new(t_row.clone(), t_row).into())
.unwrap();

let outputs = f_build
.input_wires()
.map(|in_wire| {
f_build
.add_dataflow_op(
LeafOp::Noop {
ty: f_build.get_wire_type(in_wire).unwrap(),
},
[in_wire],
)
.unwrap()
.out_wire(0)
})
.collect_vec();

f_build.finish_with_outputs(outputs).unwrap();
module_builder.finish_prelude_hugr().unwrap()
};

let ser_hugr: SerHugrV0 = (&hugr).try_into().unwrap();
// HUGR internal structures are not preserved across serialization, so
// test equality on SerHugrV0 instead.
assert_eq!(ser_roundtrip(&ser_hugr), ser_hugr);
check_hugr_roundtrip(&hugr);
}

#[test]
Expand All @@ -419,25 +416,14 @@ pub mod test {
.unwrap()
.out_wire(0);
}
let h = dfg.finish_hugr_with_outputs(params, &EMPTY_REG)?;

let ser = serde_json::to_string(&h)?;
let h_deser: Hugr = serde_json::from_str(&ser)?;

// Check the canonicalization works
let mut h_canon = h;
h_canon.canonicalize_nodes(|_, _| {});

for node in h_deser.nodes() {
assert_eq!(h_deser.get_optype(node), h_canon.get_optype(node));
assert_eq!(h_deser.get_parent(node), h_canon.get_parent(node));
}
let hugr = dfg.finish_hugr_with_outputs(params, &EMPTY_REG)?;

check_hugr_roundtrip(&hugr);
Ok(())
}

#[test]
fn hierarchy_order() {
fn canonicalisation() {
let mut hugr = closed_dfg_root_hugr(FunctionType::new(vec![QB], vec![QB]));
let [old_in, out] = hugr.get_io(hugr.root()).unwrap();
hugr.connect(old_in, 0, out, 0).unwrap();
Expand All @@ -450,18 +436,8 @@ pub mod test {
hugr.remove_node(old_in).unwrap();
hugr.update_validate(&PRELUDE_REGISTRY).unwrap();

let ser = serde_json::to_vec(&hugr).unwrap();
let new_hugr: Hugr = serde_json::from_slice(&ser).unwrap();
let new_hugr: Hugr = check_hugr_roundtrip(&hugr);
new_hugr.validate(&EMPTY_REG).unwrap_err();
new_hugr.validate(&PRELUDE_REGISTRY).unwrap();

// Check the canonicalization works
let mut h_canon = hugr.clone();
h_canon.canonicalize_nodes(|_, _| {});

for node in new_hugr.nodes() {
assert_eq!(new_hugr.get_optype(node), h_canon.get_optype(node));
assert_eq!(new_hugr.get_parent(node), h_canon.get_parent(node));
}
}
}

0 comments on commit aede3bc

Please sign in to comment.