Ed Page 57c97cc190 test(script): Switch frontmatter tests to end-to-end
This will make it easier to validate error improvements I'm working on
as well as make it easier to update from rust-lang/rust
2025-08-29 16:11:59 -05:00

416 lines
15 KiB
Rust

use std::collections::BTreeMap;
use snapbox::assert_data_eq;
use crate::prelude::*;
#[test]
fn ensure_all_fixtures_have_tests() {
let mut code_gen_divider = "//".to_owned();
code_gen_divider.push_str(" START CODE GENERATION");
let self_path = snapbox::utils::current_rs!();
let self_source = std::fs::read_to_string(&self_path).unwrap();
let (header, _) = self_source
.split_once(&code_gen_divider)
.expect("code-gen divider is present");
let header = header.trim();
let fixture_root = snapbox::utils::current_dir!().join("rustc_fixtures");
let mut fixtures = BTreeMap::new();
for entry in std::fs::read_dir(fixture_root).unwrap() {
let entry = entry.unwrap();
let path = entry.path();
let fn_name = file_to_fn(&path);
fixtures
.entry(fn_name.clone())
.or_insert_with(|| Fixture::new(fn_name))
.add_path(path);
}
let fixtures = fixtures
.into_values()
.filter(Fixture::is_valid)
.map(|f| f.to_string())
.collect::<String>();
let actual = format!(
"{header}
{code_gen_divider}
{fixtures}"
);
assert_data_eq!(actual, snapbox::Data::read_from(&self_path, None).raw());
}
fn file_to_fn(path: &std::path::Path) -> String {
let name = path.file_stem().unwrap().to_str().unwrap();
name.replace("-", "_")
}
fn sanitize_path(path: &std::path::Path) -> String {
path.strip_prefix(env!("CARGO_MANIFEST_DIR"))
.unwrap()
.as_os_str()
.to_string_lossy()
.replace("\\", "/")
}
struct Fixture {
fn_name: String,
input: std::path::PathBuf,
output: Option<std::path::PathBuf>,
}
impl Fixture {
fn new(fn_name: String) -> Self {
Self {
fn_name,
input: Default::default(),
output: Default::default(),
}
}
fn is_valid(&self) -> bool {
!self.input.as_os_str().is_empty()
}
fn add_path(&mut self, path: std::path::PathBuf) {
if path.extension().map(|ext| ext.to_str().unwrap()) == Some("rs") {
assert!(
self.input.as_os_str().is_empty(),
"similarly named fixtures:/n{}/n{}",
self.input.display(),
path.display()
);
self.input = path;
} else {
assert!(
self.output.is_none(),
"conflicting assertions:/n{}/n{}",
self.output.as_ref().unwrap().display(),
path.display()
);
self.output = Some(path);
}
}
}
impl std::fmt::Display for Fixture {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let fn_name = &self.fn_name;
let fixture_path = sanitize_path(&self.input);
match self
.output
.as_ref()
.map(|path| path.extension().unwrap().to_str().unwrap())
{
Some("stderr") => {
let assertion_path = sanitize_path(self.output.as_ref().unwrap());
write!(
fmt,
r#"
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn {fn_name}() {{
let fixture_path = {fixture_path:?};
let assertion_path = {assertion_path:?};
assert_failure(fixture_path, assertion_path);
}}
"#
)
}
Some("stdout") | None => {
let mut backup_path = self.input.clone();
backup_path.set_extension("stdout");
let assertion_path = sanitize_path(self.output.as_ref().unwrap_or(&backup_path));
write!(
fmt,
r#"
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn {fn_name}() {{
let fixture_path = {fixture_path:?};
let assertion_path = {assertion_path:?};
assert_success(fixture_path, assertion_path);
}}
"#
)
}
Some(_) => {
panic!(
"unsupported assertiong: {}",
self.output.as_ref().unwrap().display()
)
}
}
}
}
#[track_caller]
fn assert_success(fixture_path: &str, assertion_path: &str) {
let p = cargo_test_support::project()
.file("script", &std::fs::read_to_string(fixture_path).unwrap())
.build();
// `read-manifest` to validate frontmatter content without processing deps, compiling
p.cargo("-Zscript read-manifest --manifest-path script")
.masquerade_as_nightly_cargo(&["script"])
.with_stdout_data(snapbox::Data::read_from(
std::path::Path::new(assertion_path),
Some(snapbox::data::DataFormat::Json),
))
.run();
}
#[track_caller]
fn assert_failure(fixture_path: &str, assertion_path: &str) {
let p = cargo_test_support::project()
.file("script", &std::fs::read_to_string(fixture_path).unwrap())
.build();
// `read-manifest` to validate frontmatter content without processing deps, compiling
p.cargo("-Zscript read-manifest --manifest-path script")
.masquerade_as_nightly_cargo(&["script"])
.with_status(101)
.with_stderr_data(snapbox::Data::read_from(
std::path::Path::new(assertion_path),
None,
))
.run();
}
// START CODE GENERATION
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn dot_in_infostring_leading() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/dot-in-infostring-leading.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/dot-in-infostring-leading.stderr";
assert_failure(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn dot_in_infostring_non_leading() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/dot-in-infostring-non-leading.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/dot-in-infostring-non-leading.stderr";
assert_failure(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn escape() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/escape.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/escape.stdout";
assert_success(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn extra_after_end() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/extra-after-end.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/extra-after-end.stderr";
assert_failure(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn frontmatter_after_tokens() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/frontmatter-after-tokens.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/frontmatter-after-tokens.stdout";
assert_success(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn frontmatter_contains_whitespace() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/frontmatter-contains-whitespace.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/frontmatter-contains-whitespace.stderr";
assert_failure(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn frontmatter_crlf() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/frontmatter-crlf.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/frontmatter-crlf.stdout";
assert_success(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn frontmatter_inner_hyphens_1() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/frontmatter-inner-hyphens-1.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/frontmatter-inner-hyphens-1.stdout";
assert_success(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn frontmatter_inner_hyphens_2() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/frontmatter-inner-hyphens-2.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/frontmatter-inner-hyphens-2.stdout";
assert_success(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn frontmatter_non_lexible_tokens() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/frontmatter-non-lexible-tokens.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/frontmatter-non-lexible-tokens.stdout";
assert_success(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn frontmatter_whitespace_1() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/frontmatter-whitespace-1.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/frontmatter-whitespace-1.stdout";
assert_success(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn frontmatter_whitespace_2() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/frontmatter-whitespace-2.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/frontmatter-whitespace-2.stderr";
assert_failure(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn frontmatter_whitespace_3() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/frontmatter-whitespace-3.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/frontmatter-whitespace-3.stdout";
assert_success(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn frontmatter_whitespace_4() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/frontmatter-whitespace-4.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/frontmatter-whitespace-4.stdout";
assert_success(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn hyphen_in_infostring_leading() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/hyphen-in-infostring-leading.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/hyphen-in-infostring-leading.stderr";
assert_failure(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn hyphen_in_infostring_non_leading() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/hyphen-in-infostring-non-leading.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/hyphen-in-infostring-non-leading.stderr";
assert_failure(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn included_frontmatter() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/included-frontmatter.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/included-frontmatter.stdout";
assert_success(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn infostring_fail() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/infostring-fail.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/infostring-fail.stderr";
assert_failure(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn mismatch_1() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/mismatch-1.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/mismatch-1.stderr";
assert_failure(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn mismatch_2() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/mismatch-2.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/mismatch-2.stderr";
assert_failure(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn multifrontmatter() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/multifrontmatter.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/multifrontmatter.stderr";
assert_failure(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn multifrontmatter_2() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/multifrontmatter-2.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/multifrontmatter-2.stdout";
assert_success(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn proc_macro_observer() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/proc-macro-observer.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/proc-macro-observer.stdout";
assert_success(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn shebang() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/shebang.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/shebang.stdout";
assert_success(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn unclosed_1() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/unclosed-1.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/unclosed-1.stderr";
assert_failure(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn unclosed_2() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/unclosed-2.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/unclosed-2.stderr";
assert_failure(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn unclosed_3() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/unclosed-3.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/unclosed-3.stderr";
assert_failure(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn unclosed_4() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/unclosed-4.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/unclosed-4.stderr";
assert_failure(fixture_path, assertion_path);
}
#[cargo_test(nightly, reason = "-Zscript is unstable")]
#[rustfmt::skip] // code-generated
fn unclosed_5() {
let fixture_path = "tests/testsuite/script/rustc_fixtures/unclosed-5.rs";
let assertion_path = "tests/testsuite/script/rustc_fixtures/unclosed-5.stderr";
assert_failure(fixture_path, assertion_path);
}