diff options
| -rw-r--r-- | rust/sample/test01/input | 1 | ||||
| -rw-r--r-- | rust/sample/test01/output | 1 | ||||
| -rw-r--r-- | rust/src/io.rs | 26 | ||||
| -rw-r--r-- | rust/src/main.rs | 8 | ||||
| -rw-r--r-- | rust/src/tester.rs | 53 | ||||
| -rw-r--r-- | rust/tests/interpret_test.rs | 10 |
6 files changed, 84 insertions, 15 deletions
diff --git a/rust/sample/test01/input b/rust/sample/test01/input new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/rust/sample/test01/input @@ -0,0 +1 @@ +12 diff --git a/rust/sample/test01/output b/rust/sample/test01/output new file mode 100644 index 0000000..48082f7 --- /dev/null +++ b/rust/sample/test01/output @@ -0,0 +1 @@ +12 diff --git a/rust/src/io.rs b/rust/src/io.rs index 33d8c4e..435f32f 100644 --- a/rust/src/io.rs +++ b/rust/src/io.rs @@ -19,6 +19,32 @@ pub fn eval_file(file_name: &str) -> String { .join(" ") } +pub fn batch_eval<I: Read, O: Write>(inp: &mut I, outp: &mut O) { + let mut env = Environment::new(); + let mut reader = BufReader::new(inp); + loop { + let mut input = String::new(); + outp.flush().unwrap(); + match reader.read_line(&mut input) { + Ok(0) => break, + Ok(_) => (), + Err(e) => { + writeln!(outp, "{}", e).unwrap(); + break; + } + } + let values = parse(&input); + let results = values + .iter() + .map(|v| eval(v, &mut env)) + .collect::<Vec<Value>>(); + for result in results { + writeln!(outp, "{}", result).unwrap(); + outp.flush().unwrap(); + } + } +} + pub fn repl<I: Read, O: Write>(inp: &mut I, outp: &mut O) { let mut env = Environment::new(); let mut reader = BufReader::new(inp); diff --git a/rust/src/main.rs b/rust/src/main.rs index b0e8ed9..8d52c46 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -1,16 +1,18 @@ use std::{ env::args, - io::{stdin, stdout}, + io::{stdin, stdout, IsTerminal}, }; -use lambda::io::{eval_file, repl}; +use lambda::io::{batch_eval, eval_file, repl}; fn main() { if args().count() > 1 { for file in args().skip(1) { println!("{}", eval_file(&file)); } - } else { + } else if stdin().is_terminal() { repl(&mut stdin(), &mut stdout()); + } else { + batch_eval(&mut stdin(), &mut stdout()); } } diff --git a/rust/src/tester.rs b/rust/src/tester.rs index 15ca468..019989b 100644 --- a/rust/src/tester.rs +++ b/rust/src/tester.rs @@ -1,15 +1,21 @@ use std::{ - fs, - path::{Path, PathBuf}, + fs::{self, read_to_string, File}, + path::PathBuf, + process::{Command, Stdio}, + time::Instant, }; pub fn main() { - let args: Vec<String> = std::env::args().collect(); + let mut args: Vec<String> = std::env::args().collect(); + // name of the process to run + let proc = args.remove(1); if args.len() > 1 { let run = traverse(&args) - .and_then(|paths| run_test(&paths)) + .and_then(|paths| run_test(&proc, &paths)) .expect("Failed to traverse directory"); println!("{:?}", run) + } else { + println!("Usage: tester <process> <directory>+"); } } @@ -29,20 +35,26 @@ fn traverse(args: &[String]) -> Result<Vec<PathBuf>, String> { } #[derive(Debug)] -struct TestRun { +pub enum TestResult { + TestSucceeded, + TestFailed(String, String), +} + +#[derive(Debug)] +pub struct TestRun { file: String, - test_result: bool, - duration: u64, + test_result: TestResult, + duration: u128, } -fn run_test(files: &Vec<PathBuf>) -> Result<Vec<TestRun>, String> { +fn run_test(proc: &str, files: &Vec<PathBuf>) -> Result<Vec<TestRun>, String> { let mut result = Vec::new(); for file in files { let mut inp = file.clone(); let mut outp = file.clone(); inp.push("input"); outp.push("output"); - let (test_result, duration) = run_test_case(&inp, &outp); + let (test_result, duration) = run_test_case(proc, &inp, &outp)?; result.push(TestRun { file: inp.as_path().to_str().unwrap().to_string(), test_result, @@ -52,6 +64,25 @@ fn run_test(files: &Vec<PathBuf>) -> Result<Vec<TestRun>, String> { Ok(result) } -fn run_test_case(inp: &std::path::PathBuf, outp: &std::path::PathBuf) -> (bool, u64) { - (true, 1) +fn run_test_case( + proc: &str, + inp: &std::path::PathBuf, + outp: &std::path::PathBuf, +) -> Result<(TestResult, u128), String> { + let input = File::open(inp).map_err(|e| e.to_string())?; + let expected = read_to_string(outp).map_err(|e| e.to_string())?; + let start = Instant::now(); + + let actual = Command::new(proc) + .stdin(Stdio::from(input)) + .output() + .map_err(|e| e.to_string())?; + + let duration = (Instant::now() - start).as_millis(); + if expected.as_bytes() == actual.stdout { + Ok((TestResult::TestSucceeded, duration)) + } else { + let actual_string = String::from_utf8(actual.stdout).map_err(|e| e.to_string())?; + Ok((TestResult::TestFailed(expected, actual_string), duration)) + } } diff --git a/rust/tests/interpret_test.rs b/rust/tests/interpret_test.rs index 0ca3356..16e7fb7 100644 --- a/rust/tests/interpret_test.rs +++ b/rust/tests/interpret_test.rs @@ -1,4 +1,4 @@ -use lambda::io::{eval_file, repl}; +use lambda::io::{batch_eval, eval_file, repl}; #[test] fn interpreter_can_read_and_interpret_file() { @@ -15,3 +15,11 @@ fn repl_can_read_and_interpret_input() { repl(&mut input.as_bytes(), &mut output); assert_eq!("> true\n> 12\n> ", String::from_utf8(output).unwrap()); } + +#[test] +fn repl_can_read_and_interpret_input_in_batch_mode() { + let input = "(def id (lam x x))\n(id 12)"; + let mut output = Vec::new(); + batch_eval(&mut input.as_bytes(), &mut output); + assert_eq!("true\n12\n", String::from_utf8(output).unwrap()); +} |
