conformance.rs (5344B)
1 #![cfg(feature = "serde")] 2 3 use std::collections::BTreeSet; 4 5 use radroots_protocol::{ 6 capability::v1::{ReticulumTarget, TransportKind}, 7 error::v1::ErrorReport, 8 event::v1::{EventClass, TradeState}, 9 radrootsd::transport_publish::v5::{DeliveryPolicy, TargetPolicy}, 10 runtime::v1::{OperationId, Risk, TransportRoute}, 11 schema::{ModuleVersion, protocol_v1_registry}, 12 }; 13 use serde::{Serialize, de::DeserializeOwned}; 14 use serde_json::Value; 15 16 const WIRE_VECTORS: &str = include_str!("fixtures/wire_values.v1.json"); 17 const GENERATED_INVENTORY: &str = include_str!("fixtures/protocol_v1.inventory.json"); 18 19 #[test] 20 fn language_neutral_wire_vectors_are_unique_and_executable() { 21 let document: Value = serde_json::from_str(WIRE_VECTORS).expect("protocol wire vectors"); 22 assert_eq!(document["suite"], "protocol_wire_values_v1"); 23 assert_eq!(document["contract_version"], "1.0.0"); 24 let vectors = document["vectors"].as_array().expect("vector array"); 25 let mut ids = BTreeSet::new(); 26 for vector in vectors { 27 let id = vector["id"].as_str().expect("vector id"); 28 assert!(ids.insert(id), "duplicate protocol vector id `{id}`"); 29 let kind = vector["kind"].as_str().expect("vector kind"); 30 let input = vector["input"].clone(); 31 let result = match kind { 32 "protocol.capability.transport_kind" => execute::<TransportKind>(input), 33 "protocol.capability.reticulum_target" => execute::<ReticulumTarget>(input), 34 "protocol.event.event_class" => execute::<EventClass>(input), 35 "protocol.event.trade_state" => execute::<TradeState>(input), 36 "protocol.runtime.operation_id" => execute::<OperationId>(input), 37 "protocol.runtime.risk" => execute::<Risk>(input), 38 "protocol.runtime.transport_route" => execute::<TransportRoute>(input), 39 "protocol.radrootsd.target_policy" => execute::<TargetPolicy>(input), 40 "protocol.radrootsd.delivery_policy" => execute::<DeliveryPolicy>(input), 41 "protocol.error.report" => execute::<ErrorReport>(input), 42 other => panic!("unimplemented protocol vector kind `{other}`"), 43 }; 44 match ( 45 vector.get("expected"), 46 vector.get("expected_error_contains"), 47 result, 48 ) { 49 (Some(expected), None, Ok(actual)) => assert_eq!(&actual, expected, "vector `{id}`"), 50 (None, Some(expected), Err(error)) => assert!( 51 error.contains(expected.as_str().expect("error fragment")), 52 "vector `{id}` expected `{expected}`, found `{error}`" 53 ), 54 (Some(_), None, Err(error)) => panic!("vector `{id}` unexpectedly failed: {error}"), 55 (None, Some(_), Ok(actual)) => { 56 panic!("vector `{id}` unexpectedly succeeded: {actual}") 57 } 58 _ => panic!("vector `{id}` has an invalid expectation shape"), 59 } 60 } 61 assert_eq!(ids.len(), 13); 62 } 63 64 #[test] 65 fn generated_inventory_is_complete_unique_and_matches_the_schema_registry() { 66 let inventory: Value = 67 serde_json::from_str(GENERATED_INVENTORY).expect("generated protocol inventory"); 68 assert_eq!(inventory["schema_version"], 1); 69 assert_eq!(inventory["package"], "radroots_protocol"); 70 71 let sources = inventory["sources"].as_array().expect("sources"); 72 let actual_modules = sources 73 .iter() 74 .map(|source| source["module"].as_str().expect("source module")) 75 .collect::<BTreeSet<_>>(); 76 let expected_modules = ModuleVersion::ALL 77 .iter() 78 .map(|module| module.path()) 79 .collect::<BTreeSet<_>>(); 80 assert_eq!(actual_modules, expected_modules); 81 82 let type_paths = sources 83 .iter() 84 .flat_map(|source| source["types"].as_array().expect("source types")) 85 .map(|item| item["rust_path"].as_str().expect("Rust path")) 86 .collect::<Vec<_>>(); 87 assert_eq!(type_paths.len(), 60); 88 assert_eq!( 89 type_paths.iter().copied().collect::<BTreeSet<_>>().len(), 90 60 91 ); 92 assert!(type_paths.contains(&"radroots_protocol::runtime::v1::OperationId")); 93 94 let inventory_schemas = inventory["schemas"] 95 .as_array() 96 .expect("schemas") 97 .iter() 98 .map(|schema| { 99 ( 100 schema["schema_id"].as_str().expect("schema id").to_owned(), 101 schema["module"].as_str().expect("schema module").to_owned(), 102 schema["generation"].as_u64().expect("generation") as u16, 103 ) 104 }) 105 .collect::<BTreeSet<_>>(); 106 let registry_schemas = protocol_v1_registry() 107 .expect("protocol registry") 108 .descriptors() 109 .iter() 110 .map(|descriptor| { 111 ( 112 descriptor.id().as_str().to_owned(), 113 descriptor.module().path().to_owned(), 114 descriptor.module().generation(), 115 ) 116 }) 117 .collect::<BTreeSet<_>>(); 118 assert_eq!(inventory_schemas.len(), 121); 119 assert_eq!(inventory_schemas, registry_schemas); 120 } 121 122 fn execute<T>(input: Value) -> Result<Value, String> 123 where 124 T: DeserializeOwned + Serialize, 125 { 126 let decoded: T = serde_json::from_value(input).map_err(|error| error.to_string())?; 127 serde_json::to_value(decoded).map_err(|error| error.to_string()) 128 }