Skip to content

Commit

Permalink
add io tests, move snapshots
Browse files Browse the repository at this point in the history
  • Loading branch information
enricozb committed May 31, 2024
1 parent 137b1f2 commit 8993406
Show file tree
Hide file tree
Showing 9 changed files with 192 additions and 24 deletions.
117 changes: 117 additions & 0 deletions tests/programs/io/read_and_print.hvm
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
@IO_T/Call = (a (b (c (d ((1 (a (b (c (d e))))) e)))))

@IO_T/Done = (a (b ((0 (a (b c))) c)))

@IO_T/MAGIC = (13683217 16719857)

@IO_T/bind = ((@IO_T/bind__C2 a) a)

@IO_T/bind__C0 = (* (a ((a b) b)))

@IO_T/bind__C1 = (* (* (a (b ((c d) (e g))))))
& @IO_T/Call ~ (@IO_T/MAGIC (a (b ((c f) g))))
& @IO_T/bind ~ (d (e f))

@IO_T/bind__C2 = (?((@IO_T/bind__C0 @IO_T/bind__C1) a) a)

@IO_T/wrap = a
& @IO_T/Done ~ (@IO_T/MAGIC a)

@String/Cons = (a (b ((1 (a (b c))) c)))

@String/Nil = ((0 a) a)

@call_io = (a (b c))
& @IO_T/Call ~ (@IO_T/MAGIC (a (b (@call_io__C0 c))))

@call_io__C0 = a
& @IO_T/Done ~ (@IO_T/MAGIC a)

@main = a
& @IO_T/bind ~ (@main__C7 (@main__C6 a))

@main__C0 = i
& @call_io ~ (e ((1 h) i))
& @String/Cons ~ (87 (d e))
& @String/Cons ~ (82 (c d))
& @String/Cons ~ (73 (b c))
& @String/Cons ~ (84 (a b))
& @String/Cons ~ (69 (@String/Nil a))
& @String/Cons ~ (39 (g h))
& @String/Cons ~ (33 (f g))
& @String/Cons ~ (10 (@String/Nil f))

@main__C1 = e
& @String/Cons ~ (87 (d e))
& @String/Cons ~ (82 (c d))
& @String/Cons ~ (73 (b c))
& @String/Cons ~ (84 (a b))
& @String/Cons ~ (69 (@String/Nil a))

@main__C2 = (* a)
& @IO_T/bind ~ (@main__C0 ((* 42) a))

@main__C3 = n
& @call_io ~ (e ((1 m) n))
& @String/Cons ~ (87 (d e))
& @String/Cons ~ (82 (c d))
& @String/Cons ~ (73 (b c))
& @String/Cons ~ (84 (a b))
& @String/Cons ~ (69 (@String/Nil a))
& @String/Cons ~ (72 (l m))
& @String/Cons ~ (101 (k l))
& @String/Cons ~ (108 (j k))
& @String/Cons ~ (108 (i j))
& @String/Cons ~ (111 (h i))
& @String/Cons ~ (44 (g h))
& @String/Cons ~ (32 (f g))
& @String/Cons ~ (39 (@String/Nil f))

@main__C4 = (a d)
& @IO_T/bind ~ (@main__C3 ((* c) d))
& @IO_T/bind ~ (b (@main__C2 c))
& @call_io ~ (@main__C1 ((1 a) b))

@main__C5 = j
& @call_io ~ (i (0 j))
& @String/Cons ~ (82 (h i))
& @String/Cons ~ (69 (g h))
& @String/Cons ~ (65 (f g))
& @String/Cons ~ (68 (e f))
& @String/Cons ~ (95 (d e))
& @String/Cons ~ (76 (c d))
& @String/Cons ~ (73 (b c))
& @String/Cons ~ (78 (a b))
& @String/Cons ~ (69 (@String/Nil a))

@main__C6 = (* a)
& @IO_T/bind ~ (@main__C5 (@main__C4 a))

@main__C7 = y
& @call_io ~ (e ((1 x) y))
& @String/Cons ~ (87 (d e))
& @String/Cons ~ (82 (c d))
& @String/Cons ~ (73 (b c))
& @String/Cons ~ (84 (a b))
& @String/Cons ~ (69 (@String/Nil a))
& @String/Cons ~ (87 (w x))
& @String/Cons ~ (104 (v w))
& @String/Cons ~ (97 (u v))
& @String/Cons ~ (116 (t u))
& @String/Cons ~ (32 (s t))
& @String/Cons ~ (105 (r s))
& @String/Cons ~ (115 (q r))
& @String/Cons ~ (32 (p q))
& @String/Cons ~ (121 (o p))
& @String/Cons ~ (111 (n o))
& @String/Cons ~ (117 (m n))
& @String/Cons ~ (114 (l m))
& @String/Cons ~ (32 (k l))
& @String/Cons ~ (110 (j k))
& @String/Cons ~ (97 (i j))
& @String/Cons ~ (109 (h i))
& @String/Cons ~ (101 (g h))
& @String/Cons ~ (63 (f g))
& @String/Cons ~ (10 (@String/Nil f))

@test-io = 1
File renamed without changes.
File renamed without changes.
File renamed without changes.
91 changes: 67 additions & 24 deletions tests/run.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
use std::{
collections::HashMap,
error::Error,
ffi::OsStr,
fs,
io::{Read, Write},
path::{Path, PathBuf},
process::{Command, Stdio},
};

use hvm::ast::Tree;
use insta::assert_snapshot;
use TSPL::Parser;
use std::{
collections::HashMap, error::Error, ffi::OsStr, fs, io::Read, path::{Path, PathBuf}, process::{Command, Stdio}
};

