Move the code to run test into its own module.
Loading a file and running the test in it can be separated from the mechanics of running multiple tests and scanning directories for test files.
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
//! available test commands.
|
//! available test commands.
|
||||||
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::time;
|
||||||
use cton_reader::TestCommand;
|
use cton_reader::TestCommand;
|
||||||
use CommandResult;
|
use CommandResult;
|
||||||
use cat;
|
use cat;
|
||||||
@@ -12,9 +13,13 @@ use filetest::runner::TestRunner;
|
|||||||
|
|
||||||
pub mod subtest;
|
pub mod subtest;
|
||||||
mod runner;
|
mod runner;
|
||||||
|
mod runone;
|
||||||
mod domtree;
|
mod domtree;
|
||||||
mod verifier;
|
mod verifier;
|
||||||
|
|
||||||
|
/// The result of running the test in a file.
|
||||||
|
pub type TestResult = Result<time::Duration, String>;
|
||||||
|
|
||||||
/// Main entry point for `cton-util test`.
|
/// Main entry point for `cton-util test`.
|
||||||
///
|
///
|
||||||
/// Take a list of filenames which can be either `.cton` files or directories.
|
/// Take a list of filenames which can be either `.cton` files or directories.
|
||||||
|
|||||||
@@ -3,22 +3,13 @@
|
|||||||
//! This module implements the `TestRunner` struct which manages executing tests as well as
|
//! This module implements the `TestRunner` struct which manages executing tests as well as
|
||||||
//! scanning directories for tests.
|
//! scanning directories for tests.
|
||||||
|
|
||||||
use std::ffi::OsStr;
|
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
use std::ffi::OsStr;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::borrow::{Borrow, Cow};
|
|
||||||
use std::panic::catch_unwind;
|
use std::panic::catch_unwind;
|
||||||
use std::time;
|
use std::path::{Path, PathBuf};
|
||||||
|
use filetest::{TestResult, runone};
|
||||||
use CommandResult;
|
use CommandResult;
|
||||||
use utils::read_to_string;
|
|
||||||
use cton_reader::parse_test;
|
|
||||||
use cretonne::ir::Function;
|
|
||||||
use cretonne::verify_function;
|
|
||||||
use filetest::new_subtest;
|
|
||||||
use filetest::subtest::{self, SubTest, Context};
|
|
||||||
|
|
||||||
type TestResult = Result<time::Duration, String>;
|
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Debug)]
|
#[derive(PartialEq, Eq, Debug)]
|
||||||
enum QueueEntry {
|
enum QueueEntry {
|
||||||
@@ -204,66 +195,9 @@ impl Job {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(&self) -> TestResult {
|
pub fn run(&self) -> TestResult {
|
||||||
match catch_unwind(|| self.run_or_panic()) {
|
match catch_unwind(|| runone::run(self.path.as_path())) {
|
||||||
Err(msg) => Err(format!("panic: {:?}", msg)),
|
Err(msg) => Err(format!("panic: {:?}", msg)),
|
||||||
Ok(result) => result,
|
Ok(result) => result,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn run_or_panic(&self) -> TestResult {
|
|
||||||
let started = time::Instant::now();
|
|
||||||
let buffer = try!(read_to_string(&self.path).map_err(|e| e.to_string()));
|
|
||||||
let testfile = try!(parse_test(&buffer).map_err(|e| e.to_string()));
|
|
||||||
if testfile.functions.is_empty() {
|
|
||||||
return Err("no functions found".to_string());
|
|
||||||
}
|
|
||||||
// Parse the test commands.
|
|
||||||
let mut tests =
|
|
||||||
try!(testfile.commands.iter().map(new_subtest).collect::<subtest::Result<Vec<_>>>());
|
|
||||||
|
|
||||||
// Sort the tests so the mutators are at the end, and those that
|
|
||||||
// don't need the verifier are at the front
|
|
||||||
tests.sort_by_key(|st| (st.is_mutating(), st.needs_verifier()));
|
|
||||||
|
|
||||||
// Isolate the last test in the hope that this is the only mutating test.
|
|
||||||
// If so, we can completely avoid cloning functions.
|
|
||||||
let last_test = match tests.pop() {
|
|
||||||
None => return Err("no test commands found".to_string()),
|
|
||||||
Some(t) => t,
|
|
||||||
};
|
|
||||||
|
|
||||||
for (func, details) in testfile.functions {
|
|
||||||
let mut context = subtest::Context {
|
|
||||||
details: details,
|
|
||||||
verified: false,
|
|
||||||
};
|
|
||||||
|
|
||||||
for test in &tests {
|
|
||||||
try!(self.run_one_test(test.borrow(), Cow::Borrowed(&func), &mut context));
|
|
||||||
}
|
|
||||||
// Run the last test with an owned function which means it won't need to clone it
|
|
||||||
// before mutating.
|
|
||||||
try!(self.run_one_test(last_test.borrow(), Cow::Owned(func), &mut context));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// TODO: Actually run the tests.
|
|
||||||
Ok(started.elapsed())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn run_one_test(&self,
|
|
||||||
test: &SubTest,
|
|
||||||
func: Cow<Function>,
|
|
||||||
context: &mut Context)
|
|
||||||
-> subtest::Result<()> {
|
|
||||||
let name = format!("{}({})", test.name(), func.name);
|
|
||||||
|
|
||||||
// Should we run the verifier before this test?
|
|
||||||
if !context.verified && test.needs_verifier() {
|
|
||||||
try!(verify_function(&func).map_err(|e| e.to_string()));
|
|
||||||
context.verified = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
test.run(func, context).map_err(|e| format!("{}: {}", name, e))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
66
src/tools/filetest/runone.rs
Normal file
66
src/tools/filetest/runone.rs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
//! Run the tests in a single test file.
|
||||||
|
|
||||||
|
use std::borrow::{Borrow, Cow};
|
||||||
|
use std::path::Path;
|
||||||
|
use std::time;
|
||||||
|
use cretonne::ir::Function;
|
||||||
|
use cretonne::verify_function;
|
||||||
|
use cton_reader::parse_test;
|
||||||
|
use utils::read_to_string;
|
||||||
|
use filetest::{TestResult, new_subtest};
|
||||||
|
use filetest::subtest::{SubTest, Context, Result};
|
||||||
|
|
||||||
|
/// Load `path` and run the test in it.
|
||||||
|
///
|
||||||
|
/// If running this test causes a panic, it will propagate as normal.
|
||||||
|
pub fn run(path: &Path) -> TestResult {
|
||||||
|
let started = time::Instant::now();
|
||||||
|
let buffer = try!(read_to_string(path).map_err(|e| e.to_string()));
|
||||||
|
let testfile = try!(parse_test(&buffer).map_err(|e| e.to_string()));
|
||||||
|
if testfile.functions.is_empty() {
|
||||||
|
return Err("no functions found".to_string());
|
||||||
|
}
|
||||||
|
// Parse the test commands.
|
||||||
|
let mut tests = try!(testfile.commands.iter().map(new_subtest).collect::<Result<Vec<_>>>());
|
||||||
|
|
||||||
|
// Sort the tests so the mutators are at the end, and those that don't need the verifier are at
|
||||||
|
// the front.
|
||||||
|
tests.sort_by_key(|st| (st.is_mutating(), st.needs_verifier()));
|
||||||
|
|
||||||
|
// Isolate the last test in the hope that this is the only mutating test.
|
||||||
|
// If so, we can completely avoid cloning functions.
|
||||||
|
let last_test = match tests.pop() {
|
||||||
|
None => return Err("no test commands found".to_string()),
|
||||||
|
Some(t) => t,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (func, details) in testfile.functions {
|
||||||
|
let mut context = Context {
|
||||||
|
details: details,
|
||||||
|
verified: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
for test in &tests {
|
||||||
|
try!(run_one_test(test.borrow(), Cow::Borrowed(&func), &mut context));
|
||||||
|
}
|
||||||
|
// Run the last test with an owned function which means it won't need to clone it before
|
||||||
|
// mutating.
|
||||||
|
try!(run_one_test(last_test.borrow(), Cow::Owned(func), &mut context));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// TODO: Actually run the tests.
|
||||||
|
Ok(started.elapsed())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_one_test(test: &SubTest, func: Cow<Function>, context: &mut Context) -> Result<()> {
|
||||||
|
let name = format!("{}({})", test.name(), func.name);
|
||||||
|
|
||||||
|
// Should we run the verifier before this test?
|
||||||
|
if !context.verified && test.needs_verifier() {
|
||||||
|
try!(verify_function(&func).map_err(|e| e.to_string()));
|
||||||
|
context.verified = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
test.run(func, context).map_err(|e| format!("{}: {}", name, e))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user