truthful 0.1.1

A logical expression parser, optimizer and evaluator.
Documentation
use std::collections::HashSet;

use super::*;
use pest::Parser;

#[test]
fn parse_not() {
    expect_rule("!", inner::Rule::not, "!");
    for expr in permutate_case("not") {
        expect_rule(&expr, inner::Rule::not, &expr);
    }
}

#[test]
fn parse_and() {
    expect_rule("^", inner::Rule::and, "^");
    for expr in permutate_case("and") {
        expect_rule(&expr, inner::Rule::and, &expr);
    }
}

#[test]
fn parse_or() {
    expect_rule("v", inner::Rule::or, "v");
    for expr in permutate_case("or") {
        expect_rule(&expr, inner::Rule::or, &expr);
    }
}

#[test]
fn parse_xor() {
    expect_rule("+", inner::Rule::xor, "+");
    for expr in permutate_case("xor") {
        expect_rule(&expr, inner::Rule::xor, &expr);
    }
}

#[test]
fn parse_cond() {
    expect_rule("->", inner::Rule::cond, "->");
    for expr in permutate_case("cond") {
        expect_rule(&expr, inner::Rule::cond, &expr);
    }
}

#[test]
fn parse_bicond() {
    expect_rule("<->", inner::Rule::bicond, "<->");
    for expr in permutate_case("bicond") {
        expect_rule(&expr, inner::Rule::bicond, &expr);
    }
}

#[test]
fn parse_equals() {
    expect_rule("=", inner::Rule::equals, "=");
    for expr in permutate_case("equals") {
        expect_rule(&expr, inner::Rule::equals, &expr);
    }
}

#[test]
fn parse_identifier() {
    expect_rule("a", inner::Rule::identifier, "a");
    expect_rule("xyz", inner::Rule::identifier, "xyz");
    expect_rule("xyz_ab-c0", inner::Rule::identifier, "xyz_ab-c0");
    expect_rule("\"xyz abc\"", inner::Rule::identifier, "\"xyz abc\"");
    expect_rule("'xyz abc'", inner::Rule::identifier, "'xyz abc'");
}

#[test]
fn parse_term() {
    expect_rule("a", inner::Rule::term, "a");
    expect_rule("(a)", inner::Rule::term, "(a)");
    expect_rule("(a + b)", inner::Rule::term, "(a + b)");
}

#[test]
fn parse_expr() {
    expect_rule("a", inner::Rule::expr, "a");
    expect_rule("(a)", inner::Rule::expr, "(a)");
    expect_rule("a + b", inner::Rule::expr, "a + b");
    expect_rule("(a + b)", inner::Rule::expr, "(a + b)");
    expect_rule("(a + b) = c", inner::Rule::expr, "(a + b) = c");
    expect_rule(
        "!(a + b) = !c -> x",
        inner::Rule::expr,
        "!(a + b) = !c -> x",
    );
}

fn expect_rule<X, Y>(expr: X, rule: inner::Rule, span: Y)
where
    X: AsRef<str>,
    Y: AsRef<str>,
{
    let pair = match inner::Parser::parse(rule, expr.as_ref()) {
        Ok(mut pair) => pair.next().unwrap(),
        Err(e) => panic!("{}", e.to_string()),
    };
    let parsed = pair.as_rule();
    let content = pair.as_str();

    assert_eq!(rule, parsed);
    assert_eq!(span.as_ref(), content);
}

fn permutate_case<X>(expr: X) -> impl IntoIterator<Item = String>
where
    X: AsRef<str>,
{
    let expr = expr.as_ref();
    let mut len = 1usize << expr.len();
    let mut result = vec![String::from(""); len];

    expr.chars().for_each(|c| {
        len /= 2;
        let mut pair = [
            c.to_lowercase().next().unwrap(),
            c.to_uppercase().next().unwrap(),
        ];

        result.iter_mut().fold(0, |mut j, r| {
            if j == len {
                let y = pair[0];
                pair[0] = pair[1];
                pair[1] = y;
                j = 1;
            } else {
                j += 1;
            }
            r.push(pair[0]);
            j
        });
    });

    result
}

#[test]
fn permutate_case_sanity() {
    assert_eq!(
        permutate_case("t").into_iter().collect::<HashSet<_>>(),
        HashSet::from_iter(vec!["t".to_string(), "T".to_string(),])
    );
    assert_eq!(
        permutate_case("ot").into_iter().collect::<HashSet<_>>(),
        HashSet::from_iter(vec![
            "ot".to_string(),
            "oT".to_string(),
            "Ot".to_string(),
            "OT".to_string(),
        ])
    );
    assert_eq!(
        permutate_case("not").into_iter().collect::<HashSet<_>>(),
        HashSet::from_iter(vec![
            "not".to_string(),
            "noT".to_string(),
            "nOt".to_string(),
            "nOT".to_string(),
            "Not".to_string(),
            "NoT".to_string(),
            "NOt".to_string(),
            "NOT".to_string(),
        ])
    );
    assert_eq!(
        permutate_case("pair").into_iter().collect::<HashSet<_>>(),
        HashSet::from_iter(vec![
            "pair".to_string(),
            "paiR".to_string(),
            "paIr".to_string(),
            "paIR".to_string(),
            "pAir".to_string(),
            "pAiR".to_string(),
            "pAIr".to_string(),
            "pAIR".to_string(),
            "Pair".to_string(),
            "PaiR".to_string(),
            "PaIr".to_string(),
            "PaIR".to_string(),
            "PAir".to_string(),
            "PAiR".to_string(),
            "PAIr".to_string(),
            "PAIR".to_string(),
        ])
    );
}