use std::{fmt::Write, ops::Deref}; use assert_panic::assert_panic; use proptest::proptest; use german_str::{str_prefix, str_suffix, GermanStr, MAX_INLINE_BYTES, MAX_LEN}; #[test] fn is_2_bytes() { assert_eq!(std::mem::size_of::(), 16); } #[test] fn assert_traits() { fn f() {} f::(); } #[test] fn assert_largest_layout_valid() { assert!(std::alloc::Layout::array::(MAX_LEN).is_ok()); } #[test] fn test_new() { assert_eq!( GermanStr::new("hello world!").unwrap().as_str(), "hello world!", ); assert_eq!( GermanStr::new("too long to fit on the stack").unwrap().as_str(), "too long to fit on the stack", ); } #[test] fn test_equality() { let a = GermanStr::new("aaaa").unwrap(); let b = GermanStr::new("aaaab").unwrap(); assert_ne!(a, b); } #[test] fn test_default() { assert_eq!( GermanStr::default(), String::default(), ); } #[test] fn test_leak() { let short = GermanStr::new("short").unwrap(); assert!(!short.is_heap_allocated()); assert!(!short.has_shared_buffer()); let mut leaked = GermanStr::new("this is obviously longer than 12 bytes").unwrap(); let og = leaked.clone(); assert!(leaked.is_heap_allocated()); assert!(!leaked.has_shared_buffer()); let leaked_copy = leaked.leaky_shared_clone(); assert!(leaked_copy.is_heap_allocated()); assert!(leaked.has_shared_buffer()); assert!(leaked_copy.has_shared_buffer()); assert_eq!(og, leaked); assert_eq!(leaked, leaked_copy); assert_eq!(leaked.heap_ptr(), leaked_copy.heap_ptr()); } proptest! { #[test] fn conversion(src: String) { let german = GermanStr::new(&src).unwrap(); let end = String::from(german); assert_eq!(src, end); } #[test] fn deref(src: String) { let german = GermanStr::new(&src).unwrap(); assert_eq!(&src, Deref::deref(&german)); } #[test] fn ordering(lhs: String, rhs: String) { let german_lhs = GermanStr::new(&lhs).unwrap(); let german_rhs = GermanStr::new(&rhs).unwrap(); assert_eq!(lhs.cmp(&rhs), german_lhs.cmp(&german_rhs)); } #[test] fn equality(lhs: String, rhs: String) { let german_lhs = GermanStr::new(&lhs).unwrap(); let german_rhs = GermanStr::new(&rhs).unwrap(); assert_eq!(lhs == rhs, german_lhs == german_rhs); } #[test] fn clone(val: String) { let german = GermanStr::new(&val).unwrap(); assert_eq!(german, german.clone()); } #[test] fn new_inline(val: String) { if val.len() > MAX_INLINE_BYTES { assert_panic!({ GermanStr::new_inline(&val); }); } else { let inline = GermanStr::new_inline(&val); assert_eq!(inline, val); } } #[test] fn prefix_bytes_slice(val: String) { let german = GermanStr::new(&val).unwrap(); let prefix_len = val.len().min(4); assert_eq!( german.prefix_bytes_slice(), &val.as_bytes()[..prefix_len], ); } #[test] fn prefix_bytes_array(val: String) { let german = GermanStr::new(&val).unwrap(); let prefix_len = val.len().min(4); let mut og_array = [0; 4]; og_array[..prefix_len].copy_from_slice(&val.as_bytes()[..prefix_len]); assert_eq!( german.prefix_bytes_array(), og_array, ); } #[test] fn suffix_bytes_slice(val: String) { let german = GermanStr::new(&val).unwrap(); assert_eq!( german.suffix_bytes_slice(), val.as_bytes().get(4..).unwrap_or_default(), ); } #[test] fn test_as_str(val: String) { let german = GermanStr::new(&val).unwrap(); assert_eq!( german.as_str(), &val, ); } #[test] fn test_to_string(val: String) { let german = GermanStr::new(&val).unwrap(); assert_eq!( &german.to_string(), &val, ); } #[test] fn test_len(val: String) { let german = GermanStr::new(&val).unwrap(); assert_eq!( german.len(), val.len(), ); } #[test] fn test_is_empty(val: String) { let german = GermanStr::new(&val).unwrap(); assert_eq!( german.is_empty(), val.is_empty(), ); } #[test] fn test_debug(val: String) { let german = GermanStr::new(&val).unwrap(); assert_eq!( format!("{german:?}"), format!("{val:?}"), ); } #[test] fn test_display(val: String) { let german = GermanStr::new(&val).unwrap(); assert_eq!( format!("{german}"), format!("{val}"), ); } #[test] fn test_str_prefix(val: String) { let german = GermanStr::new(&val).unwrap(); assert_eq!( str_prefix::(german), str_prefix::(val), ); } #[test] fn test_str_suffix(val: String) { let german = GermanStr::new(&val).unwrap(); assert_eq!( str_suffix::(&german), str_suffix::(&val), ); } #[test] fn build_writer(values: Vec) { let mut writer = german_str::Writer::new(); let mut string = String::new(); for val in &values { writer.write_str(val).unwrap(); string.push_str(val); } let german = Into::::into(writer); assert_eq!(german, string); } } #[cfg(feature = "serde")] mod serde_tests { use std::collections::HashMap; use std::hash::Hash; use serde::{Deserialize, Serialize}; use super::*; #[derive(Serialize, Deserialize)] struct ExampleStruct { raw: T, vec: Vec, map: HashMap, } proptest! { #[test] fn roundtrip(raw: String, vec: Vec, map: HashMap) { let initial = ExampleStruct { raw, vec, map }; let json = serde_json::to_string(&initial).unwrap(); let parsed = serde_json::from_str::>(&json).unwrap(); assert_eq!(parsed.raw, initial.raw); assert_eq!(parsed.vec, initial.vec); let mut parsed_vec = parsed .map .iter() .map(|(a, b)| (a.as_str(), b.as_str())) .collect::>(); parsed_vec.sort(); let mut initial_vec = initial .map .iter() .map(|(a, b)| (a.as_str(), b.as_str())) .collect::>(); initial_vec.sort(); assert_eq!(parsed_vec, initial_vec); } } }