From fb071a14bd065da54c5bbc497033503932925cb2 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 25 Aug 2022 10:10:32 +0000 Subject: [PATCH] Use ui_test from crates.io instead of having it in-tree --- Cargo.lock | 4 +- Cargo.toml | 2 +- miri | 4 +- ui_test/Cargo.lock | 578 -------------------------------- ui_test/Cargo.toml | 21 -- ui_test/README.md | 51 --- ui_test/src/dependencies.rs | 137 -------- ui_test/src/lib.rs | 637 ------------------------------------ ui_test/src/parser.rs | 327 ------------------ ui_test/src/parser/tests.rs | 85 ----- ui_test/src/rustc_stderr.rs | 155 --------- ui_test/src/tests.rs | 294 ----------------- 12 files changed, 5 insertions(+), 2290 deletions(-) delete mode 100644 ui_test/Cargo.lock delete mode 100644 ui_test/Cargo.toml delete mode 100644 ui_test/README.md delete mode 100644 ui_test/src/dependencies.rs delete mode 100644 ui_test/src/lib.rs delete mode 100644 ui_test/src/parser.rs delete mode 100644 ui_test/src/parser/tests.rs delete mode 100644 ui_test/src/rustc_stderr.rs delete mode 100644 ui_test/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index f660ed77620..b0601ba3d46 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -756,7 +756,9 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.1.0" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a7bfdb147f57c498ca629c7802b57899de0bb82ae36b6f01f1540da41832f1" dependencies = [ "cargo_metadata", "color-eyre", diff --git a/Cargo.toml b/Cargo.toml index 208b3a76443..39bc9185db3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ libc = "0.2" [dev-dependencies] colored = "2" -ui_test = { path = "ui_test" } +ui_test = "0.1" # Features chosen to match those required by env_logger, to avoid rebuilds regex = { version = "1.5.5", default-features = false, features = ["perf", "std"] } lazy_static = "1.4.0" diff --git a/miri b/miri index a72fe91f594..84bd7481709 100755 --- a/miri +++ b/miri @@ -186,9 +186,8 @@ test|bless) export MIRI_BLESS="Gesundheit" fi # Then test, and let caller control flags. - # Only in root project and ui_test as `cargo-miri` has no tests. + # Only in root project as `cargo-miri` has no tests. $CARGO test $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" - $CARGO test $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml "$@" ;; run) # Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so @@ -219,7 +218,6 @@ fmt) ;; clippy) $CARGO clippy $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" - $CARGO clippy $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml --all-targets "$@" $CARGO clippy $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; cargo) diff --git a/ui_test/Cargo.lock b/ui_test/Cargo.lock deleted file mode 100644 index 9addea9b19d..00000000000 --- a/ui_test/Cargo.lock +++ /dev/null @@ -1,578 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" -dependencies = [ - "memchr", -] - -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "camino" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", -] - -[[package]] -name = "cc" -version = "1.0.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "color-eyre" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ebf286c900a6d5867aeff75cfee3192857bb7f24b547d4f0df2ed6baa812c90" -dependencies = [ - "backtrace", - "color-spantrace", - "eyre", - "indenter", - "once_cell", - "owo-colors", - "tracing-error", -] - -[[package]] -name = "color-spantrace" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce" -dependencies = [ - "once_cell", - "owo-colors", - "tracing-core", - "tracing-error", -] - -[[package]] -name = "colored" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" -dependencies = [ - "atty", - "lazy_static", - "winapi", -] - -[[package]] -name = "crossbeam" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845" -dependencies = [ - "cfg-if", - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "lazy_static", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" -dependencies = [ - "cfg-if", - "lazy_static", -] - -[[package]] -name = "ctor" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "diff" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" - -[[package]] -name = "eyre" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" -dependencies = [ - "indenter", - "once_cell", -] - -[[package]] -name = "gimli" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "indenter" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" - -[[package]] -name = "itoa" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "miniz_oxide" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" -dependencies = [ - "adler", -] - -[[package]] -name = "object" -version = "0.28.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" - -[[package]] -name = "output_vt100" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" -dependencies = [ - "winapi", -] - -[[package]] -name = "owo-colors" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "decf7381921fea4dcb2549c5667eda59b3ec297ab7e2b5fc33eac69d2e7da87b" - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "pretty_assertions" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563" -dependencies = [ - "ansi_term", - "ctor", - "diff", - "output_vt100", -] - -[[package]] -name = "proc-macro2" -version = "1.0.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" - -[[package]] -name = "rustc-demangle" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[package]] -name = "ryu" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "semver" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" -dependencies = [ - "serde", -] - -[[package]] -name = "serde" -version = "1.0.137" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.137" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sharded-slab" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "syn" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thread_local" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" -dependencies = [ - "once_cell", -] - -[[package]] -name = "tracing" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-error" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" -dependencies = [ - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a713421342a5a666b7577783721d3117f1b69a393df803ee17bb73b1e122a59" -dependencies = [ - "sharded-slab", - "thread_local", - "tracing-core", -] - -[[package]] -name = "ui_test" -version = "0.1.0" -dependencies = [ - "cargo_metadata", - "color-eyre", - "colored", - "crossbeam", - "lazy_static", - "pretty_assertions", - "regex", - "rustc_version", - "serde", - "serde_json", -] - -[[package]] -name = "unicode-ident" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/ui_test/Cargo.toml b/ui_test/Cargo.toml deleted file mode 100644 index bb14eb7ecfe..00000000000 --- a/ui_test/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "ui_test" -version = "0.1.0" -edition = "2021" - -[lib] -test = true # we have unit tests -doctest = false # but no doc tests - -[dependencies] -rustc_version = "0.4" -colored = "2" -# Features chosen to match those required by env_logger, to avoid rebuilds -regex = { version = "1.5.5", default-features = false, features = ["perf", "std"] } -pretty_assertions = "1.2.1" -crossbeam = "0.8.1" -lazy_static = "1.4.0" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -color-eyre = { version = "0.6.1", default-features = false, features = ["capture-spantrace"] } -cargo_metadata = "0.15" diff --git a/ui_test/README.md b/ui_test/README.md deleted file mode 100644 index 3db3361faa5..00000000000 --- a/ui_test/README.md +++ /dev/null @@ -1,51 +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). - -## 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`. -* `//@stderr-per-bitwidth` produces one stderr file per bitwidth, as they may differ significantly sometimes -* `//@error-pattern: XXX` make sure the stderr output contains `XXX` -* `//@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 before the `~` in square brackets: `//[XXX]~` -* `//@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. - -## Significant differences to compiletest-rs - -* `ignore-target-*` and `only-target-*` opereate solely on the triple, instead of supporting things like `macos` -* only `//~` comments can be individualized per revision -* 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 diff --git a/ui_test/src/dependencies.rs b/ui_test/src/dependencies.rs deleted file mode 100644 index 582641b97ae..00000000000 --- a/ui_test/src/dependencies.rs +++ /dev/null @@ -1,137 +0,0 @@ -use color_eyre::eyre::{bail, Result}; -use std::{ - collections::{HashMap, HashSet}, - path::{Path, PathBuf}, - process::Command, -}; - -use crate::{Config, 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, - /// The name as chosen in the `Cargo.toml` and its corresponding rmeta file. - pub dependencies: Vec<(String, PathBuf)>, -} - -/// Compiles dependencies and returns the crate names and corresponding rmeta files. -pub fn build_dependencies(config: &Config) -> Result { - let manifest_path = match &config.dependencies_crate_manifest_path { - Some(path) => path, - None => return Ok(Default::default()), - }; - let (program, args, envs): (&Path, &[_], &[_]) = match &config.dependency_builder { - Some(db) => (&db.program, &db.args, &db.envs), - None => (Path::new("cargo"), &[], &[]), - }; - let mut build = Command::new(program); - build.args(args); - // HACK: we're using `cargo run` (or `cargo miri run`), because the latter does not - // support `cargo miri build` yet. - build.arg("run"); - - 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 setup_command = |cmd: &mut Command| { - cmd.envs(envs.iter().map(|(k, v)| (k, v))); - cmd.arg("--manifest-path").arg(manifest_path); - if matches!(config.output_conflict_handling, OutputConflictHandling::Error) { - cmd.arg("--locked"); - } - }; - - setup_command(&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:\nstderr:\n{stderr}\n\nstdout:{stdout}"); - } - - // Collect all artifacts generated - let output = output.stdout; - let output = String::from_utf8(output)?; - let mut import_paths: HashSet = HashSet::new(); - let mut artifacts: HashMap<_, _> = output - .lines() - .filter_map(|line| { - let message = serde_json::from_str::(line).ok()?; - if let cargo_metadata::Message::CompilerArtifact(artifact) = message { - for filename in &artifact.filenames { - import_paths.insert(filename.parent().unwrap().into()); - } - let filename = artifact - .filenames - .into_iter() - .find(|filename| filename.extension() == Some("rmeta"))?; - Some((artifact.package_id, filename.into_std_path_buf())) - } else { - None - } - }) - .collect(); - - // Check which crates are mentioned in the crate itself - let mut metadata = cargo_metadata::MetadataCommand::new().cargo_command(); - setup_command(&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)?; - - 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() - .map(|package| { - // Get the id for the package matching the version requirement of the dep - let id = &metadata - .packages - .iter() - .find(|&dep| dep.name == package.name && package.req.matches(&dep.version)) - .expect("dependency does not exist") - .id; - // Return the name chosen in `Cargo.toml` and the path to the corresponding artifact - ( - package.rename.clone().unwrap_or_else(|| package.name.clone()), - artifacts.remove(id).expect("package without artifact"), - ) - }) - .collect(); - let import_paths = import_paths.into_iter().collect(); - return Ok(Dependencies { dependencies, import_paths }); - } - - bail!("no json found in cargo-metadata output") -} diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs deleted file mode 100644 index c87ac938ffd..00000000000 --- a/ui_test/src/lib.rs +++ /dev/null @@ -1,637 +0,0 @@ -#![allow( - clippy::enum_variant_names, - clippy::useless_format, - clippy::too_many_arguments, - rustc::internal -)] - -use std::collections::VecDeque; -use std::ffi::OsString; -use std::fmt::Write; -use std::path::{Path, PathBuf}; -use std::process::{Command, ExitStatus}; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::Mutex; - -pub use color_eyre; -use color_eyre::eyre::Result; -use colored::*; -use parser::{ErrorMatch, Pattern}; -use regex::Regex; -use rustc_stderr::{Level, Message}; - -use crate::dependencies::build_dependencies; -use crate::parser::{Comments, Condition}; - -mod dependencies; -mod parser; -mod rustc_stderr; -#[cfg(test)] -mod tests; - -#[derive(Debug)] -pub struct Config { - /// Arguments passed to the binary that is executed. - pub args: Vec, - /// `None` to run on the host, otherwise a target triple - pub target: Option, - /// Filters applied to stderr output before processing it - pub stderr_filters: Filter, - /// Filters applied to stdout output before processing it - pub stdout_filters: Filter, - /// The folder in which to start searching for .rs files - pub root_dir: PathBuf, - pub mode: Mode, - pub program: PathBuf, - pub output_conflict_handling: OutputConflictHandling, - /// Only run tests with one of these strings in their path/name - pub path_filter: Vec, - /// Path to a `Cargo.toml` that describes which dependencies the tests can access. - pub dependencies_crate_manifest_path: Option, - /// Can be used to override what command to run instead of `cargo` to build the - /// dependencies in `manifest_path` - pub dependency_builder: Option, - /// Print one character per test instead of one line - pub quiet: bool, -} - -#[derive(Debug)] -pub struct DependencyBuilder { - pub program: PathBuf, - pub args: Vec, - pub envs: Vec<(String, OsString)>, -} - -#[derive(Debug)] -pub enum OutputConflictHandling { - /// The default: emit a diff of the expected/actual output. - Error, - /// 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, -} - -pub type Filter = Vec<(Regex, &'static str)>; - -pub fn run_tests(mut config: Config) -> Result<()> { - eprintln!(" Compiler flags: {:?}", config.args); - - // Get the triple with which to run the tests - let target = config.target.clone().unwrap_or_else(|| config.get_host()); - - eprintln!(" Building test dependencies..."); - let dependencies = build_dependencies(&config)?; - for (name, dependency) in dependencies.dependencies { - config.args.push("--extern".into()); - let mut dep = OsString::from(name); - dep.push("="); - dep.push(dependency); - config.args.push(dep); - } - for import_path in dependencies.import_paths { - config.args.push("-L".into()); - config.args.push(import_path.into()); - } - let config = config; - - // A channel for files to process - let (submit, receive) = crossbeam::channel::unbounded(); - - // Some statistics and failure reports. - let failures = Mutex::new(vec![]); - let succeeded = AtomicUsize::default(); - let ignored = AtomicUsize::default(); - let filtered = AtomicUsize::default(); - - crossbeam::scope(|s| -> Result<()> { - // Create a thread that is in charge of walking the directory and submitting jobs. - // It closes the channel when it is done. - s.spawn(|_| { - let mut todo = VecDeque::new(); - todo.push_back(config.root_dir.clone()); - while let Some(path) = todo.pop_front() { - if path.is_dir() { - // 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().collect::, _>>().unwrap(); - entries.sort_by_key(|e| e.file_name()); - for entry in entries { - todo.push_back(entry.path()); - } - } else if path.extension().map(|ext| ext == "rs").unwrap_or(false) { - // Forward .rs files to the test workers. - submit.send(path).unwrap(); - } - } - // There will be no more jobs. This signals the workers to quit. - // (This also ensures `submit` is moved into this closure.) - drop(submit); - }); - - // A channel for the messages emitted by the individual test threads. - let (finished_files_sender, finished_files_recv) = crossbeam::channel::unbounded(); - enum TestResult { - Ok, - Failed, - Ignored, - } - - s.spawn(|_| { - if config.quiet { - for (i, (_, result)) in finished_files_recv.into_iter().enumerate() { - // Humans start counting at 1 - let i = i + 1; - match result { - TestResult::Ok => eprint!("{}", ".".green()), - TestResult::Failed => eprint!("{}", "F".red().bold()), - TestResult::Ignored => eprint!("{}", "i".yellow()), - } - if i % 100 == 0 { - eprintln!(" {i}"); - } - } - } else { - for (msg, result) in finished_files_recv { - eprint!("{msg} ... "); - eprintln!( - "{}", - match result { - TestResult::Ok => "ok".green(), - TestResult::Failed => "FAILED".red().bold(), - TestResult::Ignored => "ignored (in-test comment)".yellow(), - } - ); - } - } - }); - - let mut threads = vec![]; - - // Create N worker threads that receive files to test. - for _ in 0..std::thread::available_parallelism().unwrap().get() { - let finished_files_sender = finished_files_sender.clone(); - threads.push(s.spawn(|_| -> Result<()> { - let finished_files_sender = finished_files_sender; - for path in &receive { - if !config.path_filter.is_empty() { - let path_display = path.display().to_string(); - if !config.path_filter.iter().any(|filter| path_display.contains(filter)) { - filtered.fetch_add(1, Ordering::Relaxed); - continue; - } - } - let comments = Comments::parse_file(&path)?; - // Ignore file if only/ignore rules do (not) apply - if !test_file_conditions(&comments, &target, &config) { - ignored.fetch_add(1, Ordering::Relaxed); - finished_files_sender - .send((path.display().to_string(), TestResult::Ignored))?; - continue; - } - // Run the test for all revisions - for revision in - comments.revisions.clone().unwrap_or_else(|| vec![String::new()]) - { - let (m, errors, stderr) = - run_test(&path, &config, &target, &revision, &comments); - - // Using a single `eprintln!` to prevent messages from threads from getting intermingled. - let mut msg = format!("{}", path.display()); - if !revision.is_empty() { - write!(msg, " (revision `{revision}`) ").unwrap(); - } - if errors.is_empty() { - finished_files_sender.send((msg, TestResult::Ok))?; - succeeded.fetch_add(1, Ordering::Relaxed); - } else { - finished_files_sender.send((msg, TestResult::Failed))?; - failures.lock().unwrap().push(( - path.clone(), - m, - revision, - errors, - stderr, - )); - } - } - } - Ok(()) - })); - } - - for thread in threads { - thread.join().unwrap()?; - } - Ok(()) - }) - .unwrap()?; - - // Print all errors in a single thread to show reliable output - let failures = failures.into_inner().unwrap(); - let succeeded = succeeded.load(Ordering::Relaxed); - let ignored = ignored.load(Ordering::Relaxed); - let filtered = filtered.load(Ordering::Relaxed); - if !failures.is_empty() { - for (path, miri, revision, errors, stderr) in &failures { - eprintln!(); - eprint!("{}", path.display().to_string().underline().bold()); - if !revision.is_empty() { - eprint!(" (revision `{}`)", revision); - } - eprint!(" {}", "FAILED:".red().bold()); - eprintln!(); - eprintln!("command: {:?}", miri); - eprintln!(); - for error in errors { - match error { - Error::ExitStatus(mode, exit_status) => eprintln!("{mode:?} got {exit_status}"), - Error::PatternNotFound { pattern, definition_line } => { - match pattern { - Pattern::SubString(s) => - eprintln!("substring `{s}` {} in stderr output", "not found".red()), - Pattern::Regex(r) => - eprintln!("`/{r}/` does {} stderr output", "not match".red()), - } - eprintln!( - "expected because of pattern here: {}:{definition_line}", - path.display().to_string().bold() - ); - } - Error::NoPatternsFound => { - eprintln!("{}", "no error patterns found in failure test".red()); - } - Error::PatternFoundInPassTest => - eprintln!("{}", "error pattern found in success test".red()), - Error::OutputDiffers { path, actual, expected } => { - eprintln!("actual output differed from expected {}", path.display()); - eprintln!("{}", pretty_assertions::StrComparison::new(expected, actual)); - eprintln!() - } - Error::ErrorsWithoutPattern { path: None, msgs } => { - eprintln!( - "There were {} unmatched diagnostics that occurred outside the testfile and had no pattern", - msgs.len(), - ); - for Message { level, message } in msgs { - eprintln!(" {level:?}: {message}") - } - } - Error::ErrorsWithoutPattern { path: Some((path, line)), msgs } => { - eprintln!( - "There were {} unmatched diagnostics at {}:{line}", - msgs.len(), - path.display() - ); - for Message { level, message } in msgs { - eprintln!(" {level:?}: {message}") - } - } - } - eprintln!(); - } - eprintln!("full stderr:"); - eprintln!("{}", stderr); - eprintln!(); - } - eprintln!("{}", "FAILURES:".red().underline().bold()); - for (path, _miri, _revision, _errors, _stderr) in &failures { - eprintln!(" {}", path.display()); - } - eprintln!(); - eprintln!( - "test result: {}. {} tests failed, {} tests passed, {} ignored, {} filtered out", - "FAIL".red(), - failures.len().to_string().red().bold(), - succeeded.to_string().green(), - ignored.to_string().yellow(), - filtered.to_string().yellow(), - ); - std::process::exit(1); - } - eprintln!(); - eprintln!( - "test result: {}. {} tests passed, {} ignored, {} filtered out", - "ok".green(), - succeeded.to_string().green(), - ignored.to_string().yellow(), - filtered.to_string().yellow(), - ); - eprintln!(); - Ok(()) -} - -#[derive(Debug)] -enum Error { - /// Got an invalid exit status for the given mode. - ExitStatus(Mode, ExitStatus), - PatternNotFound { - pattern: Pattern, - definition_line: usize, - }, - /// 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 { - path: PathBuf, - actual: String, - expected: String, - }, - ErrorsWithoutPattern { - msgs: Vec, - path: Option<(PathBuf, usize)>, - }, -} - -type Errors = Vec; - -fn run_test( - path: &Path, - config: &Config, - target: &str, - revision: &str, - comments: &Comments, -) -> (Command, Errors, String) { - // Run miri - let mut miri = Command::new(&config.program); - miri.args(config.args.iter()); - miri.arg(path); - if !revision.is_empty() { - miri.arg(format!("--cfg={revision}")); - } - miri.arg("--error-format=json"); - for arg in &comments.compile_flags { - miri.arg(arg); - } - miri.envs(comments.env_vars.iter().map(|(k, v)| (k, v))); - let output = miri.output().expect("could not execute miri"); - let mut errors = config.mode.ok(output.status); - let stderr = check_test_result( - path, - config, - target, - revision, - comments, - &mut errors, - &output.stdout, - &output.stderr, - ); - (miri, errors, stderr) -} - -fn check_test_result( - path: &Path, - config: &Config, - target: &str, - revision: &str, - comments: &Comments, - errors: &mut Errors, - stdout: &[u8], - stderr: &[u8], -) -> String { - // Always remove annotation comments from stderr. - let diagnostics = rustc_stderr::process(path, stderr); - let stdout = std::str::from_utf8(stdout).unwrap(); - // Check output files (if any) - let revised = |extension: &str| { - if revision.is_empty() { - extension.to_string() - } else { - format!("{}.{}", revision, extension) - } - }; - // Check output files against actual output - check_output( - &diagnostics.rendered, - path, - errors, - revised("stderr"), - target, - &config.stderr_filters, - config, - comments, - ); - check_output( - stdout, - path, - errors, - revised("stdout"), - target, - &config.stdout_filters, - config, - comments, - ); - // Check error annotations in the source against output - check_annotations( - diagnostics.messages, - diagnostics.messages_from_unknown_file_or_line, - path, - errors, - config, - revision, - comments, - ); - diagnostics.rendered -} - -fn check_annotations( - mut messages: Vec>, - mut messages_from_unknown_file_or_line: Vec, - path: &Path, - errors: &mut Errors, - config: &Config, - revision: &str, - comments: &Comments, -) { - if let Some((ref error_pattern, definition_line)) = comments.error_pattern { - // first check the diagnostics messages outside of our file. We check this first, so that - // you can mix in-file annotations with //@error-pattern 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 { pattern: error_pattern.clone(), definition_line }); - } - } - - // 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, revision: ref rev, definition_line, line, level } in - &comments.error_matches - { - if let Some(rev) = rev { - if rev != revision { - continue; - } - } - - // 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. - lowest_annotation_level = std::cmp::min(lowest_annotation_level, level); - - if let Some(msgs) = messages.get_mut(line) { - 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: pattern.clone(), definition_line }); - } - - let filter = |msgs: Vec| -> Vec<_> { - msgs.into_iter() - .filter(|msg| { - msg.level - >= comments.require_annotations_for_level.unwrap_or(lowest_annotation_level) - }) - .collect() - }; - - 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() { - errors - .push(Error::ErrorsWithoutPattern { path: Some((path.to_path_buf(), line)), msgs }); - } - } - - match (config.mode, comments.error_pattern.is_some() || !comments.error_matches.is_empty()) { - (Mode::Pass, true) | (Mode::Panic, true) => errors.push(Error::PatternFoundInPassTest), - (Mode::Fail, false) => errors.push(Error::NoPatternsFound), - _ => {} - } -} - -fn check_output( - output: &str, - path: &Path, - errors: &mut Errors, - kind: String, - target: &str, - filters: &Filter, - config: &Config, - comments: &Comments, -) { - let output = normalize(path, output, filters, comments); - let path = output_path(path, comments, kind, target); - match config.output_conflict_handling { - OutputConflictHandling::Bless => - if output.is_empty() { - let _ = std::fs::remove_file(path); - } else { - std::fs::write(path, &output).unwrap(); - }, - OutputConflictHandling::Error => { - let expected_output = std::fs::read_to_string(&path).unwrap_or_default(); - if output != expected_output { - errors.push(Error::OutputDiffers { - path, - actual: output, - expected: expected_output, - }); - } - } - OutputConflictHandling::Ignore => {} - } -} - -fn output_path(path: &Path, comments: &Comments, kind: String, target: &str) -> PathBuf { - if comments.stderr_per_bitwidth { - return path.with_extension(format!("{}bit.{kind}", get_pointer_width(target))); - } - path.with_extension(kind) -} - -fn test_condition(condition: &Condition, target: &str, config: &Config) -> bool { - match condition { - Condition::Bitwidth(bits) => get_pointer_width(target) == *bits, - Condition::Target(t) => target.contains(t), - Condition::OnHost => config.target.is_none(), - } -} - -/// Returns whether according to the in-file conditions, this file should be run. -fn test_file_conditions(comments: &Comments, target: &str, config: &Config) -> bool { - if comments.ignore.iter().any(|c| test_condition(c, target, config)) { - return false; - } - comments.only.iter().all(|c| test_condition(c, target, 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: &str, filters: &Filter, comments: &Comments) -> String { - // Useless paths - let mut text = text.replace(&path.parent().unwrap().display().to_string(), "$DIR"); - if let Some(lib_path) = option_env!("RUSTC_LIB_PATH") { - text = text.replace(lib_path, "RUSTLIB"); - } - - for (regex, replacement) in filters.iter() { - text = regex.replace_all(&text, *replacement).to_string(); - } - - for (from, to) in &comments.normalize_stderr { - text = from.replace_all(&text, to).to_string(); - } - text -} - -impl Config { - fn get_host(&self) -> String { - rustc_version::VersionMeta::for_command(std::process::Command::new(&self.program)) - .expect("failed to parse rustc version info") - .host - } -} - -#[derive(Copy, Clone, Debug)] -pub enum Mode { - // The test passes a full execution of the rustc driver - Pass, - // The rustc driver panicked - Panic, - // The rustc driver emitted an error - Fail, -} - -impl Mode { - fn ok(self, status: ExitStatus) -> Errors { - match (status.code(), self) { - (Some(1), Mode::Fail) | (Some(101), Mode::Panic) | (Some(0), Mode::Pass) => vec![], - _ => vec![Error::ExitStatus(self, status)], - } - } -} diff --git a/ui_test/src/parser.rs b/ui_test/src/parser.rs deleted file mode 100644 index d583e625fac..00000000000 --- a/ui_test/src/parser.rs +++ /dev/null @@ -1,327 +0,0 @@ -use std::path::Path; - -use regex::Regex; - -use crate::rustc_stderr::Level; - -use color_eyre::eyre::{bail, ensure, eyre, Result}; - -#[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 speicified once - pub revisions: Option>, - /// Don't run this test if any of these filters apply - pub ignore: Vec, - /// Only run this test if all of these filters apply - pub only: Vec, - /// 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, - /// 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, String)>, - /// An arbitrary pattern to look for in the stderr. - pub error_pattern: Option<(Pattern, usize)>, - pub error_matches: Vec, - /// Ignore diagnostics below this level. - /// `None` means pick the lowest level from the `error_pattern`s. - pub require_annotations_for_level: Option, -} - -/// The conditions used for "ignore" and "only" filters. -#[derive(Debug)] -pub(crate) enum Condition { - /// The given string must appear in the target. - Target(String), - /// Tests that the bitwidth is the given one. - Bitwidth(u8), - /// Tests that the target is the host. - OnHost, -} - -#[derive(Debug, Clone)] -pub(crate) enum Pattern { - SubString(String), - Regex(Regex), -} - -#[derive(Debug)] -pub(crate) struct ErrorMatch { - pub pattern: Pattern, - pub revision: Option, - pub level: Level, - /// The line where the message was defined, for reporting issues with it (e.g. in case it wasn't found). - pub definition_line: usize, - /// The line this pattern is expecting to find a message in. - pub line: usize, -} - -impl Condition { - fn parse(c: &str) -> Result { - if c == "on-host" { - Ok(Condition::OnHost) - } else if let Some(bits) = c.strip_suffix("bit") { - let bits: u8 = bits.parse().map_err(|_err| { - eyre!("invalid ignore/only filter ending in 'bit': {c:?} is not a valid bitwdith") - })?; - Ok(Condition::Bitwidth(bits)) - } else if let Some(target) = c.strip_prefix("target-") { - Ok(Condition::Target(target.to_owned())) - } else { - Err(eyre!("invalid ignore/only condition {c:?}")) - } - } -} - -impl Comments { - pub(crate) fn parse_file(path: &Path) -> Result { - let content = std::fs::read_to_string(path)?; - Self::parse(path, &content) - } - - /// Parse comments in `content`. - /// `path` is only used to emit diagnostics if parsing fails. - pub(crate) fn parse(path: &Path, content: &str) -> Result { - let mut this = Self::default(); - - let mut fallthrough_to = None; // The line that a `|` will refer to. - for (l, line) in content.lines().enumerate() { - let l = l + 1; // enumerate starts at 0, but line numbers start at 1 - this.parse_checked_line(l, &mut fallthrough_to, line).map_err(|err| { - err.wrap_err(format!("{}:{l}: failed to parse annotation", path.display())) - })?; - } - Ok(this) - } - - fn parse_checked_line( - &mut self, - l: usize, - fallthrough_to: &mut Option, - line: &str, - ) -> Result<()> { - if let Some((_, command)) = line.split_once("//@") { - self.parse_command(command.trim(), l) - } else if let Some((_, pattern)) = line.split_once("//~") { - self.parse_pattern(pattern, fallthrough_to, l) - } else if let Some((_, pattern)) = line.split_once("//[") { - self.parse_revisioned_pattern(pattern, fallthrough_to, l) - } else { - *fallthrough_to = None; - Ok(()) - } - } - - fn parse_command(&mut self, command: &str, l: usize) -> Result<()> { - // Commands are letters or dashes, grab everything until the first character that is neither of those. - let (command, args) = - match command.chars().position(|c: char| !c.is_alphanumeric() && c != '-') { - None => (command, ""), - Some(i) => { - let (command, args) = command.split_at(i); - let mut args = args.chars(); - // Commands are separated from their arguments by ':' or ' ' - let next = args - .next() - .expect("the `position` above guarantees that there is at least one char"); - ensure!(next == ':', "test command must be followed by : (or end the line)"); - (command, args.as_str().trim()) - } - }; - - match command { - "revisions" => { - ensure!(self.revisions.is_none(), "cannot specifiy revisions twice"); - self.revisions = Some(args.split_whitespace().map(|s| s.to_string()).collect()); - } - "compile-flags" => { - self.compile_flags.extend(args.split_whitespace().map(|s| s.to_string())); - } - "rustc-env" => - for env in args.split_whitespace() { - let (k, v) = env.split_once('=').ok_or_else(|| { - eyre!("environment variables must be key/value pairs separated by a `=`") - })?; - self.env_vars.push((k.to_string(), v.to_string())); - }, - "normalize-stderr-test" => { - /// 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(s: &str) -> Result<(&str, &str)> { - let mut chars = s.char_indices(); - match chars.next().ok_or_else(|| eyre!("missing arguments"))?.1 { - '"' => { - let s = chars.as_str(); - let mut escaped = false; - for (i, c) in chars { - if escaped { - // Accept any character as literal after a `\`. - escaped = false; - } else if c == '"' { - return Ok((&s[..(i - 1)], s[i..].trim_start())); - } else { - escaped = c == '\\'; - } - } - bail!("no closing quotes found for {s}") - } - c => bail!("expected '\"', got {c}"), - } - } - - let (from, rest) = parse_str(args)?; - - let to = rest.strip_prefix("->").ok_or_else(|| { - eyre!("normalize-stderr-test needs a pattern and replacement separated by `->`") - })?.trim_start(); - let (to, rest) = parse_str(to)?; - - ensure!(rest.is_empty(), "trailing text after pattern replacement: {rest}"); - - let from = Regex::new(from)?; - self.normalize_stderr.push((from, to.to_string())); - } - "error-pattern" => { - ensure!( - self.error_pattern.is_none(), - "cannot specifiy error_pattern twice, previous: {:?}", - self.error_pattern - ); - self.error_pattern = Some((Pattern::parse(args.trim())?, l)); - } - "stderr-per-bitwidth" => { - // args are ignored (can be used as comment) - ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice"); - self.stderr_per_bitwidth = true; - } - "require-annotations-for-level" => { - ensure!( - self.require_annotations_for_level.is_none(), - "cannot specify `require-annotations-for-level` twice" - ); - self.require_annotations_for_level = Some(args.trim().parse()?); - } - command => { - if let Some(s) = command.strip_prefix("ignore-") { - // args are ignored (can be sue as comment) - self.ignore.push(Condition::parse(s)?); - return Ok(()); - } - - if let Some(s) = command.strip_prefix("only-") { - // args are ignored (can be sue as comment) - self.only.push(Condition::parse(s)?); - return Ok(()); - } - bail!("unknown command {command}"); - } - } - - Ok(()) - } - - fn parse_pattern( - &mut self, - pattern: &str, - fallthrough_to: &mut Option, - l: usize, - ) -> Result<()> { - self.parse_pattern_inner(pattern, fallthrough_to, None, l) - } - - fn parse_revisioned_pattern( - &mut self, - pattern: &str, - fallthrough_to: &mut Option, - l: usize, - ) -> Result<()> { - let (revision, pattern) = - pattern.split_once(']').ok_or_else(|| eyre!("`//[` without corresponding `]`"))?; - if let Some(pattern) = pattern.strip_prefix('~') { - self.parse_pattern_inner(pattern, fallthrough_to, Some(revision.to_owned()), l) - } else { - bail!("revisioned pattern must have `~` following the `]`"); - } - } - - // parse something like (?P\||[\^]+)? *(?PERROR|HELP|WARN|NOTE): (?P.*) - fn parse_pattern_inner( - &mut self, - pattern: &str, - fallthrough_to: &mut Option, - revision: Option, - l: usize, - ) -> Result<()> { - let (match_line, pattern) = - match pattern.chars().next().ok_or_else(|| eyre!("no pattern specified"))? { - '|' => - ( - *fallthrough_to - .as_mut() - .ok_or_else(|| eyre!("`//~|` pattern without preceding line"))?, - &pattern[1..], - ), - '^' => { - let offset = pattern.chars().take_while(|&c| c == '^').count(); - (l - offset, &pattern[offset..]) - } - _ => (l, pattern), - }; - - let pattern = pattern.trim_start(); - let offset = pattern - .chars() - .position(|c| !matches!(c, 'A'..='Z' | 'a'..='z')) - .ok_or_else(|| eyre!("pattern without level"))?; - - let level = pattern[..offset].parse()?; - let pattern = &pattern[offset..]; - let pattern = pattern.strip_prefix(':').ok_or_else(|| eyre!("no `:` after level found"))?; - - let pattern = pattern.trim(); - - ensure!(!pattern.is_empty(), "no pattern specified"); - - let pattern = Pattern::parse(pattern)?; - - *fallthrough_to = Some(match_line); - - self.error_matches.push(ErrorMatch { - pattern, - revision, - level, - definition_line: l, - line: match_line, - }); - - Ok(()) - } -} - -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), - } - } - - pub(crate) fn parse(pattern: &str) -> Result { - if let Some(pattern) = pattern.strip_prefix('/') { - let regex = - pattern.strip_suffix('/').ok_or_else(|| eyre!("regex must end with `/`"))?; - Ok(Pattern::Regex(Regex::new(regex)?)) - } else { - Ok(Pattern::SubString(pattern.to_string())) - } - } -} diff --git a/ui_test/src/parser/tests.rs b/ui_test/src/parser/tests.rs deleted file mode 100644 index 343857d44bd..00000000000 --- a/ui_test/src/parser/tests.rs +++ /dev/null @@ -1,85 +0,0 @@ -use std::path::Path; - -use crate::parser::Pattern; - -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(Path::new(""), s).unwrap(); - println!("parsed comments: {:#?}", comments); - assert_eq!(comments.error_matches[0].definition_line, 5); - assert_eq!(comments.error_matches[0].revision, None); - match &comments.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) -} - "; - assert!(Comments::parse(Path::new(""), s).is_err(), "expected parsing to fail"); -} - -#[test] -fn parse_slash_slash_at() { - let s = r" -//@ error-pattern: foomp -use std::mem; - - "; - let comments = Comments::parse(Path::new(""), s).unwrap(); - println!("parsed comments: {:#?}", comments); - let pat = comments.error_pattern.unwrap(); - assert_eq!(format!("{:?}", pat.0), r#"SubString("foomp")"#); - assert_eq!(pat.1, 2); -} - -#[test] -fn parse_regex_error_pattern() { - let s = r" -//@ error-pattern: /foomp/ -use std::mem; - - "; - let comments = Comments::parse(Path::new(""), s).unwrap(); - println!("parsed comments: {:#?}", comments); - let pat = comments.error_pattern.unwrap(); - assert_eq!(format!("{:?}", pat.0), r#"Regex(foomp)"#); - assert_eq!(pat.1, 2); -} - -#[test] -fn parse_slash_slash_at_fail() { - let s = r" -//@ error-patttern foomp -use std::mem; - - "; - assert!(Comments::parse(Path::new(""), s).is_err(), "expected parsing to fail"); -} - -#[test] -fn missing_colon_fail() { - let s = r" -//@stderr-per-bitwidth hello -use std::mem; - - "; - assert!(Comments::parse(Path::new(""), s).is_err(), "expected parsing to fail"); -} diff --git a/ui_test/src/rustc_stderr.rs b/ui_test/src/rustc_stderr.rs deleted file mode 100644 index 8e031947581..00000000000 --- a/ui_test/src/rustc_stderr.rs +++ /dev/null @@ -1,155 +0,0 @@ -use std::{ - fmt::Write, - path::{Path, PathBuf}, -}; - -use color_eyre::eyre::{eyre, Error}; -use regex::Regex; - -#[derive(serde::Deserialize, Debug)] -struct RustcMessage { - rendered: Option, - spans: Vec, - level: String, - message: String, - children: Vec, -} - -#[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)] -pub(crate) struct Message { - pub(crate) level: Level, - pub(crate) message: String, -} - -/// Information about macro expansion. -#[derive(serde::Deserialize, Debug)] -struct Expansion { - span: Span, -} - -#[derive(serde::Deserialize, Debug)] -struct Span { - line_start: usize, - file_name: PathBuf, - expansion: Option>, -} - -impl std::str::FromStr for Level { - type Err = Error; - fn from_str(s: &str) -> Result { - 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(eyre!("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: String, - /// Per line, a list of messages for that line. - pub messages: Vec>, - /// Messages not on any line (usually because they are from libstd) - pub messages_from_unknown_file_or_line: Vec, -} - -impl RustcMessage { - fn line(&self, file: &Path) -> Option { - self.spans.iter().find_map(|span| span.line(file)) - } - - /// Put the message and its children into the line-indexed list. - fn insert_recursive( - self, - file: &Path, - messages: &mut Vec>, - messages_from_unknown_file_or_line: &mut Vec, - line: Option, - ) { - let line = self.line(file).or(line); - let msg = Message { level: self.level.parse().unwrap(), message: self.message }; - if let Some(line) = line { - if messages.len() <= line { - messages.resize_with(line + 1, Vec::new); - } - messages[line].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 Span { - /// Returns a line number *in the given file*, if possible. - fn line(&self, file: &Path) -> Option { - if self.file_name == file { - Some(self.line_start) - } else { - self.expansion.as_ref()?.span.line(file) - } - } -} - -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 stderr = std::str::from_utf8(stderr).unwrap(); - let mut rendered = String::new(); - let mut messages = vec![]; - let mut messages_from_unknown_file_or_line = vec![]; - for line in stderr.lines() { - if line.starts_with('{') { - match serde_json::from_str::(line) { - Ok(msg) => { - write!( - rendered, - "{}", - filter_annotations_from_rendered(msg.rendered.as_ref().unwrap()) - ) - .unwrap(); - 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: {}\nerr:{}", line, err), - } - } else { - // FIXME: do we want to throw interpreter stderr into a separate file? - writeln!(rendered, "{}", line).unwrap(); - } - } - Diagnostics { rendered, messages, messages_from_unknown_file_or_line } -} diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs deleted file mode 100644 index 2032988ed38..00000000000 --- a/ui_test/src/tests.rs +++ /dev/null @@ -1,294 +0,0 @@ -use std::path::{Path, PathBuf}; - -use crate::rustc_stderr::Level; -use crate::rustc_stderr::Message; - -use super::*; - -fn config() -> Config { - Config { - args: vec![], - target: None, - stderr_filters: vec![], - stdout_filters: vec![], - root_dir: PathBuf::from("$RUSTROOT"), - mode: Mode::Fail, - path_filter: vec![], - program: PathBuf::from("cake"), - output_conflict_handling: OutputConflictHandling::Error, - dependencies_crate_manifest_path: None, - dependency_builder: None, - quiet: false, - } -} - -#[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 path = Path::new("$DIR/"); - let comments = Comments::parse(path, 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, - } - ] - ]; - check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); - match &errors[..] { - [ - Error::PatternNotFound { definition_line: 5, .. }, - Error::ErrorsWithoutPattern { path: Some((_, 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(Path::new(""), 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, - } - ] - ]; - let mut errors = vec![]; - check_annotations( - messages, - vec![], - Path::new("moobar"), - &mut errors, - &config, - "", - &comments, - ); - 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, - } - ] - ]; - let mut errors = vec![]; - check_annotations( - messages, - vec![], - Path::new("moobar"), - &mut errors, - &config, - "", - &comments, - ); - match &errors[..] { - [ - Error::PatternNotFound { definition_line: 5, .. }, - Error::ErrorsWithoutPattern { path: Some((_, 4)), .. }, - ] => {} - _ => 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, - } - ] - ]; - let mut errors = vec![]; - check_annotations( - messages, - vec![], - Path::new("moobar"), - &mut errors, - &config, - "", - &comments, - ); - match &errors[..] { - // Note no `ErrorsWithoutPattern`, because there are no `//~NOTE` in the test file, so we ignore them - [Error::PatternNotFound { definition_line: 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(Path::new(""), 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, - } - ] - ]; - let mut errors = vec![]; - check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); - match &errors[..] { - [Error::PatternNotFound { definition_line: 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(Path::new(""), 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, - }, - Message { - message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), - level: Level::Error, - } - ] - ]; - let mut errors = vec![]; - check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); - match &errors[..] { - [Error::ErrorsWithoutPattern { path: Some((_, 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(Path::new(""), 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, - }, - Message { - message: "kaboom".to_string(), - level: Level::Warn, - }, - Message { - message: "cake".to_string(), - level: Level::Warn, - }, - ], - ]; - let mut errors = vec![]; - check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); - match &errors[..] { - [Error::ErrorsWithoutPattern { path: Some((_, 5)), msgs, .. }] => - match &msgs[..] { - [Message { message, level: Level::Warn }] 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(Path::new(""), 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, - }, - Message { - message: "kaboom".to_string(), - level: Level::Warn, - }, - Message { - message: "cake".to_string(), - level: Level::Warn, - }, - ], - ]; - let mut errors = vec![]; - check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); - match &errors[..] { - [] => {} - _ => panic!("{:#?}", errors), - } -}