Skip to content

Commit

Permalink
Add fuzz tests for StorageVec::binary_search* (#867)
Browse files Browse the repository at this point in the history
* Add fuzz tests for `StorageVec::binary_search*`

* Decrease number of fuzz tests which are run

We found that bugs are usually already found
with low numbers.

* Apply suggestions from code review

Co-authored-by: Hernando Castano <[email protected]>

* Improve expect

* Fix variable naming

Co-authored-by: Hernando Castano <[email protected]>
  • Loading branch information
Michael Müller and HCastano authored Jul 21, 2021
1 parent 5fd8f87 commit bffe9bf
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -415,7 +415,7 @@ fuzz-tests:
<<: *test-refs
variables:
# The QUICKCHECK_TESTS default is 100
QUICKCHECK_TESTS: 20000
QUICKCHECK_TESTS: 5000
rules:
- if: $CI_PIPELINE_SOURCE == "schedule"
- if: $CI_COMMIT_REF_NAME == "master"
Expand Down
108 changes: 107 additions & 1 deletion crates/storage/src/collections/vec/fuzz_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::{
},
Pack,
};

use itertools::Itertools;
use quickcheck::{
Arbitrary,
Gen,
Expand Down Expand Up @@ -83,3 +83,109 @@ crate::fuzz_storage!("vec_1", StorageVec<u32>);
crate::fuzz_storage!("vec_2", StorageVec<Option<Pack<Option<u32>>>>);
crate::fuzz_storage!("vec_3", StorageVec<(bool, (u32, u128))>);
crate::fuzz_storage!("vec_4", StorageVec<(i128, u32, bool, Option<(u32, i128)>)>);

#[quickcheck]
fn fuzz_binary_search(mut std_vec: Vec<i32>) {
// given
if std_vec.len() == 0 {
return
}
let original_std_vec = std_vec.clone();
std_vec.sort();
let ink_vec = StorageVec::from_iter(std_vec.clone());

for x in original_std_vec {
// when
let index = std_vec
.binary_search(&x)
.expect("`x` must be found in `Vec`") as u32;
let ink_index = ink_vec
.binary_search(&x)
.expect("`x` must be found in `StorageVec`");
let ink_index_by = ink_vec
.binary_search_by(|by_x| by_x.cmp(&x))
.expect("`x` must be found in `StorageVec`");

// then
assert_eq!(index, ink_index);
assert_eq!(index, ink_index_by);
}
}

#[quickcheck]
fn fuzz_binary_search_nonexistent(std_vec: Vec<i32>) {
// given
if std_vec.len() == 0 {
return
}
let mut unique_std_vec: Vec<i32> = std_vec.into_iter().unique().collect();
let removed_el = unique_std_vec
.pop()
.expect("length is non-zero, first element must exist");
unique_std_vec.sort();
let ink_vec = StorageVec::from_iter(unique_std_vec.clone());

// when
let std_err_index = unique_std_vec
.binary_search(&removed_el)
.expect_err("element must not be found") as u32;
let ink_err_index = ink_vec
.binary_search(&removed_el)
.expect_err("element must not be found");
let ink_search_by_err_index = ink_vec
.binary_search_by(|by_x| by_x.cmp(&removed_el))
.expect_err("element must not be found");

// then
assert_eq!(std_err_index, ink_err_index);
assert_eq!(std_err_index, ink_search_by_err_index);
}

#[quickcheck]
fn fuzz_binary_search_by_key(mut std_vec: Vec<(i32, i32)>) {
// given
if std_vec.len() == 0 {
return
}
let original_std_vec = std_vec.clone();
std_vec.sort_by_key(|&(_a, b)| b);
let ink_vec = StorageVec::from_iter(std_vec.clone());

for (_x, y) in original_std_vec {
// when
let std_index = std_vec
.binary_search_by_key(&y, |&(_a, b)| b)
.expect("`y` must be found in `Vec`") as u32;
let ink_index = ink_vec
.binary_search_by_key(&y, |&(_a, b)| b)
.expect("`y` must be found in `StorageVec`");

// then
assert_eq!(std_index, ink_index);
}
}
#[quickcheck]
fn fuzz_binary_search_by_key_nonexistent(std_vec: Vec<(i32, i32)>) {
// given
if std_vec.len() == 0 {
return
}
let mut unique_std_vec: Vec<(i32, i32)> =
std_vec.into_iter().unique_by(|&(_a, b)| b).collect();
let removed_el = unique_std_vec
.pop()
.expect("length is non-zero, first element must exist");
unique_std_vec.sort_by_key(|&(_a, b)| b);
let ink_vec = StorageVec::from_iter(unique_std_vec.clone());

// when
let std_err_index = unique_std_vec
.binary_search_by_key(&removed_el.1, |&(_a, b)| b)
.expect_err("element must not be found in `Vec`") as u32;
let ink_err_index = ink_vec
.binary_search_by_key(&removed_el.1, |&(_a, b)| b)
.expect_err("element must not be found in `StorageVec`");

// then
assert_eq!(std_err_index, ink_err_index);
}

0 comments on commit bffe9bf

Please sign in to comment.