proptest_support/
lib.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Support for property test usage.
6
7use std::any::Any;
8use std::fmt::Debug;
9use std::str::FromStr as _;
10
11use proptest::test_runner::{FailurePersistence, PersistedSeed};
12
13/// Persists all failed seeds to the source file.
14///
15/// Proptest generates nondeterministic tests in the sense that different seeds
16/// will be used in each run, this is intended because we expect the properties
17/// to hold for all possible inputs. So test flakes should be treated as test
18/// failures. This struct configures the containing proptest to log the seeds
19/// that caused test failures, please add all those seeds to the source file
20/// so that the test failure can be persisted.
21#[derive(Clone, Debug, PartialEq)]
22pub struct FailedSeeds(pub Vec<&'static str>);
23
24impl FailurePersistence for FailedSeeds {
25    fn load_persisted_failures2(&self, _source_file: Option<&'static str>) -> Vec<PersistedSeed> {
26        let Self(seeds) = self;
27        seeds.iter().map(|s| PersistedSeed::from_str(s).expect("malformed seed")).collect()
28    }
29
30    fn save_persisted_failure2(
31        &mut self,
32        source_file: Option<&'static str>,
33        seed: PersistedSeed,
34        shrunken_value: &dyn Debug,
35    ) {
36        eprintln!("Test failed when: {:?}", shrunken_value);
37        eprintln!("To reproduce this failure please add the following line:");
38        // The `Display` and `FromStr` impl for `PersistedSeed` are inverse
39        // of each other.
40        eprintln!("\"{}\"", seed);
41        eprintln!("to the test config in file {}", source_file.expect("failed to get source file"));
42    }
43
44    fn box_clone(&self) -> Box<dyn FailurePersistence> {
45        Box::new(self.clone())
46    }
47
48    fn eq(&self, other: &dyn FailurePersistence) -> bool {
49        other.as_any().downcast_ref::<Self>().map_or(false, |x| x == self)
50    }
51
52    fn as_any(&self) -> &dyn Any {
53        self
54    }
55}
56
57#[macro_export]
58macro_rules! failed_seeds_no_std {
59    ($($seed:literal),*) => {
60        Some({
61            use alloc::{boxed::Box, vec};
62            Box::new(proptest_support::FailedSeeds(vec![$($seed),*]))
63        })
64    }
65}
66
67#[macro_export]
68macro_rules! failed_seeds {
69    ($($seed:literal),*) => {
70        Some({
71            Box::new(proptest_support::FailedSeeds(vec![$($seed),*]))
72        })
73    }
74}