use super::SharedStr;
use crate::SharedBytes;
use quickcheck::Arbitrary;
use std::{convert::identity, ops::Range, sync::Arc};
type Bounds = Range<usize>;
#[test]
fn qc_to_bytes_and_back() {
quickcheck::quickcheck(test_to_bytes_and_back as fn(SharedStringFromVecFn, String, Bounds))
}
fn test_to_bytes_and_back(new: SharedStringFromVecFn, string: String, bounds: Bounds) {
let shared_string = new
.call(string)
.try_slice_into(bounds)
.unwrap_or_else(identity);
let actual_bytes = SharedBytes::from(shared_string.clone());
assert_eq!(actual_bytes, shared_string.as_bytes());
let actual_string = SharedStr::from_utf8(actual_bytes).unwrap();
assert_eq!(actual_string, shared_string);
}
#[test]
fn qc_try_slice_to_subset() {
quickcheck::quickcheck(test_try_slice_to_subset as fn(SharedStringFromVecFn, String, Bounds))
}
fn test_try_slice_to_subset(new: SharedStringFromVecFn, string: String, bounds: Bounds) {
let shared_string = new.call(string);
let subset = match shared_string.get(bounds) {
Some(x) => x,
None => return,
};
let actual = shared_string
.clone()
.try_slice_into(shared_string.range_of_subset(subset))
.unwrap();
assert_eq!(actual, subset);
}
#[test]
fn try_slice_range() {
for &new in SHARED_STRING_FROM_STATIC_FNS {
let actual_1 = new("0123456").try_slice_into(2..6).unwrap();
assert_eq!(actual_1, "2345");
let actual_2 = actual_1.try_slice_into(1..3).unwrap();
assert_eq!(actual_2, "34");
}
}
#[test]
fn try_slice_range_to() {
for &new in SHARED_STRING_FROM_STATIC_FNS {
let actual_1 = new("0123456").try_slice_into(..6).unwrap();
assert_eq!(actual_1, "012345");
let actual_2 = actual_1.try_slice_into(..3).unwrap();
assert_eq!(actual_2, "012");
}
}
#[test]
fn try_slice_range_from() {
for &new in SHARED_STRING_FROM_STATIC_FNS {
let actual_1 = new("0123456").try_slice_into(3..).unwrap();
assert_eq!(actual_1, "3456");
let actual_2 = actual_1.try_slice_into(1..).unwrap();
assert_eq!(actual_2, "456");
}
}
#[test]
fn try_slice_inside_utf_8_char() {
let string = "€".to_owned();
assert_eq!(string.as_bytes(), [226, 130, 172].as_slice());
let shared_string = SharedStr::from(Arc::new(string.clone()));
let actual_err = shared_string.try_slice_into(1..2).unwrap_err();
assert_eq!(actual_err, string);
}
#[test]
fn qc_shared_string_slices_like_std() {
quickcheck::quickcheck(
test_shared_string_slices_like_std as fn(String, SharedStringFromVecFn, Vec<Bounds>),
)
}
#[test]
fn shared_string_slices_like_std_max_upper_bound() {
test_shared_string_slices_like_std(
"0".to_owned(),
SharedStringFromVecFn(SharedStr::from_string),
vec![0..1, 0..usize::MAX],
)
}
fn test_shared_string_slices_like_std(
string: String,
new: SharedStringFromVecFn,
bounds: Vec<Bounds>,
) {
let mut shared_string = new.call(string.clone());
let mut std_slice = string.as_str();
for bound in bounds {
let actual_result = shared_string.try_slice_into(bound.clone());
let expected_result = std_slice.get(bound).ok_or(std_slice);
match actual_result {
Err(actual) => {
let expected = expected_result.unwrap_err();
assert_eq!(actual, expected);
return;
}
Ok(actual) => {
let expected = expected_result.unwrap();
assert_eq!(actual, expected);
shared_string = actual;
std_slice = expected;
}
}
}
}
#[test]
fn qc_try_split_off() {
quickcheck::quickcheck(test_try_split_off as fn(SharedStringFromVecFn, String, Bounds, usize))
}
#[test]
fn try_split_off_max_index() {
test_try_split_off(
SharedStringFromVecFn(SharedStr::from_string),
"a".to_owned(),
0..1,
usize::MAX,
)
}
fn test_try_split_off(new: SharedStringFromVecFn, string: String, bounds: Bounds, index: usize) {
let mut expected_str = match string.get(bounds.clone()) {
Some(b) => b.to_owned(),
None => string.clone(),
};
let mut actual_str = new
.call(string)
.try_slice_into(bounds)
.unwrap_or_else(identity);
match actual_str.try_split_off(index) {
None => assert_eq!(expected_str.get(index..), None),
Some(actual_split) => {
let expected_split = expected_str.split_off(index);
assert_eq!(actual_split, expected_split);
assert_eq!(actual_str, expected_str);
}
};
}
const SHARED_STRING_FROM_STATIC_FNS: &[fn(&'static str) -> SharedStr] = &[
SharedStr::from_static,
|b| SharedStr::from_string(b.to_owned()),
|b| SharedStr::from(Arc::new(b.to_owned())),
];
const SHARED_STRING_FROM_STRING_FNS: &[fn(String) -> SharedStr] = &[
shared_string_static_from_leak,
SharedStr::from_string,
shared_string_arc_string_from_string,
];
fn shared_string_static_from_leak(b: String) -> SharedStr {
SharedStr::from_static(Box::leak(b.into_boxed_str()))
}
fn shared_string_arc_string_from_string(b: String) -> SharedStr {
SharedStr::from_arc_string(Arc::new(b))
}
#[derive(Debug, Clone, Copy)]
struct SharedStringFromVecFn(fn(String) -> SharedStr);
impl SharedStringFromVecFn {
fn call(self, b: String) -> SharedStr {
(self.0)(b)
}
}
impl Arbitrary for SharedStringFromVecFn {
fn arbitrary(g: &mut quickcheck::Gen) -> Self {
Self(*g.choose(SHARED_STRING_FROM_STRING_FNS).unwrap())
}
}