From f458187d2836ef3061d3f662d2279e10f9de77bf Mon Sep 17 00:00:00 2001 From: teor Date: Wed, 7 Jul 2021 14:45:44 +1000 Subject: [PATCH 1/2] Add a TypeNameToDebug formatter to zebra_chain This formatter makes it much easier to diagnose proptest errors. It will be used in a future PR. Implement Arbitrary and DerefMut for all the formatters. Also make the formatter type bounds consistent, to produce better compiler errors. --- zebra-chain/src/fmt.rs | 101 ++++++++++++++++++++++++++++++++++++----- 1 file changed, 90 insertions(+), 11 deletions(-) diff --git a/zebra-chain/src/fmt.rs b/zebra-chain/src/fmt.rs index e0635eedd43..601ff154af5 100644 --- a/zebra-chain/src/fmt.rs +++ b/zebra-chain/src/fmt.rs @@ -2,20 +2,54 @@ use std::{fmt, ops}; +#[cfg(any(test, feature = "proptest-impl"))] +use proptest::prelude::*; +#[cfg(any(test, feature = "proptest-impl"))] +use proptest_derive::Arbitrary; + +/// Wrapper to override `Debug`, redirecting it to the type's name. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))] +pub struct TypeNameToDebug(pub T); + +impl fmt::Debug for TypeNameToDebug { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str(std::any::type_name::()) + } +} + +impl ops::Deref for TypeNameToDebug { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl ops::DerefMut for TypeNameToDebug { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl From for TypeNameToDebug { + fn from(t: T) -> Self { + Self(t) + } +} + /// Wrapper to override `Debug`, redirecting it to the `Display` impl. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct DisplayToDebug(pub T); +#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))] +pub struct DisplayToDebug(pub T); -impl fmt::Debug for DisplayToDebug -where - T: fmt::Display, -{ +impl fmt::Debug for DisplayToDebug { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { self.0.fmt(f) } } -impl ops::Deref for DisplayToDebug { +impl ops::Deref for DisplayToDebug { type Target = T; fn deref(&self) -> &Self::Target { @@ -23,7 +57,13 @@ impl ops::Deref for DisplayToDebug { } } -impl From for DisplayToDebug { +impl ops::DerefMut for DisplayToDebug { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl From for DisplayToDebug { fn from(t: T) -> Self { Self(t) } @@ -34,7 +74,10 @@ impl From for DisplayToDebug { /// For collections and exact size iterators, it only displays the /// collection/iterator type, the item type, and the length. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct SummaryDebug(pub CollectionOrIter); +pub struct SummaryDebug(pub CollectionOrIter) +where + CollectionOrIter: IntoIterator + Clone, + ::IntoIter: ExactSizeIterator; impl fmt::Debug for SummaryDebug where @@ -52,7 +95,11 @@ where } } -impl ops::Deref for SummaryDebug { +impl ops::Deref for SummaryDebug +where + CollectionOrIter: IntoIterator + Clone, + ::IntoIter: ExactSizeIterator, +{ type Target = CollectionOrIter; fn deref(&self) -> &Self::Target { @@ -60,7 +107,21 @@ impl ops::Deref for SummaryDebug { } } -impl From for SummaryDebug { +impl ops::DerefMut for SummaryDebug +where + CollectionOrIter: IntoIterator + Clone, + ::IntoIter: ExactSizeIterator, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } +} + +impl From for SummaryDebug +where + CollectionOrIter: IntoIterator + Clone, + ::IntoIter: ExactSizeIterator, +{ fn from(collection: CollectionOrIter) -> Self { Self(collection) } @@ -68,7 +129,8 @@ impl From for SummaryDebug impl IntoIterator for SummaryDebug where - CollectionOrIter: IntoIterator, + CollectionOrIter: IntoIterator + Clone, + ::IntoIter: ExactSizeIterator, { type Item = ::Item; type IntoIter = ::IntoIter; @@ -77,3 +139,20 @@ where self.0.into_iter() } } + +#[cfg(any(test, feature = "proptest-impl"))] +impl Arbitrary for SummaryDebug +where + CollectionOrIter: Arbitrary + IntoIterator + Clone + 'static, + ::IntoIter: ExactSizeIterator, +{ + type Parameters = ::Parameters; + + fn arbitrary_with(args: Self::Parameters) -> Self::Strategy { + CollectionOrIter::arbitrary_with(args) + .prop_map_into() + .boxed() + } + + type Strategy = BoxedStrategy; +} From 6d15b88a505e2d633bf8a78ba38d820b570f3344 Mon Sep 17 00:00:00 2001 From: teor Date: Fri, 9 Jul 2021 12:14:45 +1000 Subject: [PATCH 2/2] Clarify how TypeNameToDebug actually works Co-authored-by: Janito Vaqueiro Ferreira Filho --- zebra-chain/src/fmt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/zebra-chain/src/fmt.rs b/zebra-chain/src/fmt.rs index 601ff154af5..ff3bbd09d22 100644 --- a/zebra-chain/src/fmt.rs +++ b/zebra-chain/src/fmt.rs @@ -7,7 +7,7 @@ use proptest::prelude::*; #[cfg(any(test, feature = "proptest-impl"))] use proptest_derive::Arbitrary; -/// Wrapper to override `Debug`, redirecting it to the type's name. +/// Wrapper to override `Debug`, redirecting it to only output the type's name. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))] pub struct TypeNameToDebug(pub T);