From d4085f4a0153cf66af098062c365541386074bf7 Mon Sep 17 00:00:00 2001 From: Rain Date: Fri, 1 May 2020 11:26:42 -0700 Subject: [PATCH] [cargo-compare] add some comparison testing to CI This works by: * setting up a real, fairly complex fixture * generating random queries using proptest * running them through cargo and guppy * ensuring that they produce the same results Not only does this give us high confidence that cargo and guppy produce the same results, it also gets us most of the way to #83. Most of the work in this commit is simply setting up all the necessary test infrastructure. We piggy-back on existing proptest infrastructure as much as possible. --- Cargo.lock | 21 ++-- fixtures/README.md | 6 +- .../inside-outside/external/.gitignore | 2 + .../inside-outside/external/Cargo.toml | 27 +++++ .../inside-outside/external/src/lib.rs | 7 ++ .../inside-outside/inactive/.gitignore | 2 + .../inside-outside/inactive/Cargo.toml | 21 ++++ .../inside-outside/inactive/src/lib.rs | 7 ++ .../inside-outside/transitive/.gitignore | 2 + .../inside-outside/transitive/Cargo.toml | 17 +++ .../inside-outside/transitive/src/lib.rs | 7 ++ .../inside-outside/workspace/.gitignore | 1 + .../inside-outside/workspace/Cargo.lock | 75 +++++++++++++ .../inside-outside/workspace/Cargo.toml | 2 + .../workspace/internal-macro/Cargo.toml | 21 ++++ .../workspace/internal-macro/build.rs | 0 .../workspace/internal-macro/src/lib.rs | 7 ++ .../workspace/internal/Cargo.toml | 24 +++++ .../workspace/internal/src/lib.rs | 7 ++ .../inside-outside/workspace/main/Cargo.toml | 27 +++++ .../inside-outside/workspace/main/build.rs | 2 + .../inside-outside/workspace/main/src/lib.rs | 7 ++ .../inside-outside/workspace/side/Cargo.toml | 10 ++ .../inside-outside/workspace/side/src/lib.rs | 7 ++ .../inside-outside/workspace/src/lib.rs | 7 ++ guppy-cmdlib/Cargo.toml | 4 + guppy-cmdlib/src/lib.rs | 7 +- guppy-cmdlib/src/proptest.rs | 33 ++++++ guppy/src/graph/build.rs | 2 + guppy/src/graph/graph_impl.rs | 10 +- guppy/src/graph/proptest09.rs | 42 +++++++- tools/cargo-compare/Cargo.toml | 8 +- tools/cargo-compare/src/common.rs | 24 +++-- tools/cargo-compare/src/diff.rs | 22 +--- tools/cargo-compare/src/lib.rs | 29 +++-- tools/cargo-compare/src/tests/fixtures.rs | 100 ++++++++++++++++++ tools/cargo-compare/src/tests/mod.rs | 7 ++ .../src/tests/proptest_helpers.rs | 35 ++++++ .../src/tests/workspace_tests.rs | 5 + 39 files changed, 593 insertions(+), 51 deletions(-) create mode 100644 fixtures/workspace/inside-outside/external/.gitignore create mode 100644 fixtures/workspace/inside-outside/external/Cargo.toml create mode 100644 fixtures/workspace/inside-outside/external/src/lib.rs create mode 100644 fixtures/workspace/inside-outside/inactive/.gitignore create mode 100644 fixtures/workspace/inside-outside/inactive/Cargo.toml create mode 100644 fixtures/workspace/inside-outside/inactive/src/lib.rs create mode 100644 fixtures/workspace/inside-outside/transitive/.gitignore create mode 100644 fixtures/workspace/inside-outside/transitive/Cargo.toml create mode 100644 fixtures/workspace/inside-outside/transitive/src/lib.rs create mode 100644 fixtures/workspace/inside-outside/workspace/.gitignore create mode 100644 fixtures/workspace/inside-outside/workspace/Cargo.lock create mode 100644 fixtures/workspace/inside-outside/workspace/Cargo.toml create mode 100644 fixtures/workspace/inside-outside/workspace/internal-macro/Cargo.toml create mode 100644 fixtures/workspace/inside-outside/workspace/internal-macro/build.rs create mode 100644 fixtures/workspace/inside-outside/workspace/internal-macro/src/lib.rs create mode 100644 fixtures/workspace/inside-outside/workspace/internal/Cargo.toml create mode 100644 fixtures/workspace/inside-outside/workspace/internal/src/lib.rs create mode 100644 fixtures/workspace/inside-outside/workspace/main/Cargo.toml create mode 100644 fixtures/workspace/inside-outside/workspace/main/build.rs create mode 100644 fixtures/workspace/inside-outside/workspace/main/src/lib.rs create mode 100644 fixtures/workspace/inside-outside/workspace/side/Cargo.toml create mode 100644 fixtures/workspace/inside-outside/workspace/side/src/lib.rs create mode 100644 fixtures/workspace/inside-outside/workspace/src/lib.rs create mode 100644 guppy-cmdlib/src/proptest.rs create mode 100644 tools/cargo-compare/src/tests/fixtures.rs create mode 100644 tools/cargo-compare/src/tests/mod.rs create mode 100644 tools/cargo-compare/src/tests/proptest_helpers.rs create mode 100644 tools/cargo-compare/src/tests/workspace_tests.rs diff --git a/Cargo.lock b/Cargo.lock index 3741b77fdc4..67d42b0d120 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,15 +106,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cargo" version = "0.46.0" -source = "git+https://github.com/rust-lang/cargo.git?rev=258c89644c4587273a3ed3ee9522d2640facba43#258c89644c4587273a3ed3ee9522d2640facba43" +source = "git+https://github.com/rust-lang/cargo.git?rev=d7966eb004571b5464efece65867b66aa01b5d7b#d7966eb004571b5464efece65867b66aa01b5d7b" dependencies = [ "anyhow 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "bytesize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo-platform 0.1.1 (git+https://github.com/rust-lang/cargo.git?rev=258c89644c4587273a3ed3ee9522d2640facba43)", + "cargo-platform 0.1.1 (git+https://github.com/rust-lang/cargo.git?rev=d7966eb004571b5464efece65867b66aa01b5d7b)", "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "core-foundation 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "crates-io 0.31.1 (git+https://github.com/rust-lang/cargo.git?rev=258c89644c4587273a3ed3ee9522d2640facba43)", + "crates-io 0.31.1 (git+https://github.com/rust-lang/cargo.git?rev=d7966eb004571b5464efece65867b66aa01b5d7b)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "crypto-hash 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "curl 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)", @@ -168,11 +168,13 @@ name = "cargo-compare" version = "0.1.0" dependencies = [ "anyhow 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo 0.46.0 (git+https://github.com/rust-lang/cargo.git?rev=258c89644c4587273a3ed3ee9522d2640facba43)", + "cargo 0.46.0 (git+https://github.com/rust-lang/cargo.git?rev=d7966eb004571b5464efece65867b66aa01b5d7b)", "diffus 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", "guppy 0.3.1", "guppy-cmdlib 0.1.0", + "once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proptest 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -194,7 +196,7 @@ dependencies = [ [[package]] name = "cargo-platform" version = "0.1.1" -source = "git+https://github.com/rust-lang/cargo.git?rev=258c89644c4587273a3ed3ee9522d2640facba43#258c89644c4587273a3ed3ee9522d2640facba43" +source = "git+https://github.com/rust-lang/cargo.git?rev=d7966eb004571b5464efece65867b66aa01b5d7b#d7966eb004571b5464efece65867b66aa01b5d7b" dependencies = [ "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -294,7 +296,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "crates-io" version = "0.31.1" -source = "git+https://github.com/rust-lang/cargo.git?rev=258c89644c4587273a3ed3ee9522d2640facba43#258c89644c4587273a3ed3ee9522d2640facba43" +source = "git+https://github.com/rust-lang/cargo.git?rev=d7966eb004571b5464efece65867b66aa01b5d7b#d7966eb004571b5464efece65867b66aa01b5d7b" dependencies = [ "anyhow 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", "curl 0.4.28 (registry+https://github.com/rust-lang/crates.io-index)", @@ -644,6 +646,7 @@ version = "0.1.0" dependencies = [ "anyhow 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", "guppy 0.3.1", + "proptest 0.9.6 (registry+https://github.com/rust-lang/crates.io-index)", "structopt 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1793,8 +1796,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum bumpalo 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "12ae9db68ad7fac5fe51304d20f016c911539251075a214f8e663babefa35187" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" "checksum bytesize 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "716960a18f978640f25101b5cbf1c6f6b0d3192fab36a2d98ca96f0ecbe41010" -"checksum cargo 0.46.0 (git+https://github.com/rust-lang/cargo.git?rev=258c89644c4587273a3ed3ee9522d2640facba43)" = "" -"checksum cargo-platform 0.1.1 (git+https://github.com/rust-lang/cargo.git?rev=258c89644c4587273a3ed3ee9522d2640facba43)" = "" +"checksum cargo 0.46.0 (git+https://github.com/rust-lang/cargo.git?rev=d7966eb004571b5464efece65867b66aa01b5d7b)" = "" +"checksum cargo-platform 0.1.1 (git+https://github.com/rust-lang/cargo.git?rev=d7966eb004571b5464efece65867b66aa01b5d7b)" = "" "checksum cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46e3374c604fb39d1a2f35ed5e4a4e30e60d01fab49446e08f1b3e9a90aef202" "checksum cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" "checksum cc 1.0.52 (registry+https://github.com/rust-lang/crates.io-index)" = "c3d87b23d6a92cd03af510a5ade527033f6aa6fa92161e2d5863a907d4c5e31d" @@ -1806,7 +1809,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum commoncrypto-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1fed34f46747aa73dfaa578069fd8279d2818ade2b55f38f22a9401c7f4083e2" "checksum core-foundation 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "57d24c7a13c43e870e37c1556b74555437870a04514f7685f5b354e090567171" "checksum core-foundation-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b3a71ab494c0b5b860bdc8407ae08978052417070c2ced38573a9157ad75b8ac" -"checksum crates-io 0.31.1 (git+https://github.com/rust-lang/cargo.git?rev=258c89644c4587273a3ed3ee9522d2640facba43)" = "" +"checksum crates-io 0.31.1 (git+https://github.com/rust-lang/cargo.git?rev=d7966eb004571b5464efece65867b66aa01b5d7b)" = "" "checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" "checksum criterion 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1fc755679c12bda8e5523a71e4d654b6bf2e14bd838dfc48cde6559a05caf7d1" "checksum criterion-plot 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a01e15e0ea58e8234f96146b1f91fa9d0e4dd7a38da93ff7a75d42c0b9d3a545" diff --git a/fixtures/README.md b/fixtures/README.md index f9ccfd3e987..1ba641df557 100644 --- a/fixtures/README.md +++ b/fixtures/README.md @@ -8,5 +8,7 @@ The fixtures are organized into several folders. * `small`: relatively simple examples that cover basic and some edge case functionality * `large`: complex examples pulled from real-world Rust repositories, that test a variety of edge cases -* `invalid`: examples that are *representable* as cargo metadata (i.e. they are valid JSON and follow the general - schema) but are *invalid* in some way; `cargo metadata` should never be able to generate these +* `invalid`: examples that are [*representable*](https://oleb.net/blog/2018/03/making-illegal-states-unrepresentable/) + as cargo metadata (i.e. they are valid JSON and follow the general schema) but are *invalid* in some way; `cargo + metadata` should never be able to generate these +* `workspace`: real workspaces, used for comparison testing with Cargo diff --git a/fixtures/workspace/inside-outside/external/.gitignore b/fixtures/workspace/inside-outside/external/.gitignore new file mode 100644 index 00000000000..96ef6c0b944 --- /dev/null +++ b/fixtures/workspace/inside-outside/external/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/fixtures/workspace/inside-outside/external/Cargo.toml b/fixtures/workspace/inside-outside/external/Cargo.toml new file mode 100644 index 00000000000..913eacf44f1 --- /dev/null +++ b/fixtures/workspace/inside-outside/external/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "external" +version = "0.1.0" +authors = ["Fake Author "] +edition = "2018" + +[dependencies] +transitive = { path = "../transitive" } +bytes = { version = "0.5", optional = true } + +[dev-dependencies] +transitive = { path = "../transitive", features = ["dev-feature"] } + +[build-dependencies] +transitive = { path = "../transitive", features = ["build-feature"] } + +[features] +internal-dev-feature = [] +internal-build-feature = [] +main-dev-feature = [] +main-build-feature = [] +macro-normal-feature = [] +macro-build-feature = [] +macro-dev-feature = [] +side-feature = ["bytes"] + +[workspace] diff --git a/fixtures/workspace/inside-outside/external/src/lib.rs b/fixtures/workspace/inside-outside/external/src/lib.rs new file mode 100644 index 00000000000..31e1bb209f9 --- /dev/null +++ b/fixtures/workspace/inside-outside/external/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/fixtures/workspace/inside-outside/inactive/.gitignore b/fixtures/workspace/inside-outside/inactive/.gitignore new file mode 100644 index 00000000000..96ef6c0b944 --- /dev/null +++ b/fixtures/workspace/inside-outside/inactive/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/fixtures/workspace/inside-outside/inactive/Cargo.toml b/fixtures/workspace/inside-outside/inactive/Cargo.toml new file mode 100644 index 00000000000..bfceb459b31 --- /dev/null +++ b/fixtures/workspace/inside-outside/inactive/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "inactive" +version = "0.1.0" +authors = ["Fake Author "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +transitive = { path = "../transitive", features = ["inactive-normal"] } + +[build-dependencies] +transitive = { path = "../transitive", features = ["inactive-build"] } + +[dev-dependencies] +transitive = { path = "../transitive", features = ["inactive-dev"] } + +[features] +extra = ["transitive/extra"] + +[workspace] diff --git a/fixtures/workspace/inside-outside/inactive/src/lib.rs b/fixtures/workspace/inside-outside/inactive/src/lib.rs new file mode 100644 index 00000000000..31e1bb209f9 --- /dev/null +++ b/fixtures/workspace/inside-outside/inactive/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/fixtures/workspace/inside-outside/transitive/.gitignore b/fixtures/workspace/inside-outside/transitive/.gitignore new file mode 100644 index 00000000000..96ef6c0b944 --- /dev/null +++ b/fixtures/workspace/inside-outside/transitive/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/fixtures/workspace/inside-outside/transitive/Cargo.toml b/fixtures/workspace/inside-outside/transitive/Cargo.toml new file mode 100644 index 00000000000..9ad0cf4d759 --- /dev/null +++ b/fixtures/workspace/inside-outside/transitive/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "transitive" +version = "0.1.0" +authors = ["Fake Author "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[features] +build-feature = [] +dev-feature = [] +inactive-normal = [] +inactive-build = [] +inactive-dev = [] +extra = [] + +[workspace] diff --git a/fixtures/workspace/inside-outside/transitive/src/lib.rs b/fixtures/workspace/inside-outside/transitive/src/lib.rs new file mode 100644 index 00000000000..31e1bb209f9 --- /dev/null +++ b/fixtures/workspace/inside-outside/transitive/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/fixtures/workspace/inside-outside/workspace/.gitignore b/fixtures/workspace/inside-outside/workspace/.gitignore new file mode 100644 index 00000000000..ea8c4bf7f35 --- /dev/null +++ b/fixtures/workspace/inside-outside/workspace/.gitignore @@ -0,0 +1 @@ +/target diff --git a/fixtures/workspace/inside-outside/workspace/Cargo.lock b/fixtures/workspace/inside-outside/workspace/Cargo.lock new file mode 100644 index 00000000000..3b3d1984970 --- /dev/null +++ b/fixtures/workspace/inside-outside/workspace/Cargo.lock @@ -0,0 +1,75 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "bytes" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "130aac562c0dd69c56b3b1cc8ffd2e17be31d0b6c25b61c96b76231aa23e39e1" + +[[package]] +name = "external" +version = "0.1.0" +dependencies = [ + "bytes", + "transitive", +] + +[[package]] +name = "inactive" +version = "0.1.0" +dependencies = [ + "transitive", +] + +[[package]] +name = "internal" +version = "0.1.0" +dependencies = [ + "bytes", + "external", + "internal-macro", + "lazy_static", +] + +[[package]] +name = "internal-macro" +version = "0.1.0" +dependencies = [ + "external", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] + +[[package]] +name = "main" +version = "0.1.0" +dependencies = [ + "external", + "inactive", + "internal", + "internal-macro", +] + +[[package]] +name = "side" +version = "0.1.0" +dependencies = [ + "external", +] + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "transitive" +version = "0.1.0" diff --git a/fixtures/workspace/inside-outside/workspace/Cargo.toml b/fixtures/workspace/inside-outside/workspace/Cargo.toml new file mode 100644 index 00000000000..70fc568e06a --- /dev/null +++ b/fixtures/workspace/inside-outside/workspace/Cargo.toml @@ -0,0 +1,2 @@ +[workspace] +members = ["main", "internal", "internal-macro", "side"] diff --git a/fixtures/workspace/inside-outside/workspace/internal-macro/Cargo.toml b/fixtures/workspace/inside-outside/workspace/internal-macro/Cargo.toml new file mode 100644 index 00000000000..48e046aea90 --- /dev/null +++ b/fixtures/workspace/inside-outside/workspace/internal-macro/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "internal-macro" +version = "0.1.0" +authors = ["Fake Author "] +edition = "2018" + +[lib] +proc-macro = true + +[dependencies] +external = { path = "../../external", features = ["macro-normal-feature"] } + +[build-dependencies] +external = { path = "../../external", features = ["macro-build-feature"] } + +[dev-dependencies] +external = { path = "../../external", features = ["macro-dev-feature"] } + +[features] +main-build-feature = [] +internal-normal-feature = [] diff --git a/fixtures/workspace/inside-outside/workspace/internal-macro/build.rs b/fixtures/workspace/inside-outside/workspace/internal-macro/build.rs new file mode 100644 index 00000000000..e69de29bb2d diff --git a/fixtures/workspace/inside-outside/workspace/internal-macro/src/lib.rs b/fixtures/workspace/inside-outside/workspace/internal-macro/src/lib.rs new file mode 100644 index 00000000000..31e1bb209f9 --- /dev/null +++ b/fixtures/workspace/inside-outside/workspace/internal-macro/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/fixtures/workspace/inside-outside/workspace/internal/Cargo.toml b/fixtures/workspace/inside-outside/workspace/internal/Cargo.toml new file mode 100644 index 00000000000..6bd6c46c4cc --- /dev/null +++ b/fixtures/workspace/inside-outside/workspace/internal/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "internal" +version = "0.1.0" +authors = ["Fake Author "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +lazy_static = "1" +external = { path = "../../external" } +internal-macro = { path = "../internal-macro", features = ["internal-normal-feature"] } + +[dev-dependencies] +lazy_static = {version = "1", features = ["spin"] } +bytes = "0.5" +external = { path = "../../external", features = ["internal-dev-feature"] } + +[build-dependencies] +external = { path = "../../external", features = ["internal-build-feature"] } + +[features] +dev-feature = [] +build-feature = [] diff --git a/fixtures/workspace/inside-outside/workspace/internal/src/lib.rs b/fixtures/workspace/inside-outside/workspace/internal/src/lib.rs new file mode 100644 index 00000000000..31e1bb209f9 --- /dev/null +++ b/fixtures/workspace/inside-outside/workspace/internal/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/fixtures/workspace/inside-outside/workspace/main/Cargo.toml b/fixtures/workspace/inside-outside/workspace/main/Cargo.toml new file mode 100644 index 00000000000..0edafdeb335 --- /dev/null +++ b/fixtures/workspace/inside-outside/workspace/main/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "main" +version = "0.1.0" +authors = ["Fake Author "] +edition = "2018" +build = "build.rs" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +external = { path = "../../external" } +internal = { path = "../internal" } + +[build-dependencies] +external = { path = "../../external", features = ["main-build-feature"] } +internal = { path = "../internal", features = ["build-feature"] } +internal-macro = { path = "../internal-macro", features = ["main-build-feature"] } + +[dev-dependencies] +external = { path = "../../external", features = ["main-dev-feature"] } +internal = { path = "../internal", features = ["dev-feature"] } + +[target.'cfg(all(unix, not(unix)))'.build-dependencies] +inactive = { path = "../../inactive" } + +[features] +inactive-extra = ["inactive/extra"] diff --git a/fixtures/workspace/inside-outside/workspace/main/build.rs b/fixtures/workspace/inside-outside/workspace/main/build.rs new file mode 100644 index 00000000000..f79c691f085 --- /dev/null +++ b/fixtures/workspace/inside-outside/workspace/main/build.rs @@ -0,0 +1,2 @@ +fn main() { +} diff --git a/fixtures/workspace/inside-outside/workspace/main/src/lib.rs b/fixtures/workspace/inside-outside/workspace/main/src/lib.rs new file mode 100644 index 00000000000..31e1bb209f9 --- /dev/null +++ b/fixtures/workspace/inside-outside/workspace/main/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/fixtures/workspace/inside-outside/workspace/side/Cargo.toml b/fixtures/workspace/inside-outside/workspace/side/Cargo.toml new file mode 100644 index 00000000000..718d982ea22 --- /dev/null +++ b/fixtures/workspace/inside-outside/workspace/side/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "side" +version = "0.1.0" +authors = ["Fake Author "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +external = { path = "../../external", features = ["side-feature"] } diff --git a/fixtures/workspace/inside-outside/workspace/side/src/lib.rs b/fixtures/workspace/inside-outside/workspace/side/src/lib.rs new file mode 100644 index 00000000000..31e1bb209f9 --- /dev/null +++ b/fixtures/workspace/inside-outside/workspace/side/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/fixtures/workspace/inside-outside/workspace/src/lib.rs b/fixtures/workspace/inside-outside/workspace/src/lib.rs new file mode 100644 index 00000000000..31e1bb209f9 --- /dev/null +++ b/fixtures/workspace/inside-outside/workspace/src/lib.rs @@ -0,0 +1,7 @@ +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert_eq!(2 + 2, 4); + } +} diff --git a/guppy-cmdlib/Cargo.toml b/guppy-cmdlib/Cargo.toml index 4cb4f6a50bc..e75e29e0d88 100644 --- a/guppy-cmdlib/Cargo.toml +++ b/guppy-cmdlib/Cargo.toml @@ -11,3 +11,7 @@ edition = "2018" anyhow = "1.0.28" guppy = { path = "../guppy" } structopt = "0.3" +proptest = { version = "0.9", optional = true } + +[features] +proptest09 = ["proptest", "guppy/proptest09"] diff --git a/guppy-cmdlib/src/lib.rs b/guppy-cmdlib/src/lib.rs index e8c2ade8095..fda0be12cb4 100644 --- a/guppy-cmdlib/src/lib.rs +++ b/guppy-cmdlib/src/lib.rs @@ -5,6 +5,9 @@ //! //! This library allows translating command-line arguments into guppy's data structures. +#[cfg(feature = "proptest09")] +pub mod proptest; + use anyhow::Result; use guppy::graph::feature::{ all_filter, default_filter, feature_filter, none_filter, FeatureFilter, FeatureQuery, @@ -66,11 +69,11 @@ impl PackagesAndFeatures { /// Context for invoking the `cargo metadata` command. /// /// The options mirror Cargo's. -#[derive(Debug, StructOpt)] +#[derive(Clone, Debug, StructOpt)] pub struct CargoMetadataOptions { /// Path to Cargo.toml #[structopt(long = "manifest-path")] - manifest_path: Option, + pub manifest_path: Option, } impl CargoMetadataOptions { diff --git a/guppy-cmdlib/src/proptest.rs b/guppy-cmdlib/src/proptest.rs new file mode 100644 index 00000000000..574f2928d54 --- /dev/null +++ b/guppy-cmdlib/src/proptest.rs @@ -0,0 +1,33 @@ +// Copyright (c) The cargo-guppy Contributors +// SPDX-License-Identifier: MIT OR Apache-2.0 + +//! Proptest support. + +use crate::PackagesAndFeatures; +use guppy::graph::PackageGraph; +use proptest::collection::hash_set; +use proptest::prelude::*; + +impl PackagesAndFeatures { + pub fn strategy<'g>(graph: &'g PackageGraph) -> impl Strategy + 'g { + let workspace = graph.workspace(); + ( + // The lower bound of 0 is important because 0 means the whole workspace. + hash_set(workspace.prop09_name_strategy(), 0..8), + any::(), + any::(), + ) + .prop_map(move |(packages, all_features, no_default_features)| { + // TODO: select features from these packages (probably requires flat_map :/ ) + Self { + packages: packages + .into_iter() + .map(|package| package.to_string()) + .collect(), + features: vec![], + all_features, + no_default_features, + } + }) + } +} diff --git a/guppy/src/graph/build.rs b/guppy/src/graph/build.rs index 85285b7e3eb..3294a91e818 100644 --- a/guppy/src/graph/build.rs +++ b/guppy/src/graph/build.rs @@ -108,6 +108,8 @@ impl WorkspaceImpl { root: workspace_root, members_by_path, members_by_name, + #[cfg(feature = "proptest09")] + name_list: OnceCell::new(), }) } } diff --git a/guppy/src/graph/graph_impl.rs b/guppy/src/graph/graph_impl.rs index cfaf356f8e7..58df4ebb0f9 100644 --- a/guppy/src/graph/graph_impl.rs +++ b/guppy/src/graph/graph_impl.rs @@ -463,7 +463,7 @@ impl<'g> DependsCache<'g> { #[derive(Clone, Debug)] pub struct Workspace<'g> { graph: &'g PackageGraph, - inner: &'g WorkspaceImpl, + pub(super) inner: &'g WorkspaceImpl, } impl<'g> Workspace<'g> { @@ -472,6 +472,11 @@ impl<'g> Workspace<'g> { &self.inner.root } + /// Returns the number of packages in this workspace. + pub fn member_count(&self) -> usize { + self.inner.members_by_path.len() + } + /// Returns an iterator over workspace paths and package metadatas, sorted by the path /// they're in. pub fn members( @@ -522,6 +527,9 @@ pub(super) struct WorkspaceImpl { // This is a BTreeMap to allow presenting data in sorted order. pub(super) members_by_path: BTreeMap, pub(super) members_by_name: BTreeMap, PackageId>, + // Cache for members by name (only used for proptests) + #[cfg(feature = "proptest09")] + pub(super) name_list: OnceCell>>, } /// Information about a specific package in a `PackageGraph`. diff --git a/guppy/src/graph/proptest09.rs b/guppy/src/graph/proptest09.rs index 1e3191458c8..624d6ba4950 100644 --- a/guppy/src/graph/proptest09.rs +++ b/guppy/src/graph/proptest09.rs @@ -1,7 +1,7 @@ // Copyright (c) The cargo-guppy Contributors // SPDX-License-Identifier: MIT OR Apache-2.0 -use crate::graph::{PackageGraph, PackageLink, PackageQuery, PackageResolver}; +use crate::graph::{PackageGraph, PackageLink, PackageQuery, PackageResolver, Workspace}; use crate::PackageId; use fixedbitset::FixedBitSet; use petgraph::prelude::*; @@ -63,6 +63,46 @@ impl PackageGraph { } } +/// ## Helpers for property testing +/// +/// The methods in this section allow a `Workspace` to be used in property-based testing +/// scenarios. +/// +/// Currently, [proptest 0.9](https://docs.rs/proptest/0.9) is supported if the `proptest09` feature +/// is enabled. +impl<'g> Workspace<'g> { + /// Returns a `Strategy` that generates random package names from this workspace. + /// + /// Requires the `proptest09` feature to be enabled. + /// + /// ## Panics + /// + /// Panics if there are no packages in this `Workspace`. + pub fn prop09_name_strategy(&self) -> impl Strategy + 'g { + let name_list = self.name_list(); + (0..name_list.len()).prop_map(move |idx| name_list[idx].as_ref()) + } + + /// Returns a `Strategy` that generates random package IDs from this workspace. + /// + /// Requires the `proptest09` feature to be enabled. + /// + /// ## Panics + /// + /// Panics if there are no packages in this `Workspace`. + pub fn prop09_id_strategy(&self) -> impl Strategy + 'g { + let members_by_name = &self.inner.members_by_name; + self.prop09_name_strategy() + .prop_map(move |name| &members_by_name[name]) + } + + fn name_list(&self) -> &'g [Box] { + self.inner + .name_list + .get_or_init(|| self.inner.members_by_name.keys().cloned().collect()) + } +} + /// A randomly generated package resolver. /// /// Created by `PackageGraph::prop09_resolver_strategy`. Requires the `proptest09` feature to be diff --git a/tools/cargo-compare/Cargo.toml b/tools/cargo-compare/Cargo.toml index 57ef7f13b73..48210c5ac75 100644 --- a/tools/cargo-compare/Cargo.toml +++ b/tools/cargo-compare/Cargo.toml @@ -9,10 +9,16 @@ edition = "2018" [dependencies] anyhow = "1.0.28" # This version of cargo has some fixes to the new feature resolver that are missing from cargo 0.44.0. -cargo = { git = "https://github.com/rust-lang/cargo.git", rev = "258c89644c4587273a3ed3ee9522d2640facba43" } +cargo = { git = "https://github.com/rust-lang/cargo.git", rev = "d7966eb004571b5464efece65867b66aa01b5d7b" } diffus = "0.9.1" either = "1.5.3" guppy = { path = "../../guppy" } guppy-cmdlib = { path = "../../guppy-cmdlib" } structopt = "0.3" tempfile = "3.1.0" + +[dev-dependencies] +guppy-cmdlib = { path = "../../guppy-cmdlib", features = ["proptest09"] } +once_cell = "1.3.1" + +proptest = "0.9" diff --git a/tools/cargo-compare/src/common.rs b/tools/cargo-compare/src/common.rs index 30d218e29a6..b94936deecf 100644 --- a/tools/cargo-compare/src/common.rs +++ b/tools/cargo-compare/src/common.rs @@ -12,7 +12,7 @@ use cargo::ops::resolve_ws_with_opts; use cargo::Config; use guppy::graph::cargo::{CargoOptions, CargoResolverVersion, CargoSet}; use guppy::graph::feature::FeatureSet; -use guppy::graph::{DependencyDirection, PackageGraph}; +use guppy::graph::DependencyDirection; use guppy::{PackageId, Platform, TargetFeatures}; use guppy_cmdlib::{CargoMetadataOptions, PackagesAndFeatures}; use std::collections::{BTreeMap, BTreeSet}; @@ -45,7 +45,7 @@ pub struct GuppyCargoCommon { impl GuppyCargoCommon { /// Resolves data for this query using Cargo. - pub fn resolve_cargo(&self, ctx: &GlobalContext) -> Result { + pub fn resolve_cargo(&self, ctx: &GlobalContext<'_>) -> Result { let config = self.cargo_make_config(ctx)?; let root_manifest = self.cargo_discover_root(&config)?; let workspace = self.cargo_make_workspace(&config, &root_manifest)?; @@ -99,12 +99,16 @@ impl GuppyCargoCommon { // platform-specific filtering happens much later in the process. // Also, use activated_features_unverified since it's possible for a particular (package // ID, features for) combination to be missing. - let target_features = - resolved_features.activated_features_unverified(pkg_id, FeaturesFor::NormalOrDev); - target_map.insert(pkg_id.to_guppy(), target_features.to_guppy()); - let host_features = - resolved_features.activated_features_unverified(pkg_id, FeaturesFor::HostDep); - host_map.insert(pkg_id.to_guppy(), host_features.to_guppy()); + if let Some(target_features) = + resolved_features.activated_features_unverified(pkg_id, FeaturesFor::NormalOrDev) + { + target_map.insert(pkg_id.to_guppy(), target_features.to_guppy()); + } + if let Some(host_features) = + resolved_features.activated_features_unverified(pkg_id, FeaturesFor::HostDep) + { + host_map.insert(pkg_id.to_guppy(), host_features.to_guppy()); + } } Ok(FeatureMap { @@ -114,8 +118,8 @@ impl GuppyCargoCommon { } /// Resolves data for this query using Guppy. - pub fn resolve_guppy(&self, _ctx: &GlobalContext, graph: &PackageGraph) -> Result { - let feature_query = self.pf.make_feature_query(graph)?; + pub fn resolve_guppy(&self, ctx: &GlobalContext<'_>) -> Result { + let feature_query = self.pf.make_feature_query(ctx.graph())?; // Note that guppy is more flexible than cargo here -- with the v1 feature resolver, it can // evaluate dependencies one of three ways: diff --git a/tools/cargo-compare/src/diff.rs b/tools/cargo-compare/src/diff.rs index 3f66781af3f..dba9a74a28d 100644 --- a/tools/cargo-compare/src/diff.rs +++ b/tools/cargo-compare/src/diff.rs @@ -13,30 +13,20 @@ use structopt::StructOpt; #[derive(Debug, StructOpt)] pub struct DiffOpts { #[structopt(flatten)] - common: GuppyCargoCommon, + pub common: GuppyCargoCommon, } impl DiffOpts { /// Executes this command. pub fn exec(self, ctx: &GlobalContext) -> Result<()> { let cargo_map = self.common.resolve_cargo(ctx)?; - let graph = self.common.metadata_opts.make_command().build_graph()?; - let guppy_map = self.common.resolve_guppy(ctx, &graph)?; - - // As of 2020-04-30, Cargo's APIs don't let users tell the difference between the package - // being missing entirely, and the package being present but with no features. - // - // Note that this is only a problem for the v2 resolver -- the v1 resolver unifies - // everything across the target and host anyway so this issue is moot there. - // - // XXX fix this upstream. - let ignore_inserts = self.common.v2; + let guppy_map = self.common.resolve_guppy(ctx)?; println!("** target diff (guppy -> cargo):"); - print_diff(&guppy_map.target_map, &cargo_map.target_map, ignore_inserts); + print_diff(&guppy_map.target_map, &cargo_map.target_map); println!("\n** host diff (guppy -> cargo):"); - print_diff(&guppy_map.host_map, &cargo_map.host_map, ignore_inserts); + print_diff(&guppy_map.host_map, &cargo_map.host_map); Ok(()) } @@ -45,12 +35,10 @@ impl DiffOpts { fn print_diff( a: &BTreeMap>, b: &BTreeMap>, - ignore_inserts: bool, ) { if let edit::Edit::Change(diff) = a.diff(&b) { for (pkg_id, diff) in diff { - let ignore = diff.is_copy() || (ignore_inserts && diff.is_insert()); - if !ignore { + if !diff.is_copy() { println!("{}: {:?}", pkg_id, diff); } } diff --git a/tools/cargo-compare/src/lib.rs b/tools/cargo-compare/src/lib.rs index 2e4c9aad1be..e46689f2990 100644 --- a/tools/cargo-compare/src/lib.rs +++ b/tools/cargo-compare/src/lib.rs @@ -6,6 +6,7 @@ use crate::diff::DiffOpts; use anyhow::Result; use either::Either; +use guppy::graph::PackageGraph; use std::env; use std::path::{Path, PathBuf}; use structopt::StructOpt; @@ -13,6 +14,8 @@ use tempfile::TempDir; pub mod common; pub mod diff; +#[cfg(test)] +mod tests; pub mod type_conversions; #[derive(Debug, StructOpt)] @@ -24,11 +27,13 @@ pub struct CargoCompare { impl CargoCompare { pub fn exec(self) -> Result<()> { - // Don't use the temporary home here so that Cargo caches can be reused. - let ctx = GlobalContext::new(false)?; - match self.cmd { - Command::Diff(opts) => opts.exec(&ctx), + Command::Diff(opts) => { + // Don't use the temporary home here so that Cargo caches can be reused. + let graph = opts.common.metadata_opts.make_command().build_graph()?; + let ctx = GlobalContext::new(false, &graph)?; + opts.exec(&ctx) + } } } } @@ -42,18 +47,22 @@ enum Command { /// Global context for Cargo comparisons. #[derive(Debug)] -pub struct GlobalContext { +pub struct GlobalContext<'g> { home_dir: Either, + graph: &'g PackageGraph, } -impl GlobalContext { - pub fn new(temp_home: bool) -> Result { +impl<'g> GlobalContext<'g> { + pub fn new(temp_home: bool, graph: &'g PackageGraph) -> Result { let home = if temp_home { Either::Left(TempDir::new()?) } else { Either::Right(env::current_dir()?) }; - Ok(Self { home_dir: home }) + Ok(Self { + home_dir: home, + graph, + }) } pub fn home_dir(&self) -> &Path { @@ -62,4 +71,8 @@ impl GlobalContext { Either::Right(home_dir) => home_dir.as_path(), } } + + pub fn graph(&self) -> &'g PackageGraph { + self.graph + } } diff --git a/tools/cargo-compare/src/tests/fixtures.rs b/tools/cargo-compare/src/tests/fixtures.rs new file mode 100644 index 00000000000..94fb4e24ef0 --- /dev/null +++ b/tools/cargo-compare/src/tests/fixtures.rs @@ -0,0 +1,100 @@ +// Copyright (c) The cargo-guppy Contributors +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use crate::common::GuppyCargoCommon; +use guppy::graph::PackageGraph; +use guppy_cmdlib::{CargoMetadataOptions, PackagesAndFeatures}; +use once_cell::sync::Lazy; +use proptest::prelude::*; +use std::path::Path; + +// --- +// Paths to fixtures, relative to the cargo-compare directory (the one with Cargo.toml) +// --- +pub(super) static INSIDE_OUTSIDE_WORKSPACE: &str = + "../../fixtures/workspace/inside-outside/workspace"; +pub(super) static CARGO_GUPPY_WORKSPACE: &str = "."; + +#[derive(Debug)] +pub struct Fixture { + metadata_opts: CargoMetadataOptions, + graph: PackageGraph, +} + +macro_rules! define_fixture { + ($name: ident, $path: ident) => { + pub(crate) fn $name() -> &'static Fixture { + static FIXTURE: Lazy = Lazy::new(|| Fixture::new($path)); + &*FIXTURE + } + }; +} + +static CARGO_MANIFEST_DIR: &str = env!("CARGO_MANIFEST_DIR"); + +impl Fixture { + pub fn new(workspace_dir: &str) -> Self { + // Assume that the workspace is relative to `CARGO_MANIFEST_DIR`. + let workspace_dir = Path::new(CARGO_MANIFEST_DIR).join(workspace_dir); + if !workspace_dir.is_dir() { + panic!( + "workspace_dir {} is not a directory", + workspace_dir.display() + ); + } + let metadata_opts = CargoMetadataOptions { + manifest_path: Some(workspace_dir.join("Cargo.toml")), + }; + let graph = metadata_opts + .make_command() + .build_graph() + .expect("constructing package graph worked"); + + Self { + metadata_opts, + graph, + } + } + + // --- + // Fixtures + // --- + + define_fixture!(inside_outside, INSIDE_OUTSIDE_WORKSPACE); + define_fixture!(cargo_guppy, CARGO_GUPPY_WORKSPACE); + + // --- + + pub fn graph(&self) -> &PackageGraph { + &self.graph + } + + /// Returns the number of proptest iterations that should be run for this fixture. + pub fn num_proptests(&self) -> u32 { + // Large graphs (like cargo-guppy's) can only really do a tiny number of proptests + // reasonably. It would be cool to figure out a way to speed it up (maybe through + // parallelization?) + if self.graph.package_count() > 100 { + 2 + } else { + 16 + } + } + + pub fn common_strategy<'a>(&'a self) -> impl Strategy + 'a { + let metadata_opts = &self.metadata_opts; + ( + PackagesAndFeatures::strategy(self.graph()), + any::(), + any::(), + // TODO: random target_platform generation + ) + .prop_map(move |(pf, include_dev, v2)| GuppyCargoCommon { + pf, + include_dev, + v2, + target_platform: None, + metadata_opts: metadata_opts.clone(), + }) + } +} diff --git a/tools/cargo-compare/src/tests/mod.rs b/tools/cargo-compare/src/tests/mod.rs new file mode 100644 index 00000000000..d14670e1d3c --- /dev/null +++ b/tools/cargo-compare/src/tests/mod.rs @@ -0,0 +1,7 @@ +// Copyright (c) The cargo-guppy Contributors +// SPDX-License-Identifier: MIT OR Apache-2.0 + +mod fixtures; +#[macro_use] +mod proptest_helpers; +mod workspace_tests; diff --git a/tools/cargo-compare/src/tests/proptest_helpers.rs b/tools/cargo-compare/src/tests/proptest_helpers.rs new file mode 100644 index 00000000000..d4e8fb1d009 --- /dev/null +++ b/tools/cargo-compare/src/tests/proptest_helpers.rs @@ -0,0 +1,35 @@ +// Copyright (c) The cargo-guppy Contributors +// SPDX-License-Identifier: MIT OR Apache-2.0 + +use crate::common::GuppyCargoCommon; +use crate::diff::DiffOpts; +use crate::GlobalContext; +use guppy::graph::PackageGraph; + +macro_rules! proptest_suite { + ($name: ident) => { + mod $name { + use crate::tests::fixtures::Fixture; + use crate::tests::proptest_helpers::*; + use proptest::prelude::*; + + #[test] + fn proptest_compare() { + let fixture = Fixture::$name(); + // cargo is pretty slow, so limit the number of test cases. + proptest!(ProptestConfig::with_cases(fixture.num_proptests()), |( + common in fixture.common_strategy(), + )| { + compare(fixture.graph(), common); + }); + } + } + } +} + +/// Test that there is no diff between guppy and cargo for the same query. +pub(super) fn compare(graph: &PackageGraph, common: GuppyCargoCommon) { + let diff_opts = DiffOpts { common }; + let ctx = GlobalContext::new(true, graph).expect("context created"); + diff_opts.exec(&ctx).expect("no errors and no diff found"); +} diff --git a/tools/cargo-compare/src/tests/workspace_tests.rs b/tools/cargo-compare/src/tests/workspace_tests.rs new file mode 100644 index 00000000000..1b8ee7547e4 --- /dev/null +++ b/tools/cargo-compare/src/tests/workspace_tests.rs @@ -0,0 +1,5 @@ +// Copyright (c) The cargo-guppy Contributors +// SPDX-License-Identifier: MIT OR Apache-2.0 + +proptest_suite!(inside_outside); +proptest_suite!(cargo_guppy);