diff options
Diffstat (limited to 'vendor/ui_test/src')
-rw-r--r-- | vendor/ui_test/src/config.rs | 9 | ||||
-rw-r--r-- | vendor/ui_test/src/lib.rs | 152 | ||||
-rw-r--r-- | vendor/ui_test/src/parser.rs | 37 |
3 files changed, 123 insertions, 75 deletions
diff --git a/vendor/ui_test/src/config.rs b/vendor/ui_test/src/config.rs index 6f24cce90..8d92fe8d8 100644 --- a/vendor/ui_test/src/config.rs +++ b/vendor/ui_test/src/config.rs @@ -82,7 +82,10 @@ impl Config { dependencies_crate_manifest_path: None, dependency_builder: CommandBuilder::cargo(), num_test_threads: std::thread::available_parallelism().unwrap(), - out_dir: std::env::current_dir().unwrap().join("target/ui"), + out_dir: std::env::var_os("CARGO_TARGET_DIR") + .map(PathBuf::from) + .unwrap_or_else(|| std::env::current_dir().unwrap().join("target")) + .join("ui"), edition: Some("2021".into()), } } @@ -128,7 +131,9 @@ impl Config { .push((Regex::new(pattern).unwrap().into(), replacement.as_ref())); } - pub(crate) fn build_dependencies_and_link_them(&mut self) -> Result<()> { + /// Compile dependencies and make sure `Config::program` contains the right flags + /// to find the dependencies. + pub fn build_dependencies_and_link_them(&mut self) -> Result<()> { let dependencies = build_dependencies(self)?; for (name, artifacts) in dependencies.dependencies { for dependency in artifacts { diff --git a/vendor/ui_test/src/lib.rs b/vendor/ui_test/src/lib.rs index 7837d0e62..1420e2881 100644 --- a/vendor/ui_test/src/lib.rs +++ b/vendor/ui_test/src/lib.rs @@ -11,7 +11,7 @@ use bstr::ByteSlice; pub use color_eyre; use color_eyre::eyre::{eyre, Result}; -use crossbeam_channel::unbounded; +use crossbeam_channel::{unbounded, Receiver, Sender}; use parser::{ErrorMatch, Revisioned}; use regex::bytes::Regex; use rustc_stderr::{Diagnostics, Level, Message}; @@ -179,15 +179,11 @@ pub fn run_tests_generic( config.build_dependencies_and_link_them()?; - // A channel for files to process - let (submit, receive) = unbounded(); - let mut results = vec![]; - thread::scope(|s| -> Result<()> { - // Create a thread that is in charge of walking the directory and submitting jobs. - // It closes the channel when it is done. - s.spawn(|| { + run_and_collect( + config.num_test_threads.get(), + |submit| { let mut todo = VecDeque::new(); todo.push_back(config.root_dir.clone()); while let Some(path) = todo.pop_front() { @@ -210,73 +206,51 @@ pub fn run_tests_generic( submit.send(path).unwrap(); } } - // There will be no more jobs. This signals the workers to quit. - // (This also ensures `submit` is moved into this closure.) - drop(submit); - }); - - // A channel for the messages emitted by the individual test threads. - // Used to produce live updates while running the tests. - let (finished_files_sender, finished_files_recv) = unbounded::<TestRun>(); - - s.spawn(|| { + }, + |receive, finished_files_sender| -> Result<()> { + for path in receive { + let maybe_config; + let config = match per_file_config(&config, &path) { + None => &config, + Some(config) => { + maybe_config = config; + &maybe_config + } + }; + let result = match std::panic::catch_unwind(|| parse_and_test_file(&path, config)) { + Ok(res) => res, + Err(err) => { + finished_files_sender.send(TestRun { + result: TestResult::Errored { + command: Command::new("<unknown>"), + errors: vec![Error::Bug( + *Box::<dyn std::any::Any + Send + 'static>::downcast::<String>( + err, + ) + .unwrap(), + )], + stderr: vec![], + }, + path, + revision: String::new(), + })?; + continue; + } + }; + for result in result { + finished_files_sender.send(result)?; + } + } + Ok(()) + }, + |finished_files_recv| { for run in finished_files_recv { status_emitter.test_result(&run.path, &run.revision, &run.result); results.push(run); } - }); - - let mut threads = vec![]; - - // Create N worker threads that receive files to test. - for _ in 0..config.num_test_threads.get() { - let finished_files_sender = finished_files_sender.clone(); - threads.push(s.spawn(|| -> Result<()> { - let finished_files_sender = finished_files_sender; - for path in &receive { - let maybe_config; - let config = match per_file_config(&config, &path) { - None => &config, - Some(config) => { - maybe_config = config; - &maybe_config - } - }; - let result = - match std::panic::catch_unwind(|| parse_and_test_file(&path, config)) { - Ok(res) => res, - Err(err) => { - finished_files_sender.send(TestRun { - result: TestResult::Errored { - command: Command::new("<unknown>"), - errors: vec![Error::Bug( - *Box::<dyn std::any::Any + Send + 'static>::downcast::< - String, - >(err) - .unwrap(), - )], - stderr: vec![], - }, - path, - revision: String::new(), - })?; - continue; - } - }; - for result in result { - finished_files_sender.send(result)?; - } - } - Ok(()) - })); - } - - for thread in threads { - thread.join().unwrap()?; - } - Ok(()) - })?; + }, + )?; let mut failures = vec![]; let mut succeeded = 0; @@ -309,6 +283,43 @@ pub fn run_tests_generic( } } +/// A generic multithreaded runner that has a thread for producing work, +/// a thread for collecting work, and `num_threads` threads for doing the work. +pub fn run_and_collect<SUBMISSION: Send, RESULT: Send>( + num_threads: usize, + submitter: impl FnOnce(Sender<SUBMISSION>) + Send, + runner: impl Sync + Fn(&Receiver<SUBMISSION>, Sender<RESULT>) -> Result<()>, + collector: impl FnOnce(Receiver<RESULT>) + Send, +) -> Result<()> { + // A channel for files to process + let (submit, receive) = unbounded(); + + thread::scope(|s| { + // Create a thread that is in charge of walking the directory and submitting jobs. + // It closes the channel when it is done. + s.spawn(|| submitter(submit)); + + // A channel for the messages emitted by the individual test threads. + // Used to produce live updates while running the tests. + let (finished_files_sender, finished_files_recv) = unbounded(); + + s.spawn(|| collector(finished_files_recv)); + + let mut threads = vec![]; + + // Create N worker threads that receive files to test. + for _ in 0..num_threads { + let finished_files_sender = finished_files_sender.clone(); + threads.push(s.spawn(|| runner(&receive, finished_files_sender))); + } + + for thread in threads { + thread.join().unwrap()?; + } + Ok(()) + }) +} + fn parse_and_test_file(path: &Path, config: &Config) -> Vec<TestRun> { let comments = match parse_comments_in_file(path) { Ok(comments) => comments, @@ -696,6 +707,7 @@ fn run_rustfix( revisioned: std::iter::once(( vec![], Revisioned { + line: 0, ignore: vec![], only: vec![], stderr_per_bitwidth: false, diff --git a/vendor/ui_test/src/parser.rs b/vendor/ui_test/src/parser.rs index d2b510e1b..b041fb812 100644 --- a/vendor/ui_test/src/parser.rs +++ b/vendor/ui_test/src/parser.rs @@ -18,7 +18,7 @@ mod tests; /// get processed by their respective use sites. #[derive(Default, Debug)] pub(crate) struct Comments { - /// List of revision names to execute. Can only be speicified once + /// List of revision names to execute. Can only be specified once pub revisions: Option<Vec<String>>, /// Comments that are only available under specific revisions. /// The defaults are in key `vec![]` @@ -78,6 +78,9 @@ impl Comments { #[derive(Default, Debug)] /// Comments that can be filtered for specific revisions. pub(crate) struct Revisioned { + /// The line in which this revisioned item was first added. + /// Used for reporting errors on unknown revisions. + pub line: usize, /// Don't run this test if any of these filters apply pub ignore: Vec<Condition>, /// Only run this test if all of these filters apply @@ -210,6 +213,27 @@ impl Comments { }), } } + if let Some(revisions) = &parser.comments.revisions { + for (key, revisioned) in &parser.comments.revisioned { + for rev in key { + if !revisions.contains(rev) { + parser.errors.push(Error::InvalidComment { + msg: format!("the revision `{rev}` is not known"), + line: revisioned.line, + }) + } + } + } + } else { + for (key, revisioned) in &parser.comments.revisioned { + if !key.is_empty() { + parser.errors.push(Error::InvalidComment { + msg: "there are no revisions in this test".into(), + line: revisioned.line, + }) + } + } + } if parser.errors.is_empty() { Ok(parser.comments) } else { @@ -332,10 +356,17 @@ impl CommentParser<Comments> { revisions: Vec<String>, f: impl FnOnce(&mut CommentParser<&mut Revisioned>), ) { + let line = self.line; let mut this = CommentParser { errors: std::mem::take(&mut self.errors), - line: self.line, - comments: self.revisioned.entry(revisions).or_default(), + line, + comments: self + .revisioned + .entry(revisions) + .or_insert_with(|| Revisioned { + line, + ..Default::default() + }), }; f(&mut this); self.errors = this.errors; |