1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
//! Assorted helpers, especially for testing.
pub(super) mod multikeymultivaluemap;

use crate::Domain;
use crate::Goal;
use crate::Query;
use crate::ReifyIn;
use crate::State;
use itertools::Itertools;
use std::fmt::Debug;

pub(crate) fn all_permutations<'a, D>(
    goals: Vec<Goal<'a, D>>,
) -> impl Iterator<Item = Vec<Goal<'a, D>>> + 'a
where
    D: Domain<'a> + 'a,
{
    let goals_len = goals.len();
    goals.into_iter().permutations(goals_len)
}

pub(crate) fn goals_resolve_to<'a, D, Q>(goals: &[Goal<'a, D>], query: Q) -> Vec<Q::Reified>
where
    D: Domain<'a> + 'a,
    Q: ReifyIn<'a, D> + 'a,
{
    let goal = Goal::all(goals.to_owned());
    goal_resolves_to(goal, query)
}

pub(crate) fn goal_resolves_to<'a, D, Q>(goal: Goal<'a, D>, query: Q) -> Vec<Q::Reified>
where
    D: Domain<'a> + 'a,
    Q: ReifyIn<'a, D> + 'a,
{
    let state = goal.apply(State::new());
    state.query(query).collect()
}

/// Test helper for ensuring that goals work no matter the order they are
/// applied.
///
/// When building lower level goals, it can be easy to make mistakes where
/// something appears to work fine but breaks when you reorder the goals. This
/// is especially a problem with [projection goals](crate::goals::project).
///
/// This function takes a `Vec<Goal<_>>`, a [Query](crate::Query) and a `Vec`
/// containing the expected values. It will try every permutation of the goals
/// (wrapped in an [`all` goal](crate::goals::all!)) and panic if any of the
/// results vary.
///
/// # Example
/// ```
/// use canrun::{Goal, var, unify, assert_1, util};
/// use canrun::example::I32;
///
/// let x = var();
/// let goals: Vec<Goal<I32>> = vec![
///     unify(2, x),
///     assert_1(x, |x| *x > 1),
/// ];
///
/// util::assert_permutations_resolve_to(goals, x, vec![2]);
/// ```
pub fn assert_permutations_resolve_to<'a, D, Q>(
    goals: Vec<Goal<'a, D>>,
    query: Q,
    expected: Vec<Q::Reified>,
) where
    D: Domain<'a> + Debug + 'a,
    Q: ReifyIn<'a, D> + Clone + 'a,
    Q::Reified: PartialEq + Clone + Debug,
{
    for permutation in all_permutations(goals) {
        let results: Vec<Q::Reified> = goals_resolve_to(&permutation, query.clone());
        if !expected
            .clone()
            .into_iter()
            .permutations(expected.len())
            .any(|e: Vec<Q::Reified>| e == results)
        {
            dbg!(permutation, results, expected);
            panic!("The permutation of the goals printed above failed!");
        }
    }
}