diff options
Diffstat (limited to 'src/tools/clippy/tests/compile-test.rs')
-rw-r--r-- | src/tools/clippy/tests/compile-test.rs | 333 |
1 files changed, 120 insertions, 213 deletions
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index e46f8bf6f..f340cf593 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -1,16 +1,13 @@ -#![feature(test)] // compiletest_rs requires this attribute #![feature(lazy_cell)] #![feature(is_sorted)] #![cfg_attr(feature = "deny-warnings", deny(warnings))] #![warn(rust_2018_idioms, unused_lifetimes)] #![allow(unused_extern_crates)] -use compiletest::{status_emitter, CommandBuilder, OutputConflictHandling}; -use ui_test as compiletest; -use ui_test::Mode as TestMode; +use ui_test::{status_emitter, Args, CommandBuilder, Config, Match, Mode, OutputConflictHandling}; use std::collections::BTreeMap; -use std::env::{self, remove_var, set_var, var_os}; +use std::env::{self, set_var, var_os}; use std::ffi::{OsStr, OsString}; use std::fs; use std::path::{Path, PathBuf}; @@ -21,7 +18,6 @@ use test_utils::IS_RUSTC_TEST_SUITE; // in the depinfo file (otherwise cargo thinks they are unused) extern crate clippy_lints; extern crate clippy_utils; -extern crate derive_new; extern crate futures; extern crate if_chain; extern crate itertools; @@ -30,11 +26,12 @@ extern crate quote; extern crate syn; extern crate tokio; +mod test_utils; + /// All crates used in UI tests are listed here static TEST_DEPENDENCIES: &[&str] = &[ "clippy_lints", "clippy_utils", - "derive_new", "futures", "if_chain", "itertools", @@ -105,32 +102,35 @@ static EXTERN_FLAGS: LazyLock<Vec<String>> = LazyLock::new(|| { .collect() }); -mod test_utils; - // whether to run internal tests or not const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal"); -fn base_config(test_dir: &str) -> compiletest::Config { - let mut config = compiletest::Config { - mode: TestMode::Yolo, - stderr_filters: vec![], - stdout_filters: vec![], - output_conflict_handling: if var_os("RUSTC_BLESS").is_some_and(|v| v != "0") - || env::args().any(|arg| arg == "--bless") - { - OutputConflictHandling::Bless - } else { - OutputConflictHandling::Error("cargo uibless".into()) +fn canonicalize(path: impl AsRef<Path>) -> PathBuf { + let path = path.as_ref(); + fs::create_dir_all(path).unwrap(); + fs::canonicalize(path).unwrap_or_else(|err| panic!("{} cannot be canonicalized: {err}", path.display())) +} + +fn base_config(test_dir: &str) -> (Config, Args) { + let mut args = Args::test().unwrap(); + args.bless |= var_os("RUSTC_BLESS").is_some_and(|v| v != "0"); + + let mut config = Config { + mode: Mode::Yolo { + rustfix: ui_test::RustfixMode::Everything, }, + stderr_filters: vec![(Match::PathBackslash, b"/")], + stdout_filters: vec![], + filter_files: env::var("TESTNAME") + .map(|filters| filters.split(',').map(str::to_string).collect()) + .unwrap_or_default(), target: None, - out_dir: PathBuf::from(std::env::var_os("CARGO_TARGET_DIR").unwrap_or("target".into())).join("ui_test"), - ..compiletest::Config::rustc(Path::new("tests").join(test_dir)) + out_dir: canonicalize(var_os("CARGO_TARGET_DIR").unwrap_or_else(|| "target".into())).join("ui_test"), + ..Config::rustc(Path::new("tests").join(test_dir)) }; - - if let Some(_path) = option_env!("RUSTC_LIB_PATH") { - //let path = PathBuf::from(path); - //config.run_lib_path = path.clone(); - //config.compile_lib_path = path; + config.with_args(&args, /* bless by default */ false); + if let OutputConflictHandling::Error(err) = &mut config.output_conflict_handling { + *err = "cargo uibless".into(); } let current_exe_path = env::current_exe().unwrap(); let deps_path = current_exe_path.parent().unwrap(); @@ -155,52 +155,34 @@ fn base_config(test_dir: &str) -> compiletest::Config { config.program.args.push(dep.into()); } - // Normalize away slashes in windows paths. - config.stderr_filter(r"\\", "/"); - - //config.build_base = profile_path.join("test").join(test_dir); config.program.program = profile_path.join(if cfg!(windows) { "clippy-driver.exe" } else { "clippy-driver" }); - config -} - -fn test_filter() -> Box<dyn Sync + Fn(&Path) -> bool> { - if let Ok(filters) = env::var("TESTNAME") { - let filters: Vec<_> = filters.split(',').map(ToString::to_string).collect(); - Box::new(move |path| filters.iter().any(|f| path.to_string_lossy().contains(f))) - } else { - Box::new(|_| true) - } + (config, args) } fn run_ui() { - let config = base_config("ui"); - //config.rustfix_coverage = true; - // use tests/clippy.toml - let _g = VarGuard::set("CARGO_MANIFEST_DIR", fs::canonicalize("tests").unwrap()); - let _threads = VarGuard::set( - "RUST_TEST_THREADS", - // if RUST_TEST_THREADS is set, adhere to it, otherwise override it - env::var("RUST_TEST_THREADS").unwrap_or_else(|_| { - std::thread::available_parallelism() - .map_or(1, std::num::NonZeroUsize::get) - .to_string() - }), - ); + let (mut config, args) = base_config("ui"); + config + .program + .envs + .push(("CLIPPY_CONF_DIR".into(), Some(canonicalize("tests").into()))); - let test_filter = test_filter(); + let quiet = args.quiet; - compiletest::run_tests_generic( - config, - move |path| compiletest::default_file_filter(path) && test_filter(path), - compiletest::default_per_file_config, - status_emitter::Text, + ui_test::run_tests_generic( + vec![config], + ui_test::default_file_filter, + ui_test::default_per_file_config, + if quiet { + status_emitter::Text::quiet() + } else { + status_emitter::Text::verbose() + }, ) .unwrap(); - check_rustfix_coverage(); } fn run_internal_tests() { @@ -208,51 +190,59 @@ fn run_internal_tests() { if !RUN_INTERNAL_TESTS { return; } - let mut config = base_config("ui-internal"); + let (mut config, args) = base_config("ui-internal"); if let OutputConflictHandling::Error(err) = &mut config.output_conflict_handling { *err = "cargo uitest --features internal -- -- --bless".into(); } - let test_filter = test_filter(); + let quiet = args.quiet; - compiletest::run_tests_generic( - config, - move |path| compiletest::default_file_filter(path) && test_filter(path), - compiletest::default_per_file_config, - status_emitter::Text, + ui_test::run_tests_generic( + vec![config], + ui_test::default_file_filter, + ui_test::default_per_file_config, + if quiet { + status_emitter::Text::quiet() + } else { + status_emitter::Text::verbose() + }, ) .unwrap(); } fn run_ui_toml() { - let mut config = base_config("ui-toml"); - - config.stderr_filter( - ®ex::escape( - &fs::canonicalize("tests") - .unwrap() - .parent() - .unwrap() - .display() - .to_string() - .replace('\\', "/"), + let (mut config, args) = base_config("ui-toml"); + + config.stderr_filters = vec![ + ( + Match::Exact( + canonicalize("tests") + .parent() + .unwrap() + .to_string_lossy() + .as_bytes() + .to_vec(), + ), + b"$DIR", ), - "$$DIR", - ); + (Match::Exact(b"\\".to_vec()), b"/"), + ]; - let test_filter = test_filter(); + let quiet = args.quiet; ui_test::run_tests_generic( - config, - |path| compiletest::default_file_filter(path) && test_filter(path), - |config, path| { - let mut config = config.clone(); + vec![config], + ui_test::default_file_filter, + |config, path, _file_contents| { config .program .envs .push(("CLIPPY_CONF_DIR".into(), Some(path.parent().unwrap().into()))); - Some(config) }, - status_emitter::Text, + if quiet { + status_emitter::Text::quiet() + } else { + status_emitter::Text::verbose() + }, ) .unwrap(); } @@ -262,7 +252,7 @@ fn run_ui_cargo() { return; } - let mut config = base_config("ui-cargo"); + let (mut config, args) = base_config("ui-cargo"); config.program.input_file_flag = CommandBuilder::cargo().input_file_flag; config.program.out_dir_flag = CommandBuilder::cargo().out_dir_flag; config.program.args = vec!["clippy".into(), "--color".into(), "never".into(), "--quiet".into()]; @@ -280,30 +270,47 @@ fn run_ui_cargo() { }); config.edition = None; - config.stderr_filter( - ®ex::escape( - &fs::canonicalize("tests") - .unwrap() - .parent() - .unwrap() - .display() - .to_string() - .replace('\\', "/"), + config.stderr_filters = vec![ + ( + Match::Exact( + canonicalize("tests") + .parent() + .unwrap() + .to_string_lossy() + .as_bytes() + .to_vec(), + ), + b"$DIR", ), - "$$DIR", - ); + (Match::Exact(b"\\".to_vec()), b"/"), + ]; - let test_filter = test_filter(); + let quiet = args.quiet; + + let ignored_32bit = |path: &Path| { + // FIXME: for some reason the modules are linted in a different order for this test + cfg!(target_pointer_width = "32") && path.ends_with("tests/ui-cargo/module_style/fail_mod/Cargo.toml") + }; ui_test::run_tests_generic( - config, - |path| test_filter(path) && path.ends_with("Cargo.toml"), - |config, path| { - let mut config = config.clone(); - config.out_dir = PathBuf::from("target/ui_test_cargo/").join(path.parent().unwrap()); - Some(config) + vec![config], + |path, config| { + path.ends_with("Cargo.toml") && ui_test::default_any_file_filter(path, config) && !ignored_32bit(path) + }, + |config, path, _file_contents| { + config.out_dir = canonicalize( + std::env::current_dir() + .unwrap() + .join("target") + .join("ui_test_cargo/") + .join(path.parent().unwrap()), + ); + }, + if quiet { + status_emitter::Text::quiet() + } else { + status_emitter::Text::verbose() }, - status_emitter::Text, ) .unwrap(); } @@ -328,7 +335,6 @@ fn main() { "cargo" => run_ui_cargo as fn(), "toml" => run_ui_toml as fn(), "internal" => run_internal_tests as fn(), - "rustfix-coverage-known-exceptions-accuracy" => rustfix_coverage_known_exceptions_accuracy as fn(), "ui-cargo-toml-metadata" => ui_cargo_toml_metadata as fn(), _ => panic!("unknown speedtest: {speedtest} || accepted speedtests are: [ui, cargo, toml, internal]"), @@ -349,95 +355,20 @@ fn main() { f(); sum += start.elapsed().as_millis(); } - println!("average {} time: {} millis.", speedtest.to_uppercase(), sum / 1000); + println!( + "average {} time: {} millis.", + speedtest.to_uppercase(), + sum / u128::from(iterations) + ); } else { run_ui(); run_ui_toml(); run_ui_cargo(); run_internal_tests(); - rustfix_coverage_known_exceptions_accuracy(); ui_cargo_toml_metadata(); } } -const RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS: &[&str] = &[ - "assign_ops2.rs", - "borrow_deref_ref_unfixable.rs", - "cast_size_32bit.rs", - "char_lit_as_u8.rs", - "cmp_owned/without_suggestion.rs", - "dbg_macro.rs", - "deref_addrof_double_trigger.rs", - "doc/unbalanced_ticks.rs", - "eprint_with_newline.rs", - "explicit_counter_loop.rs", - "iter_skip_next_unfixable.rs", - "let_and_return.rs", - "literals.rs", - "map_flatten.rs", - "map_unwrap_or.rs", - "match_bool.rs", - "mem_replace_macro.rs", - "needless_arbitrary_self_type_unfixable.rs", - "needless_borrow_pat.rs", - "needless_for_each_unfixable.rs", - "nonminimal_bool.rs", - "print_literal.rs", - "redundant_static_lifetimes_multiple.rs", - "ref_binding_to_reference.rs", - "repl_uninit.rs", - "result_map_unit_fn_unfixable.rs", - "search_is_some.rs", - "single_component_path_imports_nested_first.rs", - "string_add.rs", - "suspicious_to_owned.rs", - "toplevel_ref_arg_non_rustfix.rs", - "unit_arg.rs", - "unnecessary_clone.rs", - "unnecessary_lazy_eval_unfixable.rs", - "write_literal.rs", - "write_literal_2.rs", -]; - -fn check_rustfix_coverage() { - let missing_coverage_path = Path::new("debug/test/ui/rustfix_missing_coverage.txt"); - let missing_coverage_path = if let Ok(target_dir) = std::env::var("CARGO_TARGET_DIR") { - PathBuf::from(target_dir).join(missing_coverage_path) - } else { - missing_coverage_path.to_path_buf() - }; - - if let Ok(missing_coverage_contents) = std::fs::read_to_string(missing_coverage_path) { - assert!(RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS.iter().is_sorted_by_key(Path::new)); - - for rs_file in missing_coverage_contents.lines() { - let rs_path = Path::new(rs_file); - if rs_path.starts_with("tests/ui/crashes") { - continue; - } - assert!(rs_path.starts_with("tests/ui/"), "{rs_file:?}"); - let filename = rs_path.strip_prefix("tests/ui/").unwrap(); - assert!( - RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS - .binary_search_by_key(&filename, Path::new) - .is_ok(), - "`{rs_file}` runs `MachineApplicable` diagnostics but is missing a `run-rustfix` annotation. \ - Please either add `//@run-rustfix` at the top of the file or add the file to \ - `RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS` in `tests/compile-test.rs`.", - ); - } - } -} - -fn rustfix_coverage_known_exceptions_accuracy() { - for filename in RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS { - let rs_path = Path::new("tests/ui").join(filename); - assert!(rs_path.exists(), "`{}` does not exist", rs_path.display()); - let fixed_path = rs_path.with_extension("fixed"); - assert!(!fixed_path.exists(), "`{}` exists", fixed_path.display()); - } -} - fn ui_cargo_toml_metadata() { let ui_cargo_path = Path::new("tests/ui-cargo"); let cargo_common_metadata_path = ui_cargo_path.join("cargo_common_metadata"); @@ -473,27 +404,3 @@ fn ui_cargo_toml_metadata() { ); } } - -/// Restores an env var on drop -#[must_use] -struct VarGuard { - key: &'static str, - value: Option<OsString>, -} - -impl VarGuard { - fn set(key: &'static str, val: impl AsRef<OsStr>) -> Self { - let value = var_os(key); - set_var(key, val); - Self { key, value } - } -} - -impl Drop for VarGuard { - fn drop(&mut self) { - match self.value.as_deref() { - None => remove_var(self.key), - Some(value) => set_var(self.key, value), - } - } -} |