diff --git a/src/lib.rs b/src/lib.rs index 1e4114fd..badce97b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,7 +27,7 @@ pub use query::{ActualSemverUpdate, RequiredSemverUpdate, SemverQuery}; /// Test a release for semver violations. #[non_exhaustive] -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] pub struct Check { /// Which packages to analyze. scope: Scope, @@ -52,7 +52,7 @@ pub enum ReleaseType { } #[non_exhaustive] -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] pub struct Rustdoc { source: RustdocSource, } @@ -102,7 +102,7 @@ impl Rustdoc { } } -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] enum RustdocSource { /// Path to the Rustdoc json file. /// Use this option when you have already generated the rustdoc file. @@ -120,12 +120,12 @@ enum RustdocSource { } /// Which packages to analyze. -#[derive(Default, Debug)] +#[derive(Default, Debug, PartialEq, Eq)] struct Scope { mode: ScopeMode, } -#[derive(Debug)] +#[derive(Debug, PartialEq, Eq)] enum ScopeMode { /// All packages except the excluded ones. DenyList(PackageSelection), @@ -140,7 +140,7 @@ impl Default for ScopeMode { } #[non_exhaustive] -#[derive(Default, Clone, Debug)] +#[derive(Default, Clone, Debug, PartialEq, Eq)] pub struct PackageSelection { selection: ScopeSelection, excluded_packages: Vec, diff --git a/src/main.rs b/src/main.rs index 945f25f6..8ad8816b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -121,7 +121,7 @@ enum SemverChecksCommands { CheckRelease(CheckRelease), } -#[derive(Debug, Args)] +#[derive(Debug, Args, Clone)] struct CheckRelease { #[command(flatten, next_help_heading = "Current")] pub manifest: clap_cargo::Manifest, @@ -340,8 +340,15 @@ impl From for cargo_semver_checks::Check { let mut baseline_features = value.baseline_features; current_features.append(&mut mutual_features.clone()); baseline_features.append(&mut mutual_features); - check.with_extra_features(current_features, baseline_features); + // Treat --features="" as a no-op like cargo does + let trim_features = |features: &mut Vec| { + features.retain(|feature| !feature.is_empty()); + }; + trim_features(&mut current_features); + trim_features(&mut baseline_features); + + check.with_extra_features(current_features, baseline_features); check } } @@ -351,3 +358,22 @@ fn verify_cli() { use clap::CommandFactory; Cargo::command().debug_assert() } + +#[test] +fn features_empty_string_is_no_op() { + use cargo_semver_checks::Check; + + let Cargo::SemverChecks(SemverChecks { + check_release: no_features, + .. + }) = Cargo::parse_from(["cargo", "semver-checks"]); + + let empty_features = CheckRelease { + features: vec![String::new()], + current_features: vec![String::new(), String::new()], + baseline_features: vec![String::new()], + ..no_features.clone() + }; + + assert_eq!(Check::from(no_features), Check::from(empty_features)); +} diff --git a/src/rustdoc_gen.rs b/src/rustdoc_gen.rs index 95732d05..be404a62 100644 --- a/src/rustdoc_gen.rs +++ b/src/rustdoc_gen.rs @@ -229,7 +229,7 @@ pub(crate) enum CrateType<'a> { /// Configuration used to choose features to enable. /// Separate configs are used for baseline and current versions. -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, PartialEq, Eq)] pub(crate) struct FeatureConfig { /// Feature set chosen as the foundation. pub(crate) features_group: FeaturesGroup, @@ -238,7 +238,7 @@ pub(crate) struct FeatureConfig { pub(crate) is_baseline: bool, } -#[derive(Debug, Clone, Serialize)] +#[derive(Debug, Clone, Serialize, PartialEq, Eq)] pub(crate) enum FeaturesGroup { All, Default,