use crate::regex::Regex;
use crate::typing::pattern::{Match, Pattern};
use proptest::prelude::*;
#[test]
fn meet_equal_is_solved() {
assert_eq!(Pattern::lit("Int").unify(&Pattern::lit("Int")), Match::Solved);
}
#[test]
fn meet_distinct_is_empty() {
assert_eq!(
Pattern::lit("Int").unify(&Pattern::lit("Bool")),
Match::Empty
);
}
#[test]
fn bottom_unifies_with_nothing() {
assert_eq!(Pattern::bottom().unify(&Pattern::lit("Int")), Match::Empty);
assert_eq!(Pattern::bottom().unify(&Pattern::bottom()), Match::Empty);
}
#[test]
fn broad_set_unifies_with_member() {
let universe = Pattern::closed(Regex::star(Regex::or(Regex::Char('a'), Regex::Char('b'))));
assert_eq!(universe.unify(&Pattern::lit("abba")), Match::Solved);
}
#[test]
fn solved_does_not_imply_containment() {
let partial = Pattern::closed(Regex::or(Regex::literal("Int"), Regex::literal("Bool")));
let expected = Pattern::lit("Int");
assert_eq!(partial.unify(&expected), Match::Solved);
assert!(!partial.subset(&expected));
}
#[test]
fn resolved_point_is_contained() {
let resolved = Pattern::lit("Int");
let expected = Pattern::closed(Regex::or(Regex::literal("Int"), Regex::literal("Bool")));
assert!(resolved.subset(&expected));
}
#[test]
fn bottom_annihilates_closed() {
for s in ["Int", "Int -> Bool", ""] {
assert_eq!(Pattern::bottom().unify(&Pattern::lit(s)), Match::Empty);
}
}
#[test]
fn subset_reflexive_on_literals() {
for s in ["Int", "a -> b -> c"] {
assert!(Pattern::lit(s).subset(&Pattern::lit(s)));
}
}
proptest! {
#[test]
fn meet_commutes(a in "[A-Za-z]{1,5}", b in "[A-Za-z]{1,5}") {
let (x, y) = (Pattern::lit(&a), Pattern::lit(&b));
prop_assert_eq!(x.unify(&y), y.unify(&x));
}
#[test]
fn singleton_meet_is_equality(a in "[A-Za-z]{0,6}", b in "[A-Za-z]{0,6}") {
let m = Pattern::lit(&a).unify(&Pattern::lit(&b));
prop_assert_eq!(matches!(m, Match::Solved), a == b);
}
}