1
use merc_utilities::test_logger;
2
use test_case::test_case;
3

            
4
use merc_aterm::ATerm;
5
use merc_data::DataExpression;
6
use merc_data::to_untyped_data_expression;
7
use merc_rec_tests::load_rec_from_strings;
8
use merc_sabre::InnermostRewriter;
9
use merc_sabre::NaiveRewriter;
10
use merc_sabre::RewriteEngine;
11
use merc_sabre::RewriteSpecification;
12
use merc_sabre::SabreRewriter;
13

            
14
/// Loads the rewrite specification and the terms to evaluate from the given REC files.
15
31
fn load_spec(rec_files: &[&str]) -> (RewriteSpecification, Vec<DataExpression>) {
16
31
    let (syntax_spec, syntax_terms) = load_rec_from_strings(rec_files).unwrap();
17
31
    let spec = syntax_spec.to_rewrite_spec();
18
31
    let terms = syntax_terms
19
31
        .iter()
20
49
        .map(|t| to_untyped_data_expression(t.clone(), None))
21
31
        .collect();
22
31
    (spec, terms)
23
31
}
24

            
25
/// Parses the expected results, one term per line, asserting that the number of
26
/// lines matches the number of terms so a drifted snapshot fails clearly.
27
31
fn parse_expected(terms: &[DataExpression], expected_result: &str) -> Vec<DataExpression> {
28
    // The snapshot files end in a trailing newline; ignore the resulting empty line.
29
31
    let lines: Vec<&str> = expected_result
30
31
        .strip_suffix('\n')
31
31
        .unwrap_or(expected_result)
32
31
        .split('\n')
33
31
        .collect();
34
31
    assert_eq!(
35
31
        lines.len(),
36
31
        terms.len(),
37
        "the snapshot has {} lines but the specification evaluates {} terms",
38
        lines.len(),
39
        terms.len()
40
    );
41

            
42
31
    lines
43
31
        .iter()
44
49
        .map(|line| to_untyped_data_expression(ATerm::from_string(line).unwrap(), None))
45
31
        .collect()
46
31
}
47

            
48
/// Rewrites every term with `rewriter` and compares against the expected results.
49
57
fn check_rewriter(
50
57
    rewriter: &mut impl RewriteEngine,
51
57
    terms: &[DataExpression],
52
57
    expected: &[DataExpression],
53
57
    engine: &str,
54
57
) {
55
91
    for (term, expected_result) in terms.iter().zip(expected) {
56
91
        let result = rewriter.rewrite(term);
57
91
        assert_eq!(
58
91
            &result, expected_result,
59
            "The {engine} rewrite result doesn't match the expected result"
60
        );
61
    }
62
57
}
63

            
64
/// A local function to share the rec_test functionality.
65
26
fn rec_test(rec_files: Vec<&str>, expected_result: &str) {
66
26
    test_logger();
67

            
68
26
    let (spec, terms) = load_spec(&rec_files);
69
26
    let expected = parse_expected(&terms, expected_result);
70

            
71
26
    check_rewriter(&mut InnermostRewriter::new(&spec), &terms, &expected, "inner");
72
26
    check_rewriter(&mut SabreRewriter::new(&spec), &terms, &expected, "sabre");
73
26
}
74

            
75
#[cfg_attr(miri, ignore)]
76
#[test_case(vec![include_str!("../../../examples/REC/rec/benchexpr10.rec"), include_str!("../../../examples/REC/rec/asfsdfbenchmark.rec")], include_str!("snapshot/result_benchexpr10.txt") ; "benchexpr10")]
77
#[test_case(vec![include_str!("../../../examples/REC/rec/benchsym10.rec"), include_str!("../../../examples/REC/rec/asfsdfbenchmark.rec")], include_str!("snapshot/result_benchsym10.txt") ; "benchsym10")]
78
#[test_case(vec![include_str!("../../../examples/REC/rec/bubblesort10.rec"), include_str!("../../../examples/REC/rec/bubblesort.rec")], include_str!("snapshot/result_bubblesort10.txt") ; "bubblesort10")]
79
#[test_case(vec![include_str!("../../../examples/REC/rec/bubblesort20.rec"), include_str!("../../../examples/REC/rec/bubblesort.rec")], include_str!("snapshot/result_bubblesort20.txt") ; "bubblesort20")]
80
#[test_case(vec![include_str!("../../../examples/REC/rec/calls.rec")], include_str!("snapshot/result_calls.txt") ; "calls")]
81
#[test_case(vec![include_str!("../../../examples/REC/rec/check1.rec")], include_str!("snapshot/result_check1.txt") ; "check1")]
82
#[test_case(vec![include_str!("../../../examples/REC/rec/check2.rec")], include_str!("snapshot/result_check2.txt") ; "check2")]
83
#[test_case(vec![include_str!("../../../examples/REC/rec/confluence.rec")], include_str!("snapshot/result_confluence.txt") ; "confluence")]
84
#[test_case(vec![include_str!("../../../examples/REC/rec/factorial5.rec"), include_str!("../../../examples/REC/rec/factorial.rec")], include_str!("snapshot/result_factorial5.txt") ; "factorial5")]
85
#[test_case(vec![include_str!("../../../examples/REC/rec/fibonacci05.rec"), include_str!("../../../examples/REC/rec/fibonacci.rec")], include_str!("snapshot/result_fibonacci05.txt") ; "fibonacci05")]
86
#[test_case(vec![include_str!("../../../examples/REC/rec/garbagecollection.rec")], include_str!("snapshot/result_garbagecollection.txt") ; "garbagecollection")]
87
#[test_case(vec![include_str!("../../../examples/REC/rec/hanoi4.rec"), include_str!("../../../examples/REC/rec/hanoi.rec")], include_str!("snapshot/result_hanoi4.txt") ; "hanoi4")]
88
#[test_case(vec![include_str!("../../../examples/REC/rec/logic3.rec")], include_str!("snapshot/result_logic3.txt") ; "logic3")]
89
#[test_case(vec![include_str!("../../../examples/REC/rec/merge.rec")], include_str!("snapshot/result_merge.txt") ; "merge")]
90
#[test_case(vec![include_str!("../../../examples/REC/rec/mergesort10.rec"), include_str!("../../../examples/REC/rec/mergesort.rec")], include_str!("snapshot/result_mergesort10.txt") ; "mergesort10")]
91
#[test_case(vec![include_str!("../../../examples/REC/rec/missionaries2.rec"), include_str!("../../../examples/REC/rec/missionaries.rec")], include_str!("snapshot/result_missionaries2.txt") ; "missionaries2")]
92
#[test_case(vec![include_str!("../../../examples/REC/rec/missionaries3.rec"), include_str!("../../../examples/REC/rec/missionaries.rec")], include_str!("snapshot/result_missionaries3.txt") ; "missionaries3")]
93
#[test_case(vec![include_str!("../../../examples/REC/rec/quicksort10.rec"), include_str!("../../../examples/REC/rec/quicksort.rec")], include_str!("snapshot/result_quicksort10.txt") ; "quicksort10")]
94
#[test_case(vec![include_str!("../../../examples/REC/rec/revelt.rec")], include_str!("snapshot/result_revelt.txt") ; "revelt")]
95
#[test_case(vec![include_str!("../../../examples/REC/rec/searchinconditions.rec")], include_str!("snapshot/result_searchinconditions.txt") ; "searchinconditions")]
96
#[test_case(vec![include_str!("../../../examples/REC/rec/sieve20.rec"), include_str!("../../../examples/REC/rec/sieve.rec")], include_str!("snapshot/result_sieve20.txt") ; "sieve20")]
97
#[test_case(vec![include_str!("../../../examples/REC/rec/sieve100.rec"), include_str!("../../../examples/REC/rec/sieve.rec")], include_str!("snapshot/result_sieve100.txt") ; "sieve100")]
98
#[test_case(vec![include_str!("../../../examples/REC/rec/soundnessofparallelengines.rec")], include_str!("snapshot/result_soundnessofparallelengines.txt") ; "soundnessofparallelengines")]
99
#[test_case(vec![include_str!("../../../examples/REC/rec/tak18.rec"), include_str!("../../../examples/REC/rec/tak.rec")], include_str!("snapshot/result_tak18.txt") ; "tak18")]
100
#[test_case(vec![include_str!("../../../examples/REC/rec/tautologyhard.rec")], include_str!("snapshot/result_tautologyhard.txt") ; "tautologyhard")]
101
#[test_case(vec![include_str!("../../../examples/REC/rec/tricky.rec")], include_str!("snapshot/result_tricky.txt") ; "tricky")]
102
26
fn test_rec_specification(rec_files: Vec<&str>, expected_result: &str) {
103
26
    rec_test(rec_files, expected_result);
104
26
}
105

            
106
#[cfg_attr(miri, ignore)]
107
#[test_case(vec![include_str!("../../../examples/REC/rec/check1.rec")], include_str!("snapshot/result_check1.txt") ; "check1")]
108
#[test_case(vec![include_str!("../../../examples/REC/rec/check2.rec")], include_str!("snapshot/result_check2.txt") ; "check2")]
109
#[test_case(vec![include_str!("../../../examples/REC/rec/logic3.rec")], include_str!("snapshot/result_logic3.txt") ; "logic3")]
110
#[test_case(vec![include_str!("../../../examples/REC/rec/searchinconditions.rec")], include_str!("snapshot/result_searchinconditions.txt") ; "searchinconditions")]
111
#[test_case(vec![include_str!("../../../examples/REC/rec/tautologyhard.rec")], include_str!("snapshot/result_tautologyhard.txt") ; "tautologyhard")]
112
5
fn test_rec_specification_naive(rec_files: Vec<&str>, expected_result: &str) {
113
5
    test_logger();
114

            
115
5
    let (spec, terms) = load_spec(&rec_files);
116
5
    let expected = parse_expected(&terms, expected_result);
117

            
118
5
    check_rewriter(&mut NaiveRewriter::new(&spec), &terms, &expected, "naive");
119
5
}
120

            
121
// These tests are too slow without optimisations.
122
#[cfg_attr(miri, ignore)]
123
#[cfg(not(debug_assertions))]
124
#[test_case(vec![include_str!("../../../examples/REC/rec/benchexpr20.rec"), include_str!("../../../examples/REC/rec/asfsdfbenchmark.rec")], include_str!("snapshot/result_benchexpr20.txt") ; "benchexpr20")]
125
#[test_case(vec![include_str!("../../../examples/REC/rec/benchsym20.rec"), include_str!("../../../examples/REC/rec/asfsdfbenchmark.rec")], include_str!("snapshot/result_benchsym20.txt") ; "benchsym20")]
126
#[test_case(vec![include_str!("../../../examples/REC/rec/bubblesort100.rec"), include_str!("../../../examples/REC/rec/bubblesort.rec")], include_str!("snapshot/result_bubblesort100.txt") ; "bubblesort100")]
127
#[test_case(vec![include_str!("../../../examples/REC/rec/empty.rec")], include_str!("snapshot/result_empty.txt") ; "empty")]
128
#[test_case(vec![include_str!("../../../examples/REC/rec/evalexpr.rec")], include_str!("snapshot/result_evalexpr.txt") ; "evalexpr")]
129
#[test_case(vec![include_str!("../../../examples/REC/rec/evaltree.rec")], include_str!("snapshot/result_evaltree.txt") ; "evaltree")]
130
#[test_case(vec![include_str!("../../../examples/REC/rec/factorial6.rec"), include_str!("../../../examples/REC/rec/factorial.rec")], include_str!("snapshot/result_factorial6.txt") ; "factorial6")]
131
#[test_case(vec![include_str!("../../../examples/REC/rec/hanoi8.rec"), include_str!("../../../examples/REC/rec/hanoi.rec")], include_str!("snapshot/result_hanoi8.txt") ; "hanoi8")]
132
#[test_case(vec![include_str!("../../../examples/REC/rec/natlist.rec")], include_str!("snapshot/result_natlist.txt") ; "natlist")]
133
#[test_case(vec![include_str!("../../../examples/REC/rec/oddeven.rec")], include_str!("snapshot/result_oddeven.txt") ; "oddeven")]
134
#[test_case(vec![include_str!("../../../examples/REC/rec/order.rec")], include_str!("snapshot/result_order.txt") ; "order")]
135
#[test_case(vec![include_str!("../../../examples/REC/rec/permutations6.rec"), include_str!("../../../examples/REC/rec/permutations.rec")], include_str!("snapshot/result_permutations6.txt") ; "permutations6")]
136
#[test_case(vec![include_str!("../../../examples/REC/rec/revnat100.rec"), include_str!("../../../examples/REC/rec/revnat.rec")], include_str!("snapshot/result_revnat100.txt") ; "revnat100")]
137
fn test_rec_specification_release(rec_files: Vec<&str>, expected_result: &str) {
138
    rec_test(rec_files, expected_result);
139
}
140

            
141
// These tests use more stack memory than is available on Windows.
142
#[cfg_attr(miri, ignore)]
143
#[cfg(all(unix, not(debug_assertions)))]
144
#[ignore]
145
#[test_case(vec![include_str!("../../../examples/REC/rec/sieve1000.rec"), include_str!("../../../examples/REC/rec/sieve.rec")], include_str!("snapshot/result_sieve1000.txt") ; "sieve1000")]
146
#[test_case(vec![include_str!("../../../examples/REC/rec/revnat1000.rec"), include_str!("../../../examples/REC/rec/revnat.rec")], include_str!("snapshot/result_revnat1000.txt") ; "revnat1000")]
147
#[test_case(vec![include_str!("../../../examples/REC/rec/closure.rec")], include_str!("snapshot/result_closure.txt") ; "closure")]
148
#[test_case(vec![include_str!("../../../examples/REC/rec/dart.rec")], include_str!("snapshot/result_dart.txt") ; "dart")]
149
#[test_case(vec![include_str!("../../../examples/REC/rec/factorial7.rec"), include_str!("../../../examples/REC/rec/factorial.rec")], include_str!("snapshot/result_factorial7.txt") ; "factorial7")]
150
#[test_case(vec![include_str!("../../../examples/REC/rec/factorial8.rec"), include_str!("../../../examples/REC/rec/factorial.rec")], include_str!("snapshot/result_factorial8.txt") ; "factorial8")]
151
// #[test_case(vec![include_str!("../../../examples/REC/rec/factorial9.rec"), include_str!("../../../examples/REC/rec/factorial.rec")], include_str!("snapshot/result_factorial9.txt") ; "factorial9")]
152
#[test_case(vec![include_str!("../../../examples/REC/rec/fibonacci18.rec"), include_str!("../../../examples/REC/rec/fibonacci.rec")], include_str!("snapshot/result_fibonacci18.txt") ; "fibonacci18")]
153
#[test_case(vec![include_str!("../../../examples/REC/rec/fibonacci19.rec"), include_str!("../../../examples/REC/rec/fibonacci.rec")], include_str!("snapshot/result_fibonacci19.txt") ; "fibonacci19")]
154
#[test_case(vec![include_str!("../../../examples/REC/rec/fibonacci20.rec"), include_str!("../../../examples/REC/rec/fibonacci.rec")], include_str!("snapshot/result_fibonacci20.txt") ; "fibonacci20")]
155
#[test_case(vec![include_str!("../../../examples/REC/rec/fibonacci21.rec"), include_str!("../../../examples/REC/rec/fibonacci.rec")], include_str!("snapshot/result_fibonacci21.txt") ; "fibonacci21")]
156
#[test_case(vec![include_str!("../../../examples/REC/rec/hanoi12.rec"), include_str!("../../../examples/REC/rec/hanoi.rec")], include_str!("snapshot/result_hanoi12.txt") ; "hanoi12")]
157
#[test_case(vec![include_str!("../../../examples/REC/rec/permutations7.rec"), include_str!("../../../examples/REC/rec/permutations.rec")], include_str!("snapshot/result_permutations7.txt") ; "permutations7")]
158
fn test_rec_specification_largestack(rec_files: Vec<&str>, expected_result: &str) {
159
    rec_test(rec_files, expected_result);
160
}
161

            
162
// // These REC tests have META data that is not supported by the current implementation.
163
// #[test_case(vec![include_str!("../../../examples/REC/rec/add8.rec")], include_str!("snapshot/result_add8.txt") ; "add8")]
164
// #[test_case(vec![include_str!("../../../examples/REC/rec/add16.rec")], include_str!("snapshot/result_add16.txt") ; "add16")]
165
// #[test_case(vec![include_str!("../../../examples/REC/rec/add32.rec")], include_str!("snapshot/result_add32.txt") ; "add32")]
166
// #[test_case(vec![include_str!("../../../examples/REC/rec/mul8.rec")], include_str!("snapshot/result_mul8.txt") ; "mul8")]
167
// #[test_case(vec![include_str!("../../../examples/REC/rec/mul16.rec")], include_str!("snapshot/result_mul16.txt") ; "mul16")]
168
// #[test_case(vec![include_str!("../../../examples/REC/rec/mul32.rec")], include_str!("snapshot/result_mul32.txt") ; "mul32")]
169
// #[test_case(vec![include_str!("../../../examples/REC/rec/omul8.rec")], include_str!("snapshot/result_omul8.txt") ; "omul8")]
170
// #[test_case(vec![include_str!("../../../examples/REC/rec/omul32.rec")], include_str!("snapshot/result_omul32.txt") ; "omul32")]
171
// #[test_case(vec![include_str!("../../../examples/REC/rec/intnat.rec")], include_str!("snapshot/result_intnat.txt") ; "intnat")]