diff options
Diffstat (limited to 'tests/random.rs')
-rw-r--r-- | tests/random.rs | 147 |
1 files changed, 109 insertions, 38 deletions
diff --git a/tests/random.rs b/tests/random.rs index a9d1609..d92ce79 100644 --- a/tests/random.rs +++ b/tests/random.rs @@ -2,54 +2,125 @@ use libtest_mimic::{Arguments, Trial}; use mt_net::{generate_random::GenerateRandomVariant, rand, ToCltPkt, ToSrvPkt}; use mt_ser::{DefCfg, MtDeserialize, MtSerialize}; -use std::{error::Error, fmt::Debug}; +use std::{ + error::Error, + fmt::Debug, + io::{Cursor, Write}, + path::Path, + process::{Command, Stdio}, +}; -fn test_reserialize<T>(type_name: &'static str) -> impl Iterator<Item = Trial> +fn test_reserialize<'a, T>(type_name: &'static str, reserialize: &Path) -> Vec<Trial> where T: MtSerialize + MtDeserialize + GenerateRandomVariant + PartialEq + Debug, { - (0..T::num_variants()).map(move |i| { - Trial::test(format!("{type_name}::{}", T::variant_name(i)), move || { - let mut rng = rand::thread_rng(); - - for _ in 0..100 { - let input = T::generate_random_variant(&mut rng, i); - - let mut writer = Vec::new(); - input - .mt_serialize::<DefCfg>(&mut writer) - .map_err(|e| format!("serialize error: {e}\ninput: {input:?}"))?; - - let mut reader = std::io::Cursor::new(writer); - let output = T::mt_deserialize::<DefCfg>(&mut reader).map_err(|e| { - format!( - "deserialize error: {e}\ninput: {input:?}\npayload: {:?}", - reader.get_ref() - ) - })?; - - if input != output { - return Err(format!( - "output did not match input\n\ - input: {input:?}\n\ - payload: {:?}\n\ - output: {output:?}", - reader.get_ref(), - ) - .into()); + (0..T::num_variants()) + .map(move |i| { + let pkt_name = format!("{type_name}::{}", T::variant_name(i)); + let reserialize = reserialize.as_os_str().to_os_string(); + + Trial::test(pkt_name.clone(), move || { + let mut rng = rand::thread_rng(); + let mut printed_stderr = false; + + for _ in 0..100 { + // use buffered IO instead of directly reading from the process + // this enables printing out payloads for debugging + + let input = T::generate_random_variant(&mut rng, i); + + let mut writer = Vec::new(); + input + .mt_serialize::<DefCfg>(&mut writer) + .map_err(|e| format!("serialize error: {e}\ninput: {input:?}"))?; + + let mut child = Command::new(&reserialize) + .arg(type_name) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .stderr(Stdio::piped()) + .spawn() + .expect("failed to spawn reserialize"); + + let mut stdin = child.stdin.take().expect("failed to open stdin"); + let payload = writer.clone(); + std::thread::spawn(move || { + stdin.write_all(&payload).expect("failed to write to stdin"); + }); + + let command_out = child.wait_with_output().expect("failed to read stdout"); + + let stderr = String::from_utf8_lossy(&command_out.stderr); + if command_out.status.success() { + if stderr.len() > 0 && !printed_stderr { + printed_stderr = true; + eprintln!("stderr for {pkt_name}: {stderr}"); + } + } else { + return Err(format!( + "reserialize returned failure\n\ + input: {input:?}\n\ + input payload: {writer:?}\n\ + stderr: {stderr}" + ) + .into()); + } + + let mut reader = Cursor::new(command_out.stdout); + let output = T::mt_deserialize::<DefCfg>(&mut reader).map_err(|e| { + format!( + "deserialize error: {e}\n\ + input: {input:?}\n\ + input payload: {writer:?}\n\ + output payload: {:?}\n\ + stderr: {stderr}", + reader.get_ref() + ) + })?; + + if input != output { + return Err(format!( + "output does not match input\n\ + input: {input:?}\n\ + output: {output:?}\n\ + input payload: {writer:?}\n\ + output payload: {:?}\n\ + stderr: {stderr}", + reader.get_ref(), + ) + .into()); + } } - } - Ok(()) + Ok(()) + }) + .with_kind("random") }) - .with_kind("random") - }) + .collect() } fn main() -> Result<(), Box<dyn Error>> { + let reserialize = Path::new(file!()).with_file_name("reserialize/reserialize"); + + if !reserialize.exists() { + if !Command::new("go") + .arg("build") + .current_dir(reserialize.parent().unwrap()) + .spawn() + .expect("go is required for random tests") + .wait() + .expect("go build didn't run") + .success() + { + panic!("go build failed"); + } + } + let args = Arguments::from_args(); - let tests = test_reserialize::<ToSrvPkt>("ToSrvPkt") - .chain(test_reserialize::<ToCltPkt>("ToCltPkt")) - .collect(); + + let mut tests = Vec::new(); + tests.extend(test_reserialize::<ToSrvPkt>("ToSrvPkt", &reserialize)); + tests.extend(test_reserialize::<ToCltPkt>("ToCltPkt", &reserialize)); + libtest_mimic::run(&args, tests).exit(); } |