blob: be848d12fdc259564c8b0930dc66174cd8eeec82 [file] [log] [blame]
//-
// 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");
}