Repository: ParkMyCar/compact_str
Pull request #68 (2022-03-27 04:45:08)

chore: Cleanup use of proptest with test-strategy
This PR uses the newer [`test-strategy`](https://github.com/frozenlib/test-strategy) crate, specifically the `#[proptest]` macro to, IMO, make the use a `proptest` a bit cleaner


Patch:
diff --git a/compact_str/Cargo.toml b/compact_str/Cargo.toml
index 70f390f5..a3c6fe1e 100644
--- a/compact_str/Cargo.toml
+++ b/compact_str/Cargo.toml
@@ -19,3 +19,4 @@ serde = { version = "1", optional = true }
 
 [dev-dependencies]
 proptest = { version = "1", default-features = false, features = ["std"] }
+test-strategy = "0.1.2"
diff --git a/compact_str/src/features/bytes.rs b/compact_str/src/features/bytes.rs
index d4a3e9cc..28a969b7 100644
--- a/compact_str/src/features/bytes.rs
+++ b/compact_str/src/features/bytes.rs
@@ -70,54 +70,50 @@ mod test {
     use std::io::Cursor;
 
     use proptest::prelude::*;
-    use proptest::strategy::Strategy;
+    use test_strategy::proptest;
 
+    use crate::tests::{
+        rand_bytes,
+        rand_unicode,
+    };
     use crate::CompactStr;
 
     const MAX_SIZE: usize = core::mem::size_of::<String>();
 
-    // generates random unicode strings, upto 80 chars long
-    fn rand_unicode() -> impl Strategy<Value = String> {
-        proptest::collection::vec(proptest::char::any(), 0..80)
-            .prop_map(|v| v.into_iter().collect())
-    }
-
-    proptest! {
-        #[test]
-        #[cfg_attr(miri, ignore)]
-        fn test_buffers_roundtrip(word in rand_unicode()) {
-            let mut buf = Cursor::new(word.as_bytes());
-            let compact = CompactStr::from_utf8_buf(&mut buf).unwrap();
+    #[proptest]
+    #[cfg_attr(miri, ignore)]
+    fn test_buffers_roundtrip(#[strategy(rand_unicode())] word: String) {
+        let mut buf = Cursor::new(word.as_bytes());
+        let compact = CompactStr::from_utf8_buf(&mut buf).unwrap();
 
-            prop_assert_eq!(&word, &compact);
-        }
+        proptest::prop_assert_eq!(&word, &compact);
+    }
 
-        #[test]
-        #[cfg_attr(miri, ignore)]
-        fn test_allocated_properly(word in rand_unicode()) {
-            let mut buf = Cursor::new(word.as_bytes());
-            let compact = CompactStr::from_utf8_buf(&mut buf).unwrap();
+    #[proptest]
+    #[cfg_attr(miri, ignore)]
+    fn test_allocated_properly(#[strategy(rand_unicode())] word: String) {
+        let mut buf = Cursor::new(word.as_bytes());
+        let compact = CompactStr::from_utf8_buf(&mut buf).unwrap();
 
-            if word.len() <= MAX_SIZE {
-                prop_assert!(!compact.is_heap_allocated())
-            } else {
-                prop_assert!(compact.is_heap_allocated())
-            }
+        if word.len() <= MAX_SIZE {
+            proptest::prop_assert!(!compact.is_heap_allocated())
+        } else {
+            proptest::prop_assert!(compact.is_heap_allocated())
         }
+    }
 
-        #[test]
-        #[cfg_attr(miri, ignore)]
-        fn test_only_accept_valid_utf8(bytes in proptest::collection::vec(any::<u8>(), 0..80)) {
-            let mut buf = Cursor::new(bytes.as_slice());
+    #[proptest]
+    #[cfg_attr(miri, ignore)]
+    fn test_only_accept_valid_utf8(#[strategy(rand_bytes())] bytes: Vec<u8>) {
+        let mut buf = Cursor::new(bytes.as_slice());
 
-            let compact_result = CompactStr::from_utf8_buf(&mut buf);
-            let str_result = core::str::from_utf8(bytes.as_slice());
+        let compact_result = CompactStr::from_utf8_buf(&mut buf);
+        let str_result = core::str::from_utf8(bytes.as_slice());
 
-            match (compact_result, str_result) {
-                (Ok(c), Ok(s)) => prop_assert_eq!(c, s),
-                (Err(c_err), Err(s_err)) => prop_assert_eq!(c_err, s_err),
-                _ => panic!("CompactStr and core::str read UTF-8 differently?"),
-            }
+        match (compact_result, str_result) {
+            (Ok(c), Ok(s)) => prop_assert_eq!(c, s),
+            (Err(c_err), Err(s_err)) => prop_assert_eq!(c_err, s_err),
+            _ => panic!("CompactStr and core::str read UTF-8 differently?"),
         }
     }
 }
diff --git a/compact_str/src/repr/arc/mod.rs b/compact_str/src/repr/arc/mod.rs
index fdea33b7..21aadd20 100644
--- a/compact_str/src/repr/arc/mod.rs
+++ b/compact_str/src/repr/arc/mod.rs
@@ -206,9 +206,10 @@ impl Extend<String> for ArcString {
 #[cfg(test)]
 mod test {
     use proptest::prelude::*;
-    use proptest::strategy::Strategy;
+    use test_strategy::proptest;
 
     use super::ArcString;
+    use crate::tests::rand_unicode;
 
     #[test]
     fn test_empty() {
@@ -277,19 +278,11 @@ mod test {
         assert_eq!(arc_str.len, example.len());
     }
 
-    // generates random unicode strings, upto 80 chars long
-    fn rand_unicode() -> impl Strategy<Value = String> {
-        proptest::collection::vec(proptest::char::any(), 0..80)
-            .prop_map(|v| v.into_iter().collect())
-    }
-
-    proptest! {
-        #[test]
-        #[cfg_attr(miri, ignore)]
-        fn test_strings_roundtrip(word in rand_unicode()) {
-            let arc_str = ArcString::from(word.as_str());
-            prop_assert_eq!(&word, arc_str.as_str());
-        }
+    #[proptest]
+    #[cfg_attr(miri, ignore)]
+    fn test_strings_roundtrip(#[strategy(rand_unicode())] word: String) {
+        let arc_str = ArcString::from(word.as_str());
+        prop_assert_eq!(&word, arc_str.as_str());
     }
 }
 
diff --git a/compact_str/src/repr/boxed/mod.rs b/compact_str/src/repr/boxed/mod.rs
index f0e026eb..317ef94d 100644
--- a/compact_str/src/repr/boxed/mod.rs
+++ b/compact_str/src/repr/boxed/mod.rs
@@ -466,11 +466,11 @@ impl Extend<String> for BoxString {
 
 #[cfg(test)]
 mod tests {
-    use proptest::collection::SizeRange;
     use proptest::prelude::*;
-    use proptest::strategy::Strategy;
+    use test_strategy::proptest;
 
     use super::BoxString;
+    use crate::tests::rand_unicode;
 
     const SIXTEEN_MB: usize = 16 * 1024 * 1024;
 
@@ -691,27 +691,20 @@ mod tests {
         assert_eq!(&format!("{}!hello!", string), box_string.as_str());
     }
 
-    // generates random unicode strings, of a given size
-    fn rand_unicode(size: impl Into<SizeRange>) -> impl Strategy<Value = String> {
-        proptest::collection::vec(proptest::char::any(), size).prop_map(|v| v.into_iter().collect())
+    #[proptest]
+    #[cfg_attr(miri, ignore)]
+    fn test_strings_roundtrip(#[strategy(rand_unicode())] word: String) {
+        let box_str = BoxString::from(word.as_str());
+        prop_assert_eq!(&word, box_str.as_str());
     }
 
-    proptest! {
-        #[test]
-        #[cfg_attr(miri, ignore)]
-        fn test_strings_roundtrip(word in rand_unicode(0..80)) {
-            let box_str = BoxString::from(word.as_str());
-            prop_assert_eq!(&word, box_str.as_str());
-        }
-
-        #[test]
-        #[cfg_attr(miri, ignore)]
-        fn test_from_string(word in rand_unicode(0..80)) {
-            let s: String = word.clone();
-            let box_str = BoxString::from_string(s);
+    #[proptest]
+    #[cfg_attr(miri, ignore)]
+    fn test_from_string(#[strategy(rand_unicode())] word: String) {
+        let s: String = word.clone();
+        let box_str = BoxString::from_string(s);
 
-            prop_assert_eq!(&word, box_str.as_str());
-        }
+        prop_assert_eq!(&word, box_str.as_str());
     }
 }
 
diff --git a/compact_str/src/repr/inline.rs b/compact_str/src/repr/inline.rs
index 1ba9110c..b8806d37 100644
--- a/compact_str/src/repr/inline.rs
+++ b/compact_str/src/repr/inline.rs
@@ -116,12 +116,13 @@ mod tests {
     use std::convert::TryFrom;
 
     use proptest::prelude::*;
+    use test_strategy::proptest;
 
     use super::{
         InlineString,
         MAX_SIZE,
     };
-    use crate::tests::rand_unicode_bytes;
+    use crate::tests::rand_unicode_with_max_len;
 
     #[test]
     fn test_sanity() {
@@ -133,15 +134,13 @@ mod tests {
         assert_eq!(inline.capacity(), MAX_SIZE);
     }
 
-    proptest! {
-        #[test]
-        #[cfg_attr(miri, ignore)]
-        fn test_roundtrip(s in rand_unicode_bytes(MAX_SIZE)) {
-            let inline = InlineString::new(&s);
+    #[proptest]
+    #[cfg_attr(miri, ignore)]
+    fn test_roundtrip(#[strategy(rand_unicode_with_max_len(MAX_SIZE))] s: String) {
+        let inline = InlineString::new(&s);
 
-            assert_eq!(inline.as_str(), s);
-            assert_eq!(inline.len(), s.len());
-        }
+        prop_assert_eq!(inline.len(), s.len());
+        prop_assert_eq!(inline.as_str(), s);
     }
 
     #[test]


Test patch:
diff --git a/compact_str/src/tests.rs b/compact_str/src/tests.rs
index 374b59f6..67779f6d 100644
--- a/compact_str/src/tests.rs
+++ b/compact_str/src/tests.rs
@@ -2,6 +2,7 @@ use std::str::FromStr;
 
 use proptest::prelude::*;
 use proptest::strategy::Strategy;
+use test_strategy::proptest;
 
 use crate::CompactStr;
 
@@ -10,13 +11,18 @@ const MAX_SIZE: usize = 24;
 #[cfg(target_pointer_width = "32")]
 const MAX_SIZE: usize = 12;
 
-// generates random unicode strings, upto 80 chars long
-fn rand_unicode() -> impl Strategy<Value = String> {
+/// generates random unicode strings, upto 80 chars long
+pub fn rand_unicode() -> impl Strategy<Value = String> {
     proptest::collection::vec(proptest::char::any(), 0..80).prop_map(|v| v.into_iter().collect())
 }
 
+/// generates a random collection of bytes, upto 80 bytes long
+pub fn rand_bytes() -> impl Strategy<Value = Vec<u8>> {
+    proptest::collection::vec(any::<u8>(), 0..80)
+}
+
 /// [`proptest::strategy::Strategy`] that generates [`String`]s with up to `len` bytes
-pub fn rand_unicode_bytes(len: usize) -> impl Strategy<Value = String> {
+pub fn rand_unicode_with_max_len(len: usize) -> impl Strategy<Value = String> {
     proptest::collection::vec(proptest::char::any(), 0..len).prop_map(move |chars| {
         let mut len_utf8 = 0;
         chars
@@ -29,7 +35,7 @@ pub fn rand_unicode_bytes(len: usize) -> impl Strategy<Value = String> {
     })
 }
 
-// generates groups upto 40 strings long of random unicode strings, upto 80 chars long
+/// generates groups upto 40 strings long of random unicode strings, upto 80 chars long
 fn rand_unicode_collection() -> impl Strategy<Value = Vec<String>> {
     proptest::collection::vec(rand_unicode(), 0..40)
 }
@@ -43,133 +49,133 @@ fn assert_allocated_properly(compact: &CompactStr) {
     }
 }
 
-proptest! {
-    #[test]
-    #[cfg_attr(miri, ignore)]
-    fn test_strings_roundtrip(word in rand_unicode()) {
-        let compact = CompactStr::new(&word);
-        prop_assert_eq!(&word, &compact);
-    }
+#[proptest]
+#[cfg_attr(miri, ignore)]
+fn test_strings_roundtrip(#[strategy(rand_unicode())] word: String) {
+    let compact = CompactStr::new(&word);
+    prop_assert_eq!(&word, &compact);
+}
 
+#[proptest]
+#[cfg_attr(miri, ignore)]
+fn test_strings_allocated_properly(#[strategy(rand_unicode())] word: String) {
+    let compact = CompactStr::new(&word);
+    assert_allocated_properly(&compact);
+}
 
-    #[test]
-    #[cfg_attr(miri, ignore)]
-    fn test_strings_allocated_properly(word in rand_unicode()) {
-        let compact = CompactStr::new(&word);
-        assert_allocated_properly(&compact);
-    }
+#[proptest]
+#[cfg_attr(miri, ignore)]
+fn test_char_iterator_roundtrips(#[strategy(rand_unicode())] word: String) {
+    let compact: CompactStr = word.clone().chars().collect();
+    prop_assert_eq!(&word, &compact)
+}
 
-    #[test]
-    #[cfg_attr(miri, ignore)]
-    fn test_char_iterator_roundtrips(word in rand_unicode()) {
-        let compact: CompactStr = word.clone().chars().collect();
-        prop_assert_eq!(&word, &compact)
-    }
+#[proptest]
+#[cfg_attr(miri, ignore)]
+fn test_string_iterator_roundtrips(#[strategy(rand_unicode_collection())] collection: Vec<String>) {
+    let compact: CompactStr = collection.clone().into_iter().collect();
+    let word: String = collection.into_iter().collect();
+    prop_assert_eq!(&word, &compact);
+}
 
-    #[test]
-    #[cfg_attr(miri, ignore)]
-    fn test_string_iterator_roundtrips(collection in rand_unicode_collection()) {
-        let compact: CompactStr = collection.clone().into_iter().collect();
-        let word: String = collection.into_iter().collect();
-        prop_assert_eq!(&word, &compact);
-    }
+#[proptest]
+#[cfg_attr(miri, ignore)]
+fn test_from_bytes_roundtrips(#[strategy(rand_unicode())] word: String) {
+    let bytes = word.into_bytes();
+    let compact = CompactStr::from_utf8(&bytes).unwrap();
+    let word = String::from_utf8(bytes).unwrap();
 
-    #[test]
-    #[cfg_attr(miri, ignore)]
-    fn test_from_bytes_roundtrips(word in rand_unicode()) {
-        let bytes = word.into_bytes();
-        let compact = CompactStr::from_utf8(&bytes).unwrap();
-        let word = String::from_utf8(bytes).unwrap();
+    prop_assert_eq!(compact, word);
+}
 
-        prop_assert_eq!(compact, word);
-    }
+#[proptest]
+#[cfg_attr(miri, ignore)]
+fn test_from_bytes_only_valid_utf8(#[strategy(rand_bytes())] bytes: Vec<u8>) {
+    let compact_result = CompactStr::from_utf8(&bytes);
+    let word_result = String::from_utf8(bytes);
 
-    #[test]
-    #[cfg_attr(miri, ignore)]
-    fn test_from_bytes_only_valid_utf8(bytes in proptest::collection::vec(any::<u8>(), 0..80)) {
-        let compact_result = CompactStr::from_utf8(&bytes);
-        let word_result = String::from_utf8(bytes);
-
-        match (compact_result, word_result) {
-            (Ok(c), Ok(s)) => prop_assert_eq!(c, s),
-            (Err(c_err), Err(s_err)) => prop_assert_eq!(c_err, s_err.utf8_error()),
-            _ => panic!("CompactStr and core::str read UTF-8 differently?"),
-        }
+    match (compact_result, word_result) {
+        (Ok(c), Ok(s)) => prop_assert_eq!(c, s),
+        (Err(c_err), Err(s_err)) => prop_assert_eq!(c_err, s_err.utf8_error()),
+        _ => panic!("CompactStr and core::str read UTF-8 differently?"),
     }
+}
 
-    #[test]
-    #[cfg_attr(miri, ignore)]
-    fn test_from_lossy_cow_roundtrips(bytes in proptest::collection::vec(any::<u8>(), 0..80)) {
-        let cow = String::from_utf8_lossy(&bytes[..]);
-        let compact = CompactStr::from(cow.clone());
-        prop_assert_eq!(cow, compact);
-    }
+#[proptest]
+#[cfg_attr(miri, ignore)]
+fn test_from_lossy_cow_roundtrips(#[strategy(rand_bytes())] bytes: Vec<u8>) {
+    let cow = String::from_utf8_lossy(&bytes[..]);
+    let compact = CompactStr::from(cow.clone());
+    prop_assert_eq!(cow, compact);
+}
 
-    #[test]
-    #[cfg_attr(miri, ignore)]
-    fn test_from_lossy_cow_allocated_properly(bytes in proptest::collection::vec(any::<u8>(), 0..80)) {
-        let cow = String::from_utf8_lossy(&bytes[..]);
-        let compact = CompactStr::from(cow);
-        assert_allocated_properly(&compact);
-    }
+#[proptest]
+#[cfg_attr(miri, ignore)]
+fn test_from_lossy_cow_allocated_properly(#[strategy(rand_bytes())] bytes: Vec<u8>) {
+    let cow = String::from_utf8_lossy(&bytes[..]);
+    let compact = CompactStr::from(cow);
+    assert_allocated_properly(&compact);
+}
 
-    #[test]
-    #[cfg_attr(miri, ignore)]
-    fn test_reserve_and_write_bytes(word in rand_unicode()) {
-        let mut compact = CompactStr::default();
-        prop_assert!(compact.is_empty());
+#[proptest]
+#[cfg_attr(miri, ignore)]
+fn test_reserve_and_write_bytes(#[strategy(rand_unicode())] word: String) {
+    let mut compact = CompactStr::default();
+    prop_assert!(compact.is_empty());
 
-        // reserve enough space to write our bytes
-        compact.reserve(word.len());
+    // reserve enough space to write our bytes
+    compact.reserve(word.len());
 
-        // SAFETY: We're writing a String which we know is UTF-8
-        let slice = unsafe { compact.as_mut_bytes() };
-        slice[..word.len()].copy_from_slice(word.as_bytes());
+    // SAFETY: We're writing a String which we know is UTF-8
+    let slice = unsafe { compact.as_mut_bytes() };
+    slice[..word.len()].copy_from_slice(word.as_bytes());
 
-        // SAFTEY: We know this is the length of our string, since `compact` started with 0 bytes
-        // and we just wrote `word.len()` bytes
-        unsafe { compact.set_len(word.len()) }
+    // SAFTEY: We know this is the length of our string, since `compact` started with 0 bytes
+    // and we just wrote `word.len()` bytes
+    unsafe { compact.set_len(word.len()) }
 
-        prop_assert_eq!(&word, &compact);
-    }
+    prop_assert_eq!(&word, &compact);
+}
 
-    #[test]
-    #[cfg_attr(miri, ignore)]
-    fn test_reserve_and_write_bytes_allocated_properly(word in rand_unicode()) {
-        let mut compact = CompactStr::default();
-        prop_assert!(compact.is_empty());
+#[proptest]
+#[cfg_attr(miri, ignore)]
+fn test_reserve_and_write_bytes_allocated_properly(#[strategy(rand_unicode())] word: String) {
+    let mut compact = CompactStr::default();
+    prop_assert!(compact.is_empty());
 
-        // reserve enough space to write our bytes
-        compact.reserve(word.len());
+    // reserve enough space to write our bytes
+    compact.reserve(word.len());
 
-        // SAFETY: We're writing a String which we know is UTF-8
-        let slice = unsafe { compact.as_mut_bytes() };
-        slice[..word.len()].copy_from_slice(word.as_bytes());
+    // SAFETY: We're writing a String which we know is UTF-8
+    let slice = unsafe { compact.as_mut_bytes() };
+    slice[..word.len()].copy_from_slice(word.as_bytes());
 
-        // SAFTEY: We know this is the length of our string, since `compact` started with 0 bytes
-        // and we just wrote `word.len()` bytes
-        unsafe { compact.set_len(word.len()) }
+    // SAFTEY: We know this is the length of our string, since `compact` started with 0 bytes
+    // and we just wrote `word.len()` bytes
+    unsafe { compact.set_len(word.len()) }
 
-        prop_assert_eq!(compact.len(), word.len());
+    prop_assert_eq!(compact.len(), word.len());
 
-        // The string should be heap allocated if `word` was > MAX_SIZE
-        //
-        // NOTE: The reserve and write API's don't currently support the Packed representation
-        prop_assert_eq!(compact.is_heap_allocated(), word.len() > MAX_SIZE);
-    }
+    // The string should be heap allocated if `word` was > MAX_SIZE
+    //
+    // NOTE: The reserve and write API's don't currently support the Packed representation
+    prop_assert_eq!(compact.is_heap_allocated(), word.len() > MAX_SIZE);
+}
 
-    #[test]
-    #[cfg_attr(miri, ignore)]
-    fn test_extend_chars_allocated_properly((start, extend) in (rand_unicode(), rand_unicode())) {
-        let mut compact = CompactStr::new(&start);
-        compact.extend(extend.chars());
+#[proptest]
+#[cfg_attr(miri, ignore)]
+fn test_extend_chars_allocated_properly(
+    #[strategy(rand_unicode())] start: String,
+    #[strategy(rand_unicode())] extend: String,
+) {
+    let mut compact = CompactStr::new(&start);
+    compact.extend(extend.chars());
 
-        let mut control = start.clone();
-        control.extend(extend.chars());
+    let mut control = start.clone();
+    control.extend(extend.chars());
 
-        prop_assert_eq!(&compact, &control);
-        assert_allocated_properly(&compact);
-    }
+    prop_assert_eq!(&compact, &control);
+    assert_allocated_properly(&compact);
 }
 
 #[test]