Browse Source

add expectation tests for nondeterministic output

Getty Ritter 2 years ago
parent
commit
7f3d8ff8ce
8 changed files with 51 additions and 13 deletions
  1. 27 9
      build.rs
  2. 10 4
      src/interp.rs
  3. 3 0
      tests/fixed.matzo
  4. 4 0
      tests/fixed.output
  5. 1 0
      tests/hello.matzo
  6. 1 0
      tests/hello.output
  7. 1 0
      tests/simple.matzo
  8. 4 0
      tests/simple.output

+ 27 - 9
build.rs

@@ -30,21 +30,39 @@ fn assert_eq(x: &str, y: &str) {
 const TEST_TEMPLATE: &str = "
 #[test]
 fn test_%PREFIX%() {
-  let mut ast = crate::ast::ASTArena::new();
+  let state = crate::interp::State::new();
   let source = include_str!(\"%ROOT%/tests/%PREFIX%.matzo\");
   let lexer = lexer::tokens(source);
-  let stmts = grammar::StmtsParser::new().parse(&mut ast, lexer);
+  let stmts = grammar::StmtsParser::new().parse(&mut state.get_ast().borrow_mut(), lexer);
   assert!(stmts.is_ok());
   let stmts = stmts.unwrap();
 
-  let mut buf = Vec::new();
-  for s in stmts {
-    writeln!(buf, \"{:?}\", s.show(&ast)).unwrap();
+  if let Ok(expected) = std::fs::read_to_string(\"%ROOT%/tests/%PREFIX%.parsed\") {
+    let mut buf = Vec::new();
+    for s in stmts.iter() {
+      writeln!(buf, \"{:?}\", s.show(&state.get_ast().borrow())).unwrap();
+    }
+    assert_eq(
+      std::str::from_utf8(&buf).unwrap().trim(),
+      expected.trim(),
+    );
+  }
+
+  if let Ok(expected) = std::fs::read_to_string(\"%ROOT%/tests/%PREFIX%.output\") {
+    let possibilities = expected.lines().collect::<Vec<&str>>();
+    let mut buf = Vec::new();
+    for stmt in stmts {
+      state.execute(&stmt, &mut buf).unwrap();
+    }
+
+    let out = std::str::from_utf8(&buf).unwrap();
+    if !possibilities.contains(&out.trim()) {
+      panic!(\"Got output\\n  `{}`\\nbut expected one of the following:\\n{}\\n\",
+        &out.trim(),
+        possibilities.iter().map(|x| format!(\"  `{}`\\n\", x)).collect::<Vec<String>>().join(\", \"),
+      );
+    }
   }
-  assert_eq(
-    std::str::from_utf8(&buf).unwrap().trim(),
-    include_str!(\"%ROOT%/tests/%PREFIX%.parsed\").trim(),
-  );
 }
 ";
 

+ 10 - 4
src/interp.rs

@@ -4,6 +4,7 @@ use std::cell::RefCell;
 use std::collections::HashMap;
 use std::fmt;
 use std::rc::Rc;
+use std::io;
 
 macro_rules! bail {
     ($fmt:expr) => { return Err(Error { message: format!($fmt), }) };
@@ -257,6 +258,10 @@ impl State {
         s
     }
 
+    pub fn get_ast(&self) -> &RefCell<ASTArena> {
+        &self.ast
+    }
+
     fn lookup(&self, env: &Env, name: Name) -> Result<Thunk, Error> {
         if let Some(env) = env {
             if let Some(ne) = env.vars.get(&name) {
@@ -275,8 +280,9 @@ impl State {
     pub fn run(&self, src: &str) -> Result<(), Error> {
         let lexed = crate::lexer::tokens(src);
         let stmts = self.parser.parse(&mut self.ast.borrow_mut(), lexed)?;
+        let mut stdout = io::stdout();
         for stmt in stmts {
-            self.execute(&stmt)?;
+            self.execute(&stmt, &mut stdout)?;
         }
         Ok(())
     }
@@ -300,7 +306,7 @@ impl State {
             }
         };
         for stmt in stmts {
-            self.execute(&stmt)?;
+            self.execute(&stmt, io::stdout())?;
         }
         Ok(())
     }
@@ -318,12 +324,12 @@ impl State {
         possibilities
     }
 
-    pub fn execute(&self, stmt: &Stmt) -> Result<(), Error> {
+    pub fn execute(&self, stmt: &Stmt, mut output: impl io::Write) -> Result<(), Error> {
         match stmt {
             Stmt::Puts(expr) => {
                 let val = self.eval(*expr, &None)?;
                 let val = self.force(val)?;
-                println!("{}", val.to_string());
+                writeln!(output, "{}", val.to_string()).unwrap();
             }
 
             Stmt::Fix(name) => {

+ 3 - 0
tests/fixed.matzo

@@ -0,0 +1,3 @@
+fix c ::= p b;
+fix v ::= a u;
+puts c v c v;

+ 4 - 0
tests/fixed.output

@@ -0,0 +1,4 @@
+papa
+pupu
+baba
+bubu

+ 1 - 0
tests/hello.matzo

@@ -0,0 +1 @@
+puts "Hello, world!";

+ 1 - 0
tests/hello.output

@@ -0,0 +1 @@
+Hello, world!

+ 1 - 0
tests/simple.matzo

@@ -0,0 +1 @@
+puts ("p" | "b") ("a" | "u");

+ 4 - 0
tests/simple.output

@@ -0,0 +1,4 @@
+pa
+pu
+ba
+bu