Skip to content

Commit f7480ac

Browse files
committed
add a proptest-based test for reachability as a POC
1 parent 1c540c8 commit f7480ac

File tree

3 files changed

+65
-0
lines changed

3 files changed

+65
-0
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,6 @@ edition = "2018"
1212
[badges]
1313
is-it-maintained-issue-resolution = { repository = "https://github.com/rust-lang-nursery/datafrog" }
1414
is-it-maintained-open-issues = { repository = "https://github.com/rust-lang-nursery/datafrog" }
15+
16+
[dev-dependencies]
17+
proptest = "0.8.7"

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ use std::rc::Rc;
1717

1818
mod join;
1919
mod map;
20+
mod test;
2021
mod treefrog;
2122
pub use crate::treefrog::{
2223
extend_anti::ExtendAnti,

src/test.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
#![cfg(test)]
2+
3+
use crate::Relation;
4+
use crate::Iteration;
5+
use crate::RelationLeaper;
6+
use proptest::prelude::*;
7+
use proptest::{proptest, proptest_helper};
8+
9+
fn inputs() -> impl Strategy<Value = Vec<(u32, u32)>> {
10+
prop::collection::vec((0_u32..100, 0_u32..100), 1..100)
11+
}
12+
13+
fn reachable_with_join(edges: &[(u32, u32)]) -> Relation<(u32, u32)> {
14+
let edges = Relation::from(edges.iter().cloned());
15+
let mut iteration = Iteration::new();
16+
17+
let edges_by_successor = iteration.variable::<(u32, u32)>("edges_invert");
18+
edges_by_successor.insert(Relation::from(edges.iter().map(|&(n1, n2)| (n2, n1))));
19+
20+
let reachable = iteration.variable::<(u32, u32)>("reachable");
21+
reachable.insert(edges);
22+
23+
while iteration.changed() {
24+
// reachable(N1, N3) :- edges(N1, N2), reachable(N2, N3).
25+
reachable.from_join(&reachable, &edges_by_successor, |&_, &n3, &n1| (n1, n3));
26+
}
27+
28+
reachable.complete()
29+
}
30+
31+
fn reachable_with_leapfrog(edges: &[(u32, u32)]) -> Relation<(u32, u32)> {
32+
let edges = Relation::from(edges.iter().cloned());
33+
let mut iteration = Iteration::new();
34+
35+
let edges_by_successor = Relation::from(edges.iter().map(|&(n1, n2)| (n2, n1)));
36+
37+
let reachable = iteration.variable::<(u32, u32)>("reachable");
38+
reachable.insert(edges);
39+
40+
while iteration.changed() {
41+
// reachable(N1, N3) :- edges(N1, N2), reachable(N2, N3).
42+
reachable.from_leapjoin(
43+
&reachable,
44+
&mut [
45+
&mut edges_by_successor.extend_with(|&(n2, _)| n2),
46+
],
47+
|&(_, n3), &n1| (n1, n3),
48+
);
49+
}
50+
51+
reachable.complete()
52+
}
53+
54+
proptest! {
55+
#[test]
56+
fn reachable(edges in inputs()) {
57+
let reachable1 = reachable_with_join(&edges);
58+
let reachable2 = reachable_with_leapfrog(&edges);
59+
assert_eq!(reachable1.elements, reachable2.elements);
60+
}
61+
}

0 commit comments

Comments
 (0)