1 //- 2 // Copyright 2017, 2018, 2019 The proptest developers 3 // 4 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 5 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your 7 // option. This file may not be copied, modified, or distributed 8 // except according to those terms. 9 10 use crate::std_facade::{fmt, Box, Vec}; 11 use core::any::Any; 12 use core::fmt::Display; 13 use core::result::Result; 14 use core::str::FromStr; 15 16 #[cfg(feature = "std")] 17 mod file; 18 mod map; 19 mod noop; 20 21 #[cfg(feature = "std")] 22 pub use self::file::*; 23 pub use self::map::*; 24 pub use self::noop::*; 25 26 use crate::test_runner::Seed; 27 28 /// Opaque struct representing a seed which can be persisted. 29 /// 30 /// The `Display` and `FromStr` implementations go to and from the format 31 /// Proptest uses for its persistence file. 32 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] 33 pub struct PersistedSeed(pub(crate) Seed); 34 35 impl Display for PersistedSeed { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result36 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 37 write!(f, "{}", self.0.to_persistence()) 38 } 39 } 40 41 impl FromStr for PersistedSeed { 42 type Err = (); 43 from_str(s: &str) -> Result<Self, ()>44 fn from_str(s: &str) -> Result<Self, ()> { 45 Seed::from_persistence(s).map(PersistedSeed).ok_or(()) 46 } 47 } 48 49 /// Provides external persistence for historical test failures by storing seeds. 50 /// 51 /// **Note**: Implementing `load_persisted_failures` and 52 /// `save_persisted_failures` is **deprecated** and these methods will be 53 /// removed in proptest 0.10.0. Instead, implement `load_persisted_failures2` 54 /// and `save_persisted_failures2`. 55 pub trait FailurePersistence: Send + Sync + fmt::Debug { 56 /// Supply seeds associated with the given `source_file` that may be used 57 /// by a `TestRunner`'s random number generator in order to consistently 58 /// recreate a previously-failing `Strategy`-provided value. 59 /// 60 /// The default implementation is **for backwards compatibility**. It 61 /// delegates to `load_persisted_failures` and converts the results into 62 /// XorShift seeds. 63 #[allow(deprecated)] load_persisted_failures2( &self, source_file: Option<&'static str>, ) -> Vec<PersistedSeed>64 fn load_persisted_failures2( 65 &self, 66 source_file: Option<&'static str>, 67 ) -> Vec<PersistedSeed> { 68 self.load_persisted_failures(source_file) 69 .into_iter() 70 .map(|seed| PersistedSeed(Seed::XorShift(seed))) 71 .collect() 72 } 73 74 /// Use `load_persisted_failures2` instead. 75 /// 76 /// This function inadvertently exposes the implementation of seeds prior 77 /// to Proptest 0.9.1 and only works with XorShift seeds. 78 #[deprecated] 79 #[allow(unused_variables)] load_persisted_failures( &self, source_file: Option<&'static str>, ) -> Vec<[u8; 16]>80 fn load_persisted_failures( 81 &self, 82 source_file: Option<&'static str>, 83 ) -> Vec<[u8; 16]> { 84 panic!("load_persisted_failures2 not implemented"); 85 } 86 87 /// Store a new failure-generating seed associated with the given `source_file`. 88 /// 89 /// The default implementation is **for backwards compatibility**. It 90 /// delegates to `save_persisted_failure` if `seed` is a XorShift seed. 91 #[allow(deprecated)] save_persisted_failure2( &mut self, source_file: Option<&'static str>, seed: PersistedSeed, shrunken_value: &dyn fmt::Debug, )92 fn save_persisted_failure2( 93 &mut self, 94 source_file: Option<&'static str>, 95 seed: PersistedSeed, 96 shrunken_value: &dyn fmt::Debug, 97 ) { 98 match seed.0 { 99 Seed::XorShift(seed) => { 100 self.save_persisted_failure(source_file, seed, shrunken_value) 101 } 102 _ => (), 103 } 104 } 105 106 /// Use `save_persisted_failures2` instead. 107 /// 108 /// This function inadvertently exposes the implementation of seeds prior 109 /// to Proptest 0.9.1 and only works with XorShift seeds. 110 #[deprecated] 111 #[allow(unused_variables)] save_persisted_failure( &mut self, source_file: Option<&'static str>, seed: [u8; 16], shrunken_value: &dyn fmt::Debug, )112 fn save_persisted_failure( 113 &mut self, 114 source_file: Option<&'static str>, 115 seed: [u8; 16], 116 shrunken_value: &dyn fmt::Debug, 117 ) { 118 panic!("save_persisted_failure2 not implemented"); 119 } 120 121 /// Delegate method for producing a trait object usable with `Clone` box_clone(&self) -> Box<dyn FailurePersistence>122 fn box_clone(&self) -> Box<dyn FailurePersistence>; 123 124 /// Equality testing delegate required due to constraints of trait objects. eq(&self, other: &dyn FailurePersistence) -> bool125 fn eq(&self, other: &dyn FailurePersistence) -> bool; 126 127 /// Assistant method for trait object comparison. as_any(&self) -> &dyn Any128 fn as_any(&self) -> &dyn Any; 129 } 130 131 impl<'a, 'b> PartialEq<dyn FailurePersistence + 'b> 132 for dyn FailurePersistence + 'a 133 { eq(&self, other: &(dyn FailurePersistence + 'b)) -> bool134 fn eq(&self, other: &(dyn FailurePersistence + 'b)) -> bool { 135 FailurePersistence::eq(self, other) 136 } 137 } 138 139 impl Clone for Box<dyn FailurePersistence> { clone(&self) -> Box<dyn FailurePersistence>140 fn clone(&self) -> Box<dyn FailurePersistence> { 141 self.box_clone() 142 } 143 } 144 145 #[cfg(test)] 146 mod tests { 147 use super::PersistedSeed; 148 use crate::test_runner::rng::Seed; 149 150 pub const INC_SEED: PersistedSeed = PersistedSeed(Seed::XorShift([ 151 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 152 ])); 153 154 pub const HI_PATH: Option<&str> = Some("hi"); 155 pub const UNREL_PATH: Option<&str> = Some("unrelated"); 156 } 157