1mod float_samplers;
16
17use crate::test_runner::TestRunner;
18use rand::distr::uniform::{SampleUniform, Uniform};
19use rand::distr::{Distribution, StandardUniform};
20
21pub(crate) fn sample_uniform<X: SampleUniform>(
24 run: &mut TestRunner,
25 start: X,
26 end: X,
27) -> X {
28 Uniform::new(start, end).expect("not uniform").sample(run.rng())
29}
30
31pub fn sample_uniform_incl<X: SampleUniform>(
34 run: &mut TestRunner,
35 start: X,
36 end: X,
37) -> X {
38 Uniform::new_inclusive(start, end).expect("not uniform").sample(run.rng())
39}
40
41macro_rules! sample_uniform {
42 ($name: ident, $incl:ident, $from:ty, $to:ty) => {
43 fn $name<X>(
44 run: &mut TestRunner,
45 start: $to,
46 end: $to,
47 ) -> $to {
48 Uniform::<$from>::new(start as $from, end as $from).expect("not uniform").sample(run.rng()) as $to
49 }
50
51 fn $incl<X>(
52 run: &mut TestRunner,
53 start: $to,
54 end: $to,
55 ) -> $to {
56 Uniform::<$from>::new_inclusive(start as $from, end as $from).expect("not uniform").sample(run.rng()) as $to
57 }
58 }
59}
60
61#[cfg(target_pointer_width = "64")]
62sample_uniform!(usize_sample_uniform, usize_sample_uniform_incl, u64, usize);
63#[cfg(target_pointer_width = "32")]
64sample_uniform!(usize_sample_uniform, usize_sample_uniform_incl, u32, usize);
65#[cfg(target_pointer_width = "16")]
66sample_uniform!(usize_sample_uniform, usize_sample_uniform_incl, u16, usize);
67
68#[cfg(target_pointer_width = "64")]
69sample_uniform!(isize_sample_uniform, isize_sample_uniform_incl, i64, isize);
70#[cfg(target_pointer_width = "32")]
71sample_uniform!(isize_sample_uniform, isize_sample_uniform_incl, i32, isize);
72#[cfg(target_pointer_width = "16")]
73sample_uniform!(isize_sample_uniform, isize_sample_uniform_incl, i16, isize);
74
75macro_rules! supported_int_any {
76 ($runner:ident, $typ:ty) => {
77 $runner.rng().random()
78 };
79}
80
81#[cfg(target_pointer_width = "64")]
82macro_rules! unsupported_int_any {
83 ($runner:ident, $typ:ty) => {
84 $runner.rng().next_u64() as $typ
85 };
86}
87
88#[cfg(not(target_pointer_width = "64"))]
89macro_rules! unsupported_int_any {
90 ($runner:ident, $typ:ty) => {
91 $runner.rng().next_u32() as $typ
92 };
93}
94
95macro_rules! int_any {
96 ($typ: ident, $int_any: ident) => {
97 #[derive(Clone, Copy, Debug)]
99 #[must_use = "strategies do nothing unless used"]
100 pub struct Any(());
101 pub const ANY: Any = Any(());
104
105 impl Strategy for Any {
106 type Tree = BinarySearch;
107 type Value = $typ;
108
109 fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
110 Ok(BinarySearch::new($int_any!(runner, $typ)))
111 }
112 }
113 };
114}
115
116macro_rules! numeric_api {
117 ($typ:ident, $epsilon:expr) => {
118 numeric_api!($typ, $typ, $epsilon);
119 };
120 ($typ:ident, $sample_typ:ty, $epsilon:expr) => {
121 numeric_api!($typ, $sample_typ, $epsilon, sample_uniform, sample_uniform_incl);
122 };
123 ($typ:ident, $epsilon:expr, $uniform:ident, $incl:ident) => {
124 numeric_api!($typ, $typ, $epsilon, $uniform, $incl);
125 };
126 ($typ:ident, $sample_typ:ty, $epsilon:expr, $uniform:ident, $incl:ident) => {
127 impl Strategy for ::core::ops::Range<$typ> {
128 type Tree = BinarySearch;
129 type Value = $typ;
130
131 fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
132 if self.is_empty() {
133 panic!(
134 "Invalid use of empty range {}..{}.",
135 self.start, self.end
136 );
137 }
138
139 Ok(BinarySearch::new_clamped(
140 self.start,
141 $crate::num::$uniform::<$sample_typ>(
142 runner,
143 self.start.into(),
144 self.end.into(),
145 )
146 .into(),
147 self.end - $epsilon,
148 ))
149 }
150 }
151
152 impl Strategy for ::core::ops::RangeInclusive<$typ> {
153 type Tree = BinarySearch;
154 type Value = $typ;
155
156 fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
157 if self.is_empty() {
158 panic!(
159 "Invalid use of empty range {}..={}.",
160 self.start(),
161 self.end()
162 );
163 }
164
165 Ok(BinarySearch::new_clamped(
166 *self.start(),
167 $crate::num::$incl::<$sample_typ>(
168 runner,
169 (*self.start()).into(),
170 (*self.end()).into(),
171 )
172 .into(),
173 *self.end(),
174 ))
175 }
176 }
177
178 impl Strategy for ::core::ops::RangeFrom<$typ> {
179 type Tree = BinarySearch;
180 type Value = $typ;
181
182 fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
183 Ok(BinarySearch::new_clamped(
184 self.start,
185 $crate::num::$incl::<$sample_typ>(
186 runner,
187 self.start.into(),
188 <$typ>::MAX.into(),
189 )
190 .into(),
191 <$typ>::MAX,
192 ))
193 }
194 }
195
196 impl Strategy for ::core::ops::RangeTo<$typ> {
197 type Tree = BinarySearch;
198 type Value = $typ;
199
200 fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
201 Ok(BinarySearch::new_clamped(
202 <$typ>::MIN,
203 $crate::num::$uniform::<$sample_typ>(
204 runner,
205 <$typ>::MIN.into(),
206 self.end.into(),
207 )
208 .into(),
209 self.end,
210 ))
211 }
212 }
213
214 impl Strategy for ::core::ops::RangeToInclusive<$typ> {
215 type Tree = BinarySearch;
216 type Value = $typ;
217
218 fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
219 Ok(BinarySearch::new_clamped(
220 <$typ>::MIN,
221 $crate::num::$incl::<$sample_typ>(
222 runner,
223 <$typ>::MIN.into(),
224 self.end.into(),
225 )
226 .into(),
227 self.end,
228 ))
229 }
230 }
231 };
232}
233
234macro_rules! signed_integer_bin_search {
235 ($typ:ident) => {
236 signed_integer_bin_search!($typ, supported_int_any, sample_uniform, sample_uniform_incl);
237 };
238 ($typ:ident, $int_any: ident, $uniform: ident, $incl: ident) => {
239 #[allow(missing_docs)]
240 pub mod $typ {
241 #[allow(unused_imports)]
242 use rand::{Rng, RngCore};
243
244 use crate::strategy::*;
245 use crate::test_runner::TestRunner;
246
247 int_any!($typ, $int_any);
248
249 #[derive(Clone, Copy, Debug)]
252 pub struct BinarySearch {
253 lo: $typ,
254 curr: $typ,
255 hi: $typ,
256 }
257 impl BinarySearch {
258 pub fn new(start: $typ) -> Self {
260 BinarySearch {
261 lo: 0,
262 curr: start,
263 hi: start,
264 }
265 }
266
267 fn new_clamped(lo: $typ, start: $typ, hi: $typ) -> Self {
271 use core::cmp::{max, min};
272
273 BinarySearch {
274 lo: if start < 0 {
275 min(0, hi - 1)
276 } else {
277 max(0, lo)
278 },
279 hi: start,
280 curr: start,
281 }
282 }
283
284 fn reposition(&mut self) -> bool {
285 let interval = self.hi - self.lo;
288 let new_mid = self.lo + interval / 2;
289
290 if new_mid == self.curr {
291 false
292 } else {
293 self.curr = new_mid;
294 true
295 }
296 }
297
298 fn magnitude_greater(lhs: $typ, rhs: $typ) -> bool {
299 if 0 == lhs {
300 false
301 } else if lhs < 0 {
302 lhs < rhs
303 } else {
304 lhs > rhs
305 }
306 }
307 }
308 impl ValueTree for BinarySearch {
309 type Value = $typ;
310
311 fn current(&self) -> $typ {
312 self.curr
313 }
314
315 fn simplify(&mut self) -> bool {
316 if !BinarySearch::magnitude_greater(self.hi, self.lo) {
317 return false;
318 }
319
320 self.hi = self.curr;
321 self.reposition()
322 }
323
324 fn complicate(&mut self) -> bool {
325 if !BinarySearch::magnitude_greater(self.hi, self.lo) {
326 return false;
327 }
328
329 self.lo = self.curr + if self.hi < 0 { -1 } else { 1 };
330
331 self.reposition()
332 }
333 }
334
335 numeric_api!($typ, 1, $uniform, $incl);
336 }
337 };
338}
339
340macro_rules! unsigned_integer_bin_search {
341 ($typ:ident) => {
342 unsigned_integer_bin_search!($typ, supported_int_any, sample_uniform, sample_uniform_incl);
343 };
344 ($typ:ident, $int_any: ident, $uniform: ident, $incl: ident) => {
345 #[allow(missing_docs)]
346 pub mod $typ {
347 #[allow(unused_imports)]
348 use rand::{Rng, RngCore};
349
350 use crate::strategy::*;
351 use crate::test_runner::TestRunner;
352
353 int_any!($typ, $int_any);
354
355 #[derive(Clone, Copy, Debug)]
358 pub struct BinarySearch {
359 lo: $typ,
360 curr: $typ,
361 hi: $typ,
362 }
363 impl BinarySearch {
364 pub fn new(start: $typ) -> Self {
366 BinarySearch {
367 lo: 0,
368 curr: start,
369 hi: start,
370 }
371 }
372
373 fn new_clamped(lo: $typ, start: $typ, _hi: $typ) -> Self {
376 BinarySearch {
377 lo: lo,
378 curr: start,
379 hi: start,
380 }
381 }
382
383 pub fn new_above(lo: $typ, start: $typ) -> Self {
386 BinarySearch::new_clamped(lo, start, start)
387 }
388
389 fn reposition(&mut self) -> bool {
390 let interval = self.hi - self.lo;
391 let new_mid = self.lo + interval / 2;
392
393 if new_mid == self.curr {
394 false
395 } else {
396 self.curr = new_mid;
397 true
398 }
399 }
400 }
401 impl ValueTree for BinarySearch {
402 type Value = $typ;
403
404 fn current(&self) -> $typ {
405 self.curr
406 }
407
408 fn simplify(&mut self) -> bool {
409 if self.hi <= self.lo {
410 return false;
411 }
412
413 self.hi = self.curr;
414 self.reposition()
415 }
416
417 fn complicate(&mut self) -> bool {
418 if self.hi <= self.lo {
419 return false;
420 }
421
422 self.lo = self.curr + 1;
423 self.reposition()
424 }
425 }
426
427 numeric_api!($typ, 1, $uniform, $incl);
428 }
429 };
430}
431
432signed_integer_bin_search!(i8);
433signed_integer_bin_search!(i16);
434signed_integer_bin_search!(i32);
435signed_integer_bin_search!(i64);
436signed_integer_bin_search!(i128);
437signed_integer_bin_search!(isize, unsupported_int_any, isize_sample_uniform, isize_sample_uniform_incl);
438unsigned_integer_bin_search!(u8);
439unsigned_integer_bin_search!(u16);
440unsigned_integer_bin_search!(u32);
441unsigned_integer_bin_search!(u64);
442unsigned_integer_bin_search!(u128);
443unsigned_integer_bin_search!(usize, unsupported_int_any, usize_sample_uniform, usize_sample_uniform_incl);
444
445bitflags! {
446 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
447 pub(crate) struct FloatTypes: u32 {
448 const POSITIVE = 0b0000_0001;
449 const NEGATIVE = 0b0000_0010;
450 const NORMAL = 0b0000_0100;
451 const SUBNORMAL = 0b0000_1000;
452 const ZERO = 0b0001_0000;
453 const INFINITE = 0b0010_0000;
454 const QUIET_NAN = 0b0100_0000;
455 const SIGNALING_NAN = 0b1000_0000;
456 const ANY =
457 Self::POSITIVE.bits() |
458 Self::NEGATIVE.bits() |
459 Self::NORMAL.bits() |
460 Self::SUBNORMAL.bits() |
461 Self::ZERO.bits() |
462 Self::INFINITE.bits() |
463 Self::QUIET_NAN.bits();
464 }
465}
466
467impl FloatTypes {
468 fn normalise(mut self) -> Self {
469 if !self.intersects(FloatTypes::POSITIVE | FloatTypes::NEGATIVE) {
470 self |= FloatTypes::POSITIVE;
471 }
472
473 if !self.intersects(
474 FloatTypes::NORMAL
475 | FloatTypes::SUBNORMAL
476 | FloatTypes::ZERO
477 | FloatTypes::INFINITE
478 | FloatTypes::QUIET_NAN
479 | FloatTypes::SIGNALING_NAN,
480 ) {
481 self |= FloatTypes::NORMAL;
482 }
483 self
484 }
485}
486
487trait FloatLayout
488where
489 StandardUniform: Distribution<Self::Bits>,
490{
491 type Bits: Copy;
492
493 const SIGN_MASK: Self::Bits;
494 const EXP_MASK: Self::Bits;
495 const EXP_ZERO: Self::Bits;
496 const MANTISSA_MASK: Self::Bits;
497}
498
499#[cfg(feature = "f16")]
500impl FloatLayout for f16 {
501 type Bits = u16;
502
503 const SIGN_MASK: u16 = 0x8000;
504 const EXP_MASK: u16 = 0x7c00;
505 const EXP_ZERO: u16 = f16::to_bits(1.0);
506 const MANTISSA_MASK: u16 = !(Self::SIGN_MASK | Self::EXP_MASK);
507}
508
509impl FloatLayout for f32 {
510 type Bits = u32;
511
512 const SIGN_MASK: u32 = 0x8000_0000;
513 const EXP_MASK: u32 = 0x7F80_0000;
514 const EXP_ZERO: u32 = 0x3F80_0000;
515 const MANTISSA_MASK: u32 = 0x007F_FFFF;
516}
517
518impl FloatLayout for f64 {
519 type Bits = u64;
520
521 const SIGN_MASK: u64 = 0x8000_0000_0000_0000;
522 const EXP_MASK: u64 = 0x7FF0_0000_0000_0000;
523 const EXP_ZERO: u64 = 0x3FF0_0000_0000_0000;
524 const MANTISSA_MASK: u64 = 0x000F_FFFF_FFFF_FFFF;
525}
526
527macro_rules! float_any {
528 ($typ:ident) => {
529 #[derive(Clone, Copy, Debug)]
558 #[must_use = "strategies do nothing unless used"]
559 pub struct Any(FloatTypes);
560
561 #[cfg(test)]
562 impl Any {
563 pub(crate) fn from_bits(bits: u32) -> Self {
564 Any(FloatTypes::from_bits_truncate(bits))
565 }
566
567 pub(crate) fn normal_bits(&self) -> FloatTypes {
568 self.0.normalise()
569 }
570 }
571
572 impl ops::BitOr for Any {
573 type Output = Self;
574
575 fn bitor(self, rhs: Self) -> Self {
576 Any(self.0 | rhs.0)
577 }
578 }
579
580 impl ops::BitOrAssign for Any {
581 fn bitor_assign(&mut self, rhs: Self) {
582 self.0 |= rhs.0
583 }
584 }
585
586 pub const POSITIVE: Any = Any(FloatTypes::POSITIVE);
594 pub const NEGATIVE: Any = Any(FloatTypes::NEGATIVE);
602 pub const NORMAL: Any = Any(FloatTypes::NORMAL);
617 pub const SUBNORMAL: Any = Any(FloatTypes::SUBNORMAL);
629 pub const ZERO: Any = Any(FloatTypes::ZERO);
637 pub const INFINITE: Any = Any(FloatTypes::INFINITE);
642 pub const QUIET_NAN: Any = Any(FloatTypes::QUIET_NAN);
663 pub const SIGNALING_NAN: Any = Any(FloatTypes::SIGNALING_NAN);
683
684 pub const ANY: Any = Any(FloatTypes::ANY);
699
700 impl Strategy for Any {
701 type Tree = BinarySearch;
702 type Value = $typ;
703
704 fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
705 let flags = self.0.normalise();
706 let sign_mask = if flags.contains(FloatTypes::NEGATIVE) {
707 $typ::SIGN_MASK
708 } else {
709 0
710 };
711 let sign_or = if flags.contains(FloatTypes::POSITIVE) {
712 0
713 } else {
714 $typ::SIGN_MASK
715 };
716
717 macro_rules! weight {
718 ($case:ident, $weight:expr) => {
719 if flags.contains(FloatTypes::$case) {
720 $weight
721 } else {
722 0
723 }
724 }
725 }
726
727 let quiet_or = $typ::NAN.to_bits() &
732 ($typ::EXP_MASK | ($typ::EXP_MASK >> 1));
733 let signaling_or = (quiet_or ^ ($typ::EXP_MASK >> 1)) |
734 $typ::EXP_MASK;
735
736 let (class_mask, class_or, allow_edge_exp, allow_zero_mant) =
737 prop_oneof![
738 weight!(NORMAL, 20) => Just(
739 ($typ::EXP_MASK | $typ::MANTISSA_MASK, 0,
740 false, true)),
741 weight!(SUBNORMAL, 3) => Just(
742 ($typ::MANTISSA_MASK, 0, true, false)),
743 weight!(ZERO, 4) => Just(
744 (0, 0, true, true)),
745 weight!(INFINITE, 2) => Just(
746 (0, $typ::EXP_MASK, true, true)),
747 weight!(QUIET_NAN, 1) => Just(
748 ($typ::MANTISSA_MASK >> 1, quiet_or,
749 true, false)),
750 weight!(SIGNALING_NAN, 1) => Just(
751 ($typ::MANTISSA_MASK >> 1, signaling_or,
752 true, false)),
753 ].new_tree(runner)?.current();
754
755 let mut generated_value: <$typ as FloatLayout>::Bits =
756 runner.rng().random();
757 generated_value &= sign_mask | class_mask;
758 generated_value |= sign_or | class_or;
759 let exp = generated_value & $typ::EXP_MASK;
760 if !allow_edge_exp && (0 == exp || $typ::EXP_MASK == exp) {
761 generated_value &= !$typ::EXP_MASK;
762 generated_value |= $typ::EXP_ZERO;
763 }
764 if !allow_zero_mant &&
765 0 == generated_value & $typ::MANTISSA_MASK
766 {
767 generated_value |= 1;
768 }
769
770 Ok(BinarySearch::new_with_types(
771 $typ::from_bits(generated_value), flags))
772 }
773 }
774 }
775}
776
777macro_rules! float_bin_search {
778 ($typ:ident, $sample_typ:ident) => {
779 #[allow(missing_docs)]
780 pub mod $typ {
781 use super::float_samplers::$sample_typ;
782
783 use core::ops;
784 #[cfg(not(feature = "std"))]
785 use num_traits::float::FloatCore;
786
787 use rand::Rng;
788
789 use super::{FloatLayout, FloatTypes};
790 use crate::strategy::*;
791 use crate::test_runner::TestRunner;
792
793 float_any!($typ);
794
795 #[derive(Clone, Copy, Debug)]
800 pub struct BinarySearch {
801 lo: $typ,
802 curr: $typ,
803 hi: $typ,
804 allowed: FloatTypes,
805 }
806
807 impl BinarySearch {
808 pub fn new(start: $typ) -> Self {
810 BinarySearch {
811 lo: 0.0,
812 curr: start,
813 hi: start,
814 allowed: FloatTypes::all(),
815 }
816 }
817
818 fn new_with_types(start: $typ, allowed: FloatTypes) -> Self {
819 BinarySearch {
820 lo: 0.0,
821 curr: start,
822 hi: start,
823 allowed,
824 }
825 }
826
827 fn new_clamped(lo: $typ, start: $typ, hi: $typ) -> Self {
831 BinarySearch {
832 lo: if start.is_sign_negative() {
833 hi.min(0.0)
834 } else {
835 lo.max(0.0)
836 },
837 hi: start,
838 curr: start,
839 allowed: FloatTypes::all(),
840 }
841 }
842
843 fn current_allowed(&self) -> bool {
844 use core::num::FpCategory::*;
845
846 let class_allowed = match self.curr.classify() {
848 Nan =>
849 {
854 self.allowed.contains(FloatTypes::QUIET_NAN)
855 || self
856 .allowed
857 .contains(FloatTypes::SIGNALING_NAN)
858 }
859 Infinite => self.allowed.contains(FloatTypes::INFINITE),
860 Zero => self.allowed.contains(FloatTypes::ZERO),
861 Subnormal => {
862 self.allowed.contains(FloatTypes::SUBNORMAL)
863 }
864 Normal => self.allowed.contains(FloatTypes::NORMAL),
865 };
866 let signum = self.curr.signum();
867 let sign_allowed = if signum > 0.0 {
868 self.allowed.contains(FloatTypes::POSITIVE)
869 } else if signum < 0.0 {
870 self.allowed.contains(FloatTypes::NEGATIVE)
871 } else {
872 true
873 };
874
875 class_allowed && sign_allowed
876 }
877
878 fn ensure_acceptable(&mut self) {
879 while !self.current_allowed() {
880 if !self.complicate_once() {
881 panic!(
882 "Unable to complicate floating-point back \
883 to acceptable value"
884 );
885 }
886 }
887 }
888
889 fn reposition(&mut self) -> bool {
890 let interval = self.hi - self.lo;
891 let interval =
892 if interval.is_finite() { interval } else { 0.0 };
893 let new_mid = self.lo + interval / 2.0;
894
895 let new_mid = if new_mid == self.curr || 0.0 == interval {
896 new_mid
897 } else {
898 self.lo
899 };
900
901 if new_mid == self.curr {
902 false
903 } else {
904 self.curr = new_mid;
905 true
906 }
907 }
908
909 fn done(lo: $typ, hi: $typ) -> bool {
910 (lo.abs() > hi.abs() && !hi.is_nan()) || lo.is_nan()
911 }
912
913 fn complicate_once(&mut self) -> bool {
914 if BinarySearch::done(self.lo, self.hi) {
915 return false;
916 }
917
918 self.lo = if self.curr == self.lo {
919 self.hi
920 } else {
921 self.curr
922 };
923
924 self.reposition()
925 }
926 }
927 impl ValueTree for BinarySearch {
928 type Value = $typ;
929
930 fn current(&self) -> $typ {
931 self.curr
932 }
933
934 fn simplify(&mut self) -> bool {
935 if BinarySearch::done(self.lo, self.hi) {
936 return false;
937 }
938
939 self.hi = self.curr;
940 if self.reposition() {
941 self.ensure_acceptable();
942 true
943 } else {
944 false
945 }
946 }
947
948 fn complicate(&mut self) -> bool {
949 if self.complicate_once() {
950 self.ensure_acceptable();
951 true
952 } else {
953 false
954 }
955 }
956 }
957
958 numeric_api!($typ, $sample_typ, 0.0);
959 }
960 };
961}
962
963#[cfg(feature = "f16")]
964float_bin_search!(f16, F16U);
965float_bin_search!(f32, F32U);
966float_bin_search!(f64, F64U);
967
968#[cfg(test)]
969mod test {
970 use crate::strategy::*;
971 use crate::test_runner::*;
972
973 use super::*;
974
975 #[test]
976 fn u8_inclusive_end_included() {
977 let mut runner = TestRunner::deterministic();
978 let mut ok = 0;
979 for _ in 0..20 {
980 let tree = (0..=1).new_tree(&mut runner).unwrap();
981 let test = runner.run_one(tree, |v| {
982 prop_assert_eq!(v, 1);
983 Ok(())
984 });
985 if test.is_ok() {
986 ok += 1;
987 }
988 }
989 assert!(ok > 1, "inclusive end not included.");
990 }
991
992 #[test]
993 fn u8_inclusive_to_end_included() {
994 let mut runner = TestRunner::deterministic();
995 let mut ok = 0;
996 for _ in 0..20 {
997 let tree = (..=1u8).new_tree(&mut runner).unwrap();
998 let test = runner.run_one(tree, |v| {
999 prop_assert_eq!(v, 1);
1000 Ok(())
1001 });
1002 if test.is_ok() {
1003 ok += 1;
1004 }
1005 }
1006 assert!(ok > 1, "inclusive end not included.");
1007 }
1008
1009 #[test]
1010 fn i8_binary_search_always_converges() {
1011 fn assert_converges<P: Fn(i32) -> bool>(start: i8, pass: P) {
1012 let mut state = i8::BinarySearch::new(start);
1013 loop {
1014 if !pass(state.current() as i32) {
1015 if !state.simplify() {
1016 break;
1017 }
1018 } else {
1019 if !state.complicate() {
1020 break;
1021 }
1022 }
1023 }
1024
1025 assert!(!pass(state.current() as i32));
1026 assert!(
1027 pass(state.current() as i32 - 1)
1028 || pass(state.current() as i32 + 1)
1029 );
1030 }
1031
1032 for start in -128..0 {
1033 for target in start + 1..1 {
1034 assert_converges(start as i8, |v| v > target);
1035 }
1036 }
1037
1038 for start in 0..128 {
1039 for target in 0..start {
1040 assert_converges(start as i8, |v| v < target);
1041 }
1042 }
1043 }
1044
1045 #[test]
1046 fn u8_binary_search_always_converges() {
1047 fn assert_converges<P: Fn(u32) -> bool>(start: u8, pass: P) {
1048 let mut state = u8::BinarySearch::new(start);
1049 loop {
1050 if !pass(state.current() as u32) {
1051 if !state.simplify() {
1052 break;
1053 }
1054 } else {
1055 if !state.complicate() {
1056 break;
1057 }
1058 }
1059 }
1060
1061 assert!(!pass(state.current() as u32));
1062 assert!(pass(state.current() as u32 - 1));
1063 }
1064
1065 for start in 0..255 {
1066 for target in 0..start {
1067 assert_converges(start as u8, |v| v <= target);
1068 }
1069 }
1070 }
1071
1072 #[test]
1073 fn signed_integer_range_including_zero_converges_to_zero() {
1074 let mut runner = TestRunner::default();
1075 for _ in 0..100 {
1076 let mut state = (-42i32..64i32).new_tree(&mut runner).unwrap();
1077 let init_value = state.current();
1078 assert!(init_value >= -42 && init_value < 64);
1079
1080 while state.simplify() {
1081 let v = state.current();
1082 assert!(v >= -42 && v < 64);
1083 }
1084
1085 assert_eq!(0, state.current());
1086 }
1087 }
1088
1089 #[test]
1090 fn negative_integer_range_stays_in_bounds() {
1091 let mut runner = TestRunner::default();
1092 for _ in 0..100 {
1093 let mut state = (..-42i32).new_tree(&mut runner).unwrap();
1094 let init_value = state.current();
1095 assert!(init_value < -42);
1096
1097 while state.simplify() {
1098 assert!(
1099 state.current() < -42,
1100 "Violated bounds: {}",
1101 state.current()
1102 );
1103 }
1104
1105 assert_eq!(-43, state.current());
1106 }
1107 }
1108
1109 #[test]
1110 fn positive_signed_integer_range_stays_in_bounds() {
1111 let mut runner = TestRunner::default();
1112 for _ in 0..100 {
1113 let mut state = (42i32..).new_tree(&mut runner).unwrap();
1114 let init_value = state.current();
1115 assert!(init_value >= 42);
1116
1117 while state.simplify() {
1118 assert!(
1119 state.current() >= 42,
1120 "Violated bounds: {}",
1121 state.current()
1122 );
1123 }
1124
1125 assert_eq!(42, state.current());
1126 }
1127 }
1128
1129 #[test]
1130 fn unsigned_integer_range_stays_in_bounds() {
1131 let mut runner = TestRunner::default();
1132 for _ in 0..100 {
1133 let mut state = (42u32..56u32).new_tree(&mut runner).unwrap();
1134 let init_value = state.current();
1135 assert!(init_value >= 42 && init_value < 56);
1136
1137 while state.simplify() {
1138 assert!(
1139 state.current() >= 42,
1140 "Violated bounds: {}",
1141 state.current()
1142 );
1143 }
1144
1145 assert_eq!(42, state.current());
1146 }
1147 }
1148
1149 mod contract_sanity {
1150 macro_rules! contract_sanity {
1151 ($t:tt) => {
1152 mod $t {
1153 use crate::strategy::check_strategy_sanity;
1154
1155 const FORTY_TWO: $t = 42 as $t;
1156 const FIFTY_SIX: $t = 56 as $t;
1157
1158 #[test]
1159 fn range() {
1160 check_strategy_sanity(FORTY_TWO..FIFTY_SIX, None);
1161 }
1162
1163 #[test]
1164 fn range_inclusive() {
1165 check_strategy_sanity(FORTY_TWO..=FIFTY_SIX, None);
1166 }
1167
1168 #[test]
1169 fn range_to() {
1170 check_strategy_sanity(..FIFTY_SIX, None);
1171 }
1172
1173 #[test]
1174 fn range_to_inclusive() {
1175 check_strategy_sanity(..=FIFTY_SIX, None);
1176 }
1177
1178 #[test]
1179 fn range_from() {
1180 check_strategy_sanity(FORTY_TWO.., None);
1181 }
1182 }
1183 };
1184 }
1185 contract_sanity!(u8);
1186 contract_sanity!(i8);
1187 contract_sanity!(u16);
1188 contract_sanity!(i16);
1189 contract_sanity!(u32);
1190 contract_sanity!(i32);
1191 contract_sanity!(u64);
1192 contract_sanity!(i64);
1193 contract_sanity!(usize);
1194 contract_sanity!(isize);
1195 #[cfg(feature = "f16")]
1196 contract_sanity!(f16);
1197 contract_sanity!(f32);
1198 contract_sanity!(f64);
1199 }
1200
1201 #[test]
1202 fn unsigned_integer_binsearch_simplify_complicate_contract_upheld() {
1203 check_strategy_sanity(0u32..1000u32, None);
1204 check_strategy_sanity(0u32..1u32, None);
1205 }
1206
1207 #[test]
1208 fn signed_integer_binsearch_simplify_complicate_contract_upheld() {
1209 check_strategy_sanity(0i32..1000i32, None);
1210 check_strategy_sanity(0i32..1i32, None);
1211 }
1212
1213 #[test]
1214 fn positive_float_simplifies_to_zero() {
1215 let mut runner = TestRunner::default();
1216 let mut value = (0.0f64..2.0).new_tree(&mut runner).unwrap();
1217
1218 while value.simplify() {}
1219
1220 assert_eq!(0.0, value.current());
1221 }
1222
1223 #[test]
1224 fn positive_float_simplifies_to_base() {
1225 let mut runner = TestRunner::default();
1226 let mut value = (1.0f64..2.0).new_tree(&mut runner).unwrap();
1227
1228 while value.simplify() {}
1229
1230 assert_eq!(1.0, value.current());
1231 }
1232
1233 #[test]
1234 fn negative_float_simplifies_to_zero() {
1235 let mut runner = TestRunner::default();
1236 let mut value = (-2.0f64..0.0).new_tree(&mut runner).unwrap();
1237
1238 while value.simplify() {}
1239
1240 assert_eq!(0.0, value.current());
1241 }
1242
1243 #[test]
1244 fn positive_float_complicates_to_original() {
1245 let mut runner = TestRunner::default();
1246 let mut value = (1.0f64..2.0).new_tree(&mut runner).unwrap();
1247 let orig = value.current();
1248
1249 assert!(value.simplify());
1250 while value.complicate() {}
1251
1252 assert_eq!(orig, value.current());
1253 }
1254
1255 #[test]
1256 fn positive_infinity_simplifies_directly_to_zero() {
1257 let mut value = f64::BinarySearch::new(::std::f64::INFINITY);
1258
1259 assert!(value.simplify());
1260 assert_eq!(0.0, value.current());
1261 assert!(value.complicate());
1262 assert_eq!(::std::f64::INFINITY, value.current());
1263 assert!(!value.clone().complicate());
1264 assert!(!value.clone().simplify());
1265 }
1266
1267 #[test]
1268 fn negative_infinity_simplifies_directly_to_zero() {
1269 let mut value = f64::BinarySearch::new(::std::f64::NEG_INFINITY);
1270
1271 assert!(value.simplify());
1272 assert_eq!(0.0, value.current());
1273 assert!(value.complicate());
1274 assert_eq!(::std::f64::NEG_INFINITY, value.current());
1275 assert!(!value.clone().complicate());
1276 assert!(!value.clone().simplify());
1277 }
1278
1279 #[test]
1280 fn nan_simplifies_directly_to_zero() {
1281 let mut value = f64::BinarySearch::new(::std::f64::NAN);
1282
1283 assert!(value.simplify());
1284 assert_eq!(0.0, value.current());
1285 assert!(value.complicate());
1286 assert!(value.current().is_nan());
1287 assert!(!value.clone().complicate());
1288 assert!(!value.clone().simplify());
1289 }
1290
1291 #[test]
1292 fn float_simplifies_to_smallest_normal() {
1293 let mut runner = TestRunner::default();
1294 let mut value = (f64::MIN_POSITIVE..2.0)
1295 .new_tree(&mut runner)
1296 .unwrap();
1297
1298 while value.simplify() {}
1299
1300 assert_eq!(f64::MIN_POSITIVE, value.current());
1301 }
1302
1303 macro_rules! float_generation_test_body {
1304 ($strategy:ident, $typ:ident) => {
1305 use std::num::FpCategory;
1306
1307 let strategy = $strategy;
1308 let bits = strategy.normal_bits();
1309
1310 let mut seen_positive = 0;
1311 let mut seen_negative = 0;
1312 let mut seen_normal = 0;
1313 let mut seen_subnormal = 0;
1314 let mut seen_zero = 0;
1315 let mut seen_infinite = 0;
1316 let mut seen_quiet_nan = 0;
1317 let mut seen_signaling_nan = 0;
1318 let mut runner = TestRunner::deterministic();
1319
1320 let fidelity_1 = f32::from_bits(0x7F80_0001).to_bits();
1323 let fidelity_2 = f32::from_bits(0xFF80_0001).to_bits();
1324 let nan_fidelity = fidelity_1 != fidelity_2;
1325
1326 for _ in 0..1024 {
1327 let mut tree = strategy.new_tree(&mut runner).unwrap();
1328 let mut increment = 1;
1329
1330 loop {
1331 let value = tree.current();
1332
1333 let sign = value.signum(); if sign < 0.0 {
1335 prop_assert!(bits.contains(FloatTypes::NEGATIVE));
1336 seen_negative += increment;
1337 } else if sign > 0.0 {
1338 prop_assert!(bits.contains(FloatTypes::POSITIVE));
1340 seen_positive += increment;
1341 }
1342
1343 match value.classify() {
1344 FpCategory::Nan if nan_fidelity => {
1345 let raw = value.to_bits();
1346 let is_negative = raw << 1 >> 1 != raw;
1347 if is_negative {
1348 prop_assert!(
1349 bits.contains(FloatTypes::NEGATIVE)
1350 );
1351 seen_negative += increment;
1352 } else {
1353 prop_assert!(
1354 bits.contains(FloatTypes::POSITIVE)
1355 );
1356 seen_positive += increment;
1357 }
1358
1359 let is_quiet = raw & ($typ::EXP_MASK >> 1)
1360 == $typ::NAN.to_bits() & ($typ::EXP_MASK >> 1);
1361 if is_quiet {
1362 prop_assert!(
1367 bits.contains(FloatTypes::QUIET_NAN)
1368 || bits.contains(
1369 FloatTypes::SIGNALING_NAN
1370 )
1371 );
1372 seen_quiet_nan += increment;
1373 seen_signaling_nan += increment;
1374 } else {
1375 prop_assert!(
1376 bits.contains(FloatTypes::SIGNALING_NAN)
1377 );
1378 seen_signaling_nan += increment;
1379 }
1380 }
1381
1382 FpCategory::Nan => {
1383 seen_positive += increment;
1389 seen_negative += increment;
1390 seen_quiet_nan += increment;
1391 seen_signaling_nan += increment;
1392 prop_assert!(
1393 bits.contains(FloatTypes::QUIET_NAN)
1394 || bits.contains(FloatTypes::SIGNALING_NAN)
1395 );
1396 }
1397 FpCategory::Infinite => {
1398 prop_assert!(bits.contains(FloatTypes::INFINITE));
1399 seen_infinite += increment;
1400 }
1401 FpCategory::Zero => {
1402 prop_assert!(bits.contains(FloatTypes::ZERO));
1403 seen_zero += increment;
1404 }
1405 FpCategory::Subnormal => {
1406 prop_assert!(bits.contains(FloatTypes::SUBNORMAL));
1407 seen_subnormal += increment;
1408 }
1409 FpCategory::Normal => {
1410 prop_assert!(bits.contains(FloatTypes::NORMAL));
1411 seen_normal += increment;
1412 }
1413 }
1414
1415 increment = 0;
1417 if !tree.simplify() {
1418 break;
1419 }
1420 }
1421 }
1422
1423 if bits.contains(FloatTypes::POSITIVE) {
1424 prop_assert!(seen_positive > 200);
1425 }
1426 if bits.contains(FloatTypes::NEGATIVE) {
1427 prop_assert!(seen_negative > 200);
1428 }
1429 if bits.contains(FloatTypes::NORMAL) {
1430 prop_assert!(seen_normal > 100);
1431 }
1432 if bits.contains(FloatTypes::SUBNORMAL) {
1433 prop_assert!(seen_subnormal > 5);
1434 }
1435 if bits.contains(FloatTypes::ZERO) {
1436 prop_assert!(seen_zero > 5);
1437 }
1438 if bits.contains(FloatTypes::INFINITE) {
1439 prop_assert!(seen_infinite > 0);
1440 }
1441 if bits.contains(FloatTypes::QUIET_NAN) {
1442 prop_assert!(seen_quiet_nan > 0);
1443 }
1444 if bits.contains(FloatTypes::SIGNALING_NAN) {
1445 prop_assert!(seen_signaling_nan > 0);
1446 }
1447 };
1448 }
1449
1450 proptest! {
1451 #![proptest_config(crate::test_runner::Config::with_cases(1024))]
1452
1453 #[cfg(feature = "f16")]
1454 #[test]
1455 fn f16_any_generates_desired_values(
1456 strategy in crate::bits::u32::ANY.prop_map(f16::Any::from_bits)
1457 ) {
1458 float_generation_test_body!(strategy, f16);
1459 }
1460
1461 #[cfg(feature = "f16")]
1462 #[test]
1463 fn f16_any_sanity(
1464 strategy in crate::bits::u32::ANY.prop_map(f16::Any::from_bits)
1465 ) {
1466 check_strategy_sanity(strategy, Some(CheckStrategySanityOptions {
1467 strict_complicate_after_simplify: false,
1468 .. CheckStrategySanityOptions::default()
1469 }));
1470 }
1471
1472 #[test]
1473 fn f32_any_generates_desired_values(
1474 strategy in crate::bits::u32::ANY.prop_map(f32::Any::from_bits)
1475 ) {
1476 float_generation_test_body!(strategy, f32);
1477 }
1478
1479 #[test]
1480 fn f32_any_sanity(
1481 strategy in crate::bits::u32::ANY.prop_map(f32::Any::from_bits)
1482 ) {
1483 check_strategy_sanity(strategy, Some(CheckStrategySanityOptions {
1484 strict_complicate_after_simplify: false,
1485 .. CheckStrategySanityOptions::default()
1486 }));
1487 }
1488
1489 #[test]
1490 fn f64_any_generates_desired_values(
1491 strategy in crate::bits::u32::ANY.prop_map(f64::Any::from_bits)
1492 ) {
1493 float_generation_test_body!(strategy, f64);
1494 }
1495
1496 #[test]
1497 fn f64_any_sanity(
1498 strategy in crate::bits::u32::ANY.prop_map(f64::Any::from_bits)
1499 ) {
1500 check_strategy_sanity(strategy, Some(CheckStrategySanityOptions {
1501 strict_complicate_after_simplify: false,
1502 .. CheckStrategySanityOptions::default()
1503 }));
1504 }
1505 }
1506
1507 mod panic_on_empty {
1508 macro_rules! panic_on_empty {
1509 ($t:tt) => {
1510 mod $t {
1511 use crate::strategy::Strategy;
1512 use crate::test_runner::TestRunner;
1513 use std::panic;
1514 use std::string::String;
1515
1516 const ZERO: $t = 0 as $t;
1517 const ONE: $t = 1 as $t;
1518
1519 #[test]
1520 fn range() {
1521 assert_eq!(
1522 panic::catch_unwind(|| {
1523 let mut runner = TestRunner::deterministic();
1524 let _ = (ZERO..ZERO).new_tree(&mut runner);
1525 })
1526 .err()
1527 .and_then(|a| a
1528 .downcast_ref::<String>()
1529 .map(|s| {
1530 s == "Invalid use of empty range 0..0."
1531 })),
1532 Some(true)
1533 );
1534 }
1535
1536 #[test]
1537 fn range_inclusive() {
1538 assert_eq!(
1539 panic::catch_unwind(|| {
1540 let mut runner = TestRunner::deterministic();
1541 let _ = (ONE..=ZERO).new_tree(&mut runner);
1542 })
1543 .err()
1544 .and_then(|a| a
1545 .downcast_ref::<String>()
1546 .map(|s| {
1547 s == "Invalid use of empty range 1..=0."
1548 })),
1549 Some(true)
1550 );
1551 }
1552 }
1553 };
1554 }
1555 panic_on_empty!(u8);
1556 panic_on_empty!(i8);
1557 panic_on_empty!(u16);
1558 panic_on_empty!(i16);
1559 panic_on_empty!(u32);
1560 panic_on_empty!(i32);
1561 panic_on_empty!(u64);
1562 panic_on_empty!(i64);
1563 panic_on_empty!(usize);
1564 panic_on_empty!(isize);
1565 #[cfg(feature = "f16")]
1566 panic_on_empty!(f16);
1567 panic_on_empty!(f32);
1568 panic_on_empty!(f64);
1569 }
1570}