asserting/
number.rs

1//! Implementations of assertions specific for numbers.
2
3use crate::assertions::{
4    AssertDecimalNumber, AssertInfinity, AssertNotANumber, AssertNumericIdentity, AssertSignum,
5};
6use crate::colored::{mark_missing, mark_missing_string, mark_unexpected};
7use crate::expectations::{
8    has_precision_of, has_scale_of, is_a_number, is_finite, is_infinite, is_integer, is_negative,
9    is_one, is_positive, is_zero, not, HasPrecisionOf, HasScaleOf, IsANumber, IsFinite, IsInfinite,
10    IsInteger, IsNegative, IsOne, IsPositive, IsZero,
11};
12use crate::properties::{
13    AdditiveIdentityProperty, DecimalProperties, InfinityProperty, IsNanProperty,
14    MultiplicativeIdentityProperty, SignumProperty,
15};
16use crate::spec::{DiffFormat, Expectation, Expression, FailingStrategy, Invertible, Spec};
17use crate::std::fmt::Debug;
18use crate::std::format;
19use crate::std::string::String;
20
21impl<S, R> AssertSignum for Spec<'_, S, R>
22where
23    S: SignumProperty + Debug,
24    R: FailingStrategy,
25{
26    fn is_negative(self) -> Self {
27        self.expecting(is_negative())
28    }
29
30    fn is_not_negative(self) -> Self {
31        self.expecting(not(is_negative()))
32    }
33
34    fn is_positive(self) -> Self {
35        self.expecting(is_positive())
36    }
37
38    fn is_not_positive(self) -> Self {
39        self.expecting(not(is_positive()))
40    }
41}
42
43impl<S> Expectation<S> for IsNegative
44where
45    S: SignumProperty + Debug,
46{
47    fn test(&mut self, subject: &S) -> bool {
48        subject.is_negative_property()
49    }
50
51    fn message(
52        &self,
53        expression: &Expression<'_>,
54        actual: &S,
55        inverted: bool,
56        format: &DiffFormat,
57    ) -> String {
58        let (not, expected) = if inverted {
59            ("not ", ">= 0")
60        } else {
61            ("", "< 0")
62        };
63        let marked_actual = mark_unexpected(actual, format);
64        let marked_expected = mark_missing_string(expected, format);
65        format!("expected {expression} to be {not}negative\n   but was: {marked_actual}\n  expected: {marked_expected}")
66    }
67}
68
69impl Invertible for IsNegative {}
70
71impl<S> Expectation<S> for IsPositive
72where
73    S: SignumProperty + Debug,
74{
75    fn test(&mut self, subject: &S) -> bool {
76        subject.is_positive_property()
77    }
78
79    fn message(
80        &self,
81        expression: &Expression<'_>,
82        actual: &S,
83        inverted: bool,
84        format: &DiffFormat,
85    ) -> String {
86        let (not, expected) = if inverted {
87            ("not ", "<= 0")
88        } else {
89            ("", "> 0")
90        };
91        let marked_actual = mark_unexpected(actual, format);
92        let marked_expected = mark_missing_string(expected, format);
93        format!("expected {expression} to be {not}positive\n   but was: {marked_actual}\n  expected: {marked_expected}")
94    }
95}
96
97impl Invertible for IsPositive {}
98
99impl<S, R> AssertNumericIdentity for Spec<'_, S, R>
100where
101    S: AdditiveIdentityProperty + MultiplicativeIdentityProperty + PartialEq + Debug,
102    R: FailingStrategy,
103{
104    fn is_zero(self) -> Self {
105        self.expecting(is_zero())
106    }
107
108    fn is_one(self) -> Self {
109        self.expecting(is_one())
110    }
111}
112
113impl<S> Expectation<S> for IsZero
114where
115    S: AdditiveIdentityProperty + PartialEq + Debug,
116{
117    fn test(&mut self, subject: &S) -> bool {
118        *subject == <S as AdditiveIdentityProperty>::additive_identity()
119    }
120
121    fn message(
122        &self,
123        expression: &Expression<'_>,
124        actual: &S,
125        inverted: bool,
126        format: &DiffFormat,
127    ) -> String {
128        let not = if inverted { "not " } else { "" };
129        let marked_actual = mark_unexpected(&actual, format);
130        let marked_expected = mark_missing(&S::additive_identity(), format);
131        format!("expected {expression} to be {not}zero\n   but was: {marked_actual}\n  expected: {not}{marked_expected}")
132    }
133}
134
135impl Invertible for IsZero {}
136
137impl<S> Expectation<S> for IsOne
138where
139    S: MultiplicativeIdentityProperty + PartialEq + Debug,
140{
141    fn test(&mut self, subject: &S) -> bool {
142        *subject == <S as MultiplicativeIdentityProperty>::multiplicative_identity()
143    }
144
145    fn message(
146        &self,
147        expression: &Expression<'_>,
148        actual: &S,
149        inverted: bool,
150        format: &DiffFormat,
151    ) -> String {
152        let not = if inverted { "not " } else { "" };
153        let marked_actual = mark_unexpected(actual, format);
154        let marked_expected = mark_missing(&S::multiplicative_identity(), format);
155        format!("expected {expression} to be {not}one\n   but was: {marked_actual}\n  expected: {not}{marked_expected}")
156    }
157}
158
159impl Invertible for IsOne {}
160
161impl<S, R> AssertInfinity for Spec<'_, S, R>
162where
163    S: InfinityProperty + Debug,
164    R: FailingStrategy,
165{
166    fn is_infinite(self) -> Self {
167        self.expecting(is_infinite())
168    }
169
170    fn is_finite(self) -> Self {
171        self.expecting(is_finite())
172    }
173}
174
175impl<S> Expectation<S> for IsFinite
176where
177    S: InfinityProperty + Debug,
178{
179    fn test(&mut self, subject: &S) -> bool {
180        subject.is_finite_property()
181    }
182
183    fn message(
184        &self,
185        expression: &Expression<'_>,
186        actual: &S,
187        inverted: bool,
188        format: &DiffFormat,
189    ) -> String {
190        let (not, expected) = if inverted {
191            ("not ", "a non-finite number")
192        } else {
193            ("", "a finite number")
194        };
195        let marked_actual = mark_unexpected(actual, format);
196        let marked_expected = mark_missing_string(expected, format);
197        format!("expected {expression} to be {not}finite\n   but was: {marked_actual}\n  expected: {marked_expected}")
198    }
199}
200
201impl Invertible for IsFinite {}
202
203impl<S> Expectation<S> for IsInfinite
204where
205    S: InfinityProperty + Debug,
206{
207    fn test(&mut self, subject: &S) -> bool {
208        subject.is_infinite_property()
209    }
210
211    fn message(
212        &self,
213        expression: &Expression<'_>,
214        actual: &S,
215        inverted: bool,
216        format: &DiffFormat,
217    ) -> String {
218        let (not, expected) = if inverted {
219            ("not ", "a non-infinite number")
220        } else {
221            ("", "an infinite number")
222        };
223        let marked_actual = mark_unexpected(actual, format);
224        let marked_expected = mark_missing_string(expected, format);
225        format!("expected {expression} to be {not}infinite\n   but was: {marked_actual}\n  expected: {marked_expected}")
226    }
227}
228
229impl Invertible for IsInfinite {}
230
231impl<S, R> AssertNotANumber for Spec<'_, S, R>
232where
233    S: IsNanProperty + Debug,
234    R: FailingStrategy,
235{
236    fn is_not_a_number(self) -> Self {
237        self.expecting(not(is_a_number()))
238    }
239
240    fn is_a_number(self) -> Self {
241        self.expecting(is_a_number())
242    }
243}
244
245impl<S> Expectation<S> for IsANumber
246where
247    S: IsNanProperty + Debug,
248{
249    fn test(&mut self, subject: &S) -> bool {
250        !subject.is_nan_property()
251    }
252
253    fn message(
254        &self,
255        expression: &Expression<'_>,
256        actual: &S,
257        inverted: bool,
258        format: &DiffFormat,
259    ) -> String {
260        let (not, expected) = if inverted {
261            ("not ", "NaN")
262        } else {
263            ("", "a number")
264        };
265        let marked_actual = mark_unexpected(actual, format);
266        let marked_expected = mark_missing_string(expected, format);
267        format!("expected {expression} to be {not}a number\n   but was: {marked_actual}\n  expected: {marked_expected}")
268    }
269}
270
271impl Invertible for IsANumber {}
272
273impl<S, R> AssertDecimalNumber for Spec<'_, S, R>
274where
275    S: DecimalProperties + Debug,
276    R: FailingStrategy,
277{
278    fn has_scale_of(self, expected_scale: i64) -> Self {
279        self.expecting(has_scale_of(expected_scale))
280    }
281
282    fn has_precision_of(self, expected_precision: u64) -> Self {
283        self.expecting(has_precision_of(expected_precision))
284    }
285
286    fn is_integer(self) -> Self {
287        self.expecting(is_integer())
288    }
289}
290
291impl<S> Expectation<S> for HasScaleOf
292where
293    S: DecimalProperties + Debug,
294{
295    fn test(&mut self, subject: &S) -> bool {
296        subject.scale_property() == self.expected_scale
297    }
298
299    fn message(
300        &self,
301        expression: &Expression<'_>,
302        actual: &S,
303        inverted: bool,
304        format: &DiffFormat,
305    ) -> String {
306        let not = if inverted { "not " } else { "" };
307        let expected_scale = self.expected_scale;
308        let marked_actual = mark_unexpected(&actual.scale_property(), format);
309        let marked_expected = mark_missing(&expected_scale, format);
310        format!("expected {expression} to {not}have a scale of {expected_scale}\n   but was: {marked_actual}\n  expected: {not}{marked_expected}")
311    }
312}
313
314impl Invertible for HasScaleOf {}
315
316impl<S> Expectation<S> for HasPrecisionOf
317where
318    S: DecimalProperties + Debug,
319{
320    fn test(&mut self, subject: &S) -> bool {
321        subject.precision_property() == self.expected_precision
322    }
323
324    fn message(
325        &self,
326        expression: &Expression<'_>,
327        actual: &S,
328        inverted: bool,
329        format: &DiffFormat,
330    ) -> String {
331        let not = if inverted { "not " } else { "" };
332        let expected_precision = self.expected_precision;
333        let marked_actual = mark_unexpected(&actual.precision_property(), format);
334        let marked_expected = mark_missing(&expected_precision, format);
335        format!("expected {expression} to {not}have a precision of {expected_precision}\n   but was: {marked_actual}\n  expected: {not}{marked_expected}")
336    }
337}
338
339impl<S> Expectation<S> for IsInteger
340where
341    S: DecimalProperties + Debug,
342{
343    fn test(&mut self, subject: &S) -> bool {
344        subject.is_integer_property()
345    }
346
347    fn message(
348        &self,
349        expression: &Expression<'_>,
350        actual: &S,
351        inverted: bool,
352        format: &DiffFormat,
353    ) -> String {
354        let (not, expected) = if inverted {
355            ("not ", "a decimal value with non-zero fraction")
356        } else {
357            ("", "an integer value")
358        };
359        let marked_actual = mark_unexpected(&actual, format);
360        let marked_expected = mark_missing_string(expected, format);
361        format!("expected {expression} to be {not}an integer value\n   but was: {marked_actual}\n  expected: {marked_expected}")
362    }
363}