chiark / gitweb /
hand: initial wdt, passes
authorIan Jackson <ijackson@chiark.greenend.org.uk>
Mon, 15 Feb 2021 00:16:17 +0000 (00:16 +0000)
committerIan Jackson <ijackson@chiark.greenend.org.uk>
Mon, 15 Feb 2021 00:16:17 +0000 (00:16 +0000)
Signed-off-by: Ian Jackson <ijackson@chiark.greenend.org.uk>
wdriver.rs
wdriver/wdt-hand.rs [new file with mode: 0644]

index f5292e665755ca91a5da4884840d9c05295a8b52..7179cc28894d36797a584972cdffb468f4892fa2 100644 (file)
@@ -47,12 +47,14 @@ pub use otter::ensure_eq;
 pub use otter::commands::{MgmtCommand, MgmtResponse};
 pub use otter::commands::{MgmtGameInstruction, MgmtGameResponse};
 pub use otter::commands::{MgmtGameUpdateMode};
-pub use otter::gamestate::{self, Generation};
+pub use otter::gamestate::{self, Generation, PlayerId};
 pub use otter::global::InstanceName;
 pub use otter::mgmtchannel::MgmtChannel;
+pub use otter::slotmap_slot_idx::KeyDataExt;
 pub use otter::spec::{Coord, GameSpec, Pos, PosC};
 pub use otter::toml_de;
 pub use otter::ui::{AbbrevPresentationLayout, PresentationLayout};
+pub use otter::ui::player_num_dasharray;
 
 pub type T4d = t4::WebDriver;
 pub type WDE = t4::error::WebDriverError;
