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