Adds pass command to clif-util. (#487)

* Adds pass command to clif-util.
This commit is contained in:
Caroline Cullen
2018-09-04 16:31:24 -07:00
committed by Dan Gohman
parent 17bb62c16c
commit 59b83912ba
8 changed files with 207 additions and 30 deletions

View File

@@ -131,17 +131,18 @@ fn worker_thread(
// The receiver should always be present for this as long as we have jobs.
replies.send(Reply::Starting { jobid, thread_num }).unwrap();
let result = catch_unwind(|| runone::run(path.as_path())).unwrap_or_else(|e| {
// The test panicked, leaving us a `Box<Any>`.
// Panics are usually strings.
if let Some(msg) = e.downcast_ref::<String>() {
Err(format!("panicked in worker #{}: {}", thread_num, msg))
} else if let Some(msg) = e.downcast_ref::<&'static str>() {
Err(format!("panicked in worker #{}: {}", thread_num, msg))
} else {
Err(format!("panicked in worker #{}", thread_num))
}
});
let result = catch_unwind(|| runone::run(path.as_path(), None, None))
.unwrap_or_else(|e| {
// The test panicked, leaving us a `Box<Any>`.
// Panics are usually strings.
if let Some(msg) = e.downcast_ref::<String>() {
Err(format!("panicked in worker #{}: {}", thread_num, msg))
} else if let Some(msg) = e.downcast_ref::<&'static str>() {
Err(format!("panicked in worker #{}: {}", thread_num, msg))
} else {
Err(format!("panicked in worker #{}", thread_num))
}
});
if let Err(ref msg) = result {
error!("FAIL: {}", msg);

View File

@@ -79,6 +79,24 @@ pub fn run(verbose: bool, files: &[String]) -> TestResult {
runner.run()
}
/// Used for 'pass' subcommand.
/// Commands are interpreted as test and executed.
///
/// Directories are scanned recursively for test cases ending in `.clif`.
///
pub fn run_passes(verbose: bool, passes: &[String], target: &str, file: &String) -> TestResult {
let mut runner = TestRunner::new(verbose);
let path = Path::new(file);
if path.is_file() {
runner.push_test(path);
} else {
runner.push_dir(path);
}
runner.run_passes(passes, target)
}
/// Create a new subcommand trait object to match `parsed.command`.
///
/// This function knows how to create all of the possible `test <foo>` commands that can appear in

View File

@@ -30,6 +30,12 @@ enum State {
Done(TestResult),
}
#[derive(PartialEq, Eq, Debug)]
pub enum IsPass {
Pass,
NotPass,
}
impl QueueEntry {
pub fn path(&self) -> &Path {
self.path.as_path()
@@ -118,7 +124,7 @@ impl TestRunner {
/// Scan any directories pushed so far.
/// Push any potential test cases found.
pub fn scan_dirs(&mut self) {
pub fn scan_dirs(&mut self, pass_status: IsPass) {
// This recursive search tries to minimize statting in a directory hierarchy containing
// mostly test cases.
//
@@ -164,8 +170,12 @@ impl TestRunner {
}
}
}
// Get the new jobs running before moving on to the next directory.
self.schedule_jobs();
if pass_status == IsPass::Pass {
continue;
} else {
// Get the new jobs running before moving on to the next directory.
self.schedule_jobs();
}
}
}
@@ -203,7 +213,7 @@ impl TestRunner {
} else {
// Run test synchronously.
self.tests[jobid].state = State::Running;
let result = runone::run(self.tests[jobid].path());
let result = runone::run(self.tests[jobid].path(), None, None);
self.finish_job(jobid, result);
}
self.new_tests = jobid + 1;
@@ -215,6 +225,20 @@ impl TestRunner {
}
}
/// Schedule any new job to run for the pass command.
fn schedule_pass_job(&mut self, passes: &[String], target: &str) {
self.tests[0].state = State::Running;
let result: Result<time::Duration, String>;
let specified_target = match target {
"" => None,
targ => Some(targ),
};
result = runone::run(self.tests[0].path(), Some(passes), specified_target);
self.finish_job(0, result);
}
/// Report the end of a job.
fn finish_job(&mut self, jobid: usize, result: TestResult) {
assert_eq!(self.tests[jobid].state, State::Running);
@@ -331,10 +355,26 @@ impl TestRunner {
/// Scan pushed directories for tests and run them.
pub fn run(&mut self) -> TestResult {
let started = time::Instant::now();
self.scan_dirs();
self.scan_dirs(IsPass::NotPass);
self.schedule_jobs();
self.drain_threads();
self.report_slow_tests();
self.drain_threads();
println!("{} tests", self.tests.len());
match self.errors {
0 => Ok(started.elapsed()),
1 => Err("1 failure".to_string()),
n => Err(format!("{} failures", n)),
}
}
/// Scan pushed directories for tests and run specified passes from commandline on them.
pub fn run_passes(&mut self, passes: &[String], target: &str) -> TestResult {
let started = time::Instant::now();
self.scan_dirs(IsPass::Pass);
self.schedule_pass_job(passes, target);
self.report_slow_tests();
println!("{} tests", self.tests.len());
match self.errors {
0 => Ok(started.elapsed()),

View File

@@ -27,12 +27,12 @@ fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
/// 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 {
pub fn run(path: &Path, passes: Option<&[String]>, target: Option<&str>) -> TestResult {
let _tt = timing::process_file();
info!("---\nFile: {}", path.to_string_lossy());
let started = time::Instant::now();
let buffer = read_to_string(path).map_err(|e| e.to_string())?;
let testfile = parse_test(&buffer).map_err(|e| e.to_string())?;
let testfile = parse_test(&buffer, passes, target).map_err(|e| e.to_string())?;
if testfile.functions.is_empty() {
return Err("no functions found".to_string());
}