diff --git a/wdriver/wdt-hand.rs b/wdriver/wdt-hand.rs
new file mode 100644 (file)
index 0000000..b9061a5
--- /dev/null
@@ -0,0 +1,320 @@
+// Copyright 2020-2021 Ian Jackson and contributors to Otter
+// SPDX-License-Identifier: AGPL-3.0-or-later
+// There is NO WARRANTY.
+
+use otter_webdriver_tests::*;
+
+struct Ctx {
+  su: Setup,
+  alice: Window,
+  bob: Window,
+}
+ctx_with_setup!{Ctx}
+
+impl Ctx {
+  #[throws(AE)]
+  fn claim(&mut self){
+    let su = &mut self.su;
+    const HAND: &str = "6.1";
+    const ALICE: &str = "1#1";
+
+    let chk = |w: &WindowGuard<'_>, pc: &str, player: &'static str| {
+      let player: PlayerId = player.try_into().context(player)?;
+      let player: slotmap::KeyData = player.into();
+      let (player,_) = player.get_idx_version();
+      let player: usize = player.try_into().unwrap();
+      let player = player.try_into().unwrap();
+      let dasharray = player_num_dasharray(player).0;
+
+      let euse = w.find_element(By::Id(&format!("piece{}", pc)))?;
+      let epath = euse.find_element(By::Tag("path"))?;
+      let attr = epath.get_attribute("stroke-dasharray")?;
+
+      ensure_eq!(attr, Some(dasharray));
+      Ok::<_,AE>(())
+    };
+
+    {
+      let mut w = su.w(&self.alice)?;
+      w.synch()?;
+
+      let hand = w.find_piece(HAND)?;
+      w.action_chain()
+        .move_pos(&hand)?
+        .click()
+        .perform()
+        .context("select hand")?;
+      w.synch()?;
+
+      w.action_chain()
+        .key_down('C')
+        .key_up('C')
+        .perform()
+        .context("claim hand")?;
+
+      w.synch()?;
+
+      chk(&w, HAND, ALICE)?;
+    }
+
+    {
+      let mut w = su.w(&self.bob)?;
+      w.synch()?;
+
+      let _hand = w.find_piece(HAND)?;
+
+      chk(&w, HAND, ALICE)?;
+    }
+  }
+/*
+  #[throws(AE)]
+  fn rotate(&mut self) -> &'static str {
+    let pc = "4.1";
+    let su = &mut self.su;
+
+    let chk = |w: &WindowGuard<'_>| {
+      let transform = format!("rotate(-90)");
+      let pd = w.find_element(By::Id(&format!("piece{}",pc)))?;
+      ensure_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()
+        .release()
+        .key_down('l')
+        .key_up('l')
+        .perform()
+        .always_context("rotate")?;
+
+      chk(&w)?;
+      w.synch()?;
+    }
+
+    {
+      let mut w = su.w(&self.bob)?;
+      w.synch()?;
+      chk(&w)?;
+    }
+
+    pc
+  }
+
+  #[throws(AE)]
+  fn drag_off(&mut self, pc: &'static str) {
+    let su = &mut self.su;
+
+    let chk = |w: &WindowGuard<'_>, exp_end| {
+      let got_end = w.find_piece(pc)?.posg()?;
+      ensure_eq!(got_end, exp_end);
+      Ok::<_,AE>(())
+    };
+
+    let table_size = self.spec.table_size
+      .ok_or(anyhow!("table size missing from spec"))?;
+
+    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.0[1] = table_size.0[1] + 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()
+        .always_context("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(AE)]
+  fn unselect(&mut self, pc: &'static str) {
+    let su = &mut self.su;
+
+    let chk = |w: &WindowGuard<'_>| {
+      let held = w.piece_held(pc)?;
+      ensure_eq!(held, None);
+      Ok::<_,AE>(())
+    };
+
+    {
+      let mut w = su.w(&self.alice)?;
+      w.action_chain()
+        .move_w(&w, PosC([10,10]))?
+        .click()
+        .release()
+        .perform()
+        .always_context("unselect by clicking elsewhere")?;
+
+      chk(&w)?;
+      w.synch()?;
+    }
+
+    {
+      let mut w = su.w(&self.bob)?;
+      w.synch()?;
+      chk(&w)?;
+    }
+  }
+
+  #[throws(AE)]
+  fn conflict(&mut self) {
+    let pc = "1.1";
+    let su = &mut self.su;
+
+    {
+      let pc = "4.1";
+      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,
+    }
+
+    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([dx, 0]);
+
+      let (sx,sy) = w.posg2posw(start)?;
+      w.action_chain()
+        .move_to(sx,sy)
+        .click()
+        .click()
+        .perform()
+        .context("select and release")?;
+
+      w.synch()?;
+
+      Ok::<_,AE>(Side { window, start, try_end })
+    };
+
+    let sides = [
+      mk_side(&self.alice, -20)?,
+      mk_side(&self.bob,    20)?,
+    ];
+
+    dbg!(&sides);
+
+    let pid = nix::unistd::Pid::from_raw(su.server_child.id() as nix::libc::pid_t);
+    nix::sys::signal::kill(pid, nix::sys::signal::SIGSTOP)?;
+
+    for side in &sides {
+      let w = su.w(side.window)?;
+
+      w.action_chain()
+        .move_w(&w, side.start)?
+        .click()
+        .release()
+
+        .click_and_hold()
+        .move_w(&w, side.try_end)?
+        .release()
+
+        .perform()
+        .context("conflicting drag")?;
+    }
+
+    nix::sys::signal::kill(pid, nix::sys::signal::SIGCONT)?;
+
+    #[derive(Debug)]
+    struct Got<'s> {
+      side: &'s Side<'s>,
+      yes: bool,
+      now: Pos,
+      log: Vec<String>,
+      held: Option<String>,
+      client: String,
+    }
+    impl<'s> Deref for Got<'s> {
+      type Target = Side<'s>;
+      fn deref<'t>(&'t self) -> &'t Side<'s> { &self.side }
+    }
+
+    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.find_elements(By::ClassName("logmsg"))?;
+      let log = log.iter()
+        .rev()
+        .map(|e| e.inner_html())
+        .take_while(|h| {
+          h.as_ref().ok()
+            .map(|s| s.contains("black knight"))
+            != Some(true)
+        })
+        .collect::<Result<Vec<String>,_>>()?;
+
+      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().filter(|got|  got.yes).next().expect("y");
+    let n = gots.iter().filter(|got| !got.yes).next().expect("n");
+    ensure_eq!(y.now, y.try_end);
+    ensure_eq!(n.now, y.try_end);
+    ensure_eq!(n.now, y.try_end);
+    ensure_eq!(n.held, y.held);
+
+    for got in &gots {
+      let conflict = got.log.iter().any(|m| m.starts_with("Conflict!"));
+      ensure_eq!(conflict, !got.yes);
+    }
+  }
+*/
+}
+
+#[throws(AE)]
+fn tests(UsualSetup { su, alice, bob, ..}: UsualSetup) {
+  let mut c = Ctx { su, alice, bob };
+
+  test!(c, "claim", c.claim()?);
+
+/*
+  test!(c, "drag-rotate-unselect", {
+    let pc = c.rotate().always_context("rotate")?;
+    c.drag_off(pc).always_context("drag off")?;
+    c.unselect(pc).always_context("unselect")?;
+  });
+
+  test!(c, "conflict", c.conflict()?);
+*/
+  debug!("finishing");
+}
+
+#[throws(AE)]
+fn main() { as_usual(tests)? }