diff --git a/crates/resolver-tests/tests/pubgrub.rs b/crates/resolver-tests/tests/pubgrub.rs new file mode 100644 index 00000000000..c6f54d95594 --- /dev/null +++ b/crates/resolver-tests/tests/pubgrub.rs @@ -0,0 +1,452 @@ +use cargo::core::{dependency::DepKind, Dependency}; + +use resolver_tests::{ + helpers::{ + dep, dep_kind, dep_req, dep_req_kind, pkg, pkg_dep, pkg_dep_link, pkg_dep_with, + pkg_id_source, registry, ToDep, + }, + pkg, resolve, resolve_and_validated, resolve_and_validated_raw, + sat::SatResolver, +}; + +#[test] +fn test_a_renamed_package() { + let reg = registry(vec![ + pkg_dep_with( + "a", + vec!["b".opt().rename("b_package")], + &[("default", &["b_package"])], + ), + pkg("b"), + ]); + + let deps = vec!["a".with(&["default"])]; + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated(deps, ®, &mut sat_resolver).is_ok()); +} + +#[test] +fn test_b_renamed_package_no_shadowing() { + let reg = registry(vec![ + pkg("url"), + pkg_dep("wasmi", vec!["wasmparser-nostd".rename("wasmparser")]), + pkg_dep("wasmparser", vec!["url".to_dep()]), + ]); + + let deps = vec![dep("wasmi")]; + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated(deps, ®, &mut sat_resolver).is_err()); +} + +#[test] +fn test_d_prerelease_semver() { + let reg = registry(vec![ + pkg!("parking_lot_core" => [dep_req("smallvec", "^1.6.1")]), + pkg(("smallvec", "2.0.0-alpha.3")), + pkg_dep_with( + ("tokio", "1.35.1"), + vec!["parking_lot_core".opt()], + &[("default", &["parking_lot_core"])], + ), + ]); + + let deps = vec!["tokio".with(&["default"])]; + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated(deps, ®, &mut sat_resolver).is_err()); +} + +#[test] +fn test_cyclic_features() { + let reg = registry(vec![pkg_dep_with( + "windows", + vec![], + &[ + ("Win32", &["Win32_Foundation"]), + ("Win32_Foundation", &["Win32"]), + ], + )]); + + let deps = vec!["windows".with(&["Win32_Foundation"])]; + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated(deps, ®, &mut sat_resolver).is_ok()); +} + +#[test] +fn test_cyclic_optional_dependencies() { + let reg = registry(vec![ + pkg_dep("async-global-executor", vec!["io-lifetimes".opt()]), + pkg_dep( + "io-lifetimes", + vec!["test".with(&["async-global-executor"])], + ), + pkg_dep_with( + "test", + vec!["async-global-executor".opt().with(&["io-lifetimes"])], + &[], + ), + ]); + + let deps = vec![dep("test")]; + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated(deps, ®, &mut sat_resolver).is_ok()); +} + +#[test] +fn test_i_cyclic_dependencies() { + let reg = registry(vec![ + pkg(("a", "1.0.0")), + pkg_dep(("a", "1.0.1"), vec![dep("dep")]), + pkg_dep("dep", vec![dep("a")]), + ]); + + let deps = vec![dep("dep")]; + + // Cyclic dependencies are not checked in the SAT resolver + assert!(resolve(deps.clone(), ®).is_err()); + assert!(SatResolver::new(®).sat_resolve(&deps)); +} + +#[test] +fn test_self_dependency() { + let reg = registry(vec![pkg_dep("dep", vec![dep("dep")])]); + + let deps = vec![dep("dep")]; + + // Cyclic dependencies are not checked in the SAT resolver + assert!(resolve(deps.clone(), ®).is_err()); + assert!(SatResolver::new(®).sat_resolve(&deps)); +} + +#[test] +fn test_activated_optional_self_dependency() { + let reg = registry(vec![pkg_dep("a", vec!["a".opt()])]); + + let deps = vec!["a".with(&["a"])]; + + // Cyclic dependencies are not checked in the SAT resolver + assert!(resolve(deps.clone(), ®).is_err()); + assert!(SatResolver::new(®).sat_resolve(&deps)); +} + +#[test] +fn test_e_build_dependency_with_same_name() { + let reg = registry(vec![ + pkg("memchr"), + pkg_dep_with( + ("regex", "1.4.6"), + vec!["memchr".opt()], + &[("default", &["memchr"])], + ), + pkg_dep("sv-parser", vec!["regex".with(&["default"])]), + pkg_dep( + "svlint", + vec![ + dep_req("regex", "^1.5"), + dep_req_kind("regex", "^1", DepKind::Build), + dep("sv-parser"), + ], + ), + ]); + + let deps = vec![dep("svlint")]; + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated(deps, ®, &mut sat_resolver).is_err()); +} + +#[test] +fn test_g_root_dev_dependency_with_same_name() { + let reg = registry(vec![pkg(("root", "1.0.1"))]); + + let deps = vec![dep_req_kind("root", "=1.0.1", DepKind::Development).rename("root101")]; + let source = pkg_id_source("root", "https://root.example.com"); + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated_raw(deps, ®, source, &mut sat_resolver).is_ok()); +} + +#[test] +fn test_t_dev_dependency() { + let reg = registry(vec![pkg_dep_with( + "burn-core", + vec![dep_kind("burn-ndarray", DepKind::Development)], + &[("default", &["burn-ndarray/std"])], + )]); + + let deps = vec!["burn-core".with(&["default"])]; + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated(deps, ®, &mut sat_resolver).is_ok()); +} + +#[test] +fn test_k_weak_dependencies() { + let reg = registry(vec![ + pkg_dep_with("borsh", vec!["borsh-derive".opt()], &[("std", &[])]), + pkg_dep_with( + "rust_decimal", + vec!["borsh".opt().with(&["borsh-derive"])], + &[("default", &["borsh?/std"])], + ), + ]); + + let deps = vec!["rust_decimal".with(&["default"])]; + + // Weak dependencies are not supported yet in the dependency resolver + assert!(resolve(deps.clone(), ®).is_err()); + assert!(SatResolver::new(®).sat_resolve(&deps)); +} + +#[test] +fn test_n_weak_dependencies() { + let reg = registry(vec![ + pkg_dep_with("memchr", vec!["std".opt()], &[("std", &["dep:std"])]), + pkg_dep_with( + "winnow", + vec!["memchr".opt()], + &[("default", &["memchr?/std"]), ("simd", &["dep:memchr"])], + ), + ]); + + let deps = vec!["winnow".with(&["default"])]; + + // Weak dependencies are not supported yet in the dependency resolver + assert!(resolve(deps.clone(), ®).is_err()); + assert!(SatResolver::new(®).sat_resolve(&deps)); +} + +#[test] +fn test_p_weak_dependencies() { + let reg = registry(vec![ + pkg_dep("a", vec![dep("bad")]), + pkg_dep_with("b", vec!["a".opt()], &[("perf-literal", &["dep:a"])]), + pkg_dep_with( + "c", + vec!["b".opt()], + &[ + ("perf-literal", &["b?/perf-literal"]), + ("perf-literal-multisubstring", &["dep:b"]), + ], + ), + pkg_dep_with("dep", vec![dep("c")], &[("default", &["c/perf-literal"])]), + ]); + + let deps = vec!["dep".with(&["default"])]; + + // Weak dependencies are not supported yet in the dependency resolver + assert!(resolve(deps.clone(), ®).is_err()); + assert!(SatResolver::new(®).sat_resolve(&deps)); +} + +#[test] +fn test_j_duplicate_sys_crate() { + let reg = registry(vec![ + pkg_dep_link("js", "js", vec![]), + pkg_dep_link("dep", "js", vec![dep("js")]), + ]); + + let deps = vec![dep("dep")]; + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated(deps, ®, &mut sat_resolver).is_err()); +} + +#[test] +fn test_h_missing_optional_dependency() { + let reg = registry(vec![ + pkg_dep("b", vec!["c".opt()]), + pkg_dep_with("dep", vec![dep("b")], &[("d", &["b/c"])]), + ]); + + let deps = vec!["dep".with(&["d"])]; + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated(deps, ®, &mut sat_resolver).is_err()); +} + +#[test] +fn test_l_feature_shadowing_missing_optional_dependency() { + let reg = registry(vec![pkg_dep_with( + "rustix", + vec!["alloc".opt()], + &[ + ("alloc", &[]), + ("default", &["alloc"]), + ("rustc-dep-of-std", &["dep:alloc"]), + ], + )]); + + let deps = vec!["rustix".with(&["default"])]; + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated(deps, ®, &mut sat_resolver).is_ok()); +} + +#[test] +fn test_m_feature_shadowing_activated_optional_dependency() { + let reg = registry(vec![ + pkg_dep("alloc", vec![dep("bad")]), + pkg_dep_with( + "rustix", + vec!["alloc".opt()], + &[ + ("alloc", &[]), + ("default", &["dep:alloc"]), + ("rustc-dep-of-std", &["alloc"]), + ], + ), + ]); + + let deps = vec!["rustix".with(&["default"])]; + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated(deps, ®, &mut sat_resolver).is_err()); +} + +#[test] +fn test_c_same_dep_twice_feature_unification() { + let reg = registry(vec![ + pkg_dep_with( + "iced", + vec!["iced_wgpu".opt(), "iced_wgpu".opt().with(&["webgl"])], + &[("default", &["iced_wgpu"])], + ), + pkg_dep_with("iced_wgpu", vec![], &[("webgl", &[])]), + ]); + + let deps = vec!["iced".with(&["default"])]; + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated(deps, ®, &mut sat_resolver).is_ok()); +} + +#[test] +fn test_o_no_implicit_feature() { + let reg = registry(vec![ + pkg("c"), + pkg_dep_with("ureq", vec!["c".opt()], &[("cookies", &["dep:c"])]), + pkg_dep_with("dep", vec![dep("ureq")], &[("cookies", &["ureq/c"])]), + ]); + + let deps = vec!["dep".with(&["cookies"])]; + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated(deps, ®, &mut sat_resolver).is_err()); +} + +#[test] +fn test_v_implicit_feature() { + let reg = registry(vec![ + pkg("c"), + pkg_dep("ureq", vec!["c".opt()]), + pkg_dep_with("dep", vec![dep("ureq")], &[("cookies", &["ureq/c"])]), + ]); + + let deps = vec!["dep".with(&["cookies"])]; + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated(deps, ®, &mut sat_resolver).is_ok()); +} + +#[test] +fn test_w_missing_explicit_default_feature() { + let reg = registry(vec![ + pkg_dep_with( + "fuel-tx", + vec![dep("serde"), "serde_json".opt()], + &[("default", &["serde/default"]), ("serde", &["serde_json"])], + ), + pkg("serde"), + ]); + + let deps = vec!["fuel-tx".with(&["default"])]; + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated(deps, ®, &mut sat_resolver).is_err()); +} + +#[test] +fn test_x_no_need_for_explicit_default_feature() { + let reg = registry(vec![ + pkg("a"), + pkg_dep_with( + "b", + vec!["a".with_default()], + &[("default", &["std"]), ("std", &[])], + ), + ]); + + let deps = vec!["b".with(&["default"])]; + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated(deps, ®, &mut sat_resolver).is_ok()); +} + +#[test] +fn test_f_dep_feature() { + let reg = registry(vec![ + pkg_dep_with("proc-macro2", vec![], &[("proc-macro", &[])]), + pkg_dep_with( + "syn", + vec![dep("proc-macro2")], + &[("proc-macro", &["proc-macro2/proc-macro"])], + ), + pkg_dep("serde_derive", vec!["syn".with(&["proc-macro"])]), + ]); + + let deps = vec![dep("serde_derive")]; + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated(deps, ®, &mut sat_resolver).is_ok()); +} + +#[test] +fn test_q_dep_feature() { + let reg = registry(vec![ + pkg_dep_with("proc-macro2", vec![], &[("proc-macro", &[])]), + pkg_dep_with( + "syn", + vec![dep("proc-macro2")], + &[("proc-macro", &["proc-macro2/proc-macro"])], + ), + ]); + + let deps = vec!["syn".with(&["proc-macro"])]; + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated(deps, ®, &mut sat_resolver).is_ok()); +} + +#[test] +fn test_r_implicit_feature_with_dep_feature() { + let reg = registry(vec![ + pkg_dep_with("quote", vec![], &[("proc-macro", &[])]), + pkg_dep_with( + "syn", + vec!["quote".opt()], + &[("default", &["quote", "quote/proc-macro"])], + ), + ]); + + let deps = vec!["syn".with(&["default"])]; + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated(deps, ®, &mut sat_resolver).is_ok()); +} + +#[test] +fn test_s_dep_feature_activating_shadowing_feature() { + let reg = registry(vec![ + pkg_dep_with( + "a", + vec!["b".opt(), "x".opt()], + &[("b", &["x"]), ("default", &["b/native"])], + ), + pkg_dep_with("b", vec![], &[("native", &[])]), + ]); + + let deps = vec!["a".with(&["default"])]; + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated(deps, ®, &mut sat_resolver).is_err()); +} + +#[test] +fn test_u_dep_feature_not_activating_shadowing_feature() { + let reg = registry(vec![ + pkg_dep_with( + "fuel-tx", + vec![dep("serde"), "serde_json".opt()], + &[("default", &["serde/default"]), ("serde", &["serde_json"])], + ), + pkg_dep_with("serde", vec![], &[("default", &[])]), + ]); + + let deps = vec!["fuel-tx".with(&["default"])]; + let mut sat_resolver = SatResolver::new(®); + assert!(resolve_and_validated(deps, ®, &mut sat_resolver).is_ok()); +}