@@ -12,54 +12,91 @@ use tempfile::TempDir;
12
12
use super :: fs:: { std_filer:: StdFiler , FsStore } ;
13
13
use super :: in_memory:: { InMemoryJsonStore , InMemoryStore } ;
14
14
use super :: inspect:: InspectStore ;
15
- use super :: KvStore ;
15
+ use super :: { KvStore , StoreResult } ;
16
16
17
17
/// Verify that executing a sequence of store operations matches a simple model.
18
18
#[ test]
19
19
fn prop_store_ops_match_model ( ) {
20
- // Strategy to generate store operations: currently, just key / value pairs to save.
20
+ // FIXME: This value type parameter needs better handling.
21
+ type V = String ;
22
+
23
+ /// Helper: Represent store operations.
24
+ #[ derive( Debug ) ]
25
+ enum StoreOp {
26
+ Save { key : String , value : V } ,
27
+ Delete { key : String } ,
28
+ }
29
+ use StoreOp :: * ;
30
+ impl StoreOp {
31
+ /// Apply operation, and also check some invariants.
32
+ fn apply ( & self , store : & mut impl KvStore < V > ) -> StoreResult < ( ) > {
33
+ match self {
34
+ Save { key, value } => {
35
+ store. save ( key, value) ?;
36
+ assert_eq ! ( store. load( key) ?. as_ref( ) , Some ( value) ) ;
37
+ }
38
+ Delete { key } => {
39
+ store. delete ( key) ?;
40
+ assert_eq ! ( store. load( key) ?, None ) ;
41
+ }
42
+ } ;
43
+ Ok ( ( ) )
44
+ }
45
+ }
46
+
47
+ // Strategy to generate lists of store operations.
21
48
let store_ops_strategy = {
22
49
let keys = prop_oneof ! ( r"[a-z]{0,5}" , ".*" ) ;
23
50
let values = prop_oneof ! ( keys. clone( ) ) ; // TODO: Non-string values
51
+ let half_ops = prop_oneof ! (
52
+ ( Just ( "Save" ) , values. clone( ) . prop_map( Some ) ) ,
53
+ ( Just ( "Delete" ) , Just ( None ) ) ,
54
+ ) ;
24
55
25
56
// This strategy will generate key / value pairs with multiple values per key,
26
57
// and shuffle them to have some interleaving, for bugs that depend on that.
27
- proptest:: collection:: hash_map ( keys, proptest:: collection:: vec ( values , 0 ..10 ) , 0 ..10 )
58
+ proptest:: collection:: hash_map ( keys, proptest:: collection:: vec ( half_ops , 0 ..10 ) , 0 ..10 )
28
59
. prop_map ( flatten_key_values)
60
+ . prop_map ( |pairs : Vec < _ > | -> Vec < StoreOp > {
61
+ pairs
62
+ . into_iter ( )
63
+ . map ( |( key, half_op) | -> StoreOp {
64
+ match half_op {
65
+ ( "Save" , Some ( value) ) => Save { key, value } ,
66
+ ( "Delete" , None ) => Delete { key } ,
67
+ unexpected => panic ! ( "unexpected: {:?}" , unexpected) ,
68
+ }
69
+ } )
70
+ . collect ( )
71
+ } )
29
72
. prop_shuffle ( )
30
73
} ;
31
74
32
- fn test ( store_ops_vec : Vec < ( String , String ) > ) -> TestCaseResult {
33
- // FIXME: This value type parameter needs better handling.
34
- type V = String ;
75
+ /// Helper: Check that store state matches model.
76
+ fn check_state ( store1 : & impl InspectStore < V > , store2 : & impl InspectStore < V > ) -> TestCaseResult {
77
+ prop_assert_eq ! ( store1. as_map( ) , store2. as_map( ) ) ;
78
+ Ok ( ( ) )
79
+ }
35
80
81
+ fn test ( store_ops_vec : Vec < StoreOp > ) -> TestCaseResult {
36
82
// Init the models
37
- let mut store_model: InMemoryStore < V > = InMemoryStore :: default ( ) ;
38
- let mut store_model_json: InMemoryJsonStore = InMemoryJsonStore :: default ( ) ;
83
+ let ref mut store_model = InMemoryStore :: default ( ) ;
84
+ let ref mut store_model_json = InMemoryJsonStore :: default ( ) ;
39
85
40
86
// Init the store under test
41
87
let temp_dir = TempDir :: new ( ) . unwrap ( ) ;
42
- let mut store_fs: FsStore < StdFiler > =
43
- FsStore :: new ( & temp_dir, StdFiler ) . expect ( "FsStore::new failed" ) ;
44
-
45
- for ( k, v) in store_ops_vec {
46
- store_model
47
- . save ( & k, & v)
48
- . expect ( "InMemoryStore save failed!" ) ;
49
- store_model_json
50
- . save ( & k, & v)
51
- . expect ( "InMemoryJsonStore save failed!" ) ;
52
- store_fs. save ( & k, & v) . expect ( "FsStore save failed!" ) ;
88
+ let ref mut store_fs = FsStore :: new ( & temp_dir, StdFiler ) . expect ( "FsStore::new failed" ) ;
89
+
90
+ for ref op in store_ops_vec {
91
+ op. apply ( store_model) . unwrap ( ) ;
92
+ op. apply ( store_model_json) . unwrap ( ) ;
93
+ op. apply ( store_fs) . unwrap ( ) ;
53
94
54
95
// Models match each other
55
- prop_assert_eq ! ( store_model. as_map ( ) , store_model_json. as_map ( ) ) ;
96
+ check_state ( store_model, store_model_json) ? ;
56
97
// Models match store_fs
57
- prop_assert_eq ! ( store_model. as_map( ) , store_fs. as_map( ) ) ;
58
- // FIXME: explicit coercion for as_map()
59
- prop_assert_eq ! (
60
- store_model_json. as_map( ) as HashMap <String , V >,
61
- store_fs. as_map( )
62
- ) ;
98
+ check_state ( store_model, store_fs) ?;
99
+ check_state ( store_model_json, store_fs) ?;
63
100
}
64
101
65
102
temp_dir. close ( ) ?;
0 commit comments