summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rust/sample/test01/input1
-rw-r--r--rust/sample/test01/output1
-rw-r--r--rust/src/io.rs26
-rw-r--r--rust/src/main.rs8
-rw-r--r--rust/src/tester.rs53
-rw-r--r--rust/tests/interpret_test.rs10
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());
+}