summaryrefslogtreecommitdiffstats
path: root/vendor/ui_test-0.20.0
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:48 +0000
commitef24de24a82fe681581cc130f342363c47c0969a (patch)
tree0d494f7e1a38b95c92426f58fe6eaa877303a86c /vendor/ui_test-0.20.0
parentReleasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff)
downloadrustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz
rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/ui_test-0.20.0')
-rw-r--r--vendor/ui_test-0.20.0/.cargo-checksum.json1
-rw-r--r--vendor/ui_test-0.20.0/CONTRIBUTING.md7
-rw-r--r--vendor/ui_test-0.20.0/Cargo.toml92
-rw-r--r--vendor/ui_test-0.20.0/README.md64
-rw-r--r--vendor/ui_test-0.20.0/src/cmd.rs120
-rw-r--r--vendor/ui_test-0.20.0/src/config.rs272
-rw-r--r--vendor/ui_test-0.20.0/src/config/args.rs90
-rw-r--r--vendor/ui_test-0.20.0/src/dependencies.rs320
-rw-r--r--vendor/ui_test-0.20.0/src/diff.rs164
-rw-r--r--vendor/ui_test-0.20.0/src/error.rs81
-rw-r--r--vendor/ui_test-0.20.0/src/github_actions.rs96
-rw-r--r--vendor/ui_test-0.20.0/src/lib.rs1270
-rw-r--r--vendor/ui_test-0.20.0/src/mode.rs93
-rw-r--r--vendor/ui_test-0.20.0/src/parser.rs822
-rw-r--r--vendor/ui_test-0.20.0/src/parser/spanned.rs264
-rw-r--r--vendor/ui_test-0.20.0/src/parser/tests.rs139
-rw-r--r--vendor/ui_test-0.20.0/src/rustc_stderr.rs201
-rw-r--r--vendor/ui_test-0.20.0/src/status_emitter.rs972
-rw-r--r--vendor/ui_test-0.20.0/src/tests.rs350
-rw-r--r--vendor/ui_test-0.20.0/tests/integration.rs120
20 files changed, 0 insertions, 5538 deletions
diff --git a/vendor/ui_test-0.20.0/.cargo-checksum.json b/vendor/ui_test-0.20.0/.cargo-checksum.json
deleted file mode 100644
index 27886f95b..000000000
--- a/vendor/ui_test-0.20.0/.cargo-checksum.json
+++ /dev/null
@@ -1 +0,0 @@
-{"files":{"CONTRIBUTING.md":"e030432e8f8830a0c6e6fb783dcae14c19d20f770d4e2e274a48693748d7bd68","Cargo.toml":"cbd19cfe012839028720b9337016bc3733e5ad39abe8ef2410acbd23e7352b59","README.md":"7bed6721a527e43182edc6b6a038fd8fe038f939c79def1cfba9976a917a3b03","src/cmd.rs":"a5d978fd5987488cd99a92d2561b70f122a3c3e8e93d0b8a89094a91bdcbbf94","src/config.rs":"2513f4f8125dfe8700c295973a316caa7216a54323ed600a49cff4d9b09eebbf","src/config/args.rs":"50e1ffc9eed4f94edf2e4bacf1d07e827c7a4fc60c1cb16d2003360b72945c6f","src/dependencies.rs":"4ddfada523b48f5053e464cd77b8c59d440fbf0c79481543405a57b6aa613d21","src/diff.rs":"b05d708188e82d7eaa36957b4a8d273e16954d304c99b58b3655087a26ddff39","src/error.rs":"14dd6d90542e3b6b2dc7ce706be73b8025f3e224639ffcfb965af5c3d210cae5","src/github_actions.rs":"f3fffae4629a3f27798f8d62a7627967e82396b36e951bb0db7596ed6b59a5cb","src/lib.rs":"743da0c1b327fe3434e89fc93fb449a22c7936bdedb2830c9c52d5895a125f65","src/mode.rs":"bcf256b2f5feefe14400b19f1b0176b2f01e3143197005a26d5f3dbf4455150a","src/parser.rs":"f2c473d8fd5c19ca54caa6a6f623acbf01389df405cbedf4d113caa0406e3582","src/parser/spanned.rs":"efebe51e6f2e8671903959230002fa71f7afbe65fbd24b3fba97607380364770","src/parser/tests.rs":"0850b18327af3a2ad97e7808541ae7616c483ff3fa1a059495e272ee5b4a1a05","src/rustc_stderr.rs":"92f93e47cc1f8dc26a854ddd51f0dbf92ca06503e3c82ba6fff5894a7bf4fffb","src/status_emitter.rs":"3cd65a96d774a62f3100398e080894fc5a670ab3e1f9d7c7bb60801452f00c37","src/tests.rs":"c5d91016280c8e6614f7244a008888a3fbb8f2c2775b347f420aa77d95134e62","tests/integration.rs":"8c755d022d019390cfa8b1cda06ee1e40052917118e9d30f9dc3c31160497cb3"},"package":"bfd8fb9b15c8332cf51bfc2dc4830063b2446a9c9d732421b56f2478024a3971"} \ No newline at end of file
diff --git a/vendor/ui_test-0.20.0/CONTRIBUTING.md b/vendor/ui_test-0.20.0/CONTRIBUTING.md
deleted file mode 100644
index d5165080c..000000000
--- a/vendor/ui_test-0.20.0/CONTRIBUTING.md
+++ /dev/null
@@ -1,7 +0,0 @@
-## Running the test suite
-
-Running `cargo test` will automatically update the `.stderr`
-and `.stdout` files.
-
-If you only want to check that the output files match and not
-update them, use `cargo test -- -- --check`
diff --git a/vendor/ui_test-0.20.0/Cargo.toml b/vendor/ui_test-0.20.0/Cargo.toml
deleted file mode 100644
index 903a924c3..000000000
--- a/vendor/ui_test-0.20.0/Cargo.toml
+++ /dev/null
@@ -1,92 +0,0 @@
-# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
-#
-# When uploading crates to the registry Cargo will automatically
-# "normalize" Cargo.toml files for maximal compatibility
-# with all versions of Cargo and also rewrite `path` dependencies
-# to registry (e.g., crates.io) dependencies.
-#
-# If you are reading this file be aware that the original Cargo.toml
-# will likely look very different (and much more reasonable).
-# See Cargo.toml.orig for the original contents.
-
-[package]
-edition = "2021"
-rust-version = "1.63"
-name = "ui_test"
-version = "0.20.0"
-description = "A test framework for testing rustc diagnostics output"
-readme = "README.md"
-license = "MIT OR Apache-2.0"
-repository = "https://github.com/oli-obk/ui_test"
-
-[lib]
-test = true
-doctest = false
-
-[[test]]
-name = "integration"
-harness = false
-
-[dependencies.annotate-snippets]
-version = "0.9.1"
-features = ["color"]
-
-[dependencies.anyhow]
-version = "1.0.6"
-
-[dependencies.bstr]
-version = "1.0.1"
-
-[dependencies.cargo-platform]
-version = "0.1.2"
-
-[dependencies.cargo_metadata]
-version = "0.15"
-
-[dependencies.color-eyre]
-version = "0.6.1"
-features = ["capture-spantrace"]
-default-features = false
-
-[dependencies.colored]
-version = "2"
-
-[dependencies.comma]
-version = "1.0.0"
-
-[dependencies.crossbeam-channel]
-version = "0.5.6"
-
-[dependencies.indicatif]
-version = "0.17.6"
-
-[dependencies.lazy_static]
-version = "1.4.0"
-
-[dependencies.levenshtein]
-version = "1.0.5"
-
-[dependencies.prettydiff]
-version = "0.6.4"
-default_features = false
-
-[dependencies.regex]
-version = "1.5.5"
-features = ["unicode-gencat"]
-default-features = false
-
-[dependencies.rustc_version]
-version = "0.4"
-
-[dependencies.rustfix]
-version = "0.6.1"
-
-[dependencies.serde]
-version = "1.0"
-features = ["derive"]
-
-[dependencies.serde_json]
-version = "1.0"
-
-[dependencies.tempfile]
-version = "3.3.0"
diff --git a/vendor/ui_test-0.20.0/README.md b/vendor/ui_test-0.20.0/README.md
deleted file mode 100644
index 40dcc5ec4..000000000
--- a/vendor/ui_test-0.20.0/README.md
+++ /dev/null
@@ -1,64 +0,0 @@
-A smaller version of compiletest-rs
-
-## Magic behavior
-
-* Tests are run in order of their filenames (files first, then recursing into folders).
- So if you have any slow tests, prepend them with a small integral number to make them get run first, taking advantage of parallelism as much as possible (instead of waiting for the slow tests at the end).
-* `cargo test --test your_test_name -- --help` lists the commands you can specify for filtering, blessing and making your tests less verbose.
- * Since `cargo test` on its own runs all tests, using `cargo test -- --check` will not work on its own, but `cargo test -- --quiet` and `cargo test -- some_test_name` will work just fine, as the CLI matches.
-
-## Supported magic comment annotations
-
-If your test tests for failure, you need to add a `//~` annotation where the error is happening
-to make sure that the test will always keep failing with a specific message at the annotated line.
-
-`//~ ERROR: XXX` make sure the stderr output contains `XXX` for an error in the line where this comment is written
-
-* Also supports `HELP`, `WARN` or `NOTE` for different kind of message
- * if one of those levels is specified explicitly, *all* diagnostics of this level or higher need an annotation. If you want to avoid this, just leave out the all caps level note entirely.
-* If the all caps note is left out, a message of any level is matched. Leaving it out is not allowed for `ERROR` levels.
-* This checks the output *before* normalization, so you can check things that get normalized away, but need to
- be careful not to accidentally have a pattern that differs between platforms.
-* if `XXX` is of the form `/XXX/` it is treated as a regex instead of a substring and will succeed if the regex matches.
-
-In order to change how a single test is tested, you can add various `//@` comments to the test.
-Any other comments will be ignored, and all `//@` comments must be formatted precisely as
-their command specifies, or the test will fail without even being run.
-
-* `//@ignore-C` avoids running the test when condition `C` is met.
- * `C` can be `target-XXX`, which checks whether the target triple contains `XXX`.
- * `C` can also be one of `64bit`, `32bit` or `16bit`.
- * `C` can also be `on-host`, which will only run the test during cross compilation testing.
-* `//@only-C` **only** runs the test when condition `C` is met. The conditions are the same as with `ignore`.
-* `//@needs-asm-support` **only** runs the test when the target supports `asm!`.
-* `//@stderr-per-bitwidth` produces one stderr file per bitwidth, as they may differ significantly sometimes
-* `//@error-in-other-file: XXX` can be used to check for errors that can't have `//~` patterns due to being reported in other files.
-* `//@revisions: XXX YYY` runs the test once for each space separated name in the list
- * emits one stderr file per revision
- * `//~` comments can be restricted to specific revisions by adding the revision name after the `~` in square brackets: `//~[XXX]`
- * `//@` comments can be restricted to specific revisions by adding the revision name after the `@` in square brackets: `//@[XXX]`
- * Note that you cannot add revisions to the `revisions` command.
-* `//@compile-flags: XXX` appends `XXX` to the command line arguments passed to the rustc driver
- * you can specify this multiple times, and all the flags will accumulate
-* `//@rustc-env: XXX=YYY` sets the env var `XXX` to `YYY` for the rustc driver execution.
- * for Miri these env vars are used during compilation via rustc and during the emulation of the program
- * you can specify this multiple times, accumulating all the env vars
-* `//@normalize-stderr-test: "REGEX" -> "REPLACEMENT"` replaces all matches of `REGEX` in the stderr with `REPLACEMENT`. The replacement may specify `$1` and similar backreferences to paste captures.
- * you can specify multiple such commands, there is no need to create a single regex that handles multiple replacements that you want to perform.
-* `//@require-annotations-for-level: LEVEL` can be used to change the level of diagnostics that require a corresponding annotation.
- * this is only useful if there are any annotations like `HELP`, `WARN` or `NOTE`, as these would automatically require annotations for all other diagnostics of the same or higher level.
-* `//@check-pass` requires that a test has no error annotations, emits no errors, and exits successfully with exit/status code 0.
-* `//@edition: EDITION` overwrites the default edition (2021) to the given edition.
-* `//@no-rustfix` do not run [rustfix] on tests that have machine applicable suggestions.
-* `//@aux-build: filename` looks for a file in the `auxiliary` directory (within the directory of the test), compiles it as a library and links the current crate against it. This allows you import the crate with `extern crate` or just via `use` statements. This will automatically detect aux files that are proc macros and build them as proc macros.
-* `//@run` compiles the test and runs the resulting binary. The resulting binary must exit successfully. Stdout and stderr are taken from the resulting binary. Any warnings during compilation are ignored.
- * You can also specify a different exit code/status that is expected via e.g. `//@run: 1` or `//@run: 101` (the latter is the standard Rust exit code for panics).
-
-[rustfix]: https://github.com/rust-lang/rustfix
-
-## Significant differences to compiletest-rs
-
-* `ignore-target-*` and `only-target-*` operate solely on the triple, instead of supporting things like `macos`
-* only supports `ui` tests
-* tests are run in named order, so you can prefix slow tests with `0` in order to make them get run first
-* `aux-build`s require specifying nested aux builds explicitly and will not allow you to reference sibling `aux-build`s' artifacts.
diff --git a/vendor/ui_test-0.20.0/src/cmd.rs b/vendor/ui_test-0.20.0/src/cmd.rs
deleted file mode 100644
index 53fa3e0f4..000000000
--- a/vendor/ui_test-0.20.0/src/cmd.rs
+++ /dev/null
@@ -1,120 +0,0 @@
-use std::{
- ffi::OsString,
- path::{Path, PathBuf},
- process::Command,
-};
-
-#[derive(Debug, Clone)]
-/// A command, its args and its environment. Used for
-/// the main command, the dependency builder and the cfg-reader.
-pub struct CommandBuilder {
- /// Path to the binary.
- pub program: PathBuf,
- /// Arguments to the binary.
- pub args: Vec<OsString>,
- /// A flag to prefix before the path to where output files should be written.
- pub out_dir_flag: Option<OsString>,
- /// A flag to set as the last flag in the command, so the `build` caller can
- /// append the filename themselves.
- pub input_file_flag: Option<OsString>,
- /// Environment variables passed to the binary that is executed.
- /// The environment variable is removed if the second tuple field is `None`
- pub envs: Vec<(OsString, Option<OsString>)>,
-}
-
-impl CommandBuilder {
- /// Uses the `CARGO` env var or just a program named `cargo` and the argument `build`.
- pub fn cargo() -> Self {
- Self {
- program: PathBuf::from(std::env::var_os("CARGO").unwrap_or_else(|| "cargo".into())),
- args: vec!["build".into()],
- out_dir_flag: Some("--target-dir".into()),
- input_file_flag: Some("--manifest-path".into()),
- envs: vec![],
- }
- }
-
- /// Uses the `RUSTC` env var or just a program named `rustc` and the argument `--error-format=json`.
- ///
- /// Take care to only append unless you actually meant to overwrite the defaults.
- /// Overwriting the defaults may make `//~ ERROR` style comments stop working.
- pub fn rustc() -> Self {
- Self {
- program: PathBuf::from(std::env::var_os("RUSTC").unwrap_or_else(|| "rustc".into())),
- args: vec!["--error-format=json".into()],
- out_dir_flag: Some("--out-dir".into()),
- input_file_flag: None,
- envs: vec![],
- }
- }
-
- /// Same as [`CommandBuilder::rustc`], but with arguments for obtaining the cfgs.
- pub fn cfgs() -> Self {
- Self {
- args: vec!["--print".into(), "cfg".into()],
- ..Self::rustc()
- }
- }
-
- /// Build a `CommandBuilder` for a command without any argumemnts.
- /// You can still add arguments later.
- pub fn cmd(cmd: impl Into<PathBuf>) -> Self {
- Self {
- program: cmd.into(),
- args: vec![],
- out_dir_flag: None,
- input_file_flag: None,
- envs: vec![],
- }
- }
-
- /// Render the command like you'd use it on a command line.
- pub fn display(&self) -> impl std::fmt::Display + '_ {
- struct Display<'a>(&'a CommandBuilder);
- impl std::fmt::Display for Display<'_> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- for (var, val) in &self.0.envs {
- if let Some(val) = val {
- write!(f, "{var:?}={val:?} ")?;
- }
- }
- self.0.program.display().fmt(f)?;
- for arg in &self.0.args {
- write!(f, " {arg:?}")?;
- }
- if let Some(flag) = &self.0.out_dir_flag {
- write!(f, " {flag:?} OUT_DIR")?;
- }
- if let Some(flag) = &self.0.input_file_flag {
- write!(f, " {flag:?}")?;
- }
- Ok(())
- }
- }
- Display(self)
- }
-
- /// Create a command with the given settings.
- pub fn build(&self, out_dir: &Path) -> Command {
- let mut cmd = Command::new(&self.program);
- cmd.args(self.args.iter());
- if let Some(flag) = &self.out_dir_flag {
- cmd.arg(flag).arg(out_dir);
- }
- if let Some(flag) = &self.input_file_flag {
- cmd.arg(flag);
- }
- self.apply_env(&mut cmd);
- cmd
- }
-
- pub(crate) fn apply_env(&self, cmd: &mut Command) {
- for (var, val) in self.envs.iter() {
- if let Some(val) = val {
- cmd.env(var, val);
- } else {
- cmd.env_remove(var);
- }
- }
- }
-}
diff --git a/vendor/ui_test-0.20.0/src/config.rs b/vendor/ui_test-0.20.0/src/config.rs
deleted file mode 100644
index 6779bab7d..000000000
--- a/vendor/ui_test-0.20.0/src/config.rs
+++ /dev/null
@@ -1,272 +0,0 @@
-use regex::bytes::Regex;
-
-use crate::{dependencies::build_dependencies, CommandBuilder, Filter, Match, Mode, RustfixMode};
-pub use color_eyre;
-use color_eyre::eyre::Result;
-use std::{
- ffi::OsString,
- num::NonZeroUsize,
- path::{Path, PathBuf},
-};
-
-mod args;
-pub use args::Args;
-
-#[derive(Debug, Clone)]
-/// Central datastructure containing all information to run the tests.
-pub struct Config {
- /// Host triple; usually will be auto-detected.
- pub host: Option<String>,
- /// `None` to run on the host, otherwise a target triple
- pub target: Option<String>,
- /// Filters applied to stderr output before processing it.
- /// By default contains a filter for replacing backslashes in paths with
- /// regular slashes.
- /// On windows, contains a filter to remove `\r`.
- pub stderr_filters: Filter,
- /// Filters applied to stdout output before processing it.
- /// On windows, contains a filter to remove `\r`.
- pub stdout_filters: Filter,
- /// The folder in which to start searching for .rs files
- pub root_dir: PathBuf,
- /// The mode in which to run the tests.
- pub mode: Mode,
- /// The binary to actually execute.
- pub program: CommandBuilder,
- /// The command to run to obtain the cfgs that the output is supposed to
- pub cfgs: CommandBuilder,
- /// What to do in case the stdout/stderr output differs from the expected one.
- pub output_conflict_handling: OutputConflictHandling,
- /// Path to a `Cargo.toml` that describes which dependencies the tests can access.
- pub dependencies_crate_manifest_path: Option<PathBuf>,
- /// The command to run can be changed from `cargo` to any custom command to build the
- /// dependencies in `dependencies_crate_manifest_path`.
- pub dependency_builder: CommandBuilder,
- /// Where to dump files like the binaries compiled from tests.
- /// Defaults to `target/ui` in the current directory.
- pub out_dir: PathBuf,
- /// The default edition to use on all tests.
- pub edition: Option<String>,
- /// Skip test files whose names contain any of these entries.
- pub skip_files: Vec<String>,
- /// Only test files whose names contain any of these entries.
- pub filter_files: Vec<String>,
- /// Override the number of threads to use.
- pub threads: Option<NonZeroUsize>,
-}
-
-impl Config {
- /// Create a configuration for testing the output of running
- /// `rustc` on the test files.
- pub fn rustc(root_dir: impl Into<PathBuf>) -> Self {
- Self {
- host: None,
- target: None,
- stderr_filters: vec![
- (Match::PathBackslash, b"/"),
- #[cfg(windows)]
- (Match::Exact(vec![b'\r']), b""),
- #[cfg(windows)]
- (Match::Exact(br"\\?\".to_vec()), b""),
- ],
- stdout_filters: vec![
- (Match::PathBackslash, b"/"),
- #[cfg(windows)]
- (Match::Exact(vec![b'\r']), b""),
- #[cfg(windows)]
- (Match::Exact(br"\\?\".to_vec()), b""),
- ],
- root_dir: root_dir.into(),
- mode: Mode::Fail {
- require_patterns: true,
- rustfix: RustfixMode::MachineApplicable,
- },
- program: CommandBuilder::rustc(),
- cfgs: CommandBuilder::cfgs(),
- output_conflict_handling: OutputConflictHandling::Bless,
- dependencies_crate_manifest_path: None,
- dependency_builder: CommandBuilder::cargo(),
- 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()),
- skip_files: Vec::new(),
- filter_files: Vec::new(),
- threads: None,
- }
- }
-
- /// Create a configuration for testing the output of running
- /// `cargo` on the test `Cargo.toml` files.
- pub fn cargo(root_dir: impl Into<PathBuf>) -> Self {
- Self {
- program: CommandBuilder::cargo(),
- edition: None,
- mode: Mode::Fail {
- require_patterns: true,
- rustfix: RustfixMode::Disabled,
- },
- ..Self::rustc(root_dir)
- }
- }
-
- /// Populate the config with the values from parsed command line arguments.
- /// If neither `--bless` or `--check` are provided `default_bless` is used.
- ///
- /// The default output conflict handling command suggests adding `--bless`
- /// to the end of the current command.
- pub fn with_args(&mut self, args: &Args, default_bless: bool) {
- let Args {
- ref filters,
- quiet: _,
- check,
- bless,
- threads,
- ref skip,
- } = *args;
-
- self.threads = threads.or(self.threads);
-
- self.filter_files.extend_from_slice(filters);
- self.skip_files.extend_from_slice(skip);
-
- let bless = match (bless, check) {
- (_, true) => false,
- (true, _) => true,
- _ => default_bless,
- };
- self.output_conflict_handling = if bless {
- OutputConflictHandling::Bless
- } else {
- OutputConflictHandling::Error(format!(
- "{} --bless",
- std::env::args()
- .map(|s| format!("{s:?}"))
- .collect::<Vec<_>>()
- .join(" ")
- ))
- };
- }
-
- /// Replace all occurrences of a path in stderr/stdout with a byte string.
- pub fn path_filter(&mut self, path: &Path, replacement: &'static (impl AsRef<[u8]> + ?Sized)) {
- self.path_stderr_filter(path, replacement);
- self.path_stdout_filter(path, replacement);
- }
-
- /// Replace all occurrences of a path in stderr with a byte string.
- pub fn path_stderr_filter(
- &mut self,
- path: &Path,
- replacement: &'static (impl AsRef<[u8]> + ?Sized),
- ) {
- let pattern = path.canonicalize().unwrap();
- self.stderr_filters
- .push((pattern.parent().unwrap().into(), replacement.as_ref()));
- }
-
- /// Replace all occurrences of a path in stdout with a byte string.
- pub fn path_stdout_filter(
- &mut self,
- path: &Path,
- replacement: &'static (impl AsRef<[u8]> + ?Sized),
- ) {
- let pattern = path.canonicalize().unwrap();
- self.stdout_filters
- .push((pattern.parent().unwrap().into(), replacement.as_ref()));
- }
-
- /// Replace all occurrences of a regex pattern in stderr/stdout with a byte string.
- pub fn filter(&mut self, pattern: &str, replacement: &'static (impl AsRef<[u8]> + ?Sized)) {
- self.stderr_filter(pattern, replacement);
- self.stdout_filter(pattern, replacement);
- }
-
- /// Replace all occurrences of a regex pattern in stderr with a byte string.
- pub fn stderr_filter(
- &mut self,
- pattern: &str,
- replacement: &'static (impl AsRef<[u8]> + ?Sized),
- ) {
- self.stderr_filters
- .push((Regex::new(pattern).unwrap().into(), replacement.as_ref()));
- }
-
- /// Replace all occurrences of a regex pattern in stdout with a byte string.
- pub fn stdout_filter(
- &mut self,
- pattern: &str,
- replacement: &'static (impl AsRef<[u8]> + ?Sized),
- ) {
- self.stdout_filters
- .push((Regex::new(pattern).unwrap().into(), replacement.as_ref()));
- }
-
- /// Compile dependencies and return the right flags
- /// to find the dependencies.
- pub fn build_dependencies(&self) -> Result<Vec<OsString>> {
- let dependencies = build_dependencies(self)?;
- let mut args = vec![];
- for (name, artifacts) in dependencies.dependencies {
- for dependency in artifacts {
- args.push("--extern".into());
- let mut dep = OsString::from(&name);
- dep.push("=");
- dep.push(dependency);
- args.push(dep);
- }
- }
- for import_path in dependencies.import_paths {
- args.push("-L".into());
- args.push(import_path.into());
- }
- Ok(args)
- }
-
- /// Make sure we have the host and target triples.
- pub fn fill_host_and_target(&mut self) -> Result<()> {
- if self.host.is_none() {
- self.host = Some(
- rustc_version::VersionMeta::for_command(std::process::Command::new(
- &self.program.program,
- ))
- .map_err(|err| {
- color_eyre::eyre::Report::new(err).wrap_err(format!(
- "failed to parse rustc version info: {}",
- self.program.display()
- ))
- })?
- .host,
- );
- }
- if self.target.is_none() {
- self.target = Some(self.host.clone().unwrap());
- }
- Ok(())
- }
-
- pub(crate) fn has_asm_support(&self) -> bool {
- static ASM_SUPPORTED_ARCHS: &[&str] = &[
- "x86", "x86_64", "arm", "aarch64", "riscv32",
- "riscv64",
- // These targets require an additional asm_experimental_arch feature.
- // "nvptx64", "hexagon", "mips", "mips64", "spirv", "wasm32",
- ];
- ASM_SUPPORTED_ARCHS
- .iter()
- .any(|arch| self.target.as_ref().unwrap().contains(arch))
- }
-}
-
-#[derive(Debug, Clone)]
-/// The different options for what to do when stdout/stderr files differ from the actual output.
-pub enum OutputConflictHandling {
- /// The string should be a command that can be executed to bless all tests.
- Error(String),
- /// Ignore mismatches in the stderr/stdout files.
- Ignore,
- /// Instead of erroring if the stderr/stdout differs from the expected
- /// automatically replace it with the found output (after applying filters).
- Bless,
-}
diff --git a/vendor/ui_test-0.20.0/src/config/args.rs b/vendor/ui_test-0.20.0/src/config/args.rs
deleted file mode 100644
index 2d65dc7d5..000000000
--- a/vendor/ui_test-0.20.0/src/config/args.rs
+++ /dev/null
@@ -1,90 +0,0 @@
-//! Default argument processing when `ui_test` is used
-//! as a test driver.
-
-use std::{borrow::Cow, num::NonZeroUsize};
-
-use color_eyre::eyre::{bail, ensure, Result};
-
-/// Plain arguments if `ui_test` is used as a binary.
-#[derive(Debug, Default)]
-pub struct Args {
- /// Filters that will be used to match on individual tests
- pub filters: Vec<String>,
-
- /// Whether to minimize output given to the user.
- pub quiet: bool,
-
- /// Whether to error on mismatches between `.stderr` files and actual
- /// output.
- pub check: bool,
-
- /// Whether to overwrite `.stderr` files on mismtach with the actual
- /// output.
- pub bless: bool,
-
- /// The number of threads to use
- pub threads: Option<NonZeroUsize>,
-
- /// Skip tests whose names contain any of these entries.
- pub skip: Vec<String>,
-}
-
-impl Args {
- /// Parse the program arguments.
- /// This is meant to be used if `ui_test` is used as a `harness=false` test, called from `cargo test`.
- pub fn test() -> Result<Self> {
- Self::default().parse_args(std::env::args().skip(1))
- }
-
- /// Parse arguments into an existing `Args` struct.
- pub fn parse_args(mut self, mut iter: impl Iterator<Item = String>) -> Result<Self> {
- while let Some(arg) = iter.next() {
- if arg == "--" {
- continue;
- }
- if arg == "--quiet" {
- self.quiet = true;
- } else if arg == "--check" {
- self.check = true;
- } else if arg == "--bless" {
- self.bless = true;
- } else if let Some(skip) = parse_value("--skip", &arg, &mut iter)? {
- self.skip.push(skip.into_owned());
- } else if arg == "--help" {
- bail!("available flags: --quiet, --check, --bless, --test-threads=n, --skip")
- } else if let Some(n) = parse_value("--test-threads", &arg, &mut iter)? {
- self.threads = Some(n.parse()?);
- } else if arg.starts_with("--") {
- bail!(
- "unknown command line flag `{arg}`: {:?}",
- iter.collect::<Vec<_>>()
- );
- } else {
- self.filters.push(arg);
- }
- }
- Ok(self)
- }
-}
-
-fn parse_value<'a>(
- name: &str,
- arg: &'a str,
- iter: &mut impl Iterator<Item = String>,
-) -> Result<Option<Cow<'a, str>>> {
- let with_eq = match arg.strip_prefix(name) {
- Some(s) => s,
- None => return Ok(None),
- };
- if let Some(n) = with_eq.strip_prefix('=') {
- Ok(Some(n.into()))
- } else {
- ensure!(with_eq.is_empty(), "`{name}` can only be followed by `=`");
-
- if let Some(next) = iter.next() {
- Ok(Some(next.into()))
- } else {
- bail!("`name` must be followed by a value")
- }
- }
-}
diff --git a/vendor/ui_test-0.20.0/src/dependencies.rs b/vendor/ui_test-0.20.0/src/dependencies.rs
deleted file mode 100644
index 0e95e0f84..000000000
--- a/vendor/ui_test-0.20.0/src/dependencies.rs
+++ /dev/null
@@ -1,320 +0,0 @@
-use cargo_metadata::{camino::Utf8PathBuf, DependencyKind};
-use cargo_platform::Cfg;
-use color_eyre::eyre::{bail, eyre, Result};
-use std::{
- collections::{hash_map::Entry, HashMap, HashSet},
- ffi::OsString,
- path::PathBuf,
- process::Command,
- str::FromStr,
- sync::{Arc, OnceLock, RwLock},
-};
-
-use crate::{
- build_aux, status_emitter::StatusEmitter, Config, Errored, Mode, OutputConflictHandling,
-};
-
-#[derive(Default, Debug)]
-pub struct Dependencies {
- /// All paths that must be imported with `-L dependency=`. This is for
- /// finding proc macros run on the host and dependencies for the target.
- pub import_paths: Vec<PathBuf>,
- /// The name as chosen in the `Cargo.toml` and its corresponding rmeta file.
- pub dependencies: Vec<(String, Vec<Utf8PathBuf>)>,
-}
-
-fn cfgs(config: &Config) -> Result<Vec<Cfg>> {
- let mut cmd = config.cfgs.build(&config.out_dir);
- cmd.arg("--target").arg(config.target.as_ref().unwrap());
- let output = cmd.output()?;
- let stdout = String::from_utf8(output.stdout)?;
-
- if !output.status.success() {
- let stderr = String::from_utf8(output.stderr)?;
- bail!(
- "failed to obtain `cfg` information from {cmd:?}:\nstderr:\n{stderr}\n\nstdout:{stdout}"
- );
- }
- let mut cfgs = vec![];
-
- for line in stdout.lines() {
- cfgs.push(Cfg::from_str(line)?);
- }
-
- Ok(cfgs)
-}
-
-/// Compiles dependencies and returns the crate names and corresponding rmeta files.
-pub(crate) fn build_dependencies(config: &Config) -> Result<Dependencies> {
- let manifest_path = match &config.dependencies_crate_manifest_path {
- Some(path) => path.to_owned(),
- None => return Ok(Default::default()),
- };
- let manifest_path = &manifest_path;
- let mut build = config.dependency_builder.build(&config.out_dir);
- build.arg(manifest_path);
-
- if let Some(target) = &config.target {
- build.arg(format!("--target={target}"));
- }
-
- // Reusable closure for setting up the environment both for artifact generation and `cargo_metadata`
- let set_locking = |cmd: &mut Command| match (&config.output_conflict_handling, &config.mode) {
- (_, Mode::Yolo { .. }) => {}
- (OutputConflictHandling::Error(_), _) => {
- cmd.arg("--locked");
- }
- _ => {}
- };
-
- set_locking(&mut build);
- build.arg("--message-format=json");
-
- let output = build.output()?;
-
- if !output.status.success() {
- let stdout = String::from_utf8(output.stdout)?;
- let stderr = String::from_utf8(output.stderr)?;
- bail!("failed to compile dependencies:\ncommand: {build:?}\nstderr:\n{stderr}\n\nstdout:{stdout}");
- }
-
- // Collect all artifacts generated
- let artifact_output = output.stdout;
- let artifact_output = String::from_utf8(artifact_output)?;
- let mut import_paths: HashSet<PathBuf> = HashSet::new();
- let mut artifacts = HashMap::new();
- for line in artifact_output.lines() {
- let Ok(message) = serde_json::from_str::<cargo_metadata::Message>(line) else {
- continue;
- };
- if let cargo_metadata::Message::CompilerArtifact(artifact) = message {
- if artifact
- .filenames
- .iter()
- .any(|f| f.ends_with("build-script-build"))
- {
- continue;
- }
- // Check that we only collect rmeta and rlib crates, not build script crates
- if artifact
- .filenames
- .iter()
- .any(|f| !matches!(f.extension(), Some("rlib" | "rmeta")))
- {
- continue;
- }
- for filename in &artifact.filenames {
- import_paths.insert(filename.parent().unwrap().into());
- }
- let package_id = artifact.package_id;
- if let Some(prev) = artifacts.insert(package_id.clone(), Ok(artifact.filenames)) {
- artifacts.insert(
- package_id.clone(),
- Err(format!("{prev:#?} vs {:#?}", artifacts[&package_id])),
- );
- }
- }
- }
-
- // Check which crates are mentioned in the crate itself
- let mut metadata = cargo_metadata::MetadataCommand::new().cargo_command();
- metadata.arg("--manifest-path").arg(manifest_path);
- config.dependency_builder.apply_env(&mut metadata);
- set_locking(&mut metadata);
- let output = metadata.output()?;
-
- if !output.status.success() {
- let stdout = String::from_utf8(output.stdout)?;
- let stderr = String::from_utf8(output.stderr)?;
- bail!("failed to run cargo-metadata:\nstderr:\n{stderr}\n\nstdout:{stdout}");
- }
-
- let output = output.stdout;
- let output = String::from_utf8(output)?;
-
- let cfg = cfgs(config)?;
-
- for line in output.lines() {
- if !line.starts_with('{') {
- continue;
- }
- let metadata: cargo_metadata::Metadata = serde_json::from_str(line)?;
- // Only take artifacts that are defined in the Cargo.toml
-
- // First, find the root artifact
- let root = metadata
- .packages
- .iter()
- .find(|package| {
- package.manifest_path.as_std_path().canonicalize().unwrap()
- == manifest_path.canonicalize().unwrap()
- })
- .unwrap();
-
- // Then go over all of its dependencies
- let dependencies = root
- .dependencies
- .iter()
- .filter(|dep| matches!(dep.kind, DependencyKind::Normal))
- // Only consider dependencies that are enabled on the current target
- .filter(|dep| match &dep.target {
- Some(platform) => platform.matches(config.target.as_ref().unwrap(), &cfg),
- None => true,
- })
- .map(|dep| {
- let package = metadata
- .packages
- .iter()
- .find(|&p| p.name == dep.name && dep.req.matches(&p.version))
- .expect("dependency does not exist");
- (
- package,
- dep.rename.clone().unwrap_or_else(|| package.name.clone()),
- )
- })
- // Also expose the root crate
- .chain(std::iter::once((root, root.name.clone())))
- .filter_map(|(package, name)| {
- // Get the id for the package matching the version requirement of the dep
- let id = &package.id;
- // Return the name chosen in `Cargo.toml` and the path to the corresponding artifact
- match artifacts.remove(id) {
- Some(Ok(artifacts)) => Some(Ok((name.replace('-', "_"), artifacts))),
- Some(Err(what)) => Some(Err(eyre!("`ui_test` does not support crates that appear as both build-dependencies and core dependencies: {id}: {what}"))),
- None => {
- if name == root.name {
- // If there are no artifacts, this is the root crate and it is being built as a binary/test
- // instead of a library. We simply add no artifacts, meaning you can't depend on functions
- // and types declared in the root crate.
- None
- } else {
- panic!("no artifact found for `{name}`(`{id}`):`\n{artifact_output}")
- }
- }
- }
- })
- .collect::<Result<Vec<_>>>()?;
- let import_paths = import_paths.into_iter().collect();
- return Ok(Dependencies {
- dependencies,
- import_paths,
- });
- }
-
- bail!("no json found in cargo-metadata output")
-}
-
-#[derive(PartialEq, Eq, Debug, Hash, Clone)]
-pub enum Build {
- /// Build the dependencies.
- Dependencies,
- /// Build an aux-build.
- Aux { aux_file: PathBuf },
-}
-impl Build {
- fn description(&self) -> String {
- match self {
- Build::Dependencies => "Building dependencies".into(),
- Build::Aux { aux_file } => format!("Building aux file {}", aux_file.display()),
- }
- }
-}
-
-pub struct BuildManager<'a> {
- #[allow(clippy::type_complexity)]
- cache: RwLock<HashMap<Build, Arc<OnceLock<Result<Vec<OsString>, ()>>>>>,
- status_emitter: &'a dyn StatusEmitter,
-}
-
-impl<'a> BuildManager<'a> {
- pub fn new(status_emitter: &'a dyn StatusEmitter) -> Self {
- Self {
- cache: Default::default(),
- status_emitter,
- }
- }
- /// This function will block until the build is done and then return the arguments
- /// that need to be passed in order to build the dependencies.
- /// The error is only reported once, all follow up invocations of the same build will
- /// have a generic error about a previous build failing.
- pub fn build(&self, what: Build, config: &Config) -> Result<Vec<OsString>, Errored> {
- // Fast path without much contention.
- if let Some(res) = self.cache.read().unwrap().get(&what).and_then(|o| o.get()) {
- return res.clone().map_err(|()| Errored {
- command: Command::new(format!("{what:?}")),
- errors: vec![],
- stderr: b"previous build failed".to_vec(),
- stdout: vec![],
- });
- }
- let mut lock = self.cache.write().unwrap();
- let once = match lock.entry(what.clone()) {
- Entry::Occupied(entry) => {
- if let Some(res) = entry.get().get() {
- return res.clone().map_err(|()| Errored {
- command: Command::new(format!("{what:?}")),
- errors: vec![],
- stderr: b"previous build failed".to_vec(),
- stdout: vec![],
- });
- }
- entry.get().clone()
- }
- Entry::Vacant(entry) => {
- let once = Arc::new(OnceLock::new());
- entry.insert(once.clone());
- once
- }
- };
- drop(lock);
-
- let mut err = None;
- once.get_or_init(|| {
- let build = self
- .status_emitter
- .register_test(what.description().into())
- .for_revision("");
- let res = match &what {
- Build::Dependencies => match config.build_dependencies() {
- Ok(args) => Ok(args),
- Err(e) => {
- err = Some(Errored {
- command: Command::new(format!("{what:?}")),
- errors: vec![],
- stderr: format!("{e:?}").into_bytes(),
- stdout: vec![],
- });
- Err(())
- }
- },
- Build::Aux { aux_file } => match build_aux(aux_file, config, self) {
- Ok(args) => Ok(args.iter().map(Into::into).collect()),
- Err(e) => {
- err = Some(e);
- Err(())
- }
- },
- };
- build.done(
- &res.as_ref()
- .map(|_| crate::TestOk::Ok)
- .map_err(|()| Errored {
- command: Command::new(what.description()),
- errors: vec![],
- stderr: vec![],
- stdout: vec![],
- }),
- );
- res
- })
- .clone()
- .map_err(|()| {
- err.unwrap_or_else(|| Errored {
- command: Command::new(what.description()),
- errors: vec![],
- stderr: b"previous build failed".to_vec(),
- stdout: vec![],
- })
- })
- }
-}
diff --git a/vendor/ui_test-0.20.0/src/diff.rs b/vendor/ui_test-0.20.0/src/diff.rs
deleted file mode 100644
index b0346c250..000000000
--- a/vendor/ui_test-0.20.0/src/diff.rs
+++ /dev/null
@@ -1,164 +0,0 @@
-use colored::*;
-use prettydiff::{basic::DiffOp, basic::DiffOp::*, diff_lines, diff_words};
-
-/// How many lines of context are displayed around the actual diffs
-const CONTEXT: usize = 2;
-
-fn skip(skipped_lines: &[&str]) {
- // When the amount of skipped lines is exactly `CONTEXT * 2`, we already
- // print all the context and don't actually skip anything.
- match skipped_lines.len().checked_sub(CONTEXT * 2) {
- Some(skipped @ 2..) => {
- // Print an initial `CONTEXT` amount of lines.
- for line in &skipped_lines[..CONTEXT] {
- println!(" {line}");
- }
- println!("... {skipped} lines skipped ...");
- // Print `... n lines skipped ...` followed by the last `CONTEXT` lines.
- for line in &skipped_lines[skipped + CONTEXT..] {
- println!(" {line}");
- }
- }
- _ => {
- // Print all the skipped lines if the amount of context desired is less than the amount of lines
- for line in skipped_lines {
- println!(" {line}");
- }
- }
- }
-}
-
-fn row(row: DiffOp<'_, &str>) {
- match row {
- Remove(l) => {
- for l in l {
- println!("{}{}", "-".red(), l.red());
- }
- }
- Equal(l) => {
- skip(l);
- }
- Replace(l, r) => {
- for (l, r) in l.iter().zip(r) {
- print_line_diff(l, r);
- }
- }
- Insert(r) => {
- for r in r {
- println!("{}{}", "+".green(), r.green());
- }
- }
- }
-}
-
-fn print_line_diff(l: &str, r: &str) {
- let diff = diff_words(l, r);
- let diff = diff.diff();
- if has_both_insertions_and_deletions(&diff)
- || !colored::control::SHOULD_COLORIZE.should_colorize()
- {
- // The line both adds and removes chars, print both lines, but highlight their differences instead of
- // drawing the entire line in red/green.
- print!("{}", "-".red());
- for char in &diff {
- match *char {
- Replace(l, _) | Remove(l) => {
- for l in l {
- print!("{}", l.to_string().on_red())
- }
- }
- Insert(_) => {}
- Equal(l) => {
- for l in l {
- print!("{l}")
- }
- }
- }
- }
- println!();
- print!("{}", "+".green());
- for char in diff {
- match char {
- Remove(_) => {}
- Replace(_, r) | Insert(r) => {
- for r in r {
- print!("{}", r.to_string().on_green())
- }
- }
- Equal(r) => {
- for r in r {
- print!("{r}")
- }
- }
- }
- }
- println!();
- } else {
- // The line only adds or only removes chars, print a single line highlighting their differences.
- print!("{}", "~".yellow());
- for char in diff {
- match char {
- Remove(l) => {
- for l in l {
- print!("{}", l.to_string().on_red())
- }
- }
- Equal(w) => {
- for w in w {
- print!("{w}")
- }
- }
- Insert(r) => {
- for r in r {
- print!("{}", r.to_string().on_green())
- }
- }
- Replace(l, r) => {
- for l in l {
- print!("{}", l.to_string().on_red())
- }
- for r in r {
- print!("{}", r.to_string().on_green())
- }
- }
- }
- }
- println!();
- }
-}
-
-fn has_both_insertions_and_deletions(diff: &[DiffOp<'_, &str>]) -> bool {
- let mut seen_l = false;
- let mut seen_r = false;
- for char in diff {
- let is_whitespace = |s: &[&str]| s.iter().any(|s| s.chars().any(|s| s.is_whitespace()));
- match char {
- Insert(l) if !is_whitespace(l) => seen_l = true,
- Remove(r) if !is_whitespace(r) => seen_r = true,
- Replace(l, r) if !is_whitespace(l) && !is_whitespace(r) => return true,
- _ => {}
- }
- }
- seen_l && seen_r
-}
-
-pub fn print_diff(expected: &[u8], actual: &[u8]) {
- let expected_str = String::from_utf8_lossy(expected);
- let actual_str = String::from_utf8_lossy(actual);
-
- if expected_str.as_bytes() != expected || actual_str.as_bytes() != actual {
- println!(
- "{}",
- "Non-UTF8 characters in output, diff may be imprecise.".red()
- );
- }
-
- let pat = |c: char| c.is_whitespace() && c != ' ' && c != '\n' && c != '\r';
- let expected_str = expected_str.replace(pat, "â–‘");
- let actual_str = actual_str.replace(pat, "â–‘");
-
- for r in diff_lines(&expected_str, &actual_str).diff() {
- row(r);
- }
- println!()
-}
diff --git a/vendor/ui_test-0.20.0/src/error.rs b/vendor/ui_test-0.20.0/src/error.rs
deleted file mode 100644
index 7298a699e..000000000
--- a/vendor/ui_test-0.20.0/src/error.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-use crate::{
- parser::{Pattern, Spanned},
- rustc_stderr::{Message, Span},
- Mode,
-};
-use std::{num::NonZeroUsize, path::PathBuf, process::ExitStatus};
-
-/// All the ways in which a test can fail.
-#[derive(Debug)]
-#[must_use]
-pub enum Error {
- /// Got an invalid exit status for the given mode.
- ExitStatus {
- /// The expected mode.
- mode: Mode,
- /// The exit status of the command.
- status: ExitStatus,
- /// The expected exit status as set in the file or derived from the mode.
- expected: i32,
- },
- /// A pattern was declared but had no matching error.
- PatternNotFound(Spanned<Pattern>),
- /// A ui test checking for failure does not have any failure patterns
- NoPatternsFound,
- /// A ui test checking for success has failure patterns
- PatternFoundInPassTest,
- /// Stderr/Stdout differed from the `.stderr`/`.stdout` file present.
- OutputDiffers {
- /// The file containing the expected output that differs from the actual output.
- path: PathBuf,
- /// The output from the command.
- actual: Vec<u8>,
- /// The contents of the file.
- expected: Vec<u8>,
- /// A command, that when run, causes the output to get blessed instead of erroring.
- bless_command: String,
- },
- /// There were errors that don't have a pattern.
- ErrorsWithoutPattern {
- /// The main message of the error.
- msgs: Vec<Message>,
- /// File and line information of the error.
- path: Option<Spanned<PathBuf>>,
- },
- /// A comment failed to parse.
- InvalidComment {
- /// The comment
- msg: String,
- /// The character range in which it was defined.
- span: Span,
- },
- /// Conflicting comments
- MultipleRevisionsWithResults {
- /// The comment being looked for
- kind: String,
- /// The lines where conflicts happened
- lines: Vec<NonZeroUsize>,
- },
- /// A subcommand (e.g. rustfix) of a test failed.
- Command {
- /// The name of the subcommand (e.g. "rustfix").
- kind: String,
- /// The exit status of the command.
- status: ExitStatus,
- },
- /// This catches crashes of ui tests and reports them along the failed test.
- Bug(String),
- /// An auxiliary build failed with its own set of errors.
- Aux {
- /// Path to the aux file.
- path: PathBuf,
- /// The errors that occurred during the build of the aux file.
- errors: Vec<Error>,
- /// The line in which the aux file was requested to be built.
- line: NonZeroUsize,
- },
- /// An error occured applying [`rustfix`] suggestions
- Rustfix(anyhow::Error),
-}
-
-pub(crate) type Errors = Vec<Error>;
diff --git a/vendor/ui_test-0.20.0/src/github_actions.rs b/vendor/ui_test-0.20.0/src/github_actions.rs
deleted file mode 100644
index 01e1d3bb2..000000000
--- a/vendor/ui_test-0.20.0/src/github_actions.rs
+++ /dev/null
@@ -1,96 +0,0 @@
-//! An interface to github actions workflow commands.
-
-use std::{
- fmt::{Debug, Write},
- num::NonZeroUsize,
-};
-
-/// Shows an error message directly in a github diff view on drop.
-pub struct Error {
- file: String,
- line: usize,
- title: String,
- message: String,
-}
-impl Error {
- /// Set a line for this error. By default the message is shown at the top of the file.
- pub fn line(mut self, line: NonZeroUsize) -> Self {
- self.line = line.get();
- self
- }
-}
-
-/// Create an error to be shown for the given file and with the given title.
-pub fn error(file: impl std::fmt::Display, title: impl Into<String>) -> Error {
- Error {
- file: file.to_string(),
- line: 0,
- title: title.into(),
- message: String::new(),
- }
-}
-
-impl Write for Error {
- fn write_str(&mut self, s: &str) -> std::fmt::Result {
- self.message.write_str(s)
- }
-}
-
-impl Drop for Error {
- fn drop(&mut self) {
- if std::env::var_os("GITHUB_ACTION").is_some() {
- let Error {
- file,
- line,
- title,
- message,
- } = self;
- let message = message.trim();
- let message = if message.is_empty() {
- "::no message".into()
- } else {
- format!("::{}", github_action_multiline_escape(message))
- };
- println!("::error file={file},line={line},title={title}{message}");
- }
- }
-}
-
-/// Append to the summary file that will be shown for the entire CI run.
-pub fn summary() -> Option<impl std::io::Write> {
- let path = std::env::var_os("GITHUB_STEP_SUMMARY")?;
- Some(std::fs::OpenOptions::new().append(true).open(path).unwrap())
-}
-
-fn github_action_multiline_escape(s: &str) -> String {
- s.replace('%', "%25")
- .replace('\n', "%0A")
- .replace('\r', "%0D")
-}
-
-/// All github actions log messages from this call to the Drop of the return value
-/// will be grouped and hidden by default in logs. Note that nesting these does
-/// not really work.
-pub fn group(name: impl std::fmt::Display) -> Group {
- if std::env::var_os("GITHUB_ACTION").is_some() {
- println!("::group::{name}");
- }
- Group(())
-}
-
-/// A guard that closes the current github actions log group on drop.
-pub struct Group(());
-
-impl Debug for Group {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- f.write_str("a handle that will close the github action group on drop")
- }
-}
-
-impl Drop for Group {
- fn drop(&mut self) {
- if std::env::var_os("GITHUB_ACTION").is_some() {
- println!("::endgroup::");
- }
- }
-}
diff --git a/vendor/ui_test-0.20.0/src/lib.rs b/vendor/ui_test-0.20.0/src/lib.rs
deleted file mode 100644
index ba051be8c..000000000
--- a/vendor/ui_test-0.20.0/src/lib.rs
+++ /dev/null
@@ -1,1270 +0,0 @@
-#![allow(
- clippy::enum_variant_names,
- clippy::useless_format,
- clippy::too_many_arguments,
- rustc::internal
-)]
-#![deny(missing_docs)]
-
-//! A crate to run the Rust compiler (or other binaries) and test their command line output.
-
-use bstr::ByteSlice;
-pub use color_eyre;
-use color_eyre::eyre::{eyre, Result};
-use crossbeam_channel::{unbounded, Receiver, Sender};
-use dependencies::{Build, BuildManager};
-use lazy_static::lazy_static;
-use parser::{ErrorMatch, MaybeSpanned, OptWithLine, Revisioned, Spanned};
-use regex::bytes::{Captures, Regex};
-use rustc_stderr::{Level, Message, Span};
-use status_emitter::{StatusEmitter, TestStatus};
-use std::borrow::Cow;
-use std::collections::{HashSet, VecDeque};
-use std::ffi::OsString;
-use std::num::NonZeroUsize;
-use std::path::{Component, Path, PathBuf, Prefix};
-use std::process::{Command, ExitStatus};
-use std::thread;
-
-use crate::parser::{Comments, Condition};
-
-mod cmd;
-mod config;
-mod dependencies;
-mod diff;
-mod error;
-pub mod github_actions;
-mod mode;
-mod parser;
-mod rustc_stderr;
-pub mod status_emitter;
-#[cfg(test)]
-mod tests;
-
-pub use cmd::*;
-pub use config::*;
-pub use error::*;
-pub use mode::*;
-
-/// A filter's match rule.
-#[derive(Clone, Debug)]
-pub enum Match {
- /// If the regex matches, the filter applies
- Regex(Regex),
- /// If the exact byte sequence is found, the filter applies
- Exact(Vec<u8>),
- /// Uses a heuristic to find backslashes in windows style paths
- PathBackslash,
-}
-impl Match {
- fn replace_all<'a>(&self, text: &'a [u8], replacement: &[u8]) -> Cow<'a, [u8]> {
- match self {
- Match::Regex(regex) => regex.replace_all(text, replacement),
- Match::Exact(needle) => text.replace(needle, replacement).into(),
- Match::PathBackslash => {
- lazy_static! {
- static ref PATH_RE: Regex = Regex::new(
- r"(?x)
- (?:
- # Match paths to files with extensions that don't include spaces
- \\(?:[\pL\pN.\-_']+[/\\])*[\pL\pN.\-_']+\.\pL+
- |
- # Allow spaces in absolute paths
- [A-Z]:\\(?:[\pL\pN.\-_'\ ]+[/\\])+
- )",
- )
- .unwrap();
- }
-
- PATH_RE.replace_all(text, |caps: &Captures<'_>| {
- caps[0].replace(r"\", replacement)
- })
- }
- }
- }
-}
-
-impl From<&'_ Path> for Match {
- fn from(v: &Path) -> Self {
- let mut v = v.display().to_string();
- // Normalize away windows canonicalized paths.
- if v.starts_with(r"\\?\") {
- v.drain(0..4);
- }
- let mut v = v.into_bytes();
- // Normalize paths on windows to use slashes instead of backslashes,
- // So that paths are rendered the same on all systems.
- for c in &mut v {
- if *c == b'\\' {
- *c = b'/';
- }
- }
- Self::Exact(v)
- }
-}
-
-impl From<Regex> for Match {
- fn from(v: Regex) -> Self {
- Self::Regex(v)
- }
-}
-
-/// Replacements to apply to output files.
-pub type Filter = Vec<(Match, &'static [u8])>;
-
-/// Run all tests as described in the config argument.
-/// Will additionally process command line arguments.
-pub fn run_tests(mut config: Config) -> Result<()> {
- let args = Args::test()?;
- if !args.quiet {
- println!("Compiler: {}", config.program.display());
- }
-
- let name = config.root_dir.display().to_string();
-
- let text = if args.quiet {
- status_emitter::Text::quiet()
- } else {
- status_emitter::Text::verbose()
- };
- config.with_args(&args, true);
-
- run_tests_generic(
- vec![config],
- default_file_filter,
- default_per_file_config,
- (text, status_emitter::Gha::<true> { name }),
- )
-}
-
-/// The filter used by `run_tests` to only run on `.rs` files that are
-/// specified by [`Config::filter_files`] and [`Config::skip_files`].
-pub fn default_file_filter(path: &Path, config: &Config) -> bool {
- path.extension().is_some_and(|ext| ext == "rs") && default_any_file_filter(path, config)
-}
-
-/// Run on all files that are specified by [`Config::filter_files`] and
-/// [`Config::skip_files`].
-///
-/// To only include rust files see [`default_file_filter`].
-pub fn default_any_file_filter(path: &Path, config: &Config) -> bool {
- let path = path.display().to_string();
- let contains_path = |files: &[String]| files.iter().any(|f| path.contains(f));
-
- if contains_path(&config.skip_files) {
- return false;
- }
-
- config.filter_files.is_empty() || contains_path(&config.filter_files)
-}
-
-/// The default per-file config used by `run_tests`.
-pub fn default_per_file_config(config: &mut Config, _path: &Path, file_contents: &[u8]) {
- // Heuristic:
- // * if the file contains `#[test]`, automatically pass `--cfg test`.
- // * if the file does not contain `fn main()` or `#[start]`, automatically pass `--crate-type=lib`.
- // This avoids having to spam `fn main() {}` in almost every test.
- if file_contents.find(b"#[proc_macro").is_some() {
- config.program.args.push("--crate-type=proc-macro".into())
- } else if file_contents.find(b"#[test]").is_some() {
- config.program.args.push("--test".into());
- } else if file_contents.find(b"fn main()").is_none()
- && file_contents.find(b"#[start]").is_none()
- {
- config.program.args.push("--crate-type=lib".into());
- }
-}
-
-/// Create a command for running a single file, with the settings from the `config` argument.
-/// Ignores various settings from `Config` that relate to finding test files.
-pub fn test_command(mut config: Config, path: &Path) -> Result<Command> {
- config.fill_host_and_target()?;
- let extra_args = config.build_dependencies()?;
-
- let comments =
- Comments::parse_file(path)?.map_err(|errors| color_eyre::eyre::eyre!("{errors:#?}"))?;
- let mut result = build_command(path, &config, "", &comments).unwrap();
- result.args(extra_args);
-
- Ok(result)
-}
-
-/// The possible non-failure results a single test can have.
-pub enum TestOk {
- /// The test passed
- Ok,
- /// The test was ignored due to a rule (`//@only-*` or `//@ignore-*`)
- Ignored,
- /// The test was filtered with the `file_filter` argument.
- Filtered,
-}
-
-/// The possible results a single test can have.
-pub type TestResult = Result<TestOk, Errored>;
-
-/// Information about a test failure.
-#[derive(Debug)]
-pub struct Errored {
- /// Command that failed
- command: Command,
- /// The errors that were encountered.
- errors: Vec<Error>,
- /// The full stderr of the test run.
- stderr: Vec<u8>,
- /// The full stdout of the test run.
- stdout: Vec<u8>,
-}
-
-struct TestRun {
- result: TestResult,
- status: Box<dyn status_emitter::TestStatus>,
-}
-
-/// A version of `run_tests` that allows more fine-grained control over running tests.
-///
-/// If multiple configs are provided only the first [`Config::threads`] value is used
-pub fn run_tests_generic(
- mut configs: Vec<Config>,
- file_filter: impl Fn(&Path, &Config) -> bool + Sync,
- per_file_config: impl Fn(&mut Config, &Path, &[u8]) + Sync,
- status_emitter: impl StatusEmitter + Send,
-) -> Result<()> {
- for config in &mut configs {
- config.fill_host_and_target()?;
- }
-
- let build_manager = BuildManager::new(&status_emitter);
-
- let mut results = vec![];
-
- let num_threads = match configs.first().and_then(|config| config.threads) {
- Some(threads) => threads,
- None => match std::env::var_os("RUST_TEST_THREADS") {
- Some(n) => n
- .to_str()
- .ok_or_else(|| eyre!("could not parse RUST_TEST_THREADS env var"))?
- .parse()?,
- None => std::thread::available_parallelism()?,
- },
- };
-
- run_and_collect(
- num_threads,
- |submit| {
- let mut todo = VecDeque::new();
- for config in &configs {
- todo.push_back((config.root_dir.clone(), config));
- }
- while let Some((path, config)) = todo.pop_front() {
- if path.is_dir() {
- if path.file_name().unwrap() == "auxiliary" {
- continue;
- }
- // Enqueue everything inside this directory.
- // We want it sorted, to have some control over scheduling of slow tests.
- let mut entries = std::fs::read_dir(path)
- .unwrap()
- .map(|e| e.unwrap().path())
- .collect::<Vec<_>>();
- entries.sort_by(|a, b| a.file_name().cmp(&b.file_name()));
- for entry in entries {
- todo.push_back((entry, config));
- }
- } else if file_filter(&path, config) {
- let status = status_emitter.register_test(path);
- // Forward .rs files to the test workers.
- submit.send((status, config)).unwrap();
- }
- }
- },
- |receive, finished_files_sender| -> Result<()> {
- for (status, config) in receive {
- let path = status.path();
- let file_contents = std::fs::read(path).unwrap();
- let mut config = config.clone();
- per_file_config(&mut config, path, &file_contents);
- let result = match std::panic::catch_unwind(|| {
- parse_and_test_file(&build_manager, &status, config, file_contents)
- }) {
- Ok(Ok(res)) => res,
- Ok(Err(err)) => {
- finished_files_sender.send(TestRun {
- result: Err(err),
- status,
- })?;
- continue;
- }
- Err(err) => {
- finished_files_sender.send(TestRun {
- result: Err(Errored {
- command: Command::new("<unknown>"),
- errors: vec![Error::Bug(
- *Box::<dyn std::any::Any + Send + 'static>::downcast::<String>(
- err,
- )
- .unwrap(),
- )],
- stderr: vec![],
- stdout: vec![],
- }),
- status,
- })?;
- continue;
- }
- };
- for result in result {
- finished_files_sender.send(result)?;
- }
- }
- Ok(())
- },
- |finished_files_recv| {
- for run in finished_files_recv {
- run.status.done(&run.result);
-
- results.push(run);
- }
- },
- )?;
-
- let mut failures = vec![];
- let mut succeeded = 0;
- let mut ignored = 0;
- let mut filtered = 0;
-
- for run in results {
- match run.result {
- Ok(TestOk::Ok) => succeeded += 1,
- Ok(TestOk::Ignored) => ignored += 1,
- Ok(TestOk::Filtered) => filtered += 1,
- Err(errored) => failures.push((run.status, errored)),
- }
- }
-
- let mut failure_emitter = status_emitter.finalize(failures.len(), succeeded, ignored, filtered);
- for (
- status,
- Errored {
- command,
- errors,
- stderr,
- stdout,
- },
- ) in &failures
- {
- let _guard = status.failed_test(command, stderr, stdout);
- failure_emitter.test_failure(status, errors);
- }
-
- if failures.is_empty() {
- Ok(())
- } else {
- Err(eyre!("tests failed"))
- }
-}
-
-/// 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: NonZeroUsize,
- 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.get() {
- 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(
- build_manager: &BuildManager<'_>,
- status: &dyn TestStatus,
- mut config: Config,
- file_contents: Vec<u8>,
-) -> Result<Vec<TestRun>, Errored> {
- let comments = parse_comments(&file_contents)?;
- const EMPTY: &[String] = &[String::new()];
- // Run the test for all revisions
- let revisions = comments.revisions.as_deref().unwrap_or(EMPTY);
- let mut built_deps = false;
- Ok(revisions
- .iter()
- .map(|revision| {
- let status = status.for_revision(revision);
- // Ignore file if only/ignore rules do (not) apply
- if !status.test_file_conditions(&comments, &config) {
- return TestRun {
- result: Ok(TestOk::Ignored),
- status,
- };
- }
-
- if !built_deps {
- status.update_status("waiting for dependencies to finish building".into());
- match build_manager.build(Build::Dependencies, &config) {
- Ok(extra_args) => config.program.args.extend(extra_args),
- Err(err) => {
- return TestRun {
- result: Err(err),
- status,
- }
- }
- }
- status.update_status(String::new());
- built_deps = true;
- }
-
- let result = status.run_test(build_manager, &config, &comments);
- TestRun { result, status }
- })
- .collect())
-}
-
-fn parse_comments(file_contents: &[u8]) -> Result<Comments, Errored> {
- match Comments::parse(file_contents) {
- Ok(comments) => Ok(comments),
- Err(errors) => Err(Errored {
- command: Command::new("parse comments"),
- errors,
- stderr: vec![],
- stdout: vec![],
- }),
- }
-}
-
-fn build_command(
- path: &Path,
- config: &Config,
- revision: &str,
- comments: &Comments,
-) -> Result<Command, Errored> {
- let mut cmd = config.program.build(&config.out_dir);
- cmd.arg(path);
- if !revision.is_empty() {
- cmd.arg(format!("--cfg={revision}"));
- }
- for arg in comments
- .for_revision(revision)
- .flat_map(|r| r.compile_flags.iter())
- {
- cmd.arg(arg);
- }
- let edition = comments.edition(revision, config)?;
-
- if let Some(edition) = edition {
- cmd.arg("--edition").arg(&*edition);
- }
-
- cmd.envs(
- comments
- .for_revision(revision)
- .flat_map(|r| r.env_vars.iter())
- .map(|(k, v)| (k, v)),
- );
-
- Ok(cmd)
-}
-
-fn build_aux(
- aux_file: &Path,
- config: &Config,
- build_manager: &BuildManager<'_>,
-) -> std::result::Result<Vec<OsString>, Errored> {
- let file_contents = std::fs::read(aux_file).map_err(|err| Errored {
- command: Command::new(format!("reading aux file `{}`", aux_file.display())),
- errors: vec![],
- stderr: err.to_string().into_bytes(),
- stdout: vec![],
- })?;
- let comments = parse_comments(&file_contents)?;
- assert_eq!(
- comments.revisions, None,
- "aux builds cannot specify revisions"
- );
-
- let mut config = config.clone();
-
- // Strip any `crate-type` flags from the args, as we need to set our own,
- // and they may conflict (e.g. `lib` vs `proc-macro`);
- let mut prev_was_crate_type = false;
- config.program.args.retain(|arg| {
- if prev_was_crate_type {
- prev_was_crate_type = false;
- return false;
- }
- if arg == "--test" {
- false
- } else if arg == "--crate-type" {
- prev_was_crate_type = true;
- false
- } else if let Some(arg) = arg.to_str() {
- !arg.starts_with("--crate-type=")
- } else {
- true
- }
- });
-
- default_per_file_config(&mut config, aux_file, &file_contents);
-
- // Put aux builds into a separate directory per path so that multiple aux files
- // from different directories (but with the same file name) don't collide.
- let relative = strip_path_prefix(aux_file.parent().unwrap(), &config.out_dir);
-
- config.out_dir.extend(relative);
-
- let mut aux_cmd = build_command(aux_file, &config, "", &comments)?;
-
- let mut extra_args = build_aux_files(
- aux_file.parent().unwrap(),
- &comments,
- "",
- &config,
- build_manager,
- )?;
- // Make sure we see our dependencies
- aux_cmd.args(extra_args.iter());
-
- aux_cmd.arg("--emit=link");
- let filename = aux_file.file_stem().unwrap().to_str().unwrap();
- let output = aux_cmd.output().unwrap();
- if !output.status.success() {
- let error = Error::Command {
- kind: "compilation of aux build failed".to_string(),
- status: output.status,
- };
- return Err(Errored {
- command: aux_cmd,
- errors: vec![error],
- stderr: rustc_stderr::process(aux_file, &output.stderr).rendered,
- stdout: output.stdout,
- });
- }
-
- // Now run the command again to fetch the output filenames
- aux_cmd.arg("--print").arg("file-names");
- let output = aux_cmd.output().unwrap();
- assert!(output.status.success());
-
- for file in output.stdout.lines() {
- let file = std::str::from_utf8(file).unwrap();
- let crate_name = filename.replace('-', "_");
- let path = config.out_dir.join(file);
- extra_args.push("--extern".into());
- let mut cname = OsString::from(&crate_name);
- cname.push("=");
- cname.push(path);
- extra_args.push(cname);
- // Help cargo find the crates added with `--extern`.
- extra_args.push("-L".into());
- extra_args.push(config.out_dir.as_os_str().to_os_string());
- }
- Ok(extra_args)
-}
-
-impl dyn TestStatus {
- fn run_test(
- &self,
- build_manager: &BuildManager<'_>,
- config: &Config,
- comments: &Comments,
- ) -> TestResult {
- let path = self.path();
- let revision = self.revision();
-
- let extra_args = build_aux_files(
- &path.parent().unwrap().join("auxiliary"),
- comments,
- revision,
- config,
- build_manager,
- )?;
-
- let mut cmd = build_command(path, config, revision, comments)?;
- cmd.args(&extra_args);
-
- let (status, stderr, stdout) = self.run_command(&mut cmd);
-
- let mode = config.mode.maybe_override(comments, revision)?;
-
- match *mode {
- Mode::Run { .. } if Mode::Pass.ok(status).is_ok() => {
- return run_test_binary(mode, path, revision, comments, cmd, config)
- }
- Mode::Panic | Mode::Yolo { .. } => {}
- Mode::Run { .. } | Mode::Pass | Mode::Fail { .. } => {
- if status.code() == Some(101) {
- let stderr = String::from_utf8_lossy(&stderr);
- let stdout = String::from_utf8_lossy(&stdout);
- return Err(Errored {
- command: cmd,
- errors: vec![Error::Bug(format!(
- "test panicked: stderr:\n{stderr}\nstdout:\n{stdout}",
- ))],
- stderr: vec![],
- stdout: vec![],
- });
- }
- }
- }
- check_test_result(
- cmd, *mode, path, config, revision, comments, status, &stdout, &stderr,
- )?;
- run_rustfix(
- &stderr, &stdout, path, comments, revision, config, *mode, extra_args,
- )?;
- Ok(TestOk::Ok)
- }
-
- /// Run a command, and if it takes more than 100ms, start appending the last stderr/stdout
- /// line to the current status spinner.
- fn run_command(&self, cmd: &mut Command) -> (ExitStatus, Vec<u8>, Vec<u8>) {
- let output = cmd.output().unwrap_or_else(|err| {
- panic!(
- "could not spawn `{:?}` as a process: {err}",
- cmd.get_program()
- )
- });
-
- (output.status, output.stderr, output.stdout)
- }
-}
-
-fn build_aux_files(
- aux_dir: &Path,
- comments: &Comments,
- revision: &str,
- config: &Config,
- build_manager: &BuildManager<'_>,
-) -> Result<Vec<OsString>, Errored> {
- let mut extra_args = vec![];
- for rev in comments.for_revision(revision) {
- for aux in &rev.aux_builds {
- let line = aux.line();
- let aux = &**aux;
- let aux_file = if aux.starts_with("..") {
- aux_dir.parent().unwrap().join(aux)
- } else {
- aux_dir.join(aux)
- };
- extra_args.extend(
- build_manager
- .build(
- Build::Aux {
- aux_file: strip_path_prefix(
- &aux_file.canonicalize().map_err(|err| Errored {
- command: Command::new(format!(
- "canonicalizing path `{}`",
- aux_file.display()
- )),
- errors: vec![],
- stderr: err.to_string().into_bytes(),
- stdout: vec![],
- })?,
- &std::env::current_dir().unwrap(),
- )
- .collect(),
- },
- config,
- )
- .map_err(
- |Errored {
- command,
- errors,
- stderr,
- stdout,
- }| Errored {
- command,
- errors: vec![Error::Aux {
- path: aux_file,
- errors,
- line,
- }],
- stderr,
- stdout,
- },
- )?,
- );
- }
- }
- Ok(extra_args)
-}
-
-fn run_test_binary(
- mode: MaybeSpanned<Mode>,
- path: &Path,
- revision: &str,
- comments: &Comments,
- mut cmd: Command,
- config: &Config,
-) -> TestResult {
- cmd.arg("--print").arg("file-names");
- let output = cmd.output().unwrap();
- assert!(output.status.success());
-
- let mut files = output.stdout.lines();
- let file = files.next().unwrap();
- assert_eq!(files.next(), None);
- let file = std::str::from_utf8(file).unwrap();
- let exe = config.out_dir.join(file);
- let mut exe = Command::new(exe);
- let output = exe.output().unwrap();
-
- let mut errors = vec![];
-
- check_test_output(
- path,
- &mut errors,
- revision,
- config,
- comments,
- &output.stdout,
- &output.stderr,
- );
-
- errors.extend(mode.ok(output.status).err());
- if errors.is_empty() {
- Ok(TestOk::Ok)
- } else {
- Err(Errored {
- command: exe,
- errors,
- stderr: vec![],
- stdout: vec![],
- })
- }
-}
-
-fn run_rustfix(
- stderr: &[u8],
- stdout: &[u8],
- path: &Path,
- comments: &Comments,
- revision: &str,
- config: &Config,
- mode: Mode,
- extra_args: Vec<OsString>,
-) -> Result<(), Errored> {
- let no_run_rustfix =
- comments.find_one_for_revision(revision, "`no-rustfix` annotations", |r| r.no_rustfix)?;
-
- let global_rustfix = match mode {
- Mode::Pass | Mode::Run { .. } | Mode::Panic => RustfixMode::Disabled,
- Mode::Fail { rustfix, .. } | Mode::Yolo { rustfix } => rustfix,
- };
-
- let fixed_code = (no_run_rustfix.is_none() && global_rustfix.enabled())
- .then_some(())
- .and_then(|()| {
- let suggestions = std::str::from_utf8(stderr)
- .unwrap()
- .lines()
- .flat_map(|line| {
- if !line.starts_with('{') {
- return vec![];
- }
- rustfix::get_suggestions_from_json(
- line,
- &HashSet::new(),
- if global_rustfix == RustfixMode::Everything {
- rustfix::Filter::Everything
- } else {
- rustfix::Filter::MachineApplicableOnly
- },
- )
- .unwrap_or_else(|err| {
- panic!("could not deserialize diagnostics json for rustfix {err}:{line}")
- })
- })
- .collect::<Vec<_>>();
- if suggestions.is_empty() {
- None
- } else {
- Some(rustfix::apply_suggestions(
- &std::fs::read_to_string(path).unwrap(),
- &suggestions,
- ))
- }
- })
- .transpose()
- .map_err(|err| Errored {
- command: Command::new(format!("rustfix {}", path.display())),
- errors: vec![Error::Rustfix(err)],
- stderr: stderr.into(),
- stdout: stdout.into(),
- })?;
-
- let edition = comments.edition(revision, config)?;
- let edition = edition
- .map(|mwl| {
- let line = mwl.span().unwrap_or(Span::INVALID);
- Spanned::new(mwl.into_inner(), line)
- })
- .into();
- let rustfix_comments = Comments {
- revisions: None,
- revisioned: std::iter::once((
- vec![],
- Revisioned {
- span: Span::INVALID,
- ignore: vec![],
- only: vec![],
- stderr_per_bitwidth: false,
- compile_flags: comments
- .for_revision(revision)
- .flat_map(|r| r.compile_flags.iter().cloned())
- .collect(),
- env_vars: comments
- .for_revision(revision)
- .flat_map(|r| r.env_vars.iter().cloned())
- .collect(),
- normalize_stderr: vec![],
- normalize_stdout: vec![],
- error_in_other_files: vec![],
- error_matches: vec![],
- require_annotations_for_level: Default::default(),
- aux_builds: comments
- .for_revision(revision)
- .flat_map(|r| r.aux_builds.iter().cloned())
- .collect(),
- edition,
- mode: OptWithLine::new(Mode::Pass, Span::INVALID),
- no_rustfix: OptWithLine::new((), Span::INVALID),
- needs_asm_support: false,
- },
- ))
- .collect(),
- };
-
- let run = fixed_code.is_some();
- let mut errors = vec![];
- let rustfix_path = check_output(
- // Always check for `.fixed` files, even if there were reasons not to run rustfix.
- // We don't want to leave around stray `.fixed` files
- fixed_code.unwrap_or_default().as_bytes(),
- path,
- &mut errors,
- "fixed",
- &Filter::default(),
- config,
- &rustfix_comments,
- revision,
- );
- if !errors.is_empty() {
- return Err(Errored {
- command: Command::new(format!("checking {}", path.display())),
- errors,
- stderr: vec![],
- stdout: vec![],
- });
- }
-
- if !run {
- return Ok(());
- }
-
- let mut cmd = build_command(&rustfix_path, config, revision, &rustfix_comments)?;
- cmd.args(extra_args);
- // picking the crate name from the file name is problematic when `.revision_name` is inserted
- cmd.arg("--crate-name").arg(
- path.file_stem()
- .unwrap()
- .to_str()
- .unwrap()
- .replace('-', "_"),
- );
- let output = cmd.output().unwrap();
- if output.status.success() {
- Ok(())
- } else {
- Err(Errored {
- command: cmd,
- errors: vec![Error::Command {
- kind: "rustfix".into(),
- status: output.status,
- }],
- stderr: rustc_stderr::process(&rustfix_path, &output.stderr).rendered,
- stdout: output.stdout,
- })
- }
-}
-
-fn revised(revision: &str, extension: &str) -> String {
- if revision.is_empty() {
- extension.to_string()
- } else {
- format!("{revision}.{extension}")
- }
-}
-
-fn check_test_result(
- command: Command,
- mode: Mode,
- path: &Path,
- config: &Config,
- revision: &str,
- comments: &Comments,
- status: ExitStatus,
- stdout: &[u8],
- stderr: &[u8],
-) -> Result<(), Errored> {
- let mut errors = vec![];
- errors.extend(mode.ok(status).err());
- // Always remove annotation comments from stderr.
- let diagnostics = rustc_stderr::process(path, stderr);
- check_test_output(
- path,
- &mut errors,
- revision,
- config,
- comments,
- stdout,
- &diagnostics.rendered,
- );
- // Check error annotations in the source against output
- check_annotations(
- diagnostics.messages,
- diagnostics.messages_from_unknown_file_or_line,
- path,
- &mut errors,
- config,
- revision,
- comments,
- )?;
- if errors.is_empty() {
- Ok(())
- } else {
- Err(Errored {
- command,
- errors,
- stderr: diagnostics.rendered,
- stdout: stdout.into(),
- })
- }
-}
-
-fn check_test_output(
- path: &Path,
- errors: &mut Vec<Error>,
- revision: &str,
- config: &Config,
- comments: &Comments,
- stdout: &[u8],
- stderr: &[u8],
-) {
- // Check output files (if any)
- // Check output files against actual output
- check_output(
- stderr,
- path,
- errors,
- "stderr",
- &config.stderr_filters,
- config,
- comments,
- revision,
- );
- check_output(
- stdout,
- path,
- errors,
- "stdout",
- &config.stdout_filters,
- config,
- comments,
- revision,
- );
-}
-
-fn check_annotations(
- mut messages: Vec<Vec<Message>>,
- mut messages_from_unknown_file_or_line: Vec<Message>,
- path: &Path,
- errors: &mut Errors,
- config: &Config,
- revision: &str,
- comments: &Comments,
-) -> Result<(), Errored> {
- let error_patterns = comments
- .for_revision(revision)
- .flat_map(|r| r.error_in_other_files.iter());
-
- let mut seen_error_match = false;
- for error_pattern in error_patterns {
- seen_error_match = true;
- // first check the diagnostics messages outside of our file. We check this first, so that
- // you can mix in-file annotations with //@error-in-other-file annotations, even if there is overlap
- // in the messages.
- if let Some(i) = messages_from_unknown_file_or_line
- .iter()
- .position(|msg| error_pattern.matches(&msg.message))
- {
- messages_from_unknown_file_or_line.remove(i);
- } else {
- errors.push(Error::PatternNotFound(error_pattern.clone()));
- }
- }
-
- // The order on `Level` is such that `Error` is the highest level.
- // We will ensure that *all* diagnostics of level at least `lowest_annotation_level`
- // are matched.
- let mut lowest_annotation_level = Level::Error;
- for &ErrorMatch {
- ref pattern,
- level,
- line,
- } in comments
- .for_revision(revision)
- .flat_map(|r| r.error_matches.iter())
- {
- seen_error_match = true;
- // If we found a diagnostic with a level annotation, make sure that all
- // diagnostics of that level have annotations, even if we don't end up finding a matching diagnostic
- // for this pattern.
- if lowest_annotation_level > level {
- lowest_annotation_level = level;
- }
-
- if let Some(msgs) = messages.get_mut(line.get()) {
- let found = msgs
- .iter()
- .position(|msg| pattern.matches(&msg.message) && msg.level == level);
- if let Some(found) = found {
- msgs.remove(found);
- continue;
- }
- }
-
- errors.push(Error::PatternNotFound(pattern.clone()));
- }
-
- let required_annotation_level = comments.find_one_for_revision(
- revision,
- "`require_annotations_for_level` annotations",
- |r| r.require_annotations_for_level,
- )?;
-
- let required_annotation_level =
- required_annotation_level.map_or(lowest_annotation_level, |l| *l);
- let filter = |mut msgs: Vec<Message>| -> Vec<_> {
- msgs.retain(|msg| msg.level >= required_annotation_level);
- msgs
- };
-
- let mode = config.mode.maybe_override(comments, revision)?;
-
- if !matches!(config.mode, Mode::Yolo { .. }) {
- let messages_from_unknown_file_or_line = filter(messages_from_unknown_file_or_line);
- if !messages_from_unknown_file_or_line.is_empty() {
- errors.push(Error::ErrorsWithoutPattern {
- path: None,
- msgs: messages_from_unknown_file_or_line,
- });
- }
-
- for (line, msgs) in messages.into_iter().enumerate() {
- let msgs = filter(msgs);
- if !msgs.is_empty() {
- let line = NonZeroUsize::new(line).expect("line 0 is always empty");
- errors.push(Error::ErrorsWithoutPattern {
- path: Some(Spanned::new(
- path.to_path_buf(),
- Span {
- line_start: line,
- ..Span::INVALID
- },
- )),
- msgs,
- });
- }
- }
- }
-
- match (*mode, seen_error_match) {
- (Mode::Pass, true) | (Mode::Panic, true) => errors.push(Error::PatternFoundInPassTest),
- (
- Mode::Fail {
- require_patterns: true,
- ..
- },
- false,
- ) => errors.push(Error::NoPatternsFound),
- _ => {}
- }
- Ok(())
-}
-
-fn check_output(
- output: &[u8],
- path: &Path,
- errors: &mut Errors,
- kind: &'static str,
- filters: &Filter,
- config: &Config,
- comments: &Comments,
- revision: &str,
-) -> PathBuf {
- let target = config.target.as_ref().unwrap();
- let output = normalize(path, output, filters, comments, revision, kind);
- let path = output_path(path, comments, revised(revision, kind), target, revision);
- match &config.output_conflict_handling {
- OutputConflictHandling::Error(bless_command) => {
- let expected_output = std::fs::read(&path).unwrap_or_default();
- if output != expected_output {
- errors.push(Error::OutputDiffers {
- path: path.clone(),
- actual: output.clone(),
- expected: expected_output,
- bless_command: bless_command.clone(),
- });
- }
- }
- OutputConflictHandling::Bless => {
- if output.is_empty() {
- let _ = std::fs::remove_file(&path);
- } else {
- std::fs::write(&path, &output).unwrap();
- }
- }
- OutputConflictHandling::Ignore => {}
- }
- path
-}
-
-fn output_path(
- path: &Path,
- comments: &Comments,
- kind: String,
- target: &str,
- revision: &str,
-) -> PathBuf {
- if comments
- .for_revision(revision)
- .any(|r| r.stderr_per_bitwidth)
- {
- return path.with_extension(format!("{}bit.{kind}", get_pointer_width(target)));
- }
- path.with_extension(kind)
-}
-
-fn test_condition(condition: &Condition, config: &Config) -> bool {
- let target = config.target.as_ref().unwrap();
- match condition {
- Condition::Bitwidth(bits) => get_pointer_width(target) == *bits,
- Condition::Target(t) => target.contains(t),
- Condition::Host(t) => config.host.as_ref().unwrap().contains(t),
- Condition::OnHost => target == config.host.as_ref().unwrap(),
- }
-}
-
-impl dyn TestStatus {
- /// Returns whether according to the in-file conditions, this file should be run.
- fn test_file_conditions(&self, comments: &Comments, config: &Config) -> bool {
- let revision = self.revision();
- if comments
- .for_revision(revision)
- .flat_map(|r| r.ignore.iter())
- .any(|c| test_condition(c, config))
- {
- return false;
- }
- if comments
- .for_revision(revision)
- .any(|r| r.needs_asm_support && !config.has_asm_support())
- {
- return false;
- }
- comments
- .for_revision(revision)
- .flat_map(|r| r.only.iter())
- .all(|c| test_condition(c, config))
- }
-}
-
-// Taken 1:1 from compiletest-rs
-fn get_pointer_width(triple: &str) -> u8 {
- if (triple.contains("64") && !triple.ends_with("gnux32") && !triple.ends_with("gnu_ilp32"))
- || triple.starts_with("s390x")
- {
- 64
- } else if triple.starts_with("avr") {
- 16
- } else {
- 32
- }
-}
-
-fn normalize(
- path: &Path,
- text: &[u8],
- filters: &Filter,
- comments: &Comments,
- revision: &str,
- kind: &'static str,
-) -> Vec<u8> {
- // Useless paths
- let path_filter = (Match::from(path.parent().unwrap()), b"$DIR" as &[u8]);
- let filters = filters.iter().chain(std::iter::once(&path_filter));
- let mut text = text.to_owned();
- if let Some(lib_path) = option_env!("RUSTC_LIB_PATH") {
- text = text.replace(lib_path, "RUSTLIB");
- }
-
- for (rule, replacement) in filters {
- text = rule.replace_all(&text, replacement).into_owned();
- }
-
- for (from, to) in comments.for_revision(revision).flat_map(|r| match kind {
- "fixed" => &[] as &[_],
- "stderr" => &r.normalize_stderr,
- "stdout" => &r.normalize_stdout,
- _ => unreachable!(),
- }) {
- text = from.replace_all(&text, to).into_owned();
- }
- text
-}
-/// Remove the common prefix of this path and the `root_dir`.
-fn strip_path_prefix<'a>(path: &'a Path, prefix: &Path) -> impl Iterator<Item = Component<'a>> {
- let mut components = path.components();
- for c in prefix.components() {
- // Windows has some funky paths. This is probably wrong, but works well in practice.
- let deverbatimize = |c| match c {
- Component::Prefix(prefix) => Err(match prefix.kind() {
- Prefix::VerbatimUNC(a, b) => Prefix::UNC(a, b),
- Prefix::VerbatimDisk(d) => Prefix::Disk(d),
- other => other,
- }),
- c => Ok(c),
- };
- let c2 = components.next();
- if Some(deverbatimize(c)) == c2.map(deverbatimize) {
- continue;
- }
- return c2.into_iter().chain(components);
- }
- None.into_iter().chain(components)
-}
diff --git a/vendor/ui_test-0.20.0/src/mode.rs b/vendor/ui_test-0.20.0/src/mode.rs
deleted file mode 100644
index ce37adc4c..000000000
--- a/vendor/ui_test-0.20.0/src/mode.rs
+++ /dev/null
@@ -1,93 +0,0 @@
-use super::Error;
-use crate::parser::Comments;
-use crate::parser::MaybeSpanned;
-use crate::Errored;
-use std::fmt::Display;
-use std::process::ExitStatus;
-
-/// When to run rustfix on tests
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum RustfixMode {
- /// Do not run rustfix on the test
- Disabled,
- /// Apply only `MachineApplicable` suggestions emitted by the test
- MachineApplicable,
- /// Apply all suggestions emitted by the test
- Everything,
-}
-
-impl RustfixMode {
- pub(crate) fn enabled(self) -> bool {
- self != RustfixMode::Disabled
- }
-}
-
-#[derive(Copy, Clone, Debug)]
-/// Decides what is expected of each test's exit status.
-pub enum Mode {
- /// The test passes a full execution of the rustc driver
- Pass,
- /// The test produces an executable binary that can get executed on the host
- Run {
- /// The expected exit code
- exit_code: i32,
- },
- /// The rustc driver panicked
- Panic,
- /// The rustc driver emitted an error
- Fail {
- /// Whether failing tests must have error patterns. Set to false if you just care about .stderr output.
- require_patterns: bool,
- /// When to run rustfix on the test
- rustfix: RustfixMode,
- },
- /// Run the tests, but always pass them as long as all annotations are satisfied and stderr files match.
- Yolo {
- /// When to run rustfix on the test
- rustfix: RustfixMode,
- },
-}
-
-impl Mode {
- pub(crate) fn ok(self, status: ExitStatus) -> Result<(), Error> {
- let expected = match self {
- Mode::Run { exit_code } => exit_code,
- Mode::Pass => 0,
- Mode::Panic => 101,
- Mode::Fail { .. } => 1,
- Mode::Yolo { .. } => return Ok(()),
- };
- if status.code() == Some(expected) {
- Ok(())
- } else {
- Err(Error::ExitStatus {
- mode: self,
- status,
- expected,
- })
- }
- }
- pub(crate) fn maybe_override(
- self,
- comments: &Comments,
- revision: &str,
- ) -> Result<MaybeSpanned<Self>, Errored> {
- let mode = comments.find_one_for_revision(revision, "mode changes", |r| r.mode)?;
- Ok(mode.map_or(MaybeSpanned::new_config(self), Into::into))
- }
-}
-
-impl Display for Mode {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- match self {
- Mode::Run { exit_code } => write!(f, "run({exit_code})"),
- Mode::Pass => write!(f, "pass"),
- Mode::Panic => write!(f, "panic"),
- Mode::Fail {
- require_patterns: _,
- rustfix: _,
- } => write!(f, "fail"),
- Mode::Yolo { rustfix: _ } => write!(f, "yolo"),
- }
- }
-}
diff --git a/vendor/ui_test-0.20.0/src/parser.rs b/vendor/ui_test-0.20.0/src/parser.rs
deleted file mode 100644
index 62ee5a1d1..000000000
--- a/vendor/ui_test-0.20.0/src/parser.rs
+++ /dev/null
@@ -1,822 +0,0 @@
-use std::{
- collections::HashMap,
- num::NonZeroUsize,
- path::{Path, PathBuf},
- process::Command,
-};
-
-use bstr::{ByteSlice, Utf8Error};
-use regex::bytes::Regex;
-
-use crate::{
- rustc_stderr::{Level, Span},
- Error, Errored, Mode,
-};
-
-use color_eyre::eyre::{Context, Result};
-
-pub(crate) use spanned::*;
-
-mod spanned;
-#[cfg(test)]
-mod tests;
-
-/// This crate supports various magic comments that get parsed as file-specific
-/// configuration values. This struct parses them all in one go and then they
-/// get processed by their respective use sites.
-#[derive(Default, Debug)]
-pub(crate) struct Comments {
- /// 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![]`
- pub revisioned: HashMap<Vec<String>, Revisioned>,
-}
-
-impl Comments {
- /// Check that a comment isn't specified twice across multiple differently revisioned statements.
- /// e.g. `//@[foo, bar] error-in-other-file: bop` and `//@[foo, baz] error-in-other-file boop` would end up
- /// specifying two error patterns that are available in revision `foo`.
- pub fn find_one_for_revision<'a, T: 'a>(
- &'a self,
- revision: &'a str,
- kind: &str,
- f: impl Fn(&'a Revisioned) -> OptWithLine<T>,
- ) -> Result<OptWithLine<T>, Errored> {
- let mut result = None;
- let mut errors = vec![];
- for rev in self.for_revision(revision) {
- if let Some(found) = f(rev).into_inner() {
- if result.is_some() {
- errors.push(found.line());
- } else {
- result = found.into();
- }
- }
- }
- if errors.is_empty() {
- Ok(result.into())
- } else {
- Err(Errored {
- command: Command::new(format!("<finding flags for revision `{revision}`>")),
- errors: vec![Error::MultipleRevisionsWithResults {
- kind: kind.to_string(),
- lines: errors,
- }],
- stderr: vec![],
- stdout: vec![],
- })
- }
- }
-
- /// Returns an iterator over all revisioned comments that match the revision.
- pub fn for_revision<'a>(&'a self, revision: &'a str) -> impl Iterator<Item = &'a Revisioned> {
- self.revisioned.iter().filter_map(move |(k, v)| {
- if k.is_empty() || k.iter().any(|rev| rev == revision) {
- Some(v)
- } else {
- None
- }
- })
- }
-
- pub(crate) fn edition(
- &self,
- revision: &str,
- config: &crate::Config,
- ) -> Result<Option<MaybeSpanned<String>>, Errored> {
- let edition =
- self.find_one_for_revision(revision, "`edition` annotations", |r| r.edition.clone())?;
- let edition = edition
- .into_inner()
- .map(MaybeSpanned::from)
- .or(config.edition.clone().map(MaybeSpanned::new_config));
- Ok(edition)
- }
-}
-
-#[derive(Debug)]
-/// Comments that can be filtered for specific revisions.
-pub(crate) struct Revisioned {
- /// The character range in which this revisioned item was first added.
- /// Used for reporting errors on unknown revisions.
- pub span: Span,
- /// 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
- pub only: Vec<Condition>,
- /// Generate one .stderr file per bit width, by prepending with `.64bit` and similar
- pub stderr_per_bitwidth: bool,
- /// Additional flags to pass to the executable
- pub compile_flags: Vec<String>,
- /// Additional env vars to set for the executable
- pub env_vars: Vec<(String, String)>,
- /// Normalizations to apply to the stderr output before emitting it to disk
- pub normalize_stderr: Vec<(Regex, Vec<u8>)>,
- /// Normalizations to apply to the stdout output before emitting it to disk
- pub normalize_stdout: Vec<(Regex, Vec<u8>)>,
- /// Arbitrary patterns to look for in the stderr.
- /// The error must be from another file, as errors from the current file must be
- /// checked via `error_matches`.
- pub error_in_other_files: Vec<Spanned<Pattern>>,
- pub error_matches: Vec<ErrorMatch>,
- /// Ignore diagnostics below this level.
- /// `None` means pick the lowest level from the `error_pattern`s.
- pub require_annotations_for_level: OptWithLine<Level>,
- pub aux_builds: Vec<Spanned<PathBuf>>,
- pub edition: OptWithLine<String>,
- /// Overwrites the mode from `Config`.
- pub mode: OptWithLine<Mode>,
- pub needs_asm_support: bool,
- /// Don't run [`rustfix`] for this test
- pub no_rustfix: OptWithLine<()>,
-}
-
-#[derive(Debug)]
-struct CommentParser<T> {
- /// The comments being built.
- comments: T,
- /// Any errors that ocurred during comment parsing.
- errors: Vec<Error>,
- /// The available commands and their parsing logic
- commands: HashMap<&'static str, CommandParserFunc>,
-}
-
-type CommandParserFunc = fn(&mut CommentParser<&mut Revisioned>, args: Spanned<&str>, span: Span);
-
-impl<T> std::ops::Deref for CommentParser<T> {
- type Target = T;
-
- fn deref(&self) -> &Self::Target {
- &self.comments
- }
-}
-
-impl<T> std::ops::DerefMut for CommentParser<T> {
- fn deref_mut(&mut self) -> &mut Self::Target {
- &mut self.comments
- }
-}
-
-/// The conditions used for "ignore" and "only" filters.
-#[derive(Debug)]
-pub(crate) enum Condition {
- /// The given string must appear in the host triple.
- Host(String),
- /// The given string must appear in the target triple.
- Target(String),
- /// Tests that the bitwidth is the given one.
- Bitwidth(u8),
- /// Tests that the target is the host.
- OnHost,
-}
-
-#[derive(Debug, Clone)]
-/// An error pattern parsed from a `//~` comment.
-pub enum Pattern {
- SubString(String),
- Regex(Regex),
-}
-
-#[derive(Debug)]
-pub(crate) struct ErrorMatch {
- pub pattern: Spanned<Pattern>,
- pub level: Level,
- /// The line this pattern is expecting to find a message in.
- pub line: NonZeroUsize,
-}
-
-impl Condition {
- fn parse(c: &str) -> std::result::Result<Self, String> {
- if c == "on-host" {
- Ok(Condition::OnHost)
- } else if let Some(bits) = c.strip_suffix("bit") {
- let bits: u8 = bits.parse().map_err(|_err| {
- format!("invalid ignore/only filter ending in 'bit': {c:?} is not a valid bitwdith")
- })?;
- Ok(Condition::Bitwidth(bits))
- } else if let Some(triple_substr) = c.strip_prefix("target-") {
- Ok(Condition::Target(triple_substr.to_owned()))
- } else if let Some(triple_substr) = c.strip_prefix("host-") {
- Ok(Condition::Host(triple_substr.to_owned()))
- } else {
- Err(format!(
- "`{c}` is not a valid condition, expected `on-host`, /[0-9]+bit/, /host-.*/, or /target-.*/"
- ))
- }
- }
-}
-
-impl Comments {
- pub(crate) fn parse_file(path: &Path) -> Result<std::result::Result<Self, Vec<Error>>> {
- let content =
- std::fs::read(path).wrap_err_with(|| format!("failed to read {}", path.display()))?;
- Ok(Self::parse(&content))
- }
-
- /// Parse comments in `content`.
- /// `path` is only used to emit diagnostics if parsing fails.
- pub(crate) fn parse(
- content: &(impl AsRef<[u8]> + ?Sized),
- ) -> std::result::Result<Self, Vec<Error>> {
- let mut parser = CommentParser {
- comments: Comments::default(),
- errors: vec![],
- commands: CommentParser::<_>::commands(),
- };
-
- let mut fallthrough_to = None; // The line that a `|` will refer to.
- for (l, line) in content.as_ref().lines().enumerate() {
- let l = NonZeroUsize::new(l + 1).unwrap(); // enumerate starts at 0, but line numbers start at 1
- let span = Span {
- line_start: l,
- line_end: l,
- column_start: NonZeroUsize::new(1).unwrap(),
- column_end: NonZeroUsize::new(line.chars().count() + 1).unwrap(),
- };
- match parser.parse_checked_line(&mut fallthrough_to, Spanned::new(line, span)) {
- Ok(()) => {}
- Err(e) => parser.error(span, format!("Comment is not utf8: {e:?}")),
- }
- }
- 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"),
- span: revisioned.span,
- })
- }
- }
- }
- } 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(),
- span: revisioned.span,
- })
- }
- }
- }
- if parser.errors.is_empty() {
- Ok(parser.comments)
- } else {
- Err(parser.errors)
- }
- }
-}
-
-impl CommentParser<Comments> {
- fn parse_checked_line(
- &mut self,
- fallthrough_to: &mut Option<NonZeroUsize>,
- line: Spanned<&[u8]>,
- ) -> std::result::Result<(), Utf8Error> {
- if let Some(command) = line.strip_prefix(b"//@") {
- self.parse_command(command.to_str()?.trim())
- } else if let Some((_, pattern)) = line.split_once_str("//~") {
- let (revisions, pattern) = self.parse_revisions(pattern.to_str()?);
- self.revisioned(revisions, |this| {
- this.parse_pattern(pattern, fallthrough_to)
- })
- } else {
- *fallthrough_to = None;
- for pos in line.find_iter("//") {
- let (_, rest) = line.to_str()?.split_at(pos + 2);
- for rest in std::iter::once(rest).chain(rest.strip_prefix(" ")) {
- if let Some('@' | '~' | '[' | ']' | '^' | '|') = rest.chars().next() {
- self.error(
- rest.span(),
- format!(
- "comment looks suspiciously like a test suite command: `{}`\n\
- All `//@` test suite commands must be at the start of the line.\n\
- The `//` must be directly followed by `@` or `~`.",
- *rest,
- ),
- );
- } else {
- let mut parser = Self {
- errors: vec![],
- comments: Comments::default(),
- commands: std::mem::take(&mut self.commands),
- };
- parser.parse_command(rest);
- if parser.errors.is_empty() {
- self.error(
- rest.span(),
- "a compiletest-rs style comment was detected.\n\
- Please use text that could not also be interpreted as a command,\n\
- and prefix all actual commands with `//@`",
- );
- }
- self.commands = parser.commands;
- }
- }
- }
- }
- Ok(())
- }
-}
-
-impl<CommentsType> CommentParser<CommentsType> {
- fn error(&mut self, span: Span, s: impl Into<String>) {
- self.errors.push(Error::InvalidComment {
- msg: s.into(),
- span,
- });
- }
-
- fn check(&mut self, span: Span, cond: bool, s: impl Into<String>) {
- if !cond {
- self.error(span, s);
- }
- }
-
- fn check_some<T>(&mut self, span: Span, opt: Option<T>, s: impl Into<String>) -> Option<T> {
- self.check(span, opt.is_some(), s);
- opt
- }
-}
-
-impl CommentParser<Comments> {
- fn parse_command(&mut self, command: Spanned<&str>) {
- let (revisions, command) = self.parse_revisions(command);
-
- // Commands are letters or dashes, grab everything until the first character that is neither of those.
- let (command, args) = match command
- .char_indices()
- .find_map(|(i, c)| (!c.is_alphanumeric() && c != '-' && c != '_').then_some(i))
- {
- None => (command, Spanned::new("", command.span().shrink_to_end())),
- Some(i) => {
- let (command, args) = command.split_at(i);
- // Commands are separated from their arguments by ':' or ' '
- let next = args
- .chars()
- .next()
- .expect("the `position` above guarantees that there is at least one char");
- self.check(
- args.span().shrink_to_start(),
- next == ':',
- "test command must be followed by `:` (or end the line)",
- );
- (command, args.split_at(next.len_utf8()).1.trim())
- }
- };
-
- if *command == "revisions" {
- self.check(
- revisions.span(),
- revisions.is_empty(),
- "revisions cannot be declared under a revision",
- );
- self.check(
- revisions.span(),
- self.revisions.is_none(),
- "cannot specify `revisions` twice",
- );
- self.revisions = Some(args.split_whitespace().map(|s| s.to_string()).collect());
- return;
- }
- self.revisioned(revisions, |this| this.parse_command(command, args));
- }
-
- fn revisioned(
- &mut self,
- revisions: Spanned<Vec<String>>,
- f: impl FnOnce(&mut CommentParser<&mut Revisioned>),
- ) {
- let span = revisions.span();
- let revisions = revisions.into_inner();
- let mut this = CommentParser {
- errors: std::mem::take(&mut self.errors),
- commands: std::mem::take(&mut self.commands),
- comments: self
- .revisioned
- .entry(revisions)
- .or_insert_with(|| Revisioned {
- span,
- ignore: Default::default(),
- only: Default::default(),
- stderr_per_bitwidth: Default::default(),
- compile_flags: Default::default(),
- env_vars: Default::default(),
- normalize_stderr: Default::default(),
- normalize_stdout: Default::default(),
- error_in_other_files: Default::default(),
- error_matches: Default::default(),
- require_annotations_for_level: Default::default(),
- aux_builds: Default::default(),
- edition: Default::default(),
- mode: Default::default(),
- needs_asm_support: Default::default(),
- no_rustfix: Default::default(),
- }),
- };
- f(&mut this);
- let CommentParser {
- errors, commands, ..
- } = this;
- self.commands = commands;
- self.errors = errors;
- }
-}
-
-impl CommentParser<&mut Revisioned> {
- fn parse_normalize_test(
- &mut self,
- args: Spanned<&str>,
- mode: &str,
- ) -> Option<(Regex, Vec<u8>)> {
- let (from, rest) = self.parse_str(args);
-
- let to = match rest.strip_prefix("->") {
- Some(v) => v,
- None => {
- self.error(
- rest.span(),
- format!(
- "normalize-{mode}-test needs a pattern and replacement separated by `->`"
- ),
- );
- return None;
- }
- }
- .trim_start();
- let (to, rest) = self.parse_str(to);
-
- self.check(
- rest.span(),
- rest.is_empty(),
- "trailing text after pattern replacement",
- );
-
- let regex = self.parse_regex(from)?;
- Some((regex, to.as_bytes().to_owned()))
- }
-
- fn commands() -> HashMap<&'static str, CommandParserFunc> {
- let mut commands = HashMap::<_, CommandParserFunc>::new();
- macro_rules! commands {
- ($($name:expr => ($this:ident, $args:ident, $span:ident)$block:block)*) => {
- $(commands.insert($name, |$this, $args, $span| {
- $block
- });)*
- };
- }
- commands! {
- "compile-flags" => (this, args, _span){
- if let Some(parsed) = comma::parse_command(*args) {
- this.compile_flags.extend(parsed);
- } else {
- this.error(args.span(), format!("`{}` contains an unclosed quotation mark", *args));
- }
- }
- "rustc-env" => (this, args, _span){
- for env in args.split_whitespace() {
- if let Some((k, v)) = this.check_some(
- args.span(),
- env.split_once('='),
- "environment variables must be key/value pairs separated by a `=`",
- ) {
- this.env_vars.push((k.to_string(), v.to_string()));
- }
- }
- }
- "normalize-stderr-test" => (this, args, _span){
- if let Some(res) = this.parse_normalize_test(args, "stderr") {
- this.normalize_stderr.push(res)
- }
- }
- "normalize-stdout-test" => (this, args, _span){
- if let Some(res) = this.parse_normalize_test(args, "stdout") {
- this.normalize_stdout.push(res)
- }
- }
- "error-pattern" => (this, _args, span){
- this.error(span, "`error-pattern` has been renamed to `error-in-other-file`");
- }
- "error-in-other-file" => (this, args, _span){
- let args = args.trim();
- let pat = this.parse_error_pattern(args);
- this.error_in_other_files.push(pat);
- }
- "stderr-per-bitwidth" => (this, _args, span){
- // args are ignored (can be used as comment)
- this.check(
- span,
- !this.stderr_per_bitwidth,
- "cannot specify `stderr-per-bitwidth` twice",
- );
- this.stderr_per_bitwidth = true;
- }
- "run-rustfix" => (this, _args, span){
- this.error(span, "rustfix is now ran by default when applicable suggestions are found");
- }
- "no-rustfix" => (this, _args, span){
- // args are ignored (can be used as comment)
- let prev = this.no_rustfix.set((), span);
- this.check(
- span,
- prev.is_none(),
- "cannot specify `no-rustfix` twice",
- );
- }
- "needs-asm-support" => (this, _args, span){
- // args are ignored (can be used as comment)
- this.check(
- span,
- !this.needs_asm_support,
- "cannot specify `needs-asm-support` twice",
- );
- this.needs_asm_support = true;
- }
- "aux-build" => (this, args, _span){
- let name = match args.split_once(":") {
- Some((name, rest)) => {
- this.error(rest.span(), "proc macros are now auto-detected, you can remove the `:proc-macro` after the file name");
- name
- },
- None => args,
- };
- this.aux_builds.push(name.map(Into::into));
- }
- "edition" => (this, args, span){
- let prev = this.edition.set((*args).into(), args.span());
- this.check(span, prev.is_none(), "cannot specify `edition` twice");
- }
- "check-pass" => (this, _args, span){
- let prev = this.mode.set(Mode::Pass, span);
- // args are ignored (can be used as comment)
- this.check(
- span,
- prev.is_none(),
- "cannot specify test mode changes twice",
- );
- }
- "run" => (this, args, span){
- this.check(
- span,
- this.mode.is_none(),
- "cannot specify test mode changes twice",
- );
- let mut set = |exit_code| this.mode.set(Mode::Run { exit_code }, args.span());
- if args.is_empty() {
- set(0);
- } else {
- match args.parse() {
- Ok(exit_code) => {set(exit_code);},
- Err(err) => this.error(args.span(), err.to_string()),
- }
- }
- }
- "require-annotations-for-level" => (this, args, span){
- let args = args.trim();
- let prev = match args.parse() {
- Ok(it) => this.require_annotations_for_level.set(it, args.span()),
- Err(msg) => {
- this.error(args.span(), msg);
- None
- },
- };
-
- this.check(
- span,
- prev.is_none(),
- "cannot specify `require-annotations-for-level` twice",
- );
- }
- }
- commands
- }
-
- fn parse_command(&mut self, command: Spanned<&str>, args: Spanned<&str>) {
- if let Some(command_handler) = self.commands.get(*command) {
- command_handler(self, args, command.span());
- } else if let Some(s) = command.strip_prefix("ignore-") {
- // args are ignored (can be used as comment)
- match Condition::parse(*s) {
- Ok(cond) => self.ignore.push(cond),
- Err(msg) => self.error(s.span(), msg),
- }
- } else if let Some(s) = command.strip_prefix("only-") {
- // args are ignored (can be used as comment)
- match Condition::parse(*s) {
- Ok(cond) => self.only.push(cond),
- Err(msg) => self.error(s.span(), msg),
- }
- } else {
- let best_match = self
- .commands
- .keys()
- .min_by_key(|key| levenshtein::levenshtein(key, *command))
- .unwrap();
- self.error(
- command.span(),
- format!(
- "`{}` is not a command known to `ui_test`, did you mean `{best_match}`?",
- *command
- ),
- );
- }
- }
-}
-
-impl<CommentsType> CommentParser<CommentsType> {
- fn parse_regex(&mut self, regex: Spanned<&str>) -> Option<Regex> {
- match Regex::new(*regex) {
- Ok(regex) => Some(regex),
- Err(err) => {
- self.error(regex.span(), format!("invalid regex: {err:?}"));
- None
- }
- }
- }
-
- /// Parses a string literal. `s` has to start with `"`; everything until the next `"` is
- /// returned in the first component. `\` can be used to escape arbitrary character.
- /// Second return component is the rest of the string with leading whitespace removed.
- fn parse_str<'a>(&mut self, s: Spanned<&'a str>) -> (Spanned<&'a str>, Spanned<&'a str>) {
- match s.strip_prefix("\"") {
- Some(s) => {
- let mut escaped = false;
- for (i, c) in s.char_indices() {
- if escaped {
- // Accept any character as literal after a `\`.
- escaped = false;
- } else if c == '"' {
- let (a, b) = s.split_at(i);
- let b = b.split_at(1).1;
- return (a, b.trim_start());
- } else {
- escaped = c == '\\';
- }
- }
- self.error(s.span(), format!("no closing quotes found for {}", *s));
- (s, Spanned::new("", s.span()))
- }
- None => {
- if s.is_empty() {
- self.error(s.span(), "expected quoted string, but found end of line")
- } else {
- self.error(
- s.span(),
- format!("expected `\"`, got `{}`", s.chars().next().unwrap()),
- )
- }
- (s, Spanned::new("", s.span()))
- }
- }
- }
-
- // parse something like \[[a-z]+(,[a-z]+)*\]
- fn parse_revisions<'a>(
- &mut self,
- pattern: Spanned<&'a str>,
- ) -> (Spanned<Vec<String>>, Spanned<&'a str>) {
- match pattern.strip_prefix("[") {
- Some(s) => {
- // revisions
- let end = s.char_indices().find_map(|(i, c)| match c {
- ']' => Some(i),
- _ => None,
- });
- let Some(end) = end else {
- self.error(s.span(), "`[` without corresponding `]`");
- return (
- Spanned::new(vec![], pattern.span().shrink_to_start()),
- pattern,
- );
- };
- let (revision, pattern) = s.split_at(end);
- let revisions = revision.split(',').map(|s| s.trim().to_string()).collect();
- (
- Spanned::new(revisions, revision.span()),
- // 1.. because `split_at` includes the separator
- pattern.split_at(1).1.trim_start(),
- )
- }
- _ => (
- Spanned::new(vec![], pattern.span().shrink_to_start()),
- pattern,
- ),
- }
- }
-}
-
-impl CommentParser<&mut Revisioned> {
- // parse something like (\[[a-z]+(,[a-z]+)*\])?(?P<offset>\||[\^]+)? *(?P<level>ERROR|HELP|WARN|NOTE): (?P<text>.*)
- fn parse_pattern(&mut self, pattern: Spanned<&str>, fallthrough_to: &mut Option<NonZeroUsize>) {
- let (match_line, pattern) = match pattern.chars().next() {
- Some('|') => (
- match fallthrough_to {
- Some(fallthrough) => *fallthrough,
- None => {
- self.error(pattern.span(), "`//~|` pattern without preceding line");
- return;
- }
- },
- pattern.split_at(1).1,
- ),
- Some('^') => {
- let offset = pattern.chars().take_while(|&c| c == '^').count();
- match pattern
- .span()
- .line_start
- .get()
- .checked_sub(offset)
- .and_then(NonZeroUsize::new)
- {
- // lines are one-indexed, so a target line of 0 is invalid, but also
- // prevented via `NonZeroUsize`
- Some(match_line) => (match_line, pattern.split_at(offset).1),
- _ => {
- self.error(pattern.span(), format!(
- "//~^ pattern is trying to refer to {} lines above, but there are only {} lines above",
- offset,
- pattern.line().get() - 1,
- ));
- return;
- }
- }
- }
- Some(_) => (pattern.span().line_start, pattern),
- None => {
- self.error(pattern.span(), "no pattern specified");
- return;
- }
- };
-
- let pattern = pattern.trim_start();
- let offset = match pattern.chars().position(|c| !c.is_ascii_alphabetic()) {
- Some(offset) => offset,
- None => {
- self.error(pattern.span(), "pattern without level");
- return;
- }
- };
-
- let (level, pattern) = pattern.split_at(offset);
- let level = match (*level).parse() {
- Ok(level) => level,
- Err(msg) => {
- self.error(level.span(), msg);
- return;
- }
- };
- let pattern = match pattern.strip_prefix(":") {
- Some(offset) => offset,
- None => {
- self.error(pattern.span(), "no `:` after level found");
- return;
- }
- };
-
- let pattern = pattern.trim();
-
- self.check(pattern.span(), !pattern.is_empty(), "no pattern specified");
-
- let pattern = self.parse_error_pattern(pattern);
-
- *fallthrough_to = Some(match_line);
-
- self.error_matches.push(ErrorMatch {
- pattern,
- level,
- line: match_line,
- });
- }
-}
-
-impl Pattern {
- pub(crate) fn matches(&self, message: &str) -> bool {
- match self {
- Pattern::SubString(s) => message.contains(s),
- Pattern::Regex(r) => r.is_match(message.as_bytes()),
- }
- }
-}
-
-impl<CommentsType> CommentParser<CommentsType> {
- fn parse_error_pattern(&mut self, pattern: Spanned<&str>) -> Spanned<Pattern> {
- if let Some(regex) = pattern.strip_prefix("/") {
- match regex.strip_suffix("/") {
- Some(regex) => match self.parse_regex(regex) {
- Some(r) => Spanned::new(Pattern::Regex(r), regex.span()),
- None => Spanned::new(Pattern::SubString(pattern.to_string()), regex.span()),
- },
- None => {
- self.error(
- regex.span(),
- "expected regex pattern due to leading `/`, but found no closing `/`",
- );
- Spanned::new(Pattern::SubString(pattern.to_string()), regex.span())
- }
- }
- } else {
- Spanned::new(Pattern::SubString(pattern.to_string()), pattern.span())
- }
- }
-}
diff --git a/vendor/ui_test-0.20.0/src/parser/spanned.rs b/vendor/ui_test-0.20.0/src/parser/spanned.rs
deleted file mode 100644
index 8c5f98ecd..000000000
--- a/vendor/ui_test-0.20.0/src/parser/spanned.rs
+++ /dev/null
@@ -1,264 +0,0 @@
-use std::num::NonZeroUsize;
-
-use bstr::{ByteSlice, Utf8Error};
-
-use crate::rustc_stderr::Span;
-
-#[derive(Default, Debug, Clone, Copy)]
-pub struct MaybeSpanned<T> {
- data: T,
- span: Option<Span>,
-}
-
-impl<T> std::ops::Deref for MaybeSpanned<T> {
- type Target = T;
-
- fn deref(&self) -> &Self::Target {
- &self.data
- }
-}
-
-impl<T> MaybeSpanned<T> {
- /// Values from the `Config` struct don't have lines.
- pub fn new_config(data: T) -> Self {
- Self { data, span: None }
- }
-
- pub fn span(&self) -> Option<Span> {
- self.span
- }
-
- pub fn into_inner(self) -> T {
- self.data
- }
-}
-
-impl<T> From<Spanned<T>> for MaybeSpanned<T> {
- fn from(value: Spanned<T>) -> Self {
- Self {
- data: value.data,
- span: Some(value.span),
- }
- }
-}
-
-#[derive(Debug, Clone, Copy)]
-pub struct Spanned<T> {
- data: T,
- span: Span,
-}
-
-impl<T> std::ops::Deref for Spanned<T> {
- type Target = T;
-
- fn deref(&self) -> &Self::Target {
- &self.data
- }
-}
-
-impl<'a> Spanned<&'a str> {
- pub fn strip_prefix(&self, prefix: &str) -> Option<Self> {
- let data = self.data.strip_prefix(prefix)?;
- let mut span = self.span;
- span.column_start =
- NonZeroUsize::new(span.column_start.get() + prefix.chars().count()).unwrap();
- Some(Self { span, data })
- }
-
- pub fn strip_suffix(&self, suffix: &str) -> Option<Self> {
- let data = self.data.strip_suffix(suffix)?;
- let mut span = self.span;
- span.column_end =
- NonZeroUsize::new(span.column_end.get() - suffix.chars().count()).unwrap();
- Some(Self { span, data })
- }
-
- pub fn trim_start(&self) -> Self {
- let data = self.data.trim_start();
- let mut span = self.span;
- span.column_start = NonZeroUsize::new(
- span.column_start.get() + self.data.chars().count() - data.chars().count(),
- )
- .unwrap();
- Self { data, span }
- }
-
- pub fn trim_end(&self) -> Self {
- let data = self.data.trim_end();
- let mut span = self.span;
- span.column_end = NonZeroUsize::new(
- span.column_end.get() - (self.data.chars().count() - data.chars().count()),
- )
- .unwrap();
- Self { data, span }
- }
-
- pub fn trim(&self) -> Self {
- self.trim_start().trim_end()
- }
-
- pub fn split_at(&self, i: usize) -> (Self, Self) {
- let (a, b) = self.data.split_at(i);
- (
- Self {
- data: a,
- span: Span {
- column_end: NonZeroUsize::new(self.span.column_start.get() + a.chars().count())
- .unwrap(),
- ..self.span
- },
- },
- Self {
- data: b,
- span: Span {
- column_start: NonZeroUsize::new(
- self.span.column_start.get() + a.chars().count(),
- )
- .unwrap(),
- ..self.span
- },
- },
- )
- }
-
- pub fn split_once(&self, splitter: &str) -> Option<(Self, Self)> {
- let (a, b) = self.data.split_once(splitter)?;
- Some((
- Self {
- data: a,
- span: Span {
- column_end: NonZeroUsize::new(self.span.column_start.get() + a.chars().count())
- .unwrap(),
- ..self.span
- },
- },
- Self {
- data: b,
- span: Span {
- column_start: NonZeroUsize::new(
- self.span.column_start.get() + a.chars().count() + splitter.chars().count(),
- )
- .unwrap(),
- ..self.span
- },
- },
- ))
- }
-}
-
-impl<'a> Spanned<&'a [u8]> {
- pub fn strip_prefix(&self, prefix: &[u8]) -> Option<Self> {
- let data = self.data.strip_prefix(prefix)?;
- let mut span = self.span;
- span.column_start = NonZeroUsize::new(span.column_start.get() + prefix.len()).unwrap();
- Some(Self { span, data })
- }
-
- pub fn split_once_str(&self, splitter: &str) -> Option<(Self, Self)> {
- let (a, b) = self.data.split_once_str(splitter)?;
- Some((
- Self {
- data: a,
- span: Span {
- column_end: NonZeroUsize::new(self.span.column_start.get() + a.len()).unwrap(),
- ..self.span
- },
- },
- Self {
- data: b,
- span: Span {
- column_start: NonZeroUsize::new(
- self.span.column_start.get() + a.len() + splitter.len(),
- )
- .unwrap(),
- ..self.span
- },
- },
- ))
- }
-
- pub fn to_str(self) -> Result<Spanned<&'a str>, Utf8Error> {
- Ok(Spanned {
- data: self.data.to_str()?,
- span: self.span,
- })
- }
-}
-
-impl<T> Spanned<T> {
- pub fn new(data: T, span: Span) -> Self {
- Self { data, span }
- }
-
- pub fn line(&self) -> NonZeroUsize {
- self.span.line_start
- }
-
- pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Spanned<U> {
- Spanned {
- data: f(self.data),
- span: self.span,
- }
- }
-
- pub fn into_inner(self) -> T {
- self.data
- }
-
- pub fn span(&self) -> Span {
- self.span
- }
-}
-
-#[derive(Debug, Clone, Copy)]
-pub struct OptWithLine<T>(Option<Spanned<T>>);
-
-impl<T> std::ops::Deref for OptWithLine<T> {
- type Target = Option<Spanned<T>>;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
-}
-
-impl<T> From<Option<Spanned<T>>> for OptWithLine<T> {
- fn from(value: Option<Spanned<T>>) -> Self {
- Self(value)
- }
-}
-
-impl<T> From<Spanned<T>> for OptWithLine<T> {
- fn from(value: Spanned<T>) -> Self {
- Self(Some(value))
- }
-}
-
-impl<T> Default for OptWithLine<T> {
- fn default() -> Self {
- Self(Default::default())
- }
-}
-
-impl<T> OptWithLine<T> {
- pub fn new(data: T, span: Span) -> Self {
- Self(Some(Spanned::new(data, span)))
- }
-
- /// Tries to set the value if not already set. Returns newly passed
- /// value in case there was already a value there.
- #[must_use]
- pub fn set(&mut self, data: T, span: Span) -> Option<Spanned<T>> {
- let new = Spanned::new(data, span);
- if self.0.is_some() {
- Some(new)
- } else {
- self.0 = Some(new);
- None
- }
- }
-
- #[must_use]
- pub fn into_inner(self) -> Option<Spanned<T>> {
- self.0
- }
-}
diff --git a/vendor/ui_test-0.20.0/src/parser/tests.rs b/vendor/ui_test-0.20.0/src/parser/tests.rs
deleted file mode 100644
index f1b3b4cbf..000000000
--- a/vendor/ui_test-0.20.0/src/parser/tests.rs
+++ /dev/null
@@ -1,139 +0,0 @@
-use crate::{
- parser::{Condition, Pattern},
- Error,
-};
-
-use super::Comments;
-
-#[test]
-fn parse_simple_comment() {
- let s = r"
-use std::mem;
-
-fn main() {
- let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address $HEX is unallocated)
-}
- ";
- let comments = Comments::parse(s).unwrap();
- println!("parsed comments: {:#?}", comments);
- assert_eq!(comments.revisioned.len(), 1);
- let revisioned = &comments.revisioned[&vec![]];
- assert_eq!(revisioned.error_matches[0].pattern.line().get(), 5);
- match &*revisioned.error_matches[0].pattern {
- Pattern::SubString(s) => {
- assert_eq!(
- s,
- "encountered a dangling reference (address $HEX is unallocated)"
- )
- }
- other => panic!("expected substring, got {other:?}"),
- }
-}
-
-#[test]
-fn parse_missing_level() {
- let s = r"
-use std::mem;
-
-fn main() {
- let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ encountered a dangling reference (address $HEX is unallocated)
-}
- ";
- let errors = Comments::parse(s).unwrap_err();
- println!("parsed comments: {:#?}", errors);
- assert_eq!(errors.len(), 1);
- match &errors[0] {
- Error::InvalidComment { msg, span } if span.line_start.get() == 5 => {
- assert_eq!(msg, "unknown level `encountered`")
- }
- _ => unreachable!(),
- }
-}
-
-#[test]
-fn parse_slash_slash_at() {
- let s = r"
-//@ error-in-other-file: foomp
-use std::mem;
-
- ";
- let comments = Comments::parse(s).unwrap();
- println!("parsed comments: {:#?}", comments);
- assert_eq!(comments.revisioned.len(), 1);
- let revisioned = &comments.revisioned[&vec![]];
- let pat = &revisioned.error_in_other_files[0];
- assert_eq!(format!("{:?}", **pat), r#"SubString("foomp")"#);
- assert_eq!(pat.line().get(), 2);
-}
-
-#[test]
-fn parse_regex_error_pattern() {
- let s = r"
-//@ error-in-other-file: /foomp/
-use std::mem;
-
- ";
- let comments = Comments::parse(s).unwrap();
- println!("parsed comments: {:#?}", comments);
- assert_eq!(comments.revisioned.len(), 1);
- let revisioned = &comments.revisioned[&vec![]];
- let pat = &revisioned.error_in_other_files[0];
- assert_eq!(format!("{:?}", **pat), r#"Regex(Regex("foomp"))"#);
- assert_eq!(pat.line().get(), 2);
-}
-
-#[test]
-fn parse_slash_slash_at_fail() {
- let s = r"
-//@ error-patttern foomp
-use std::mem;
-
- ";
- let errors = Comments::parse(s).unwrap_err();
- println!("parsed comments: {:#?}", errors);
- assert_eq!(errors.len(), 2);
- match &errors[0] {
- Error::InvalidComment { msg, span } if span.line_start.get() == 2 => {
- assert!(msg.contains("must be followed by `:`"))
- }
- _ => unreachable!(),
- }
- match &errors[1] {
- Error::InvalidComment { msg, span } if span.line_start.get() == 2 => {
- assert_eq!(msg, "`error-patttern` is not a command known to `ui_test`, did you mean `error-pattern`?");
- }
- _ => unreachable!(),
- }
-}
-
-#[test]
-fn missing_colon_fail() {
- let s = r"
-//@stderr-per-bitwidth hello
-use std::mem;
-
- ";
- let errors = Comments::parse(s).unwrap_err();
- println!("parsed comments: {:#?}", errors);
- assert_eq!(errors.len(), 1);
- match &errors[0] {
- Error::InvalidComment { msg, span } if span.line_start.get() == 2 => {
- assert!(msg.contains("must be followed by `:`"))
- }
- _ => unreachable!(),
- }
-}
-
-#[test]
-fn parse_x86_64() {
- let s = r"//@ only-target-x86_64-unknown-linux";
- let comments = Comments::parse(s).unwrap();
- println!("parsed comments: {:#?}", comments);
- assert_eq!(comments.revisioned.len(), 1);
- let revisioned = &comments.revisioned[&vec![]];
- assert_eq!(revisioned.only.len(), 1);
- match &revisioned.only[0] {
- Condition::Target(t) => assert_eq!(t, "x86_64-unknown-linux"),
- _ => unreachable!(),
- }
-}
diff --git a/vendor/ui_test-0.20.0/src/rustc_stderr.rs b/vendor/ui_test-0.20.0/src/rustc_stderr.rs
deleted file mode 100644
index 4a371ce1d..000000000
--- a/vendor/ui_test-0.20.0/src/rustc_stderr.rs
+++ /dev/null
@@ -1,201 +0,0 @@
-use bstr::ByteSlice;
-use regex::Regex;
-use std::{
- num::NonZeroUsize,
- path::{Path, PathBuf},
-};
-
-#[derive(serde::Deserialize, Debug)]
-struct RustcMessage {
- rendered: Option<String>,
- spans: Vec<RustcSpan>,
- level: String,
- message: String,
- children: Vec<RustcMessage>,
-}
-
-#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
-pub(crate) enum Level {
- Ice = 5,
- Error = 4,
- Warn = 3,
- Help = 2,
- Note = 1,
- /// Only used for "For more information about this error, try `rustc --explain EXXXX`".
- FailureNote = 0,
-}
-
-#[derive(Debug)]
-/// A diagnostic message.
-pub struct Message {
- pub(crate) level: Level,
- pub(crate) message: String,
- pub(crate) line_col: Option<Span>,
-}
-
-/// Information about macro expansion.
-#[derive(serde::Deserialize, Debug)]
-struct Expansion {
- span: RustcSpan,
-}
-
-#[derive(serde::Deserialize, Debug)]
-struct RustcSpan {
- #[serde(flatten)]
- line_col: Span,
- file_name: PathBuf,
- is_primary: bool,
- expansion: Option<Box<Expansion>>,
-}
-
-#[derive(serde::Deserialize, Debug, Copy, Clone)]
-pub struct Span {
- pub line_start: NonZeroUsize,
- pub column_start: NonZeroUsize,
- pub line_end: NonZeroUsize,
- pub column_end: NonZeroUsize,
-}
-
-impl Span {
- pub const INVALID: Self = Self {
- line_start: NonZeroUsize::MAX,
- column_start: NonZeroUsize::MAX,
- line_end: NonZeroUsize::MAX,
- column_end: NonZeroUsize::MAX,
- };
-
- pub fn shrink_to_end(self) -> Span {
- Self {
- line_start: self.line_end,
- column_start: self.column_end,
- ..self
- }
- }
-
- pub fn shrink_to_start(self) -> Span {
- Self {
- line_end: self.line_start,
- column_end: self.column_start,
- ..self
- }
- }
-}
-
-impl std::str::FromStr for Level {
- type Err = String;
- fn from_str(s: &str) -> Result<Self, Self::Err> {
- match s {
- "ERROR" | "error" => Ok(Self::Error),
- "WARN" | "warning" => Ok(Self::Warn),
- "HELP" | "help" => Ok(Self::Help),
- "NOTE" | "note" => Ok(Self::Note),
- "failure-note" => Ok(Self::FailureNote),
- "error: internal compiler error" => Ok(Self::Ice),
- _ => Err(format!("unknown level `{s}`")),
- }
- }
-}
-
-#[derive(Debug)]
-pub(crate) struct Diagnostics {
- /// Rendered and concatenated version of all diagnostics.
- /// This is equivalent to non-json diagnostics.
- pub rendered: Vec<u8>,
- /// Per line, a list of messages for that line.
- pub messages: Vec<Vec<Message>>,
- /// Messages not on any line (usually because they are from libstd)
- pub messages_from_unknown_file_or_line: Vec<Message>,
-}
-
-impl RustcMessage {
- fn line(&self, file: &Path) -> Option<Span> {
- let span = |primary| self.spans.iter().find_map(|span| span.line(file, primary));
- span(true).or_else(|| span(false))
- }
-
- /// Put the message and its children into the line-indexed list.
- fn insert_recursive(
- self,
- file: &Path,
- messages: &mut Vec<Vec<Message>>,
- messages_from_unknown_file_or_line: &mut Vec<Message>,
- line: Option<Span>,
- ) {
- let line = self.line(file).or(line);
- let msg = Message {
- level: self.level.parse().unwrap(),
- message: self.message,
- line_col: line,
- };
- if let Some(line) = line {
- if messages.len() <= line.line_start.get() {
- messages.resize_with(line.line_start.get() + 1, Vec::new);
- }
- messages[line.line_start.get()].push(msg);
- // All other messages go into the general bin, unless they are specifically of the
- // "aborting due to X previous errors" variety, as we never want to match those. They
- // only count the number of errors and provide no useful information about the tests.
- } else if !(msg.message.starts_with("aborting due to")
- && msg.message.contains("previous error"))
- {
- messages_from_unknown_file_or_line.push(msg);
- }
- for child in self.children {
- child.insert_recursive(file, messages, messages_from_unknown_file_or_line, line)
- }
- }
-}
-
-impl RustcSpan {
- /// Returns the most expanded line number *in the given file*, if possible.
- fn line(&self, file: &Path, primary: bool) -> Option<Span> {
- if let Some(exp) = &self.expansion {
- if let Some(line) = exp.span.line(file, primary && !self.is_primary) {
- return Some(line);
- }
- }
- ((!primary || self.is_primary) && self.file_name == file).then_some(self.line_col)
- }
-}
-
-pub(crate) fn filter_annotations_from_rendered(rendered: &str) -> std::borrow::Cow<'_, str> {
- let annotations = Regex::new(r" *//(\[[a-z,]+\])?~.*").unwrap();
- annotations.replace_all(rendered, "")
-}
-
-pub(crate) fn process(file: &Path, stderr: &[u8]) -> Diagnostics {
- let mut rendered = Vec::new();
- let mut messages = vec![];
- let mut messages_from_unknown_file_or_line = vec![];
- for (line_number, line) in stderr.lines_with_terminator().enumerate() {
- if line.starts_with_str(b"{") {
- match serde_json::from_slice::<RustcMessage>(line) {
- Ok(msg) => {
- rendered.extend(
- filter_annotations_from_rendered(msg.rendered.as_ref().unwrap()).as_bytes(),
- );
- msg.insert_recursive(
- file,
- &mut messages,
- &mut messages_from_unknown_file_or_line,
- None,
- );
- }
- Err(err) => {
- panic!(
- "failed to parse rustc JSON output at line {line_number}: {err}: {}",
- line.to_str_lossy()
- )
- }
- }
- } else {
- // FIXME: do we want to throw interpreter stderr into a separate file?
- rendered.extend(line);
- }
- }
- Diagnostics {
- rendered,
- messages,
- messages_from_unknown_file_or_line,
- }
-}
diff --git a/vendor/ui_test-0.20.0/src/status_emitter.rs b/vendor/ui_test-0.20.0/src/status_emitter.rs
deleted file mode 100644
index b32235907..000000000
--- a/vendor/ui_test-0.20.0/src/status_emitter.rs
+++ /dev/null
@@ -1,972 +0,0 @@
-//! Variaous schemes for reporting messages during testing or after testing is done.
-
-use annotate_snippets::{
- display_list::{DisplayList, FormatOptions},
- snippet::{Annotation, AnnotationType, Slice, Snippet, SourceAnnotation},
-};
-use bstr::ByteSlice;
-use colored::Colorize;
-use crossbeam_channel::{Sender, TryRecvError};
-use indicatif::{MultiProgress, ProgressBar, ProgressDrawTarget, ProgressStyle};
-
-use crate::{
- github_actions,
- parser::Pattern,
- rustc_stderr::{Message, Span},
- Error, Errored, Errors, TestOk, TestResult,
-};
-use std::{
- collections::HashMap,
- fmt::{Debug, Write as _},
- io::Write as _,
- num::NonZeroUsize,
- panic::RefUnwindSafe,
- path::{Path, PathBuf},
- process::Command,
- sync::atomic::AtomicBool,
- time::Duration,
-};
-
-/// A generic way to handle the output of this crate.
-pub trait StatusEmitter: Sync + RefUnwindSafe {
- /// Invoked the moment we know a test will later be run.
- /// Useful for progress bars and such.
- fn register_test(&self, path: PathBuf) -> Box<dyn TestStatus>;
-
- /// Create a report about the entire test run at the end.
- #[allow(clippy::type_complexity)]
- fn finalize(
- &self,
- failed: usize,
- succeeded: usize,
- ignored: usize,
- filtered: usize,
- ) -> Box<dyn Summary>;
-}
-
-/// Information about a specific test run.
-pub trait TestStatus: Send + Sync + RefUnwindSafe {
- /// Create a copy of this test for a new revision.
- fn for_revision(&self, revision: &str) -> Box<dyn TestStatus>;
-
- /// Invoked before each failed test prints its errors along with a drop guard that can
- /// gets invoked afterwards.
- fn failed_test<'a>(
- &'a self,
- cmd: &'a Command,
- stderr: &'a [u8],
- stdout: &'a [u8],
- ) -> Box<dyn Debug + 'a>;
-
- /// Change the status of the test while it is running to supply some kind of progress
- fn update_status(&self, msg: String);
-
- /// A test has finished, handle the result immediately.
- fn done(&self, _result: &TestResult) {}
-
- /// The path of the test file.
- fn path(&self) -> &Path;
-
- /// The revision, usually an empty string.
- fn revision(&self) -> &str;
-}
-
-/// Report a summary at the end of a test run.
-pub trait Summary {
- /// A test has finished, handle the result.
- fn test_failure(&mut self, _status: &dyn TestStatus, _errors: &Errors) {}
-}
-
-impl Summary for () {}
-
-/// A human readable output emitter.
-#[derive(Clone)]
-pub struct Text {
- sender: Sender<Msg>,
- progress: bool,
-}
-
-#[derive(Debug)]
-enum Msg {
- Pop(String, Option<String>),
- Push(String),
- Inc,
- IncLength,
- Finish,
- Status(String, String),
-}
-
-impl Text {
- fn start_thread() -> Sender<Msg> {
- let (sender, receiver) = crossbeam_channel::unbounded();
- std::thread::spawn(move || {
- let bars = MultiProgress::new();
- let mut progress = None;
- let mut threads: HashMap<String, ProgressBar> = HashMap::new();
- 'outer: loop {
- std::thread::sleep(Duration::from_millis(100));
- loop {
- match receiver.try_recv() {
- Ok(val) => match val {
- Msg::Pop(msg, new_msg) => {
- let Some(spinner) = threads.remove(&msg) else {
- // This can happen when a test was not run at all, because it failed directly during
- // comment parsing.
- continue;
- };
- spinner.set_style(
- ProgressStyle::with_template("{prefix} {msg}").unwrap(),
- );
- if let Some(new_msg) = new_msg {
- bars.remove(&spinner);
- let spinner = bars.insert(0, spinner);
- spinner.tick();
- spinner.finish_with_message(new_msg);
- } else {
- spinner.finish_and_clear();
- }
- }
- Msg::Status(msg, status) => {
- threads.get_mut(&msg).unwrap().set_message(status);
- }
- Msg::Push(msg) => {
- let spinner =
- bars.add(ProgressBar::new_spinner().with_prefix(msg.clone()));
- spinner.set_style(
- ProgressStyle::with_template("{prefix} {spinner} {msg}")
- .unwrap(),
- );
- threads.insert(msg, spinner);
- }
- Msg::IncLength => {
- progress
- .get_or_insert_with(|| bars.add(ProgressBar::new(0)))
- .inc_length(1);
- }
- Msg::Inc => {
- progress.as_ref().unwrap().inc(1);
- }
- Msg::Finish => return,
- },
- Err(TryRecvError::Disconnected) => break 'outer,
- Err(TryRecvError::Empty) => break,
- }
- }
- for spinner in threads.values() {
- spinner.tick()
- }
- if let Some(progress) = &progress {
- progress.tick()
- }
- }
- assert_eq!(threads.len(), 0);
- if let Some(progress) = progress {
- progress.tick();
- assert!(progress.is_finished());
- }
- });
- sender
- }
-
- /// Print one line per test that gets run.
- pub fn verbose() -> Self {
- Self {
- sender: Self::start_thread(),
- progress: false,
- }
- }
- /// Print a progress bar.
- pub fn quiet() -> Self {
- Self {
- sender: Self::start_thread(),
- progress: true,
- }
- }
-}
-
-struct TextTest {
- text: Text,
- path: PathBuf,
- revision: String,
- first: AtomicBool,
-}
-
-impl TextTest {
- fn msg(&self) -> String {
- if self.revision.is_empty() {
- self.path.display().to_string()
- } else {
- format!("{} ({})", self.path.display(), self.revision)
- }
- }
-}
-
-impl TestStatus for TextTest {
- fn done(&self, result: &TestResult) {
- if self.text.progress {
- self.text.sender.send(Msg::Inc).unwrap();
- self.text.sender.send(Msg::Pop(self.msg(), None)).unwrap();
- } else {
- let result = match result {
- Ok(TestOk::Ok) => "ok".green(),
- Err(Errored { .. }) => "FAILED".red().bold(),
- Ok(TestOk::Ignored) => "ignored (in-test comment)".yellow(),
- Ok(TestOk::Filtered) => return,
- };
- let old_msg = self.msg();
- let msg = format!("... {result}");
- if ProgressDrawTarget::stdout().is_hidden() {
- println!("{old_msg} {msg}");
- std::io::stdout().flush().unwrap();
- } else {
- self.text.sender.send(Msg::Pop(old_msg, Some(msg))).unwrap();
- }
- }
- }
-
- fn update_status(&self, msg: String) {
- self.text.sender.send(Msg::Status(self.msg(), msg)).unwrap();
- }
-
- fn failed_test<'a>(
- &self,
- cmd: &Command,
- stderr: &'a [u8],
- stdout: &'a [u8],
- ) -> Box<dyn Debug + 'a> {
- println!();
- let path = self.path.display().to_string();
- print!("{}", path.underline().bold());
- let revision = if self.revision.is_empty() {
- String::new()
- } else {
- format!(" (revision `{}`)", self.revision)
- };
- print!("{revision}");
- print!(" {}", "FAILED:".red().bold());
- println!();
- println!("command: {cmd:?}");
- println!();
-
- #[derive(Debug)]
- struct Guard<'a> {
- stderr: &'a [u8],
- stdout: &'a [u8],
- }
- impl<'a> Drop for Guard<'a> {
- fn drop(&mut self) {
- println!("full stderr:");
- std::io::stdout().write_all(self.stderr).unwrap();
- println!();
- println!("full stdout:");
- std::io::stdout().write_all(self.stdout).unwrap();
- println!();
- println!();
- }
- }
- Box::new(Guard { stderr, stdout })
- }
-
- fn path(&self) -> &Path {
- &self.path
- }
-
- fn for_revision(&self, revision: &str) -> Box<dyn TestStatus> {
- assert_eq!(self.revision, "");
- if !self.first.swap(false, std::sync::atomic::Ordering::Relaxed) && self.text.progress {
- self.text.sender.send(Msg::IncLength).unwrap();
- }
-
- let text = Self {
- text: self.text.clone(),
- path: self.path.clone(),
- revision: revision.to_owned(),
- first: AtomicBool::new(false),
- };
- self.text.sender.send(Msg::Push(text.msg())).unwrap();
- Box::new(text)
- }
-
- fn revision(&self) -> &str {
- &self.revision
- }
-}
-
-impl StatusEmitter for Text {
- fn register_test(&self, path: PathBuf) -> Box<dyn TestStatus> {
- if self.progress {
- self.sender.send(Msg::IncLength).unwrap();
- }
- Box::new(TextTest {
- text: self.clone(),
- path,
- revision: String::new(),
- first: AtomicBool::new(true),
- })
- }
-
- fn finalize(
- &self,
- failures: usize,
- succeeded: usize,
- ignored: usize,
- filtered: usize,
- ) -> Box<dyn Summary> {
- self.sender.send(Msg::Finish).unwrap();
- while !self.sender.is_empty() {
- std::thread::sleep(Duration::from_millis(10));
- }
- if !ProgressDrawTarget::stdout().is_hidden() {
- // The progress bars do not have a trailing newline, so let's
- // add it here.
- println!();
- }
- // Print all errors in a single thread to show reliable output
- if failures == 0 {
- println!();
- print!("test result: {}.", "ok".green());
- if succeeded > 0 {
- print!(" {} passed;", succeeded.to_string().green());
- }
- if ignored > 0 {
- print!(" {} ignored;", ignored.to_string().yellow());
- }
- if filtered > 0 {
- print!(" {} filtered out;", filtered.to_string().yellow());
- }
- println!();
- println!();
- Box::new(())
- } else {
- struct Summarizer {
- failures: Vec<String>,
- succeeded: usize,
- ignored: usize,
- filtered: usize,
- }
-
- impl Summary for Summarizer {
- fn test_failure(&mut self, status: &dyn TestStatus, errors: &Errors) {
- for error in errors {
- print_error(error, status.path());
- }
-
- self.failures.push(if status.revision().is_empty() {
- format!(" {}", status.path().display())
- } else {
- format!(
- " {} (revision {})",
- status.path().display(),
- status.revision()
- )
- });
- }
- }
-
- impl Drop for Summarizer {
- fn drop(&mut self) {
- println!("{}", "FAILURES:".red().underline().bold());
- for line in &self.failures {
- println!("{line}");
- }
- println!();
- print!("test result: {}.", "FAIL".red());
- print!(" {} failed;", self.failures.len().to_string().green());
- if self.succeeded > 0 {
- print!(" {} passed;", self.succeeded.to_string().green());
- }
- if self.ignored > 0 {
- print!(" {} ignored;", self.ignored.to_string().yellow());
- }
- if self.filtered > 0 {
- print!(" {} filtered out;", self.filtered.to_string().yellow());
- }
- println!();
- println!();
- }
- }
- Box::new(Summarizer {
- failures: vec![],
- succeeded,
- ignored,
- filtered,
- })
- }
- }
-}
-
-fn print_error(error: &Error, path: &Path) {
- match error {
- Error::ExitStatus {
- mode,
- status,
- expected,
- } => {
- println!("{mode} test got {status}, but expected {expected}")
- }
- Error::Command { kind, status } => {
- println!("{kind} failed with {status}");
- }
- Error::PatternNotFound(pattern) => {
- let msg = match &**pattern {
- Pattern::SubString(s) => {
- format!("substring `{s}` {} in stderr output", "not found")
- }
- Pattern::Regex(r) => {
- format!("`/{r}/` does {} stderr output", "not match")
- }
- };
- create_error(
- msg,
- &[(
- &[("expected because of this pattern", Some(pattern.span()))],
- pattern.line(),
- )],
- path,
- );
- }
- Error::NoPatternsFound => {
- println!("{}", "no error patterns found in fail test".red());
- }
- Error::PatternFoundInPassTest => {
- println!("{}", "error pattern found in pass test".red())
- }
- Error::OutputDiffers {
- path: output_path,
- actual,
- expected,
- bless_command,
- } => {
- println!("{}", "actual output differed from expected".underline());
- println!(
- "Execute `{}` to update `{}` to the actual output",
- bless_command,
- output_path.display()
- );
- println!("{}", format!("--- {}", output_path.display()).red());
- println!(
- "{}",
- format!(
- "+++ <{} output>",
- output_path.extension().unwrap().to_str().unwrap()
- )
- .green()
- );
- crate::diff::print_diff(expected, actual);
- }
- Error::ErrorsWithoutPattern { path, msgs } => {
- if let Some(path) = path.as_ref() {
- let line = path.line();
- let msgs = msgs
- .iter()
- .map(|msg| (format!("{:?}: {}", msg.level, msg.message), msg.line_col))
- .collect::<Vec<_>>();
- create_error(
- format!("There were {} unmatched diagnostics", msgs.len()),
- &[(
- &msgs
- .iter()
- .map(|(msg, lc)| (msg.as_ref(), *lc))
- .collect::<Vec<_>>(),
- line,
- )],
- path,
- );
- } else {
- println!(
- "There were {} unmatched diagnostics that occurred outside the testfile and had no pattern",
- msgs.len(),
- );
- for Message {
- level,
- message,
- line_col: _,
- } in msgs
- {
- println!(" {level:?}: {message}")
- }
- }
- }
- Error::InvalidComment { msg, span } => {
- create_error(msg, &[(&[("", Some(*span))], span.line_start)], path)
- }
- Error::MultipleRevisionsWithResults { kind, lines } => {
- let title = format!("multiple {kind} found");
- create_error(
- title,
- &lines
- .iter()
- .map(|&line| (&[] as &[_], line))
- .collect::<Vec<_>>(),
- path,
- )
- }
- Error::Bug(msg) => {
- println!("A bug in `ui_test` occurred: {msg}");
- }
- Error::Aux {
- path: aux_path,
- errors,
- line,
- } => {
- println!("Aux build from {}:{line} failed", path.display());
- for error in errors {
- print_error(error, aux_path);
- }
- }
- Error::Rustfix(error) => {
- println!(
- "failed to apply suggestions for {} with rustfix: {error}",
- path.display()
- );
- println!("Add //@no-rustfix to the test file to ignore rustfix suggestions");
- }
- }
- println!();
-}
-
-#[allow(clippy::type_complexity)]
-fn create_error(
- s: impl AsRef<str>,
- lines: &[(&[(&str, Option<Span>)], NonZeroUsize)],
- file: &Path,
-) {
- let source = std::fs::read_to_string(file).unwrap();
- let source: Vec<_> = source.split_inclusive('\n').collect();
- let file = file.display().to_string();
- let msg = Snippet {
- title: Some(Annotation {
- id: None,
- annotation_type: AnnotationType::Error,
- label: Some(s.as_ref()),
- }),
- slices: lines
- .iter()
- .map(|(label, line)| {
- let source = source[line.get() - 1];
- let len = source.chars().count();
- Slice {
- source,
- line_start: line.get(),
- origin: Some(&file),
- annotations: label
- .iter()
- .map(|(label, lc)| SourceAnnotation {
- range: lc.map_or((0, len - 1), |lc| {
- assert_eq!(lc.line_start, *line);
- if lc.line_end > lc.line_start {
- (lc.column_start.get() - 1, len - 1)
- } else if lc.column_start == lc.column_end {
- if lc.column_start.get() - 1 == len {
- // rustc sometimes produces spans pointing *after* the `\n` at the end of the line,
- // but we want to render an annotation at the end.
- (lc.column_start.get() - 2, lc.column_start.get() - 1)
- } else {
- (lc.column_start.get() - 1, lc.column_start.get())
- }
- } else {
- (lc.column_start.get() - 1, lc.column_end.get() - 1)
- }
- }),
- label,
- annotation_type: AnnotationType::Error,
- })
- .collect(),
- fold: false,
- }
- })
- .collect(),
- footer: vec![],
- opt: FormatOptions {
- color: colored::control::SHOULD_COLORIZE.should_colorize(),
- anonymized_line_numbers: false,
- margin: None,
- },
- };
- println!("{}", DisplayList::from(msg));
-}
-
-fn gha_error(error: &Error, test_path: &str, revision: &str) {
- match error {
- Error::ExitStatus {
- mode,
- status,
- expected,
- } => {
- github_actions::error(
- test_path,
- format!("{mode} test{revision} got {status}, but expected {expected}"),
- );
- }
- Error::Command { kind, status } => {
- github_actions::error(test_path, format!("{kind}{revision} failed with {status}"));
- }
- Error::PatternNotFound(pattern) => {
- github_actions::error(test_path, format!("Pattern not found{revision}"))
- .line(pattern.line());
- }
- Error::NoPatternsFound => {
- github_actions::error(
- test_path,
- format!("no error patterns found in fail test{revision}"),
- );
- }
- Error::PatternFoundInPassTest => {
- github_actions::error(
- test_path,
- format!("error pattern found in pass test{revision}"),
- );
- }
- Error::OutputDiffers {
- path: output_path,
- actual,
- expected,
- bless_command,
- } => {
- if expected.is_empty() {
- let mut err = github_actions::error(
- test_path,
- "test generated output, but there was no output file",
- );
- writeln!(
- err,
- "you likely need to bless the tests with `{bless_command}`"
- )
- .unwrap();
- return;
- }
-
- let mut line = 1;
- for r in
- prettydiff::diff_lines(expected.to_str().unwrap(), actual.to_str().unwrap()).diff()
- {
- use prettydiff::basic::DiffOp::*;
- match r {
- Equal(s) => {
- line += s.len();
- continue;
- }
- Replace(l, r) => {
- let mut err = github_actions::error(
- output_path.display().to_string(),
- "actual output differs from expected",
- )
- .line(NonZeroUsize::new(line + 1).unwrap());
- writeln!(err, "this line was expected to be `{}`", r[0]).unwrap();
- line += l.len();
- }
- Remove(l) => {
- let mut err = github_actions::error(
- output_path.display().to_string(),
- "extraneous lines in output",
- )
- .line(NonZeroUsize::new(line + 1).unwrap());
- writeln!(
- err,
- "remove this line and possibly later ones by blessing the test"
- )
- .unwrap();
- line += l.len();
- }
- Insert(r) => {
- let mut err = github_actions::error(
- output_path.display().to_string(),
- "missing line in output",
- )
- .line(NonZeroUsize::new(line + 1).unwrap());
- writeln!(err, "bless the test to create a line containing `{}`", r[0])
- .unwrap();
- // Do not count these lines, they don't exist in the original file and
- // would thus mess up the line number.
- }
- }
- }
- }
- Error::ErrorsWithoutPattern { path, msgs } => {
- if let Some(path) = path.as_ref() {
- let line = path.line();
- let path = path.display();
- let mut err =
- github_actions::error(&path, format!("Unmatched diagnostics{revision}"))
- .line(line);
- for Message {
- level,
- message,
- line_col: _,
- } in msgs
- {
- writeln!(err, "{level:?}: {message}").unwrap();
- }
- } else {
- let mut err = github_actions::error(
- test_path,
- format!("Unmatched diagnostics outside the testfile{revision}"),
- );
- for Message {
- level,
- message,
- line_col: _,
- } in msgs
- {
- writeln!(err, "{level:?}: {message}").unwrap();
- }
- }
- }
- Error::InvalidComment { msg, span } => {
- let mut err = github_actions::error(test_path, format!("Could not parse comment"))
- .line(span.line_start);
- writeln!(err, "{msg}").unwrap();
- }
- Error::MultipleRevisionsWithResults { kind, lines } => {
- github_actions::error(test_path, format!("multiple {kind} found")).line(lines[0]);
- }
- Error::Bug(_) => {}
- Error::Aux {
- path: aux_path,
- errors,
- line,
- } => {
- github_actions::error(test_path, format!("Aux build failed")).line(*line);
- for error in errors {
- gha_error(error, &aux_path.display().to_string(), "")
- }
- }
- Error::Rustfix(error) => {
- github_actions::error(
- test_path,
- format!("failed to apply suggestions with rustfix: {error}"),
- );
- }
- }
-}
-
-/// Emits Github Actions Workspace commands to show the failures directly in the github diff view.
-/// If the const generic `GROUP` boolean is `true`, also emit `::group` commands.
-pub struct Gha<const GROUP: bool> {
- /// Show a specific name for the final summary.
- pub name: String,
-}
-
-#[derive(Clone)]
-struct PathAndRev<const GROUP: bool> {
- path: PathBuf,
- revision: String,
-}
-
-impl<const GROUP: bool> TestStatus for PathAndRev<GROUP> {
- fn path(&self) -> &Path {
- &self.path
- }
-
- fn for_revision(&self, revision: &str) -> Box<dyn TestStatus> {
- assert_eq!(self.revision, "");
- Box::new(Self {
- path: self.path.clone(),
- revision: revision.to_owned(),
- })
- }
-
- fn failed_test(&self, _cmd: &Command, _stderr: &[u8], _stdout: &[u8]) -> Box<dyn Debug> {
- if GROUP {
- Box::new(github_actions::group(format_args!(
- "{}:{}",
- self.path.display(),
- self.revision
- )))
- } else {
- Box::new(())
- }
- }
-
- fn revision(&self) -> &str {
- &self.revision
- }
-
- fn update_status(&self, _msg: String) {}
-}
-
-impl<const GROUP: bool> StatusEmitter for Gha<GROUP> {
- fn register_test(&self, path: PathBuf) -> Box<dyn TestStatus> {
- Box::new(PathAndRev::<GROUP> {
- path,
- revision: String::new(),
- })
- }
-
- fn finalize(
- &self,
- _failures: usize,
- succeeded: usize,
- ignored: usize,
- filtered: usize,
- ) -> Box<dyn Summary> {
- struct Summarizer<const GROUP: bool> {
- failures: Vec<String>,
- succeeded: usize,
- ignored: usize,
- filtered: usize,
- name: String,
- }
-
- impl<const GROUP: bool> Summary for Summarizer<GROUP> {
- fn test_failure(&mut self, status: &dyn TestStatus, errors: &Errors) {
- let revision = if status.revision().is_empty() {
- "".to_string()
- } else {
- format!(" (revision: {})", status.revision())
- };
- for error in errors {
- gha_error(error, &status.path().display().to_string(), &revision);
- }
- self.failures
- .push(format!("{}{revision}", status.path().display()));
- }
- }
- impl<const GROUP: bool> Drop for Summarizer<GROUP> {
- fn drop(&mut self) {
- if let Some(mut file) = github_actions::summary() {
- writeln!(file, "### {}", self.name).unwrap();
- for line in &self.failures {
- writeln!(file, "* {line}").unwrap();
- }
- writeln!(file).unwrap();
- writeln!(file, "| failed | passed | ignored | filtered out |").unwrap();
- writeln!(file, "| --- | --- | --- | --- |").unwrap();
- writeln!(
- file,
- "| {} | {} | {} | {} |",
- self.failures.len(),
- self.succeeded,
- self.ignored,
- self.filtered,
- )
- .unwrap();
- }
- }
- }
-
- Box::new(Summarizer::<GROUP> {
- failures: vec![],
- succeeded,
- ignored,
- filtered,
- name: self.name.clone(),
- })
- }
-}
-
-impl<T: TestStatus, U: TestStatus> TestStatus for (T, U) {
- fn done(&self, result: &TestResult) {
- self.0.done(result);
- self.1.done(result);
- }
-
- fn failed_test<'a>(
- &'a self,
- cmd: &'a Command,
- stderr: &'a [u8],
- stdout: &'a [u8],
- ) -> Box<dyn Debug + 'a> {
- Box::new((
- self.0.failed_test(cmd, stderr, stdout),
- self.1.failed_test(cmd, stderr, stdout),
- ))
- }
-
- fn path(&self) -> &Path {
- let path = self.0.path();
- assert_eq!(path, self.1.path());
- path
- }
-
- fn revision(&self) -> &str {
- let rev = self.0.revision();
- assert_eq!(rev, self.1.revision());
- rev
- }
-
- fn for_revision(&self, revision: &str) -> Box<dyn TestStatus> {
- Box::new((self.0.for_revision(revision), self.1.for_revision(revision)))
- }
-
- fn update_status(&self, msg: String) {
- self.0.update_status(msg.clone());
- self.1.update_status(msg)
- }
-}
-
-impl<T: StatusEmitter, U: StatusEmitter> StatusEmitter for (T, U) {
- fn register_test(&self, path: PathBuf) -> Box<dyn TestStatus> {
- Box::new((
- self.0.register_test(path.clone()),
- self.1.register_test(path),
- ))
- }
-
- fn finalize(
- &self,
- failures: usize,
- succeeded: usize,
- ignored: usize,
- filtered: usize,
- ) -> Box<dyn Summary> {
- Box::new((
- self.1.finalize(failures, succeeded, ignored, filtered),
- self.0.finalize(failures, succeeded, ignored, filtered),
- ))
- }
-}
-
-impl<T: TestStatus + ?Sized> TestStatus for Box<T> {
- fn done(&self, result: &TestResult) {
- (**self).done(result);
- }
-
- fn path(&self) -> &Path {
- (**self).path()
- }
-
- fn revision(&self) -> &str {
- (**self).revision()
- }
-
- fn for_revision(&self, revision: &str) -> Box<dyn TestStatus> {
- (**self).for_revision(revision)
- }
-
- fn failed_test<'a>(
- &'a self,
- cmd: &'a Command,
- stderr: &'a [u8],
- stdout: &'a [u8],
- ) -> Box<dyn Debug + 'a> {
- (**self).failed_test(cmd, stderr, stdout)
- }
-
- fn update_status(&self, msg: String) {
- (**self).update_status(msg)
- }
-}
-
-impl<T: StatusEmitter + ?Sized> StatusEmitter for Box<T> {
- fn register_test(&self, path: PathBuf) -> Box<dyn TestStatus> {
- (**self).register_test(path)
- }
-
- fn finalize(
- &self,
- failures: usize,
- succeeded: usize,
- ignored: usize,
- filtered: usize,
- ) -> Box<dyn Summary> {
- (**self).finalize(failures, succeeded, ignored, filtered)
- }
-}
-
-impl Summary for (Box<dyn Summary>, Box<dyn Summary>) {
- fn test_failure(&mut self, status: &dyn TestStatus, errors: &Errors) {
- self.0.test_failure(status, errors);
- self.1.test_failure(status, errors);
- }
-}
diff --git a/vendor/ui_test-0.20.0/src/tests.rs b/vendor/ui_test-0.20.0/src/tests.rs
deleted file mode 100644
index 791027d4f..000000000
--- a/vendor/ui_test-0.20.0/src/tests.rs
+++ /dev/null
@@ -1,350 +0,0 @@
-use std::path::{Path, PathBuf};
-
-use crate::rustc_stderr::Level;
-use crate::rustc_stderr::Message;
-
-use super::*;
-
-fn config() -> Config {
- Config {
- root_dir: PathBuf::from("$RUSTROOT"),
- program: CommandBuilder::cmd("cake"),
- ..Config::rustc(PathBuf::new())
- }
-}
-
-#[test]
-fn issue_2156() {
- let s = r"
-use std::mem;
-
-fn main() {
- let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address $HEX is unallocated)
-}
- ";
- let comments = Comments::parse(s).unwrap();
- let mut errors = vec![];
- let config = config();
- let messages = vec![
- vec![], vec![], vec![], vec![], vec![],
- vec![
- Message {
- message:"Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(),
- level: Level::Error,
- line_col: None,
- }
- ]
- ];
- check_annotations(
- messages,
- vec![],
- Path::new("moobar"),
- &mut errors,
- &config,
- "",
- &comments,
- )
- .unwrap();
- match &errors[..] {
- [Error::PatternNotFound(pattern), Error::ErrorsWithoutPattern { path, .. }]
- if path.as_ref().is_some_and(|p| p.line().get() == 5) && pattern.line().get() == 5 => {}
- _ => panic!("{:#?}", errors),
- }
-}
-
-#[test]
-fn find_pattern() {
- let s = r"
-use std::mem;
-
-fn main() {
- let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated)
-}
- ";
- let comments = Comments::parse(s).unwrap();
- let config = config();
- {
- let messages = vec![vec![], vec![], vec![], vec![], vec![], vec![
- Message {
- message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(),
- level: Level::Error,
- line_col: None,
- }
- ]
- ];
- let mut errors = vec![];
- check_annotations(
- messages,
- vec![],
- Path::new("moobar"),
- &mut errors,
- &config,
- "",
- &comments,
- )
- .unwrap();
- match &errors[..] {
- [] => {}
- _ => panic!("{:#?}", errors),
- }
- }
-
- // only difference to above is a wrong line number
- {
- let messages = vec![vec![], vec![], vec![], vec![], vec![
- Message {
- message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(),
- level: Level::Error,
- line_col: None,
- }
- ]
- ];
- let mut errors = vec![];
- check_annotations(
- messages,
- vec![],
- Path::new("moobar"),
- &mut errors,
- &config,
- "",
- &comments,
- )
- .unwrap();
- match &errors[..] {
- [Error::PatternNotFound(pattern), Error::ErrorsWithoutPattern { path, .. }]
- if path.as_ref().is_some_and(|p| p.line().get() == 4)
- && pattern.line().get() == 5 => {}
- _ => panic!("not the expected error: {:#?}", errors),
- }
- }
-
- // only difference to first is a wrong level
- {
- let messages = vec![
- vec![], vec![], vec![], vec![], vec![],
- vec![
- Message {
- message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(),
- level: Level::Note,
- line_col: None,
- }
- ]
- ];
- let mut errors = vec![];
- check_annotations(
- messages,
- vec![],
- Path::new("moobar"),
- &mut errors,
- &config,
- "",
- &comments,
- )
- .unwrap();
- match &errors[..] {
- // Note no `ErrorsWithoutPattern`, because there are no `//~NOTE` in the test file, so we ignore them
- [Error::PatternNotFound(pattern)] if pattern.line().get() == 5 => {}
- _ => panic!("not the expected error: {:#?}", errors),
- }
- }
-}
-
-#[test]
-fn duplicate_pattern() {
- let s = r"
-use std::mem;
-
-fn main() {
- let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated)
- //~^ ERROR: encountered a dangling reference (address 0x10 is unallocated)
-}
- ";
- let comments = Comments::parse(s).unwrap();
- let config = config();
- let messages = vec![
- vec![], vec![], vec![], vec![], vec![],
- vec![
- Message {
- message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(),
- level: Level::Error,
- line_col: None,
- }
- ]
- ];
- let mut errors = vec![];
- check_annotations(
- messages,
- vec![],
- Path::new("moobar"),
- &mut errors,
- &config,
- "",
- &comments,
- )
- .unwrap();
- match &errors[..] {
- [Error::PatternNotFound(pattern)] if pattern.line().get() == 6 => {}
- _ => panic!("{:#?}", errors),
- }
-}
-
-#[test]
-fn missing_pattern() {
- let s = r"
-use std::mem;
-
-fn main() {
- let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated)
-}
- ";
- let comments = Comments::parse(s).unwrap();
- let config = config();
- let messages = vec![
- vec![], vec![], vec![], vec![], vec![],
- vec![
- Message {
- message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(),
- level: Level::Error,
- line_col: None,
- },
- Message {
- message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(),
- level: Level::Error,
- line_col: None,
- }
- ]
- ];
- let mut errors = vec![];
- check_annotations(
- messages,
- vec![],
- Path::new("moobar"),
- &mut errors,
- &config,
- "",
- &comments,
- )
- .unwrap();
- match &errors[..] {
- [Error::ErrorsWithoutPattern { path, .. }]
- if path.as_ref().is_some_and(|p| p.line().get() == 5) => {}
- _ => panic!("{:#?}", errors),
- }
-}
-
-#[test]
-fn missing_warn_pattern() {
- let s = r"
-use std::mem;
-
-fn main() {
- let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated)
- //~^ WARN: cake
-}
- ";
- let comments = Comments::parse(s).unwrap();
- let config = config();
- let messages= vec![
- vec![],
- vec![],
- vec![],
- vec![],
- vec![],
- vec![
- Message {
- message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(),
- level: Level::Error,
- line_col: None,
- },
- Message {
- message: "kaboom".to_string(),
- level: Level::Warn,
- line_col: None,
- },
- Message {
- message: "cake".to_string(),
- level: Level::Warn,
- line_col: None,
- },
- ],
- ];
- let mut errors = vec![];
- check_annotations(
- messages,
- vec![],
- Path::new("moobar"),
- &mut errors,
- &config,
- "",
- &comments,
- )
- .unwrap();
- match &errors[..] {
- [Error::ErrorsWithoutPattern { path, msgs, .. }]
- if path.as_ref().is_some_and(|p| p.line().get() == 5) =>
- {
- match &msgs[..] {
- [Message {
- message,
- level: Level::Warn,
- line_col: _,
- }] if message == "kaboom" => {}
- _ => panic!("{:#?}", msgs),
- }
- }
- _ => panic!("{:#?}", errors),
- }
-}
-
-#[test]
-fn missing_implicit_warn_pattern() {
- let s = r"
-use std::mem;
-//@require-annotations-for-level: ERROR
-fn main() {
- let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated)
- //~^ WARN: cake
-}
- ";
- let comments = Comments::parse(s).unwrap();
- let config = config();
- let messages = vec![
- vec![],
- vec![],
- vec![],
- vec![],
- vec![],
- vec![
- Message {
- message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(),
- level: Level::Error,
- line_col: None,
- },
- Message {
- message: "kaboom".to_string(),
- level: Level::Warn,
- line_col: None,
- },
- Message {
- message: "cake".to_string(),
- level: Level::Warn,
- line_col: None,
- },
- ],
- ];
- let mut errors = vec![];
- check_annotations(
- messages,
- vec![],
- Path::new("moobar"),
- &mut errors,
- &config,
- "",
- &comments,
- )
- .unwrap();
- match &errors[..] {
- [] => {}
- _ => panic!("{:#?}", errors),
- }
-}
diff --git a/vendor/ui_test-0.20.0/tests/integration.rs b/vendor/ui_test-0.20.0/tests/integration.rs
deleted file mode 100644
index abc9a92e2..000000000
--- a/vendor/ui_test-0.20.0/tests/integration.rs
+++ /dev/null
@@ -1,120 +0,0 @@
-use std::path::Path;
-
-use ui_test::color_eyre::Result;
-use ui_test::*;
-
-fn main() -> Result<()> {
- let path = Path::new(file!()).parent().unwrap();
- let root_dir = path.join("integrations");
- let mut config = Config {
- ..Config::cargo(root_dir.clone())
- };
- let args = Args::test()?;
- config.with_args(&args, true);
-
- config.program.args = vec![
- "test".into(),
- "--color".into(),
- "never".into(),
- "--quiet".into(),
- "--jobs".into(),
- "1".into(),
- "--no-fail-fast".into(),
- ];
- config
- .program
- .envs
- .push(("RUST_TEST_THREADS".into(), Some("1".into())));
-
- config
- .program
- .envs
- .push(("BLESS".into(), (!args.check).then(|| String::new().into())));
-
- config.stdout_filter("in ([0-9]m )?[0-9\\.]+s", "");
- config.stdout_filter(r#""--out-dir"(,)? "[^"]+""#, r#""--out-dir"$1 "$$TMP"#);
- config.filter(
- "( *process didn't exit successfully: `[^-]+)-[0-9a-f]+",
- "$1-HASH",
- );
- // Windows io::Error uses "exit code".
- config.filter("exit code", "exit status");
- config.filter(
- "The system cannot find the file specified.",
- "No such file or directory",
- );
- // The order of the `/deps` directory flag is flaky
- config.stdout_filter("/deps", "");
- config.path_filter(std::path::Path::new(path), "$DIR");
- config.stdout_filter("[0-9a-f]+\\.rmeta", "$$HASH.rmeta");
- // Windows backslashes are sometimes escaped.
- // Insert the replacement filter at the start to make sure the filter for single backslashes
- // runs afterwards.
- config
- .stdout_filters
- .insert(0, (Match::Exact(b"\\\\".to_vec()), b"\\"));
- config.filter("\\.exe", b"");
- config.stdout_filter(r#"(panic.*)\.rs:[0-9]+:[0-9]+"#, "$1.rs");
- config.filter(" [0-9]: .*", "");
- config.stdout_filter("/target/[^/]+/[^/]+/debug", "/target/$$TMP/$$TRIPLE/debug");
- config.stdout_filter("/target/.tmp[^/ \"]+", "/target/$$TMP");
- // Normalize proc macro filenames on windows to their linux repr
- config.stdout_filter("/([^/\\.]+)\\.dll", "/lib$1.so");
- // Normalize proc macro filenames on mac to their linux repr
- config.stdout_filter("/([^/\\.]+)\\.dylib", "/$1.so");
- config.stdout_filter("(command: )\"[^<rp][^\"]+", "$1\"$$CMD");
- config.filter("(src/.*?\\.rs):[0-9]+:[0-9]+", "$1:LL:CC");
- config.filter("program not found", "No such file or directory");
- config.filter(" \\(os error [0-9]+\\)", "");
-
- let text = if args.quiet {
- ui_test::status_emitter::Text::quiet()
- } else {
- ui_test::status_emitter::Text::verbose()
- };
-
- run_tests_generic(
- vec![
- Config {
- mode: Mode::Pass,
- ..config.clone()
- },
- Config {
- mode: Mode::Panic,
- ..config
- },
- ],
- |path, config| {
- let fail = path
- .parent()
- .unwrap()
- .file_name()
- .unwrap()
- .to_str()
- .unwrap()
- .ends_with("-fail");
- if cfg!(windows) && path.components().any(|c| c.as_os_str() == "basic-bin") {
- // on windows there's also a .pdb file, so we get additional errors that aren't there on other platforms
- return false;
- }
- path.ends_with("Cargo.toml")
- && path.parent().unwrap().parent().unwrap() == root_dir
- && match config.mode {
- Mode::Pass => !fail,
- // This is weird, but `cargo test` returns 101 instead of 1 when
- // multiple [[test]]s exist. If there's only one test, it returns
- // 1 on failure.
- Mode::Panic => fail,
- Mode::Run { .. } | Mode::Yolo { .. } | Mode::Fail { .. } => unreachable!(),
- }
- && default_any_file_filter(path, config)
- },
- |_, _, _| {},
- (
- text,
- ui_test::status_emitter::Gha::<true> {
- name: "integration tests".into(),
- },
- ),
- )
-}