qc.rs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. // When testing functions, QuickCheck (QC) uses small values for integer (`u*`/`i*`) arguments
  2. // (~ `[-100, 100]`), but these values don't stress all the code paths in our intrinsics. Here we
  3. // create newtypes over the primitive integer types with the goal of having full control over the
  4. // random values that will be used to test our intrinsics.
  5. use std::boxed::Box;
  6. use std::fmt;
  7. use quickcheck::{Arbitrary, Gen};
  8. use int::LargeInt;
  9. // Generates values in the full range of the integer type
  10. macro_rules! arbitrary {
  11. ($TY:ident : $ty:ident) => {
  12. #[derive(Clone, Copy)]
  13. pub struct $TY(pub $ty);
  14. impl Arbitrary for $TY {
  15. fn arbitrary<G>(g: &mut G) -> $TY
  16. where G: Gen
  17. {
  18. $TY(g.gen())
  19. }
  20. fn shrink(&self) -> Box<Iterator<Item=$TY>> {
  21. struct Shrinker {
  22. x: $ty,
  23. }
  24. impl Iterator for Shrinker {
  25. type Item = $TY;
  26. fn next(&mut self) -> Option<$TY> {
  27. self.x /= 2;
  28. if self.x == 0 {
  29. None
  30. } else {
  31. Some($TY(self.x))
  32. }
  33. }
  34. }
  35. if self.0 == 0 {
  36. ::quickcheck::empty_shrinker()
  37. } else {
  38. Box::new(Shrinker { x: self.0 })
  39. }
  40. }
  41. }
  42. impl fmt::Debug for $TY {
  43. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  44. fmt::Debug::fmt(&self.0, f)
  45. }
  46. }
  47. }
  48. }
  49. arbitrary!(I32: i32);
  50. arbitrary!(U32: u32);
  51. // These integers are "too large". If we generate e.g. `u64` values in the full range then there's
  52. // only `1 / 2^32` chance of seeing a value smaller than `2^32` (i.e. whose higher "word" (32-bits)
  53. // is `0`)! But this is an important group of values to tests because we have special code paths for
  54. // them. Instead we'll generate e.g. `u64` integers this way: uniformly pick between (a) setting the
  55. // low word to 0 and generating a random high word, (b) vice versa: high word to 0 and random low
  56. // word or (c) generate both words randomly. This let's cover better the code paths in our
  57. // intrinsics.
  58. macro_rules! arbitrary_large {
  59. ($TY:ident : $ty:ident) => {
  60. #[derive(Clone, Copy)]
  61. pub struct $TY(pub $ty);
  62. impl Arbitrary for $TY {
  63. fn arbitrary<G>(g: &mut G) -> $TY
  64. where G: Gen
  65. {
  66. if g.gen() {
  67. $TY($ty::from_parts(g.gen(), g.gen()))
  68. } else if g.gen() {
  69. $TY($ty::from_parts(0, g.gen()))
  70. } else {
  71. $TY($ty::from_parts(g.gen(), 0))
  72. }
  73. }
  74. fn shrink(&self) -> Box<Iterator<Item=$TY>> {
  75. struct Shrinker {
  76. x: $ty,
  77. }
  78. impl Iterator for Shrinker {
  79. type Item = $TY;
  80. fn next(&mut self) -> Option<$TY> {
  81. self.x /= 2;
  82. if self.x == 0 {
  83. None
  84. } else {
  85. Some($TY(self.x))
  86. }
  87. }
  88. }
  89. if self.0 == 0 {
  90. ::quickcheck::empty_shrinker()
  91. } else {
  92. Box::new(Shrinker { x: self.0 })
  93. }
  94. }
  95. }
  96. impl fmt::Debug for $TY {
  97. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
  98. fmt::Debug::fmt(&self.0, f)
  99. }
  100. }
  101. }
  102. }
  103. arbitrary_large!(I64: i64);
  104. arbitrary_large!(U64: u64);