mago-codex 1.26.0

PHP type system representation, comparison logic, and codebase metadata for static analysis.
Documentation
mod combiner_common;

use combiner_common::*;

#[test]
fn null_idempotent() {
    for n in 1..=10 {
        assert_self_idempotent(null(), n);
    }
}

#[test]
fn void_idempotent() {
    for n in 1..=10 {
        let r = combine_default(vec![void(); n]);
        assert_eq!(r.len(), 1);
        assert_eq!(atomic_id_string(&r[0]), "void");
    }
}

#[test]
fn never_idempotent() {
    for n in 1..=10 {
        assert_self_idempotent(never(), n);
    }
}

#[test]
fn void_or_null_yields_null() {
    assert_combines_to(vec![void(), null()], vec![null()]);
    assert_combines_to(vec![null(), void()], vec![null()]);
}

#[test]
fn void_with_int_yields_int_or_null() {
    assert_combines_to(vec![void(), t_int()], vec![t_int(), null()]);
    assert_combines_to(vec![t_int(), void()], vec![t_int(), null()]);
}

#[test]
fn void_with_string_yields_string_or_null() {
    assert_combines_to(vec![void(), t_string()], vec![t_string(), null()]);
    assert_combines_to(vec![t_string(), void()], vec![t_string(), null()]);
}

#[test]
fn void_with_bool_yields_bool_or_null() {
    assert_combines_to(vec![void(), t_bool()], vec![t_bool(), null()]);
    assert_combines_to(vec![t_bool(), void()], vec![t_bool(), null()]);
}

#[test]
fn void_with_object_yields_object_or_null() {
    assert_combines_to(vec![void(), t_object_any()], vec![t_object_any(), null()]);
    assert_combines_to(vec![void(), t_named("Foo")], vec![t_named("Foo"), null()]);
}

#[test]
fn void_with_resource_yields_resource_or_null() {
    assert_combines_to(vec![void(), t_resource()], vec![t_resource(), null()]);
    assert_combines_to(vec![void(), t_open_resource()], vec![t_open_resource(), null()]);
}

#[test]
fn void_or_never_yields_null() {
    assert_combines_to(vec![void(), never()], vec![null()]);
    assert_combines_to(vec![never(), void()], vec![null()]);
}

#[test]
fn void_with_two_other_types_becomes_null() {
    let r = combine_default(vec![void(), t_int(), t_string()]);
    let mut ids: Vec<String> = r.iter().map(atomic_id_string).collect();
    ids.sort();
    assert_eq!(ids, vec!["int", "null", "string"]);
}

#[test]
fn null_or_int_kept_separate() {
    let r = combine_default(vec![null(), t_int()]);
    let mut ids: Vec<String> = r.iter().map(atomic_id_string).collect();
    ids.sort();
    assert_eq!(ids, vec!["int", "null"]);
}

#[test]
fn null_or_string_kept_separate() {
    let r = combine_default(vec![null(), t_string()]);
    let mut ids: Vec<String> = r.iter().map(atomic_id_string).collect();
    ids.sort();
    assert_eq!(ids, vec!["null", "string"]);
}

#[test]
fn null_or_bool_kept_separate() {
    let r = combine_default(vec![null(), t_bool()]);
    let mut ids: Vec<String> = r.iter().map(atomic_id_string).collect();
    ids.sort();
    assert_eq!(ids, vec!["bool", "null"]);
}

#[test]
fn null_or_object_kept_separate() {
    let r = combine_default(vec![null(), t_object_any()]);
    let mut ids: Vec<String> = r.iter().map(atomic_id_string).collect();
    ids.sort();
    assert_eq!(ids, vec!["null", "object"]);
}

#[test]
fn null_absorbs_never() {
    assert_combines_to(vec![null(), never()], vec![null()]);
    assert_combines_to(vec![never(), null()], vec![null()]);
}

#[test]
fn never_dropped_with_int() {
    assert_combines_to(vec![never(), t_int()], vec![t_int()]);
    assert_combines_to(vec![t_int(), never()], vec![t_int()]);
}

#[test]
fn never_dropped_with_string() {
    assert_combines_to(vec![never(), t_string()], vec![t_string()]);
}

#[test]
fn never_dropped_with_array() {
    assert_combines_to(vec![never(), t_empty_array()], vec![t_empty_array()]);
}

#[test]
fn never_dropped_with_object() {
    assert_combines_to(vec![never(), t_named("X")], vec![t_named("X")]);
}

#[test]
fn never_dropped_with_three_atoms() {
    let r = combine_default(vec![never(), t_int(), t_string()]);
    let mut ids: Vec<String> = r.iter().map(atomic_id_string).collect();
    ids.sort();
    assert_eq!(ids, vec!["int", "string"]);
}

#[test]
fn many_nevers_collapse() {
    for n in 1..=10 {
        assert_combines_to(vec![never(); n], vec![never()]);
    }
}

#[test]
fn never_with_many_others_disappears() {
    let mut inputs = vec![never()];
    for i in 0..5 {
        inputs.push(t_lit_int(i));
    }
    let r = combine_default(inputs);
    assert_eq!(r.len(), 5);
    assert!(r.iter().all(|a| !matches!(a, mago_codex::ttype::atomic::TAtomic::Never)));
}