1#![allow(clippy::result_large_err)]
2#![allow(clippy::too_many_arguments)]
3#![allow(clippy::redundant_pattern_matching)]
4
5pub mod arbitrary;
29pub mod config;
30pub mod ergonomic;
31pub mod error;
32pub mod execution;
33pub mod generator;
34pub mod performance;
35pub mod primitives;
36pub mod property;
37pub mod rng;
38pub mod shrink;
39pub mod statistics;
40pub mod strategy;
41pub mod test_runner;
42
43pub use arbitrary::Arbitrary;
45pub use config::{
46 ConfigError, ConfigManager, GeneratorConfig, GlobalConfig, TestConfig, create_test_config,
47 create_test_config_with_overrides, get_global_config, set_global_config,
48};
49pub use error::PropertyError;
50pub use execution::{
51 AsyncPropertyTest, PropertyTest, PropertyTestBuilder, check, check_async,
52 check_async_with_config, check_with_config,
53};
54pub use generator::{
55 BoxedGenerator, ConstantGenerator, Generator, GeneratorRegistry, OneOfGenerator,
56};
57pub use performance::{
58 LazyGenerator, ParallelConfig, ParallelPropertyTest, StreamingShrinkStrategy, check_parallel,
59 lazy,
60};
61pub use primitives::*;
64pub use property::{AsyncProperty, Property};
65pub use rng::{DefaultRngProvider, RngManager, RngProvider, create_rng, create_seeded_rng};
66pub use shrink::{AsyncShrinkEngine, ShrinkConfig, ShrinkEngine, ShrinkResult, Shrinkable};
67pub use statistics::{CoverageThresholdsBuilder, StatisticsCollector};
68pub use strategy::Strategy;
69pub use test_runner::{
70 DefaultFormatter, JsonFormatter, TestContext, TestOutputFormatter, TestResult, TestRunner,
71 VerboseFormatter,
72};
73
74pub use error::{PropertyResult, TestFailure, TestSuccess};
76
77pub use strategy::{just, one_of, range};
79
80#[cfg(feature = "derive")]
82pub use protest_derive::Generator;
83
84#[cfg(feature = "derive")]
86pub use protest_derive::property_test;
87
88#[cfg(feature = "derive")]
90pub use protest_derive::test_builder;
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95 use std::time::Duration;
96
97 #[test]
98 fn test_config_defaults() {
99 let test_config = TestConfig::default();
100 assert_eq!(test_config.iterations, 100);
101 assert_eq!(test_config.max_shrink_iterations, 1000);
102 assert_eq!(test_config.shrink_timeout, Duration::from_secs(10));
103 assert!(test_config.seed.is_none());
104 }
105
106 #[test]
107 fn test_generator_config_defaults() {
108 let gen_config = GeneratorConfig::default();
109 assert_eq!(gen_config.size_hint, 10);
110 assert_eq!(gen_config.max_depth, 5);
111 assert!(gen_config.custom_ranges.is_empty());
112 }
113
114 #[test]
115 fn test_global_config_defaults() {
116 let global_config = GlobalConfig::default();
117 assert_eq!(global_config.default_iterations, 100);
118 assert!(global_config.default_seed.is_none());
119 }
120
121 #[test]
122 fn test_property_error_display() {
123 let error = PropertyError::PropertyFailed {
124 message: "test failed".to_string(),
125 context: None,
126 iteration: None,
127 };
128 assert_eq!(format!("{}", error), "Property failed: test failed");
129
130 let error = PropertyError::ShrinkageTimeout {
131 iterations: 500,
132 last_successful_shrink: None,
133 };
134 assert_eq!(
135 format!("{}", error),
136 "Shrinkage timeout after 500 iterations"
137 );
138 }
139
140 #[test]
141 fn test_public_api_integration() {
142 use rand::thread_rng;
143
144 let strategy = just(42).zip(range(1, 10));
146 let mut rng = thread_rng();
147 let config = GeneratorConfig::default();
148
149 let (left, right) = strategy.generate(&mut rng, &config);
150 assert_eq!(left, 42);
151 assert!((1..=10).contains(&right));
152 }
153
154 #[test]
155 fn test_strategy_composition_public_api() {
156 use rand::thread_rng;
157
158 let strategy = range(1, 5)
160 .map(|x| x * 2)
161 .filter(|&x| x > 4)
162 .zip(just("test"));
163
164 let mut rng = thread_rng();
165 let config = GeneratorConfig::default();
166
167 let (number, text) = strategy.generate(&mut rng, &config);
168 assert!(number > 4);
169 assert!(number <= 10);
170 assert!(number % 2 == 0);
171 assert_eq!(text, "test");
172 }
173}