diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3ec1bf7f..6b806283 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -59,7 +59,6 @@ jobs: run: | cargo --version rustc --version - # TODO: Maybe also check clippy and rustfmt here. - name: Build run: cargo build --all-targets - uses: taiki-e/install-action@v2 @@ -71,8 +70,7 @@ jobs: - name: Check rustfmt run: cargo fmt --all --check - name: Check clippy - # TODO: -- -D warnings - run: cargo clippy --all-targets --all-features + run: cargo clippy --all-targets --all-features -- -D warnings - name: Check typos uses: crate-ci/typos@master - name: Build release binary @@ -89,7 +87,7 @@ jobs: strategy: matrix: os: [macOS-latest, ubuntu-latest, windows-latest] - version: [stable, nightly, "1.74"] + version: [stable, nightly, "1.78"] runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 @@ -115,8 +113,10 @@ jobs: - name: Check rustfmt run: cargo fmt --all --check - name: Check clippy - # TODO: Deny warnings - run: cargo clippy --all-targets --all-features + if: matrix.version == 'stable' + # Clippy checks can vary between versions in a way that makes it a bit + # fiddly to satisfy them all, so only insist that they pass on stable. + run: cargo clippy --all-targets --all-features -- -D warnings - run: cargo update - name: Test after cargo update run: cargo test --workspace diff --git a/Cargo.lock b/Cargo.lock index 623e5f90..a8f55dae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "aho-corasick" -version = "0.7.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" -dependencies = [ - "memchr", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -35,39 +26,16 @@ dependencies = [ "libc", ] -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "anstream" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c" -dependencies = [ - "anstyle 1.0.7", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon 2.1.0", - "colorchoice", - "utf8parse", -] - [[package]] name = "anstream" -version = "0.6.15" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +checksum = "8acc5369981196006228e28809f761875c0327210a891e941f4c683b3a99529b" dependencies = [ - "anstyle 1.0.7", + "anstyle", "anstyle-parse", "anstyle-query", - "anstyle-wincon 3.0.4", + "anstyle-wincon", "colorchoice", "is_terminal_polyfill", "utf8parse", @@ -75,69 +43,55 @@ dependencies = [ [[package]] name = "anstyle" -version = "0.3.5" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2" - -[[package]] -name = "anstyle" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" +checksum = "55cc3b69f167a1ef2e161439aa98aed94e6028e5f9a59be9a6ffb47aef1651f9" [[package]] name = "anstyle-parse" -version = "0.2.4" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +checksum = "3b2d16507662817a6a20a9ea92df6652ee4f94f914589377d69f3b21bc5798a9" dependencies = [ "utf8parse", ] [[package]] name = "anstyle-query" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad186efb764318d35165f1758e7dcef3b10628e26d41a44bc5550652e6804391" -dependencies = [ - "windows-sys 0.52.0", -] - -[[package]] -name = "anstyle-wincon" -version = "2.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd" +checksum = "79947af37f4177cfead1110013d678905c37501914fba0efea834c3fe9a8d60c" dependencies = [ - "anstyle 1.0.7", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] name = "anstyle-wincon" -version = "3.0.4" +version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" dependencies = [ - "anstyle 1.0.7", - "windows-sys 0.52.0", + "anstyle", + "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.86" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" +checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" [[package]] name = "assert_cmd" -version = "2.0.0" +version = "2.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54f002ce7d0c5e809ebb02be78fd503aeed4a511fd0fcaff6e6914cbdabbfa33" +checksum = "dc1835b7f27878de8525dc71410b5a31cdcc5f230aed5ba5df968e09c201b23d" dependencies = [ - "bstr 0.2.17", + "anstyle", + "bstr", "doc-comment", - "predicates 2.1.5", + "libc", + "predicates", "predicates-core", "predicates-tree", "wait-timeout", @@ -156,9 +110,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "bitflags" @@ -168,28 +122,18 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" - -[[package]] -name = "bstr" -version = "0.2.17" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "lazy_static", - "memchr", - "regex-automata 0.1.10", -] +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" [[package]] name = "bstr" -version = "1.9.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05efc5cfd9110c8416e471df0e96702d58690178e206e61b7173706673c93706" +checksum = "1a68f1f47cdf0ec8ee4b941b2eee2a80cb796db73118c0dd09ac63fbe405be22" dependencies = [ "memchr", + "regex-automata 0.4.9", "serde", ] @@ -207,9 +151,9 @@ checksum = "5ce89b21cab1437276d2650d57e971f9d548a2d9037cc231abdc0562b97498ce" [[package]] name = "camino" -version = "1.1.6" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59e92b5a388f549b863a7bea62612c09f24c8393560709a54558a9abdfb3b9c" +checksum = "8b96ec4966b5813e2c0507c1f86115c8c5abaadc3980879c3424042a02fd1ad3" dependencies = [ "serde", ] @@ -235,16 +179,16 @@ dependencies = [ "ignore", "indoc", "insta", - "itertools 0.12.0", + "itertools", "jobserver", "lazy_static", "mutants 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "nix 0.28.0", + "nix", "num_cpus", "nutmeg", "patch", "path-slash", - "predicates 3.0.0", + "predicates", "pretty_assertions", "proc-macro2", "quote", @@ -254,7 +198,7 @@ dependencies = [ "serde_json", "similar", "strum", - "syn 2.0.46", + "syn", "tempfile", "test-log", "time", @@ -268,32 +212,35 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ "serde", ] [[package]] name = "cargo_metadata" -version = "0.18.0" +version = "0.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb9ac64500cc83ce4b9f8dafa78186aa008c8dea77a09b94cd307fd0cd5022a8" +checksum = "8769706aad5d996120af43197bf46ef6ad0fda35216b4505f926a365a232d924" dependencies = [ "camino", "cargo-platform", "semver", "serde", "serde_json", - "thiserror", + "thiserror 2.0.4", ] [[package]] name = "cc" -version = "1.0.99" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695" +checksum = "27f657647bcff5394bf56c7317665bbf790a137a50eaaa5c6bfbb9e27a518f2d" +dependencies = [ + "shlex", +] [[package]] name = "cfg-if" @@ -303,9 +250,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" @@ -318,107 +265,104 @@ dependencies = [ "js-sys", "num-traits", "wasm-bindgen", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] name = "clap" -version = "4.4.1" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c8d502cbaec4595d2e7d5f61e318f05417bd2b66fdc3809498f0d3fdf0bea27" +checksum = "3135e7ec2ef7b10c6ed8950f0f792ed96ee093fa088608f1c76e569722700c84" dependencies = [ "clap_builder", "clap_derive", - "once_cell", ] [[package]] name = "clap_builder" -version = "4.4.1" +version = "4.5.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5891c7bc0edb3e1c2204fc5e94009affabeb1821c9e5fdc3959536c5c0bb984d" +checksum = "30582fc632330df2bd26877bde0c1f4470d57c582bbc070376afcd04d8cb4838" dependencies = [ - "anstream 0.5.0", - "anstyle 1.0.7", + "anstream", + "anstyle", "clap_lex", "strsim", - "terminal_size 0.2.6", + "terminal_size 0.4.1", ] [[package]] name = "clap_complete" -version = "4.0.0" +version = "4.5.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32b2326335cf37df6f430050fc5de9370726bb76e5a35df80f2d0855e745bee8" +checksum = "d9647a559c112175f17cf724dc72d3645680a883c58481332779192b0d8e7a01" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.4.0" +version = "4.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9fd1a5729c4548118d7d70ff234a44868d00489a4b6597b0b020918a0e91a1a" +checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" dependencies = [ - "heck 0.4.1", + "heck", "proc-macro2", "quote", - "syn 2.0.46", + "syn", ] [[package]] name = "clap_lex" -version = "0.5.1" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "color-print" -version = "0.3.1" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43997eb83c8c067d48bbe9de556f9bc2b7e287ed97af05ab76673be451c71c21" +checksum = "3aa954171903797d5623e047d9ab69d91b493657917bdfb8c2c80ecaf9cdb6f4" dependencies = [ "color-print-proc-macro", ] [[package]] name = "color-print-proc-macro" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77ff1a80c5f3cb1ca7c06ffdd71b6a6dd6d8f896c42141fbd43f50ed28dcdb93" +checksum = "692186b5ebe54007e45a59aea47ece9eb4108e141326c304cdc91699a7118a22" dependencies = [ "nom", "proc-macro2", "quote", - "syn 2.0.46", + "syn", ] [[package]] name = "colorchoice" -version = "1.0.1" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" +checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "console" -version = "0.15.0" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28b32d32ca44b70c3e4acd7db1babf555fa026e385fb95f18028f88848b3c31" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ "encode_unicode", + "lazy_static", "libc", - "once_cell", - "regex", - "terminal_size 0.1.17", "unicode-width", - "winapi", + "windows-sys 0.52.0", ] [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cp_r" @@ -439,29 +383,38 @@ dependencies = [ ] [[package]] -name = "crossbeam-utils" -version = "0.8.20" +name = "crossbeam-deque" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] [[package]] -name = "ctor" -version = "0.1.26" +name = "crossbeam-epoch" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "quote", - "syn 1.0.109", + "crossbeam-utils", ] +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + [[package]] name = "ctrlc" -version = "3.2.1" +version = "3.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a19c6cedffdc8c03a3346d723eb20bd85a13362bb96dc2ac000842c6381ec7bf" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" dependencies = [ - "nix 0.23.2", - "winapi", + "nix", + "windows-sys 0.59.0", ] [[package]] @@ -493,9 +446,9 @@ checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" [[package]] name = "either" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" [[package]] name = "encode_unicode" @@ -518,8 +471,8 @@ version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e13fa619b91fb2381732789fc5de83b45675e882f66623b7d8cb4f643017018d" dependencies = [ - "anstream 0.6.15", - "anstyle 1.0.7", + "anstream", + "anstyle", "env_filter", "log", ] @@ -532,30 +485,30 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "fastrand" -version = "2.0.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "filetime" -version = "0.2.23" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +checksum = "35c0522e981e68cbfa8c3f978441a5f34b30b96e146b33cd3359176b50fe8586" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", - "windows-sys 0.52.0", + "libredox", + "windows-sys 0.59.0", ] [[package]] @@ -585,34 +538,22 @@ dependencies = [ [[package]] name = "globset" -version = "0.4.10" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" +checksum = "15f1ce686646e7f1e19bf7d5533fe443a45dbfb990e00629110797578b42fb19" dependencies = [ - "aho-corasick 0.7.20", - "bstr 1.9.1", - "fnv", + "aho-corasick", + "bstr", "log", - "regex", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hashbrown" -version = "0.14.5" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" [[package]] name = "heck" @@ -643,9 +584,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -666,58 +607,45 @@ dependencies = [ [[package]] name = "ignore" -version = "0.4.20" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" +checksum = "6d89fd380afde86567dfba715db065673989d6253f42b88179abd3eae47bda4b" dependencies = [ + "crossbeam-deque", "globset", - "lazy_static", "log", "memchr", - "regex", + "regex-automata 0.4.9", "same-file", - "thread_local", "walkdir", "winapi-util", ] [[package]] name = "indexmap" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" -dependencies = [ - "autocfg", - "hashbrown 0.12.3", -] - -[[package]] -name = "indexmap" -version = "2.2.6" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown", ] [[package]] name = "indoc" -version = "2.0.0" +version = "2.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fe2b9d82064e8a0226fddb3547f37f28eaa46d0fc210e275d835f08cf3b76a7" +checksum = "b248f5224d1d606005e02c97f5aa4e88eeb230488bcc03bc9ca4d7991399f2b5" [[package]] name = "insta" -version = "1.12.0" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c0c443f6dceb3a1cb7607c87501aa91e4b9c976044f725c2a74ca2152c91a4" +checksum = "7e9ffc4d4892617c50a928c52b2961cb5174b6fc6ebf252b2fac9d21955c48b8" dependencies = [ "console", - "once_cell", - "serde", - "serde_json", - "serde_yaml", + "lazy_static", + "linked-hash-map", "similar", ] @@ -740,57 +668,60 @@ checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" [[package]] name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itertools" -version = "0.12.0" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25db6b064527c5d482d0423354fcd07a89a2dfe07b67892e62411946db7f07b0" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jobserver" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +checksum = "48d1dbcbbeb6a7fec7e059840aa538bd62aaccf972c7346c4d9d2059312853d0" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.69" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" +checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7" dependencies = [ + "once_cell", "wasm-bindgen", ] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.155" +version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" + +[[package]] +name = "libredox" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" +dependencies = [ + "bitflags 2.6.0", + "libc", + "redox_syscall", +] [[package]] name = "linked-hash-map" @@ -822,9 +753,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "matchers" @@ -837,18 +768,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" - -[[package]] -name = "memoffset" -version = "0.6.5" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "minimal-lexical" @@ -868,24 +790,11 @@ checksum = "bc0287524726960e07b119cebd01678f852f147742ae0d925e6a520dca956126" [[package]] name = "nix" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c" -dependencies = [ - "bitflags 1.3.2", - "cc", - "cfg-if", - "libc", - "memoffset", -] - -[[package]] -name = "nix" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "cfg-if", "cfg_aliases", "libc", @@ -962,23 +871,14 @@ dependencies = [ "atty", "parking_lot", "terminal_size 0.2.6", - "yansi", + "yansi 0.5.1", ] [[package]] name = "once_cell" -version = "1.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" - -[[package]] -name = "output_vt100" -version = "0.1.3" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" -dependencies = [ - "winapi", -] +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "overload" @@ -1004,9 +904,9 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.1", + "redox_syscall", "smallvec", - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -1022,15 +922,15 @@ dependencies = [ [[package]] name = "path-slash" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54014ba3c1880122928735226f78b6f5bf5bd1fed15e41e92cf7aa20278ce28" +checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" [[package]] name = "pin-project-lite" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" +checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" [[package]] name = "powerfmt" @@ -1040,25 +940,13 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "predicates" -version = "2.1.5" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" +checksum = "7e9086cc7640c29a356d1a29fd134380bee9d8f79a17410aa76e7ad295f42c97" dependencies = [ - "difflib", - "itertools 0.10.5", - "predicates-core", -] - -[[package]] -name = "predicates" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7d6ab0758c8486d593e1614f3af1d0f07d93d3ff15e47f78819d1ac2d6d094c" -dependencies = [ - "anstyle 0.3.5", + "anstyle", "difflib", "float-cmp", - "itertools 0.10.5", "normalize-line-endings", "predicates-core", "regex", @@ -1066,15 +954,15 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" +checksum = "ae8177bee8e75d6846599c6b9ff679ed51e882816914eec639944d7c9aa11931" [[package]] name = "predicates-tree" -version = "1.0.9" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +checksum = "41b740d195ed3166cd147c8047ec98db0e22ec019eb8eeb76d343b795304fb13" dependencies = [ "predicates-core", "termtree", @@ -1082,21 +970,19 @@ dependencies = [ [[package]] name = "pretty_assertions" -version = "1.0.0" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0cfe1b2403f172ba0f234e500906ee0a3e493fb81092dac23ebefe129301cc" +checksum = "3ae130e2f271fbc2ac3a40fb1d07180839cdbbe443c7a27e1e3c13c5cac0116d" dependencies = [ - "ansi_term", - "ctor", "diff", - "output_vt100", + "yansi 1.0.1", ] [[package]] name = "proc-macro2" -version = "1.0.74" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2de98502f212cfcea8d0bb305bd0f49d7ebdd75b64ba0a68f937d888f4e0d6db" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -1109,41 +995,32 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.35" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ - "bitflags 1.3.2", -] - -[[package]] -name = "redox_syscall" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" -dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", ] [[package]] name = "regex" -version = "1.10.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d119d7c7ca818f8a53c300863d4f87566aac09943aef5b355bb83969dae75d87" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ - "aho-corasick 1.1.3", + "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.9", + "regex-syntax 0.8.5", ] [[package]] @@ -1157,13 +1034,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ - "aho-corasick 1.1.3", + "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -1174,9 +1051,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "rustix" @@ -1194,11 +1071,11 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.34" +version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ - "bitflags 2.5.0", + "bitflags 2.6.0", "errno", "libc", "linux-raw-sys 0.4.14", @@ -1207,9 +1084,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "rusty-fork" @@ -1255,54 +1132,43 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.194" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.194" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.46", + "syn", ] [[package]] name = "serde_json" -version = "1.0.117" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "itoa", + "memchr", "ryu", "serde", ] [[package]] name = "serde_spanned" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" -dependencies = [ - "serde", -] - -[[package]] -name = "serde_yaml" -version = "0.8.26" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" +checksum = "87607cb1398ed59d48732e575a4c28a7a8ebf2454b964fe3f224f2afc07909e1" dependencies = [ - "indexmap 1.9.3", - "ryu", "serde", - "yaml-rust", ] [[package]] @@ -1314,11 +1180,17 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + [[package]] name = "similar" -version = "2.1.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e24979f63a11545f5f2c60141afe249d4f19f84581ea2138065e400941d83d3" +checksum = "1de1d4f81173b03af4c0cbed3c898f6bff5b870e4a7f5d6f4057d62a7a4b686e" [[package]] name = "smallvec" @@ -1328,15 +1200,15 @@ checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" -version = "0.26.0" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "117c413ac8a6cc19c773939932477a341e416eff7f0e84db42f091d85d7c6e0e" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ "strum_macros", ] @@ -1347,29 +1219,18 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "rustversion", - "syn 2.0.46", -] - -[[package]] -name = "syn" -version = "1.0.109" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", + "syn", ] [[package]] name = "syn" -version = "2.0.46" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89456b690ff72fddcecf231caedbe615c59480c93358a93dfae7fc29e3ebbf0e" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -1378,35 +1239,35 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.9.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.4.1", - "rustix 0.38.34", - "windows-sys 0.52.0", + "once_cell", + "rustix 0.38.41", + "windows-sys 0.59.0", ] [[package]] name = "terminal_size" -version = "0.1.17" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" +checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" dependencies = [ - "libc", - "winapi", + "rustix 0.37.27", + "windows-sys 0.48.0", ] [[package]] name = "terminal_size" -version = "0.2.6" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" +checksum = "5352447f921fda68cf61b4101566c0bdb5104eff6804d0678e5227580ab6a4e9" dependencies = [ - "rustix 0.37.27", - "windows-sys 0.48.0", + "rustix 0.38.41", + "windows-sys 0.59.0", ] [[package]] @@ -1434,27 +1295,47 @@ checksum = "5999e24eaa32083191ba4e425deb75cdf25efefabe5aaccb7446dd0d4122a3f5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.46", + "syn", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", ] [[package]] name = "thiserror" -version = "1.0.61" +version = "2.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" +checksum = "2f49a1853cf82743e3b7950f77e0f4d622ca36cf4317cba00c767838bac8d490" dependencies = [ - "thiserror-impl", + "thiserror-impl 2.0.4", ] [[package]] name = "thiserror-impl" -version = "1.0.61" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.46", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8381894bb3efe0c4acac3ded651301ceee58a15d47c2e34885ed1908ad667061" +dependencies = [ + "proc-macro2", + "quote", + "syn", ] [[package]] @@ -1469,9 +1350,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.36" +version = "0.3.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" +checksum = "35e7868883861bd0e56d9ac6efcaaca0d6d5d82a2a7ec8209ff492c07cf37b21" dependencies = [ "deranged", "itoa", @@ -1490,9 +1371,9 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" +checksum = "2834e6017e3e5e4b9834939793b282bc03b37a3336245fa820e35e233e2a85de" dependencies = [ "num-conv", "time-core", @@ -1500,9 +1381,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.0" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c226a7bba6d859b63c92c4b4fe69c5b6b72d0cb897dbc8e6012298e6154cb56e" +checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" dependencies = [ "serde", "serde_spanned", @@ -1512,20 +1393,20 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" +checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" dependencies = [ "serde", ] [[package]] name = "toml_edit" -version = "0.20.7" +version = "0.22.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" +checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" dependencies = [ - "indexmap 2.2.6", + "indexmap", "serde", "serde_spanned", "toml_datetime", @@ -1534,9 +1415,9 @@ dependencies = [ [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "pin-project-lite", "tracing-attributes", @@ -1545,31 +1426,32 @@ dependencies = [ [[package]] name = "tracing-appender" -version = "0.2.0" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94571df2eae3ed4353815ea5a90974a594a1792d8782ff2cbcc9392d1101f366" +checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" dependencies = [ "crossbeam-channel", + "thiserror 1.0.69", "time", "tracing-subscriber", ] [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.46", + "syn", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -1588,9 +1470,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", "nu-ansi-term", @@ -1606,15 +1488,15 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "utf8parse" @@ -1655,34 +1537,34 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.92" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" +checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396" dependencies = [ "cfg-if", + "once_cell", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.92" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" +checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.46", + "syn", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.92" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" +checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1690,28 +1572,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.92" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" +checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.46", + "syn", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.92" +version = "0.2.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" +checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6" [[package]] name = "web-sys" -version = "0.3.69" +version = "0.3.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" +checksum = "04dd7223427d52553d3702c004d3b2fe07c148165faa56313cb00211e31c12bc" dependencies = [ "js-sys", "wasm-bindgen", @@ -1719,11 +1601,11 @@ dependencies = [ [[package]] name = "whoami" -version = "1.5.0" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fec781d48b41f8163426ed18e8fc2864c12937df9ce54c88ede7bd47270893e" +checksum = "372d5b87f58ec45c384ba03563b03544dc5fadc3983e434b286913f5b4a9bb6d" dependencies = [ - "redox_syscall 0.4.1", + "redox_syscall", "wasite", "web-sys", ] @@ -1746,11 +1628,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" +checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1765,7 +1647,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", ] [[package]] @@ -1783,7 +1665,16 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.5", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", ] [[package]] @@ -1803,18 +1694,18 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.5", - "windows_aarch64_msvc 0.52.5", - "windows_i686_gnu 0.52.5", + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.5", - "windows_x86_64_gnu 0.52.5", - "windows_x86_64_gnullvm 0.52.5", - "windows_x86_64_msvc 0.52.5", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", ] [[package]] @@ -1825,9 +1716,9 @@ checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" @@ -1837,9 +1728,9 @@ checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" @@ -1849,15 +1740,15 @@ checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" @@ -1867,9 +1758,9 @@ checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" @@ -1879,9 +1770,9 @@ checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" @@ -1891,9 +1782,9 @@ checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" @@ -1903,30 +1794,27 @@ checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.52.5" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.5.40" +version = "0.6.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" dependencies = [ "memchr", ] [[package]] -name = "yaml-rust" -version = "0.4.5" +name = "yansi" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" -dependencies = [ - "linked-hash-map", -] +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" [[package]] name = "yansi" -version = "0.5.1" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" +checksum = "cfe53a6657fd280eaa890a3bc59152892ffa3e30101319d168b781ed6529b049" diff --git a/Cargo.toml b/Cargo.toml index 22587b6d..db560582 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ repository = "https://github.com/sourcefrog/cargo-mutants" homepage = "https://mutants.rs/" categories = ["development-tools::testing"] keywords = ["testing", "mutants", "cargo", "mutation-testing", "coverage"] -rust-version = "1.74" +rust-version = "1.78" [package.metadata.wix] upgrade-guid = "CA7BFE8D-F3A7-4D1D-AE43-B7749110FA90" @@ -22,7 +22,7 @@ eula = false [dependencies] anyhow = "1.0.86" camino = "1.1.6" -cargo_metadata = "0.18" +cargo_metadata = "0.19" clap = { version = "4.4.1", features = [ "deprecated", "derive", @@ -39,7 +39,7 @@ globset = "0.4.10" humantime = "2.1.0" ignore = "0.4.20" indoc = "2.0.0" -itertools = "0.12" +itertools = "0.13" jobserver = "0.1" mutants = "0.0.3" num_cpus = "1.16" @@ -47,7 +47,7 @@ patch = "0.7" path-slash = "0.2" quote = "1.0.35" regex = "1.10" -serde_json = "1.0.117" +serde_json = "1.0.118" similar = "2.1" strum = { version = "0.26", features = ["derive"] } tempfile = "3.8" @@ -76,7 +76,7 @@ version = "2.0.46" features = ["full", "extra-traits", "visit"] [target.'cfg(unix)'.dependencies] -nix = { version = "0.28", features = ["process", "signal"] } +nix = { version = "0.29", features = ["process", "signal"] } [dev-dependencies] assert_cmd = "2.0" diff --git a/book/book.toml b/book/book.toml index 228e3ed9..a9be9f36 100644 --- a/book/book.toml +++ b/book/book.toml @@ -6,6 +6,8 @@ src = "src" title = "cargo-mutants" [output.html] +git-repository-url = "https://github.com/sourcefrog/cargo-mutants" +edit-url-template = "https://github.com/sourcefrog/cargo-mutants/edit/main/book/{path}" [output.linkcheck] follow-web-links = true diff --git a/book/src/mutants-out.md b/book/src/mutants-out.md index 20182c09..e7cfff62 100644 --- a/book/src/mutants-out.md +++ b/book/src/mutants-out.md @@ -1,6 +1,7 @@ # The `mutants.out` directory -A `mutants.out` directory is created in the original source directory. You can put the output directory elsewhere with the `--output` option. +A `mutants.out` directory is created in the original source directory. You can put the output directory elsewhere with the `--output` option +or using `CARGO_MUTANTS_OUTPUT` environment variable or via `output` directive in the config file. On each run, any existing `mutants.out` is renamed to `mutants.out.old`, and any existing `mutants.out.old` is deleted. diff --git a/src/cargo.rs b/src/cargo.rs index 1cf59e67..79653999 100644 --- a/src/cargo.rs +++ b/src/cargo.rs @@ -2,6 +2,9 @@ //! Run Cargo as a subprocess, including timeouts and propagating signals. +#![warn(clippy::pedantic)] +#![allow(clippy::module_name_repetitions)] + use std::env; use std::iter::once; use std::time::{Duration, Instant}; @@ -23,7 +26,7 @@ use crate::Result; #[allow(clippy::too_many_arguments)] // I agree it's a lot but I'm not sure wrapping in a struct would be better. pub fn run_cargo( build_dir: &BuildDir, - jobserver: &Option, + jobserver: Option<&jobserver::Client>, packages: &PackageSelection, phase: Phase, timeout: Option, @@ -155,12 +158,7 @@ fn cargo_argv(packages: &PackageSelection, phase: Phase, options: &Options) -> V cargo_args.push("--all-features".to_owned()); } // N.B. it can make sense to have --all-features and also explicit features from non-default packages.` - cargo_args.extend( - features - .features - .iter() - .map(|f| format!("--features={}", f)), - ); + cargo_args.extend(features.features.iter().map(|f| format!("--features={f}"))); cargo_args.extend(options.additional_cargo_args.iter().cloned()); if phase == Phase::Test { cargo_args.extend(options.additional_cargo_test_args.iter().cloned()); @@ -168,7 +166,7 @@ fn cargo_argv(packages: &PackageSelection, phase: Phase, options: &Options) -> V cargo_args } -/// Return adjusted CARGO_ENCODED_RUSTFLAGS, including any changes to cap-lints. +/// Return adjusted `CARGO_ENCODED_RUSTFLAGS`, including any changes to cap-lints. /// /// It seems we have to set this in the environment because Cargo doesn't expose /// a way to pass it in as an option from all commands? @@ -240,7 +238,7 @@ mod test { // let relative_manifest_path = Utf8PathBuf::from("testdata/something/Cargo.toml"); options .additional_cargo_test_args - .extend(["--lib", "--no-fail-fast"].iter().map(|s| s.to_string())); + .extend(["--lib", "--no-fail-fast"].iter().map(ToString::to_string)); // TODO: It wolud be a bit better to use `--manifest-path` here, to get // the fix for // but it's temporarily regressed. @@ -292,7 +290,7 @@ mod test { let mut options = Options::default(); options .additional_cargo_test_args - .extend(["--lib", "--no-fail-fast"].iter().map(|s| s.to_string())); + .extend(["--lib", "--no-fail-fast"].iter().map(|&s| s.to_string())); options .additional_cargo_args .extend(["--release".to_owned()]); diff --git a/src/config.rs b/src/config.rs index c50ded02..e56b4919 100644 --- a/src/config.rs +++ b/src/config.rs @@ -14,7 +14,7 @@ use std::path::Path; use std::str::FromStr; use anyhow::Context; -use camino::Utf8Path; +use camino::{Utf8Path, Utf8PathBuf}; use serde::Deserialize; use crate::options::TestTool; @@ -47,6 +47,8 @@ pub struct Config { pub additional_cargo_test_args: Vec, /// Minimum test timeout, in seconds, as a floor on the autoset value. pub minimum_test_timeout: Option, + /// Output directory. + pub output: Option, /// Cargo profile. pub profile: Option, /// Skip calls to functions or methods with these names. diff --git a/src/console.rs b/src/console.rs index 57102df1..07062426 100644 --- a/src/console.rs +++ b/src/console.rs @@ -8,7 +8,6 @@ use std::io; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; -use anyhow::Context; use camino::{Utf8Path, Utf8PathBuf}; use console::{style, StyledObject}; use humantime::format_duration; @@ -21,7 +20,7 @@ use crate::options::Colors; use crate::outcome::{LabOutcome, ScenarioOutcome, SummaryOutcome}; use crate::scenario::Scenario; use crate::tail_file::TailFile; -use crate::{Mutant, Options, Phase, Result}; +use crate::{Mutant, Options, Phase}; /// An interface to the console for the rest of cargo-mutants. /// @@ -42,14 +41,6 @@ impl Console { } } - pub fn set_colors_enabled(&self, colors: Colors) { - if let Some(colors) = colors.forced_value() { - ::console::set_colors_enabled(colors); - ::console::set_colors_enabled_stderr(colors); - } - // Otherwise, let the console crate decide, based on isatty, etc. - } - pub fn walk_tree_start(&self) { self.view .update(|model| model.walk_tree = Some(WalkModel::default())); @@ -69,18 +60,12 @@ impl Console { } /// Update that a cargo task is starting. - pub fn scenario_started( - &self, - dir: &Utf8Path, - scenario: &Scenario, - log_file: File, - ) -> Result<()> { + pub fn scenario_started(&self, dir: &Utf8Path, scenario: &Scenario, log_file: File) { let start = Instant::now(); - let scenario_model = ScenarioModel::new(dir, scenario, start, log_file)?; + let scenario_model = ScenarioModel::new(dir, scenario, start, log_file); self.view.update(|model| { model.scenario_models.push(scenario_model); }); - Ok(()) } /// Update that cargo finished. @@ -92,7 +77,9 @@ impl Console { options: &Options, ) { self.view.update(|model| { - model.mutants_done += scenario.is_mutant() as usize; + if scenario.is_mutant() { + model.mutants_done += 1; + } match outcome.summary() { SummaryOutcome::CaughtMutant => model.mutants_caught += 1, SummaryOutcome::MissedMutant => model.mutants_missed += 1, @@ -169,7 +156,7 @@ impl Console { .iter_mut() .find(|m| m.dest == dest) .expect("copy in progress") - .bytes_copied(total_bytes) + .bytes_copied(total_bytes); }); } @@ -183,7 +170,7 @@ impl Console { self.view.update(|model| { model.n_mutants = n_mutants; model.lab_start_time = Some(Instant::now()); - }) + }); } /// Update that work is starting on testing a given number of mutants. @@ -196,13 +183,13 @@ impl Console { pub fn scenario_phase_started(&self, dir: &Utf8Path, phase: Phase) { self.view.update(|model| { model.find_scenario_mut(dir).phase_started(phase); - }) + }); } pub fn scenario_phase_finished(&self, dir: &Utf8Path, phase: Phase) { self.view.update(|model| { model.find_scenario_mut(dir).phase_finished(phase); - }) + }); } pub fn lab_finished(&self, lab_outcome: &LabOutcome, start_time: Instant, options: &Options) { @@ -216,7 +203,7 @@ impl Console { } pub fn clear(&self) { - self.view.clear() + self.view.clear(); } pub fn message(&self, message: &str) { @@ -224,11 +211,11 @@ impl Console { // stderr... // self.view.clear(); - print!("{}", message); + print!("{message}"); } pub fn tick(&self) { - self.view.update(|_| ()) + self.view.update(|_| ()); } /// Return a tracing `MakeWriter` that will send messages via nutmeg to the console. @@ -251,8 +238,8 @@ impl Console { /// Configure tracing to send messages to the console and debug log. /// - /// The debug log is opened later and provided by [Console::set_debug_log]. - pub fn setup_global_trace(&self, console_trace_level: Level, colors: Colors) -> Result<()> { + /// The debug log is opened later and provided by [`Console::set_debug_log`]. + pub fn setup_global_trace(&self, console_trace_level: Level, colors: Colors) { // Show time relative to the start of the program. let uptime = tracing_subscriber::fmt::time::uptime(); let stderr_colors = colors @@ -275,10 +262,17 @@ impl Console { .with(debug_log_layer) .with(console_layer) .init(); - Ok(()) } } +pub fn enable_console_colors(colors: Colors) { + if let Some(colors) = colors.forced_value() { + ::console::set_colors_enabled(colors); + ::console::set_colors_enabled_stderr(colors); + } + // Otherwise, let the console crate decide, based on isatty, etc. +} + impl Default for Console { fn default() -> Self { Self::new() @@ -367,26 +361,27 @@ struct LabModel { } impl nutmeg::Model for LabModel { + #[allow(clippy::cast_precision_loss)] fn render(&mut self, width: usize) -> String { let mut s = String::with_capacity(1024); if let Some(walk_tree) = &mut self.walk_tree { s += &walk_tree.render(width); } - for copy_model in self.copy_models.iter_mut() { + for copy_model in &mut self.copy_models { if !s.is_empty() { - s.push('\n') + s.push('\n'); } s.push_str(©_model.render(width)); } - for sm in self.scenario_models.iter_mut() { + for sm in &mut self.scenario_models { if !s.is_empty() { - s.push('\n') + s.push('\n'); } s.push_str(&sm.render(width)); } if let Some(lab_start_time) = self.lab_start_time { if !s.is_empty() { - s.push('\n') + s.push('\n'); } let elapsed = lab_start_time.elapsed(); s += &format!( @@ -489,21 +484,15 @@ struct ScenarioModel { } impl ScenarioModel { - fn new( - dir: &Utf8Path, - scenario: &Scenario, - start: Instant, - log_file: File, - ) -> Result { - let log_tail = TailFile::new(log_file).context("Failed to open log file")?; - Ok(ScenarioModel { + fn new(dir: &Utf8Path, scenario: &Scenario, start: Instant, log_file: File) -> ScenarioModel { + ScenarioModel { dir: dir.to_owned(), name: style_scenario(scenario, true), phase: None, phase_start: start, - log_tail, + log_tail: TailFile::new(log_file), previous_phase_durations: Vec::new(), - }) + } } fn phase_started(&mut self, phase: Phase) { @@ -569,7 +558,7 @@ impl CopyModel { /// /// `bytes_copied` is the total bytes copied so far. fn bytes_copied(&mut self, bytes_copied: u64) { - self.bytes_copied = bytes_copied + self.bytes_copied = bytes_copied; } } diff --git a/src/copy_tree.rs b/src/copy_tree.rs index 92cb7813..71a20808 100644 --- a/src/copy_tree.rs +++ b/src/copy_tree.rs @@ -25,8 +25,6 @@ use windows::copy_symlink; static VCS_DIRS: &[&str] = &[".git", ".hg", ".bzr", ".svn", "_darcs", ".pijul"]; /// Copy a source tree, with some exclusions, to a new temporary directory. -/// -/// Regardless, anything matching [SOURCE_EXCLUDE] is excluded. pub fn copy_tree( from_path: &Utf8Path, name_base: &str, diff --git a/src/fnvalue.rs b/src/fnvalue.rs index c5e1baab..1408b596 100644 --- a/src/fnvalue.rs +++ b/src/fnvalue.rs @@ -2,6 +2,8 @@ //! Mutations of replacing a function body with a value of a (hopefully) appropriate type. +#![warn(clippy::pedantic)] + use std::iter; use itertools::Itertools; @@ -25,8 +27,7 @@ pub(crate) fn return_type_replacements( } /// Generate some values that we hope are reasonable replacements for a type. -/// -/// This is really the heart of cargo-mutants. +#[allow(clippy::too_many_lines)] fn type_replacements(type_: &Type, error_exprs: &[Expr]) -> impl Iterator { // This could probably change to run from some configuration rather than // hardcoding various types, which would make it easier to support tree-specific @@ -292,7 +293,7 @@ fn known_container(path: &Path) -> Option<(&Ident, &Type)> { /// Match known simple collections that can be empty or constructed from an /// iterator. /// -/// Returns the short name (like "VecDeque") and the inner type. +/// Returns the short name (like `"VecDeque"`) and the inner type. fn known_collection(path: &Path) -> Option<(&Ident, &Type)> { let last = path.segments.last()?; if ![ @@ -445,7 +446,7 @@ mod test { #[test] fn recurse_into_result_bool() { check_replacements( - parse_quote! {-> std::result::Result }, + &parse_quote! {-> std::result::Result }, &[], &["Ok(true)", "Ok(false)"], ); @@ -454,7 +455,7 @@ mod test { #[test] fn recurse_into_result_result_bool_with_error_values() { check_replacements( - parse_quote! {-> std::result::Result> }, + &parse_quote! {-> std::result::Result> }, &[parse_quote! { anyhow!("mutated") }], &[ "Ok(Ok(true))", @@ -467,43 +468,43 @@ mod test { #[test] fn u16_replacements() { - check_replacements(parse_quote! { -> u16 }, &[], &["0", "1"]); + check_replacements(&parse_quote! { -> u16 }, &[], &["0", "1"]); } #[test] fn isize_replacements() { - check_replacements(parse_quote! { -> isize }, &[], &["0", "1", "-1"]); + check_replacements(&parse_quote! { -> isize }, &[], &["0", "1", "-1"]); } #[test] fn nonzero_integer_replacements() { check_replacements( - parse_quote! { -> std::num::NonZeroIsize }, + &parse_quote! { -> std::num::NonZeroIsize }, &[], &["1", "-1"], ); - check_replacements(parse_quote! { -> std::num::NonZeroUsize }, &[], &["1"]); + check_replacements(&parse_quote! { -> std::num::NonZeroUsize }, &[], &["1"]); - check_replacements(parse_quote! { -> std::num::NonZeroU32 }, &[], &["1"]); + check_replacements(&parse_quote! { -> std::num::NonZeroU32 }, &[], &["1"]); } #[test] fn unit_replacement() { - check_replacements(parse_quote! { -> () }, &[], &["()"]); + check_replacements(&parse_quote! { -> () }, &[], &["()"]); } #[test] fn result_unit_replacement() { - check_replacements(parse_quote! { -> Result<(), Error> }, &[], &["Ok(())"]); + check_replacements(&parse_quote! { -> Result<(), Error> }, &[], &["Ok(())"]); - check_replacements(parse_quote! { -> Result<()> }, &[], &["Ok(())"]); + check_replacements(&parse_quote! { -> Result<()> }, &[], &["Ok(())"]); } #[test] fn http_response_replacement() { check_replacements( - parse_quote! { -> HttpResponse }, + &parse_quote! { -> HttpResponse }, &[], &["HttpResponse::Ok().finish()"], ); @@ -512,7 +513,7 @@ mod test { #[test] fn option_usize_replacement() { check_replacements( - parse_quote! { -> Option }, + &parse_quote! { -> Option }, &[], &["None", "Some(0)", "Some(1)"], ); @@ -521,7 +522,7 @@ mod test { #[test] fn box_usize_replacement() { check_replacements( - parse_quote! { -> Box }, + &parse_quote! { -> Box }, &[], &["Box::new(0)", "Box::new(1)"], ); @@ -530,7 +531,7 @@ mod test { #[test] fn box_unrecognized_type_replacement() { check_replacements( - parse_quote! { -> Box }, + &parse_quote! { -> Box }, &[], &["Box::new(Default::default())"], ); @@ -539,7 +540,7 @@ mod test { #[test] fn vec_string_replacement() { check_replacements( - parse_quote! { -> std::vec::Vec }, + &parse_quote! { -> std::vec::Vec }, &[], &["vec![]", "vec![String::new()]", r#"vec!["xyzzy".into()]"#], ); @@ -547,18 +548,18 @@ mod test { #[test] fn float_replacement() { - check_replacements(parse_quote! { -> f32 }, &[], &["0.0", "1.0", "-1.0"]); + check_replacements(&parse_quote! { -> f32 }, &[], &["0.0", "1.0", "-1.0"]); } #[test] fn ref_replacement_recurses() { - check_replacements(parse_quote! { -> &bool }, &[], &["&true", "&false"]); + check_replacements(&parse_quote! { -> &bool }, &[], &["&true", "&false"]); } #[test] fn array_replacement() { check_replacements( - parse_quote! { -> [u8; 256] }, + &parse_quote! { -> [u8; 256] }, &[], &["[0; 256]", "[1; 256]"], ); @@ -569,7 +570,7 @@ mod test { // Also checks that it matches the path, even using an atypical path. // TODO: Ideally this would be fully qualified like `alloc::sync::Arc::new(String::new())`. check_replacements( - parse_quote! { -> alloc::sync::Arc }, + &parse_quote! { -> alloc::sync::Arc }, &[], &["Arc::new(String::new())", r#"Arc::new("xyzzy".into())"#], ); @@ -580,7 +581,7 @@ mod test { // Also checks that it matches the path, even using an atypical path. // TODO: Ideally this would be fully qualified like `alloc::sync::Rc::new(String::new())`. check_replacements( - parse_quote! { -> alloc::sync::Rc }, + &parse_quote! { -> alloc::sync::Rc }, &[], &["Rc::new(String::new())", r#"Rc::new("xyzzy".into())"#], ); @@ -652,7 +653,7 @@ mod test { #[test] fn btreeset_replacement() { check_replacements( - parse_quote! { -> std::collections::BTreeSet }, + &parse_quote! { -> std::collections::BTreeSet }, &[], &[ "BTreeSet::new()", @@ -665,7 +666,7 @@ mod test { #[test] fn cow_generates_borrowed_and_owned() { check_replacements( - parse_quote! { -> Cow<'static, str> }, + &parse_quote! { -> Cow<'static, str> }, &[], &[ r#"Cow::Borrowed("")"#, @@ -681,7 +682,7 @@ mod test { // This looks like something that holds a &str, and maybe can be constructed // from a &str, but we don't know anything else about it, so we just guess. check_replacements( - parse_quote! { -> UnknownContainer<'static, str> }, + &parse_quote! { -> UnknownContainer<'static, str> }, &[], &[ "UnknownContainer::new()", @@ -698,16 +699,16 @@ mod test { #[test] fn tuple_combinations() { check_replacements( - parse_quote! { -> (bool, usize) }, + &parse_quote! { -> (bool, usize) }, &[], &["(true, 0)", "(true, 1)", "(false, 0)", "(false, 1)"], - ) + ); } #[test] fn tuple_combination_longer() { check_replacements( - parse_quote! { -> (bool, Option) }, + &parse_quote! { -> (bool, Option) }, &[], &[ "(true, None)", @@ -717,13 +718,13 @@ mod test { "(false, Some(String::new()))", r#"(false, Some("xyzzy".into()))"#, ], - ) + ); } #[test] fn iter_replacement() { check_replacements( - parse_quote! { -> impl Iterator }, + &parse_quote! { -> impl Iterator }, &[], &[ "::std::iter::empty()", @@ -755,7 +756,7 @@ mod test { #[test] fn slice_replacement() { check_replacements( - parse_quote! { -> [u8] }, + &parse_quote! { -> [u8] }, &[], &[ "Vec::leak(Vec::new())", @@ -768,7 +769,7 @@ mod test { #[test] fn btreemap_replacement() { check_replacements( - parse_quote! { -> BTreeMap }, + &parse_quote! { -> BTreeMap }, &[], &[ "BTreeMap::new()", @@ -780,9 +781,9 @@ mod test { ); } - fn check_replacements(return_type: ReturnType, error_exprs: &[Expr], expected: &[&str]) { + fn check_replacements(return_type: &ReturnType, error_exprs: &[Expr], expected: &[&str]) { assert_eq!( - return_type_replacements(&return_type, error_exprs) + return_type_replacements(return_type, error_exprs) .into_iter() .map(|t| t.to_pretty_string()) .collect_vec(), diff --git a/src/in_diff.rs b/src/in_diff.rs index ab9a30e7..84efe18e 100644 --- a/src/in_diff.rs +++ b/src/in_diff.rs @@ -51,7 +51,7 @@ pub fn diff_filter(mutants: Vec, diff_text: &str) -> Result> } } let mut matched: Vec = Vec::with_capacity(mutants.len()); - 'mutant: for mutant in mutants.into_iter() { + 'mutant: for mutant in mutants { let path = mutant.source_file.path(); if let Some(lines_changed) = lines_changed_by_path.get(path) { // We could do be smarter about searching for an intersection of ranges, rather @@ -206,8 +206,8 @@ fn partial_new_file<'d>(patch: &Patch<'d>) -> Vec<(usize, &'d str)> { } } debug_assert_eq!( - lineno, - (hunk.new_range.start + hunk.new_range.count) as usize, + Ok(lineno), + (hunk.new_range.start + hunk.new_range.count).try_into(), "Wrong number of resulting lines?" ); } @@ -271,7 +271,7 @@ index eb42779..a0091b7 100644 #[test] fn affected_lines_from_single_insertion() { - let orig_lines = (1..=4).map(|i| format!("line {}\n", i)).collect_vec(); + let orig_lines = (1..=4).map(|i| format!("line {i}\n")).collect_vec(); for i in 1..=5 { let mut new = orig_lines.clone(); let new_value = "new line\n".to_owned(); @@ -291,7 +291,7 @@ index eb42779..a0091b7 100644 #[test] fn affected_lines_from_single_deletion() { - let orig_lines = (1..=5).map(|i| format!("line {}\n", i)).collect_vec(); + let orig_lines = (1..=5).map(|i| format!("line {i}\n")).collect_vec(); for i in 1..=5 { let mut new = orig_lines.clone(); new.remove(i - 1); @@ -312,7 +312,7 @@ index eb42779..a0091b7 100644 #[test] fn affected_lines_from_double_deletion() { - let orig_lines = (1..=5).map(|i| format!("line {}\n", i)).collect_vec(); + let orig_lines = (1..=5).map(|i| format!("line {i}\n")).collect_vec(); for i in 1..=4 { let mut new = orig_lines.clone(); new.remove(i - 1); @@ -332,7 +332,7 @@ index eb42779..a0091b7 100644 #[test] fn affected_lines_from_replacement() { - let orig_lines = (1..=5).map(|i| format!("line {}\n", i)).collect_vec(); + let orig_lines = (1..=5).map(|i| format!("line {i}\n")).collect_vec(); for i in 1..=5 { let insertion = ["new 1\n".to_owned(), "new 2\n".to_owned()]; let new = orig_lines[..(i - 1)] diff --git a/src/lab.rs b/src/lab.rs index cd487a3e..81873a79 100644 --- a/src/lab.rs +++ b/src/lab.rs @@ -203,7 +203,7 @@ impl Lab<'_> { Worker { build_dir, output_mutex: &self.output_mutex, - jobserver: &self.jobserver, + jobserver: self.jobserver.as_ref(), options: self.options, console: self.console, } @@ -217,7 +217,7 @@ impl Lab<'_> { struct Worker<'a> { build_dir: &'a BuildDir, output_mutex: &'a Mutex, - jobserver: &'a Option, + jobserver: Option<&'a jobserver::Client>, options: &'a Options, console: &'a Console, } @@ -262,7 +262,7 @@ impl Worker<'_> { .start_scenario(scenario)?; let dir = self.build_dir.path(); self.console - .scenario_started(dir, scenario, scenario_output.open_log_read()?)?; + .scenario_started(dir, scenario, scenario_output.open_log_read()?); if let Some(mutant) = scenario.mutant() { let mutated_code = mutant.mutated_code(); diff --git a/src/main.rs b/src/main.rs index 73f23000..b6c495ad 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,9 @@ //! //! See for the manual and more information. +#![warn(clippy::pedantic)] +#![allow(clippy::module_name_repetitions, clippy::needless_raw_string_hashes)] + mod build_dir; mod cargo; mod config; @@ -49,6 +52,7 @@ use clap::builder::Styles; use clap::{ArgAction, CommandFactory, Parser, ValueEnum}; use clap_complete::{generate, Shell}; use color_print::cstr; +use console::enable_console_colors; use output::{load_previously_caught, OutputDir}; use tracing::{debug, info}; @@ -102,6 +106,7 @@ pub enum BaselineStrategy { /// Find inadequately-tested code that can be removed without any tests failing. /// /// See for more information. +#[allow(clippy::struct_excessive_bools)] #[derive(Parser, PartialEq, Debug)] #[command( author, @@ -278,7 +283,12 @@ pub struct Args { line_col: bool, /// Create mutants.out within this directory. - #[arg(long, short = 'o', help_heading = "Output")] + #[arg( + long, + short = 'o', + env = "CARGO_MUTANTS_OUTPUT", + help_heading = "Output" + )] output: Option, /// Include only mutants in code touched by this diff. @@ -434,8 +444,8 @@ fn main() -> Result<()> { } let console = Console::new(); - console.setup_global_trace(args.level, args.colors)?; // We don't have Options yet. - console.set_colors_enabled(args.colors); + console.setup_global_trace(args.level, args.colors); // We don't have Options yet. + enable_console_colors(args.colors); interrupt::install_handler(); let start_dir: &Utf8Path = if let Some(manifest_path) = &args.manifest_path { @@ -523,7 +533,7 @@ mod test { let args = super::Args::command(); let mut problems = Vec::new(); for arg in args.get_arguments() { - if let Some(help) = arg.get_help().map(|s| s.to_string()) { + if let Some(help) = arg.get_help().map(ToString::to_string) { if !help.starts_with(char::is_uppercase) { problems.push(format!( "Help for {:?} does not start with a capital letter: {:?}", @@ -547,9 +557,9 @@ mod test { problems.push(format!("No help for {:?}", arg.get_id())); } } - problems.iter().for_each(|s| eprintln!("{s}")); - if !problems.is_empty() { - panic!("Problems with help text"); + for problem in &problems { + eprintln!("{problem}"); } + assert!(problems.is_empty(), "Problems with help text"); } } diff --git a/src/manifest.rs b/src/manifest.rs index 09d578c4..50894202 100644 --- a/src/manifest.rs +++ b/src/manifest.rs @@ -18,6 +18,7 @@ use crate::Result; /// /// `manifest_source_dir` is the directory originally containing the manifest, from /// which the absolute paths are calculated. +#[allow(clippy::module_name_repetitions)] pub fn fix_manifest(manifest_scratch_path: &Utf8Path, source_dir: &Utf8Path) -> Result<()> { let toml_str = read_to_string(manifest_scratch_path).with_context(|| { format!("failed to read manifest from build directory: {manifest_scratch_path}") diff --git a/src/mutate.rs b/src/mutate.rs index fd5c3525..a21634ef 100644 --- a/src/mutate.rs +++ b/src/mutate.rs @@ -57,6 +57,7 @@ pub struct Mutant { #[derive(Eq, PartialEq, Debug, Serialize)] pub struct Function { /// The function that's being mutated, including any containing namespaces. + #[allow(clippy::struct_field_names)] pub function_name: String, /// The return type of the function, including a leading "-> ", as a fragment of Rust syntax. @@ -84,8 +85,7 @@ impl Mutant { self.styled_parts() .into_iter() .map(|x| x.force_styling(false).to_string()) - .collect::>() - .join("") + .collect::() } pub fn name(&self, show_line_col: bool) -> String { @@ -126,6 +126,7 @@ impl Mutant { fn styled_parts(&self) -> Vec> { // This is like `impl Display for Mutant`, but with colors. // The text content should be the same. + #[allow(clippy::needless_pass_by_value)] // actually is needed for String vs &str? fn s(s: S) -> StyledObject { style(s.to_string()) } @@ -186,7 +187,7 @@ impl Mutant { .to_string() } - /// Apply this mutant to the relevant file within a BuildDir. + /// Apply this mutant to the relevant file within a `BuildDir`. pub fn apply(&self, build_dir: &BuildDir, mutated_code: &str) -> Result<()> { trace!(?self, "Apply mutant"); build_dir.overwrite_file(&self.source_file.tree_relative_path, mutated_code) @@ -236,7 +237,7 @@ impl Serialize for Mutant { let mut ss = serializer.serialize_struct("Mutant", 7)?; ss.serialize_field("package", &self.source_file.package_name)?; ss.serialize_field("file", &self.source_file.tree_relative_slashes())?; - ss.serialize_field("function", &self.function.as_ref().map(|a| a.as_ref()))?; + ss.serialize_field("function", &self.function.as_ref().map(Arc::as_ref))?; ss.serialize_field("span", &self.span)?; ss.serialize_field("replacement", &self.replacement)?; ss.serialize_field("genre", &self.genre)?; @@ -327,21 +328,21 @@ mod test { .unwrap() .mutants; let descriptions = mutants.iter().map(Mutant::describe_change).collect_vec(); - insta::assert_snapshot!( - descriptions.join("\n"), - @r###" - replace controlled_loop with () - replace > with == in controlled_loop - replace > with < in controlled_loop - replace * with + in controlled_loop - replace * with / in controlled_loop - "### + assert_eq!( + descriptions, + [ + "replace controlled_loop with ()", + "replace > with == in controlled_loop", + "replace > with < in controlled_loop", + "replace * with + in controlled_loop", + "replace * with / in controlled_loop", + ] ); } #[test] fn always_skip_constructors_called_new() { - let code = indoc! { r#" + let code = indoc! { r" struct S { x: i32, } @@ -351,7 +352,7 @@ mod test { Self { x } } } - "# }; + " }; let mutants = mutate_source_str(code, &Options::default()).unwrap(); assert_eq!(mutants, []); } @@ -422,6 +423,6 @@ mod test { fn strip_trailing_space(s: &str) -> String { // Split on \n so that we retain empty lines etc - s.split('\n').map(|l| l.trim_end()).join("\n") + s.split('\n').map(str::trim_end).join("\n") } } diff --git a/src/options.rs b/src/options.rs index 86620022..8ee391b4 100644 --- a/src/options.rs +++ b/src/options.rs @@ -8,10 +8,14 @@ //! 2. Config options (read from `.cargo/mutants.toml`) //! 3. Built-in defaults +#![warn(clippy::pedantic)] + +use std::env; #[cfg(test)] use std::ffi::OsString; use std::time::Duration; +use camino::Utf8PathBuf; use globset::GlobSet; use regex::RegexSet; use serde::Deserialize; @@ -21,11 +25,12 @@ use tracing::warn; use crate::config::Config; use crate::glob::build_glob_set; -use crate::*; +use crate::{Args, BaselineStrategy, Context, Phase, Result, ValueEnum}; /// Options for mutation testing, based on both command-line arguments and the /// config file. #[derive(Default, Debug, Clone)] +#[allow(clippy::struct_excessive_bools)] pub struct Options { /// Run tests in an unmutated tree? pub baseline: BaselineStrategy, @@ -200,7 +205,7 @@ impl Colors { /// /// Otherwise, return None, meaning we should decide based on the /// detected terminal characteristics. - pub fn forced_value(&self) -> Option { + pub fn forced_value(self) -> Option { // From https://bixense.com/clicolors/ if env::var("NO_COLOR").is_ok_and(|x| x != "0") { Some(false) @@ -216,7 +221,7 @@ impl Colors { } #[mutants::skip] // depends on a real tty etc, hard to test - pub fn active_stdout(&self) -> bool { + pub fn active_stdout(self) -> bool { self.forced_value() .unwrap_or_else(::console::colors_enabled) } @@ -243,7 +248,7 @@ impl Options { args.test_package .iter() .flat_map(|s| s.split(',')) - .map(|s| s.to_string()) + .map(ToString::to_string) .collect(), ) } else if args.test_workspace.is_none() && config.test_workspace == Some(true) { @@ -258,7 +263,7 @@ impl Options { .skip_calls .iter() .flat_map(|s| s.split(',')) - .map(|s| s.to_string()) + .map(ToString::to_string) .chain(config.skip_calls.iter().cloned()) .collect(); if args @@ -301,7 +306,7 @@ impl Options { jobserver_tasks: args.jobserver_tasks, leak_dirs: args.leak_dirs, minimum_test_timeout, - output_in_dir: args.output.clone(), + output_in_dir: args.output.clone().or(config.output.clone()), print_caught: args.caught, print_unviable: args.unviable, profile: args.profile.as_ref().or(config.profile.as_ref()).cloned(), @@ -338,6 +343,8 @@ impl Options { /// If the arguments are invalid. #[cfg(test)] pub fn from_arg_strs, S: Into + Clone>(args: I) -> Options { + use crate::Args; + use clap::Parser; let args = Args::try_parse_from(args).expect("Failed to parse args"); Options::from_args(&args).expect("Build options from args") } @@ -377,11 +384,13 @@ mod test { use std::io::Write; use std::str::FromStr; + use clap::Parser; use indoc::indoc; use rusty_fork::rusty_fork_test; use tempfile::NamedTempFile; use super::*; + use crate::Args; #[test] fn default_options() { @@ -445,10 +454,10 @@ mod test { #[test] fn cli_timeout_multiplier_overrides_config() { - let config = indoc! { r#" + let config = indoc! { r" timeout_multiplier = 1.0 build_timeout_multiplier = 2.0 - "#}; + "}; let mut config_file = NamedTempFile::new().unwrap(); config_file.write_all(config.as_bytes()).unwrap(); let args = Args::parse_from([ @@ -682,9 +691,9 @@ mod test { #[test] fn test_workspace_config_true() { let args = Args::try_parse_from(["mutants"]).unwrap(); - let config = indoc! { r#" + let config = indoc! { r" test_workspace = true - "#}; + "}; let config = Config::from_str(config).unwrap(); let options = Options::new(&args, &config).unwrap(); assert_eq!(options.test_package, TestPackages::Workspace); @@ -693,9 +702,9 @@ mod test { #[test] fn test_workspace_config_false() { let args = Args::try_parse_from(["mutants"]).unwrap(); - let config = indoc! { r#" + let config = indoc! { r" test_workspace = false - "#}; + "}; let config = Config::from_str(config).unwrap(); let options = Options::new(&args, &config).unwrap(); assert_eq!(options.test_package, TestPackages::Mutated); @@ -704,9 +713,9 @@ mod test { #[test] fn test_workspace_args_override_config_true() { let args = Args::try_parse_from(["mutants", "--test-workspace=true"]).unwrap(); - let config = indoc! { r#" + let config = indoc! { r" test_workspace = false - "#}; + "}; let config = Config::from_str(config).unwrap(); let options = Options::new(&args, &config).unwrap(); assert_eq!(options.test_package, TestPackages::Workspace); @@ -715,9 +724,9 @@ mod test { #[test] fn test_workspace_args_override_config_false() { let args = Args::try_parse_from(["mutants", "--test-workspace=false"]).unwrap(); - let config = indoc! { r#" + let config = indoc! { r" test_workspace = true - "#}; + "}; let config = Config::from_str(config).unwrap(); let options = Options::new(&args, &config).unwrap(); assert_eq!(options.test_package, TestPackages::Mutated); @@ -804,10 +813,10 @@ mod test { // You can configure off the default `with_capacity` skip_calls let args = Args::try_parse_from(["mutants"]).unwrap(); let config = Config::from_str( - r#" + r" skip_calls_defaults = false skip_calls = [] - "#, + ", ) .unwrap(); let options = Options::new(&args, &config).unwrap(); diff --git a/src/outcome.rs b/src/outcome.rs index 0ca5cab3..90e6c22c 100644 --- a/src/outcome.rs +++ b/src/outcome.rs @@ -3,9 +3,11 @@ //! The outcome of running a single mutation scenario, or a whole lab. use std::fmt; -use std::time::Duration; -use std::time::Instant; +use std::fs::read_to_string; +use std::time::{Duration, Instant}; +use anyhow::Context; +use camino::Utf8PathBuf; use humantime::format_duration; use output::ScenarioOutput; use serde::ser::SerializeStruct; @@ -15,7 +17,7 @@ use tracing::warn; use crate::console::plural; use crate::process::Exit; -use crate::*; +use crate::{exit_code, output, Options, Result, Scenario}; /// What phase of running a scenario. /// @@ -36,7 +38,7 @@ pub enum Phase { } impl Phase { - pub fn name(&self) -> &'static str { + pub fn name(self) -> &'static str { match self { Phase::Check => "check", Phase::Build => "build", @@ -53,6 +55,7 @@ impl fmt::Display for Phase { /// The outcome from a whole lab run containing multiple mutants. #[derive(Debug, Default, Serialize)] +#[allow(clippy::module_name_repetitions)] pub struct LabOutcome { /// All the scenario outcomes, including baseline builds. pub outcomes: Vec, @@ -140,6 +143,7 @@ impl LabOutcome { /// The result of running one mutation scenario. #[derive(Debug, Clone, Eq, PartialEq)] +#[allow(clippy::module_name_repetitions)] pub struct ScenarioOutcome { /// A file holding the text output from running this test. // TODO: Maybe this should be a log object? @@ -173,9 +177,9 @@ impl Serialize for ScenarioOutcome { impl ScenarioOutcome { pub fn new(scenario_output: &ScenarioOutput, scenario: Scenario) -> ScenarioOutcome { ScenarioOutcome { - output_dir: scenario_output.output_dir.to_owned(), + output_dir: scenario_output.output_dir.clone(), log_path: scenario_output.log_path().to_owned(), - diff_path: scenario_output.diff_path.to_owned(), + diff_path: scenario_output.diff_path.clone(), scenario, phase_results: Vec::new(), } @@ -311,6 +315,7 @@ impl Serialize for PhaseResult { /// Overall summary outcome for one mutant. #[derive(Debug, Clone, Eq, PartialEq, Serialize, Hash)] +#[allow(clippy::module_name_repetitions)] pub enum SummaryOutcome { Success, CaughtMutant, diff --git a/src/output.rs b/src/output.rs index 1505489a..71fd0616 100644 --- a/src/output.rs +++ b/src/output.rs @@ -2,14 +2,14 @@ //! A `mutants.out` directory holding logs and other output. -use std::collections::hash_map::Entry; -use std::collections::HashMap; -use std::fs::{create_dir, remove_dir_all, rename, write, File, OpenOptions}; +use std::collections::{hash_map::Entry, HashMap}; +use std::fs::{create_dir, read_to_string, remove_dir_all, rename, write, File, OpenOptions}; use std::io::{BufWriter, Write}; use std::path::Path; use std::thread::sleep; use std::time::Duration; +use camino::{Utf8Path, Utf8PathBuf}; use fs2::FileExt; use path_slash::PathExt; use serde::Serialize; @@ -18,7 +18,7 @@ use time::OffsetDateTime; use tracing::{info, trace}; use crate::outcome::{LabOutcome, SummaryOutcome}; -use crate::*; +use crate::{check_interrupted, Context, Mutant, Result, Scenario, ScenarioOutcome}; const OUTDIR_NAME: &str = "mutants.out"; const ROTATED_NAME: &str = "mutants.out.old"; @@ -86,6 +86,7 @@ impl LockFile { /// A `mutants.out` directory holding logs and other output information. #[derive(Debug)] +#[allow(clippy::module_name_repetitions)] pub struct OutputDir { path: Utf8PathBuf, @@ -276,7 +277,7 @@ pub fn load_previously_caught(output_parent_dir: &Utf8Path) -> Result Result Result<()> { - self.message(&format!("mutation diff:\n{}", diff))?; + self.message(&format!("mutation diff:\n{diff}"))?; let diff_path = self.diff_path.as_ref().expect("should know the diff path"); write(self.output_dir.join(diff_path), diff.as_bytes()) .with_context(|| format!("write diff to {diff_path}")) @@ -332,7 +334,7 @@ impl ScenarioOutput { OpenOptions::new() .read(true) .open(&path) - .with_context(|| format!("reopen {} for read", path)) + .with_context(|| format!("reopen {path} for read")) } /// Open a new handle that appends to the log file, so that it can be passed to a subprocess. @@ -341,7 +343,7 @@ impl ScenarioOutput { OpenOptions::new() .append(true) .open(&path) - .with_context(|| format!("reopen {} for append", path)) + .with_context(|| format!("reopen {path} for append")) } /// Write a message, with a marker. @@ -370,6 +372,7 @@ mod test { use tempfile::{tempdir, TempDir}; use super::*; + use crate::workspace::Workspace; fn minimal_source_tree() -> TempDir { let tmp = tempdir().unwrap(); diff --git a/src/package.rs b/src/package.rs index f11d4785..bb2c86e8 100644 --- a/src/package.rs +++ b/src/package.rs @@ -20,6 +20,7 @@ pub struct Package { /// A more specific view of which packages to mutate, after resolving `PackageFilter::Auto`. #[derive(Debug, Clone)] +#[allow(clippy::module_name_repetitions)] pub enum PackageSelection { All, Explicit(Vec), diff --git a/src/path.rs b/src/path.rs index 75eb304b..99027c7c 100644 --- a/src/path.rs +++ b/src/path.rs @@ -28,7 +28,7 @@ pub fn ascent(path: &Utf8Path) -> isize { max_ascent } -/// An extension trait that helps Utf8Path print with forward slashes, +/// An extension trait that helps `Utf8Path` print with forward slashes, /// even on Windows. /// /// This makes the output more consistent across platforms and so easier diff --git a/src/pretty.rs b/src/pretty.rs index ee1cec5c..1e91a112 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -1,4 +1,4 @@ -// Copyright 2021-2023 Martin Pool +// Copyright 2021-2024 Martin Pool //! Convert a token stream back to (reasonably) pretty Rust code in a string. @@ -10,10 +10,10 @@ pub(crate) trait ToPrettyString { fn to_pretty_string(&self) -> String; } -/// Convert a TokenStream representing some code to a reasonably formatted +/// Convert a `TokenStream` representing some code to a reasonably formatted /// string of Rust code. /// -/// [TokenStream] has a `to_string`, but it adds spaces in places that don't +/// `TokenStream` has a `to_string`, but it adds spaces in places that don't /// look idiomatic, so this reimplements it in a way that looks better. /// /// This is probably not correctly formatted for all Rust syntax, and only tries @@ -23,7 +23,7 @@ where T: ToTokens, { fn to_pretty_string(&self) -> String { - use TokenTree::*; + use TokenTree::{Group, Ident, Literal, Punct}; let mut b = String::with_capacity(200); let mut ts = self.to_token_stream().into_iter().peekable(); while let Some(tt) = ts.next() { diff --git a/src/process.rs b/src/process.rs index 17bbfb44..439c1f67 100644 --- a/src/process.rs +++ b/src/process.rs @@ -5,7 +5,8 @@ //! On Unix, the subprocess runs as its own process group, so that any //! grandchild processes are also signalled if it's interrupted. -#![allow(clippy::option_map_unit_fn)] // I don't think it's clearer with if/let. +#![warn(clippy::pedantic)] +#![allow(clippy::redundant_else)] use std::ffi::OsStr; use std::process::{Child, Command, Stdio}; @@ -49,7 +50,7 @@ impl Process { env: &[(String, String)], cwd: &Utf8Path, timeout: Option, - jobserver: &Option, + jobserver: Option<&jobserver::Client>, scenario_output: &mut ScenarioOutput, console: &Console, ) -> Result { @@ -57,10 +58,9 @@ impl Process { let process_status = loop { if let Some(exit_status) = child.poll()? { break exit_status; - } else { - console.tick(); - sleep(WAIT_POLL_INTERVAL); } + console.tick(); + sleep(WAIT_POLL_INTERVAL); }; scenario_output.message(&format!("result: {process_status:?}"))?; Ok(process_status) @@ -72,7 +72,7 @@ impl Process { env: &[(String, String)], cwd: &Utf8Path, timeout: Option, - jobserver: &Option, + jobserver: Option<&jobserver::Client>, scenario_output: &mut ScenarioOutput, ) -> Result { let start = Instant::now(); @@ -88,7 +88,9 @@ impl Process { .stdout(scenario_output.open_log_append()?) .stderr(scenario_output.open_log_append()?) .current_dir(cwd); - jobserver.as_ref().map(|js| js.configure(&mut command)); + if let Some(js) = jobserver { + js.configure(&mut command); + } configure_command(&mut command); let child = command .spawn() @@ -143,26 +145,26 @@ pub enum Exit { /// Exited with status 0. Success, /// Exited with status non-0. - Failure(u32), + Failure(i32), /// Exceeded its timeout, and killed. Timeout, /// Killed by some signal. #[cfg(unix)] - Signalled(u8), + Signalled(i32), /// Unknown or unexpected situation. Other, } impl Exit { - pub fn is_success(&self) -> bool { - *self == Exit::Success + pub fn is_success(self) -> bool { + self == Exit::Success } - pub fn is_timeout(&self) -> bool { - *self == Exit::Timeout + pub fn is_timeout(self) -> bool { + self == Exit::Timeout } - pub fn is_failure(&self) -> bool { + pub fn is_failure(self) -> bool { matches!(self, Exit::Failure(_)) } } @@ -201,13 +203,13 @@ mod test { fn shell_quoting() { assert_eq!(quote_argv(["foo".to_string()]), "foo"); assert_eq!( - quote_argv(["foo bar", r#"\blah\x"#, r#""quoted""#]), + quote_argv(["foo bar", r"\blah\x", r#""quoted""#]), r#"foo\ bar \\blah\\x \"quoted\""# ); assert_eq!(quote_argv([""]), ""); assert_eq!( quote_argv(["with whitespace", "\r\n\t\t"]), - r#"with\ whitespace \r\n\t\t"# + r"with\ whitespace \r\n\t\t" ); } } diff --git a/src/process/unix.rs b/src/process/unix.rs index 5243456f..d5f52aac 100644 --- a/src/process/unix.rs +++ b/src/process/unix.rs @@ -43,10 +43,10 @@ impl From for Exit { if code == 0 { Exit::Success } else { - Exit::Failure(code as u32) + Exit::Failure(code) } } else if let Some(signal) = status.signal() { - return Exit::Signalled(signal as u8); + return Exit::Signalled(signal); } else { Exit::Other } diff --git a/src/process/windows.rs b/src/process/windows.rs index 9bb913bf..c37950fd 100644 --- a/src/process/windows.rs +++ b/src/process/windows.rs @@ -20,7 +20,7 @@ impl From for Exit { if code == 0 { Exit::Success } else { - Exit::Failure(code as u32) + Exit::Failure(code) } } else { Exit::Other diff --git a/src/source.rs b/src/source.rs index 0240cedd..057cff91 100644 --- a/src/source.rs +++ b/src/source.rs @@ -21,6 +21,7 @@ use crate::span::LineColumn; /// Code is normalized to Unix line endings as it's read in, and modified /// files are written with Unix line endings. #[derive(Clone, Debug, Eq, PartialEq)] +#[allow(clippy::module_name_repetitions)] pub struct SourceFile { /// Which package within the workspace contains this file? pub package_name: String, @@ -30,7 +31,7 @@ pub struct SourceFile { /// Full copy of the unmodified source. /// - /// This is held in an [Arc] so that SourceFiles can be cloned without using excessive + /// This is held in an [Arc] so that `SourceFile`s can be cloned without using excessive /// amounts of memory. pub code: Arc, @@ -40,7 +41,7 @@ pub struct SourceFile { } impl SourceFile { - /// Construct a SourceFile representing a file within a tree. + /// Construct a `SourceFile` representing a file within a tree. /// /// This eagerly loads the text of the file. /// diff --git a/src/span.rs b/src/span.rs index 5dd0b817..6f12fe0e 100644 --- a/src/span.rs +++ b/src/span.rs @@ -3,7 +3,7 @@ //! Locations (line/column) and spans between them in source code. //! //! This is similar to, and can be automatically derived from, -//! [proc_macro2::Span] and [proc_macro2::LineColumn], but is +//! `proc_macro2::Span` and `proc_macro2::LineColumn`, but is //! a bit more convenient for our purposes. use std::fmt; @@ -183,13 +183,13 @@ mod test { #[test] fn linecolumn_debug_form() { let lc = LineColumn { line: 1, column: 2 }; - assert_eq!(format!("{:?}", lc), "LineColumn(1, 2)"); + assert_eq!(format!("{lc:?}"), "LineColumn(1, 2)"); } #[test] fn span_debug_form() { let span = Span::quad(1, 2, 3, 4); - assert_eq!(format!("{:?}", span), "Span(1, 2, 3, 4)"); + assert_eq!(format!("{span:?}"), "Span(1, 2, 3, 4)"); } #[test] @@ -230,7 +230,7 @@ mod test { } #[test] fn span_ops() { - let source = indoc! { r#" + let source = indoc! { r" fn foo() { some(); @@ -238,19 +238,19 @@ mod test { } const BAR: u32 = 32; - "# }; + " }; // typical multi-line case let span = Span::quad(2, 10, 5, 2); assert_eq!(span.extract(source), "{\n some();\n stuff();\n}"); let replaced = span.replace(source, "{ /* body deleted */ }"); assert_eq!( replaced, - indoc! { r#" + indoc! { r" fn foo() { /* body deleted */ } const BAR: u32 = 32; - "# } + " } ); // single-line case @@ -259,7 +259,7 @@ mod test { let replaced = span.replace(source, "69"); assert_eq!( replaced, - indoc! { r#" + indoc! { r" fn foo() { some(); @@ -267,7 +267,7 @@ mod test { } const BAR: u32 = 69; - "# } + " } ); } } diff --git a/src/tail_file.rs b/src/tail_file.rs index ee5e386c..71789f1e 100644 --- a/src/tail_file.rs +++ b/src/tail_file.rs @@ -23,12 +23,12 @@ pub struct TailFile { impl TailFile { /// Watch lines appended to the given file, which should be open for reading. - pub fn new(file: File) -> Result { - Ok(TailFile { + pub fn new(file: File) -> TailFile { + TailFile { file, last_line_seen: String::new(), read_buf: Vec::new(), - }) + } } /// Return the last non-empty, non-whitespace line from this file, or an empty string @@ -67,7 +67,7 @@ mod test { let mut tempfile = tempfile::NamedTempFile::new().unwrap(); let path: Utf8PathBuf = tempfile.path().to_owned().try_into().unwrap(); let reopened = File::open(&path).unwrap(); - let mut tailer = TailFile::new(reopened).unwrap(); + let mut tailer = TailFile::new(reopened); assert_eq!( tailer.last_line().unwrap(), diff --git a/src/timeouts.rs b/src/timeouts.rs index 47d191df..2d191442 100644 --- a/src/timeouts.rs +++ b/src/timeouts.rs @@ -31,17 +31,17 @@ impl Timeouts { baseline.phase_result(Phase::Build).map(|pr| pr.duration), options, ), - test: test_timeout( + test: Some(test_timeout( baseline.phase_result(Phase::Test).map(|pr| pr.duration), options, - ), + )), } } pub fn without_baseline(options: &Options) -> Timeouts { Timeouts { build: build_timeout(None, options), - test: test_timeout(None, options), + test: Some(test_timeout(None, options)), } } } @@ -51,15 +51,15 @@ fn warn_fallback_timeout(phase_name: &str, option: &str) { warn!("An explicit {phase_name} timeout is recommended when using {option}; using {FALLBACK_TIMEOUT_SECS} seconds by default"); } -fn test_timeout(baseline_duration: Option, options: &Options) -> Option { +fn test_timeout(baseline_duration: Option, options: &Options) -> Duration { if let Some(explicit) = options.test_timeout { - Some(explicit) + explicit } else if let Some(baseline_duration) = baseline_duration { let timeout = max( options.minimum_test_timeout, - Duration::from_secs( + Duration::from_secs_f64( (baseline_duration.as_secs_f64() * options.test_timeout_multiplier.unwrap_or(5.0)) - .ceil() as u64, + .ceil(), ), ); if options.show_times { @@ -68,10 +68,13 @@ fn test_timeout(baseline_duration: Option, options: &Options) -> Optio humantime::format_duration(timeout) ); } - Some(timeout) + timeout + } else if options.check_only { + // We won't have run baseline tests, and we won't run any other tests either. + Duration::from_secs(0) } else { warn_fallback_timeout("test", "--baseline=skip"); - Some(Duration::from_secs(FALLBACK_TIMEOUT_SECS)) + Duration::from_secs(FALLBACK_TIMEOUT_SECS) } } @@ -113,7 +116,7 @@ mod test { assert_eq!(options.test_timeout_multiplier, Some(1.5)); assert_eq!( test_timeout(Some(Duration::from_secs(40)), &options), - Some(Duration::from_secs(60)), + Duration::from_secs(60), ); } @@ -124,7 +127,7 @@ mod test { assert_eq!( test_timeout(Some(Duration::from_secs(40)), &options), - Some(Duration::from_secs(60)), + Duration::from_secs(60), ); } @@ -167,7 +170,7 @@ mod test { assert_eq!(options.test_timeout_multiplier, Some(2.0)); assert_eq!( test_timeout(Some(Duration::from_secs(42)), &options), - Some(Duration::from_secs(42 * 2)), + Duration::from_secs(42 * 2), ); } @@ -195,7 +198,7 @@ mod test { assert_eq!(options.test_timeout_multiplier, None); assert_eq!( test_timeout(Some(Duration::from_secs(42)), &options), - Some(Duration::from_secs(42 * 5)), + Duration::from_secs(42 * 5), ); } @@ -240,7 +243,7 @@ mod test { let options = Options::new(&args, &Config::default()).unwrap(); assert_eq!(options.test_timeout_multiplier, None); - assert_eq!(test_timeout(None, &options), Some(Duration::from_secs(300))); + assert_eq!(test_timeout(None, &options), Duration::from_secs(300)); assert_eq!(build_timeout(None, &options), None); } } diff --git a/src/visit.rs b/src/visit.rs index babe4117..83547444 100644 --- a/src/visit.rs +++ b/src/visit.rs @@ -7,10 +7,13 @@ //! e.g. for cargo they are identified from the targets. The tree walker then //! follows `mod` statements to recursively visit other referenced files. +#![warn(clippy::pedantic)] + use std::collections::VecDeque; use std::sync::Arc; use std::vec; +use camino::{Utf8Path, Utf8PathBuf}; use proc_macro2::{Ident, TokenStream}; use quote::{quote, ToTokens}; use syn::ext::IdentExt; @@ -24,7 +27,7 @@ use crate::mutate::Function; use crate::pretty::ToPrettyString; use crate::source::SourceFile; use crate::span::Span; -use crate::*; +use crate::{check_interrupted, Console, Context, Genre, Mutant, Options, Result}; /// Mutants and files discovered in a source tree. /// @@ -44,7 +47,7 @@ impl Discovered { trace!(?name, "skip previously caught mutant"); } !c - }) + }); } } @@ -72,13 +75,13 @@ pub fn walk_tree( // collect any mutants from them, and they don't count as "seen" for // `--list-files`. for mod_namespace in &external_mods { - if let Some(mod_path) = find_mod_source(workspace_dir, &source_file, mod_namespace)? { + if let Some(mod_path) = find_mod_source(workspace_dir, &source_file, mod_namespace) { file_queue.extend(SourceFile::load( workspace_dir, &mod_path, &source_file.package_name, false, - )?) + )?); } } let path = &source_file.tree_relative_path; @@ -184,8 +187,7 @@ impl ModNamespace { fn get_filesystem_name(&self) -> &Utf8Path { self.path_attribute .as_ref() - .map(Utf8PathBuf::as_path) - .unwrap_or(Utf8Path::new(&self.name)) + .map_or(Utf8Path::new(&self.name), Utf8PathBuf::as_path) } } @@ -263,14 +265,14 @@ impl DiscoveryVisitor<'_> { } /// Record that we generated some mutants. - fn collect_mutant(&mut self, span: Span, replacement: TokenStream, genre: Genre) { + fn collect_mutant(&mut self, span: Span, replacement: &TokenStream, genre: Genre) { self.mutants.push(Mutant { source_file: self.source_file.clone(), function: self.fn_stack.last().cloned(), span, replacement: replacement.to_pretty_string(), genre, - }) + }); } fn collect_fn_mutants(&mut self, sig: &Signature, block: &Block) { @@ -299,7 +301,7 @@ impl DiscoveryVisitor<'_> { if orig_block == new_block { debug!("Replacement is the same as the function body; skipping"); } else { - self.collect_mutant(body_span, rep, Genre::FnValue); + self.collect_mutant(body_span, &rep, Genre::FnValue); } } } @@ -527,10 +529,8 @@ impl<'ast> Visit<'ast> for DiscoveryVisitor<'_> { BinOp::Ge(_) => vec![quote! {<}], BinOp::Add(_) => vec![quote! {-}, quote! {*}], BinOp::AddAssign(_) => vec![quote! {-=}, quote! {*=}], - BinOp::Sub(_) => vec![quote! {+}, quote! {/}], - BinOp::SubAssign(_) => vec![quote! {+=}, quote! {/=}], - BinOp::Mul(_) => vec![quote! {+}, quote! {/}], - BinOp::MulAssign(_) => vec![quote! {+=}, quote! {/=}], + BinOp::Sub(_) | BinOp::Mul(_) => vec![quote! {+}, quote! {/}], + BinOp::SubAssign(_) | BinOp::MulAssign(_) => vec![quote! {+=}, quote! {/=}], BinOp::Div(_) => vec![quote! {%}, quote! {*}], BinOp::DivAssign(_) => vec![quote! {%=}, quote! {*=}], BinOp::Rem(_) => vec![quote! {/}, quote! {+}], @@ -555,7 +555,7 @@ impl<'ast> Visit<'ast> for DiscoveryVisitor<'_> { }; replacements .into_iter() - .for_each(|rep| self.collect_mutant(i.op.span().into(), rep, Genre::BinaryOperator)); + .for_each(|rep| self.collect_mutant(i.op.span().into(), &rep, Genre::BinaryOperator)); syn::visit::visit_expr_binary(self, i); } @@ -567,7 +567,7 @@ impl<'ast> Visit<'ast> for DiscoveryVisitor<'_> { } match i.op { UnOp::Not(_) | UnOp::Neg(_) => { - self.collect_mutant(i.op.span().into(), quote! {}, Genre::UnaryOperator); + self.collect_mutant(i.op.span().into(), "e! {}, Genre::UnaryOperator); } _ => { trace!( @@ -596,7 +596,7 @@ fn find_mod_source( tree_root: &Utf8Path, parent: &SourceFile, mod_namespace: &ExternalModRef, -) -> Result> { +) -> Option { // First, work out whether the mod will be a sibling in the same directory, or // in a child directory. // @@ -663,15 +663,14 @@ fn find_mod_source( let full_path = tree_root.join(&relative_path); if full_path.is_file() { trace!("found submodule in {full_path}"); - return Ok(Some(relative_path)); - } else { - tried_paths.push(full_path); + return Some(relative_path); } + tried_paths.push(full_path); } let mod_name = &mod_child.name; let definition_site = parent.format_source_location(mod_child.source_location.start); warn!(?definition_site, %mod_name, ?tried_paths, "referent of mod not found"); - Ok(None) + None } /// True if the signature of a function is such that it should be excluded. @@ -738,15 +737,12 @@ fn path_is(path: &syn::Path, idents: &[&str]) -> bool { /// /// This does not check type arguments. fn path_ends_with(path: &syn::Path, ident: &str) -> bool { - path.segments - .last() - .map(|s| s.ident == ident) - .unwrap_or(false) + path.segments.last().is_some_and(|s| s.ident == ident) } /// True if the attribute contains `mutants::skip`. /// -/// This for example returns true for `#[mutants::skip] or `#[cfg_attr(test, mutants::skip)]`. +/// This for example returns true for `#[mutants::skip]` or `#[cfg_attr(test, mutants::skip)]`. fn attr_is_mutants_skip(attr: &Attribute) -> bool { if path_is(attr.path(), &["mutants", "skip"]) { return true; @@ -757,7 +753,7 @@ fn attr_is_mutants_skip(attr: &Attribute) -> bool { let mut skip = false; if let Err(err) = attr.parse_nested_meta(|meta| { if path_is(&meta.path, &["mutants", "skip"]) { - skip = true + skip = true; } Ok(()) }) { @@ -802,11 +798,12 @@ fn find_path_attribute(attrs: &[Attribute]) -> std::result::Result std::result::Result, String> { let token_string = token_stream.to_string(); let item_mod = syn::parse_str::(&token_string).unwrap_or_else(|err| { @@ -880,13 +877,13 @@ mod test { #[test] fn find_path_attribute_on_module_item() { - let outer = run_find_path_attribute(quote! { + let outer = run_find_path_attribute("e! { #[path = "foo_file.rs"] mod foo; }); assert_eq!(outer, Ok(Some(Utf8PathBuf::from("foo_file.rs")))); - let inner = run_find_path_attribute(quote! { + let inner = run_find_path_attribute("e! { mod foo { #![path = "foo_folder"] @@ -900,26 +897,26 @@ mod test { #[test] fn reject_module_path_absolute() { // dots are valid - let dots = run_find_path_attribute(quote! { + let dots = run_find_path_attribute("e! { #[path = "contains/../dots.rs"] mod dots; }); assert_eq!(dots, Ok(Some(Utf8PathBuf::from("contains/../dots.rs")))); - let dots_inner = run_find_path_attribute(quote! { + let dots_inner = run_find_path_attribute("e! { mod dots_in_path { #![path = "contains/../dots"] } }); assert_eq!(dots_inner, Ok(Some(Utf8PathBuf::from("contains/../dots")))); - let leading_slash = run_find_path_attribute(quote! { + let leading_slash = run_find_path_attribute("e! { #[path = "/leading_slash.rs"] mod dots; }); assert_eq!(leading_slash, Err("/leading_slash.rs".to_owned())); - let allow_other_slashes = run_find_path_attribute(quote! { + let allow_other_slashes = run_find_path_attribute("e! { #[path = "foo/other/slashes/are/allowed.rs"] mod dots; }); @@ -928,7 +925,7 @@ mod test { Ok(Some(Utf8PathBuf::from("foo/other/slashes/are/allowed.rs"))) ); - let leading_slash2 = run_find_path_attribute(quote! { + let leading_slash2 = run_find_path_attribute("e! { #[path = "/leading_slash/../and_dots.rs"] mod dots; }); @@ -978,9 +975,7 @@ mod test { #[test] fn skip_with_capacity_by_default() { - let args = Args::try_parse_from(["mutants"]).unwrap(); - let config = Config::default(); - let options = Options::new(&args, &config).unwrap(); + let options = Options::from_arg_strs(["mutants"]); let mut mutants = mutate_source_str( indoc! {" fn main() { @@ -997,9 +992,7 @@ mod test { #[test] fn mutate_vec_with_capacity_when_default_skips_are_turned_off() { - let args = Args::try_parse_from(["mutants", "--skip-calls-defaults", "false"]).unwrap(); - let config = Config::default(); - let options = Options::new(&args, &config).unwrap(); + let options = Options::from_arg_strs(["mutants", "--skip-calls-defaults", "false"]); let mutants = mutate_source_str( indoc! {" fn main() { diff --git a/src/workspace.rs b/src/workspace.rs index 62228ef8..ee1aef1f 100644 --- a/src/workspace.rs +++ b/src/workspace.rs @@ -22,7 +22,7 @@ use std::process::Command; use anyhow::{anyhow, bail, ensure, Context}; use camino::{Utf8Path, Utf8PathBuf}; -use cargo_metadata::Metadata; +use cargo_metadata::{Metadata, TargetKind}; use itertools::Itertools; use serde_json::Value; use tracing::{debug, debug_span, error, warn}; @@ -306,7 +306,17 @@ fn package_top_sources( fn should_mutate_target(target: &cargo_metadata::Target) -> bool { for kind in &target.kind { - if kind == "bin" || kind == "proc-macro" || kind.ends_with("lib") { + // bin / proc-macro / *lib + if matches!( + kind, + TargetKind::Bin + | TargetKind::ProcMacro + | TargetKind::CDyLib + | TargetKind::DyLib + | TargetKind::Lib + | TargetKind::RLib + | TargetKind::StaticLib + ) { return true; } } diff --git a/tests/check_build.rs b/tests/check_build.rs index 6401c5d8..ecf044f3 100644 --- a/tests/check_build.rs +++ b/tests/check_build.rs @@ -2,6 +2,7 @@ //! Tests for `--check` +use indoc::indoc; use predicates::prelude::*; use pretty_assertions::assert_eq; @@ -16,8 +17,7 @@ fn small_well_tested_tree_check_only() { .current_dir(tmp_src_dir.path()) .assert() .success() - .stdout(predicate::function(|stdout: &str| { - insta::assert_snapshot!(stdout, @r###" + .stdout(indoc! {r" Found 4 mutants to test ok Unmutated baseline ok src/lib.rs:5:5: replace factorial -> u32 with 0 @@ -25,9 +25,8 @@ fn small_well_tested_tree_check_only() { ok src/lib.rs:7:11: replace *= with += in factorial ok src/lib.rs:7:11: replace *= with /= in factorial 4 mutants tested: 4 succeeded - "###); - true - })); + "}) + .stderr(""); let outcomes = outcome_json_counts(&tmp_src_dir); assert_eq!( outcomes, @@ -124,8 +123,7 @@ fn check_tree_with_mutants_skip() { .env_remove("RUST_BACKTRACE") .assert() .success() - .stdout(predicate::function(|stdout: &str| { - insta::assert_snapshot!(stdout, @r###" + .stdout(indoc! { r" Found 5 mutants to test ok Unmutated baseline ok src/lib.rs:15:5: replace controlled_loop with () @@ -134,9 +132,8 @@ fn check_tree_with_mutants_skip() { ok src/lib.rs:21:53: replace * with + in controlled_loop ok src/lib.rs:21:53: replace * with / in controlled_loop 5 mutants tested: 5 succeeded - "###); - true - })); + "}) + .stderr(""); assert_eq!( outcome_json_counts(&tmp_src_dir), serde_json::json!({ diff --git a/tests/config.rs b/tests/config.rs index 504c30ef..57a4b5f1 100644 --- a/tests/config.rs +++ b/tests/config.rs @@ -263,3 +263,51 @@ fn additional_cargo_test_args() { .assert() .success(); } + +#[test] +/// Set the `--output` directory via `output` config directive. +fn output_option_use_config() { + let output_tmpdir = TempDir::new().unwrap(); + let output_via_config = output_tmpdir.path().join("output_via_config"); + let testdata = copy_of_testdata("factorial"); + + let out_path_str = output_via_config + .to_string_lossy() + .escape_default() + .to_string(); + write_config_file(&testdata, &format!("output = \"{out_path_str}\"")); + + assert!( + !testdata.path().join("mutants.out").exists(), + "mutants.out should not be in a clean copy of the test data" + ); + + run() + .arg("mutants") + .args(["--check", "--no-times"]) + .arg("-d") + .arg(testdata.path()) + .assert() + .success(); + + assert!( + !testdata.path().join("mutants.out").exists(), + "mutants.out should not be in the source directory" + ); + let mutants_out = output_via_config.join("mutants.out"); + assert!( + mutants_out.exists(), + "mutants.out is in changed `output` directory" + ); + for name in [ + "mutants.json", + "debug.log", + "outcomes.json", + "missed.txt", + "caught.txt", + "timeout.txt", + "unviable.txt", + ] { + assert!(mutants_out.join(name).is_file(), "{name} is in mutants.out",); + } +} diff --git a/tests/in_place.rs b/tests/in_place.rs index 49bfd6a9..9e248c97 100644 --- a/tests/in_place.rs +++ b/tests/in_place.rs @@ -30,17 +30,18 @@ fn in_place_check_leaves_no_changes() -> Result<()> { "stderr:\n{}", String::from_utf8_lossy(&cmd.get_output().stderr) ); - fn check_file(tmp: &Path, new_name: &str, old_name: &str) -> Result<()> { - let orig_path = Path::new("testdata/small_well_tested"); - println!("comparing {new_name} and {old_name}"); - assert_eq!( - read_to_string(tmp.join(new_name))?.replace("\r\n", "\n"), - read_to_string(orig_path.join(old_name))?.replace("\r\n", "\n"), - "{old_name} should be the same as {new_name}" - ); - Ok(()) - } check_file(tmp_path, "Cargo.toml", "Cargo_test.toml")?; check_file(tmp_path, "src/lib.rs", "src/lib.rs")?; Ok(()) } + +fn check_file(tmp: &Path, new_name: &str, old_name: &str) -> Result<()> { + let orig_path = Path::new("testdata/small_well_tested"); + println!("comparing {new_name} and {old_name}"); + assert_eq!( + read_to_string(tmp.join(new_name))?.replace("\r\n", "\n"), + read_to_string(orig_path.join(old_name))?.replace("\r\n", "\n"), + "{old_name} should be the same as {new_name}" + ); + Ok(()) +} diff --git a/tests/iterate.rs b/tests/iterate.rs index 2252bd9d..e90a4c14 100644 --- a/tests/iterate.rs +++ b/tests/iterate.rs @@ -15,6 +15,7 @@ use tempfile::tempdir; use self::util::run; #[test] +#[allow(clippy::too_many_lines)] // long but pretty straightforward fn iterate() { let temp = tempdir().unwrap(); diff --git a/tests/main.rs b/tests/main.rs index fd1bd89d..f428de98 100644 --- a/tests/main.rs +++ b/tests/main.rs @@ -494,6 +494,46 @@ fn output_option() { } } +#[test] +/// Set the `--output` directory via environment variable `CARGO_MUTANTS_OUTPUT` +fn output_option_use_env() { + let tmp_src_dir = copy_of_testdata("factorial"); + let output_tmpdir = TempDir::new().unwrap(); + let output_via_env = output_tmpdir.path().join("output_via_env"); + assert!( + !tmp_src_dir.path().join("mutants.out").exists(), + "mutants.out should not be in a clean copy of the test data" + ); + run() + .env("CARGO_MUTANTS_OUTPUT", &output_via_env) + .arg("mutants") + .args(["--check", "--no-times"]) + .arg("-d") + .arg(tmp_src_dir.path()) + .assert() + .success(); + assert!( + !tmp_src_dir.path().join("mutants.out").exists(), + "mutants.out should not be in the source directory" + ); + let mutants_out = output_via_env.join("mutants.out"); + assert!( + mutants_out.exists(), + "mutants.out is in $CARGO_MUTANTS_OUTPUT directory" + ); + for name in [ + "mutants.json", + "debug.log", + "outcomes.json", + "missed.txt", + "caught.txt", + "timeout.txt", + "unviable.txt", + ] { + assert!(mutants_out.join(name).is_file(), "{name} is in mutants.out",); + } +} + #[test] fn check_succeeds_in_tree_that_builds_but_fails_tests() { // --check doesn't actually run the tests so won't discover that they fail. diff --git a/tests/util/mod.rs b/tests/util/mod.rs index 07ec37ec..ae9fe246 100644 --- a/tests/util/mod.rs +++ b/tests/util/mod.rs @@ -89,7 +89,7 @@ pub fn copy_testdata_to>(tree_name: &str, dest: P) { }) .after_entry_copied(|path, _file_type, _stats| { if path.ends_with("Cargo_test.toml") || path.ends_with(".cargo_test") { - renames.push(dest.join(path)) + renames.push(dest.join(path)); } Ok(()) })