use crate::*;
#[derive(Deref)]
struct Ctx {
#[deref] su: Setup,
alice: Window,
bob: Window,
spec: GameSpec,
}
usual_wanted_tests!{Ctx, su}
impl Ctx {
#[throws(Explode)]
fn drag(&mut self){
let su = &mut self.su;
let p1_vpid = su.initial_vpid_by_desc_glob("a red disc")?;
let p2_vpid = su.initial_vpid_by_desc_glob("a blue square")?;
let alice_p1g = {
let mut w = su.w(&self.alice)?;
w.synch()?;
let p1 = w.find_piece(&p1_vpid)?;
let p2 = w.find_piece(&p2_vpid)?;
let p1g_old = p1.posg()?;
let (p2x,p2y) = p2.posw()?;
w.action_chain()
.move_pos(&p1)?
.click_and_hold()
.move_to(p2x + 5, p2y + 10)
.release()
.perform()?;
let p1g_new = p1.posg()?;
dbg!(p1g_old, p1g_new);
assert!( p1g_new != p1g_old );
w.synch()?;
p1g_new
};
{
let mut w = su.w(&self.bob)?;
w.synch()?;
let p1 = w.find_piece(&p1_vpid)?;
assert_eq!(p1.posg()?, alice_p1g);
}
}
#[throws(Explode)]
fn rotate(&mut self) -> String {
let su = &mut self.su;
let pc = su.initial_vpid_by_desc_glob("a black knight")?;
let chk = |w: &WindowGuard<'_>| {
let transform = format!("rotate(-90)");
let pd = w.find_element(By::Id(&w.vpidelem("piece",&pc)?))?;
assert_eq!(pd.get_attribute("transform")?, Some(transform));
Ok::<_,AE>(())
};
{
let mut w = su.w(&self.alice)?;
let p = w.find_piece(&pc)?;
w.action_chain()
.move_pos(&p)?
.click()
.send_keys('l')
.perform()
.did("rotate")?;
chk(&w)?;
w.synch()?;
}
{
let mut w = su.w(&self.bob)?;
w.synch()?;
chk(&w)?;
}
pc
}
#[throws(Explode)]
fn drag_off(&mut self, pc: &str) {
let su = &mut self.su;
let chk = |w: &WindowGuard<'_>, exp_end| {
let got_end = w.find_piece(pc)?.posg()?;
assert_eq!(got_end, exp_end);
Ok::<_,AE>(())
};
let table_size = self.spec.table_size;
let exp_end = {
let mut w = su.w(&self.alice)?;
let p = w.find_piece(pc)?;
let start = p.posg()?;
let end = |d| { let mut e = start; e.coords[1] = table_size.y() + d; e };
let try_end = end(10);
let exp_end = end(0);
w.action_chain()
.move_w(&w, start)?
.click_and_hold()
.move_w(&w, try_end)?
.release()
.perform()
.did("drag off")?;
w.synch()?;
chk(&w, exp_end)?;
exp_end
};
{
let mut w = su.w(&self.bob)?;
w.synch()?;
chk(&w, exp_end)?;
}
pc
}
#[throws(Explode)]
fn unselect(&mut self, pc: &str) {
let su = &mut self.su;
let chk = |w: &WindowGuard<'_>| {
let held = w.piece_held(pc)?;
assert_eq!(held, None);
Ok::<_,AE>(())
};
{
let mut w = su.w(&self.alice)?;
w.action_chain()
.move_w(&w, PosC::new(10,10))?
.click()
.perform()
.did("unselect by clicking elsewhere")?;
chk(&w)?;
w.synch()?;
}
{
let mut w = su.w(&self.bob)?;
w.synch()?;
chk(&w)?;
}
}
#[throws(Explode)]
fn conflict(&mut self) {
let su = &mut self.su;
let pc = su.initial_vpid_by_desc_glob("a red disc")?;
{
let pc = su.initial_vpid_by_desc_glob("a black knight")?;
let w = su.w(&self.alice)?;
w.action_chain()
.move_pc(&w, &pc)?
.click();
}
#[derive(Debug)]
struct Side<'s> {
window: &'s Window,
start: Pos,
try_end: Pos,
before_gen: Generation,
}
let mut mk_side = |window, dx| {
let mut w = su.w(window)?;
let p = w.find_piece(&pc)?;
let start = p.posg()?;
let try_end = (start + PosC::new(dx, 0))?;
let (sx,sy) = w.posg2posw(start)?;
w.action_chain()
.move_to(sx,sy)
.click()
.click()
.perform()
.did("select and release")?;
let gen = w.synch()?;
Ok::<_,AE>(Side { window, start, try_end, before_gen: gen })
};
let sides = [
mk_side(&self.alice, -20)?,
mk_side(&self.bob, 20)?,
];
dbg!(&sides);
#[derive(Debug)]
struct Got<'s> {
side: &'s Side<'s>,
yes: bool,
now: Pos,
log: Vec<String>,
held: Option<String>,
#[allow(dead_code)] client: String,
}
impl<'s> Deref for Got<'s> {
type Target = Side<'s>;
fn deref<'t>(&'t self) -> &'t Side<'s> { self.side }
}
let check = |su: &mut Setup, before_gen, check_end_pos|{
let gots = sides.iter().map(|side|{
let mut w = su.w(side.window)?;
w.synch()?;
let p = w.find_piece(&pc)?;
let now = p.posg()?;
let log = w.retrieve_log(before_gen)?;
let held = w.piece_held(&pc)?;
let client = w.client()?;
let yes = held.as_ref() == Some(&client);
Ok::<_,AE>(Got { side, now, log, held, client, yes })
}).collect::<Result<Vec<_>,AE>>()?;
dbg!(&gots);
let y = gots.iter().find(|got| got.yes).expect("y");
let n = gots.iter().find(|got| !got.yes).expect("n");
if check_end_pos {
assert_eq!(y.now, y.try_end);
assert_eq!(n.now, y.try_end);
assert_eq!(n.now, y.try_end);
}
assert_eq!(n.held, y.held);
for got in &gots {
let conflicts = got.log.find_conflicts();
let helderrs = got.log.iter()
.filter(|m| m.contains("piece held by another player"))
.cloned().collect_vec();
dbg!( &conflicts, &helderrs );
assert!( conflicts.len() <= 1 );
assert!( helderrs .len() <= 1 );
if got.yes {
assert_eq!( conflicts.len(), 0 );
assert_eq!( helderrs .len(), 0 );
} else {
assert!( conflicts.len() == 1 ||
helderrs .len() == 1 );
}
}
let mut yw = su.w(y.window)?;
yw.action_chain()
.move_w(&yw, y.now)?
.click()
.perform()
.did("ungrab to tidy")?;
let gen = yw.synch()?;
Ok::<_,AE>((gen, y.now))
};
let paused = su.pause_otter()?;
for side in &sides {
let w = su.w(side.window)?;
w.action_chain()
.move_w(&w, side.start)?
.click()
.click_and_hold()
.move_w(&w, side.try_end)?
.release()
.perform()
.did("conflicting drag")?;
}
let pauseable = paused.resume()?;
let (gen_before, pos_now) = check(su, sides[0].before_gen, true)
.did("conflicting drag, check")?;
let paused = pauseable.pause()?;
for side in &sides {
let w = su.w(side.window)?;
w.action_chain()
.move_w(&w, pos_now)?
.click()
.perform()
.did("conflicting grasp")?;
}
let _pauseable = paused.resume()?;
check(su, gen_before, false)
.did("conflicting grasp, check")?;
}
}
#[throws(Explode)]
fn tests(UsualSetup { su, alice, bob, spec, ..}: UsualSetup) {
let mut c = Ctx { su, alice, bob, spec };
test!(c, "drag", c.drag()?);
test!(c, "drag-rotate-unselect", {
let pc = c.rotate().did("rotate")?;
c.drag_off(&pc).did("drag off")?;
c.unselect(&pc).did("unselect")?;
});
test!(c, "conflict", c.conflict()?);
debug!("finishing");
}
#[throws(Explode)]
pub fn main() { as_usual(tests, module_path!())? }