From aede3bc14bcb616d659c1527401a0e85decafb87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Agust=C3=ADn=20Borgna?= <121866228+aborgna-q@users.noreply.github.com> Date: Fri, 1 Dec 2023 17:30:07 +0100 Subject: [PATCH] test: Unify the serialisation tests (#730) 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`. --- src/hugr/serialize.rs | 112 +++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 68 deletions(-) diff --git a/src/hugr/serialize.rs b/src/hugr/serialize.rs index 17a2c8d11..97ba57ab5 100644 --- a/src/hugr/serialize.rs +++ b/src/hugr/serialize.rs @@ -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, }; @@ -277,11 +278,47 @@ pub mod test { assert_eq!(ser_roundtrip(&hg), hg); } + /// Serialize and deserialize a value. pub fn ser_roundtrip(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); @@ -323,7 +360,7 @@ pub mod test { op_types[n] = NodeType::new_pure(gen_optype(&g, n)); } - let hg = Hugr { + let hugr = Hugr { graph: g, hierarchy: h, root, @@ -331,10 +368,7 @@ pub mod test { 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] @@ -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] @@ -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(); @@ -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)); - } } }