Skip to main content

aster/auto_reply/
whitelist.rs

1//! 白名单管理器
2//!
3//! 管理允许触发自动回复的用户列表。
4//!
5//! # 功能
6//!
7//! - 维护允许触发自动回复的用户 ID 集合
8//! - 空白名单时允许所有用户(禁用白名单检查)
9//! - 非空白名单时只允许白名单中的用户
10//! - 支持动态添加/移除用户
11//!
12//! # 示例
13//!
14//! ```rust
15//! use aster::auto_reply::WhitelistManager;
16//!
17//! // 创建空白名单(允许所有用户)
18//! let mut whitelist = WhitelistManager::new();
19//! assert!(whitelist.is_allowed("any_user"));
20//!
21//! // 添加用户后,只允许白名单中的用户
22//! whitelist.add_user("user1".to_string());
23//! assert!(whitelist.is_allowed("user1"));
24//! assert!(!whitelist.is_allowed("user2"));
25//!
26//! // 清空白名单后,再次允许所有用户
27//! whitelist.clear();
28//! assert!(whitelist.is_allowed("any_user"));
29//! ```
30
31use std::collections::HashSet;
32
33/// 白名单管理器
34///
35/// 管理允许触发自动回复的用户列表。
36/// 当白名单为空时,所有用户都被允许(相当于禁用白名单检查)。
37/// 当白名单非空时,只有白名单中的用户才被允许。
38#[derive(Debug, Clone)]
39pub struct WhitelistManager {
40    /// 允许的用户 ID 集合
41    allowed_users: HashSet<String>,
42}
43
44impl Default for WhitelistManager {
45    fn default() -> Self {
46        Self::new()
47    }
48}
49
50impl WhitelistManager {
51    /// 创建新的白名单管理器
52    ///
53    /// 创建一个空的白名单,此时所有用户都被允许。
54    ///
55    /// # 示例
56    ///
57    /// ```rust
58    /// use aster::auto_reply::WhitelistManager;
59    ///
60    /// let whitelist = WhitelistManager::new();
61    /// assert!(whitelist.is_allowed("any_user"));
62    /// ```
63    pub fn new() -> Self {
64        Self {
65            allowed_users: HashSet::new(),
66        }
67    }
68
69    /// 从用户列表创建白名单管理器
70    ///
71    /// # 参数
72    ///
73    /// * `users` - 初始白名单用户 ID 列表
74    ///
75    /// # 示例
76    ///
77    /// ```rust
78    /// use aster::auto_reply::WhitelistManager;
79    ///
80    /// let whitelist = WhitelistManager::from_users(vec![
81    ///     "user1".to_string(),
82    ///     "user2".to_string(),
83    /// ]);
84    /// assert!(whitelist.is_allowed("user1"));
85    /// assert!(!whitelist.is_allowed("user3"));
86    /// ```
87    pub fn from_users(users: Vec<String>) -> Self {
88        Self {
89            allowed_users: users.into_iter().collect(),
90        }
91    }
92
93    /// 检查用户是否在白名单中
94    ///
95    /// 当白名单为空时,所有用户都被允许。
96    /// 当白名单非空时,只有白名单中的用户才被允许。
97    ///
98    /// # 参数
99    ///
100    /// * `user_id` - 要检查的用户 ID
101    ///
102    /// # 返回值
103    ///
104    /// 如果用户被允许则返回 `true`,否则返回 `false`。
105    ///
106    /// # 示例
107    ///
108    /// ```rust
109    /// use aster::auto_reply::WhitelistManager;
110    ///
111    /// let mut whitelist = WhitelistManager::new();
112    ///
113    /// // 空白名单时允许所有用户
114    /// assert!(whitelist.is_allowed("any_user"));
115    ///
116    /// // 添加用户后只允许白名单中的用户
117    /// whitelist.add_user("allowed_user".to_string());
118    /// assert!(whitelist.is_allowed("allowed_user"));
119    /// assert!(!whitelist.is_allowed("other_user"));
120    /// ```
121    pub fn is_allowed(&self, user_id: &str) -> bool {
122        self.allowed_users.is_empty() || self.allowed_users.contains(user_id)
123    }
124
125    /// 检查白名单是否启用
126    ///
127    /// 当白名单非空时,白名单检查被启用。
128    ///
129    /// # 返回值
130    ///
131    /// 如果白名单非空则返回 `true`,否则返回 `false`。
132    pub fn is_enabled(&self) -> bool {
133        !self.allowed_users.is_empty()
134    }
135
136    /// 添加用户到白名单
137    ///
138    /// # 参数
139    ///
140    /// * `user_id` - 要添加的用户 ID
141    ///
142    /// # 示例
143    ///
144    /// ```rust
145    /// use aster::auto_reply::WhitelistManager;
146    ///
147    /// let mut whitelist = WhitelistManager::new();
148    /// whitelist.add_user("user1".to_string());
149    /// assert!(whitelist.is_allowed("user1"));
150    /// ```
151    pub fn add_user(&mut self, user_id: String) {
152        self.allowed_users.insert(user_id);
153    }
154
155    /// 从白名单移除用户
156    ///
157    /// # 参数
158    ///
159    /// * `user_id` - 要移除的用户 ID
160    ///
161    /// # 返回值
162    ///
163    /// 如果用户存在并被移除则返回 `true`,否则返回 `false`。
164    ///
165    /// # 示例
166    ///
167    /// ```rust
168    /// use aster::auto_reply::WhitelistManager;
169    ///
170    /// let mut whitelist = WhitelistManager::from_users(vec!["user1".to_string()]);
171    /// assert!(whitelist.remove_user("user1"));
172    /// assert!(!whitelist.remove_user("user1")); // 已经移除
173    /// ```
174    pub fn remove_user(&mut self, user_id: &str) -> bool {
175        self.allowed_users.remove(user_id)
176    }
177
178    /// 获取所有白名单用户
179    ///
180    /// # 返回值
181    ///
182    /// 返回白名单中所有用户 ID 的引用列表。
183    ///
184    /// # 示例
185    ///
186    /// ```rust
187    /// use aster::auto_reply::WhitelistManager;
188    ///
189    /// let whitelist = WhitelistManager::from_users(vec![
190    ///     "user1".to_string(),
191    ///     "user2".to_string(),
192    /// ]);
193    /// let users = whitelist.list_users();
194    /// assert_eq!(users.len(), 2);
195    /// ```
196    pub fn list_users(&self) -> Vec<&String> {
197        self.allowed_users.iter().collect()
198    }
199
200    /// 获取白名单用户数量
201    ///
202    /// # 返回值
203    ///
204    /// 返回白名单中的用户数量。
205    pub fn len(&self) -> usize {
206        self.allowed_users.len()
207    }
208
209    /// 检查白名单是否为空
210    ///
211    /// # 返回值
212    ///
213    /// 如果白名单为空则返回 `true`,否则返回 `false`。
214    pub fn is_empty(&self) -> bool {
215        self.allowed_users.is_empty()
216    }
217
218    /// 清空白名单
219    ///
220    /// 清空后所有用户都将被允许。
221    ///
222    /// # 示例
223    ///
224    /// ```rust
225    /// use aster::auto_reply::WhitelistManager;
226    ///
227    /// let mut whitelist = WhitelistManager::from_users(vec!["user1".to_string()]);
228    /// assert!(!whitelist.is_allowed("user2"));
229    ///
230    /// whitelist.clear();
231    /// assert!(whitelist.is_allowed("user2")); // 清空后允许所有用户
232    /// ```
233    pub fn clear(&mut self) {
234        self.allowed_users.clear();
235    }
236}
237
238#[cfg(test)]
239mod tests {
240    use super::*;
241    use proptest::prelude::*;
242
243    // ============================================================================
244    // Property-Based Tests
245    // ============================================================================
246    // Feature: auto-reply-mechanism, Property 3: 白名单操作一致性
247    // **Validates: Requirements 3.1-3.6**
248
249    /// 白名单操作类型
250    #[derive(Debug, Clone)]
251    enum WhitelistOp {
252        Add(String),
253        Remove(String),
254        Clear,
255    }
256
257    /// 生成有效的用户 ID
258    fn arb_user_id() -> impl Strategy<Value = String> {
259        "[a-zA-Z0-9_]{1,20}".prop_map(|s| s)
260    }
261
262    /// 生成白名单操作
263    fn arb_whitelist_op() -> impl Strategy<Value = WhitelistOp> {
264        prop_oneof![
265            arb_user_id().prop_map(WhitelistOp::Add),
266            arb_user_id().prop_map(WhitelistOp::Remove),
267            Just(WhitelistOp::Clear),
268        ]
269    }
270
271    /// 生成操作序列
272    fn arb_op_sequence() -> impl Strategy<Value = Vec<WhitelistOp>> {
273        prop::collection::vec(arb_whitelist_op(), 0..50)
274    }
275
276    /// 应用操作到白名单,返回预期的用户集合
277    fn apply_ops_to_set(ops: &[WhitelistOp]) -> std::collections::HashSet<String> {
278        let mut set = std::collections::HashSet::new();
279        for op in ops {
280            match op {
281                WhitelistOp::Add(user_id) => {
282                    set.insert(user_id.clone());
283                }
284                WhitelistOp::Remove(user_id) => {
285                    set.remove(user_id);
286                }
287                WhitelistOp::Clear => {
288                    set.clear();
289                }
290            }
291        }
292        set
293    }
294
295    /// 应用操作到 WhitelistManager
296    fn apply_ops_to_whitelist(whitelist: &mut WhitelistManager, ops: &[WhitelistOp]) {
297        for op in ops {
298            match op {
299                WhitelistOp::Add(user_id) => {
300                    whitelist.add_user(user_id.clone());
301                }
302                WhitelistOp::Remove(user_id) => {
303                    whitelist.remove_user(user_id);
304                }
305                WhitelistOp::Clear => {
306                    whitelist.clear();
307                }
308            }
309        }
310    }
311
312    proptest! {
313        #![proptest_config(ProptestConfig::with_cases(20))]
314
315        /// Property 3.1: 添加用户后 is_allowed 返回 true
316        /// **Validates: Requirements 3.1, 3.4**
317        #[test]
318        fn prop_add_user_then_allowed(user_id in arb_user_id()) {
319            let mut whitelist = WhitelistManager::new();
320            whitelist.add_user(user_id.clone());
321
322            // 添加后该用户应该被允许
323            prop_assert!(whitelist.is_allowed(&user_id));
324        }
325
326        /// Property 3.2: 空白名单允许所有用户
327        /// **Validates: Requirement 3.2**
328        #[test]
329        fn prop_empty_whitelist_allows_all(user_id in arb_user_id()) {
330            let whitelist = WhitelistManager::new();
331
332            // 空白名单应该允许任何用户
333            prop_assert!(whitelist.is_allowed(&user_id));
334            prop_assert!(whitelist.is_empty());
335        }
336
337        /// Property 3.3: 非空白名单只允许白名单中的用户
338        /// **Validates: Requirement 3.3**
339        #[test]
340        fn prop_non_empty_whitelist_restricts(
341            allowed_user in arb_user_id(),
342            other_user in arb_user_id()
343        ) {
344            // 确保两个用户不同
345            prop_assume!(allowed_user != other_user);
346
347            let whitelist = WhitelistManager::from_users(vec![allowed_user.clone()]);
348
349            // 白名单中的用户应该被允许
350            prop_assert!(whitelist.is_allowed(&allowed_user));
351            // 不在白名单中的用户应该被拒绝
352            prop_assert!(!whitelist.is_allowed(&other_user));
353        }
354
355        /// Property 3.4: 移除用户后 is_allowed 返回 false(如果白名单非空)
356        /// **Validates: Requirements 3.3, 3.5**
357        #[test]
358        fn prop_remove_user_then_not_allowed(
359            user_to_remove in arb_user_id(),
360            other_user in arb_user_id()
361        ) {
362            // 确保两个用户不同
363            prop_assume!(user_to_remove != other_user);
364
365            let mut whitelist = WhitelistManager::from_users(vec![
366                user_to_remove.clone(),
367                other_user.clone(),
368            ]);
369
370            // 移除前应该被允许
371            prop_assert!(whitelist.is_allowed(&user_to_remove));
372
373            // 移除用户
374            whitelist.remove_user(&user_to_remove);
375
376            // 移除后应该不被允许(因为白名单非空)
377            prop_assert!(!whitelist.is_allowed(&user_to_remove));
378            // 其他用户仍然被允许
379            prop_assert!(whitelist.is_allowed(&other_user));
380        }
381
382        /// Property 3.5: 移除最后一个用户后允许所有用户
383        /// **Validates: Requirements 3.2, 3.5**
384        #[test]
385        fn prop_remove_last_user_allows_all(
386            user_id in arb_user_id(),
387            test_user in arb_user_id()
388        ) {
389            let mut whitelist = WhitelistManager::from_users(vec![user_id.clone()]);
390
391            // 移除前,非白名单用户不被允许
392            if user_id != test_user {
393                prop_assert!(!whitelist.is_allowed(&test_user));
394            }
395
396            // 移除最后一个用户
397            whitelist.remove_user(&user_id);
398
399            // 白名单为空后,所有用户都被允许
400            prop_assert!(whitelist.is_empty());
401            prop_assert!(whitelist.is_allowed(&test_user));
402            prop_assert!(whitelist.is_allowed(&user_id));
403        }
404
405        /// Property 3.6: 操作序列与集合语义一致
406        /// **Validates: Requirements 3.1-3.6**
407        #[test]
408        fn prop_operations_consistent_with_set_semantics(
409            ops in arb_op_sequence(),
410            test_users in prop::collection::vec(arb_user_id(), 1..10)
411        ) {
412            let mut whitelist = WhitelistManager::new();
413
414            // 应用操作序列
415            apply_ops_to_whitelist(&mut whitelist, &ops);
416
417            // 计算预期的集合状态
418            let expected_set = apply_ops_to_set(&ops);
419
420            // 验证白名单状态与预期集合一致
421            prop_assert_eq!(whitelist.len(), expected_set.len());
422            prop_assert_eq!(whitelist.is_empty(), expected_set.is_empty());
423
424            // 验证每个测试用户的 is_allowed 结果
425            for user in &test_users {
426                let expected_allowed = expected_set.is_empty() || expected_set.contains(user);
427                prop_assert_eq!(
428                    whitelist.is_allowed(user),
429                    expected_allowed,
430                    "User {} should be {} but was {}",
431                    user,
432                    if expected_allowed { "allowed" } else { "not allowed" },
433                    if whitelist.is_allowed(user) { "allowed" } else { "not allowed" }
434                );
435            }
436        }
437
438        /// Property 3.7: 重复添加用户是幂等的
439        /// **Validates: Requirement 3.4**
440        #[test]
441        fn prop_add_user_idempotent(user_id in arb_user_id(), times in 1usize..10) {
442            let mut whitelist = WhitelistManager::new();
443
444            // 多次添加同一用户
445            for _ in 0..times {
446                whitelist.add_user(user_id.clone());
447            }
448
449            // 用户数量应该是 1
450            prop_assert_eq!(whitelist.len(), 1);
451            // 用户应该被允许
452            prop_assert!(whitelist.is_allowed(&user_id));
453        }
454
455        /// Property 3.8: 移除不存在的用户不影响白名单
456        /// **Validates: Requirement 3.5**
457        #[test]
458        fn prop_remove_nonexistent_user_no_effect(
459            existing_user in arb_user_id(),
460            nonexistent_user in arb_user_id()
461        ) {
462            prop_assume!(existing_user != nonexistent_user);
463
464            let mut whitelist = WhitelistManager::from_users(vec![existing_user.clone()]);
465            let len_before = whitelist.len();
466
467            // 移除不存在的用户
468            let removed = whitelist.remove_user(&nonexistent_user);
469
470            // 应该返回 false
471            prop_assert!(!removed);
472            // 长度不变
473            prop_assert_eq!(whitelist.len(), len_before);
474            // 现有用户仍然被允许
475            prop_assert!(whitelist.is_allowed(&existing_user));
476        }
477
478        /// Property 3.9: 清空后允许所有用户
479        /// **Validates: Requirement 3.2**
480        #[test]
481        fn prop_clear_allows_all(
482            initial_users in prop::collection::vec(arb_user_id(), 1..10),
483            test_user in arb_user_id()
484        ) {
485            let mut whitelist = WhitelistManager::from_users(initial_users);
486
487            // 清空前可能不允许某些用户
488            whitelist.clear();
489
490            // 清空后应该允许所有用户
491            prop_assert!(whitelist.is_empty());
492            prop_assert!(whitelist.is_allowed(&test_user));
493        }
494
495        /// Property 3.10: list_users 返回所有白名单用户
496        /// **Validates: Requirement 3.1, 3.6**
497        #[test]
498        fn prop_list_users_complete(users in prop::collection::hash_set(arb_user_id(), 0..20)) {
499            let users_vec: Vec<String> = users.iter().cloned().collect();
500            let whitelist = WhitelistManager::from_users(users_vec);
501
502            let listed: std::collections::HashSet<&String> = whitelist.list_users().into_iter().collect();
503
504            // 列出的用户数量应该与输入一致
505            prop_assert_eq!(listed.len(), users.len());
506
507            // 每个输入用户都应该在列表中
508            for user in &users {
509                prop_assert!(listed.contains(user));
510            }
511        }
512    }
513
514    // ============================================================================
515    // Unit Tests
516    // ============================================================================
517
518    /// 测试创建空白名单
519    #[test]
520    fn test_new_whitelist_is_empty() {
521        let whitelist = WhitelistManager::new();
522        assert!(whitelist.is_empty());
523        assert!(!whitelist.is_enabled());
524        assert_eq!(whitelist.len(), 0);
525    }
526
527    /// 测试空白名单允许所有用户
528    /// **Validates: Requirement 3.2**
529    #[test]
530    fn test_empty_whitelist_allows_all_users() {
531        let whitelist = WhitelistManager::new();
532        assert!(whitelist.is_allowed("user1"));
533        assert!(whitelist.is_allowed("user2"));
534        assert!(whitelist.is_allowed("any_random_user"));
535    }
536
537    /// 测试从用户列表创建白名单
538    #[test]
539    fn test_from_users() {
540        let whitelist =
541            WhitelistManager::from_users(vec!["user1".to_string(), "user2".to_string()]);
542        assert_eq!(whitelist.len(), 2);
543        assert!(whitelist.is_enabled());
544        assert!(whitelist.is_allowed("user1"));
545        assert!(whitelist.is_allowed("user2"));
546    }
547
548    /// 测试非空白名单只允许白名单中的用户
549    /// **Validates: Requirement 3.3**
550    #[test]
551    fn test_non_empty_whitelist_restricts_users() {
552        let whitelist = WhitelistManager::from_users(vec!["allowed_user".to_string()]);
553        assert!(whitelist.is_allowed("allowed_user"));
554        assert!(!whitelist.is_allowed("other_user"));
555        assert!(!whitelist.is_allowed("random_user"));
556    }
557
558    /// 测试添加用户到白名单
559    /// **Validates: Requirement 3.4**
560    #[test]
561    fn test_add_user() {
562        let mut whitelist = WhitelistManager::new();
563
564        // 添加前允许所有用户
565        assert!(whitelist.is_allowed("user1"));
566        assert!(whitelist.is_allowed("user2"));
567
568        // 添加用户后只允许白名单中的用户
569        whitelist.add_user("user1".to_string());
570        assert!(whitelist.is_allowed("user1"));
571        assert!(!whitelist.is_allowed("user2"));
572
573        // 添加更多用户
574        whitelist.add_user("user2".to_string());
575        assert!(whitelist.is_allowed("user1"));
576        assert!(whitelist.is_allowed("user2"));
577        assert!(!whitelist.is_allowed("user3"));
578    }
579
580    /// 测试从白名单移除用户
581    /// **Validates: Requirement 3.5**
582    #[test]
583    fn test_remove_user() {
584        let mut whitelist =
585            WhitelistManager::from_users(vec!["user1".to_string(), "user2".to_string()]);
586
587        // 移除存在的用户
588        assert!(whitelist.remove_user("user1"));
589        assert!(!whitelist.is_allowed("user1"));
590        assert!(whitelist.is_allowed("user2"));
591
592        // 移除不存在的用户
593        assert!(!whitelist.remove_user("user1"));
594        assert!(!whitelist.remove_user("nonexistent"));
595    }
596
597    /// 测试移除最后一个用户后允许所有用户
598    #[test]
599    fn test_remove_last_user_allows_all() {
600        let mut whitelist = WhitelistManager::from_users(vec!["user1".to_string()]);
601
602        assert!(!whitelist.is_allowed("other_user"));
603
604        whitelist.remove_user("user1");
605
606        // 白名单为空后允许所有用户
607        assert!(whitelist.is_allowed("other_user"));
608        assert!(whitelist.is_allowed("any_user"));
609    }
610
611    /// 测试检查用户是否在白名单中
612    /// **Validates: Requirement 3.6**
613    #[test]
614    fn test_is_allowed() {
615        let whitelist =
616            WhitelistManager::from_users(vec!["user1".to_string(), "user2".to_string()]);
617
618        assert!(whitelist.is_allowed("user1"));
619        assert!(whitelist.is_allowed("user2"));
620        assert!(!whitelist.is_allowed("user3"));
621    }
622
623    /// 测试获取白名单用户列表
624    #[test]
625    fn test_list_users() {
626        let whitelist =
627            WhitelistManager::from_users(vec!["user1".to_string(), "user2".to_string()]);
628
629        let users = whitelist.list_users();
630        assert_eq!(users.len(), 2);
631        assert!(users.contains(&&"user1".to_string()));
632        assert!(users.contains(&&"user2".to_string()));
633    }
634
635    /// 测试清空白名单
636    #[test]
637    fn test_clear() {
638        let mut whitelist =
639            WhitelistManager::from_users(vec!["user1".to_string(), "user2".to_string()]);
640
641        assert!(!whitelist.is_allowed("other_user"));
642
643        whitelist.clear();
644
645        assert!(whitelist.is_empty());
646        assert!(!whitelist.is_enabled());
647        assert!(whitelist.is_allowed("other_user"));
648        assert!(whitelist.is_allowed("any_user"));
649    }
650
651    /// 测试重复添加用户
652    #[test]
653    fn test_add_duplicate_user() {
654        let mut whitelist = WhitelistManager::new();
655
656        whitelist.add_user("user1".to_string());
657        whitelist.add_user("user1".to_string());
658
659        assert_eq!(whitelist.len(), 1);
660        assert!(whitelist.is_allowed("user1"));
661    }
662
663    /// 测试 Default trait
664    #[test]
665    fn test_default() {
666        let whitelist = WhitelistManager::default();
667        assert!(whitelist.is_empty());
668        assert!(whitelist.is_allowed("any_user"));
669    }
670
671    /// 测试 Clone trait
672    #[test]
673    fn test_clone() {
674        let mut original = WhitelistManager::from_users(vec!["user1".to_string()]);
675        let cloned = original.clone();
676
677        // 修改原始不影响克隆
678        original.add_user("user2".to_string());
679
680        assert!(original.is_allowed("user2"));
681        assert!(!cloned.is_allowed("user2"));
682    }
683}