1use std::collections::HashMap;
49use std::path::PathBuf;
50use std::time::Duration;
51
52use anyhow::Result;
53use chrono::Utc;
54use serde::{Deserialize, Serialize};
55
56use crate::auto_reply::cooldown::{CooldownCheckResult, CooldownTracker};
57use crate::auto_reply::group::GroupActivation;
58use crate::auto_reply::keyword_matcher::KeywordMatcher;
59use crate::auto_reply::message::{IncomingMessage, RejectionReason, TriggerContext, TriggerResult};
60use crate::auto_reply::registry::{AutoReplyTrigger, TriggerRegistry};
61use crate::auto_reply::types::{TriggerConfig, TriggerType};
62use crate::auto_reply::whitelist::WhitelistManager;
63
64#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
75pub struct AutoReplyStats {
76 pub total_triggers: usize,
78 pub enabled_triggers: usize,
80 pub whitelist_size: usize,
82 pub group_activations: usize,
84}
85
86pub struct AutoReplyManager {
99 registry: TriggerRegistry,
101 whitelist: WhitelistManager,
103 cooldown: CooldownTracker,
105 keyword_matcher: KeywordMatcher,
107 group_activations: HashMap<String, GroupActivation>,
109 config_path: PathBuf,
111}
112
113impl AutoReplyManager {
114 pub async fn new(config_path: PathBuf) -> Result<Self> {
124 Ok(Self {
125 registry: TriggerRegistry::new(),
126 whitelist: WhitelistManager::new(),
127 cooldown: CooldownTracker::new(Duration::from_secs(60)),
128 keyword_matcher: KeywordMatcher::new(),
129 group_activations: HashMap::new(),
130 config_path,
131 })
132 }
133
134 pub fn should_reply(&mut self, message: &IncomingMessage) -> TriggerResult {
169 if !self.check_whitelist(message) {
173 return TriggerResult::Rejected {
174 reason: RejectionReason::NotInWhitelist,
175 };
176 }
177
178 if let Some(group_id) = &message.group_id {
181 if let Some(rejection) = self.check_group_activation(group_id, message.mentions_bot) {
182 return TriggerResult::Rejected { reason: rejection };
183 }
184 }
185
186 let enabled_triggers: Vec<AutoReplyTrigger> = self
190 .registry
191 .get_enabled_triggers()
192 .into_iter()
193 .cloned()
194 .collect();
195
196 for trigger in enabled_triggers {
200 if let Some(match_result) = self.evaluate_trigger(&trigger, message) {
201 match self.check_cooldown(message, trigger.trigger_type) {
205 CooldownCheckResult::Allowed => {
206 self.cooldown.record_trigger(&message.sender_id);
208
209 let context = TriggerContext {
212 trigger_id: trigger.id.clone(),
213 trigger_type: trigger.trigger_type,
214 message: message.clone(),
215 match_details: match_result,
216 triggered_at: Utc::now(),
217 extra: HashMap::new(),
218 };
219
220 return TriggerResult::Triggered {
221 trigger: Box::new(trigger),
222 context: Box::new(context),
223 };
224 }
225 CooldownCheckResult::InCooldown { remaining } => {
226 return TriggerResult::Rejected {
228 reason: RejectionReason::InCooldown { remaining },
229 };
230 }
231 }
232 }
233 }
234
235 TriggerResult::NoMatch
238 }
239
240 fn check_whitelist(&self, message: &IncomingMessage) -> bool {
247 if let Some(group_id) = &message.group_id {
249 if let Some(activation) = self.group_activations.get(group_id) {
250 if let Some(is_allowed) = activation.is_user_whitelisted(&message.sender_id) {
252 return is_allowed;
253 }
254 }
255 }
256
257 self.whitelist.is_allowed(&message.sender_id)
259 }
260
261 fn check_group_activation(
265 &self,
266 group_id: &str,
267 mentions_bot: bool,
268 ) -> Option<RejectionReason> {
269 if let Some(activation) = self.group_activations.get(group_id) {
270 if !activation.enabled {
272 return Some(RejectionReason::GroupNotActivated);
273 }
274
275 if activation.require_mention && !mentions_bot {
277 return Some(RejectionReason::RequiresMention);
278 }
279 }
280
281 None
282 }
283
284 fn check_cooldown(
288 &self,
289 message: &IncomingMessage,
290 trigger_type: TriggerType,
291 ) -> CooldownCheckResult {
292 if let Some(group_id) = &message.group_id {
294 if let Some(activation) = self.group_activations.get(group_id) {
295 if let Some(cooldown_seconds) = activation.cooldown_seconds {
296 let cooldown = Duration::from_secs(cooldown_seconds);
298 return self.check_cooldown_with_duration(&message.sender_id, cooldown);
299 }
300 }
301 }
302
303 self.cooldown
305 .check_cooldown(&message.sender_id, trigger_type)
306 }
307
308 fn check_cooldown_with_duration(
313 &self,
314 user_id: &str,
315 _cooldown: Duration,
316 ) -> CooldownCheckResult {
317 self.cooldown.check_cooldown(user_id, TriggerType::Mention)
323 }
324
325 fn evaluate_trigger(
331 &mut self,
332 trigger: &AutoReplyTrigger,
333 message: &IncomingMessage,
334 ) -> Option<Option<crate::auto_reply::keyword_matcher::KeywordMatchResult>> {
335 if !trigger.enabled {
337 return None;
338 }
339
340 match trigger.trigger_type {
341 TriggerType::Mention => {
342 if message.mentions_bot {
344 Some(None)
345 } else {
346 None
347 }
348 }
349 TriggerType::Keyword => {
350 if let TriggerConfig::Keyword(config) = &trigger.config {
352 self.keyword_matcher
353 .match_message(&message.content, config)
354 .map(Some)
355 } else {
356 None
357 }
358 }
359 TriggerType::DirectMessage => {
360 if message.is_direct_message {
362 Some(None)
363 } else {
364 None
365 }
366 }
367 TriggerType::Schedule => {
368 None
371 }
372 TriggerType::Webhook => {
373 None
376 }
377 }
378 }
379
380 pub fn register_trigger(&mut self, trigger: AutoReplyTrigger) {
386 self.registry.register(trigger);
387 }
388
389 pub fn unregister_trigger(&mut self, trigger_id: &str) -> Option<AutoReplyTrigger> {
399 self.registry.unregister(trigger_id)
400 }
401
402 pub fn set_group_activation(&mut self, activation: GroupActivation) {
408 self.group_activations
409 .insert(activation.group_id.clone(), activation);
410 }
411
412 pub fn get_group_activation(&self, group_id: &str) -> Option<&GroupActivation> {
422 self.group_activations.get(group_id)
423 }
424
425 pub fn remove_group_activation(&mut self, group_id: &str) -> Option<GroupActivation> {
435 self.group_activations.remove(group_id)
436 }
437
438 pub fn add_to_whitelist(&mut self, user_id: String) {
444 self.whitelist.add_user(user_id);
445 }
446
447 pub fn remove_from_whitelist(&mut self, user_id: &str) -> bool {
457 self.whitelist.remove_user(user_id)
458 }
459
460 pub fn is_user_whitelisted(&self, user_id: &str) -> bool {
470 self.whitelist.is_allowed(user_id)
471 }
472
473 pub fn set_default_cooldown(&mut self, duration: Duration) {
479 self.cooldown = CooldownTracker::new(duration);
480 }
481
482 pub fn set_type_cooldown(&mut self, trigger_type: TriggerType, duration: Duration) {
489 self.cooldown.set_type_cooldown(trigger_type, duration);
490 }
491
492 pub fn reset_user_cooldown(&mut self, user_id: &str) {
498 self.cooldown.reset_cooldown(user_id);
499 }
500
501 pub fn config_path(&self) -> &PathBuf {
503 &self.config_path
504 }
505
506 pub async fn save_config(&self) -> Result<()> {
510 Ok(())
512 }
513
514 pub async fn reload_config(&mut self) -> Result<()> {
518 Ok(())
520 }
521
522 pub fn get_stats(&self) -> AutoReplyStats {
544 let all_triggers = self.registry.get_all_triggers();
545 let enabled_count = all_triggers.iter().filter(|t| t.enabled).count();
546
547 AutoReplyStats {
548 total_triggers: all_triggers.len(),
549 enabled_triggers: enabled_count,
550 whitelist_size: self.whitelist.len(),
551 group_activations: self.group_activations.len(),
552 }
553 }
554}
555
556#[cfg(test)]
557mod tests {
558 use super::*;
559 use crate::auto_reply::types::KeywordTriggerConfig;
560
561 fn create_test_message(
563 sender_id: &str,
564 content: &str,
565 is_dm: bool,
566 mentions_bot: bool,
567 group_id: Option<&str>,
568 ) -> IncomingMessage {
569 IncomingMessage {
570 id: "msg-1".to_string(),
571 sender_id: sender_id.to_string(),
572 sender_name: Some("Test User".to_string()),
573 content: content.to_string(),
574 channel: "test".to_string(),
575 group_id: group_id.map(String::from),
576 is_direct_message: is_dm,
577 mentions_bot,
578 timestamp: Utc::now(),
579 metadata: HashMap::new(),
580 }
581 }
582
583 fn create_mention_trigger(id: &str, priority: u32) -> AutoReplyTrigger {
585 AutoReplyTrigger {
586 id: id.to_string(),
587 name: format!("Mention Trigger {}", id),
588 enabled: true,
589 trigger_type: TriggerType::Mention,
590 config: TriggerConfig::Mention,
591 priority,
592 response_template: None,
593 }
594 }
595
596 fn create_keyword_trigger(id: &str, patterns: Vec<&str>, priority: u32) -> AutoReplyTrigger {
598 AutoReplyTrigger {
599 id: id.to_string(),
600 name: format!("Keyword Trigger {}", id),
601 enabled: true,
602 trigger_type: TriggerType::Keyword,
603 config: TriggerConfig::Keyword(KeywordTriggerConfig {
604 patterns: patterns.into_iter().map(String::from).collect(),
605 case_insensitive: false,
606 use_regex: false,
607 }),
608 priority,
609 response_template: None,
610 }
611 }
612
613 fn create_dm_trigger(id: &str, priority: u32) -> AutoReplyTrigger {
615 AutoReplyTrigger {
616 id: id.to_string(),
617 name: format!("DM Trigger {}", id),
618 enabled: true,
619 trigger_type: TriggerType::DirectMessage,
620 config: TriggerConfig::DirectMessage,
621 priority,
622 response_template: None,
623 }
624 }
625
626 #[tokio::test]
632 async fn test_new_manager() {
633 let manager = AutoReplyManager::new(PathBuf::from("test.json"))
634 .await
635 .unwrap();
636
637 assert!(manager.config_path().ends_with("test.json"));
638 }
639
640 #[tokio::test]
643 async fn test_no_triggers_returns_no_match() {
644 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
645 .await
646 .unwrap();
647
648 let message = create_test_message("user1", "hello", false, false, None);
649 let result = manager.should_reply(&message);
650
651 assert!(matches!(result, TriggerResult::NoMatch));
652 }
653
654 #[tokio::test]
657 async fn test_mention_trigger_matches() {
658 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
659 .await
660 .unwrap();
661
662 manager.register_trigger(create_mention_trigger("mention-1", 10));
663
664 let message = create_test_message("user1", "hello @bot", false, true, None);
666 let result = manager.should_reply(&message);
667
668 match result {
669 TriggerResult::Triggered { trigger, context } => {
670 assert_eq!(trigger.id, "mention-1");
671 assert_eq!(context.trigger_type, TriggerType::Mention);
672 }
673 _ => panic!("Expected Triggered result"),
674 }
675 }
676
677 #[tokio::test]
679 async fn test_mention_trigger_no_match() {
680 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
681 .await
682 .unwrap();
683
684 manager.register_trigger(create_mention_trigger("mention-1", 10));
685
686 let message = create_test_message("user1", "hello", false, false, None);
688 let result = manager.should_reply(&message);
689
690 assert!(matches!(result, TriggerResult::NoMatch));
691 }
692
693 #[tokio::test]
696 async fn test_keyword_trigger_matches() {
697 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
698 .await
699 .unwrap();
700
701 manager.register_trigger(create_keyword_trigger("kw-1", vec!["help", "帮助"], 10));
702
703 let message = create_test_message("user1", "I need help", false, false, None);
705 let result = manager.should_reply(&message);
706
707 match result {
708 TriggerResult::Triggered { trigger, context } => {
709 assert_eq!(trigger.id, "kw-1");
710 assert_eq!(context.trigger_type, TriggerType::Keyword);
711 assert!(context.match_details.is_some());
712 assert_eq!(context.match_details.unwrap().matched_pattern, "help");
713 }
714 _ => panic!("Expected Triggered result"),
715 }
716 }
717
718 #[tokio::test]
720 async fn test_dm_trigger_matches() {
721 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
722 .await
723 .unwrap();
724
725 manager.register_trigger(create_dm_trigger("dm-1", 10));
726
727 let message = create_test_message("user1", "hello", true, false, None);
729 let result = manager.should_reply(&message);
730
731 match result {
732 TriggerResult::Triggered { trigger, context } => {
733 assert_eq!(trigger.id, "dm-1");
734 assert_eq!(context.trigger_type, TriggerType::DirectMessage);
735 }
736 _ => panic!("Expected Triggered result"),
737 }
738 }
739
740 #[tokio::test]
743 async fn test_multiple_triggers_priority() {
744 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
745 .await
746 .unwrap();
747
748 manager.register_trigger(create_mention_trigger("mention-low", 100));
750 manager.register_trigger(create_mention_trigger("mention-high", 10));
751 manager.register_trigger(create_mention_trigger("mention-mid", 50));
752
753 let message = create_test_message("user1", "hello @bot", false, true, None);
755 let result = manager.should_reply(&message);
756
757 match result {
758 TriggerResult::Triggered { trigger, .. } => {
759 assert_eq!(trigger.id, "mention-high");
760 assert_eq!(trigger.priority, 10);
761 }
762 _ => panic!("Expected Triggered result"),
763 }
764 }
765
766 #[tokio::test]
769 async fn test_whitelist_rejection() {
770 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
771 .await
772 .unwrap();
773
774 manager.register_trigger(create_mention_trigger("mention-1", 10));
775
776 manager.add_to_whitelist("allowed_user".to_string());
778
779 let message = create_test_message("other_user", "hello @bot", false, true, None);
781 let result = manager.should_reply(&message);
782
783 match result {
784 TriggerResult::Rejected { reason } => {
785 assert!(matches!(reason, RejectionReason::NotInWhitelist));
786 }
787 _ => panic!("Expected Rejected result with NotInWhitelist"),
788 }
789 }
790
791 #[tokio::test]
793 async fn test_whitelist_allowed() {
794 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
795 .await
796 .unwrap();
797
798 manager.register_trigger(create_mention_trigger("mention-1", 10));
799
800 manager.add_to_whitelist("allowed_user".to_string());
802
803 let message = create_test_message("allowed_user", "hello @bot", false, true, None);
805 let result = manager.should_reply(&message);
806
807 assert!(matches!(result, TriggerResult::Triggered { .. }));
808 }
809
810 #[tokio::test]
812 async fn test_empty_whitelist_allows_all() {
813 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
814 .await
815 .unwrap();
816
817 manager.register_trigger(create_mention_trigger("mention-1", 10));
818
819 let message = create_test_message("any_user", "hello @bot", false, true, None);
821 let result = manager.should_reply(&message);
822
823 assert!(matches!(result, TriggerResult::Triggered { .. }));
824 }
825
826 #[tokio::test]
829 async fn test_group_disabled_rejection() {
830 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
831 .await
832 .unwrap();
833
834 manager.register_trigger(create_mention_trigger("mention-1", 10));
835
836 manager.set_group_activation(GroupActivation::disabled("group-123"));
838
839 let message = create_test_message("user1", "hello @bot", false, true, Some("group-123"));
841 let result = manager.should_reply(&message);
842
843 match result {
844 TriggerResult::Rejected { reason } => {
845 assert!(matches!(reason, RejectionReason::GroupNotActivated));
846 }
847 _ => panic!("Expected Rejected result with GroupNotActivated"),
848 }
849 }
850
851 #[tokio::test]
854 async fn test_group_require_mention() {
855 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
856 .await
857 .unwrap();
858
859 manager.register_trigger(create_keyword_trigger("kw-1", vec!["help"], 10));
860
861 manager.set_group_activation(GroupActivation::new("group-123").with_require_mention(true));
863
864 let message = create_test_message("user1", "help", false, false, Some("group-123"));
866 let result = manager.should_reply(&message);
867
868 match result {
869 TriggerResult::Rejected { reason } => {
870 assert!(matches!(reason, RejectionReason::RequiresMention));
871 }
872 _ => panic!("Expected Rejected result with RequiresMention"),
873 }
874
875 let message_with_mention =
877 create_test_message("user1", "help @bot", false, true, Some("group-123"));
878 let result = manager.should_reply(&message_with_mention);
879
880 assert!(matches!(result, TriggerResult::Triggered { .. }));
883 }
884
885 #[tokio::test]
888 async fn test_group_specific_whitelist() {
889 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
890 .await
891 .unwrap();
892
893 manager.register_trigger(create_mention_trigger("mention-1", 10));
894
895 manager.set_group_activation(
897 GroupActivation::new("group-123").with_whitelist(vec!["group_user".to_string()]),
898 );
899
900 let message =
902 create_test_message("other_user", "hello @bot", false, true, Some("group-123"));
903 let result = manager.should_reply(&message);
904
905 match result {
906 TriggerResult::Rejected { reason } => {
907 assert!(matches!(reason, RejectionReason::NotInWhitelist));
908 }
909 _ => panic!("Expected Rejected result with NotInWhitelist"),
910 }
911
912 let message_allowed =
914 create_test_message("group_user", "hello @bot", false, true, Some("group-123"));
915 let result = manager.should_reply(&message_allowed);
916
917 assert!(matches!(result, TriggerResult::Triggered { .. }));
918 }
919
920 #[tokio::test]
923 async fn test_cooldown_rejection() {
924 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
925 .await
926 .unwrap();
927
928 manager.register_trigger(create_mention_trigger("mention-1", 10));
929
930 let message1 = create_test_message("user1", "hello @bot", false, true, None);
932 let result1 = manager.should_reply(&message1);
933 assert!(matches!(result1, TriggerResult::Triggered { .. }));
934
935 let message2 = create_test_message("user1", "hello again @bot", false, true, None);
937 let result2 = manager.should_reply(&message2);
938
939 match result2 {
940 TriggerResult::Rejected { reason } => match reason {
941 RejectionReason::InCooldown { remaining } => {
942 assert!(remaining > Duration::ZERO);
943 }
944 _ => panic!("Expected InCooldown rejection"),
945 },
946 _ => panic!("Expected Rejected result"),
947 }
948 }
949
950 #[tokio::test]
952 async fn test_independent_user_cooldowns() {
953 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
954 .await
955 .unwrap();
956
957 manager.register_trigger(create_mention_trigger("mention-1", 10));
958
959 let message1 = create_test_message("user1", "hello @bot", false, true, None);
961 let result1 = manager.should_reply(&message1);
962 assert!(matches!(result1, TriggerResult::Triggered { .. }));
963
964 let message2 = create_test_message("user2", "hello @bot", false, true, None);
966 let result2 = manager.should_reply(&message2);
967 assert!(matches!(result2, TriggerResult::Triggered { .. }));
968 }
969
970 #[tokio::test]
972 async fn test_reset_user_cooldown() {
973 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
974 .await
975 .unwrap();
976
977 manager.register_trigger(create_mention_trigger("mention-1", 10));
978
979 let message1 = create_test_message("user1", "hello @bot", false, true, None);
981 let _ = manager.should_reply(&message1);
982
983 manager.reset_user_cooldown("user1");
985
986 let message2 = create_test_message("user1", "hello again @bot", false, true, None);
988 let result2 = manager.should_reply(&message2);
989 assert!(matches!(result2, TriggerResult::Triggered { .. }));
990 }
991
992 #[tokio::test]
997 async fn test_register_and_unregister_trigger() {
998 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
999 .await
1000 .unwrap();
1001
1002 let trigger = create_mention_trigger("test-trigger", 10);
1003 manager.register_trigger(trigger);
1004
1005 let removed = manager.unregister_trigger("test-trigger");
1007 assert!(removed.is_some());
1008 assert_eq!(removed.unwrap().id, "test-trigger");
1009
1010 let removed_again = manager.unregister_trigger("test-trigger");
1012 assert!(removed_again.is_none());
1013 }
1014
1015 #[tokio::test]
1016 async fn test_group_activation_management() {
1017 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
1018 .await
1019 .unwrap();
1020
1021 manager.set_group_activation(GroupActivation::new("group-1").with_require_mention(true));
1023
1024 let activation = manager.get_group_activation("group-1");
1026 assert!(activation.is_some());
1027 assert!(activation.unwrap().require_mention);
1028
1029 let removed = manager.remove_group_activation("group-1");
1031 assert!(removed.is_some());
1032
1033 assert!(manager.get_group_activation("group-1").is_none());
1035 }
1036
1037 #[tokio::test]
1038 async fn test_whitelist_management() {
1039 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
1040 .await
1041 .unwrap();
1042
1043 assert!(manager.is_user_whitelisted("any_user"));
1045
1046 manager.add_to_whitelist("user1".to_string());
1048 assert!(manager.is_user_whitelisted("user1"));
1049 assert!(!manager.is_user_whitelisted("user2"));
1050
1051 assert!(manager.remove_from_whitelist("user1"));
1053 assert!(manager.is_user_whitelisted("user1")); }
1055
1056 #[tokio::test]
1057 async fn test_cooldown_settings() {
1058 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
1059 .await
1060 .unwrap();
1061
1062 manager.set_default_cooldown(Duration::from_secs(120));
1064
1065 manager.set_type_cooldown(TriggerType::Mention, Duration::from_secs(30));
1067 }
1068
1069 #[tokio::test]
1075 async fn test_get_stats_empty_manager() {
1076 let manager = AutoReplyManager::new(PathBuf::from("test.json"))
1077 .await
1078 .unwrap();
1079
1080 let stats = manager.get_stats();
1081
1082 assert_eq!(stats.total_triggers, 0);
1083 assert_eq!(stats.enabled_triggers, 0);
1084 assert_eq!(stats.whitelist_size, 0);
1085 assert_eq!(stats.group_activations, 0);
1086 }
1087
1088 #[tokio::test]
1090 async fn test_get_stats_with_triggers() {
1091 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
1092 .await
1093 .unwrap();
1094
1095 manager.register_trigger(create_mention_trigger("t1", 10));
1097 manager.register_trigger(create_keyword_trigger("t2", vec!["help"], 20));
1098
1099 let mut disabled_trigger = create_dm_trigger("t3", 30);
1101 disabled_trigger.enabled = false;
1102 manager.register_trigger(disabled_trigger);
1103
1104 let stats = manager.get_stats();
1105
1106 assert_eq!(stats.total_triggers, 3);
1107 assert_eq!(stats.enabled_triggers, 2);
1108 }
1109
1110 #[tokio::test]
1112 async fn test_get_stats_with_whitelist() {
1113 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
1114 .await
1115 .unwrap();
1116
1117 manager.add_to_whitelist("user1".to_string());
1118 manager.add_to_whitelist("user2".to_string());
1119 manager.add_to_whitelist("user3".to_string());
1120
1121 let stats = manager.get_stats();
1122
1123 assert_eq!(stats.whitelist_size, 3);
1124 }
1125
1126 #[tokio::test]
1128 async fn test_get_stats_with_group_activations() {
1129 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
1130 .await
1131 .unwrap();
1132
1133 manager.set_group_activation(GroupActivation::new("group-1"));
1134 manager.set_group_activation(GroupActivation::new("group-2"));
1135
1136 let stats = manager.get_stats();
1137
1138 assert_eq!(stats.group_activations, 2);
1139 }
1140
1141 #[tokio::test]
1143 async fn test_get_stats_complete() {
1144 let mut manager = AutoReplyManager::new(PathBuf::from("test.json"))
1145 .await
1146 .unwrap();
1147
1148 manager.register_trigger(create_mention_trigger("t1", 10));
1150 manager.register_trigger(create_keyword_trigger("t2", vec!["help"], 20));
1151 let mut disabled = create_dm_trigger("t3", 30);
1152 disabled.enabled = false;
1153 manager.register_trigger(disabled);
1154
1155 manager.add_to_whitelist("user1".to_string());
1157 manager.add_to_whitelist("user2".to_string());
1158
1159 manager.set_group_activation(GroupActivation::new("group-1"));
1161 manager.set_group_activation(GroupActivation::new("group-2"));
1162 manager.set_group_activation(GroupActivation::new("group-3"));
1163
1164 let stats = manager.get_stats();
1165
1166 assert_eq!(stats.total_triggers, 3);
1167 assert_eq!(stats.enabled_triggers, 2);
1168 assert_eq!(stats.whitelist_size, 2);
1169 assert_eq!(stats.group_activations, 3);
1170 }
1171}