use assert_cmd::Command; use assert_fs::prelude::*; use assert_fs::NamedTempFile; use itertools::Itertools; use std::fs::read_to_string; use std::path::Path; fn seq(from: isize, to: isize, step_width: usize) -> String { (from..=to).step_by(step_width).join("\n") + "\n" } fn seq_ring(from: isize, to: isize, modulo: isize, reminders: &[isize]) -> String { (from..=to) .filter(|i| reminders.iter().any(|reminder| i % modulo == *reminder)) .join("\n") + "\n" } fn outputs(prefix: &str, count: usize) -> Vec { (0..count) .map(|i| NamedTempFile::new(prefix.to_string() + "_output_" + &i.to_string()).unwrap()) .collect() } fn paths(files: &[NamedTempFile]) -> Vec<&Path> { files.iter().map(NamedTempFile::path).collect() } fn close(files: Vec) { files .into_iter() .try_for_each(NamedTempFile::close) .unwrap(); } fn zsplit() -> Command { let runner = escargot::CargoBuild::new() .bin("zsplit") .release() .run() .unwrap(); Command::from_std(runner.command()) } #[test] fn simple() { let input = NamedTempFile::new("simple_input").unwrap(); let to = 1000; input.write_str(&seq(0, to, 1)).unwrap(); let outputs = outputs("simple", 4); zsplit() .arg(input.path()) .args(&paths(&outputs)) .assert() .success(); for i in 0..outputs.len() { assert_eq!( read_to_string(&outputs[i]).unwrap(), seq(i as isize, to, outputs.len()) ); } input.close().unwrap(); close(outputs); } #[test] fn simple_pipe() { let to = 100_000; let outputs = outputs("simple_pipe", 4); zsplit() .write_stdin(seq(0, to, 1)) .arg("-") .args(&paths(&outputs)) .assert() .success(); for i in 0..outputs.len() { assert_eq!( read_to_string(&outputs[i]).unwrap(), seq(i as isize, to, outputs.len()) ); } close(outputs); } #[test] fn unsymmetric_pipe() { let to = 100_000; let outputs = outputs("unsymmetric_pipe", 4); zsplit() .write_stdin(seq(0, to, 1)) .arg("-") .args(&paths(&outputs)) .args(["-d", "3", "3", "2"]) .assert() .success(); assert_eq!( read_to_string(&outputs[0]).unwrap(), seq_ring(0, to, 9, &[0, 1, 2]) ); assert_eq!( read_to_string(&outputs[1]).unwrap(), seq_ring(0, to, 9, &[3, 4, 5]) ); assert_eq!( read_to_string(&outputs[2]).unwrap(), seq_ring(0, to, 9, &[6, 7]) ); assert_eq!( read_to_string(&outputs[3]).unwrap(), seq_ring(0, to, 9, &[8]) ); close(outputs); } #[test] fn multiple_pipe() { let to = 100_000; let outputs = outputs("multiple_pipe", 4); zsplit() .write_stdin(seq(0, to, 1)) .arg("-") .args(&paths(&outputs)) .arg("--line-factor=2") .assert() .success(); assert_eq!( read_to_string(&outputs[0]).unwrap(), seq_ring(0, to, 8, &[0, 1]) ); assert_eq!( read_to_string(&outputs[1]).unwrap(), seq_ring(0, to, 8, &[2, 3]) ); assert_eq!( read_to_string(&outputs[2]).unwrap(), seq_ring(0, to, 8, &[4, 5]) ); assert_eq!( read_to_string(&outputs[3]).unwrap(), seq_ring(0, to, 8, &[6, 7]) ); close(outputs); } #[test] fn multiple_unsymmetric_pipe() { let to = 100_000; let outputs = outputs("multiple_unsymmetric_pipe", 3); zsplit() .write_stdin(seq(0, to, 1)) .arg("-") .args(&paths(&outputs)) .arg("--line-factor=2") .args(["-d", "1", "3", "2"]) .assert() .success(); assert_eq!( read_to_string(&outputs[0]).unwrap(), seq_ring(0, to, 12, &[0, 1]) ); assert_eq!( read_to_string(&outputs[1]).unwrap(), seq_ring(0, to, 12, &[2, 3, 4, 5, 6, 7]) ); assert_eq!( read_to_string(&outputs[2]).unwrap(), seq_ring(0, to, 12, &[8, 9, 10, 11]) ); close(outputs); } #[test] fn many_outputs() { let to = 100_000; let outputs = outputs("many_outputs", 42); zsplit() .write_stdin(seq(0, to, 1)) .arg("-") .args(&paths(&outputs)) .assert() .success(); for i in 0..outputs.len() { assert_eq!( read_to_string(&outputs[i]).unwrap(), seq(i as isize, to, outputs.len()) ); } close(outputs); } #[test] fn usage_error() { let input = NamedTempFile::new("usage_error_input").unwrap(); let outputs = outputs("usage_error", 2); zsplit() .arg(input.path()) .arg(input.path()) .args(&paths(&outputs)) .assert() .failure() .code(i32::from(sysexits::ExitCode::Usage)); for i in 0..outputs.len() { read_to_string(&outputs[i]).unwrap_err(); } input.close().unwrap(); close(outputs); }