@@ -9,36 +9,13 @@ use crate::queue::Queue;
99use crate :: unordered_map:: UnorderedMap ;
1010use crate :: vector:: Vector ;
1111use crate :: ERR_EMPTY ;
12+ use crate :: ERR_NOT_FOUND ;
13+ use evolve_testing:: proptest_config:: proptest_config;
1214use proptest:: prelude:: * ;
13- use std:: collections:: { HashMap , VecDeque } ;
15+ use std:: collections:: { BTreeMap , HashMap , VecDeque } ;
1416
1517const MAX_OPS : usize = 32 ;
1618const MAX_KEYS : usize = 16 ;
17- const DEFAULT_CASES : u32 = 128 ;
18- const CI_CASES : u32 = 32 ;
19-
20- fn proptest_cases ( ) -> u32 {
21- if let Ok ( value) = std:: env:: var ( "EVOLVE_PROPTEST_CASES" ) {
22- if let Ok ( parsed) = value. parse :: < u32 > ( ) {
23- if parsed > 0 {
24- return parsed;
25- }
26- }
27- }
28-
29- if std:: env:: var ( "EVOLVE_CI" ) . is_ok ( ) || std:: env:: var ( "CI" ) . is_ok ( ) {
30- return CI_CASES ;
31- }
32-
33- DEFAULT_CASES
34- }
35-
36- fn proptest_config ( ) -> proptest:: test_runner:: Config {
37- proptest:: test_runner:: Config {
38- cases : proptest_cases ( ) ,
39- ..Default :: default ( )
40- }
41- }
4219
4320proptest ! {
4421 #![ proptest_config( proptest_config( ) ) ]
@@ -216,3 +193,76 @@ proptest! {
216193 prop_assert_eq!( actual_pairs, expected_pairs) ;
217194 }
218195}
196+
197+ // ============================================================================
198+ // Map model-based test
199+ // ============================================================================
200+
201+ #[ derive( Clone , Debug ) ]
202+ enum MapOp {
203+ Set { key : u64 , value : u64 } ,
204+ Get { key : u64 } ,
205+ Remove { key : u64 } ,
206+ Exists { key : u64 } ,
207+ }
208+
209+ fn map_ops_strategy ( ) -> impl Strategy < Value = Vec < MapOp > > {
210+ let keys: Vec < u64 > = ( 0 ..MAX_KEYS as u64 ) . collect ( ) ;
211+
212+ let set = ( proptest:: sample:: select ( keys. clone ( ) ) , any :: < u64 > ( ) )
213+ . prop_map ( |( key, value) | MapOp :: Set { key, value } ) ;
214+ let get = proptest:: sample:: select ( keys. clone ( ) ) . prop_map ( |key| MapOp :: Get { key } ) ;
215+ let remove = proptest:: sample:: select ( keys. clone ( ) ) . prop_map ( |key| MapOp :: Remove { key } ) ;
216+ let exists = proptest:: sample:: select ( keys) . prop_map ( |key| MapOp :: Exists { key } ) ;
217+
218+ let op = prop_oneof ! [ 4 => set, 2 => get, 2 => remove, 1 => exists] ;
219+ proptest:: collection:: vec ( op, 0 ..=MAX_OPS )
220+ }
221+
222+ proptest ! {
223+ #![ proptest_config( proptest_config( ) ) ]
224+
225+ #[ test]
226+ fn prop_map_matches_model( ops in map_ops_strategy( ) ) {
227+ let map: Map <u64 , u64 > = Map :: new( 50 ) ;
228+ let mut env = MockEnvironment :: new( 1 , 2 ) ;
229+ let mut model: BTreeMap <u64 , u64 > = BTreeMap :: new( ) ;
230+
231+ for op in ops {
232+ match op {
233+ MapOp :: Set { key, value } => {
234+ map. set( & key, & value, & mut env) . unwrap( ) ;
235+ model. insert( key, value) ;
236+ }
237+ MapOp :: Get { key } => {
238+ let actual = map. may_get( & key, & mut env) . unwrap( ) ;
239+ let expected = model. get( & key) . copied( ) ;
240+ prop_assert_eq!( actual, expected) ;
241+
242+ // Also verify get() returns ERR_NOT_FOUND for missing keys
243+ if expected. is_none( ) {
244+ prop_assert_eq!( map. get( & key, & mut env) . unwrap_err( ) , ERR_NOT_FOUND ) ;
245+ } else {
246+ prop_assert_eq!( map. get( & key, & mut env) . unwrap( ) , expected. unwrap( ) ) ;
247+ }
248+ }
249+ MapOp :: Remove { key } => {
250+ map. remove( & key, & mut env) . unwrap( ) ;
251+ model. remove( & key) ;
252+ }
253+ MapOp :: Exists { key } => {
254+ let actual = map. exists( & key, & mut env) . unwrap( ) ;
255+ let expected = model. contains_key( & key) ;
256+ prop_assert_eq!( actual, expected) ;
257+ }
258+ }
259+ }
260+
261+ // Final state: verify all keys match the model
262+ for key in 0 ..MAX_KEYS as u64 {
263+ let expected = model. get( & key) . copied( ) ;
264+ let actual = map. may_get( & key, & mut env) . unwrap( ) ;
265+ prop_assert_eq!( actual, expected) ;
266+ }
267+ }
268+ }
0 commit comments