use pattern_core::{Combinable, Pattern};
use proptest::prelude::*;
fn arb_string_pattern() -> impl Strategy<Value = Pattern<String>> {
let leaf = any::<String>().prop_map(Pattern::point);
leaf.prop_recursive(
3, 10, 5, |inner| {
(any::<String>(), prop::collection::vec(inner, 0..5))
.prop_map(|(value, elements)| Pattern::pattern(value, elements))
},
)
}
fn arb_vec_pattern() -> impl Strategy<Value = Pattern<Vec<i32>>> {
let leaf = prop::collection::vec(any::<i32>(), 0..10).prop_map(Pattern::point);
leaf.prop_recursive(
3, 10, 5, |inner| {
(
prop::collection::vec(any::<i32>(), 0..10),
prop::collection::vec(inner, 0..5),
)
.prop_map(|(value, elements)| Pattern::pattern(value, elements))
},
)
}
fn arb_deep_string_pattern() -> impl Strategy<Value = Pattern<String>> {
let leaf = any::<String>().prop_map(Pattern::point);
leaf.prop_recursive(
10, 20, 3, |inner| {
(any::<String>(), prop::collection::vec(inner, 0..3))
.prop_map(|(value, elements)| Pattern::pattern(value, elements))
},
)
}
fn arb_wide_string_pattern() -> impl Strategy<Value = Pattern<String>> {
let leaf = any::<String>().prop_map(Pattern::point);
leaf.prop_recursive(
2, 50, 20, |inner| {
(any::<String>(), prop::collection::vec(inner, 0..20))
.prop_map(|(value, elements)| Pattern::pattern(value, elements))
},
)
}
proptest! {
#[test]
fn prop_left_identity_string(p in arb_string_pattern()) {
let empty = Pattern::<String>::default();
let result = empty.combine(p.clone());
prop_assert_eq!(result, p);
}
}
proptest! {
#[test]
fn prop_right_identity_string(p in arb_string_pattern()) {
let empty = Pattern::<String>::default();
let result = p.clone().combine(empty);
prop_assert_eq!(result, p);
}
}
proptest! {
#[test]
fn prop_left_identity_vec(p in arb_vec_pattern()) {
let empty = Pattern::<Vec<i32>>::default();
let result = empty.combine(p.clone());
prop_assert_eq!(result, p);
}
}
proptest! {
#[test]
fn prop_right_identity_vec(p in arb_vec_pattern()) {
let empty = Pattern::<Vec<i32>>::default();
let result = p.clone().combine(empty);
prop_assert_eq!(result, p);
}
}
proptest! {
#[test]
fn prop_left_identity_deep(p in arb_deep_string_pattern()) {
let empty = Pattern::<String>::default();
let result = empty.combine(p.clone());
prop_assert_eq!(result, p);
}
}
proptest! {
#[test]
fn prop_right_identity_deep(p in arb_deep_string_pattern()) {
let empty = Pattern::<String>::default();
let result = p.clone().combine(empty);
prop_assert_eq!(result, p);
}
}
proptest! {
#[test]
fn prop_left_identity_wide(p in arb_wide_string_pattern()) {
let empty = Pattern::<String>::default();
let result = empty.combine(p.clone());
prop_assert_eq!(result, p);
}
}
proptest! {
#[test]
fn prop_right_identity_wide(p in arb_wide_string_pattern()) {
let empty = Pattern::<String>::default();
let result = p.clone().combine(empty);
prop_assert_eq!(result, p);
}
}
proptest! {
#[test]
fn prop_identity_atomic_string(value in any::<String>()) {
let empty = Pattern::<String>::default();
let p = Pattern::point(value);
prop_assert_eq!(empty.clone().combine(p.clone()), p.clone());
prop_assert_eq!(p.clone().combine(empty), p);
}
}
proptest! {
#[test]
fn prop_identity_atomic_vec(value in prop::collection::vec(any::<i32>(), 0..100)) {
let empty = Pattern::<Vec<i32>>::default();
let p = Pattern::point(value);
prop_assert_eq!(empty.clone().combine(p.clone()), p.clone());
prop_assert_eq!(p.clone().combine(empty), p);
}
}
#[test]
fn test_default_combine_default_string() {
let empty1 = Pattern::<String>::default();
let empty2 = Pattern::<String>::default();
let result = empty1.combine(empty2.clone());
assert_eq!(result, empty2);
assert_eq!(result.value(), "");
assert_eq!(result.length(), 0);
}
#[test]
fn test_default_combine_default_vec() {
let empty1 = Pattern::<Vec<i32>>::default();
let empty2 = Pattern::<Vec<i32>>::default();
let result = empty1.combine(empty2.clone());
assert_eq!(result, empty2);
assert_eq!(result.length(), 0);
}
#[test]
fn test_default_combine_default_unit() {
let empty1 = Pattern::<()>::default();
let empty2 = Pattern::<()>::default();
let result = empty1.combine(empty2.clone());
assert_eq!(result, empty2);
}
proptest! {
#[test]
fn prop_identity_preserves_value(value in any::<String>()) {
let empty = Pattern::<String>::default();
let p = Pattern::point(value.clone());
let left_result = empty.clone().combine(p.clone());
let right_result = p.clone().combine(empty);
prop_assert_eq!(left_result.value(), &value);
prop_assert_eq!(right_result.value(), &value);
}
}
proptest! {
#[test]
fn prop_identity_preserves_structure(
value in any::<String>(),
elements in prop::collection::vec(any::<String>().prop_map(Pattern::point), 0..10)
) {
let empty = Pattern::<String>::default();
let p = Pattern::pattern(value.clone(), elements.clone());
let left_result = empty.clone().combine(p.clone());
let right_result = p.clone().combine(empty);
prop_assert_eq!(left_result.value(), &value);
prop_assert_eq!(left_result.length(), elements.len());
prop_assert_eq!(right_result.value(), &value);
prop_assert_eq!(right_result.length(), elements.len());
}
}
proptest! {
#[test]
fn prop_identity_preserves_depth(p in arb_deep_string_pattern()) {
let empty = Pattern::<String>::default();
let original_depth = p.depth();
let left_result = empty.clone().combine(p.clone());
let right_result = p.clone().combine(empty);
prop_assert_eq!(left_result.depth(), original_depth);
prop_assert_eq!(right_result.depth(), original_depth);
}
}
proptest! {
#[test]
fn prop_both_identity_laws_string(p in arb_string_pattern()) {
let empty = Pattern::<String>::default();
let left_identity = empty.clone().combine(p.clone());
let right_identity = p.clone().combine(empty);
prop_assert_eq!(left_identity, p.clone(), "Left identity failed");
prop_assert_eq!(right_identity, p, "Right identity failed");
}
}
proptest! {
#[test]
fn prop_both_identity_laws_vec(p in arb_vec_pattern()) {
let empty = Pattern::<Vec<i32>>::default();
let left_identity = empty.clone().combine(p.clone());
let right_identity = p.clone().combine(empty);
prop_assert_eq!(left_identity, p.clone(), "Left identity failed");
prop_assert_eq!(right_identity, p, "Right identity failed");
}
}