Skip to content

Commit 3908812

Browse files
author
GBathie
committed
Add end-to-end tests
1 parent 1de4e5b commit 3908812

File tree

3 files changed

+156
-2
lines changed

3 files changed

+156
-2
lines changed

src/algos/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ pub trait BoolAlgoParams {
5252
}
5353

5454
/// Return a [`Vec`] containing all size-1 LTL formulas, that consist only of an atomic proposition.
55-
fn atoms(traces: &[Trace], atomic_propositions: Vec<String>) -> Vec<LtlFormula> {
55+
pub(crate) fn atoms(traces: &[Trace], atomic_propositions: Vec<String>) -> Vec<LtlFormula> {
5656
let mut atoms = Vec::new();
5757
for (i, s) in atomic_propositions.into_iter().enumerate() {
5858
let charac = traces
@@ -71,7 +71,10 @@ fn atoms(traces: &[Trace], atomic_propositions: Vec<String>) -> Vec<LtlFormula>
7171
}
7272

7373
/// Create an [`LtlCache`] containing all formulas in `atoms`.
74-
fn create_initial_cache(atoms: Vec<LtlFormula>, target: &[bool]) -> (Option<LtlFormula>, LtlCache) {
74+
pub(crate) fn create_initial_cache(
75+
atoms: Vec<LtlFormula>,
76+
target: &[bool],
77+
) -> (Option<LtlFormula>, LtlCache) {
7578
let mut ltl_cache = LtlCache::new();
7679
// Add empty line for size 0 in cache
7780
ltl_cache.new_line(0);

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,6 @@ pub mod traits;
88

99
/// Hash type of [`ltl::LtlFormula`] and [`bool::BoolFormula`], parametric for easier configuration.
1010
type HashType = u64;
11+
12+
#[cfg(test)]
13+
mod tests;

src/tests/mod.rs

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
use std::rc::Rc;
2+
3+
use crate::{
4+
algos::{atoms, create_initial_cache, enumeration::aux::enum_aux},
5+
formula::{rebuild_formula, tree::FormulaTree},
6+
ltl::{AtomicProposition, trace::parse_traces},
7+
ops::{binary::LtlBinaryOp, unary::LtlUnaryOp},
8+
};
9+
10+
/// Helper macro to implement helper functions :-)
11+
macro_rules! helper_ops_unary {
12+
($( $f:ident as $g:ident ),*) => {
13+
$(
14+
#[allow(non_snake_case, dead_code)]
15+
pub(crate) fn $g(f: FormulaTree) -> FormulaTree {
16+
FormulaTree::UnaryNode {
17+
op: LtlUnaryOp::$f,
18+
child: Rc::from(f),
19+
}
20+
}
21+
)*
22+
};
23+
}
24+
25+
macro_rules! helper_ops_binary {
26+
($( $f:ident as $g:ident ),*) => {
27+
$(
28+
#[allow(non_snake_case, dead_code)]
29+
pub(crate) fn $g(left: FormulaTree, right: FormulaTree) -> FormulaTree {
30+
FormulaTree::BinaryNode {
31+
op: LtlBinaryOp::$f,
32+
left: Rc::from(left),
33+
right: Rc::from(right),
34+
}
35+
}
36+
)*
37+
};
38+
}
39+
40+
helper_ops_unary!(Globally as G, Finally as F, WeakNext as X, StrongNext as SX);
41+
helper_ops_binary!(Until as U, Release as R, Or as OR, And as AND);
42+
fn build_atom(s: &str, i: usize) -> FormulaTree {
43+
FormulaTree::Atom(AtomicProposition(s.into(), i))
44+
}
45+
46+
fn test_ltl_search(instance: &str, expected: FormulaTree) {
47+
let instance = parse_traces(&instance);
48+
let v = expected.eval(&instance.traces).accepted_vec();
49+
assert_eq!(
50+
instance.target, v,
51+
"Expected formula does not satisfy input!"
52+
);
53+
54+
let atoms = atoms(&instance.traces, instance.atomic_propositions);
55+
// Add initial formulas
56+
let (atom, mut ltl_cache) = create_initial_cache(atoms, &instance.target);
57+
if let Some(f) = atom {
58+
let f = rebuild_formula(&f, &ltl_cache);
59+
assert_eq!(f, expected);
60+
return;
61+
}
62+
63+
let max_size = expected.size();
64+
65+
// Ltl search
66+
let ltl_res = enum_aux(
67+
&mut ltl_cache,
68+
&instance.operators,
69+
&instance.target,
70+
max_size,
71+
);
72+
73+
let f = rebuild_formula(&ltl_res.unwrap(), &ltl_cache);
74+
assert!(f.size() <= expected.size());
75+
}
76+
77+
#[test]
78+
fn globally_a() {
79+
let example = r#"{
80+
"positive_traces": [
81+
{
82+
"a": ["1", "1", "1", "1"]
83+
}
84+
],
85+
"negative_traces": [
86+
{
87+
"a": ["1", "1", "1", "0"]
88+
},
89+
{
90+
"a": ["0", "1"]
91+
},
92+
{
93+
"a": ["0", "0", "1", "1"]
94+
},
95+
{
96+
"a": ["1", "0", "1", "0"]
97+
}
98+
],
99+
"atomic_propositions": ["a"],
100+
"number_atomic_propositions": 1,
101+
"number_traces": 5,
102+
"number_positive_traces": 1,
103+
"number_negative_traces": 4,
104+
"max_length_traces": 4
105+
}"#;
106+
107+
let exp = G(build_atom("a", 0));
108+
test_ltl_search(example, exp);
109+
}
110+
111+
#[test]
112+
fn globally_a_or_b() {
113+
let example = r#"{
114+
"positive_traces": [
115+
{
116+
"a": ["0", "1", "1", "1"],
117+
"b": ["1", "0", "0", "0"]
118+
}
119+
],
120+
"negative_traces": [
121+
{
122+
"a": ["1", "1", "1", "0"],
123+
"b": ["0", "0", "0", "0"]
124+
},
125+
{
126+
"a": ["0", "1"],
127+
"b": ["0", "0"]
128+
},
129+
{
130+
"a": ["0", "0", "1", "1"],
131+
"b": ["1", "0", "0", "0"]
132+
},
133+
{
134+
"b": ["1", "1", "0", "0", "0"],
135+
"a": ["1", "0", "1", "0", "1"]
136+
}
137+
],
138+
"atomic_propositions": ["a", "b"],
139+
"number_atomic_propositions": 2,
140+
"number_traces": 5,
141+
"number_positive_traces": 1,
142+
"number_negative_traces": 4,
143+
"max_length_traces": 5
144+
}"#;
145+
146+
let exp = G(OR(build_atom("a", 0), build_atom("b", 1)));
147+
test_ltl_search(example, exp);
148+
}

0 commit comments

Comments
 (0)