chiark / gitweb /
73a15c65e82c6aa8fb52f4ef421df205ca1cf368
[otter.git] / wdriver / wdt-hand.rs
1 // Copyright 2020-2021 Ian Jackson and contributors to Otter
2 // SPDX-License-Identifier: AGPL-3.0-or-later
3 // There is NO WARRANTY.
4
5 use crate::*;
6
7 #[derive(Deref)]
8 struct Ctx {
9   #[deref] su: Setup,
10   alice: Window,
11   bob: Window,
12 }
13 usual_wanted_tests!{Ctx, su}
14
15 const HAND: &str = "6v1";
16 const PAWN: &str = "7v1";
17 const PAWN2: &str = "8v1";
18 const ALICE: &str = "1#1";
19
20 #[throws(Explode)]
21 pub fn player_dasharray(player: &'static str) -> String {
22   let player: PlayerId = player.try_into().context(player)?;
23   let player: slotmap::KeyData = player.into();
24   let (player,_) = player.get_idx_version();
25   let player: usize = player.try_into().unwrap();
26   let player = player.try_into().unwrap();
27   let dasharray = player_num_dasharray(player);
28   dasharray.into_html_string()
29 }
30
31 impl Ctx {
32   #[throws(Explode)]
33   fn claim(&mut self){
34     let su = &mut self.su;
35
36     let chk = |
37         w: &mut WindowGuard<'_>, pc: &str,
38         player: Option<&'static str>
39     | {
40       w.synch()?;
41
42       let dasharray = player.map(player_dasharray).transpose()?;
43       let euse = w.find_element(By::Id(&w.vpidelem("piece", pc)?))?;
44       let epath = euse.find_element(By::Tag("path"))?;
45       let attr = epath.get_attribute("stroke-dasharray")?;
46
47       assert_eq!(attr, dasharray);
48       Ok::<_,AE>(())
49     };
50
51     let hand_posg = {
52       let mut w = su.w(&self.alice)?;
53       w.synch()?;
54
55       let hand = w.find_piece(HAND)?;
56       let hand_pieceid = hand.pieceid.to_string();
57
58       let hand_posg = hand.posg()?;
59       w.action_chain()
60         .move_pos(&hand)?
61         .send_keys("W")
62         .click()
63         .send_keys("tW")
64         .click()
65         .perform()
66         .did("select hand")?;
67       w.synch()?;
68
69       let top = w.execute_script(&format!(r##"
70           return defs_marker.previousElementSibling.dataset.piece;
71       "##))?;
72       assert_eq!( top.value().as_str().unwrap(),
73                   hand_pieceid );
74
75       w.action_chain()
76         .send_keys('C')
77         .perform()
78         .did("claim hand")?;
79       w.synch()?;
80
81       let top = w.execute_script(&format!(r##"
82           return pieces_marker.nextElementSibling.dataset.piece;
83       "##))?;
84       assert_eq!( top.value().as_str().unwrap(),
85                   hand_pieceid );
86
87       w.action_chain()
88         .click()
89         .perform()
90         .did("deselect")?;
91
92       chk(&mut w, HAND, Some(ALICE))?;
93
94       hand_posg
95     };
96
97     {
98       let mut w = su.w(&self.bob)?;
99       chk(&mut w, HAND, Some(ALICE))?;
100
101       w.get(w.current_url()?)?;
102       chk(&mut w, HAND, Some(ALICE))?;
103     }
104
105     {
106       let mut w = su.w(&self.alice)?;
107       let pawn = w.find_piece(PAWN)?;
108       w.action_chain()
109         .move_pos(&pawn)?
110         .click_and_hold()
111         .move_w(&w, (hand_posg + PosC::new(20,0))?)?
112         .release()
113         .perform()?;
114       w.synch()?;
115     }
116
117     for side in &[&self.alice, &self.bob] {
118       let mut w = su.w(side)?;
119       w.synch()?;
120       let log = w.retrieve_log((&mut |_: &'_ _| false) as LogIgnoreBeforeFn)?;
121       log.assert_no_conflicts();
122     }
123
124     {
125       let mut w = su.w(&self.alice)?;
126
127       let hand = w.find_piece(HAND)?;
128       w.action_chain()
129         .move_pos(&hand)?
130         .click()
131         .perform()
132         .did("select hand")?;
133       w.synch()?;
134
135       w.action_chain()
136         .send_keys('C')
137         .perform()
138         .did("unclaim hand")?;
139
140       w.action_chain()
141         .click()
142         .perform()
143         .did("deselect")?;
144
145       chk(&mut w, HAND, None)?;
146     }
147     {
148       let mut w = su.w(&self.bob)?;
149       chk(&mut w, HAND, None)?;
150     }
151   }
152
153   #[throws(Explode)]
154   fn ungrab_race(&mut self){
155     let su = &mut self.su;
156
157     const P_ALICE: &str = PAWN;
158     const P_BOB:   &str = PAWN2;
159     const DEST: Pos = PosC::new(50, 20);
160
161     {
162       let mut w = su.w(&self.alice)?;
163
164       w.action_chain()
165         .move_pc(&w, P_ALICE)?
166         .click()
167
168         .click_and_hold()
169         .move_w(&w, DEST)?
170         .release()
171
172         .perform()
173         .did("alice, drag pawn over target")?;
174       w.synch()?;
175     }
176
177     {
178       let mut w = su.w(&self.bob)?;
179
180       w.action_chain()
181         .move_pc(&w, P_BOB)?
182         .click_and_hold()
183         .move_w(&w, (DEST + PosC::new(2,0))?)?
184         .release()
185         .perform()
186         .did("bob, drag pawn to target")?;
187       w.synch()?;
188     }
189
190     {
191       let mut w = su.w(&self.alice)?;
192
193       w.action_chain()
194         .move_pc(&w, P_ALICE)?
195         .click()
196         .perform()
197         .did("alice, drop pawn on target")?;
198       w.synch()?;
199     }
200
201     let mut chk_alice_on_top = |pl|{
202       let mut w = su.w(pl)?;
203       w.synch()?;
204       let pcs = w.pieces()?;
205       let find = |pc| {
206         let vpid = w.piece_vpid(pc).unwrap();
207         pcs.iter().enumerate()
208           .find_map(|(ix, wp)| if wp.piece == vpid { Some(ix) } else { None })
209           .unwrap()
210       };
211       assert!(
212         dbgc!( find(P_ALICE) ) > dbgc!( find(P_BOB) )
213       );
214       Ok::<_,AE>(())
215     };
216
217
218     chk_alice_on_top(&self.alice).did("chk alice")?;
219     chk_alice_on_top(&self.bob  ).did("chk bob"  )?;
220   }
221
222   #[throws(Explode)]
223   fn regrab_race(&mut self){
224     let su = &mut self.su;
225     const MIDHAND: Pos = PosC::new(40, 40);
226     const OUTHAND: Pos = PosC::new(20, 20);
227
228     let bob_gen = {
229       let mut w = su.w(&self.bob)?;
230
231       w.action_chain()
232         
233         .move_pc(&w, PAWN)?
234         .click_and_hold()
235         .move_w(&w, (MIDHAND + Pos::new(-20,0))?)?
236         .release()
237
238         .move_w(&w, MIDHAND)?
239         .click()
240
241         .send_keys('C')
242
243         .perform()
244         .did("bob, setup")?;
245
246       w.synch()?
247     };
248
249     let alice_gen = {
250       let pauseable = su.otter_pauseable();
251       
252       let mut w = su.w(&self.alice)?;
253       w.synch()?;
254       let pawn = w.find_piece(PAWN)?;
255       let start = pawn.posw()?;
256
257       let paused = pauseable.pause()?;
258
259       w.action_chain()
260         .move_pos(start)?
261         .click_and_hold()
262         .move_w(&w, OUTHAND)?
263         .release()
264
265         .click()
266
267         .perform()
268         .did("alice, drag out, and re-select")?;
269
270       paused.resume()?;
271
272       w.synch()?
273     };
274
275     for (who, gen) in &[(&self.alice, alice_gen),
276                         (&self.bob,   bob_gen  )] {
277       dbgc!(&who.name);
278       let w = su.w(who)?;
279
280       let held = w.piece_held(PAWN)?;
281       assert_eq!( held.unwrap(), ALICE );
282
283       let log = w.retrieve_log(*gen)?;
284       assert_eq!( log.find_conflicts(), Vec::<String>::new() );
285     }
286
287     {
288       let mut w = su.w(&self.alice)?;
289       w.action_chain()
290         .click()
291         .perform()
292         .did("alice, ungrasp for tidy up")?;
293       w.synch()?;
294     }
295   }
296 }
297
298 #[throws(Explode)]
299 fn tests(UsualSetup { su, alice, bob, ..}: UsualSetup) {
300   let mut c = Ctx { su, alice, bob };
301
302   test!(c, "claim",       c.claim()       ?);
303   test!(c, "ungrab-race", c.ungrab_race() ?);
304   test!(c, "regrab-race", c.regrab_race() ?);
305
306   debug!("finishing");
307 }
308
309 #[throws(Explode)]
310 pub fn main() { as_usual(tests, module_path!())? }