From 7820db2132c8647f878af684807d61231b1c75e4 Mon Sep 17 00:00:00 2001 From: haraldmaida Date: Sat, 7 Jun 2025 09:31:36 +0200 Subject: [PATCH 1/2] feat: number specific assertions for `rust_decimal::Decimal` --- .github/workflows/ci.yml | 2 +- Cargo.toml | 2 + examples/fixture/mod.rs | 2 + justfile | 4 +- src/lib.rs | 2 + src/num_bigint/mod.rs | 3 +- src/rust_decimal/mod.rs | 39 ++++++++++ src/rust_decimal/tests.rs | 154 ++++++++++++++++++++++++++++++++++++++ tests/version_numbers.rs | 2 + 9 files changed, 205 insertions(+), 5 deletions(-) create mode 100644 src/rust_decimal/mod.rs create mode 100644 src/rust_decimal/tests.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8ac22d7..e587cc3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -94,7 +94,7 @@ jobs: uses: actions-rs/cargo@v1 with: command: test - args: --no-default-features --features "colored, float-cmp, num-bigint" + args: --no-default-features --features "colored, float-cmp, num-bigint, rust-decimal" msrv: name: Build with MSRV diff --git a/Cargo.toml b/Cargo.toml index bb21e26..4f63753 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ default = ["std", "colored", "float-cmp", "panic", "regex"] colored = ["dep:sdiff"] float-cmp = ["dep:float-cmp"] num-bigint = ["dep:num-bigint", "dep:lazy_static"] +rust-decimal = ["dep:rust_decimal"] panic = ["std"] regex = ["dep:regex"] std = [] @@ -34,6 +35,7 @@ hashbrown = "0.15" float-cmp = { version = "0.10", optional = true } lazy_static = { version = "1", optional = true } num-bigint = { version = "0.4", default-features = false, optional = true } +rust_decimal = { version = "1", default-features = false, optional = true } regex = { version = "1", optional = true } sdiff = { version = "0.1", optional = true } diff --git a/examples/fixture/mod.rs b/examples/fixture/mod.rs index b860670..8229bfb 100644 --- a/examples/fixture/mod.rs +++ b/examples/fixture/mod.rs @@ -12,6 +12,8 @@ mod dummy_extern_uses { use proptest as _; #[cfg(feature = "regex")] use regex as _; + #[cfg(feature = "rust-decimal")] + use rust_decimal as _; #[cfg(feature = "colored")] use sdiff as _; use serial_test as _; diff --git a/justfile b/justfile index dbf1b95..b57c821 100644 --- a/justfile +++ b/justfile @@ -37,7 +37,7 @@ lint-all-features: # linting code using Clippy for no-std environment lint-no-std: - cargo clippy --all-targets --no-default-features --features "colored, float-cmp, num-bigint" + cargo clippy --all-targets --no-default-features --features "colored, float-cmp, num-bigint, rust-decimal" # linting code using Clippy with no features enabled lint-no-features: @@ -55,7 +55,7 @@ test-all-features: # run tests for no-std environment test-no-std: - cargo test --no-default-features --features "colored, float-cmp, num-bigint" + cargo test --no-default-features --features "colored, float-cmp, num-bigint, rust-decimal" # run tests with no features enabled test-no-features: diff --git a/src/lib.rs b/src/lib.rs index eb1934e..50bc9bb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -695,6 +695,8 @@ mod panic; mod predicate; mod range; mod result; +#[cfg(feature = "rust-decimal")] +mod rust_decimal; mod slice; mod string; mod vec; diff --git a/src/num_bigint/mod.rs b/src/num_bigint/mod.rs index 7c3936b..540fa98 100644 --- a/src/num_bigint/mod.rs +++ b/src/num_bigint/mod.rs @@ -1,5 +1,4 @@ -use crate::prelude::{AdditiveIdentityProperty, MultiplicativeIdentityProperty}; -use crate::properties::SignumProperty; +use crate::properties::{AdditiveIdentityProperty, MultiplicativeIdentityProperty, SignumProperty}; use crate::std::vec; use lazy_static::lazy_static; use num_bigint::{BigInt, BigUint, Sign}; diff --git a/src/rust_decimal/mod.rs b/src/rust_decimal/mod.rs new file mode 100644 index 0000000..36028f5 --- /dev/null +++ b/src/rust_decimal/mod.rs @@ -0,0 +1,39 @@ +use crate::properties::{AdditiveIdentityProperty, MultiplicativeIdentityProperty, SignumProperty}; +use rust_decimal::Decimal; + +impl SignumProperty for Decimal { + fn is_negative_property(&self) -> bool { + self.is_sign_negative() + } + + fn is_positive_property(&self) -> bool { + self.is_sign_positive() && !self.is_zero() + } +} + +impl AdditiveIdentityProperty for Decimal { + fn additive_identity() -> Self { + Self::ZERO + } +} + +impl AdditiveIdentityProperty for &Decimal { + fn additive_identity() -> Self { + &Decimal::ZERO + } +} + +impl MultiplicativeIdentityProperty for Decimal { + fn multiplicative_identity() -> Self { + Self::ONE + } +} + +impl MultiplicativeIdentityProperty for &Decimal { + fn multiplicative_identity() -> Self { + &Decimal::ONE + } +} + +#[cfg(test)] +mod tests; diff --git a/src/rust_decimal/tests.rs b/src/rust_decimal/tests.rs new file mode 100644 index 0000000..6be69cf --- /dev/null +++ b/src/rust_decimal/tests.rs @@ -0,0 +1,154 @@ +use crate::prelude::*; +use rust_decimal::Decimal; + +#[test] +fn decimal_is_equal_to_other() { + let subject = Decimal::new(42_831, 3); + + assert_that(subject).is_equal_to(Decimal::new(42_831, 3)); + + assert_that(Decimal::new(42_831, 3)).is_equal_to(Decimal::new(428_310, 4)); + assert_that(Decimal::new(0, 0)).is_equal_to(Decimal::new(0, 2)); + assert_that(Decimal::new(-0, 0)).is_equal_to(Decimal::new(0, 0)); +} + +#[test] +fn verify_decimal_is_equal_to_other_fails() { + let subject = Decimal::new(42_831, 3); + + let failures = verify_that(subject) + .is_equal_to(Decimal::new(-42_831, 3)) + .display_failures(); + + assert_eq!( + failures, + &[r"assertion failed: expected subject is equal to -42.831 + but was: 42.831 + expected: -42.831 +"] + ); +} + +#[test] +fn decimal_is_not_equal_to_other() { + let subject = Decimal::new(42_831, 3); + + assert_that(subject).is_not_equal_to(Decimal::new(42_831, 2)); +} + +#[test] +fn borrowed_decimal_is_equal_to_other() { + let subject = Decimal::new(-42_831, 3); + + assert_that(&subject).is_equal_to(&Decimal::new(-42_831, 3)); +} + +#[test] +fn decimal_is_less_than_other() { + let subject = Decimal::new(42_831, 3); + + assert_that(&subject).is_less_than(&Decimal::new(1_592_834, 3)); + assert_that(subject).is_less_than(Decimal::new(42_832, 3)); +} + +#[test] +fn decimal_is_greater_than_other() { + let subject = Decimal::new(42_831, 3); + + assert_that(&subject).is_greater_than(&Decimal::new(-232_199, 3)); + assert_that(subject).is_greater_than(Decimal::new(42_830, 3)); +} + +#[test] +fn decimal_is_at_least_other() { + let subject = Decimal::new(42_831, 3); + + assert_that(&subject).is_at_least(&Decimal::new(42_831, 3)); + assert_that(&subject).is_at_least(&Decimal::new(42_830, 3)); + assert_that(subject).is_at_least(Decimal::new(-332, 3)); +} + +#[test] +fn decimal_is_at_most_other() { + let subject = Decimal::new(42_831, 3); + + assert_that(&subject).is_at_most(&Decimal::new(42_831, 3)); + assert_that(&subject).is_at_most(&Decimal::new(42_832, 3)); + assert_that(subject).is_at_most(Decimal::new(65_587_929, 3)); +} + +#[test] +fn decimal_is_negative() { + let subject = Decimal::new(-42_831, 3); + + assert_that(&subject).is_negative(); +} + +#[test] +fn decimal_is_not_negative() { + assert_that(&Decimal::new(42_831, 3)).is_not_negative(); + assert_that(Decimal::new(0, 0)).is_not_negative(); +} + +#[test] +fn decimal_is_positive() { + let subject = Decimal::new(42_831, 3); + + assert_that(&subject).is_positive(); +} + +#[test] +fn decimal_is_not_positive() { + assert_that(&Decimal::new(-42_831, 3)).is_not_positive(); + assert_that(Decimal::new(0, 0)).is_not_positive(); +} + +#[test] +fn decimal_signum_of_zero() { + assert_that(Decimal::new(0, 0)).is_zero(); + assert_that(Decimal::new(0, 0).is_sign_positive()).is_true(); + assert_that(Decimal::new(0, 0).is_sign_negative()).is_false(); + assert_that(Decimal::new(-0, 0).is_sign_negative()).is_false(); +} + +#[test] +fn borrowed_decimal_is_negative() { + assert_that(&Decimal::new(-42_831, 3)).is_negative(); +} + +#[test] +fn borrowed_decimal_is_positive() { + assert_that(&Decimal::new(42_831, 3)).is_positive(); +} + +#[test] +fn mutable_borrowed_decimal_is_negative() { + assert_that(&mut Decimal::new(-42_831, 3)).is_negative(); +} + +#[test] +fn mutable_borrowed_decimal_is_positive() { + assert_that(&mut Decimal::new(42_831, 3)).is_positive(); +} + +#[test] +fn decimal_is_zero() { + assert_that(Decimal::new(0, 0)).is_zero(); + assert_that(Decimal::new(-0, 0)).is_zero(); + assert_that(Decimal::new(0, 2)).is_zero(); +} + +#[test] +fn decimal_is_one() { + assert_that(Decimal::new(1, 0)).is_one(); +} + +#[test] +fn borrowed_decimal_is_zero() { + assert_that(&Decimal::new(0, 0)).is_zero(); +} + +#[test] +fn borrowed_decimal_is_one() { + assert_that(&Decimal::new(1, 0)).is_one(); +} diff --git a/tests/version_numbers.rs b/tests/version_numbers.rs index af64141..46e42aa 100644 --- a/tests/version_numbers.rs +++ b/tests/version_numbers.rs @@ -16,6 +16,8 @@ mod dummy_extern_uses { use proptest as _; #[cfg(feature = "regex")] use regex as _; + #[cfg(feature = "rust-decimal")] + use rust_decimal as _; #[cfg(feature = "colored")] use sdiff as _; use serial_test as _; From cbd1d98b7b100396d5344e40fee14bbefe028c5b Mon Sep 17 00:00:00 2001 From: haraldmaida Date: Sat, 7 Jun 2025 09:35:15 +0200 Subject: [PATCH 2/2] add: add `rust_decimal::Decimal` to available assertions in README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 8fa4f23..cbfa6be 100644 --- a/README.md +++ b/README.md @@ -182,6 +182,7 @@ for numbers of types and `usize` * floating point numbers: `f32` and `f64` * `num_bigint::BigInt` and `num_bigint::BigUint` (requires crate feature `num-bigint`) +* `rust_decimal::Decimal` (requires crate feature `rust-decimal`) | assertion | description | |-----------|--------------------------------------------------------------|