1use crate::common::{WebElement, ELEMENT_KEY};
6use icu_segmenter::GraphemeClusterSegmenter;
7use serde::de::{self, Deserialize, Deserializer};
8use serde::ser::{Serialize, Serializer};
9use serde_json::Value;
10use std::default::Default;
11use std::f64;
12
13#[derive(Debug, PartialEq, Serialize, Deserialize)]
14pub struct ActionSequence {
15 pub id: String,
16 #[serde(flatten)]
17 pub actions: ActionsType,
18}
19
20#[derive(Debug, PartialEq, Serialize, Deserialize)]
21#[serde(tag = "type")]
22pub enum ActionsType {
23 #[serde(rename = "none")]
24 Null { actions: Vec<NullActionItem> },
25 #[serde(rename = "key")]
26 Key { actions: Vec<KeyActionItem> },
27 #[serde(rename = "pointer")]
28 Pointer {
29 #[serde(default)]
30 parameters: PointerActionParameters,
31 actions: Vec<PointerActionItem>,
32 },
33 #[serde(rename = "wheel")]
34 Wheel { actions: Vec<WheelActionItem> },
35}
36
37#[derive(Debug, PartialEq, Serialize, Deserialize)]
38#[serde(untagged)]
39pub enum NullActionItem {
40 General(GeneralAction),
41}
42
43#[derive(Debug, PartialEq, Serialize, Deserialize)]
44#[serde(tag = "type")]
45pub enum GeneralAction {
46 #[serde(rename = "pause")]
47 Pause(PauseAction),
48}
49
50#[derive(Debug, PartialEq, Serialize, Deserialize)]
51pub struct PauseAction {
52 #[serde(
53 default,
54 skip_serializing_if = "Option::is_none",
55 deserialize_with = "deserialize_to_option_u64"
56 )]
57 pub duration: Option<u64>,
58}
59
60#[derive(Debug, PartialEq, Serialize, Deserialize)]
61#[serde(untagged)]
62pub enum KeyActionItem {
63 General(GeneralAction),
64 Key(KeyAction),
65}
66
67#[derive(Debug, PartialEq, Serialize, Deserialize)]
68#[serde(tag = "type")]
69pub enum KeyAction {
70 #[serde(rename = "keyDown")]
71 Down(KeyDownAction),
72 #[serde(rename = "keyUp")]
73 Up(KeyUpAction),
74}
75
76#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
77pub struct KeyDownAction {
78 #[serde(deserialize_with = "deserialize_key_action_value")]
79 pub value: String,
80}
81
82#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
83pub struct KeyUpAction {
84 #[serde(deserialize_with = "deserialize_key_action_value")]
85 pub value: String,
86}
87
88fn deserialize_key_action_value<'de, D>(deserializer: D) -> Result<String, D::Error>
89where
90 D: Deserializer<'de>,
91{
92 String::deserialize(deserializer).map(|value| {
93 if GraphemeClusterSegmenter::new().segment_str(&value).count() != 2 {
95 return Err(de::Error::custom(format!(
96 "'{}' should only contain a single Unicode code point",
97 value
98 )));
99 }
100
101 Ok(value)
102 })?
103}
104
105#[derive(Clone, Copy, Debug, Default, PartialEq, Serialize, Deserialize)]
106#[serde(rename_all = "lowercase")]
107pub enum PointerType {
108 #[default]
109 Mouse,
110 Pen,
111 Touch,
112}
113
114#[derive(Debug, Default, PartialEq, Serialize, Deserialize)]
115pub struct PointerActionParameters {
116 #[serde(rename = "pointerType")]
117 pub pointer_type: PointerType,
118}
119
120#[derive(Debug, PartialEq, Serialize, Deserialize)]
121#[serde(untagged)]
122pub enum PointerActionItem {
123 General(GeneralAction),
124 Pointer(PointerAction),
125}
126
127#[derive(Debug, PartialEq, Serialize, Deserialize)]
128#[serde(tag = "type")]
129pub enum PointerAction {
130 #[serde(rename = "pointerCancel")]
131 Cancel,
132 #[serde(rename = "pointerDown")]
133 Down(PointerDownAction),
134 #[serde(rename = "pointerMove")]
135 Move(PointerMoveAction),
136 #[serde(rename = "pointerUp")]
137 Up(PointerUpAction),
138}
139
140#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
141pub struct PointerDownAction {
142 pub button: u64,
143 #[serde(
144 default,
145 skip_serializing_if = "Option::is_none",
146 deserialize_with = "deserialize_to_option_u64"
147 )]
148 pub width: Option<u64>,
149 #[serde(
150 default,
151 skip_serializing_if = "Option::is_none",
152 deserialize_with = "deserialize_to_option_u64"
153 )]
154 pub height: Option<u64>,
155 #[serde(
156 default,
157 skip_serializing_if = "Option::is_none",
158 deserialize_with = "deserialize_to_pressure"
159 )]
160 pub pressure: Option<f64>,
161 #[serde(
162 default,
163 skip_serializing_if = "Option::is_none",
164 deserialize_with = "deserialize_to_tangential_pressure"
165 )]
166 pub tangentialPressure: Option<f64>,
167 #[serde(
168 default,
169 skip_serializing_if = "Option::is_none",
170 deserialize_with = "deserialize_to_tilt"
171 )]
172 pub tiltX: Option<i64>,
173 #[serde(
174 default,
175 skip_serializing_if = "Option::is_none",
176 deserialize_with = "deserialize_to_tilt"
177 )]
178 pub tiltY: Option<i64>,
179 #[serde(
180 default,
181 skip_serializing_if = "Option::is_none",
182 deserialize_with = "deserialize_to_twist"
183 )]
184 pub twist: Option<u64>,
185 #[serde(
186 default,
187 skip_serializing_if = "Option::is_none",
188 deserialize_with = "deserialize_to_altitude_angle"
189 )]
190 pub altitudeAngle: Option<f64>,
191 #[serde(
192 default,
193 skip_serializing_if = "Option::is_none",
194 deserialize_with = "deserialize_to_azimuth_angle"
195 )]
196 pub azimuthAngle: Option<f64>,
197}
198
199#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
200pub struct PointerMoveAction {
201 #[serde(
202 default,
203 skip_serializing_if = "Option::is_none",
204 deserialize_with = "deserialize_to_option_u64"
205 )]
206 pub duration: Option<u64>,
207 #[serde(default)]
208 pub origin: PointerOrigin,
209 pub x: f64,
210 pub y: f64,
211 #[serde(
212 default,
213 skip_serializing_if = "Option::is_none",
214 deserialize_with = "deserialize_to_option_u64"
215 )]
216 pub width: Option<u64>,
217 #[serde(
218 default,
219 skip_serializing_if = "Option::is_none",
220 deserialize_with = "deserialize_to_option_u64"
221 )]
222 pub height: Option<u64>,
223 #[serde(
224 default,
225 skip_serializing_if = "Option::is_none",
226 deserialize_with = "deserialize_to_pressure"
227 )]
228 pub pressure: Option<f64>,
229 #[serde(
230 default,
231 skip_serializing_if = "Option::is_none",
232 deserialize_with = "deserialize_to_tangential_pressure"
233 )]
234 pub tangentialPressure: Option<f64>,
235 #[serde(
236 default,
237 skip_serializing_if = "Option::is_none",
238 deserialize_with = "deserialize_to_tilt"
239 )]
240 pub tiltX: Option<i64>,
241 #[serde(
242 default,
243 skip_serializing_if = "Option::is_none",
244 deserialize_with = "deserialize_to_tilt"
245 )]
246 pub tiltY: Option<i64>,
247 #[serde(
248 default,
249 skip_serializing_if = "Option::is_none",
250 deserialize_with = "deserialize_to_twist"
251 )]
252 pub twist: Option<u64>,
253 #[serde(
254 default,
255 skip_serializing_if = "Option::is_none",
256 deserialize_with = "deserialize_to_altitude_angle"
257 )]
258 pub altitudeAngle: Option<f64>,
259 #[serde(
260 default,
261 skip_serializing_if = "Option::is_none",
262 deserialize_with = "deserialize_to_azimuth_angle"
263 )]
264 pub azimuthAngle: Option<f64>,
265}
266
267#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
268pub struct PointerUpAction {
269 pub button: u64,
270 #[serde(
271 default,
272 skip_serializing_if = "Option::is_none",
273 deserialize_with = "deserialize_to_option_u64"
274 )]
275 pub width: Option<u64>,
276 #[serde(
277 default,
278 skip_serializing_if = "Option::is_none",
279 deserialize_with = "deserialize_to_option_u64"
280 )]
281 pub height: Option<u64>,
282 #[serde(
283 default,
284 skip_serializing_if = "Option::is_none",
285 deserialize_with = "deserialize_to_pressure"
286 )]
287 pub pressure: Option<f64>,
288 #[serde(
289 default,
290 skip_serializing_if = "Option::is_none",
291 deserialize_with = "deserialize_to_tangential_pressure"
292 )]
293 pub tangentialPressure: Option<f64>,
294 #[serde(
295 default,
296 skip_serializing_if = "Option::is_none",
297 deserialize_with = "deserialize_to_tilt"
298 )]
299 pub tiltX: Option<i64>,
300 #[serde(
301 default,
302 skip_serializing_if = "Option::is_none",
303 deserialize_with = "deserialize_to_tilt"
304 )]
305 pub tiltY: Option<i64>,
306 #[serde(
307 default,
308 skip_serializing_if = "Option::is_none",
309 deserialize_with = "deserialize_to_twist"
310 )]
311 pub twist: Option<u64>,
312 #[serde(
313 default,
314 skip_serializing_if = "Option::is_none",
315 deserialize_with = "deserialize_to_altitude_angle"
316 )]
317 pub altitudeAngle: Option<f64>,
318 #[serde(
319 default,
320 skip_serializing_if = "Option::is_none",
321 deserialize_with = "deserialize_to_azimuth_angle"
322 )]
323 pub azimuthAngle: Option<f64>,
324}
325
326#[derive(Clone, Debug, Default, PartialEq, Serialize)]
327pub enum PointerOrigin {
328 #[serde(
329 rename = "element-6066-11e4-a52e-4f735466cecf",
330 serialize_with = "serialize_webelement_id"
331 )]
332 Element(WebElement),
333 #[serde(rename = "pointer")]
334 Pointer,
335 #[serde(rename = "viewport")]
336 #[default]
337 Viewport,
338}
339
340impl<'de> Deserialize<'de> for PointerOrigin {
344 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
345 where
346 D: Deserializer<'de>,
347 {
348 let value = Value::deserialize(deserializer)?;
349 if let Some(web_element) = value.get(ELEMENT_KEY) {
350 String::deserialize(web_element)
351 .map(|id| PointerOrigin::Element(WebElement(id)))
352 .map_err(de::Error::custom)
353 } else if value == "pointer" {
354 Ok(PointerOrigin::Pointer)
355 } else if value == "viewport" {
356 Ok(PointerOrigin::Viewport)
357 } else {
358 Err(de::Error::custom(format!(
359 "unknown value `{}`, expected `pointer`, `viewport`, or `element-6066-11e4-a52e-4f735466cecf`",
360 value
361 )))
362 }
363 }
364}
365
366#[derive(Debug, PartialEq, Serialize, Deserialize)]
367#[serde(untagged)]
368pub enum WheelActionItem {
369 General(GeneralAction),
370 Wheel(WheelAction),
371}
372
373#[derive(Debug, PartialEq, Serialize, Deserialize)]
374#[serde(tag = "type")]
375pub enum WheelAction {
376 #[serde(rename = "scroll")]
377 Scroll(WheelScrollAction),
378}
379
380#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
381pub struct WheelScrollAction {
382 #[serde(
383 default,
384 skip_serializing_if = "Option::is_none",
385 deserialize_with = "deserialize_to_option_u64"
386 )]
387 pub duration: Option<u64>,
388 #[serde(default)]
389 pub origin: PointerOrigin,
390 pub x: Option<i64>,
391 pub y: Option<i64>,
392 pub deltaX: Option<i64>,
393 pub deltaY: Option<i64>,
394}
395
396fn serialize_webelement_id<S>(element: &WebElement, serializer: S) -> Result<S::Ok, S::Error>
397where
398 S: Serializer,
399{
400 element.to_string().serialize(serializer)
401}
402
403fn deserialize_to_option_i64<'de, D>(deserializer: D) -> Result<Option<i64>, D::Error>
404where
405 D: Deserializer<'de>,
406{
407 Option::deserialize(deserializer)?
408 .ok_or_else(|| de::Error::custom("invalid type: null, expected i64"))
409}
410
411fn deserialize_to_option_u64<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
412where
413 D: Deserializer<'de>,
414{
415 Option::deserialize(deserializer)?
416 .ok_or_else(|| de::Error::custom("invalid type: null, expected i64"))
417}
418
419fn deserialize_to_option_f64<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error>
420where
421 D: Deserializer<'de>,
422{
423 Option::deserialize(deserializer)?
424 .ok_or_else(|| de::Error::custom("invalid type: null, expected f64"))
425}
426
427fn deserialize_to_pressure<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error>
428where
429 D: Deserializer<'de>,
430{
431 let opt_value = deserialize_to_option_f64(deserializer)?;
432 if let Some(value) = opt_value
433 && !(0f64..=1.0).contains(&value) {
434 return Err(de::Error::custom(format!("{} is outside range 0-1", value)));
435 };
436 Ok(opt_value)
437}
438
439fn deserialize_to_tangential_pressure<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error>
440where
441 D: Deserializer<'de>,
442{
443 let opt_value = deserialize_to_option_f64(deserializer)?;
444 if let Some(value) = opt_value
445 && !(-1.0..=1.0).contains(&value) {
446 return Err(de::Error::custom(format!(
447 "{} is outside range -1-1",
448 value
449 )));
450 };
451 Ok(opt_value)
452}
453
454fn deserialize_to_tilt<'de, D>(deserializer: D) -> Result<Option<i64>, D::Error>
455where
456 D: Deserializer<'de>,
457{
458 let opt_value = deserialize_to_option_i64(deserializer)?;
459 if let Some(value) = opt_value
460 && !(-90..=90).contains(&value) {
461 return Err(de::Error::custom(format!(
462 "{} is outside range -90-90",
463 value
464 )));
465 };
466 Ok(opt_value)
467}
468
469fn deserialize_to_twist<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
470where
471 D: Deserializer<'de>,
472{
473 let opt_value = deserialize_to_option_u64(deserializer)?;
474 if let Some(value) = opt_value
475 && !(0..=359).contains(&value) {
476 return Err(de::Error::custom(format!(
477 "{} is outside range 0-359",
478 value
479 )));
480 };
481 Ok(opt_value)
482}
483
484fn deserialize_to_altitude_angle<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error>
485where
486 D: Deserializer<'de>,
487{
488 let opt_value = deserialize_to_option_f64(deserializer)?;
489 if let Some(value) = opt_value
490 && !(0f64..=f64::consts::FRAC_PI_2).contains(&value) {
491 return Err(de::Error::custom(format!(
492 "{} is outside range 0-PI/2",
493 value
494 )));
495 };
496 Ok(opt_value)
497}
498
499fn deserialize_to_azimuth_angle<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error>
500where
501 D: Deserializer<'de>,
502{
503 let opt_value = deserialize_to_option_f64(deserializer)?;
504 if let Some(value) = opt_value
505 && !(0f64..=f64::consts::TAU).contains(&value) {
506 return Err(de::Error::custom(format!(
507 "{} is outside range 0-2*PI",
508 value
509 )));
510 };
511 Ok(opt_value)
512}
513
514#[cfg(test)]
515mod test {
516 use super::*;
517 use crate::test::{assert_de, assert_ser_de};
518 use serde_json::{self, json, Value};
519
520 #[test]
521 fn test_json_action_sequence_null() {
522 let json = json!({
523 "id": "some_key",
524 "type": "none",
525 "actions": [{
526 "type": "pause",
527 "duration": 1,
528 }]
529 });
530 let seq = ActionSequence {
531 id: "some_key".into(),
532 actions: ActionsType::Null {
533 actions: vec![NullActionItem::General(GeneralAction::Pause(PauseAction {
534 duration: Some(1),
535 }))],
536 },
537 };
538
539 assert_ser_de(&seq, json);
540 }
541
542 #[test]
543 fn test_json_action_sequence_key() {
544 let json = json!({
545 "id": "some_key",
546 "type": "key",
547 "actions": [
548 {"type": "keyDown", "value": "f"},
549 ],
550 });
551 let seq = ActionSequence {
552 id: "some_key".into(),
553 actions: ActionsType::Key {
554 actions: vec![KeyActionItem::Key(KeyAction::Down(KeyDownAction {
555 value: String::from("f"),
556 }))],
557 },
558 };
559
560 assert_ser_de(&seq, json);
561 }
562
563 #[test]
564 fn test_json_action_sequence_pointer() {
565 let json = json!({
566 "id": "some_pointer",
567 "type": "pointer",
568 "parameters": {
569 "pointerType": "mouse"
570 },
571 "actions": [
572 {"type": "pointerDown", "button": 0},
573 {"type": "pointerMove", "origin": "pointer", "x": 10.5, "y": 20.5},
574 {"type": "pointerUp", "button": 0},
575 ]
576 });
577 let seq = ActionSequence {
578 id: "some_pointer".into(),
579 actions: ActionsType::Pointer {
580 parameters: PointerActionParameters {
581 pointer_type: PointerType::Mouse,
582 },
583 actions: vec![
584 PointerActionItem::Pointer(PointerAction::Down(PointerDownAction {
585 button: 0,
586 ..Default::default()
587 })),
588 PointerActionItem::Pointer(PointerAction::Move(PointerMoveAction {
589 origin: PointerOrigin::Pointer,
590 duration: None,
591 x: 10.5,
592 y: 20.5,
593 ..Default::default()
594 })),
595 PointerActionItem::Pointer(PointerAction::Up(PointerUpAction {
596 button: 0,
597 ..Default::default()
598 })),
599 ],
600 },
601 };
602
603 assert_ser_de(&seq, json);
604 }
605
606 #[test]
607 fn test_json_action_sequence_id_missing() {
608 let json = json!({
609 "type": "key",
610 "actions": [],
611 });
612 assert!(serde_json::from_value::<ActionSequence>(json).is_err());
613 }
614
615 #[test]
616 fn test_json_action_sequence_id_null() {
617 let json = json!({
618 "id": null,
619 "type": "key",
620 "actions": [],
621 });
622 assert!(serde_json::from_value::<ActionSequence>(json).is_err());
623 }
624
625 #[test]
626 fn test_json_action_sequence_actions_missing() {
627 assert!(serde_json::from_value::<ActionSequence>(json!({"id": "3"})).is_err());
628 }
629
630 #[test]
631 fn test_json_action_sequence_actions_null() {
632 let json = json!({
633 "id": "3",
634 "actions": null,
635 });
636 assert!(serde_json::from_value::<ActionSequence>(json).is_err());
637 }
638
639 #[test]
640 fn test_json_action_sequence_actions_invalid_type() {
641 let json = json!({
642 "id": "3",
643 "actions": "foo",
644 });
645 assert!(serde_json::from_value::<ActionSequence>(json).is_err());
646 }
647
648 #[test]
649 fn test_json_actions_type_null() {
650 let json = json!({
651 "type": "none",
652 "actions": [{
653 "type": "pause",
654 "duration": 1,
655 }],
656 });
657 let null = ActionsType::Null {
658 actions: vec![NullActionItem::General(GeneralAction::Pause(PauseAction {
659 duration: Some(1),
660 }))],
661 };
662
663 assert_ser_de(&null, json);
664 }
665
666 #[test]
667 fn test_json_actions_type_key() {
668 let json = json!({
669 "type": "key",
670 "actions": [{
671 "type": "keyDown",
672 "value": "f",
673 }],
674 });
675 let key = ActionsType::Key {
676 actions: vec![KeyActionItem::Key(KeyAction::Down(KeyDownAction {
677 value: String::from("f"),
678 }))],
679 };
680
681 assert_ser_de(&key, json);
682 }
683
684 #[test]
685 fn test_json_actions_type_pointer() {
686 let json = json!({
687 "type": "pointer",
688 "parameters": {"pointerType": "mouse"},
689 "actions": [
690 {"type": "pointerDown", "button": 1},
691 ]});
692 let pointer = ActionsType::Pointer {
693 parameters: PointerActionParameters {
694 pointer_type: PointerType::Mouse,
695 },
696 actions: vec![PointerActionItem::Pointer(PointerAction::Down(
697 PointerDownAction {
698 button: 1,
699 ..Default::default()
700 },
701 ))],
702 };
703
704 assert_ser_de(&pointer, json);
705 }
706
707 #[test]
708 fn test_json_actions_type_pointer_with_parameters_missing() {
709 let json = json!({
710 "type": "pointer",
711 "actions": [
712 {"type": "pointerDown", "button": 1},
713 ]});
714 let pointer = ActionsType::Pointer {
715 parameters: PointerActionParameters {
716 pointer_type: PointerType::Mouse,
717 },
718 actions: vec![PointerActionItem::Pointer(PointerAction::Down(
719 PointerDownAction {
720 button: 1,
721 ..Default::default()
722 },
723 ))],
724 };
725
726 assert_de(&pointer, json);
727 }
728
729 #[test]
730 fn test_json_actions_type_pointer_with_parameters_invalid_type() {
731 let json = json!({
732 "type": "pointer",
733 "parameters": null,
734 "actions": [
735 {"type":"pointerDown", "button": 1},
736 ]});
737 assert!(serde_json::from_value::<ActionsType>(json).is_err());
738 }
739
740 #[test]
741 fn test_json_actions_type_invalid() {
742 let json = json!({"actions": [{"foo": "bar"}]});
743 assert!(serde_json::from_value::<ActionsType>(json).is_err());
744 }
745
746 #[test]
747 fn test_json_null_action_item_general() {
748 let pause =
749 NullActionItem::General(GeneralAction::Pause(PauseAction { duration: Some(1) }));
750 assert_ser_de(&pause, json!({"type": "pause", "duration": 1}));
751 }
752
753 #[test]
754 fn test_json_null_action_item_invalid_type() {
755 assert!(serde_json::from_value::<NullActionItem>(json!({"type": "invalid"})).is_err());
756 }
757
758 #[test]
759 fn test_json_general_action_pause() {
760 let pause = GeneralAction::Pause(PauseAction { duration: Some(1) });
761 assert_ser_de(&pause, json!({"type": "pause", "duration": 1}));
762 }
763
764 #[test]
765 fn test_json_general_action_pause_with_duration_missing() {
766 let pause = GeneralAction::Pause(PauseAction { duration: None });
767 assert_ser_de(&pause, json!({"type": "pause"}));
768 }
769
770 #[test]
771 fn test_json_general_action_pause_with_duration_null() {
772 let json = json!({"type": "pause", "duration": null});
773 assert!(serde_json::from_value::<GeneralAction>(json).is_err());
774 }
775
776 #[test]
777 fn test_json_general_action_pause_with_duration_invalid_type() {
778 let json = json!({"type": "pause", "duration":" foo"});
779 assert!(serde_json::from_value::<GeneralAction>(json).is_err());
780 }
781
782 #[test]
783 fn test_json_general_action_pause_with_duration_negative() {
784 let json = json!({"type": "pause", "duration": -30});
785 assert!(serde_json::from_value::<GeneralAction>(json).is_err());
786 }
787
788 #[test]
789 fn test_json_key_action_item_general() {
790 let pause = KeyActionItem::General(GeneralAction::Pause(PauseAction { duration: Some(1) }));
791 assert_ser_de(&pause, json!({"type": "pause", "duration": 1}));
792 }
793
794 #[test]
795 fn test_json_key_action_item_key() {
796 let key_down = KeyActionItem::Key(KeyAction::Down(KeyDownAction {
797 value: String::from("f"),
798 }));
799 assert_ser_de(&key_down, json!({"type": "keyDown", "value": "f"}));
800 }
801
802 #[test]
803 fn test_json_key_action_item_invalid_type() {
804 assert!(serde_json::from_value::<KeyActionItem>(json!({"type": "invalid"})).is_err());
805 }
806
807 #[test]
808 fn test_json_key_action_missing_subtype() {
809 assert!(serde_json::from_value::<KeyAction>(json!({"value": "f"})).is_err());
810 }
811
812 #[test]
813 fn test_json_key_action_wrong_subtype() {
814 let json = json!({"type": "pause", "value": "f"});
815 assert!(serde_json::from_value::<KeyAction>(json).is_err());
816 }
817
818 #[test]
819 fn test_json_key_action_down() {
820 let key_down = KeyAction::Down(KeyDownAction {
821 value: "f".to_string(),
822 });
823 assert_ser_de(&key_down, json!({"type": "keyDown", "value": "f"}));
824 }
825
826 #[test]
827 fn test_json_key_action_down_with_value_unicode() {
828 let key_down = KeyAction::Down(KeyDownAction {
829 value: "à".to_string(),
830 });
831 assert_ser_de(&key_down, json!({"type": "keyDown", "value": "à"}));
832 }
833
834 #[test]
835 fn test_json_key_action_down_with_value_unicode_encoded() {
836 let key_down = KeyAction::Down(KeyDownAction {
837 value: "à".to_string(),
838 });
839 assert_de(&key_down, json!({"type": "keyDown", "value": "\u{00E0}"}));
840 }
841
842 #[test]
843 fn test_json_key_action_down_with_value_missing() {
844 assert!(serde_json::from_value::<KeyAction>(json!({"type": "keyDown"})).is_err());
845 }
846
847 #[test]
848 fn test_json_key_action_down_with_value_null() {
849 let json = json!({"type": "keyDown", "value": null});
850 assert!(serde_json::from_value::<KeyAction>(json).is_err());
851 }
852
853 #[test]
854 fn test_json_key_action_down_with_value_invalid_type() {
855 let json = json!({"type": "keyDown", "value": ["f", "o", "o"]});
856 assert!(serde_json::from_value::<KeyAction>(json).is_err());
857 }
858
859 #[test]
860 fn test_json_key_action_down_with_multiple_code_points() {
861 let json = json!({"type": "keyDown", "value": "fo"});
862 assert!(serde_json::from_value::<KeyAction>(json).is_err());
863 }
864
865 #[test]
866 fn test_json_key_action_up() {
867 let key_up = KeyAction::Up(KeyUpAction {
868 value: "f".to_string(),
869 });
870 assert_ser_de(&key_up, json!({"type": "keyUp", "value": "f"}));
871 }
872
873 #[test]
874 fn test_json_key_action_up_with_value_unicode() {
875 let key_up = KeyAction::Up(KeyUpAction {
876 value: "à".to_string(),
877 });
878 assert_ser_de(&key_up, json!({"type":"keyUp", "value": "à"}));
879 }
880
881 #[test]
882 fn test_json_key_action_up_with_value_unicode_encoded() {
883 let key_up = KeyAction::Up(KeyUpAction {
884 value: "à".to_string(),
885 });
886 assert_de(&key_up, json!({"type": "keyUp", "value": "\u{00E0}"}));
887 }
888
889 #[test]
890 fn test_json_key_action_up_with_value_missing() {
891 assert!(serde_json::from_value::<KeyAction>(json!({"type": "keyUp"})).is_err());
892 }
893
894 #[test]
895 fn test_json_key_action_up_with_value_null() {
896 let json = json!({"type": "keyUp", "value": null});
897 assert!(serde_json::from_value::<KeyAction>(json).is_err());
898 }
899
900 #[test]
901 fn test_json_key_action_up_with_value_invalid_type() {
902 let json = json!({"type": "keyUp", "value": ["f","o","o"]});
903 assert!(serde_json::from_value::<KeyAction>(json).is_err());
904 }
905
906 #[test]
907 fn test_json_key_action_up_with_multiple_code_points() {
908 let json = json!({"type": "keyUp", "value": "fo"});
909 assert!(serde_json::from_value::<KeyAction>(json).is_err());
910 }
911
912 #[test]
913 fn test_json_pointer_action_item_general() {
914 let pause =
915 PointerActionItem::General(GeneralAction::Pause(PauseAction { duration: Some(1) }));
916 assert_ser_de(&pause, json!({"type": "pause", "duration": 1}));
917 }
918
919 #[test]
920 fn test_json_pointer_action_item_pointer() {
921 let cancel = PointerActionItem::Pointer(PointerAction::Cancel);
922 assert_ser_de(&cancel, json!({"type": "pointerCancel"}));
923 }
924
925 #[test]
926 fn test_json_pointer_action_item_invalid() {
927 assert!(serde_json::from_value::<PointerActionItem>(json!({"type": "invalid"})).is_err());
928 }
929
930 #[test]
931 fn test_json_pointer_action_parameters_mouse() {
932 let mouse = PointerActionParameters {
933 pointer_type: PointerType::Mouse,
934 };
935 assert_ser_de(&mouse, json!({"pointerType": "mouse"}));
936 }
937
938 #[test]
939 fn test_json_pointer_action_parameters_pen() {
940 let pen = PointerActionParameters {
941 pointer_type: PointerType::Pen,
942 };
943 assert_ser_de(&pen, json!({"pointerType": "pen"}));
944 }
945
946 #[test]
947 fn test_json_pointer_action_parameters_touch() {
948 let touch = PointerActionParameters {
949 pointer_type: PointerType::Touch,
950 };
951 assert_ser_de(&touch, json!({"pointerType": "touch"}));
952 }
953
954 #[test]
955 fn test_json_pointer_action_item_invalid_type() {
956 let json = json!({"type": "pointerInvalid"});
957 assert!(serde_json::from_value::<PointerActionItem>(json).is_err());
958 }
959
960 #[test]
961 fn test_json_pointer_action_missing_subtype() {
962 assert!(serde_json::from_value::<PointerAction>(json!({"button": 1})).is_err());
963 }
964
965 #[test]
966 fn test_json_pointer_action_invalid_subtype() {
967 let json = json!({"type": "invalid", "button": 1});
968 assert!(serde_json::from_value::<PointerAction>(json).is_err());
969 }
970
971 #[test]
972 fn test_json_pointer_action_cancel() {
973 assert_ser_de(&PointerAction::Cancel, json!({"type": "pointerCancel"}));
974 }
975
976 #[test]
977 fn test_json_pointer_action_down() {
978 let pointer_down = PointerAction::Down(PointerDownAction {
979 button: 1,
980 ..Default::default()
981 });
982 assert_ser_de(&pointer_down, json!({"type": "pointerDown", "button": 1}));
983 }
984
985 #[test]
986 fn test_json_pointer_action_down_with_button_missing() {
987 let json = json!({"type": "pointerDown"});
988 assert!(serde_json::from_value::<PointerAction>(json).is_err());
989 }
990
991 #[test]
992 fn test_json_pointer_action_down_with_button_null() {
993 let json = json!({
994 "type": "pointerDown",
995 "button": null,
996 });
997 assert!(serde_json::from_value::<PointerAction>(json).is_err());
998 }
999
1000 #[test]
1001 fn test_json_pointer_action_down_with_button_invalid_type() {
1002 let json = json!({
1003 "type": "pointerDown",
1004 "button": "foo",
1005 });
1006 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1007 }
1008
1009 #[test]
1010 fn test_json_pointer_action_down_with_button_negative() {
1011 let json = json!({
1012 "type": "pointerDown",
1013 "button": -30,
1014 });
1015 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1016 }
1017
1018 #[test]
1019 fn test_json_pointer_action_move() {
1020 let json = json!({
1021 "type": "pointerMove",
1022 "duration": 100,
1023 "origin": "viewport",
1024 "x": 5.5,
1025 "y": 10.5,
1026 });
1027 let pointer_move = PointerAction::Move(PointerMoveAction {
1028 duration: Some(100),
1029 origin: PointerOrigin::Viewport,
1030 x: 5.5,
1031 y: 10.5,
1032 ..Default::default()
1033 });
1034
1035 assert_ser_de(&pointer_move, json);
1036 }
1037
1038 #[test]
1039 fn test_json_pointer_action_move_missing_subtype() {
1040 let json = json!({
1041 "duration": 100,
1042 "origin": "viewport",
1043 "x": 5.5,
1044 "y": 10.5,
1045 });
1046 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1047 }
1048
1049 #[test]
1050 fn test_json_pointer_action_move_wrong_subtype() {
1051 let json = json!({
1052 "type": "pointerUp",
1053 "duration": 100,
1054 "origin": "viewport",
1055 "x": 5.5,
1056 "y": 10.5,
1057 });
1058 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1059 }
1060
1061 #[test]
1062 fn test_json_pointer_action_move_with_duration_missing() {
1063 let json = json!({
1064 "type": "pointerMove",
1065 "origin": "viewport",
1066 "x": 5.5,
1067 "y": 10.5,
1068 });
1069 let pointer_move = PointerAction::Move(PointerMoveAction {
1070 duration: None,
1071 origin: PointerOrigin::Viewport,
1072 x: 5.5,
1073 y: 10.5,
1074 ..Default::default()
1075 });
1076
1077 assert_ser_de(&pointer_move, json);
1078 }
1079
1080 #[test]
1081 fn test_json_pointer_action_move_with_duration_null() {
1082 let json = json!({
1083 "type": "pointerMove",
1084 "duration": null,
1085 "origin": "viewport",
1086 "x": 5.5,
1087 "y": 10.5,
1088 });
1089 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1090 }
1091
1092 #[test]
1093 fn test_json_pointer_action_move_with_duration_invalid_type() {
1094 let json = json!({
1095 "type": "pointerMove",
1096 "duration": "invalid",
1097 "origin": "viewport",
1098 "x": 5.5,
1099 "y": 10.5,
1100 });
1101 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1102 }
1103
1104 #[test]
1105 fn test_json_pointer_action_move_with_duration_negative() {
1106 let json = json!({
1107 "type": "pointerMove",
1108 "duration": -30,
1109 "origin": "viewport",
1110 "x": 5.5,
1111 "y": 10.5,
1112 });
1113 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1114 }
1115
1116 #[test]
1117 fn test_json_pointer_action_move_with_origin_missing() {
1118 let json = json!({
1119 "type": "pointerMove",
1120 "duration": 100,
1121 "x": 5.5,
1122 "y": 10.5,
1123 });
1124 let pointer_move = PointerAction::Move(PointerMoveAction {
1125 duration: Some(100),
1126 origin: PointerOrigin::Viewport,
1127 x: 5.5,
1128 y: 10.5,
1129 ..Default::default()
1130 });
1131
1132 assert_de(&pointer_move, json);
1133 }
1134
1135 #[test]
1136 fn test_json_pointer_action_move_with_origin_webelement() {
1137 let json = json!({
1138 "type": "pointerMove",
1139 "duration": 100,
1140 "origin": {ELEMENT_KEY: "elem"},
1141 "x": 5.5,
1142 "y": 10.5,
1143 });
1144 let pointer_move = PointerAction::Move(PointerMoveAction {
1145 duration: Some(100),
1146 origin: PointerOrigin::Element(WebElement("elem".into())),
1147 x: 5.5,
1148 y: 10.5,
1149 ..Default::default()
1150 });
1151
1152 assert_ser_de(&pointer_move, json);
1153 }
1154
1155 #[test]
1156 fn test_json_pointer_action_move_with_origin_webelement_and_legacy_element() {
1157 let json = json!({
1158 "type": "pointerMove",
1159 "duration": 100,
1160 "origin": {ELEMENT_KEY: "elem"},
1161 "x": 5.5,
1162 "y": 10.5,
1163 });
1164 let pointer_move = PointerAction::Move(PointerMoveAction {
1165 duration: Some(100),
1166 origin: PointerOrigin::Element(WebElement("elem".into())),
1167 x: 5.5,
1168 y: 10.5,
1169 ..Default::default()
1170 });
1171
1172 assert_de(&pointer_move, json);
1173 }
1174
1175 #[test]
1176 fn test_json_pointer_action_move_with_origin_only_legacy_element() {
1177 let json = json!({
1178 "type": "pointerMove",
1179 "duration": 100,
1180 "origin": {ELEMENT_KEY: "elem"},
1181 "x": 5,
1182 "y": 10,
1183 });
1184 assert!(serde_json::from_value::<PointerOrigin>(json).is_err());
1185 }
1186
1187 #[test]
1188 fn test_json_pointer_action_move_with_x_null() {
1189 let json = json!({
1190 "type": "pointerMove",
1191 "duration": 100,
1192 "origin": "viewport",
1193 "x": null,
1194 "y": 10,
1195 });
1196 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1197 }
1198
1199 #[test]
1200 fn test_json_pointer_action_move_with_x_invalid_type() {
1201 let json = json!({
1202 "type": "pointerMove",
1203 "duration": 100,
1204 "origin": "viewport",
1205 "x": "invalid",
1206 "y": 10,
1207 });
1208 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1209 }
1210
1211 #[test]
1212 fn test_json_pointer_action_move_with_y_null() {
1213 let json = json!({
1214 "type": "pointerMove",
1215 "duration": 100,
1216 "origin": "viewport",
1217 "x": 5,
1218 "y": null,
1219 });
1220 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1221 }
1222
1223 #[test]
1224 fn test_json_pointer_action_move_with_y_invalid_type() {
1225 let json = json!({
1226 "type": "pointerMove",
1227 "duration": 100,
1228 "origin": "viewport",
1229 "x": 5,
1230 "y": "invalid",
1231 });
1232 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1233 }
1234
1235 #[test]
1236 fn test_json_pointer_action_up() {
1237 let pointer_up = PointerAction::Up(PointerUpAction {
1238 button: 1,
1239 ..Default::default()
1240 });
1241 assert_ser_de(&pointer_up, json!({"type": "pointerUp", "button": 1}));
1242 }
1243
1244 #[test]
1245 fn test_json_pointer_action_up_with_button_missing() {
1246 assert!(serde_json::from_value::<PointerAction>(json!({"type": "pointerUp"})).is_err());
1247 }
1248
1249 #[test]
1250 fn test_json_pointer_action_up_with_button_null() {
1251 let json = json!({
1252 "type": "pointerUp",
1253 "button": null,
1254 });
1255 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1256 }
1257
1258 #[test]
1259 fn test_json_pointer_action_up_with_button_invalid_type() {
1260 let json = json!({
1261 "type": "pointerUp",
1262 "button": "foo",
1263 });
1264 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1265 }
1266
1267 #[test]
1268 fn test_json_pointer_action_up_with_button_negative() {
1269 let json = json!({
1270 "type": "pointerUp",
1271 "button": -30,
1272 });
1273 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1274 }
1275
1276 #[test]
1277 fn test_json_pointer_origin_pointer() {
1278 assert_ser_de(&PointerOrigin::Pointer, json!("pointer"));
1279 }
1280
1281 #[test]
1282 fn test_json_pointer_origin_viewport() {
1283 assert_ser_de(&PointerOrigin::Viewport, json!("viewport"));
1284 }
1285
1286 #[test]
1287 fn test_json_pointer_origin_web_element() {
1288 let element = PointerOrigin::Element(WebElement("elem".into()));
1289 assert_ser_de(&element, json!({ELEMENT_KEY: "elem"}));
1290 }
1291
1292 #[test]
1293 fn test_json_pointer_origin_invalid_type() {
1294 assert!(serde_json::from_value::<PointerOrigin>(json!("invalid")).is_err());
1295 }
1296
1297 #[test]
1298 fn test_json_pointer_type_mouse() {
1299 assert_ser_de(&PointerType::Mouse, json!("mouse"));
1300 }
1301
1302 #[test]
1303 fn test_json_pointer_type_pen() {
1304 assert_ser_de(&PointerType::Pen, json!("pen"));
1305 }
1306
1307 #[test]
1308 fn test_json_pointer_type_touch() {
1309 assert_ser_de(&PointerType::Touch, json!("touch"));
1310 }
1311
1312 #[test]
1313 fn test_json_pointer_type_invalid_type() {
1314 assert!(serde_json::from_value::<PointerType>(json!("invalid")).is_err());
1315 }
1316
1317 #[test]
1318 fn test_pointer_properties() {
1319 for actionType in ["pointerUp", "pointerDown", "pointerMove"] {
1322 for (prop_name, value, is_valid) in [
1323 ("pressure", Value::from(0), true),
1324 ("pressure", Value::from(0.5), true),
1325 ("pressure", Value::from(1), true),
1326 ("pressure", Value::from(1.1), false),
1327 ("pressure", Value::from(-0.1), false),
1328 ("tangentialPressure", Value::from(-1), true),
1329 ("tangentialPressure", Value::from(0), true),
1330 ("tangentialPressure", Value::from(1.0), true),
1331 ("tangentialPressure", Value::from(-1.1), false),
1332 ("tangentialPressure", Value::from(1.1), false),
1333 ("tiltX", Value::from(-90), true),
1334 ("tiltX", Value::from(0), true),
1335 ("tiltX", Value::from(45), true),
1336 ("tiltX", Value::from(90), true),
1337 ("tiltX", Value::from(0.5), false),
1338 ("tiltX", Value::from(-91), false),
1339 ("tiltX", Value::from(91), false),
1340 ("tiltY", Value::from(-90), true),
1341 ("tiltY", Value::from(0), true),
1342 ("tiltY", Value::from(45), true),
1343 ("tiltY", Value::from(90), true),
1344 ("tiltY", Value::from(0.5), false),
1345 ("tiltY", Value::from(-91), false),
1346 ("tiltY", Value::from(91), false),
1347 ("twist", Value::from(0), true),
1348 ("twist", Value::from(180), true),
1349 ("twist", Value::from(359), true),
1350 ("twist", Value::from(360), false),
1351 ("twist", Value::from(-1), false),
1352 ("twist", Value::from(23.5), false),
1353 ("altitudeAngle", Value::from(0), true),
1354 ("altitudeAngle", Value::from(f64::consts::FRAC_PI_4), true),
1355 ("altitudeAngle", Value::from(f64::consts::FRAC_PI_2), true),
1356 (
1357 "altitudeAngle",
1358 Value::from(f64::consts::FRAC_PI_2 + 0.1),
1359 false,
1360 ),
1361 ("altitudeAngle", Value::from(-f64::consts::FRAC_PI_4), false),
1362 ("azimuthAngle", Value::from(0), true),
1363 ("azimuthAngle", Value::from(f64::consts::PI), true),
1364 ("azimuthAngle", Value::from(f64::consts::TAU), true),
1365 ("azimuthAngle", Value::from(f64::consts::TAU + 0.01), false),
1366 ("azimuthAngle", Value::from(-f64::consts::FRAC_PI_4), false),
1367 ] {
1368 let mut json = serde_json::Map::new();
1369 json.insert("type".into(), actionType.into());
1370 if actionType != "pointerMove" {
1371 json.insert("button".into(), Value::from(0));
1372 } else {
1373 json.insert("x".into(), Value::from(0));
1374 json.insert("y".into(), Value::from(0));
1375 }
1376 json.insert(prop_name.into(), value);
1377 println!("{:?}", json);
1378 let deserialized = serde_json::from_value::<PointerAction>(json.into());
1379 if is_valid {
1380 assert!(deserialized.is_ok());
1381 } else {
1382 assert!(deserialized.is_err());
1383 }
1384 }
1385 }
1386 }
1387}