Add proptests for sled conversions (#1253)

* Add proptests for sled conversions
* document primary helper functions
This commit is contained in:
Jane Lusby 2020-11-04 20:47:56 -08:00 committed by GitHub
parent 1e3cf6dc5c
commit 06e74d15ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 150 additions and 7 deletions

View File

@ -9,6 +9,7 @@ use zebra_chain::{
sprout, transaction, transparent,
};
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct TransactionLocation {
pub height: block::Height,
pub index: u32,
@ -123,6 +124,13 @@ impl IntoSled for block::Hash {
}
}
impl FromSled for block::Hash {
fn from_ivec(bytes: sled::IVec) -> Self {
let array = bytes.as_ref().try_into().unwrap();
Self(array)
}
}
impl IntoSled for &sprout::Nullifier {
type Bytes = [u8; 32];
@ -159,13 +167,6 @@ impl IntoSled for () {
}
}
impl FromSled for block::Hash {
fn from_ivec(bytes: sled::IVec) -> Self {
let array = bytes.as_ref().try_into().unwrap();
Self(array)
}
}
impl IntoSled for block::Height {
type Bytes = [u8; 4];
@ -274,3 +275,145 @@ impl SledDeserialize for sled::Tree {
value_bytes.map(V::from_ivec)
}
}
#[cfg(test)]
mod tests {
use super::*;
use proptest::{arbitrary::any, prelude::*};
use std::ops::Deref;
impl Arbitrary for TransactionLocation {
type Parameters = ();
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
(any::<block::Height>(), any::<u32>())
.prop_map(|(height, index)| Self { height, index })
.boxed()
}
type Strategy = BoxedStrategy<Self>;
}
fn round_trip<T>(input: T) -> T
where
T: IntoSled + FromSled,
{
let bytes = input.into_ivec();
T::from_ivec(bytes)
}
/// The round trip test covers types that are used as value field in a sled
/// Tree. Only these types are ever deserialized, and so they're the only
/// ones that implement both `IntoSled` and `FromSled`.
fn assert_round_trip<T>(input: T)
where
T: IntoSled + FromSled + Clone + PartialEq + std::fmt::Debug,
{
let before = input.clone();
let after = round_trip(input);
assert_eq!(before, after);
}
/// This test asserts that types that are used as sled keys behave correctly.
/// Any type that implements `IntoIVec` can be used as a sled key. The value
/// is serialized via `IntoSled::into_ivec` when the `key`, `value` pair is
/// inserted into the sled tree. The `as_bytes` impl on the other hand is
/// called for most other operations when comparing a key against existing
/// keys in the sled database, such as `contains`.
fn assert_as_bytes_matches_ivec<T>(input: T)
where
T: IntoSled + Clone,
{
let before = input.clone();
let ivec = input.into_ivec();
assert_eq!(before.as_bytes().as_ref(), ivec.as_ref());
}
#[test]
fn roundtrip_transaction_location() {
zebra_test::init();
proptest!(|(val in any::<TransactionLocation>())| assert_round_trip(val));
}
#[test]
fn roundtrip_block_hash() {
zebra_test::init();
proptest!(|(val in any::<block::Hash>())| assert_round_trip(val));
}
#[test]
fn roundtrip_block_height() {
zebra_test::init();
proptest!(|(val in any::<block::Height>())| assert_round_trip(val));
}
#[test]
fn roundtrip_block() {
zebra_test::init();
proptest!(|(block in any::<Block>())| {
let bytes = block.into_ivec();
let deserialized: Arc<Block> = FromSled::from_ivec(bytes);
assert_eq!(&block, deserialized.deref());
});
}
#[test]
fn roundtrip_transparent_output() {
zebra_test::init();
proptest!(|(block in any::<transparent::Output>())| {
let bytes = block.into_ivec();
let deserialized: transparent::Output = FromSled::from_ivec(bytes);
assert_eq!(block, deserialized);
});
}
#[test]
fn key_matches_ivec_transaction_location() {
zebra_test::init();
proptest!(|(val in any::<TransactionLocation>())| assert_as_bytes_matches_ivec(val));
}
#[test]
fn key_matches_ivec_trans_hash() {
zebra_test::init();
proptest!(|(val in any::<transaction::Hash>())| assert_as_bytes_matches_ivec(val));
}
#[test]
fn key_matches_ivec_block_hash() {
zebra_test::init();
proptest!(|(val in any::<block::Hash>())| assert_as_bytes_matches_ivec(val));
}
#[test]
fn key_matches_ivec_sprout_nullifier() {
zebra_test::init();
proptest!(|(val in any::<sprout::Nullifier>())| assert_as_bytes_matches_ivec(&val));
}
#[test]
fn key_matches_ivec_sapling_nullifier() {
zebra_test::init();
proptest!(|(val in any::<sapling::Nullifier>())| assert_as_bytes_matches_ivec(&val));
}
#[test]
fn key_matches_ivec_block_height() {
zebra_test::init();
proptest!(|(val in any::<block::Height>())| assert_as_bytes_matches_ivec(val));
}
#[test]
fn key_matches_ivec_transparent_output() {
zebra_test::init();
proptest!(|(val in any::<transparent::Output>())| assert_as_bytes_matches_ivec(&val));
}
#[test]
fn key_matches_ivec_transparent_outpoint() {
zebra_test::init();
proptest!(|(val in any::<transparent::OutPoint>())| assert_as_bytes_matches_ivec(val));
}
}