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 if !(0f64..=1.0).contains(&value) {
434 return Err(de::Error::custom(format!("{} is outside range 0-1", value)));
435 }
436 };
437 Ok(opt_value)
438}
439
440fn deserialize_to_tangential_pressure<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error>
441where
442 D: Deserializer<'de>,
443{
444 let opt_value = deserialize_to_option_f64(deserializer)?;
445 if let Some(value) = opt_value {
446 if !(-1.0..=1.0).contains(&value) {
447 return Err(de::Error::custom(format!(
448 "{} is outside range -1-1",
449 value
450 )));
451 }
452 };
453 Ok(opt_value)
454}
455
456fn deserialize_to_tilt<'de, D>(deserializer: D) -> Result<Option<i64>, D::Error>
457where
458 D: Deserializer<'de>,
459{
460 let opt_value = deserialize_to_option_i64(deserializer)?;
461 if let Some(value) = opt_value {
462 if !(-90..=90).contains(&value) {
463 return Err(de::Error::custom(format!(
464 "{} is outside range -90-90",
465 value
466 )));
467 }
468 };
469 Ok(opt_value)
470}
471
472fn deserialize_to_twist<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
473where
474 D: Deserializer<'de>,
475{
476 let opt_value = deserialize_to_option_u64(deserializer)?;
477 if let Some(value) = opt_value {
478 if !(0..=359).contains(&value) {
479 return Err(de::Error::custom(format!(
480 "{} is outside range 0-359",
481 value
482 )));
483 }
484 };
485 Ok(opt_value)
486}
487
488fn deserialize_to_altitude_angle<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error>
489where
490 D: Deserializer<'de>,
491{
492 let opt_value = deserialize_to_option_f64(deserializer)?;
493 if let Some(value) = opt_value {
494 if !(0f64..=f64::consts::FRAC_PI_2).contains(&value) {
495 return Err(de::Error::custom(format!(
496 "{} is outside range 0-PI/2",
497 value
498 )));
499 }
500 };
501 Ok(opt_value)
502}
503
504fn deserialize_to_azimuth_angle<'de, D>(deserializer: D) -> Result<Option<f64>, D::Error>
505where
506 D: Deserializer<'de>,
507{
508 let opt_value = deserialize_to_option_f64(deserializer)?;
509 if let Some(value) = opt_value {
510 if !(0f64..=f64::consts::TAU).contains(&value) {
511 return Err(de::Error::custom(format!(
512 "{} is outside range 0-2*PI",
513 value
514 )));
515 }
516 };
517 Ok(opt_value)
518}
519
520#[cfg(test)]
521mod test {
522 use super::*;
523 use crate::test::{assert_de, assert_ser_de};
524 use serde_json::{self, json, Value};
525
526 #[test]
527 fn test_json_action_sequence_null() {
528 let json = json!({
529 "id": "some_key",
530 "type": "none",
531 "actions": [{
532 "type": "pause",
533 "duration": 1,
534 }]
535 });
536 let seq = ActionSequence {
537 id: "some_key".into(),
538 actions: ActionsType::Null {
539 actions: vec![NullActionItem::General(GeneralAction::Pause(PauseAction {
540 duration: Some(1),
541 }))],
542 },
543 };
544
545 assert_ser_de(&seq, json);
546 }
547
548 #[test]
549 fn test_json_action_sequence_key() {
550 let json = json!({
551 "id": "some_key",
552 "type": "key",
553 "actions": [
554 {"type": "keyDown", "value": "f"},
555 ],
556 });
557 let seq = ActionSequence {
558 id: "some_key".into(),
559 actions: ActionsType::Key {
560 actions: vec![KeyActionItem::Key(KeyAction::Down(KeyDownAction {
561 value: String::from("f"),
562 }))],
563 },
564 };
565
566 assert_ser_de(&seq, json);
567 }
568
569 #[test]
570 fn test_json_action_sequence_pointer() {
571 let json = json!({
572 "id": "some_pointer",
573 "type": "pointer",
574 "parameters": {
575 "pointerType": "mouse"
576 },
577 "actions": [
578 {"type": "pointerDown", "button": 0},
579 {"type": "pointerMove", "origin": "pointer", "x": 10.5, "y": 20.5},
580 {"type": "pointerUp", "button": 0},
581 ]
582 });
583 let seq = ActionSequence {
584 id: "some_pointer".into(),
585 actions: ActionsType::Pointer {
586 parameters: PointerActionParameters {
587 pointer_type: PointerType::Mouse,
588 },
589 actions: vec![
590 PointerActionItem::Pointer(PointerAction::Down(PointerDownAction {
591 button: 0,
592 ..Default::default()
593 })),
594 PointerActionItem::Pointer(PointerAction::Move(PointerMoveAction {
595 origin: PointerOrigin::Pointer,
596 duration: None,
597 x: 10.5,
598 y: 20.5,
599 ..Default::default()
600 })),
601 PointerActionItem::Pointer(PointerAction::Up(PointerUpAction {
602 button: 0,
603 ..Default::default()
604 })),
605 ],
606 },
607 };
608
609 assert_ser_de(&seq, json);
610 }
611
612 #[test]
613 fn test_json_action_sequence_id_missing() {
614 let json = json!({
615 "type": "key",
616 "actions": [],
617 });
618 assert!(serde_json::from_value::<ActionSequence>(json).is_err());
619 }
620
621 #[test]
622 fn test_json_action_sequence_id_null() {
623 let json = json!({
624 "id": null,
625 "type": "key",
626 "actions": [],
627 });
628 assert!(serde_json::from_value::<ActionSequence>(json).is_err());
629 }
630
631 #[test]
632 fn test_json_action_sequence_actions_missing() {
633 assert!(serde_json::from_value::<ActionSequence>(json!({"id": "3"})).is_err());
634 }
635
636 #[test]
637 fn test_json_action_sequence_actions_null() {
638 let json = json!({
639 "id": "3",
640 "actions": null,
641 });
642 assert!(serde_json::from_value::<ActionSequence>(json).is_err());
643 }
644
645 #[test]
646 fn test_json_action_sequence_actions_invalid_type() {
647 let json = json!({
648 "id": "3",
649 "actions": "foo",
650 });
651 assert!(serde_json::from_value::<ActionSequence>(json).is_err());
652 }
653
654 #[test]
655 fn test_json_actions_type_null() {
656 let json = json!({
657 "type": "none",
658 "actions": [{
659 "type": "pause",
660 "duration": 1,
661 }],
662 });
663 let null = ActionsType::Null {
664 actions: vec![NullActionItem::General(GeneralAction::Pause(PauseAction {
665 duration: Some(1),
666 }))],
667 };
668
669 assert_ser_de(&null, json);
670 }
671
672 #[test]
673 fn test_json_actions_type_key() {
674 let json = json!({
675 "type": "key",
676 "actions": [{
677 "type": "keyDown",
678 "value": "f",
679 }],
680 });
681 let key = ActionsType::Key {
682 actions: vec![KeyActionItem::Key(KeyAction::Down(KeyDownAction {
683 value: String::from("f"),
684 }))],
685 };
686
687 assert_ser_de(&key, json);
688 }
689
690 #[test]
691 fn test_json_actions_type_pointer() {
692 let json = json!({
693 "type": "pointer",
694 "parameters": {"pointerType": "mouse"},
695 "actions": [
696 {"type": "pointerDown", "button": 1},
697 ]});
698 let pointer = ActionsType::Pointer {
699 parameters: PointerActionParameters {
700 pointer_type: PointerType::Mouse,
701 },
702 actions: vec![PointerActionItem::Pointer(PointerAction::Down(
703 PointerDownAction {
704 button: 1,
705 ..Default::default()
706 },
707 ))],
708 };
709
710 assert_ser_de(&pointer, json);
711 }
712
713 #[test]
714 fn test_json_actions_type_pointer_with_parameters_missing() {
715 let json = json!({
716 "type": "pointer",
717 "actions": [
718 {"type": "pointerDown", "button": 1},
719 ]});
720 let pointer = ActionsType::Pointer {
721 parameters: PointerActionParameters {
722 pointer_type: PointerType::Mouse,
723 },
724 actions: vec![PointerActionItem::Pointer(PointerAction::Down(
725 PointerDownAction {
726 button: 1,
727 ..Default::default()
728 },
729 ))],
730 };
731
732 assert_de(&pointer, json);
733 }
734
735 #[test]
736 fn test_json_actions_type_pointer_with_parameters_invalid_type() {
737 let json = json!({
738 "type": "pointer",
739 "parameters": null,
740 "actions": [
741 {"type":"pointerDown", "button": 1},
742 ]});
743 assert!(serde_json::from_value::<ActionsType>(json).is_err());
744 }
745
746 #[test]
747 fn test_json_actions_type_invalid() {
748 let json = json!({"actions": [{"foo": "bar"}]});
749 assert!(serde_json::from_value::<ActionsType>(json).is_err());
750 }
751
752 #[test]
753 fn test_json_null_action_item_general() {
754 let pause =
755 NullActionItem::General(GeneralAction::Pause(PauseAction { duration: Some(1) }));
756 assert_ser_de(&pause, json!({"type": "pause", "duration": 1}));
757 }
758
759 #[test]
760 fn test_json_null_action_item_invalid_type() {
761 assert!(serde_json::from_value::<NullActionItem>(json!({"type": "invalid"})).is_err());
762 }
763
764 #[test]
765 fn test_json_general_action_pause() {
766 let pause = GeneralAction::Pause(PauseAction { duration: Some(1) });
767 assert_ser_de(&pause, json!({"type": "pause", "duration": 1}));
768 }
769
770 #[test]
771 fn test_json_general_action_pause_with_duration_missing() {
772 let pause = GeneralAction::Pause(PauseAction { duration: None });
773 assert_ser_de(&pause, json!({"type": "pause"}));
774 }
775
776 #[test]
777 fn test_json_general_action_pause_with_duration_null() {
778 let json = json!({"type": "pause", "duration": null});
779 assert!(serde_json::from_value::<GeneralAction>(json).is_err());
780 }
781
782 #[test]
783 fn test_json_general_action_pause_with_duration_invalid_type() {
784 let json = json!({"type": "pause", "duration":" foo"});
785 assert!(serde_json::from_value::<GeneralAction>(json).is_err());
786 }
787
788 #[test]
789 fn test_json_general_action_pause_with_duration_negative() {
790 let json = json!({"type": "pause", "duration": -30});
791 assert!(serde_json::from_value::<GeneralAction>(json).is_err());
792 }
793
794 #[test]
795 fn test_json_key_action_item_general() {
796 let pause = KeyActionItem::General(GeneralAction::Pause(PauseAction { duration: Some(1) }));
797 assert_ser_de(&pause, json!({"type": "pause", "duration": 1}));
798 }
799
800 #[test]
801 fn test_json_key_action_item_key() {
802 let key_down = KeyActionItem::Key(KeyAction::Down(KeyDownAction {
803 value: String::from("f"),
804 }));
805 assert_ser_de(&key_down, json!({"type": "keyDown", "value": "f"}));
806 }
807
808 #[test]
809 fn test_json_key_action_item_invalid_type() {
810 assert!(serde_json::from_value::<KeyActionItem>(json!({"type": "invalid"})).is_err());
811 }
812
813 #[test]
814 fn test_json_key_action_missing_subtype() {
815 assert!(serde_json::from_value::<KeyAction>(json!({"value": "f"})).is_err());
816 }
817
818 #[test]
819 fn test_json_key_action_wrong_subtype() {
820 let json = json!({"type": "pause", "value": "f"});
821 assert!(serde_json::from_value::<KeyAction>(json).is_err());
822 }
823
824 #[test]
825 fn test_json_key_action_down() {
826 let key_down = KeyAction::Down(KeyDownAction {
827 value: "f".to_string(),
828 });
829 assert_ser_de(&key_down, json!({"type": "keyDown", "value": "f"}));
830 }
831
832 #[test]
833 fn test_json_key_action_down_with_value_unicode() {
834 let key_down = KeyAction::Down(KeyDownAction {
835 value: "à".to_string(),
836 });
837 assert_ser_de(&key_down, json!({"type": "keyDown", "value": "à"}));
838 }
839
840 #[test]
841 fn test_json_key_action_down_with_value_unicode_encoded() {
842 let key_down = KeyAction::Down(KeyDownAction {
843 value: "à".to_string(),
844 });
845 assert_de(&key_down, json!({"type": "keyDown", "value": "\u{00E0}"}));
846 }
847
848 #[test]
849 fn test_json_key_action_down_with_value_missing() {
850 assert!(serde_json::from_value::<KeyAction>(json!({"type": "keyDown"})).is_err());
851 }
852
853 #[test]
854 fn test_json_key_action_down_with_value_null() {
855 let json = json!({"type": "keyDown", "value": null});
856 assert!(serde_json::from_value::<KeyAction>(json).is_err());
857 }
858
859 #[test]
860 fn test_json_key_action_down_with_value_invalid_type() {
861 let json = json!({"type": "keyDown", "value": ["f", "o", "o"]});
862 assert!(serde_json::from_value::<KeyAction>(json).is_err());
863 }
864
865 #[test]
866 fn test_json_key_action_down_with_multiple_code_points() {
867 let json = json!({"type": "keyDown", "value": "fo"});
868 assert!(serde_json::from_value::<KeyAction>(json).is_err());
869 }
870
871 #[test]
872 fn test_json_key_action_up() {
873 let key_up = KeyAction::Up(KeyUpAction {
874 value: "f".to_string(),
875 });
876 assert_ser_de(&key_up, json!({"type": "keyUp", "value": "f"}));
877 }
878
879 #[test]
880 fn test_json_key_action_up_with_value_unicode() {
881 let key_up = KeyAction::Up(KeyUpAction {
882 value: "à".to_string(),
883 });
884 assert_ser_de(&key_up, json!({"type":"keyUp", "value": "à"}));
885 }
886
887 #[test]
888 fn test_json_key_action_up_with_value_unicode_encoded() {
889 let key_up = KeyAction::Up(KeyUpAction {
890 value: "à".to_string(),
891 });
892 assert_de(&key_up, json!({"type": "keyUp", "value": "\u{00E0}"}));
893 }
894
895 #[test]
896 fn test_json_key_action_up_with_value_missing() {
897 assert!(serde_json::from_value::<KeyAction>(json!({"type": "keyUp"})).is_err());
898 }
899
900 #[test]
901 fn test_json_key_action_up_with_value_null() {
902 let json = json!({"type": "keyUp", "value": null});
903 assert!(serde_json::from_value::<KeyAction>(json).is_err());
904 }
905
906 #[test]
907 fn test_json_key_action_up_with_value_invalid_type() {
908 let json = json!({"type": "keyUp", "value": ["f","o","o"]});
909 assert!(serde_json::from_value::<KeyAction>(json).is_err());
910 }
911
912 #[test]
913 fn test_json_key_action_up_with_multiple_code_points() {
914 let json = json!({"type": "keyUp", "value": "fo"});
915 assert!(serde_json::from_value::<KeyAction>(json).is_err());
916 }
917
918 #[test]
919 fn test_json_pointer_action_item_general() {
920 let pause =
921 PointerActionItem::General(GeneralAction::Pause(PauseAction { duration: Some(1) }));
922 assert_ser_de(&pause, json!({"type": "pause", "duration": 1}));
923 }
924
925 #[test]
926 fn test_json_pointer_action_item_pointer() {
927 let cancel = PointerActionItem::Pointer(PointerAction::Cancel);
928 assert_ser_de(&cancel, json!({"type": "pointerCancel"}));
929 }
930
931 #[test]
932 fn test_json_pointer_action_item_invalid() {
933 assert!(serde_json::from_value::<PointerActionItem>(json!({"type": "invalid"})).is_err());
934 }
935
936 #[test]
937 fn test_json_pointer_action_parameters_mouse() {
938 let mouse = PointerActionParameters {
939 pointer_type: PointerType::Mouse,
940 };
941 assert_ser_de(&mouse, json!({"pointerType": "mouse"}));
942 }
943
944 #[test]
945 fn test_json_pointer_action_parameters_pen() {
946 let pen = PointerActionParameters {
947 pointer_type: PointerType::Pen,
948 };
949 assert_ser_de(&pen, json!({"pointerType": "pen"}));
950 }
951
952 #[test]
953 fn test_json_pointer_action_parameters_touch() {
954 let touch = PointerActionParameters {
955 pointer_type: PointerType::Touch,
956 };
957 assert_ser_de(&touch, json!({"pointerType": "touch"}));
958 }
959
960 #[test]
961 fn test_json_pointer_action_item_invalid_type() {
962 let json = json!({"type": "pointerInvalid"});
963 assert!(serde_json::from_value::<PointerActionItem>(json).is_err());
964 }
965
966 #[test]
967 fn test_json_pointer_action_missing_subtype() {
968 assert!(serde_json::from_value::<PointerAction>(json!({"button": 1})).is_err());
969 }
970
971 #[test]
972 fn test_json_pointer_action_invalid_subtype() {
973 let json = json!({"type": "invalid", "button": 1});
974 assert!(serde_json::from_value::<PointerAction>(json).is_err());
975 }
976
977 #[test]
978 fn test_json_pointer_action_cancel() {
979 assert_ser_de(&PointerAction::Cancel, json!({"type": "pointerCancel"}));
980 }
981
982 #[test]
983 fn test_json_pointer_action_down() {
984 let pointer_down = PointerAction::Down(PointerDownAction {
985 button: 1,
986 ..Default::default()
987 });
988 assert_ser_de(&pointer_down, json!({"type": "pointerDown", "button": 1}));
989 }
990
991 #[test]
992 fn test_json_pointer_action_down_with_button_missing() {
993 let json = json!({"type": "pointerDown"});
994 assert!(serde_json::from_value::<PointerAction>(json).is_err());
995 }
996
997 #[test]
998 fn test_json_pointer_action_down_with_button_null() {
999 let json = json!({
1000 "type": "pointerDown",
1001 "button": null,
1002 });
1003 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1004 }
1005
1006 #[test]
1007 fn test_json_pointer_action_down_with_button_invalid_type() {
1008 let json = json!({
1009 "type": "pointerDown",
1010 "button": "foo",
1011 });
1012 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1013 }
1014
1015 #[test]
1016 fn test_json_pointer_action_down_with_button_negative() {
1017 let json = json!({
1018 "type": "pointerDown",
1019 "button": -30,
1020 });
1021 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1022 }
1023
1024 #[test]
1025 fn test_json_pointer_action_move() {
1026 let json = json!({
1027 "type": "pointerMove",
1028 "duration": 100,
1029 "origin": "viewport",
1030 "x": 5.5,
1031 "y": 10.5,
1032 });
1033 let pointer_move = PointerAction::Move(PointerMoveAction {
1034 duration: Some(100),
1035 origin: PointerOrigin::Viewport,
1036 x: 5.5,
1037 y: 10.5,
1038 ..Default::default()
1039 });
1040
1041 assert_ser_de(&pointer_move, json);
1042 }
1043
1044 #[test]
1045 fn test_json_pointer_action_move_missing_subtype() {
1046 let json = json!({
1047 "duration": 100,
1048 "origin": "viewport",
1049 "x": 5.5,
1050 "y": 10.5,
1051 });
1052 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1053 }
1054
1055 #[test]
1056 fn test_json_pointer_action_move_wrong_subtype() {
1057 let json = json!({
1058 "type": "pointerUp",
1059 "duration": 100,
1060 "origin": "viewport",
1061 "x": 5.5,
1062 "y": 10.5,
1063 });
1064 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1065 }
1066
1067 #[test]
1068 fn test_json_pointer_action_move_with_duration_missing() {
1069 let json = json!({
1070 "type": "pointerMove",
1071 "origin": "viewport",
1072 "x": 5.5,
1073 "y": 10.5,
1074 });
1075 let pointer_move = PointerAction::Move(PointerMoveAction {
1076 duration: None,
1077 origin: PointerOrigin::Viewport,
1078 x: 5.5,
1079 y: 10.5,
1080 ..Default::default()
1081 });
1082
1083 assert_ser_de(&pointer_move, json);
1084 }
1085
1086 #[test]
1087 fn test_json_pointer_action_move_with_duration_null() {
1088 let json = json!({
1089 "type": "pointerMove",
1090 "duration": null,
1091 "origin": "viewport",
1092 "x": 5.5,
1093 "y": 10.5,
1094 });
1095 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1096 }
1097
1098 #[test]
1099 fn test_json_pointer_action_move_with_duration_invalid_type() {
1100 let json = json!({
1101 "type": "pointerMove",
1102 "duration": "invalid",
1103 "origin": "viewport",
1104 "x": 5.5,
1105 "y": 10.5,
1106 });
1107 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1108 }
1109
1110 #[test]
1111 fn test_json_pointer_action_move_with_duration_negative() {
1112 let json = json!({
1113 "type": "pointerMove",
1114 "duration": -30,
1115 "origin": "viewport",
1116 "x": 5.5,
1117 "y": 10.5,
1118 });
1119 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1120 }
1121
1122 #[test]
1123 fn test_json_pointer_action_move_with_origin_missing() {
1124 let json = json!({
1125 "type": "pointerMove",
1126 "duration": 100,
1127 "x": 5.5,
1128 "y": 10.5,
1129 });
1130 let pointer_move = PointerAction::Move(PointerMoveAction {
1131 duration: Some(100),
1132 origin: PointerOrigin::Viewport,
1133 x: 5.5,
1134 y: 10.5,
1135 ..Default::default()
1136 });
1137
1138 assert_de(&pointer_move, json);
1139 }
1140
1141 #[test]
1142 fn test_json_pointer_action_move_with_origin_webelement() {
1143 let json = json!({
1144 "type": "pointerMove",
1145 "duration": 100,
1146 "origin": {ELEMENT_KEY: "elem"},
1147 "x": 5.5,
1148 "y": 10.5,
1149 });
1150 let pointer_move = PointerAction::Move(PointerMoveAction {
1151 duration: Some(100),
1152 origin: PointerOrigin::Element(WebElement("elem".into())),
1153 x: 5.5,
1154 y: 10.5,
1155 ..Default::default()
1156 });
1157
1158 assert_ser_de(&pointer_move, json);
1159 }
1160
1161 #[test]
1162 fn test_json_pointer_action_move_with_origin_webelement_and_legacy_element() {
1163 let json = json!({
1164 "type": "pointerMove",
1165 "duration": 100,
1166 "origin": {ELEMENT_KEY: "elem"},
1167 "x": 5.5,
1168 "y": 10.5,
1169 });
1170 let pointer_move = PointerAction::Move(PointerMoveAction {
1171 duration: Some(100),
1172 origin: PointerOrigin::Element(WebElement("elem".into())),
1173 x: 5.5,
1174 y: 10.5,
1175 ..Default::default()
1176 });
1177
1178 assert_de(&pointer_move, json);
1179 }
1180
1181 #[test]
1182 fn test_json_pointer_action_move_with_origin_only_legacy_element() {
1183 let json = json!({
1184 "type": "pointerMove",
1185 "duration": 100,
1186 "origin": {ELEMENT_KEY: "elem"},
1187 "x": 5,
1188 "y": 10,
1189 });
1190 assert!(serde_json::from_value::<PointerOrigin>(json).is_err());
1191 }
1192
1193 #[test]
1194 fn test_json_pointer_action_move_with_x_null() {
1195 let json = json!({
1196 "type": "pointerMove",
1197 "duration": 100,
1198 "origin": "viewport",
1199 "x": null,
1200 "y": 10,
1201 });
1202 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1203 }
1204
1205 #[test]
1206 fn test_json_pointer_action_move_with_x_invalid_type() {
1207 let json = json!({
1208 "type": "pointerMove",
1209 "duration": 100,
1210 "origin": "viewport",
1211 "x": "invalid",
1212 "y": 10,
1213 });
1214 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1215 }
1216
1217 #[test]
1218 fn test_json_pointer_action_move_with_y_null() {
1219 let json = json!({
1220 "type": "pointerMove",
1221 "duration": 100,
1222 "origin": "viewport",
1223 "x": 5,
1224 "y": null,
1225 });
1226 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1227 }
1228
1229 #[test]
1230 fn test_json_pointer_action_move_with_y_invalid_type() {
1231 let json = json!({
1232 "type": "pointerMove",
1233 "duration": 100,
1234 "origin": "viewport",
1235 "x": 5,
1236 "y": "invalid",
1237 });
1238 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1239 }
1240
1241 #[test]
1242 fn test_json_pointer_action_up() {
1243 let pointer_up = PointerAction::Up(PointerUpAction {
1244 button: 1,
1245 ..Default::default()
1246 });
1247 assert_ser_de(&pointer_up, json!({"type": "pointerUp", "button": 1}));
1248 }
1249
1250 #[test]
1251 fn test_json_pointer_action_up_with_button_missing() {
1252 assert!(serde_json::from_value::<PointerAction>(json!({"type": "pointerUp"})).is_err());
1253 }
1254
1255 #[test]
1256 fn test_json_pointer_action_up_with_button_null() {
1257 let json = json!({
1258 "type": "pointerUp",
1259 "button": null,
1260 });
1261 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1262 }
1263
1264 #[test]
1265 fn test_json_pointer_action_up_with_button_invalid_type() {
1266 let json = json!({
1267 "type": "pointerUp",
1268 "button": "foo",
1269 });
1270 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1271 }
1272
1273 #[test]
1274 fn test_json_pointer_action_up_with_button_negative() {
1275 let json = json!({
1276 "type": "pointerUp",
1277 "button": -30,
1278 });
1279 assert!(serde_json::from_value::<PointerAction>(json).is_err());
1280 }
1281
1282 #[test]
1283 fn test_json_pointer_origin_pointer() {
1284 assert_ser_de(&PointerOrigin::Pointer, json!("pointer"));
1285 }
1286
1287 #[test]
1288 fn test_json_pointer_origin_viewport() {
1289 assert_ser_de(&PointerOrigin::Viewport, json!("viewport"));
1290 }
1291
1292 #[test]
1293 fn test_json_pointer_origin_web_element() {
1294 let element = PointerOrigin::Element(WebElement("elem".into()));
1295 assert_ser_de(&element, json!({ELEMENT_KEY: "elem"}));
1296 }
1297
1298 #[test]
1299 fn test_json_pointer_origin_invalid_type() {
1300 assert!(serde_json::from_value::<PointerOrigin>(json!("invalid")).is_err());
1301 }
1302
1303 #[test]
1304 fn test_json_pointer_type_mouse() {
1305 assert_ser_de(&PointerType::Mouse, json!("mouse"));
1306 }
1307
1308 #[test]
1309 fn test_json_pointer_type_pen() {
1310 assert_ser_de(&PointerType::Pen, json!("pen"));
1311 }
1312
1313 #[test]
1314 fn test_json_pointer_type_touch() {
1315 assert_ser_de(&PointerType::Touch, json!("touch"));
1316 }
1317
1318 #[test]
1319 fn test_json_pointer_type_invalid_type() {
1320 assert!(serde_json::from_value::<PointerType>(json!("invalid")).is_err());
1321 }
1322
1323 #[test]
1324 fn test_pointer_properties() {
1325 for actionType in ["pointerUp", "pointerDown", "pointerMove"] {
1328 for (prop_name, value, is_valid) in [
1329 ("pressure", Value::from(0), true),
1330 ("pressure", Value::from(0.5), true),
1331 ("pressure", Value::from(1), true),
1332 ("pressure", Value::from(1.1), false),
1333 ("pressure", Value::from(-0.1), false),
1334 ("tangentialPressure", Value::from(-1), true),
1335 ("tangentialPressure", Value::from(0), true),
1336 ("tangentialPressure", Value::from(1.0), true),
1337 ("tangentialPressure", Value::from(-1.1), false),
1338 ("tangentialPressure", Value::from(1.1), false),
1339 ("tiltX", Value::from(-90), true),
1340 ("tiltX", Value::from(0), true),
1341 ("tiltX", Value::from(45), true),
1342 ("tiltX", Value::from(90), true),
1343 ("tiltX", Value::from(0.5), false),
1344 ("tiltX", Value::from(-91), false),
1345 ("tiltX", Value::from(91), false),
1346 ("tiltY", Value::from(-90), true),
1347 ("tiltY", Value::from(0), true),
1348 ("tiltY", Value::from(45), true),
1349 ("tiltY", Value::from(90), true),
1350 ("tiltY", Value::from(0.5), false),
1351 ("tiltY", Value::from(-91), false),
1352 ("tiltY", Value::from(91), false),
1353 ("twist", Value::from(0), true),
1354 ("twist", Value::from(180), true),
1355 ("twist", Value::from(359), true),
1356 ("twist", Value::from(360), false),
1357 ("twist", Value::from(-1), false),
1358 ("twist", Value::from(23.5), false),
1359 ("altitudeAngle", Value::from(0), true),
1360 ("altitudeAngle", Value::from(f64::consts::FRAC_PI_4), true),
1361 ("altitudeAngle", Value::from(f64::consts::FRAC_PI_2), true),
1362 (
1363 "altitudeAngle",
1364 Value::from(f64::consts::FRAC_PI_2 + 0.1),
1365 false,
1366 ),
1367 ("altitudeAngle", Value::from(-f64::consts::FRAC_PI_4), false),
1368 ("azimuthAngle", Value::from(0), true),
1369 ("azimuthAngle", Value::from(f64::consts::PI), true),
1370 ("azimuthAngle", Value::from(f64::consts::TAU), true),
1371 ("azimuthAngle", Value::from(f64::consts::TAU + 0.01), false),
1372 ("azimuthAngle", Value::from(-f64::consts::FRAC_PI_4), false),
1373 ] {
1374 let mut json = serde_json::Map::new();
1375 json.insert("type".into(), actionType.into());
1376 if actionType != "pointerMove" {
1377 json.insert("button".into(), Value::from(0));
1378 } else {
1379 json.insert("x".into(), Value::from(0));
1380 json.insert("y".into(), Value::from(0));
1381 }
1382 json.insert(prop_name.into(), value);
1383 println!("{:?}", json);
1384 let deserialized = serde_json::from_value::<PointerAction>(json.into());
1385 if is_valid {
1386 assert!(deserialized.is_ok());
1387 } else {
1388 assert!(deserialized.is_err());
1389 }
1390 }
1391 }
1392 }
1393}