use traceforge::*;
use channel::Builder;
use loc::CommunicationModel;
const TEST_RUNS: u32 = 20;
fn ltr_config() -> Config {
Config::builder()
.with_policy(SchedulePolicy::Arbitrary)
.build()
}
fn arbitrary_config() -> Config {
Config::builder()
.with_policy(SchedulePolicy::Arbitrary)
.build()
}
#[test]
fn smoke() {
let stats = traceforge::verify(ltr_config(), || {
let chan = Builder::new().with_name("foo").build();
let chanp = Builder::new().with_name("bar").build();
chan.0.send_msg(42);
chanp.0.send_msg(17);
let _ = chan.1.recv_msg_block();
});
assert_eq!(stats.execs, 1);
}
#[test]
fn equal_channels() {
let stats = traceforge::verify(ltr_config(), || {
let id = "foo";
let chan1 = Builder::new().with_name(id).build();
let chan2 = Builder::<i32>::new().with_name(id).build();
chan1.0.send_msg(1);
let _ = chan2.1.recv_msg();
});
assert_eq!(stats.execs, 2);
}
#[test]
fn forward_revisit() {
for comm in [CommunicationModel::NoOrder, CommunicationModel::LocalOrder] {
let stats = traceforge::verify(ltr_config(), move || {
let chan = Builder::new().with_comm(comm).build();
chan.0.send_msg(1);
chan.0.send_msg(2);
let _ = thread::spawn(move || {
let _ = chan.1.recv_msg();
});
});
match comm {
CommunicationModel::NoOrder => assert_eq!(stats.execs, 3),
CommunicationModel::LocalOrder => assert_eq!(stats.execs, 2),
_ => {}
}
}
}
#[test]
fn backward_revisit() {
for comm in [CommunicationModel::NoOrder, CommunicationModel::LocalOrder] {
let stats = traceforge::verify(ltr_config(), move || {
let (sender, receiver) = Builder::new().with_comm(comm).build();
let _ = thread::spawn(move || {
sender.send_msg(1);
});
let _ = receiver.recv_msg();
});
assert_eq!(stats.execs, 2);
}
}
#[test]
fn no_prefix_rev_cb() {
let stats = traceforge::verify(ltr_config(), || {
let (sender, receiver) = Builder::new().build();
let _ = receiver.recv_msg();
let _ = thread::spawn(move || {
sender.send_msg(1);
});
});
assert_eq!(stats.execs, 1);
}
#[test]
fn no_prefix_rev_ej() {
let statsp = traceforge::verify(ltr_config(), || {
let (sender, receiver) = Builder::new().build();
let p = thread::spawn(move || {
let _ = receiver.recv_msg();
});
p.join().unwrap();
sender.send_msg(1);
});
assert_eq!(statsp.execs, 1);
}
#[test]
fn maximality1() {
let stats = traceforge::verify(ltr_config(), || {
let (sender, receiver) = Builder::new().build();
let _ = thread::spawn(move || {
sender.send_msg(1);
});
let _ = receiver.recv_msg();
let _ = receiver.recv_msg();
});
assert_eq!(stats.execs, 3);
}
#[test]
fn maximality2() {
for comm in [CommunicationModel::NoOrder, CommunicationModel::LocalOrder] {
for _ in 0..TEST_RUNS {
let stats = traceforge::verify(arbitrary_config(), move || {
let (sender, receiver) = Builder::new().with_comm(comm).build();
let _ = thread::spawn(move || {
sender.send_msg(1);
sender.send_msg(2);
});
let _ = receiver.recv_msg();
let _ = receiver.recv_msg();
});
match comm {
CommunicationModel::NoOrder => assert_eq!(stats.execs, 7),
CommunicationModel::LocalOrder => assert_eq!(stats.execs, 4),
_ => {}
}
}
}
}
#[test]
fn stress_max() {
for comm in [CommunicationModel::NoOrder, CommunicationModel::LocalOrder] {
for r in 0..10 {
for _ in 0..TEST_RUNS {
let stats = traceforge::verify(arbitrary_config(), move || {
let (sender, receiver) = Builder::new().with_comm(comm).build();
let _ = thread::spawn(move || {
let s = if comm == CommunicationModel::NoOrder {
2
} else {
r
};
for _ in 0..s {
sender.send_msg(1);
}
});
for _ in 0..r {
let _ = receiver.recv_msg();
}
});
let expected = if comm == CommunicationModel::NoOrder {
(r * r + r + 1) as usize
} else {
2_i32.pow(r) as usize
};
assert_eq!(stats.execs, expected);
}
}
}
}
#[test]
fn block() {
let stats = traceforge::verify(ltr_config(), || {
let chan = Builder::new().build();
let () = chan.1.recv_msg_block();
});
assert_eq!(stats.execs, 0);
assert_eq!(stats.block, 1);
}
#[test]
fn rrb_s() {
let stats = traceforge::verify(ltr_config(), move || {
let (sender, receiver) = Builder::new().build();
let _ = thread::spawn(move || {
sender.send_msg(1);
});
let _ = receiver.recv_msg();
let _ = receiver.recv_msg_block();
});
assert_eq!(stats.execs, 1);
assert_eq!(stats.block, 1);
}
#[test]
fn blocking_rev() {
let stats = traceforge::verify(ltr_config(), move || {
let (sender, receiver) = Builder::new()
.with_comm(CommunicationModel::NoOrder)
.build();
let _ = thread::spawn(move || {
sender.send_msg(1);
sender.send_msg(2);
sender.send_msg(3);
});
let _ = receiver.recv_msg_block();
let _ = receiver.recv_msg_block();
});
assert_eq!(stats.execs, 6);
}
#[test]
fn select() {
let stats = traceforge::verify(ltr_config(), move || {
let ch1 = Builder::new()
.with_comm(CommunicationModel::NoOrder)
.build();
let ch2 = Builder::new()
.with_comm(CommunicationModel::NoOrder)
.build();
ch1.0.send_msg(1);
ch2.0.send_msg(1);
let _ = traceforge::select_msg([&ch1.1, &ch2.1].iter(), CommunicationModel::NoOrder)
.map(|x| x.0);
});
assert_eq!(stats.execs, 3);
}
#[test]
fn select_rev() {
for comm in [CommunicationModel::NoOrder, CommunicationModel::LocalOrder] {
for _ in 0..TEST_RUNS {
let stats = traceforge::verify(arbitrary_config(), move || {
let (sender1, receiver1) = Builder::new().with_comm(comm).build();
let (sender2, receiver2) = Builder::new().with_comm(comm).build();
let (sender3, receiver3) = Builder::new().with_comm(comm).build();
let _ = thread::spawn(move || {
sender1.send_msg(1);
sender2.send_msg(2);
sender3.send_msg(3);
});
let _ = traceforge::select_msg_block([&receiver1, &receiver2].iter(), comm).0;
let _ = traceforge::select_msg_block([&receiver1, &receiver3].iter(), comm).0;
let _ = traceforge::select_msg_block([&receiver2, &receiver3].iter(), comm).0;
});
if comm == CommunicationModel::NoOrder {
assert_eq!(stats.execs, 2);
assert_eq!(stats.block, 1);
} else {
assert_eq!(stats.execs, 1);
assert_eq!(stats.block, 0);
}
}
}
}
#[test]
fn three_arbitrary_threads() {
for _ in 0..TEST_RUNS {
let stats = traceforge::verify(arbitrary_config(), move || {
let (sender1, receiver1) = Builder::new().build();
let (sender2, receiver2) = Builder::new().build();
let (sender3, receiver3) = Builder::new().build();
let _ = thread::spawn(move || {
sender1.send_msg(1);
let _ = receiver2.recv_msg();
});
let _ = thread::spawn(move || {
sender2.send_msg(2);
sender3.send_msg(3);
});
let comm = CommunicationModel::default();
let _ = traceforge::select_msg_block([&receiver1, &receiver3].iter(), comm).0;
let _ = traceforge::select_msg([&receiver1, &receiver3].iter(), comm).map(|x| x.0);
});
assert_eq!(stats.execs, 8);
assert_eq!(stats.block, 0);
}
}
#[test]
fn legacy_channel() {
for _ in 0..TEST_RUNS {
let stats = traceforge::verify(arbitrary_config(), || {
let h = thread::spawn(move || {
let _: Option<i32> = traceforge::recv_msg();
});
if (<bool>::nondet)() {
traceforge::send_msg(h.thread().id(), 42);
} else {
traceforge::send_msg(h.thread().id(), 17);
}
});
assert_eq!(stats.execs, 4);
assert_eq!(stats.block, 0);
}
}
#[test]
fn select_index() {
let _stats = traceforge::verify(ltr_config(), move || {
let (sender1, receiver1) = Builder::new()
.with_comm(CommunicationModel::NoOrder)
.build();
let (sender2, receiver2) = Builder::new()
.with_comm(CommunicationModel::NoOrder)
.build();
let chans = [&receiver1, &receiver2];
sender1.send_msg(42u32);
sender2.send_msg(43u32);
let comm = CommunicationModel::default();
let (v, i) = traceforge::select_msg_block(chans.iter(), comm);
assert_eq!(v as usize, i + 42);
});
}
#[test]
#[should_panic(expected = "Detected duplicate channel")]
fn select_no_duplicate_match() {
let stats = traceforge::verify(ltr_config(), move || {
let (sender1, receiver1) = Builder::new().with_name(42).build();
let (_sender2, receiver2) = Builder::new().with_name(42).build();
let chans = [&receiver1, &receiver2];
sender1.send_msg(());
let comm = CommunicationModel::default();
let () = traceforge::select_msg_block(chans.iter(), comm).0;
});
assert_eq!(stats.execs, 1);
}