| //- |
| // Copyright 2017, 2018, 2019 The proptest developers |
| // |
| // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
| // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
| // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
| // option. This file may not be copied, modified, or distributed |
| // except according to those terms. |
| |
| use core::any::Any; |
| use core::fmt::Display; |
| use core::result::Result; |
| use core::str::FromStr; |
| use crate::std_facade::{fmt, Box, Vec}; |
| |
| #[cfg(feature = "std")] |
| mod file; |
| mod map; |
| mod noop; |
| |
| #[cfg(feature = "std")] |
| pub use self::file::*; |
| pub use self::map::*; |
| pub use self::noop::*; |
| |
| use crate::test_runner::Seed; |
| |
| /// Opaque struct representing a seed which can be persisted. |
| /// |
| /// The `Display` and `FromStr` implementations go to and from the format |
| /// Proptest uses for its persistence file. |
| #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] |
| pub struct PersistedSeed(pub(crate) Seed); |
| |
| impl Display for PersistedSeed { |
| fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
| write!(f, "{}", self.0.to_persistence()) |
| } |
| } |
| |
| impl FromStr for PersistedSeed { |
| type Err = (); |
| |
| fn from_str(s: &str) -> Result<Self, ()> { |
| Seed::from_persistence(s).map(PersistedSeed).ok_or(()) |
| } |
| } |
| |
| /// Provides external persistence for historical test failures by storing seeds. |
| /// |
| /// **Note**: Implementing `load_persisted_failures` and |
| /// `save_persisted_failures` is **deprecated** and these methods will be |
| /// removed in proptest 0.10.0. Instead, implement `load_persisted_failures2` |
| /// and `save_persisted_failures2`. |
| pub trait FailurePersistence: Send + Sync + fmt::Debug { |
| /// Supply seeds associated with the given `source_file` that may be used |
| /// by a `TestRunner`'s random number generator in order to consistently |
| /// recreate a previously-failing `Strategy`-provided value. |
| /// |
| /// The default implementation is **for backwards compatibility**. It |
| /// delegates to `load_persisted_failures` and converts the results into |
| /// XorShift seeds. |
| #[allow(deprecated)] |
| fn load_persisted_failures2(&self, source_file: Option<&'static str>) |
| -> Vec<PersistedSeed> { |
| self.load_persisted_failures(source_file) |
| .into_iter() |
| .map(|seed| PersistedSeed(Seed::XorShift(seed))) |
| .collect() |
| } |
| |
| /// Use `load_persisted_failures2` instead. |
| /// |
| /// This function inadvertently exposes the implementation of seeds prior |
| /// to Proptest 0.9.1 and only works with XorShift seeds. |
| #[deprecated] |
| #[allow(unused_variables)] |
| fn load_persisted_failures(&self, source_file: Option<&'static str>) |
| -> Vec<[u8; 16]> { |
| panic!("load_persisted_failures2 not implemented"); |
| } |
| |
| /// Store a new failure-generating seed associated with the given `source_file`. |
| /// |
| /// The default implementation is **for backwards compatibility**. It |
| /// delegates to `save_persisted_failure` if `seed` is a XorShift seed. |
| #[allow(deprecated)] |
| fn save_persisted_failure2( |
| &mut self, |
| source_file: Option<&'static str>, |
| seed: PersistedSeed, |
| shrunken_value: &dyn fmt::Debug) |
| { |
| match seed.0 { |
| Seed::XorShift(seed) => self.save_persisted_failure( |
| source_file, seed, shrunken_value), |
| _ => (), |
| } |
| } |
| |
| /// Use `save_persisted_failures2` instead. |
| /// |
| /// This function inadvertently exposes the implementation of seeds prior |
| /// to Proptest 0.9.1 and only works with XorShift seeds. |
| #[deprecated] |
| #[allow(unused_variables)] |
| fn save_persisted_failure( |
| &mut self, |
| source_file: Option<&'static str>, |
| seed: [u8;16], |
| shrunken_value: &dyn fmt::Debug) |
| { |
| panic!("save_persisted_failure2 not implemented"); |
| } |
| |
| /// Delegate method for producing a trait object usable with `Clone` |
| fn box_clone(&self) -> Box<dyn FailurePersistence>; |
| |
| /// Equality testing delegate required due to constraints of trait objects. |
| fn eq(&self, other: &dyn FailurePersistence) -> bool; |
| |
| /// Assistant method for trait object comparison. |
| fn as_any(&self) -> &dyn Any; |
| } |
| |
| impl<'a, 'b> PartialEq<dyn FailurePersistence + 'b> |
| for dyn FailurePersistence + 'a { |
| fn eq(&self, other: &(dyn FailurePersistence + 'b)) -> bool { |
| FailurePersistence::eq(self, other) |
| } |
| } |
| |
| impl Clone for Box<dyn FailurePersistence> { |
| fn clone(&self) -> Box<dyn FailurePersistence> { |
| self.box_clone() |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use super::PersistedSeed; |
| use crate::test_runner::rng::Seed; |
| |
| pub const INC_SEED: PersistedSeed = |
| PersistedSeed( |
| Seed::XorShift( |
| [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15])); |
| |
| pub const HI_PATH: Option<&str> = Some("hi"); |
| pub const UNREL_PATH: Option<&str> = Some("unrelated"); |
| } |