proptest/test_runner/
result_cache.rs

1//-
2// Copyright 2018 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
10use crate::std_facade::fmt;
11use crate::std_facade::Box;
12#[cfg(feature = "std")]
13use std::collections::HashMap;
14
15use crate::test_runner::errors::TestCaseResult;
16
17/// A key used for the result cache.
18///
19/// The capabilities of this structure are currently quite limited; all one can
20/// do with safe code is get the `&dyn Debug` of the test input value. This may
21/// improve in the future, particularly at such a time that specialisation
22/// becomes stable.
23#[derive(Debug)]
24pub struct ResultCacheKey<'a> {
25    value: &'a dyn fmt::Debug,
26}
27
28impl<'a> ResultCacheKey<'a> {
29    pub(crate) fn new(value: &'a dyn fmt::Debug) -> Self {
30        Self { value }
31    }
32
33    /// Return the test input value as an `&dyn Debug`.
34    pub fn value_debug(&self) -> &dyn fmt::Debug {
35        self.value
36    }
37}
38
39/// An object which can cache the outcomes of tests.
40pub trait ResultCache {
41    /// Convert the given cache key into a `u64` representing that value. The
42    /// u64 is used as the key below.
43    ///
44    /// This is a separate step so that ownership of the key value can be
45    /// handed off to user code without needing to be able to clone it.
46    fn key(&self, key: &ResultCacheKey) -> u64;
47    /// Save `result` as the outcome associated with the test input in `key`.
48    ///
49    /// `result` is passed as a reference so that the decision to clone depends
50    /// on whether the cache actually plans on storing it.
51    fn put(&mut self, key: u64, result: &TestCaseResult);
52    /// If `put()` has been called with a semantically equivalent `key`, return
53    /// the saved result. Otherwise, return `None`.
54    fn get(&self, key: u64) -> Option<&TestCaseResult>;
55}
56
57#[cfg(feature = "std")]
58#[derive(Debug, Default, Clone)]
59struct BasicResultCache {
60    entries: HashMap<u64, TestCaseResult>,
61}
62
63#[cfg(feature = "std")]
64impl ResultCache for BasicResultCache {
65    fn key(&self, val: &ResultCacheKey) -> u64 {
66        use std::collections::hash_map::DefaultHasher;
67        use std::hash::Hasher;
68        use std::io::{self, Write};
69
70        struct HashWriter(DefaultHasher);
71        impl io::Write for HashWriter {
72            fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
73                self.0.write(buf);
74                Ok(buf.len())
75            }
76
77            fn flush(&mut self) -> io::Result<()> {
78                Ok(())
79            }
80        }
81
82        let mut hash = HashWriter(DefaultHasher::default());
83        write!(hash, "{:?}", val).expect("Debug format returned Err");
84        hash.0.finish()
85    }
86
87    fn put(&mut self, key: u64, result: &TestCaseResult) {
88        self.entries.insert(key, result.clone());
89    }
90
91    fn get(&self, key: u64) -> Option<&TestCaseResult> {
92        self.entries.get(&key)
93    }
94}
95
96/// A basic result cache.
97///
98/// Values are identified by their `Debug` string representation.
99#[cfg(feature = "std")]
100#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
101pub fn basic_result_cache() -> Box<dyn ResultCache> {
102    Box::new(BasicResultCache::default())
103}
104
105pub(crate) struct NoOpResultCache;
106impl ResultCache for NoOpResultCache {
107    fn key(&self, _: &ResultCacheKey) -> u64 {
108        0
109    }
110    fn put(&mut self, _: u64, _: &TestCaseResult) {}
111    fn get(&self, _: u64) -> Option<&TestCaseResult> {
112        None
113    }
114}
115
116/// A result cache that does nothing.
117///
118/// This is the default value of `ProptestConfig.result_cache`.
119pub fn noop_result_cache() -> Box<dyn ResultCache> {
120    Box::new(NoOpResultCache)
121}