use crate::logic::typing::Type;
fn is_partial_any(t: &Type) -> bool {
match t {
Type::Partial(inner, _) => matches!(**inner, Type::Any),
_ => false,
}
}
fn is_complete(t: &Type) -> bool {
!matches!(t, Type::Partial(_, _))
}
#[test]
fn test_empty_input() {
let res = Type::parse_partial("").unwrap();
assert!(is_partial_any(&res));
if let Type::Partial(inner, input) = res {
assert!(matches!(*inner, Type::Any));
assert_eq!(input, "");
} else {
panic!("Expected partial");
}
}
#[test]
fn test_complete_atom() {
let res = Type::parse_partial("int").unwrap();
assert!(is_complete(&res));
if let Type::Atom(s) = res {
assert_eq!(s, "int");
} else {
panic!("Expected Atom, got {:?}", res);
}
}
#[test]
fn test_partial_arrow_start() {
let res = Type::parse_partial("int ->").unwrap();
if let Type::Partial(inner, input) = res {
if let Type::Arrow(l, r) = *inner {
if let Type::Atom(s) = *l {
assert_eq!(s, "int");
} else {
panic!("Left should be Atom(int)");
}
assert!(matches!(*r, Type::Any));
} else {
panic!("Expected Arrow");
}
assert_eq!(input, "int ->");
} else {
panic!("Expected partial");
}
}
#[test]
fn test_partial_arrow_space() {
let res = Type::parse_partial("int -> ").unwrap();
if let Type::Partial(inner, input) = res {
if let Type::Arrow(_l, r) = *inner {
assert!(matches!(*r, Type::Any));
} else {
panic!("Expected Arrow");
}
assert_eq!(input, "int -> ");
} else {
panic!("Expected partial");
}
}
#[test]
fn test_partial_parens_open() {
let res = Type::parse_partial("(").unwrap();
if let Type::Partial(_inner, input) = res {
assert_eq!(input, "(");
} else {
panic!("Expected partial");
}
}
#[test]
fn test_partial_inner_parens() {
let res = Type::parse_partial("(int").unwrap();
if let Type::Partial(inner, input) = res {
if let Type::Atom(s) = *inner {
assert_eq!(s, "int");
} else {
panic!("Expected Atom(int)");
}
assert_eq!(input, "(int");
} else {
panic!("Expected partial");
}
}
#[test]
fn test_partial_nested_arrow() {
let res = Type::parse_partial("A -> B ->").unwrap();
if let Type::Partial(inner, input) = res {
if let Type::Arrow(_l1, r1) = *inner {
if let Type::Arrow(_l2, r2) = *r1 {
assert!(matches!(*r2, Type::Any));
} else {
panic!("Expected nested Arrow");
}
} else {
panic!("Expected Arrow");
}
assert_eq!(input, "A -> B ->");
} else {
panic!("Expected partial");
}
}
#[test]
fn test_partial_identifier() {
let res = Type::parse_partial("'int").unwrap();
if let Type::Partial(inner, input) = res {
if let Type::Raw(s) = *inner {
assert_eq!(s, "int");
} else {
panic!("Expected Raw");
}
assert_eq!(input, "'int");
} else {
panic!("Expected partial");
}
}
#[test]
fn test_partial_unicode_arrow_prefix_does_not_panic() {
let res = Type::parse_partial("A-").unwrap();
assert!(matches!(res, Type::Partial(_, _)), "A- should be partial");
if let Type::Partial(inner, input) = res {
if let Type::Arrow(l, r) = *inner {
assert!(matches!(*l, Type::Atom(_)));
assert!(matches!(*r, Type::Any));
} else {
panic!("Expected Arrow");
}
assert_eq!(input, "A-");
}
let res2 = Type::parse_partial("A →").unwrap();
assert!(matches!(res2, Type::Partial(_, _)), "A → should be partial (no right side)");
if let Type::Partial(inner, input) = res2 {
if let Type::Arrow(l, r) = *inner {
assert!(matches!(*l, Type::Atom(_)));
assert!(matches!(*r, Type::Any));
} else {
panic!("Expected Arrow");
}
assert_eq!(input, "A →");
}
let res3 = Type::parse_partial("A→").unwrap();
assert!(matches!(res3, Type::Partial(_, _)), "A→ should be partial (no right side)");
}
#[test]
fn test_partial_ascii_arrow_no_space() {
let res = Type::parse_partial("A->").unwrap();
assert!(matches!(res, Type::Partial(_, _)), "A-> should be partial");
if let Type::Partial(inner, input) = res {
if let Type::Arrow(l, r) = *inner {
assert!(matches!(*l, Type::Atom(_)));
assert!(matches!(*r, Type::Any));
} else {
panic!("Expected Arrow");
}
assert_eq!(input, "A->");
}
}
#[test]
fn test_partial_arrow_with_trailing_space() {
let res = Type::parse_partial("A -> ").unwrap();
assert!(matches!(res, Type::Partial(_, _)), "A -> should be partial");
if let Type::Partial(inner, input) = res {
if let Type::Arrow(_l, r) = *inner {
assert!(matches!(*r, Type::Any));
} else {
panic!("Expected Arrow");
}
assert_eq!(input, "A -> ");
}
}
#[test]
fn test_complete_arrow_with_right_side() {
let res = Type::parse_partial("A -> B").unwrap();
assert!(matches!(res, Type::Arrow(_, _)), "A -> B should be complete");
if let Type::Arrow(l, r) = res {
assert!(matches!(*l, Type::Atom(_)));
assert!(matches!(*r, Type::Atom(_)));
}
}
#[test]
fn test_partial_negation_hole_is_any() {
let res = Type::parse_partial("¬").unwrap();
if let Type::Partial(inner, input) = res {
assert!(matches!(*inner, Type::Not(t) if matches!(*t, Type::Any)));
assert_eq!(input, "¬");
} else {
panic!("Expected partial");
}
}