use std::cell::RefCell;
use std::rc::Rc;
use simu::SimEnv;
use simu::Container;
type Log = Rc<RefCell<Vec<String>>>;
fn new_log() -> Log { Rc::new(RefCell::new(Vec::new())) }
#[test]
fn get_immediate_when_level_sufficient() {
let mut env = SimEnv::with_seed(0);
let h = env.handle();
let c = Container::new(10.0, 5.0);
let log = new_log();
{
let c = c.clone();
let log = log.clone();
env.spawn(async move {
c.get(3.0).await;
log.borrow_mut().push(format!("level:{}", c.level()));
});
}
env.run();
assert_eq!(*log.borrow(), vec!["level:2"]);
assert_eq!(h.now(), 0.0);
}
#[test]
fn put_immediate_when_space_available() {
let mut env = SimEnv::with_seed(0);
let h = env.handle();
let c = Container::empty(10.0);
let log = new_log();
{
let c = c.clone();
let log = log.clone();
env.spawn(async move {
c.put(4.0).await;
log.borrow_mut().push(format!("level:{}", c.level()));
});
}
env.run();
assert_eq!(*log.borrow(), vec!["level:4"]);
assert_eq!(h.now(), 0.0);
}
#[test]
fn get_blocks_then_wakes_on_put() {
let mut env = SimEnv::with_seed(0);
let c = Container::empty(10.0);
let log = new_log();
{
let h = env.handle();
let c = c.clone();
env.spawn(async move {
h.timeout(5.0).await;
c.put(3.0).await;
});
}
{
let h = env.handle();
let c = c.clone();
let log = log.clone();
env.spawn(async move {
c.get(3.0).await;
log.borrow_mut().push(format!("B_got:{}", h.now()));
});
}
env.run();
assert_eq!(*log.borrow(), vec!["B_got:5"]);
}
#[test]
fn put_blocks_then_wakes_on_get() {
let mut env = SimEnv::with_seed(0);
let c = Container::new(5.0, 5.0); let log = new_log();
{
let h = env.handle();
let c = c.clone();
env.spawn(async move {
h.timeout(3.0).await;
c.get(2.0).await;
});
}
{
let h = env.handle();
let c = c.clone();
let log = log.clone();
env.spawn(async move {
c.put(2.0).await;
log.borrow_mut().push(format!("B_put:{}", h.now()));
});
}
env.run();
assert_eq!(*log.borrow(), vec!["B_put:3"]);
}
#[test]
fn fifo_ordering_for_get_waiters() {
let mut env = SimEnv::with_seed(0);
let c = Container::empty(10.0);
let log = new_log();
for name in ["G1", "G2", "G3"] {
let h = env.handle();
let c = c.clone();
let log = log.clone();
env.spawn(async move {
c.get(4.0).await;
log.borrow_mut().push(format!("{}:{}", name, h.now()));
});
}
{
let h = env.handle();
let c = c.clone();
env.spawn(async move {
for _ in 0..3 {
h.timeout(1.0).await;
c.put(4.0).await;
}
});
}
env.run();
assert_eq!(*log.borrow(), vec!["G1:1", "G2:2", "G3:3"]);
}
#[test]
fn fifo_ordering_for_put_waiters() {
let mut env = SimEnv::with_seed(0);
let c = Container::new(4.0, 4.0); let log = new_log();
for name in ["P1", "P2", "P3"] {
let h = env.handle();
let c = c.clone();
let log = log.clone();
env.spawn(async move {
c.put(4.0).await;
log.borrow_mut().push(format!("{}:{}", name, h.now()));
});
}
{
let h = env.handle();
let c = c.clone();
env.spawn(async move {
for _ in 0..3 {
h.timeout(1.0).await;
c.get(4.0).await;
}
});
}
env.run();
assert_eq!(*log.borrow(), vec!["P1:1", "P2:2", "P3:3"]);
}
#[test]
fn fresh_small_get_queues_behind_blocked_large_get() {
let mut env = SimEnv::with_seed(0);
let c = Container::empty(10.0);
let log = new_log();
{
let h = env.handle();
let c = c.clone();
let log = log.clone();
env.spawn(async move {
c.get(8.0).await;
log.borrow_mut().push(format!("G_big:{}", h.now()));
});
}
{
let h = env.handle();
let c = c.clone();
let log = log.clone();
env.spawn(async move {
h.timeout(2.0).await;
c.get(3.0).await;
log.borrow_mut().push(format!("G_small:{}", h.now()));
});
}
{
let h = env.handle();
let c = c.clone();
env.spawn(async move {
h.timeout(1.0).await;
c.put(5.0).await;
h.timeout(2.0).await; c.put(5.0).await;
h.timeout(1.0).await; c.put(1.0).await;
});
}
env.run();
assert_eq!(*log.borrow(), vec!["G_big:3", "G_small:4"]);
}
#[test]
fn fresh_small_put_queues_behind_blocked_large_put() {
let mut env = SimEnv::with_seed(0);
let c = Container::new(10.0, 10.0); let log = new_log();
{
let h = env.handle();
let c = c.clone();
let log = log.clone();
env.spawn(async move {
c.put(8.0).await;
log.borrow_mut().push(format!("P_big:{}", h.now()));
});
}
{
let h = env.handle();
let c = c.clone();
let log = log.clone();
env.spawn(async move {
h.timeout(2.0).await;
c.put(3.0).await;
log.borrow_mut().push(format!("P_small:{}", h.now()));
});
}
{
let h = env.handle();
let c = c.clone();
env.spawn(async move {
h.timeout(1.0).await;
c.get(5.0).await;
h.timeout(2.0).await; c.get(5.0).await;
h.timeout(1.0).await; c.get(1.0).await;
});
}
env.run();
assert_eq!(*log.borrow(), vec!["P_big:3", "P_small:4"]);
}
#[test]
fn cascade_chain_get_put_get_put() {
let mut env = SimEnv::with_seed(0);
let c = Container::new(4.0, 4.0);
let log = new_log();
for label in ["P1", "P2"] {
let h = env.handle();
let c = c.clone();
let log = log.clone();
let label = label.to_string();
env.spawn(async move {
c.put(4.0).await;
log.borrow_mut().push(format!("{}:{}", label, h.now()));
});
}
{
let h = env.handle();
let c = c.clone();
let log = log.clone();
env.spawn(async move {
c.get(4.0).await; log.borrow_mut().push(format!("G_init:{}", h.now()));
});
}
for label in ["G1", "G2"] {
let h = env.handle();
let c = c.clone();
let log = log.clone();
let label = label.to_string();
env.spawn(async move {
c.get(4.0).await;
log.borrow_mut().push(format!("{}:{}", label, h.now()));
});
}
env.run();
let entries = log.borrow().clone();
assert_eq!(entries.len(), 5);
for entry in &entries {
assert!(
entry.ends_with(":0"),
"expected every cascade step at t=0, got: {:?}",
entries,
);
}
assert!(entries.contains(&"G_init:0".to_string()));
assert!(entries.contains(&"P1:0".to_string()));
assert!(entries.contains(&"P2:0".to_string()));
assert!(entries.contains(&"G1:0".to_string()));
assert!(entries.contains(&"G2:0".to_string()));
}
#[test]
fn cascade_satisfies_multiple_gets() {
let mut env = SimEnv::with_seed(0);
let c = Container::empty(100.0);
let log = new_log();
for i in 1..=4u32 {
let h = env.handle();
let c = c.clone();
let log = log.clone();
env.spawn(async move {
c.get(5.0).await;
log.borrow_mut().push(format!("G{}:{}", i, h.now()));
});
}
{
let h = env.handle();
let c = c.clone();
env.spawn(async move {
h.timeout(1.0).await;
c.put(20.0).await;
});
}
env.run();
assert_eq!(*log.borrow(), vec!["G1:1", "G2:1", "G3:1", "G4:1"]);
}
#[test]
fn immediate_get_cascade_wakes_multiple_blocked_puts() {
let mut env = SimEnv::with_seed(0);
let c = Container::new(10.0, 10.0); let log = new_log();
for name in ["P1", "P2"] {
let h = env.handle();
let c = c.clone();
let log = log.clone();
env.spawn(async move {
c.put(3.0).await;
log.borrow_mut().push(format!("{}:{}", name, h.now()));
});
}
{
let h = env.handle();
let c = c.clone();
env.spawn(async move {
h.timeout(1.0).await;
c.get(6.0).await;
});
}
env.run();
assert_eq!(*log.borrow(), vec!["P1:1", "P2:1"]);
assert_eq!(c.level(), 10.0);
}
#[test]
fn level_and_capacity_accessors() {
let mut env = SimEnv::with_seed(0);
let c = Container::new(10.0, 3.0);
assert_eq!(c.capacity(), 10.0);
assert_eq!(c.level(), 3.0);
{
let c = c.clone();
env.spawn(async move {
c.put(4.0).await; c.get(2.0).await; });
}
env.run();
assert_eq!(c.level(), 5.0);
}
#[test]
#[should_panic(expected = "capacity must be positive")]
fn zero_capacity_panics() {
let _ = Container::new(0.0, 0.0);
}
#[test]
#[should_panic(expected = "capacity must be positive")]
fn negative_capacity_panics() {
let _ = Container::new(-1.0, 0.0);
}
#[test]
#[should_panic(expected = "initial_level must not exceed capacity")]
fn initial_level_exceeds_capacity_panics() {
let _ = Container::new(5.0, 6.0);
}
#[test]
#[should_panic(expected = "exceeds capacity")]
fn put_exceeding_capacity_panics() {
let c = Container::new(10.0, 0.0);
let _req = c.put(11.0); }
#[test]
#[should_panic(expected = "exceeds capacity")]
fn get_exceeding_capacity_panics() {
let c = Container::new(10.0, 0.0);
let _req = c.get(11.0);
}
#[test]
fn amount_equal_to_capacity_is_allowed() {
let c = Container::new(10.0, 10.0);
let _req = c.get(10.0);
let c2 = Container::empty(10.0);
let _req2 = c2.put(10.0);
}