1mod float_samplers;
16
17use crate::test_runner::TestRunner;
18use rand::distributions::uniform::{SampleUniform, Uniform};
19use rand::distributions::{Distribution, Standard};
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).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).sample(run.rng())
39}
40
41macro_rules! int_any {
42 ($typ: ident) => {
43 #[derive(Clone, Copy, Debug)]
45 #[must_use = "strategies do nothing unless used"]
46 pub struct Any(());
47 pub const ANY: Any = Any(());
50
51 impl Strategy for Any {
52 type Tree = BinarySearch;
53 type Value = $typ;
54
55 fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
56 Ok(BinarySearch::new(runner.rng().gen()))
57 }
58 }
59 };
60}
61
62macro_rules! numeric_api {
63 ($typ:ident, $epsilon:expr) => {
64 numeric_api!($typ, $typ, $epsilon);
65 };
66 ($typ:ident, $sample_typ:ty, $epsilon:expr) => {
67 impl Strategy for ::core::ops::Range<$typ> {
68 type Tree = BinarySearch;
69 type Value = $typ;
70
71 fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
72 if self.is_empty() {
73 panic!(
74 "Invalid use of empty range {}..{}.",
75 self.start, self.end
76 );
77 }
78
79 Ok(BinarySearch::new_clamped(
80 self.start,
81 $crate::num::sample_uniform::<$sample_typ>(
82 runner,
83 self.start.into(),
84 self.end.into(),
85 )
86 .into(),
87 self.end - $epsilon,
88 ))
89 }
90 }
91
92 impl Strategy for ::core::ops::RangeInclusive<$typ> {
93 type Tree = BinarySearch;
94 type Value = $typ;
95
96 fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
97 if self.is_empty() {
98 panic!(
99 "Invalid use of empty range {}..={}.",
100 self.start(),
101 self.end()
102 );
103 }
104
105 Ok(BinarySearch::new_clamped(
106 *self.start(),
107 $crate::num::sample_uniform_incl::<$sample_typ>(
108 runner,
109 (*self.start()).into(),
110 (*self.end()).into(),
111 )
112 .into(),
113 *self.end(),
114 ))
115 }
116 }
117
118 impl Strategy for ::core::ops::RangeFrom<$typ> {
119 type Tree = BinarySearch;
120 type Value = $typ;
121
122 fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
123 Ok(BinarySearch::new_clamped(
124 self.start,
125 $crate::num::sample_uniform_incl::<$sample_typ>(
126 runner,
127 self.start.into(),
128 ::core::$typ::MAX.into(),
129 )
130 .into(),
131 ::core::$typ::MAX,
132 ))
133 }
134 }
135
136 impl Strategy for ::core::ops::RangeTo<$typ> {
137 type Tree = BinarySearch;
138 type Value = $typ;
139
140 fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
141 Ok(BinarySearch::new_clamped(
142 ::core::$typ::MIN,
143 $crate::num::sample_uniform::<$sample_typ>(
144 runner,
145 ::core::$typ::MIN.into(),
146 self.end.into(),
147 )
148 .into(),
149 self.end,
150 ))
151 }
152 }
153
154 impl Strategy for ::core::ops::RangeToInclusive<$typ> {
155 type Tree = BinarySearch;
156 type Value = $typ;
157
158 fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
159 Ok(BinarySearch::new_clamped(
160 ::core::$typ::MIN,
161 $crate::num::sample_uniform_incl::<$sample_typ>(
162 runner,
163 ::core::$typ::MIN.into(),
164 self.end.into(),
165 )
166 .into(),
167 self.end,
168 ))
169 }
170 }
171 };
172}
173
174macro_rules! signed_integer_bin_search {
175 ($typ:ident) => {
176 #[allow(missing_docs)]
177 pub mod $typ {
178 use rand::Rng;
179
180 use crate::strategy::*;
181 use crate::test_runner::TestRunner;
182
183 int_any!($typ);
184
185 #[derive(Clone, Copy, Debug)]
188 pub struct BinarySearch {
189 lo: $typ,
190 curr: $typ,
191 hi: $typ,
192 }
193 impl BinarySearch {
194 pub fn new(start: $typ) -> Self {
196 BinarySearch {
197 lo: 0,
198 curr: start,
199 hi: start,
200 }
201 }
202
203 fn new_clamped(lo: $typ, start: $typ, hi: $typ) -> Self {
207 use core::cmp::{max, min};
208
209 BinarySearch {
210 lo: if start < 0 {
211 min(0, hi - 1)
212 } else {
213 max(0, lo)
214 },
215 hi: start,
216 curr: start,
217 }
218 }
219
220 fn reposition(&mut self) -> bool {
221 let interval = self.hi - self.lo;
224 let new_mid = self.lo + interval / 2;
225
226 if new_mid == self.curr {
227 false
228 } else {
229 self.curr = new_mid;
230 true
231 }
232 }
233
234 fn magnitude_greater(lhs: $typ, rhs: $typ) -> bool {
235 if 0 == lhs {
236 false
237 } else if lhs < 0 {
238 lhs < rhs
239 } else {
240 lhs > rhs
241 }
242 }
243 }
244 impl ValueTree for BinarySearch {
245 type Value = $typ;
246
247 fn current(&self) -> $typ {
248 self.curr
249 }
250
251 fn simplify(&mut self) -> bool {
252 if !BinarySearch::magnitude_greater(self.hi, self.lo) {
253 return false;
254 }
255
256 self.hi = self.curr;
257 self.reposition()
258 }
259
260 fn complicate(&mut self) -> bool {
261 if !BinarySearch::magnitude_greater(self.hi, self.lo) {
262 return false;
263 }
264
265 self.lo = self.curr + if self.hi < 0 { -1 } else { 1 };
266
267 self.reposition()
268 }
269 }
270
271 numeric_api!($typ, 1);
272 }
273 };
274}
275
276macro_rules! unsigned_integer_bin_search {
277 ($typ:ident) => {
278 #[allow(missing_docs)]
279 pub mod $typ {
280 use rand::Rng;
281
282 use crate::strategy::*;
283 use crate::test_runner::TestRunner;
284
285 int_any!($typ);
286
287 #[derive(Clone, Copy, Debug)]
290 pub struct BinarySearch {
291 lo: $typ,
292 curr: $typ,
293 hi: $typ,
294 }
295 impl BinarySearch {
296 pub fn new(start: $typ) -> Self {
298 BinarySearch {
299 lo: 0,
300 curr: start,
301 hi: start,
302 }
303 }
304
305 fn new_clamped(lo: $typ, start: $typ, _hi: $typ) -> Self {
308 BinarySearch {
309 lo: lo,
310 curr: start,
311 hi: start,
312 }
313 }
314
315 pub fn new_above(lo: $typ, start: $typ) -> Self {
318 BinarySearch::new_clamped(lo, start, start)
319 }
320
321 fn reposition(&mut self) -> bool {
322 let interval = self.hi - self.lo;
323 let new_mid = self.lo + interval / 2;
324
325 if new_mid == self.curr {
326 false
327 } else {
328 self.curr = new_mid;
329 true
330 }
331 }
332 }
333 impl ValueTree for BinarySearch {
334 type Value = $typ;
335
336 fn current(&self) -> $typ {
337 self.curr
338 }
339
340 fn simplify(&mut self) -> bool {
341 if self.hi <= self.lo {
342 return false;
343 }
344
345 self.hi = self.curr;
346 self.reposition()
347 }
348
349 fn complicate(&mut self) -> bool {
350 if self.hi <= self.lo {
351 return false;
352 }
353
354 self.lo = self.curr + 1;
355 self.reposition()
356 }
357 }
358
359 numeric_api!($typ, 1);
360 }
361 };
362}
363
364signed_integer_bin_search!(i8);
365signed_integer_bin_search!(i16);
366signed_integer_bin_search!(i32);
367signed_integer_bin_search!(i64);
368signed_integer_bin_search!(i128);
369signed_integer_bin_search!(isize);
370unsigned_integer_bin_search!(u8);
371unsigned_integer_bin_search!(u16);
372unsigned_integer_bin_search!(u32);
373unsigned_integer_bin_search!(u64);
374unsigned_integer_bin_search!(u128);
375unsigned_integer_bin_search!(usize);
376
377bitflags! {
378 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
379 pub(crate) struct FloatTypes: u32 {
380 const POSITIVE = 0b0000_0001;
381 const NEGATIVE = 0b0000_0010;
382 const NORMAL = 0b0000_0100;
383 const SUBNORMAL = 0b0000_1000;
384 const ZERO = 0b0001_0000;
385 const INFINITE = 0b0010_0000;
386 const QUIET_NAN = 0b0100_0000;
387 const SIGNALING_NAN = 0b1000_0000;
388 const ANY =
389 Self::POSITIVE.bits() |
390 Self::NEGATIVE.bits() |
391 Self::NORMAL.bits() |
392 Self::SUBNORMAL.bits() |
393 Self::ZERO.bits() |
394 Self::INFINITE.bits() |
395 Self::QUIET_NAN.bits();
396 }
397}
398
399impl FloatTypes {
400 fn normalise(mut self) -> Self {
401 if !self.intersects(FloatTypes::POSITIVE | FloatTypes::NEGATIVE) {
402 self |= FloatTypes::POSITIVE;
403 }
404
405 if !self.intersects(
406 FloatTypes::NORMAL
407 | FloatTypes::SUBNORMAL
408 | FloatTypes::ZERO
409 | FloatTypes::INFINITE
410 | FloatTypes::QUIET_NAN
411 | FloatTypes::SIGNALING_NAN,
412 ) {
413 self |= FloatTypes::NORMAL;
414 }
415 self
416 }
417}
418
419trait FloatLayout
420where
421 Standard: Distribution<Self::Bits>,
422{
423 type Bits: Copy;
424
425 const SIGN_MASK: Self::Bits;
426 const EXP_MASK: Self::Bits;
427 const EXP_ZERO: Self::Bits;
428 const MANTISSA_MASK: Self::Bits;
429}
430
431impl FloatLayout for f32 {
432 type Bits = u32;
433
434 const SIGN_MASK: u32 = 0x8000_0000;
435 const EXP_MASK: u32 = 0x7F80_0000;
436 const EXP_ZERO: u32 = 0x3F80_0000;
437 const MANTISSA_MASK: u32 = 0x007F_FFFF;
438}
439
440impl FloatLayout for f64 {
441 type Bits = u64;
442
443 const SIGN_MASK: u64 = 0x8000_0000_0000_0000;
444 const EXP_MASK: u64 = 0x7FF0_0000_0000_0000;
445 const EXP_ZERO: u64 = 0x3FF0_0000_0000_0000;
446 const MANTISSA_MASK: u64 = 0x000F_FFFF_FFFF_FFFF;
447}
448
449macro_rules! float_any {
450 ($typ:ident) => {
451 #[derive(Clone, Copy, Debug)]
480 #[must_use = "strategies do nothing unless used"]
481 pub struct Any(FloatTypes);
482
483 #[cfg(test)]
484 impl Any {
485 pub(crate) fn from_bits(bits: u32) -> Self {
486 Any(FloatTypes::from_bits_truncate(bits))
487 }
488
489 pub(crate) fn normal_bits(&self) -> FloatTypes {
490 self.0.normalise()
491 }
492 }
493
494 impl ops::BitOr for Any {
495 type Output = Self;
496
497 fn bitor(self, rhs: Self) -> Self {
498 Any(self.0 | rhs.0)
499 }
500 }
501
502 impl ops::BitOrAssign for Any {
503 fn bitor_assign(&mut self, rhs: Self) {
504 self.0 |= rhs.0
505 }
506 }
507
508 pub const POSITIVE: Any = Any(FloatTypes::POSITIVE);
516 pub const NEGATIVE: Any = Any(FloatTypes::NEGATIVE);
524 pub const NORMAL: Any = Any(FloatTypes::NORMAL);
539 pub const SUBNORMAL: Any = Any(FloatTypes::SUBNORMAL);
551 pub const ZERO: Any = Any(FloatTypes::ZERO);
559 pub const INFINITE: Any = Any(FloatTypes::INFINITE);
564 pub const QUIET_NAN: Any = Any(FloatTypes::QUIET_NAN);
585 pub const SIGNALING_NAN: Any = Any(FloatTypes::SIGNALING_NAN);
605
606 pub const ANY: Any = Any(FloatTypes::ANY);
621
622 impl Strategy for Any {
623 type Tree = BinarySearch;
624 type Value = $typ;
625
626 fn new_tree(&self, runner: &mut TestRunner) -> NewTree<Self> {
627 let flags = self.0.normalise();
628 let sign_mask = if flags.contains(FloatTypes::NEGATIVE) {
629 $typ::SIGN_MASK
630 } else {
631 0
632 };
633 let sign_or = if flags.contains(FloatTypes::POSITIVE) {
634 0
635 } else {
636 $typ::SIGN_MASK
637 };
638
639 macro_rules! weight {
640 ($case:ident, $weight:expr) => {
641 if flags.contains(FloatTypes::$case) {
642 $weight
643 } else {
644 0
645 }
646 }
647 }
648
649 let quiet_or = ::core::$typ::NAN.to_bits() &
654 ($typ::EXP_MASK | ($typ::EXP_MASK >> 1));
655 let signaling_or = (quiet_or ^ ($typ::EXP_MASK >> 1)) |
656 $typ::EXP_MASK;
657
658 let (class_mask, class_or, allow_edge_exp, allow_zero_mant) =
659 prop_oneof![
660 weight!(NORMAL, 20) => Just(
661 ($typ::EXP_MASK | $typ::MANTISSA_MASK, 0,
662 false, true)),
663 weight!(SUBNORMAL, 3) => Just(
664 ($typ::MANTISSA_MASK, 0, true, false)),
665 weight!(ZERO, 4) => Just(
666 (0, 0, true, true)),
667 weight!(INFINITE, 2) => Just(
668 (0, $typ::EXP_MASK, true, true)),
669 weight!(QUIET_NAN, 1) => Just(
670 ($typ::MANTISSA_MASK >> 1, quiet_or,
671 true, false)),
672 weight!(SIGNALING_NAN, 1) => Just(
673 ($typ::MANTISSA_MASK >> 1, signaling_or,
674 true, false)),
675 ].new_tree(runner)?.current();
676
677 let mut generated_value: <$typ as FloatLayout>::Bits =
678 runner.rng().gen();
679 generated_value &= sign_mask | class_mask;
680 generated_value |= sign_or | class_or;
681 let exp = generated_value & $typ::EXP_MASK;
682 if !allow_edge_exp && (0 == exp || $typ::EXP_MASK == exp) {
683 generated_value &= !$typ::EXP_MASK;
684 generated_value |= $typ::EXP_ZERO;
685 }
686 if !allow_zero_mant &&
687 0 == generated_value & $typ::MANTISSA_MASK
688 {
689 generated_value |= 1;
690 }
691
692 Ok(BinarySearch::new_with_types(
693 $typ::from_bits(generated_value), flags))
694 }
695 }
696 }
697}
698
699macro_rules! float_bin_search {
700 ($typ:ident, $sample_typ:ident) => {
701 #[allow(missing_docs)]
702 pub mod $typ {
703 use super::float_samplers::$sample_typ;
704
705 use core::ops;
706 #[cfg(not(feature = "std"))]
707 use num_traits::float::FloatCore;
708
709 use rand::Rng;
710
711 use super::{FloatLayout, FloatTypes};
712 use crate::strategy::*;
713 use crate::test_runner::TestRunner;
714
715 float_any!($typ);
716
717 #[derive(Clone, Copy, Debug)]
722 pub struct BinarySearch {
723 lo: $typ,
724 curr: $typ,
725 hi: $typ,
726 allowed: FloatTypes,
727 }
728
729 impl BinarySearch {
730 pub fn new(start: $typ) -> Self {
732 BinarySearch {
733 lo: 0.0,
734 curr: start,
735 hi: start,
736 allowed: FloatTypes::all(),
737 }
738 }
739
740 fn new_with_types(start: $typ, allowed: FloatTypes) -> Self {
741 BinarySearch {
742 lo: 0.0,
743 curr: start,
744 hi: start,
745 allowed,
746 }
747 }
748
749 fn new_clamped(lo: $typ, start: $typ, hi: $typ) -> Self {
753 BinarySearch {
754 lo: if start.is_sign_negative() {
755 hi.min(0.0)
756 } else {
757 lo.max(0.0)
758 },
759 hi: start,
760 curr: start,
761 allowed: FloatTypes::all(),
762 }
763 }
764
765 fn current_allowed(&self) -> bool {
766 use core::num::FpCategory::*;
767
768 let class_allowed = match self.curr.classify() {
770 Nan =>
771 {
776 self.allowed.contains(FloatTypes::QUIET_NAN)
777 || self
778 .allowed
779 .contains(FloatTypes::SIGNALING_NAN)
780 }
781 Infinite => self.allowed.contains(FloatTypes::INFINITE),
782 Zero => self.allowed.contains(FloatTypes::ZERO),
783 Subnormal => {
784 self.allowed.contains(FloatTypes::SUBNORMAL)
785 }
786 Normal => self.allowed.contains(FloatTypes::NORMAL),
787 };
788 let signum = self.curr.signum();
789 let sign_allowed = if signum > 0.0 {
790 self.allowed.contains(FloatTypes::POSITIVE)
791 } else if signum < 0.0 {
792 self.allowed.contains(FloatTypes::NEGATIVE)
793 } else {
794 true
795 };
796
797 class_allowed && sign_allowed
798 }
799
800 fn ensure_acceptable(&mut self) {
801 while !self.current_allowed() {
802 if !self.complicate_once() {
803 panic!(
804 "Unable to complicate floating-point back \
805 to acceptable value"
806 );
807 }
808 }
809 }
810
811 fn reposition(&mut self) -> bool {
812 let interval = self.hi - self.lo;
813 let interval =
814 if interval.is_finite() { interval } else { 0.0 };
815 let new_mid = self.lo + interval / 2.0;
816
817 let new_mid = if new_mid == self.curr || 0.0 == interval {
818 new_mid
819 } else {
820 self.lo
821 };
822
823 if new_mid == self.curr {
824 false
825 } else {
826 self.curr = new_mid;
827 true
828 }
829 }
830
831 fn done(lo: $typ, hi: $typ) -> bool {
832 (lo.abs() > hi.abs() && !hi.is_nan()) || lo.is_nan()
833 }
834
835 fn complicate_once(&mut self) -> bool {
836 if BinarySearch::done(self.lo, self.hi) {
837 return false;
838 }
839
840 self.lo = if self.curr == self.lo {
841 self.hi
842 } else {
843 self.curr
844 };
845
846 self.reposition()
847 }
848 }
849 impl ValueTree for BinarySearch {
850 type Value = $typ;
851
852 fn current(&self) -> $typ {
853 self.curr
854 }
855
856 fn simplify(&mut self) -> bool {
857 if BinarySearch::done(self.lo, self.hi) {
858 return false;
859 }
860
861 self.hi = self.curr;
862 if self.reposition() {
863 self.ensure_acceptable();
864 true
865 } else {
866 false
867 }
868 }
869
870 fn complicate(&mut self) -> bool {
871 if self.complicate_once() {
872 self.ensure_acceptable();
873 true
874 } else {
875 false
876 }
877 }
878 }
879
880 numeric_api!($typ, $sample_typ, 0.0);
881 }
882 };
883}
884
885float_bin_search!(f32, F32U);
886float_bin_search!(f64, F64U);
887
888#[cfg(test)]
889mod test {
890 use crate::strategy::*;
891 use crate::test_runner::*;
892
893 use super::*;
894
895 #[test]
896 fn u8_inclusive_end_included() {
897 let mut runner = TestRunner::deterministic();
898 let mut ok = 0;
899 for _ in 0..20 {
900 let tree = (0..=1).new_tree(&mut runner).unwrap();
901 let test = runner.run_one(tree, |v| {
902 prop_assert_eq!(v, 1);
903 Ok(())
904 });
905 if test.is_ok() {
906 ok += 1;
907 }
908 }
909 assert!(ok > 1, "inclusive end not included.");
910 }
911
912 #[test]
913 fn u8_inclusive_to_end_included() {
914 let mut runner = TestRunner::deterministic();
915 let mut ok = 0;
916 for _ in 0..20 {
917 let tree = (..=1u8).new_tree(&mut runner).unwrap();
918 let test = runner.run_one(tree, |v| {
919 prop_assert_eq!(v, 1);
920 Ok(())
921 });
922 if test.is_ok() {
923 ok += 1;
924 }
925 }
926 assert!(ok > 1, "inclusive end not included.");
927 }
928
929 #[test]
930 fn i8_binary_search_always_converges() {
931 fn assert_converges<P: Fn(i32) -> bool>(start: i8, pass: P) {
932 let mut state = i8::BinarySearch::new(start);
933 loop {
934 if !pass(state.current() as i32) {
935 if !state.simplify() {
936 break;
937 }
938 } else {
939 if !state.complicate() {
940 break;
941 }
942 }
943 }
944
945 assert!(!pass(state.current() as i32));
946 assert!(
947 pass(state.current() as i32 - 1)
948 || pass(state.current() as i32 + 1)
949 );
950 }
951
952 for start in -128..0 {
953 for target in start + 1..1 {
954 assert_converges(start as i8, |v| v > target);
955 }
956 }
957
958 for start in 0..128 {
959 for target in 0..start {
960 assert_converges(start as i8, |v| v < target);
961 }
962 }
963 }
964
965 #[test]
966 fn u8_binary_search_always_converges() {
967 fn assert_converges<P: Fn(u32) -> bool>(start: u8, pass: P) {
968 let mut state = u8::BinarySearch::new(start);
969 loop {
970 if !pass(state.current() as u32) {
971 if !state.simplify() {
972 break;
973 }
974 } else {
975 if !state.complicate() {
976 break;
977 }
978 }
979 }
980
981 assert!(!pass(state.current() as u32));
982 assert!(pass(state.current() as u32 - 1));
983 }
984
985 for start in 0..255 {
986 for target in 0..start {
987 assert_converges(start as u8, |v| v <= target);
988 }
989 }
990 }
991
992 #[test]
993 fn signed_integer_range_including_zero_converges_to_zero() {
994 let mut runner = TestRunner::default();
995 for _ in 0..100 {
996 let mut state = (-42i32..64i32).new_tree(&mut runner).unwrap();
997 let init_value = state.current();
998 assert!(init_value >= -42 && init_value < 64);
999
1000 while state.simplify() {
1001 let v = state.current();
1002 assert!(v >= -42 && v < 64);
1003 }
1004
1005 assert_eq!(0, state.current());
1006 }
1007 }
1008
1009 #[test]
1010 fn negative_integer_range_stays_in_bounds() {
1011 let mut runner = TestRunner::default();
1012 for _ in 0..100 {
1013 let mut state = (..-42i32).new_tree(&mut runner).unwrap();
1014 let init_value = state.current();
1015 assert!(init_value < -42);
1016
1017 while state.simplify() {
1018 assert!(
1019 state.current() < -42,
1020 "Violated bounds: {}",
1021 state.current()
1022 );
1023 }
1024
1025 assert_eq!(-43, state.current());
1026 }
1027 }
1028
1029 #[test]
1030 fn positive_signed_integer_range_stays_in_bounds() {
1031 let mut runner = TestRunner::default();
1032 for _ in 0..100 {
1033 let mut state = (42i32..).new_tree(&mut runner).unwrap();
1034 let init_value = state.current();
1035 assert!(init_value >= 42);
1036
1037 while state.simplify() {
1038 assert!(
1039 state.current() >= 42,
1040 "Violated bounds: {}",
1041 state.current()
1042 );
1043 }
1044
1045 assert_eq!(42, state.current());
1046 }
1047 }
1048
1049 #[test]
1050 fn unsigned_integer_range_stays_in_bounds() {
1051 let mut runner = TestRunner::default();
1052 for _ in 0..100 {
1053 let mut state = (42u32..56u32).new_tree(&mut runner).unwrap();
1054 let init_value = state.current();
1055 assert!(init_value >= 42 && init_value < 56);
1056
1057 while state.simplify() {
1058 assert!(
1059 state.current() >= 42,
1060 "Violated bounds: {}",
1061 state.current()
1062 );
1063 }
1064
1065 assert_eq!(42, state.current());
1066 }
1067 }
1068
1069 mod contract_sanity {
1070 macro_rules! contract_sanity {
1071 ($t:tt) => {
1072 mod $t {
1073 use crate::strategy::check_strategy_sanity;
1074
1075 const FORTY_TWO: $t = 42 as $t;
1076 const FIFTY_SIX: $t = 56 as $t;
1077
1078 #[test]
1079 fn range() {
1080 check_strategy_sanity(FORTY_TWO..FIFTY_SIX, None);
1081 }
1082
1083 #[test]
1084 fn range_inclusive() {
1085 check_strategy_sanity(FORTY_TWO..=FIFTY_SIX, None);
1086 }
1087
1088 #[test]
1089 fn range_to() {
1090 check_strategy_sanity(..FIFTY_SIX, None);
1091 }
1092
1093 #[test]
1094 fn range_to_inclusive() {
1095 check_strategy_sanity(..=FIFTY_SIX, None);
1096 }
1097
1098 #[test]
1099 fn range_from() {
1100 check_strategy_sanity(FORTY_TWO.., None);
1101 }
1102 }
1103 };
1104 }
1105 contract_sanity!(u8);
1106 contract_sanity!(i8);
1107 contract_sanity!(u16);
1108 contract_sanity!(i16);
1109 contract_sanity!(u32);
1110 contract_sanity!(i32);
1111 contract_sanity!(u64);
1112 contract_sanity!(i64);
1113 contract_sanity!(usize);
1114 contract_sanity!(isize);
1115 contract_sanity!(f32);
1116 contract_sanity!(f64);
1117 }
1118
1119 #[test]
1120 fn unsigned_integer_binsearch_simplify_complicate_contract_upheld() {
1121 check_strategy_sanity(0u32..1000u32, None);
1122 check_strategy_sanity(0u32..1u32, None);
1123 }
1124
1125 #[test]
1126 fn signed_integer_binsearch_simplify_complicate_contract_upheld() {
1127 check_strategy_sanity(0i32..1000i32, None);
1128 check_strategy_sanity(0i32..1i32, None);
1129 }
1130
1131 #[test]
1132 fn positive_float_simplifies_to_zero() {
1133 let mut runner = TestRunner::default();
1134 let mut value = (0.0f64..2.0).new_tree(&mut runner).unwrap();
1135
1136 while value.simplify() {}
1137
1138 assert_eq!(0.0, value.current());
1139 }
1140
1141 #[test]
1142 fn positive_float_simplifies_to_base() {
1143 let mut runner = TestRunner::default();
1144 let mut value = (1.0f64..2.0).new_tree(&mut runner).unwrap();
1145
1146 while value.simplify() {}
1147
1148 assert_eq!(1.0, value.current());
1149 }
1150
1151 #[test]
1152 fn negative_float_simplifies_to_zero() {
1153 let mut runner = TestRunner::default();
1154 let mut value = (-2.0f64..0.0).new_tree(&mut runner).unwrap();
1155
1156 while value.simplify() {}
1157
1158 assert_eq!(0.0, value.current());
1159 }
1160
1161 #[test]
1162 fn positive_float_complicates_to_original() {
1163 let mut runner = TestRunner::default();
1164 let mut value = (1.0f64..2.0).new_tree(&mut runner).unwrap();
1165 let orig = value.current();
1166
1167 assert!(value.simplify());
1168 while value.complicate() {}
1169
1170 assert_eq!(orig, value.current());
1171 }
1172
1173 #[test]
1174 fn positive_infinity_simplifies_directly_to_zero() {
1175 let mut value = f64::BinarySearch::new(::std::f64::INFINITY);
1176
1177 assert!(value.simplify());
1178 assert_eq!(0.0, value.current());
1179 assert!(value.complicate());
1180 assert_eq!(::std::f64::INFINITY, value.current());
1181 assert!(!value.clone().complicate());
1182 assert!(!value.clone().simplify());
1183 }
1184
1185 #[test]
1186 fn negative_infinity_simplifies_directly_to_zero() {
1187 let mut value = f64::BinarySearch::new(::std::f64::NEG_INFINITY);
1188
1189 assert!(value.simplify());
1190 assert_eq!(0.0, value.current());
1191 assert!(value.complicate());
1192 assert_eq!(::std::f64::NEG_INFINITY, value.current());
1193 assert!(!value.clone().complicate());
1194 assert!(!value.clone().simplify());
1195 }
1196
1197 #[test]
1198 fn nan_simplifies_directly_to_zero() {
1199 let mut value = f64::BinarySearch::new(::std::f64::NAN);
1200
1201 assert!(value.simplify());
1202 assert_eq!(0.0, value.current());
1203 assert!(value.complicate());
1204 assert!(value.current().is_nan());
1205 assert!(!value.clone().complicate());
1206 assert!(!value.clone().simplify());
1207 }
1208
1209 #[test]
1210 fn float_simplifies_to_smallest_normal() {
1211 let mut runner = TestRunner::default();
1212 let mut value = (::std::f64::MIN_POSITIVE..2.0)
1213 .new_tree(&mut runner)
1214 .unwrap();
1215
1216 while value.simplify() {}
1217
1218 assert_eq!(::std::f64::MIN_POSITIVE, value.current());
1219 }
1220
1221 macro_rules! float_generation_test_body {
1222 ($strategy:ident, $typ:ident) => {
1223 use std::num::FpCategory;
1224
1225 let strategy = $strategy;
1226 let bits = strategy.normal_bits();
1227
1228 let mut seen_positive = 0;
1229 let mut seen_negative = 0;
1230 let mut seen_normal = 0;
1231 let mut seen_subnormal = 0;
1232 let mut seen_zero = 0;
1233 let mut seen_infinite = 0;
1234 let mut seen_quiet_nan = 0;
1235 let mut seen_signaling_nan = 0;
1236 let mut runner = TestRunner::deterministic();
1237
1238 let fidelity_1 = f32::from_bits(0x7F80_0001).to_bits();
1241 let fidelity_2 = f32::from_bits(0xFF80_0001).to_bits();
1242 let nan_fidelity = fidelity_1 != fidelity_2;
1243
1244 for _ in 0..1024 {
1245 let mut tree = strategy.new_tree(&mut runner).unwrap();
1246 let mut increment = 1;
1247
1248 loop {
1249 let value = tree.current();
1250
1251 let sign = value.signum(); if sign < 0.0 {
1253 prop_assert!(bits.contains(FloatTypes::NEGATIVE));
1254 seen_negative += increment;
1255 } else if sign > 0.0 {
1256 prop_assert!(bits.contains(FloatTypes::POSITIVE));
1258 seen_positive += increment;
1259 }
1260
1261 match value.classify() {
1262 FpCategory::Nan if nan_fidelity => {
1263 let raw = value.to_bits();
1264 let is_negative = raw << 1 >> 1 != raw;
1265 if is_negative {
1266 prop_assert!(
1267 bits.contains(FloatTypes::NEGATIVE)
1268 );
1269 seen_negative += increment;
1270 } else {
1271 prop_assert!(
1272 bits.contains(FloatTypes::POSITIVE)
1273 );
1274 seen_positive += increment;
1275 }
1276
1277 let is_quiet = raw & ($typ::EXP_MASK >> 1)
1278 == ::std::$typ::NAN.to_bits()
1279 & ($typ::EXP_MASK >> 1);
1280 if is_quiet {
1281 prop_assert!(
1286 bits.contains(FloatTypes::QUIET_NAN)
1287 || bits.contains(
1288 FloatTypes::SIGNALING_NAN
1289 )
1290 );
1291 seen_quiet_nan += increment;
1292 seen_signaling_nan += increment;
1293 } else {
1294 prop_assert!(
1295 bits.contains(FloatTypes::SIGNALING_NAN)
1296 );
1297 seen_signaling_nan += increment;
1298 }
1299 }
1300
1301 FpCategory::Nan => {
1302 seen_positive += increment;
1308 seen_negative += increment;
1309 seen_quiet_nan += increment;
1310 seen_signaling_nan += increment;
1311 prop_assert!(
1312 bits.contains(FloatTypes::QUIET_NAN)
1313 || bits.contains(FloatTypes::SIGNALING_NAN)
1314 );
1315 }
1316 FpCategory::Infinite => {
1317 prop_assert!(bits.contains(FloatTypes::INFINITE));
1318 seen_infinite += increment;
1319 }
1320 FpCategory::Zero => {
1321 prop_assert!(bits.contains(FloatTypes::ZERO));
1322 seen_zero += increment;
1323 }
1324 FpCategory::Subnormal => {
1325 prop_assert!(bits.contains(FloatTypes::SUBNORMAL));
1326 seen_subnormal += increment;
1327 }
1328 FpCategory::Normal => {
1329 prop_assert!(bits.contains(FloatTypes::NORMAL));
1330 seen_normal += increment;
1331 }
1332 }
1333
1334 increment = 0;
1336 if !tree.simplify() {
1337 break;
1338 }
1339 }
1340 }
1341
1342 if bits.contains(FloatTypes::POSITIVE) {
1343 prop_assert!(seen_positive > 200);
1344 }
1345 if bits.contains(FloatTypes::NEGATIVE) {
1346 prop_assert!(seen_negative > 200);
1347 }
1348 if bits.contains(FloatTypes::NORMAL) {
1349 prop_assert!(seen_normal > 100);
1350 }
1351 if bits.contains(FloatTypes::SUBNORMAL) {
1352 prop_assert!(seen_subnormal > 5);
1353 }
1354 if bits.contains(FloatTypes::ZERO) {
1355 prop_assert!(seen_zero > 5);
1356 }
1357 if bits.contains(FloatTypes::INFINITE) {
1358 prop_assert!(seen_infinite > 0);
1359 }
1360 if bits.contains(FloatTypes::QUIET_NAN) {
1361 prop_assert!(seen_quiet_nan > 0);
1362 }
1363 if bits.contains(FloatTypes::SIGNALING_NAN) {
1364 prop_assert!(seen_signaling_nan > 0);
1365 }
1366 };
1367 }
1368
1369 proptest! {
1370 #![proptest_config(crate::test_runner::Config::with_cases(1024))]
1371
1372 #[test]
1373 fn f32_any_generates_desired_values(
1374 strategy in crate::bits::u32::ANY.prop_map(f32::Any::from_bits)
1375 ) {
1376 float_generation_test_body!(strategy, f32);
1377 }
1378
1379 #[test]
1380 fn f32_any_sanity(
1381 strategy in crate::bits::u32::ANY.prop_map(f32::Any::from_bits)
1382 ) {
1383 check_strategy_sanity(strategy, Some(CheckStrategySanityOptions {
1384 strict_complicate_after_simplify: false,
1385 .. CheckStrategySanityOptions::default()
1386 }));
1387 }
1388
1389 #[test]
1390 fn f64_any_generates_desired_values(
1391 strategy in crate::bits::u32::ANY.prop_map(f64::Any::from_bits)
1392 ) {
1393 float_generation_test_body!(strategy, f64);
1394 }
1395
1396 #[test]
1397 fn f64_any_sanity(
1398 strategy in crate::bits::u32::ANY.prop_map(f64::Any::from_bits)
1399 ) {
1400 check_strategy_sanity(strategy, Some(CheckStrategySanityOptions {
1401 strict_complicate_after_simplify: false,
1402 .. CheckStrategySanityOptions::default()
1403 }));
1404 }
1405 }
1406
1407 mod panic_on_empty {
1408 macro_rules! panic_on_empty {
1409 ($t:tt) => {
1410 mod $t {
1411 use crate::strategy::Strategy;
1412 use crate::test_runner::TestRunner;
1413 use std::panic;
1414 use std::string::String;
1415
1416 const ZERO: $t = 0 as $t;
1417 const ONE: $t = 1 as $t;
1418
1419 #[test]
1420 fn range() {
1421 assert_eq!(
1422 panic::catch_unwind(|| {
1423 let mut runner = TestRunner::deterministic();
1424 let _ = (ZERO..ZERO).new_tree(&mut runner);
1425 })
1426 .err()
1427 .and_then(|a| a
1428 .downcast_ref::<String>()
1429 .map(|s| {
1430 s == "Invalid use of empty range 0..0."
1431 })),
1432 Some(true)
1433 );
1434 }
1435
1436 #[test]
1437 fn range_inclusive() {
1438 assert_eq!(
1439 panic::catch_unwind(|| {
1440 let mut runner = TestRunner::deterministic();
1441 let _ = (ONE..=ZERO).new_tree(&mut runner);
1442 })
1443 .err()
1444 .and_then(|a| a
1445 .downcast_ref::<String>()
1446 .map(|s| {
1447 s == "Invalid use of empty range 1..=0."
1448 })),
1449 Some(true)
1450 );
1451 }
1452 }
1453 };
1454 }
1455 panic_on_empty!(u8);
1456 panic_on_empty!(i8);
1457 panic_on_empty!(u16);
1458 panic_on_empty!(i16);
1459 panic_on_empty!(u32);
1460 panic_on_empty!(i32);
1461 panic_on_empty!(u64);
1462 panic_on_empty!(i64);
1463 panic_on_empty!(usize);
1464 panic_on_empty!(isize);
1465 panic_on_empty!(f32);
1466 panic_on_empty!(f64);
1467 }
1468}