1use std::{
4 fmt,
5 hash::{Hash, Hasher},
6 path::PathBuf,
7};
8
9use bitflags::bitflags;
10
11#[cfg(feature = "serde")]
12use serde::{Deserialize, Serialize};
13
14#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
16#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
17#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
18pub enum AccessMode {
19 Any,
21
22 Execute,
24
25 Read,
27
28 Write,
30
31 Other,
33}
34
35#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
37#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
38#[cfg_attr(feature = "serde", serde(tag = "kind", content = "mode"))]
39#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
40pub enum AccessKind {
41 Any,
43
44 Read,
46
47 Open(AccessMode),
49
50 Close(AccessMode),
52
53 Other,
55}
56
57#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
59#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
60#[cfg_attr(feature = "serde", serde(tag = "kind"))]
61#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
62pub enum CreateKind {
63 Any,
65
66 File,
68
69 Folder,
71
72 Other,
74}
75
76#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
78#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
79#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
80pub enum DataChange {
81 Any,
83
84 Size,
86
87 Content,
89
90 Other,
92}
93
94#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
96#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
97#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
98pub enum MetadataKind {
99 Any,
101
102 AccessTime,
104
105 WriteTime,
107
108 Permissions,
110
111 Ownership,
113
114 Extended,
119
120 Other,
122}
123
124#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
126#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
127#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
128pub enum RenameMode {
129 Any,
131
132 To,
134
135 From,
137
138 Both,
143
144 Other,
146}
147
148#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
150#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
151#[cfg_attr(feature = "serde", serde(tag = "kind", content = "mode"))]
152#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
153pub enum ModifyKind {
154 Any,
156
157 Data(DataChange),
159
160 Metadata(MetadataKind),
162
163 #[cfg_attr(feature = "serde", serde(rename = "rename"))]
165 Name(RenameMode),
166
167 Other,
169}
170
171#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
173#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
174#[cfg_attr(feature = "serde", serde(tag = "kind"))]
175#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
176pub enum RemoveKind {
177 Any,
179
180 File,
182
183 Folder,
185
186 Other,
188}
189
190#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
196#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
197#[cfg_attr(feature = "serde", serde(rename_all = "kebab-case"))]
198#[cfg_attr(
199 all(feature = "serde", not(feature = "serialization-compat-6")),
200 serde(tag = "type")
201)]
202pub enum EventKind {
203 #[default]
211 Any,
212
213 Access(AccessKind),
221
222 Create(CreateKind),
227
228 Modify(ModifyKind),
233
234 Remove(RemoveKind),
243
244 Other,
248}
249
250impl EventKind {
251 pub fn is_access(&self) -> bool {
253 matches!(self, EventKind::Access(_))
254 }
255
256 pub fn is_create(&self) -> bool {
258 matches!(self, EventKind::Create(_))
259 }
260
261 pub fn is_modify(&self) -> bool {
263 matches!(self, EventKind::Modify(_))
264 }
265
266 pub fn is_remove(&self) -> bool {
268 matches!(self, EventKind::Remove(_))
269 }
270
271 pub fn is_other(&self) -> bool {
273 matches!(self, EventKind::Other)
274 }
275}
276
277bitflags! {
278 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
301 #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
302 pub struct EventKindMask: u32 {
303 const CREATE = 0b0000_0001;
305
306 const REMOVE = 0b0000_0010;
308
309 const MODIFY_DATA = 0b0000_0100;
311
312 const MODIFY_META = 0b0000_1000;
314
315 const MODIFY_NAME = 0b0001_0000;
317
318 const ACCESS_OPEN = 0b0010_0000;
320
321 const ACCESS_CLOSE = 0b0100_0000;
324
325 const ACCESS_CLOSE_NOWRITE = 0b1000_0000;
329
330 const ALL_MODIFY = Self::MODIFY_DATA.bits() | Self::MODIFY_META.bits() | Self::MODIFY_NAME.bits();
332
333 const ALL_ACCESS = Self::ACCESS_OPEN.bits() | Self::ACCESS_CLOSE.bits() | Self::ACCESS_CLOSE_NOWRITE.bits();
335
336 const CORE = Self::CREATE.bits() | Self::REMOVE.bits() | Self::ALL_MODIFY.bits();
339
340 const ALL = Self::CORE.bits() | Self::ALL_ACCESS.bits();
342 }
343}
344
345impl Default for EventKindMask {
346 fn default() -> Self {
347 EventKindMask::ALL
348 }
349}
350
351impl EventKindMask {
352 pub fn matches(&self, kind: &EventKind) -> bool {
372 match kind {
373 EventKind::Any | EventKind::Other => true,
375
376 EventKind::Create(_) => self.intersects(EventKindMask::CREATE),
378
379 EventKind::Remove(_) => self.intersects(EventKindMask::REMOVE),
381
382 EventKind::Modify(modify_kind) => match modify_kind {
384 ModifyKind::Data(_) => self.intersects(EventKindMask::MODIFY_DATA),
385 ModifyKind::Metadata(_) => self.intersects(EventKindMask::MODIFY_META),
386 ModifyKind::Name(_) => self.intersects(EventKindMask::MODIFY_NAME),
387 ModifyKind::Any | ModifyKind::Other => self.intersects(EventKindMask::ALL_MODIFY),
389 },
390
391 EventKind::Access(access_kind) => match access_kind {
393 AccessKind::Open(_) => self.intersects(EventKindMask::ACCESS_OPEN),
394 AccessKind::Close(AccessMode::Write) => {
396 self.intersects(EventKindMask::ACCESS_CLOSE)
397 }
398 AccessKind::Close(AccessMode::Read) => {
400 self.intersects(EventKindMask::ACCESS_CLOSE_NOWRITE)
401 }
402 AccessKind::Close(_) => self
404 .intersects(EventKindMask::ACCESS_CLOSE | EventKindMask::ACCESS_CLOSE_NOWRITE),
405 AccessKind::Read | AccessKind::Any | AccessKind::Other => {
407 self.intersects(EventKindMask::ALL_ACCESS)
408 }
409 },
410 }
411 }
412}
413
414#[derive(Clone)]
419#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
420pub struct Event {
421 #[cfg_attr(
444 all(feature = "serde", not(feature = "serialization-compat-6")),
445 serde(flatten)
446 )]
447 #[cfg_attr(
448 all(feature = "serde", feature = "serialization-compat-6"),
449 serde(rename = "type")
450 )]
451 pub kind: EventKind,
452
453 pub paths: Vec<PathBuf>,
462
463 #[cfg_attr(feature = "serde", serde(default))]
490 pub attrs: EventAttributes,
491}
492
493#[derive(Clone, Default, Debug)]
495#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
496pub struct EventAttributes {
497 #[cfg_attr(feature = "serde", serde(flatten))]
498 inner: Option<Box<EventAttributesInner>>,
499}
500
501#[derive(Clone, Default, Debug)]
502#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
503struct EventAttributesInner {
504 #[cfg_attr(
510 feature = "serde",
511 serde(default, skip_serializing_if = "Option::is_none")
512 )]
513 tracker: Option<usize>,
514
515 #[cfg_attr(
517 feature = "serde",
518 serde(default, skip_serializing_if = "Option::is_none")
519 )]
520 flag: Option<Flag>,
521
522 #[cfg_attr(
534 feature = "serde",
535 serde(default, skip_serializing_if = "Option::is_none")
536 )]
537 info: Option<String>,
538
539 #[cfg_attr(
545 feature = "serde",
546 serde(default, skip_serializing_if = "Option::is_none")
547 )]
548 source: Option<String>,
549
550 #[cfg_attr(
555 feature = "serde",
556 serde(default, skip_serializing, skip_deserializing)
557 )]
558 process_id: Option<u32>,
559}
560
561impl EventAttributes {
562 pub fn new() -> Self {
564 Self { inner: None }
565 }
566
567 pub fn tracker(&self) -> Option<usize> {
569 self.inner.as_ref().and_then(|inner| inner.tracker)
570 }
571
572 pub fn flag(&self) -> Option<Flag> {
574 self.inner.as_ref().and_then(|inner| inner.flag)
575 }
576
577 pub fn info(&self) -> Option<&str> {
579 self.inner.as_ref().and_then(|inner| inner.info.as_deref())
580 }
581
582 pub fn source(&self) -> Option<&str> {
584 self.inner
585 .as_ref()
586 .and_then(|inner| inner.source.as_deref())
587 }
588
589 pub fn process_id(&self) -> Option<u32> {
594 self.inner.as_ref().and_then(|inner| inner.process_id)
595 }
596
597 pub fn set_tracker(&mut self, tracker: usize) {
599 self.inner_mut().tracker = Some(tracker);
600 }
601
602 pub fn set_flag(&mut self, flag: Flag) {
604 self.inner_mut().flag = Some(flag);
605 }
606
607 pub fn set_info(&mut self, info: &str) {
609 self.inner_mut().info = Some(info.to_string());
610 }
611
612 pub fn set_process_id(&mut self, process_id: u32) {
614 self.inner_mut().process_id = Some(process_id)
615 }
616
617 fn inner_mut(&mut self) -> &mut EventAttributesInner {
618 self.inner.get_or_insert_with(Box::default)
619 }
620}
621
622#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
627#[cfg_attr(feature = "serde", derive(Deserialize, Serialize))]
628#[cfg_attr(
629 all(feature = "serde", not(feature = "serialization-compat-6")),
630 serde(rename_all = "camelCase")
631)]
632pub enum Flag {
633 Rescan,
641}
642
643impl Event {
644 pub fn need_rescan(&self) -> bool {
649 matches!(self.flag(), Some(Flag::Rescan))
650 }
651 pub fn tracker(&self) -> Option<usize> {
653 self.attrs.tracker()
654 }
655
656 pub fn flag(&self) -> Option<Flag> {
658 self.attrs.flag()
659 }
660
661 pub fn info(&self) -> Option<&str> {
663 self.attrs.info()
664 }
665
666 pub fn source(&self) -> Option<&str> {
668 self.attrs.source()
669 }
670
671 pub fn new(kind: EventKind) -> Self {
673 Self {
674 kind,
675 paths: Vec::new(),
676 attrs: EventAttributes::new(),
677 }
678 }
679
680 pub fn set_kind(mut self, kind: EventKind) -> Self {
682 self.kind = kind;
683 self
684 }
685
686 pub fn add_path(mut self, path: PathBuf) -> Self {
688 self.paths.push(path);
689 self
690 }
691
692 pub fn add_some_path(self, path: Option<PathBuf>) -> Self {
694 if let Some(path) = path {
695 self.add_path(path)
696 } else {
697 self
698 }
699 }
700
701 pub fn set_tracker(mut self, tracker: usize) -> Self {
703 self.attrs.set_tracker(tracker);
704 self
705 }
706
707 pub fn set_info(mut self, info: &str) -> Self {
709 self.attrs.set_info(info);
710 self
711 }
712
713 pub fn set_flag(mut self, flag: Flag) -> Self {
715 self.attrs.set_flag(flag);
716 self
717 }
718
719 pub fn set_process_id(mut self, process_id: u32) -> Self {
721 self.attrs.set_process_id(process_id);
722 self
723 }
724}
725
726impl fmt::Debug for Event {
727 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
728 f.debug_struct("Event")
729 .field("kind", &self.kind)
730 .field("paths", &self.paths)
731 .field("attr:tracker", &self.tracker())
732 .field("attr:flag", &self.flag())
733 .field("attr:info", &self.info())
734 .field("attr:source", &self.source())
735 .finish()
736 }
737}
738impl Default for Event {
739 fn default() -> Self {
740 Self {
741 kind: EventKind::default(),
742 paths: Vec::new(),
743 attrs: EventAttributes::new(),
744 }
745 }
746}
747
748impl Eq for Event {}
749impl PartialEq for Event {
750 fn eq(&self, other: &Self) -> bool {
751 self.kind.eq(&other.kind)
752 && self.paths.eq(&other.paths)
753 && self.tracker().eq(&other.tracker())
754 && self.flag().eq(&other.flag())
755 && self.info().eq(&other.info())
756 && self.source().eq(&other.source())
757 }
758}
759
760impl Hash for Event {
761 fn hash<H: Hasher>(&self, state: &mut H) {
762 self.kind.hash(state);
763 self.paths.hash(state);
764 self.tracker().hash(state);
765 self.flag().hash(state);
766 self.info().hash(state);
767 self.source().hash(state);
768 }
769}
770
771#[cfg(test)]
772mod event_kind_mask_tests {
773 use super::*;
774
775 #[test]
776 fn default_is_all() {
777 assert_eq!(EventKindMask::default(), EventKindMask::ALL);
778 }
779
780 #[test]
781 fn matches_create_events() {
782 let mask = EventKindMask::CREATE;
783 assert!(mask.matches(&EventKind::Create(CreateKind::File)));
784 assert!(mask.matches(&EventKind::Create(CreateKind::Folder)));
785 assert!(mask.matches(&EventKind::Create(CreateKind::Any)));
786 assert!(mask.matches(&EventKind::Create(CreateKind::Other)));
787 assert!(!mask.matches(&EventKind::Remove(RemoveKind::File)));
788 }
789
790 #[test]
791 fn matches_remove_events() {
792 let mask = EventKindMask::REMOVE;
793 assert!(mask.matches(&EventKind::Remove(RemoveKind::File)));
794 assert!(mask.matches(&EventKind::Remove(RemoveKind::Folder)));
795 assert!(mask.matches(&EventKind::Remove(RemoveKind::Any)));
796 assert!(!mask.matches(&EventKind::Create(CreateKind::File)));
797 }
798
799 #[test]
800 fn matches_access_open_events() {
801 let mask = EventKindMask::ACCESS_OPEN;
802 assert!(mask.matches(&EventKind::Access(AccessKind::Open(AccessMode::Any))));
803 assert!(mask.matches(&EventKind::Access(AccessKind::Open(AccessMode::Read))));
804 assert!(mask.matches(&EventKind::Access(AccessKind::Open(AccessMode::Write))));
805 assert!(!mask.matches(&EventKind::Access(AccessKind::Close(AccessMode::Write))));
806 assert!(!mask.matches(&EventKind::Create(CreateKind::File)));
807 }
808
809 #[test]
810 fn matches_access_close_events() {
811 let mask = EventKindMask::ACCESS_CLOSE;
813 assert!(mask.matches(&EventKind::Access(AccessKind::Close(AccessMode::Write))));
814 assert!(mask.matches(&EventKind::Access(AccessKind::Close(AccessMode::Any)))); assert!(!mask.matches(&EventKind::Access(AccessKind::Close(AccessMode::Read)))); assert!(!mask.matches(&EventKind::Access(AccessKind::Open(AccessMode::Any))));
817 }
818
819 #[test]
820 fn matches_access_close_nowrite_events() {
821 let mask = EventKindMask::ACCESS_CLOSE_NOWRITE;
823 assert!(mask.matches(&EventKind::Access(AccessKind::Close(AccessMode::Read))));
824 assert!(mask.matches(&EventKind::Access(AccessKind::Close(AccessMode::Any)))); assert!(!mask.matches(&EventKind::Access(AccessKind::Close(AccessMode::Write)))); assert!(!mask.matches(&EventKind::Access(AccessKind::Open(AccessMode::Any))));
827 }
828
829 #[test]
830 fn combined_close_masks_match_both() {
831 let mask = EventKindMask::ACCESS_CLOSE | EventKindMask::ACCESS_CLOSE_NOWRITE;
833 assert!(mask.matches(&EventKind::Access(AccessKind::Close(AccessMode::Write))));
834 assert!(mask.matches(&EventKind::Access(AccessKind::Close(AccessMode::Read))));
835 assert!(mask.matches(&EventKind::Access(AccessKind::Close(AccessMode::Any))));
836 }
837
838 #[test]
839 fn all_access_matches_open_close_read_any_other() {
840 let mask = EventKindMask::ALL_ACCESS;
841 assert!(mask.matches(&EventKind::Access(AccessKind::Open(AccessMode::Read))));
842 assert!(mask.matches(&EventKind::Access(AccessKind::Close(AccessMode::Write))));
843 assert!(mask.matches(&EventKind::Access(AccessKind::Read)));
844 assert!(mask.matches(&EventKind::Access(AccessKind::Any)));
845 assert!(mask.matches(&EventKind::Access(AccessKind::Other)));
846 }
847
848 #[test]
849 fn matches_modify_data_events() {
850 let mask = EventKindMask::MODIFY_DATA;
851 assert!(mask.matches(&EventKind::Modify(ModifyKind::Data(DataChange::Any))));
852 assert!(mask.matches(&EventKind::Modify(ModifyKind::Data(DataChange::Size))));
853 assert!(mask.matches(&EventKind::Modify(ModifyKind::Data(DataChange::Content))));
854 assert!(!mask.matches(&EventKind::Modify(ModifyKind::Metadata(MetadataKind::Any))));
855 assert!(!mask.matches(&EventKind::Modify(ModifyKind::Name(RenameMode::From))));
856 }
857
858 #[test]
859 fn matches_modify_metadata_events() {
860 let mask = EventKindMask::MODIFY_META;
861 assert!(mask.matches(&EventKind::Modify(ModifyKind::Metadata(MetadataKind::Any))));
862 assert!(mask.matches(&EventKind::Modify(ModifyKind::Metadata(
863 MetadataKind::Permissions
864 ))));
865 assert!(!mask.matches(&EventKind::Modify(ModifyKind::Data(DataChange::Any))));
866 }
867
868 #[test]
869 fn matches_modify_name_events() {
870 let mask = EventKindMask::MODIFY_NAME;
871 assert!(mask.matches(&EventKind::Modify(ModifyKind::Name(RenameMode::From))));
872 assert!(mask.matches(&EventKind::Modify(ModifyKind::Name(RenameMode::To))));
873 assert!(mask.matches(&EventKind::Modify(ModifyKind::Name(RenameMode::Both))));
874 assert!(!mask.matches(&EventKind::Modify(ModifyKind::Data(DataChange::Any))));
875 }
876
877 #[test]
878 fn all_modify_matches_data_meta_name() {
879 let mask = EventKindMask::ALL_MODIFY;
880 assert!(mask.matches(&EventKind::Modify(ModifyKind::Data(DataChange::Any))));
881 assert!(mask.matches(&EventKind::Modify(ModifyKind::Metadata(MetadataKind::Any))));
882 assert!(mask.matches(&EventKind::Modify(ModifyKind::Name(RenameMode::From))));
883 assert!(mask.matches(&EventKind::Modify(ModifyKind::Any)));
884 assert!(mask.matches(&EventKind::Modify(ModifyKind::Other)));
885 }
886
887 #[test]
888 fn any_and_other_always_pass() {
889 let empty = EventKindMask::empty();
890 assert!(empty.matches(&EventKind::Any));
891 assert!(empty.matches(&EventKind::Other));
892 }
893
894 #[test]
895 fn core_excludes_access() {
896 let core = EventKindMask::CORE;
897 assert!(core.matches(&EventKind::Create(CreateKind::File)));
898 assert!(core.matches(&EventKind::Remove(RemoveKind::File)));
899 assert!(core.matches(&EventKind::Modify(ModifyKind::Data(DataChange::Any))));
900 assert!(core.matches(&EventKind::Modify(ModifyKind::Metadata(MetadataKind::Any))));
901 assert!(core.matches(&EventKind::Modify(ModifyKind::Name(RenameMode::From))));
902 assert!(!core.matches(&EventKind::Access(AccessKind::Open(AccessMode::Any))));
903 assert!(!core.matches(&EventKind::Access(AccessKind::Close(AccessMode::Write))));
904 }
905
906 #[test]
907 fn empty_mask_only_passes_any_other() {
908 let empty = EventKindMask::empty();
909 assert!(empty.matches(&EventKind::Any));
910 assert!(empty.matches(&EventKind::Other));
911 assert!(!empty.matches(&EventKind::Create(CreateKind::File)));
912 assert!(!empty.matches(&EventKind::Remove(RemoveKind::File)));
913 assert!(!empty.matches(&EventKind::Modify(ModifyKind::Data(DataChange::Any))));
914 assert!(!empty.matches(&EventKind::Access(AccessKind::Open(AccessMode::Any))));
915 }
916
917 #[test]
918 fn bitwise_or_combines_masks() {
919 let mask = EventKindMask::CREATE | EventKindMask::REMOVE;
920 assert!(mask.matches(&EventKind::Create(CreateKind::File)));
921 assert!(mask.matches(&EventKind::Remove(RemoveKind::Folder)));
922 assert!(!mask.matches(&EventKind::Modify(ModifyKind::Data(DataChange::Any))));
923 assert!(!mask.matches(&EventKind::Access(AccessKind::Open(AccessMode::Any))));
924 }
925
926 #[test]
927 fn all_matches_everything() {
928 let all = EventKindMask::ALL;
929 assert!(all.matches(&EventKind::Any));
930 assert!(all.matches(&EventKind::Other));
931 assert!(all.matches(&EventKind::Create(CreateKind::File)));
932 assert!(all.matches(&EventKind::Remove(RemoveKind::File)));
933 assert!(all.matches(&EventKind::Modify(ModifyKind::Data(DataChange::Any))));
934 assert!(all.matches(&EventKind::Access(AccessKind::Open(AccessMode::Any))));
935 assert!(all.matches(&EventKind::Access(AccessKind::Close(AccessMode::Write))));
936 }
937
938 #[test]
939 fn access_read_and_any_match_with_all_access() {
940 let mask = EventKindMask::ALL_ACCESS;
942 assert!(mask.matches(&EventKind::Access(AccessKind::Read)));
943 assert!(mask.matches(&EventKind::Access(AccessKind::Any)));
944 assert!(mask.matches(&EventKind::Access(AccessKind::Other)));
945 }
946}
947
948#[cfg(all(test, feature = "serde", not(feature = "serialization-compat-6")))]
949mod tests {
950 use super::*;
951
952 use insta::assert_snapshot;
953 use rstest::rstest;
954
955 #[rustfmt::skip]
956 #[rstest]
957 #[case("any", EventKind::Any)]
958 #[case("access-any", EventKind::Access(AccessKind::Any))]
959 #[case("access-read", EventKind::Access(AccessKind::Read))]
960 #[case("access-open-any", EventKind::Access(AccessKind::Open(AccessMode::Any)))]
961 #[case("access-open-execute", EventKind::Access(AccessKind::Open(AccessMode::Execute)))]
962 #[case("access-open-read", EventKind::Access(AccessKind::Open(AccessMode::Read)))]
963 #[case("access-open-write", EventKind::Access(AccessKind::Open(AccessMode::Write)))]
964 #[case("access-open-other", EventKind::Access(AccessKind::Open(AccessMode::Other)))]
965 #[case("access-close-any", EventKind::Access(AccessKind::Close(AccessMode::Any)))]
966 #[case("access-close-execute", EventKind::Access(AccessKind::Close(AccessMode::Execute)))]
967 #[case("access-close-read", EventKind::Access(AccessKind::Close(AccessMode::Read)))]
968 #[case("access-close-write", EventKind::Access(AccessKind::Close(AccessMode::Write)))]
969 #[case("access-close-other", EventKind::Access(AccessKind::Close(AccessMode::Other)))]
970 #[case("access-other", EventKind::Access(AccessKind::Other))]
971 #[case("create-any", EventKind::Create(CreateKind::Any))]
972 #[case("create-file", EventKind::Create(CreateKind::File))]
973 #[case("create-folder", EventKind::Create(CreateKind::Folder))]
974 #[case("create-other", EventKind::Create(CreateKind::Other))]
975 #[case("modify-any", EventKind::Modify(ModifyKind::Any))]
976 #[case("modify-data-any", EventKind::Modify(ModifyKind::Data(DataChange::Any)))]
977 #[case("modify-data-size", EventKind::Modify(ModifyKind::Data(DataChange::Size)))]
978 #[case("modify-data-content", EventKind::Modify(ModifyKind::Data(DataChange::Content)))]
979 #[case("modify-data-other", EventKind::Modify(ModifyKind::Data(DataChange::Other)))]
980 #[case("modify-metadata-any", EventKind::Modify(ModifyKind::Metadata(MetadataKind::Any)))]
981 #[case("modify-metadata-accesstime", EventKind::Modify(ModifyKind::Metadata(MetadataKind::AccessTime)))]
982 #[case("modify-metadata-writetime", EventKind::Modify(ModifyKind::Metadata(MetadataKind::WriteTime)))]
983 #[case("modify-metadata-permissions", EventKind::Modify(ModifyKind::Metadata(MetadataKind::Permissions)))]
984 #[case("modify-metadata-ownership", EventKind::Modify(ModifyKind::Metadata(MetadataKind::Ownership)))]
985 #[case("modify-metadata-extended", EventKind::Modify(ModifyKind::Metadata(MetadataKind::Extended)))]
986 #[case("modify-metadata-other", EventKind::Modify(ModifyKind::Metadata(MetadataKind::Other)))]
987 #[case("modify-name-any", EventKind::Modify(ModifyKind::Name(RenameMode::Any)))]
988 #[case("modify-name-to", EventKind::Modify(ModifyKind::Name(RenameMode::To)))]
989 #[case("modify-name-from", EventKind::Modify(ModifyKind::Name(RenameMode::From)))]
990 #[case("modify-name-both", EventKind::Modify(ModifyKind::Name(RenameMode::Both)))]
991 #[case("modify-name-other", EventKind::Modify(ModifyKind::Name(RenameMode::Other)))]
992 #[case("modify-other", EventKind::Modify(ModifyKind::Other))]
993 #[case("remove-any", EventKind::Remove(RemoveKind::Any))]
994 #[case("remove-file", EventKind::Remove(RemoveKind::File))]
995 #[case("remove-folder", EventKind::Remove(RemoveKind::Folder))]
996 #[case("remove-other", EventKind::Remove(RemoveKind::Other))]
997 #[case("other", EventKind::Other)]
998 fn serialize_event_kind(
999 #[case] name: &str,
1000 #[case] event_kind: EventKind,
1001 ) {
1002 let event = Event::new(event_kind);
1003 let json = serde_json::to_string(&event).unwrap();
1004 assert_snapshot!(name, json);
1005 }
1006
1007 #[test]
1008 fn serialize_event_with_attrs() {
1009 let event = Event::new(EventKind::Any)
1010 .set_tracker(123)
1011 .set_flag(Flag::Rescan)
1012 .set_info("test event")
1013 .set_process_id(0);
1014 let json = serde_json::to_string(&event).unwrap();
1015 assert_snapshot!(json);
1016 }
1017}