@@ -2131,4 +2131,197 @@ mod tests {
21312131 assert_eq ! ( actual, expected, "bitmap_has_all: fixture={name}" ) ;
21322132 } ) ;
21332133 }
2134+
2135+ /// proptests for bitmap functions:
2136+ ///
2137+ /// - [x] bitmap_contains
2138+ /// - [x] bitmap_min
2139+ /// - [x] bitmap_max
2140+ /// - [x] bitmap_has_any
2141+ /// - [x] bitmap_has_all
2142+ ///
2143+ /// According to comment in src/common/column/tests/it/bitmap/assign_ops.rs,
2144+ /// following prop tests are ignored when using `miri`.
2145+ #[ cfg_attr( miri, ignore) ]
2146+ mod proptests {
2147+ use proptest:: bits:: BitSetLike ;
2148+ use proptest:: bits:: SampledBitSetStrategy ;
2149+ use proptest:: collection:: SizeRange ;
2150+ use proptest:: collection:: btree_map;
2151+ use proptest:: prelude:: * ;
2152+ use roaring:: RoaringBitmap ;
2153+
2154+ use super :: * ;
2155+
2156+ /// The random bits strategy.
2157+ ///
2158+ /// Generate random bits with [`Store::sampled`].
2159+ #[ derive( Clone , Debug ) ]
2160+ struct Store ( Vec < u16 > ) ;
2161+
2162+ impl Store {
2163+ fn sampled (
2164+ size : impl Into < SizeRange > ,
2165+ bits : impl Into < SizeRange > ,
2166+ ) -> SampledBitSetStrategy < Self > {
2167+ SampledBitSetStrategy :: new ( size. into ( ) , bits. into ( ) )
2168+ }
2169+ }
2170+
2171+ /// Implement BitSetLike as required by SampledBitSetStrategy.
2172+ impl BitSetLike for Store {
2173+ fn new_bitset ( max : usize ) -> Self {
2174+ assert ! ( max <= u16 :: MAX as usize + 1 ) ;
2175+ Store ( Vec :: new ( ) )
2176+ }
2177+ fn len ( & self ) -> usize {
2178+ u16:: MAX as usize + 1
2179+ }
2180+ fn test ( & self , bit : usize ) -> bool {
2181+ self . 0 . binary_search ( & ( bit as u16 ) ) . is_ok ( )
2182+ }
2183+ fn set ( & mut self , bit : usize ) {
2184+ let v = bit as u16 ;
2185+ if let Err ( pos) = self . 0 . binary_search ( & v) {
2186+ self . 0 . insert ( pos, v) ;
2187+ }
2188+ }
2189+ fn clear ( & mut self , bit : usize ) {
2190+ let v = bit as u16 ;
2191+ if let Ok ( pos) = self . 0 . binary_search ( & v) {
2192+ self . 0 . remove ( pos) ;
2193+ }
2194+ }
2195+ fn count ( & self ) -> usize {
2196+ self . 0 . len ( )
2197+ }
2198+ }
2199+
2200+ /// The container strategy.
2201+ ///
2202+ /// Generates:
2203+ /// 50% array container with 1 to 4096 values
2204+ /// 50% bitmap container with 4097 to 65536 values
2205+ fn container_strategy ( ) -> impl Strategy < Value = Vec < u16 > > {
2206+ prop_oneof ! [
2207+ Store :: sampled( 1 ..=4096 , ..=u16 :: MAX as usize ) . prop_map( |bs| bs. 0 ) ,
2208+ Store :: sampled( 4097 ..u16 :: MAX as usize , ..=u16 :: MAX as usize ) . prop_map( |bs| bs. 0 ) ,
2209+ ]
2210+ }
2211+
2212+ /// The RoaringBitmap strategy.
2213+ ///
2214+ /// Generate 0 to 16 containers, with containers from [`container_strategy`].
2215+ fn bitmap_strategy ( ) -> impl Strategy < Value = RoaringBitmap > {
2216+ btree_map ( 0u16 ..=16 , container_strategy ( ) , 0usize ..=16 ) . prop_map ( |map| {
2217+ let mut bitmap = RoaringBitmap :: new ( ) ;
2218+ for ( key, values) in map {
2219+ for v in values {
2220+ bitmap. insert ( ( key as u32 ) << 16 | v as u32 ) ;
2221+ }
2222+ }
2223+ bitmap
2224+ } )
2225+ }
2226+
2227+ /// The RoaringTreemap strategy.
2228+ ///
2229+ /// Generate 0 to 16 RoaringBitmaps, each generated by [`bitmap_strategy`].
2230+ fn tree_strategy ( ) -> impl Strategy < Value = RoaringTreemap > {
2231+ btree_map ( 0u32 ..=16 , bitmap_strategy ( ) , 0usize ..=16 ) . prop_map ( |map| {
2232+ let mut treemap = RoaringTreemap :: new ( ) ;
2233+ for ( key, bitmap) in map {
2234+ if !bitmap. is_empty ( ) {
2235+ for v in bitmap. iter ( ) {
2236+ treemap. insert ( ( key as u64 ) << 32 | v as u64 ) ;
2237+ }
2238+ }
2239+ }
2240+ treemap
2241+ } )
2242+ }
2243+
2244+ /// The serialization strategy.
2245+ ///
2246+ /// Serialize RoaringTreemap from [`tree_strategy`] into `Vec<u8>`:
2247+ /// 80% HybridBitmap
2248+ /// 10% Legacy
2249+ /// 10% Empty
2250+ fn serialization_strategy ( ) -> impl Strategy < Value = ( Vec < u8 > , RoaringTreemap ) > {
2251+ prop_oneof ! [
2252+ 8 => tree_strategy( ) . prop_map( |tree| {
2253+ let bm = HybridBitmap :: from_iter( tree. iter( ) ) ;
2254+ let mut buf = Vec :: new( ) ;
2255+ bm. serialize_into( & mut buf) . unwrap( ) ;
2256+ ( buf, tree)
2257+ } ) ,
2258+ 1 => tree_strategy( ) . prop_map( |tree| {
2259+ let mut buf = Vec :: new( ) ;
2260+ tree. serialize_into( & mut buf) . unwrap( ) ;
2261+ ( buf, tree)
2262+ } ) ,
2263+ 1 => Just ( ( Vec :: new( ) , RoaringTreemap :: new( ) ) ) ,
2264+ ]
2265+ }
2266+
2267+ /// The probe strategy, picks random value for bitmap_contains to probe.
2268+ ///
2269+ /// 50% hit: probe = random value from tree (via nth)
2270+ /// 50% miss: probe = random u64
2271+ fn probe_strategy ( ) -> impl Strategy < Value = ( Vec < u8 > , RoaringTreemap , u64 ) > {
2272+ ( serialization_strategy ( ) , any :: < bool > ( ) , any :: < u64 > ( ) ) . prop_map (
2273+ |( ( buf, tree) , is_hit, random_value) | {
2274+ let probe = if is_hit && !tree. is_empty ( ) {
2275+ let idx = ( random_value % tree. len ( ) ) as usize ;
2276+ tree. iter ( ) . nth ( idx) . unwrap_or ( random_value)
2277+ } else {
2278+ random_value
2279+ } ;
2280+ ( buf, tree, probe)
2281+ } ,
2282+ )
2283+ }
2284+
2285+ proptest ! {
2286+ // Make the test run faster by limiting the number of cases, running 32 cases
2287+ // took ~16 seconds in release, and ~160 in debug.
2288+ // One can override this by setting the `PROPTEST_CASES` environment variable.
2289+ #![ proptest_config( ProptestConfig :: with_cases( 32 ) ) ]
2290+
2291+ #[ test]
2292+ fn prop_bitmap_contains( ( buf, tree, value) in probe_strategy( ) ) {
2293+ let expected = tree. contains( value) ;
2294+ let actual = bitmap_contains( & buf, value) . unwrap( ) ;
2295+ assert_eq!( actual, expected) ;
2296+ }
2297+
2298+ #[ test]
2299+ fn prop_bitmap_min( ( buf, tree) in serialization_strategy( ) ) {
2300+ assert_eq!( bitmap_min( & buf) . unwrap( ) , tree. min( ) ) ;
2301+ }
2302+
2303+ #[ test]
2304+ fn prop_bitmap_max( ( buf, tree) in serialization_strategy( ) ) {
2305+ assert_eq!( bitmap_max( & buf) . unwrap( ) , tree. max( ) ) ;
2306+ }
2307+
2308+ #[ test]
2309+ fn prop_bitmap_has_any(
2310+ ( ( lhs_buf, lhs_tree) , ( rhs_buf, rhs_tree) ) in ( serialization_strategy( ) , serialization_strategy( ) )
2311+ ) {
2312+ let expected = !( lhs_tree & rhs_tree) . is_empty( ) ;
2313+ let actual = bitmap_has_any( & lhs_buf, & rhs_buf) . unwrap( ) ;
2314+ assert_eq!( actual, expected) ;
2315+ }
2316+
2317+ #[ test]
2318+ fn prop_bitmap_has_all(
2319+ ( ( lhs_buf, lhs_tree) , ( rhs_buf, rhs_tree) ) in ( serialization_strategy( ) , serialization_strategy( ) )
2320+ ) {
2321+ let expected = lhs_tree. is_superset( & rhs_tree) ;
2322+ let actual = bitmap_has_all( & lhs_buf, & rhs_buf) . unwrap( ) ;
2323+ assert_eq!( actual, expected) ;
2324+ }
2325+ }
2326+ }
21342327}
0 commit comments