#[test]
fn test_run_programs() {
Expand All @@ -25,33 +31,65 @@ fn manifest_relative(sub: &str) -> PathBuf {
}

fn test_file(path: &Path) {
if fs::read_to_string(path).unwrap().contains("@test-skip = 1") {
let contents = fs::read_to_string(path).unwrap();
if contents.contains("@test-skip = 1") {
println!("skipping {path:?}");
return;
}
if contents.contains("@test-io = 1") {
test_io_file(path);
return;
}

println!("testing {path:?}...");
let rust_output = execute_hvm(&["run".as_ref(), path.as_os_str()]).unwrap();
let rust_output = execute_hvm(&["run".as_ref(), path.as_os_str()], false).unwrap();
assert_snapshot!(rust_output);

println!(" testing {path:?}, C...");
let c_output = execute_hvm(&["run-c".as_ref(), path.as_os_str()]).unwrap();
let c_output = execute_hvm(&["run-c".as_ref(), path.as_os_str()], false).unwrap();
assert_eq!(c_output, rust_output, "{path:?}: C output does not match rust output");

if cfg!(feature = "cuda") {
println!(" testing {path:?}, CUDA...");
let cuda_output = execute_hvm(&["run-cu".as_ref(), path.as_os_str()]).unwrap();
assert_eq!(cuda_output, rust_output, "{path:?}: CUDA output does not match rust output");
let cuda_output = execute_hvm(&["run-cu".as_ref(), path.as_os_str()], false).unwrap();
assert_eq!(
cuda_output, rust_output,
"{path:?}: CUDA output does not match rust output"
);
}
}

fn test_io_file(path: &Path) {
println!(" testing (io) {path:?}, C...");
let c_output = execute_hvm(&["run-c".as_ref(), path.as_os_str()], true).unwrap();
assert_snapshot!(c_output);

if cfg!(feature = "cuda") {
println!(" testing (io) {path:?}, CUDA...");
let cuda_output = execute_hvm(&["run-cu".as_ref(), path.as_os_str()], true).unwrap();
assert_eq!(cuda_output, c_output, "{path:?}: CUDA output does not match C output");
}
}

fn execute_hvm(args: &[&OsStr]) -> Result<String, Box<dyn Error>> {
fn execute_hvm(args: &[&OsStr], send_io: bool) -> Result<String, Box<dyn Error>> {
// Spawn the command
let mut child =
Command::new(env!("CARGO_BIN_EXE_hvm")).args(args).stdout(Stdio::piped()).stderr(Stdio::piped()).spawn()?;
let mut child = Command::new(env!("CARGO_BIN_EXE_hvm"))
.args(args)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;

// Capture the output of the command
let mut stdout = child.stdout.take().ok_or("Couldn't capture stdout!")?;
let mut stderr = child.stderr.take().ok_or("Couldn't capture stderr!")?;

// Wait for the command to finish and get the exit status
if send_io {
let mut stdin = child.stdin.take().ok_or("Couldn't capture stdin!")?;
stdin.write_all(b"io from the tests\n")?;
drop(stdin);
}
let status = child.wait()?;

// Read the output
Expand All @@ -62,30 +100,35 @@ fn execute_hvm(args: &[&OsStr]) -> Result<String, Box<dyn Error>> {
Ok(if !status.success() {
format!("exited with code {status}:\n{output}")
} else {
parse_output(&output).unwrap_or_else(|err| {
panic!("error parsing output:\n{err}\n\n{output}")
})
parse_output(&output).unwrap_or_else(|err| panic!("error parsing output:\n{err}\n\n{output}"))
})
}

fn parse_output(output: &str) -> Result<String, String> {
let mut parser = hvm::ast::CoreParser::new(output);
parser.consume("Result:")?;
let mut tree = parser.parse_tree()?;
normalize_vars(&mut tree, &mut HashMap::new());
// TODO: include iteration count in snapshot once consistent
// parser.consume("- ITRS:")?;
// let itrs = parser.parse_u64()?;
// Ok(format!("Result: {}\n- ITRS: {}", tree.show(), itrs))
Ok(format!("Result: {}", tree.show()))
let mut lines = Vec::new();

for line in output.lines() {
if line.starts_with("Result:") {
let mut parser = hvm::ast::CoreParser::new(line);
parser.consume("Result:")?;
let mut tree = parser.parse_tree()?;
normalize_vars(&mut tree, &mut HashMap::new());
lines.push(format!("Result: {}", tree.show()));
} else if !line.starts_with("- ITRS:") && !line.starts_with("- TIME:") && !line.starts_with("- MIPS:") {
// TODO: include iteration count in snapshot once consistent
lines.push(line.to_string())
}
}

Ok(lines.join("\n"))
}

fn normalize_vars(tree: &mut Tree, vars: &mut HashMap<String, usize>) {
match tree {
Tree::Var { nam } => {
let next_var = vars.len();
*nam = format!("x{}", vars.entry(std::mem::take(nam)).or_insert(next_var));
},
}
Tree::Era | Tree::Ref { .. } | Tree::Num { .. } => {}
Tree::Con { fst, snd } | Tree::Dup { fst, snd } | Tree::Opr { fst, snd } | Tree::Swi { fst, snd } => {
normalize_vars(fst, vars);
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
8 changes: 8 additions & 0 deletions tests/snapshots/run__io_file@io__read_and_print.hvm.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
source: tests/run.rs
expression: c_output
input_file: tests/programs/io/read_and_print.hvm
---
What is your name?
Hello, 'io from the tests'!
Result: 42

0 comments on commit 8993406

Please sign in to comment.