Skip to main content

openlark_core/validation/
core.rs

1//! 核心验证功能
2
3use tracing::warn;
4
5/// 检查字符是否为中文字符
6///
7/// 使用 Unicode 范围检查来识别中文字符
8///
9/// # 参数
10/// - `c`: 要检查的字符
11///
12/// # 返回
13/// true 如果是中文字符,false 否则
14pub fn is_chinese_char(c: char) -> bool {
15    // CJK Unified Ideographs (扩展A-F区)
16    let ranges = [
17        (0x4E00, 0x9FFF),   // CJK Unified Ideographs
18        (0x3400, 0x4DBF),   // CJK Unified Ideographs Extension A
19        (0x20000, 0x2A6DF), // CJK Unified Ideographs Extension B
20        (0x2A700, 0x2B73F), // CJK Unified Ideographs Extension C
21        (0x2B740, 0x2B81F), // CJK Unified Ideographs Extension D
22        (0x2B820, 0x2CEAF), // CJK Unified Ideographs Extension E
23        (0x2CEB0, 0x2EBEF), // CJK Unified Ideographs Extension F
24        (0x3000, 0x303F),   // CJK Symbols and Punctuation
25        (0x31C0, 0x31EF),   // CJK Strokes
26        (0x2F00, 0x2FD5),   // Kangxi Radicals
27        (0x2E80, 0x2EFF),   // CJK Radicals Supplement
28        (0xF900, 0xFAFF),   // CJK Compatibility Ideographs
29        (0x2F800, 0x2FA1F), // CJK Compatibility Ideographs Supplement
30    ];
31
32    let code = c as u32;
33    ranges
34        .iter()
35        .any(|&(start, end)| code >= start && code <= end)
36}
37
38/// 验证字符串长度,如果超过最大长度则截断
39///
40/// # 参数
41/// - `input`: 输入字符串
42/// - `max_len`: 最大长度
43/// - `field_name`: 字段名称(用于日志)
44///
45/// # 返回
46/// 验证后的字符串(可能被截断)
47pub fn validate_string_length(input: String, max_len: usize, field_name: &str) -> String {
48    if input.len() > max_len {
49        warn!(
50            "字段 {} 超过最大长度 {},当前长度 {},将被截断",
51            field_name,
52            max_len,
53            input.len()
54        );
55        // 安全截断,确保不会截断UTF-8字符
56        input.chars().take(max_len).collect()
57    } else {
58        input
59    }
60}
61
62/// 验证必填列表字段
63///
64/// # 参数
65/// - `values`: 列表字段
66/// - `max_len`: 最大长度限制
67/// - `field_name`: 字段名称(用于日志)
68///
69/// # 返回
70/// true 如果字段有效且长度合规,false 否则
71pub fn validate_required_list_length(values: &[String], max_len: usize, field_name: &str) -> bool {
72    if values.is_empty() {
73        warn!("必填列表字段 {} 为空", field_name);
74        false
75    } else if values.len() > max_len {
76        warn!(
77            "必填列表字段 {} 长度 {} 超过最大限制 {}",
78            field_name,
79            values.len(),
80            max_len
81        );
82        false
83    } else {
84        true
85    }
86}
87
88/// 验证内容大小
89///
90/// # 参数
91/// - `content`: 内容
92/// - `max_size`: 最大大小(字节)
93/// - `content_type`: 内容类型(用于日志)
94///
95/// # 返回
96/// true 如果大小有效,false 否则
97pub fn validate_content_size(content: &str, max_size: usize, content_type: &str) -> bool {
98    let content_size = content.len();
99    if content_size > max_size {
100        warn!(
101            "{} 内容大小 {} 超过最大限制 {}",
102            content_type, content_size, max_size
103        );
104        false
105    } else {
106        true
107    }
108}
109
110/// 验证结果
111#[derive(Debug, Clone, PartialEq)]
112pub enum ValidationResult {
113    /// 验证成功
114    Valid,
115    /// 验证失败,附带错误信息
116    Invalid(String),
117    /// 需要清理,附带清理后的值
118    Sanitized(String),
119}
120
121impl ValidationResult {
122    /// 检查验证结果是否有效
123    pub fn is_valid(&self) -> bool {
124        matches!(self, ValidationResult::Valid)
125    }
126
127    /// 获取错误信息(如果有)
128    pub fn error_message(&self) -> Option<&String> {
129        match self {
130            ValidationResult::Invalid(msg) => Some(msg),
131            _ => None,
132        }
133    }
134
135    /// 获取清理后的值(如果有)
136    pub fn sanitized_value(&self) -> Option<&String> {
137        match self {
138            ValidationResult::Sanitized(value) => Some(value),
139            _ => None,
140        }
141    }
142
143    /// 将验证结果转换为结果类型
144    pub fn into_result(self) -> Result<String, String> {
145        match self {
146            ValidationResult::Valid => Ok(String::new()),
147            ValidationResult::Invalid(msg) => Err(msg),
148            ValidationResult::Sanitized(value) => Ok(value),
149        }
150    }
151}
152
153/// 验证构建器特征
154pub trait ValidateBuilder {
155    /// 最终的输出类型
156    type Output;
157
158    /// 添加必填验证
159    fn required(self, value: Option<String>, field_name: &str) -> Self;
160
161    /// 添加长度验证
162    fn length(self, value: String, min_len: usize, max_len: usize, field_name: &str) -> Self;
163
164    /// 添加自定义验证
165    fn custom<F>(self, value: String, validator: F, error_msg: &str) -> Self
166    where
167        F: FnOnce(&str) -> bool;
168
169    /// 执行验证
170    fn validate(&self) -> ValidationResult;
171
172    /// 构建最终结果
173    fn build(self) -> Self::Output;
174}
175
176/// 默认验证构建器实现
177#[derive(Debug)]
178pub struct DefaultValidateBuilder {
179    value: Option<String>,
180    errors: Vec<String>,
181}
182
183impl DefaultValidateBuilder {
184    /// 创建新的验证构建器
185    pub fn new() -> Self {
186        Self {
187            value: None,
188            errors: Vec::new(),
189        }
190    }
191
192    /// 设置初始值
193    pub fn value(mut self, value: String) -> Self {
194        self.value = Some(value);
195        self
196    }
197}
198
199impl ValidateBuilder for DefaultValidateBuilder {
200    type Output = Result<String, Vec<String>>;
201
202    fn required(mut self, value: Option<String>, field_name: &str) -> Self {
203        match value {
204            Some(v) => {
205                if v.trim().is_empty() {
206                    self.errors.push(format!("字段 {} 不能为空", field_name));
207                } else {
208                    self.value = Some(v);
209                }
210            }
211            None => {
212                self.errors.push(format!("字段 {} 不能为空", field_name));
213            }
214        }
215        self
216    }
217
218    fn length(mut self, value: String, min_len: usize, max_len: usize, field_name: &str) -> Self {
219        if value.len() < min_len {
220            self.errors.push(format!(
221                "字段 {} 长度 {} 小于最小长度 {}",
222                field_name,
223                value.len(),
224                min_len
225            ));
226        } else if value.len() > max_len {
227            self.errors.push(format!(
228                "字段 {} 长度 {} 超过最大长度 {}",
229                field_name,
230                value.len(),
231                max_len
232            ));
233        } else {
234            self.value = Some(validate_string_length(value, max_len, field_name));
235        }
236        self
237    }
238
239    fn custom<F>(mut self, value: String, validator: F, error_msg: &str) -> Self
240    where
241        F: FnOnce(&str) -> bool,
242    {
243        if validator(&value) {
244            self.value = Some(value);
245        } else {
246            self.errors.push(error_msg.to_string());
247        }
248        self
249    }
250
251    fn validate(&self) -> ValidationResult {
252        if self.errors.is_empty() {
253            ValidationResult::Valid
254        } else {
255            ValidationResult::Invalid(self.errors.join("; "))
256        }
257    }
258
259    fn build(self) -> Self::Output {
260        if self.errors.is_empty() {
261            Ok(self.value.unwrap_or_default())
262        } else {
263            Err(self.errors)
264        }
265    }
266}
267
268impl Default for DefaultValidateBuilder {
269    fn default() -> Self {
270        Self::new()
271    }
272}
273
274#[cfg(test)]
275mod tests {
276    use super::*;
277
278    #[test]
279    fn test_is_chinese_char() {
280        assert!(is_chinese_char('你'));
281        assert!(is_chinese_char('好'));
282        assert!(is_chinese_char('世'));
283        assert!(is_chinese_char('界'));
284        assert!(!is_chinese_char('a'));
285        assert!(!is_chinese_char('1'));
286        assert!(!is_chinese_char('!'));
287    }
288
289    #[test]
290    fn test_validate_string_length() {
291        let long_string = "这是一个很长的字符串用于测试截断功能".to_string();
292        let result = validate_string_length(long_string.clone(), 10, "测试字段");
293        assert_eq!(result.chars().count(), 10); // 确保字符数正好是10
294        assert!(result.len() <= 30); // 字节数可能更多(UTF-8)
295
296        let short_string = "短".to_string();
297        let result = validate_string_length(short_string, 10, "测试字段");
298        assert_eq!(result, "短");
299    }
300
301    #[test]
302    fn test_validate_content_size() {
303        let content = "这是一个测试内容";
304        assert!(validate_content_size(content, 30, "测试内容")); // 30 > 25字节
305        assert!(!validate_content_size(content, 20, "测试内容")); // 20 < 25字节
306    }
307
308    #[test]
309    fn test_validation_result() {
310        let valid = ValidationResult::Valid;
311        assert!(valid.is_valid());
312        assert_eq!(valid.error_message(), None);
313        assert_eq!(valid.sanitized_value(), None);
314
315        let invalid = ValidationResult::Invalid("错误".to_string());
316        assert!(!invalid.is_valid());
317        assert_eq!(invalid.error_message(), Some(&"错误".to_string()));
318        assert_eq!(invalid.sanitized_value(), None);
319
320        let sanitized = ValidationResult::Sanitized("清理后".to_string());
321        assert!(!sanitized.is_valid());
322        assert_eq!(sanitized.error_message(), None);
323        assert_eq!(sanitized.sanitized_value(), Some(&"清理后".to_string()));
324    }
325
326    #[test]
327    fn test_default_validate_builder() {
328        let builder = DefaultValidateBuilder::new();
329
330        // 成功案例
331        let result = builder
332            .value("测试值".to_string())
333            .length("测试值".to_string(), 1, 10, "测试字段")
334            .build();
335        assert!(result.is_ok());
336
337        // 失败案例
338        let result = DefaultValidateBuilder::new()
339            .value("这是一个很长的测试值".to_string())
340            .length("这是一个很长的测试值".to_string(), 1, 5, "测试字段")
341            .build();
342        assert!(result.is_err());
343    }
344
345    #[test]
346    fn test_is_chinese_char_unicode_boundaries() {
347        let chinese_boundaries = [
348            (0x4E00, 0x9FFF),
349            (0x3400, 0x4DBF),
350            (0x20000, 0x2A6DF),
351            (0x2A700, 0x2B73F),
352            (0x2B740, 0x2B81F),
353            (0x2B820, 0x2CEAF),
354            (0x2CEB0, 0x2EBEF),
355            (0x3000, 0x303F),
356            (0x31C0, 0x31EF),
357            (0x2F00, 0x2FD5),
358            (0x2E80, 0x2EFF),
359            (0xF900, 0xFAFF),
360            (0x2F800, 0x2FA1F),
361        ];
362
363        for (start, end) in chinese_boundaries {
364            let start_char = char::from_u32(start).expect("start must be valid char");
365            let end_char = char::from_u32(end).expect("end must be valid char");
366            assert!(is_chinese_char(start_char));
367            assert!(is_chinese_char(end_char));
368        }
369
370        assert!(!is_chinese_char(
371            char::from_u32(0x4DFF).expect("valid char")
372        ));
373        assert!(!is_chinese_char(
374            char::from_u32(0xA000).expect("valid char")
375        ));
376        assert!(!is_chinese_char('A'));
377        assert!(!is_chinese_char('😀'));
378    }
379
380    #[test]
381    fn test_validate_string_length_utf8_truncation() {
382        let input = "A你😀B".to_string();
383        let result = validate_string_length(input, 3, "utf8字段");
384        assert_eq!(result, "A你😀");
385        assert!(result.is_char_boundary(result.len()));
386
387        let empty_result = validate_string_length("任何值".to_string(), 0, "零长度字段");
388        assert_eq!(empty_result, "");
389
390        let ascii_exact = validate_string_length("abcd".to_string(), 4, "ascii字段");
391        assert_eq!(ascii_exact, "abcd");
392    }
393
394    #[test]
395    fn test_validate_required_list_length_boundaries() {
396        let empty: Vec<String> = vec![];
397        assert!(!validate_required_list_length(&empty, 3, "列表字段"));
398
399        let one = vec!["a".to_string()];
400        assert!(validate_required_list_length(&one, 1, "列表字段"));
401
402        let max = vec!["a".to_string(), "b".to_string(), "c".to_string()];
403        assert!(validate_required_list_length(&max, 3, "列表字段"));
404
405        let overflow = vec![
406            "a".to_string(),
407            "b".to_string(),
408            "c".to_string(),
409            "d".to_string(),
410        ];
411        assert!(!validate_required_list_length(&overflow, 3, "列表字段"));
412
413        let non_empty_when_max_zero = vec!["a".to_string()];
414        assert!(!validate_required_list_length(
415            &non_empty_when_max_zero,
416            0,
417            "列表字段"
418        ));
419    }
420
421    #[test]
422    fn test_validate_content_size_various_sizes() {
423        assert!(validate_content_size("", 0, "空内容"));
424        assert!(!validate_content_size("a", 0, "单字符内容"));
425
426        let ascii = "abcd";
427        assert!(validate_content_size(ascii, 4, "ascii内容"));
428        assert!(!validate_content_size(ascii, 3, "ascii内容"));
429
430        let utf8 = "你a";
431        assert!(validate_content_size(utf8, 4, "utf8内容"));
432        assert!(!validate_content_size(utf8, 3, "utf8内容"));
433
434        let kb_content = "x".repeat(1024);
435        assert!(validate_content_size(&kb_content, 1024, "1KB内容"));
436        assert!(!validate_content_size(&kb_content, 1023, "1KB内容"));
437    }
438
439    #[test]
440    fn test_default_validate_builder_all_methods() {
441        let ok_builder = DefaultValidateBuilder::default()
442            .value("seed".to_string())
443            .required(Some("abc".to_string()), "字段A")
444            .length("abc".to_string(), 1, 10, "字段A")
445            .custom("abc".to_string(), |v| v.contains('b'), "自定义校验失败");
446
447        assert!(ok_builder.validate().is_valid());
448        assert_eq!(ok_builder.build(), Ok("abc".to_string()));
449
450        let required_none = DefaultValidateBuilder::new().required(None, "字段B");
451        assert!(matches!(
452            required_none.validate(),
453            ValidationResult::Invalid(_)
454        ));
455        assert_eq!(
456            required_none.build(),
457            Err(vec!["字段 字段B 不能为空".to_string()])
458        );
459
460        let required_blank =
461            DefaultValidateBuilder::new().required(Some("   ".to_string()), "字段C");
462        assert!(matches!(
463            required_blank.validate(),
464            ValidationResult::Invalid(_)
465        ));
466
467        let length_too_short =
468            DefaultValidateBuilder::new().length("ab".to_string(), 3, 5, "字段D");
469        assert!(matches!(
470            length_too_short.validate(),
471            ValidationResult::Invalid(_)
472        ));
473
474        let length_too_long =
475            DefaultValidateBuilder::new().length("abcdef".to_string(), 1, 5, "字段E");
476        assert!(matches!(
477            length_too_long.validate(),
478            ValidationResult::Invalid(_)
479        ));
480
481        let custom_fail =
482            DefaultValidateBuilder::new().custom("abc".to_string(), |v| v.len() > 10, "必须大于10");
483        assert!(matches!(
484            custom_fail.validate(),
485            ValidationResult::Invalid(_)
486        ));
487    }
488
489    #[test]
490    fn test_validation_result_into_result_variants() {
491        assert_eq!(ValidationResult::Valid.into_result(), Ok(String::new()));
492        assert_eq!(
493            ValidationResult::Sanitized("clean".to_string()).into_result(),
494            Ok("clean".to_string())
495        );
496        assert_eq!(
497            ValidationResult::Invalid("bad".to_string()).into_result(),
498            Err("bad".to_string())
499        );
500    }
501
502    #[test]
503    fn test_validate_string_length_empty_string() {
504        let result = validate_string_length(String::new(), 8, "空字符串字段");
505        assert_eq!(result, "");
506    }
507
508    #[test]
509    fn test_validate_required_list_length_exact_match() {
510        let values = vec!["x".to_string(), "y".to_string()];
511        assert!(validate_required_list_length(&values, 2, "列表字段"));
512    }
513
514    #[test]
515    fn test_validate_content_size_multibyte_edge() {
516        let content = "你";
517        assert!(validate_content_size(content, 3, "中文内容"));
518        assert!(!validate_content_size(content, 2, "中文内容"));
519    }
520
521    #[test]
522    fn test_default_validate_builder_value_only_build() {
523        let result = DefaultValidateBuilder::new()
524            .value("预设值".to_string())
525            .build();
526        assert_eq!(result, Ok("预设值".to_string()));
527    }
528
529    // ===== 新增测试用例,提升覆盖率至 70%+ =====
530
531    #[test]
532    fn test_is_chinese_char_cjk_extension_c_d() {
533        // CJK Unified Ideographs Extension C (0x2A700 - 0x2B73F)
534        assert!(is_chinese_char(char::from_u32(0x2A700).unwrap()));
535        assert!(is_chinese_char(char::from_u32(0x2A800).unwrap()));
536        assert!(is_chinese_char(char::from_u32(0x2B73F).unwrap()));
537
538        // CJK Unified Ideographs Extension D (0x2B740 - 0x2B81F)
539        assert!(is_chinese_char(char::from_u32(0x2B740).unwrap()));
540        assert!(is_chinese_char(char::from_u32(0x2B800).unwrap()));
541        assert!(is_chinese_char(char::from_u32(0x2B81F).unwrap()));
542
543        // 边界外(Extension D之前)
544        assert!(!is_chinese_char(char::from_u32(0x2A6FF).unwrap()));
545    }
546
547    #[test]
548    fn test_is_chinese_char_cjk_extension_e_f() {
549        // CJK Unified Ideographs Extension E (0x2B820 - 0x2CEAF)
550        assert!(is_chinese_char(char::from_u32(0x2B820).unwrap()));
551        assert!(is_chinese_char(char::from_u32(0x2B900).unwrap()));
552        assert!(is_chinese_char(char::from_u32(0x2CEAF).unwrap()));
553
554        // CJK Unified Ideographs Extension F (0x2CEB0 - 0x2EBEF)
555        assert!(is_chinese_char(char::from_u32(0x2CEB0).unwrap()));
556        assert!(is_chinese_char(char::from_u32(0x2D000).unwrap()));
557        assert!(is_chinese_char(char::from_u32(0x2EBEF).unwrap()));
558
559        // 边界外(Extension F之后)
560        assert!(!is_chinese_char(char::from_u32(0x2EBF0).unwrap()));
561    }
562
563    #[test]
564    fn test_is_chinese_char_cjk_symbols_punctuation() {
565        // CJK Symbols and Punctuation (0x3000 - 0x303F)
566        assert!(is_chinese_char(' ')); // 全角空格 0x3000
567        assert!(is_chinese_char('、')); // 顿号 0x3001
568        assert!(is_chinese_char('。')); // 句号 0x3002
569        assert!(is_chinese_char(char::from_u32(0x303F).unwrap())); // 边界
570
571        // 边界外
572        assert!(!is_chinese_char(char::from_u32(0x3040).unwrap()));
573    }
574
575    #[test]
576    fn test_is_chinese_char_cjk_strokes_kangxi() {
577        // CJK Strokes (0x31C0 - 0x31EF)
578        assert!(is_chinese_char(char::from_u32(0x31C0).unwrap()));
579        assert!(is_chinese_char(char::from_u32(0x31E0).unwrap()));
580        assert!(is_chinese_char(char::from_u32(0x31EF).unwrap()));
581
582        // Kangxi Radicals (0x2F00 - 0x2FD5)
583        assert!(is_chinese_char(char::from_u32(0x2F00).unwrap()));
584        assert!(is_chinese_char(char::from_u32(0x2FA0).unwrap()));
585        assert!(is_chinese_char(char::from_u32(0x2FD5).unwrap()));
586
587        // CJK Radicals Supplement (0x2E80 - 0x2EFF)
588        assert!(is_chinese_char(char::from_u32(0x2E80).unwrap()));
589        assert!(is_chinese_char(char::from_u32(0x2EC0).unwrap()));
590        assert!(is_chinese_char(char::from_u32(0x2EFF).unwrap()));
591    }
592
593    #[test]
594    fn test_is_chinese_char_cjk_compatibility() {
595        // CJK Compatibility Ideographs (0xF900 - 0xFAFF)
596        assert!(is_chinese_char(char::from_u32(0xF900).unwrap()));
597        assert!(is_chinese_char(char::from_u32(0xFA00).unwrap()));
598        assert!(is_chinese_char(char::from_u32(0xFAFF).unwrap()));
599
600        // CJK Compatibility Ideographs Supplement (0x2F800 - 0x2FA1F)
601        assert!(is_chinese_char(char::from_u32(0x2F800).unwrap()));
602        assert!(is_chinese_char(char::from_u32(0x2F900).unwrap()));
603        assert!(is_chinese_char(char::from_u32(0x2FA1F).unwrap()));
604
605        // 边界外
606        assert!(!is_chinese_char(char::from_u32(0x2FA20).unwrap()));
607    }
608
609    #[test]
610    fn test_validate_string_length_multibyte_boundary() {
611        // 测试多字节字符在边界截断的情况
612        // 注意:validate_string_length 使用 chars().take() 是按字符数截取,不是字节数
613        let chinese = "中文字符测试".to_string();
614
615        // 截取2个字符
616        let result = validate_string_length(chinese.clone(), 2, "中文测试");
617        assert_eq!(result.chars().count(), 2);
618        assert_eq!(result, "中文");
619
620        // 截取4个字符
621        let result = validate_string_length(chinese.clone(), 4, "中文测试");
622        assert_eq!(result.chars().count(), 4);
623        assert_eq!(result, "中文字符");
624
625        // 截取6个字符
626        let result = validate_string_length(chinese.clone(), 6, "中文测试");
627        assert_eq!(result.chars().count(), 6);
628        assert_eq!(result, "中文字符测试");
629
630        // 测试 emoji(每个emoji是1个字符)
631        let emoji = "A😀B😁C".to_string();
632        let result = validate_string_length(emoji, 5, "emoji测试");
633        assert_eq!(result, "A😀B😁C"); // 5个字符正好
634
635        // 测试 emoji 截断
636        let emoji = "A😀B😁C".to_string();
637        let result = validate_string_length(emoji, 3, "emoji测试");
638        assert_eq!(result, "A😀B"); // 3个字符
639    }
640
641    #[test]
642    fn test_validate_string_length_exact_boundary() {
643        // 测试精确边界条件
644        let s = "ABC".to_string();
645
646        // 正好等于最大长度
647        let result = validate_string_length(s.clone(), 3, "边界测试");
648        assert_eq!(result, "ABC");
649
650        // 超过1字节
651        let result = validate_string_length(s.clone(), 2, "边界测试");
652        assert_eq!(result, "AB");
653
654        // 超过很多
655        let result = validate_string_length(s.clone(), 0, "边界测试");
656        assert_eq!(result, "");
657    }
658
659    #[test]
660    fn test_validate_required_list_length_zero_max() {
661        // 测试 max_len = 0 的情况
662        let empty: Vec<String> = vec![];
663        assert!(!validate_required_list_length(&empty, 0, "零列表"));
664
665        // 有元素但max_len为0
666        let with_items = vec!["a".to_string()];
667        assert!(!validate_required_list_length(&with_items, 0, "零列表"));
668    }
669
670    #[test]
671    fn test_validate_required_list_length_large_lists() {
672        // 测试大列表
673        let large: Vec<String> = (0..100).map(|i| format!("item{}", i)).collect();
674        assert!(validate_required_list_length(&large, 100, "大列表"));
675        assert!(validate_required_list_length(&large, 200, "更大列表"));
676        assert!(!validate_required_list_length(&large, 50, "小列表"));
677        assert!(!validate_required_list_length(&large, 99, "刚好少一个"));
678    }
679
680    #[test]
681    fn test_validate_required_list_length_single_item() {
682        // 测试单元素列表
683        let single = vec!["only".to_string()];
684        assert!(validate_required_list_length(&single, 1, "单元素"));
685        assert!(validate_required_list_length(&single, 5, "宽松限制"));
686        assert!(!validate_required_list_length(&single, 0, "零限制"));
687    }
688
689    #[test]
690    fn test_validate_content_size_mb_sizes() {
691        // 测试 MB 级别的内容大小
692        let content_1mb = "x".repeat(1024 * 1024);
693        assert!(validate_content_size(&content_1mb, 1024 * 1024, "1MB内容"));
694        assert!(!validate_content_size(
695            &content_1mb,
696            1024 * 1024 - 1,
697            "1MB-1内容"
698        ));
699
700        let content_10mb = "x".repeat(10 * 1024 * 1024);
701        assert!(validate_content_size(
702            &content_10mb,
703            10 * 1024 * 1024,
704            "10MB内容"
705        ));
706        assert!(!validate_content_size(
707            &content_10mb,
708            10 * 1024 * 1024 - 1,
709            "10MB-1内容"
710        ));
711    }
712
713    #[test]
714    fn test_validate_content_size_empty_and_small() {
715        // 测试空内容和小内容
716        assert!(validate_content_size("", 0, "空内容0限制"));
717        assert!(validate_content_size("", 1, "空内容1限制"));
718        assert!(validate_content_size("a", 1, "单字节1限制"));
719        assert!(!validate_content_size("a", 0, "单字节0限制"));
720
721        // 测试中文内容
722        assert!(validate_content_size("你好", 6, "中文6字节")); // "你好" = 6字节
723        assert!(!validate_content_size("你好", 5, "中文5字节"));
724    }
725
726    #[test]
727    fn test_default_validate_builder_chain_multiple_validations() {
728        // 测试多验证链式调用
729        let builder = DefaultValidateBuilder::new()
730            .required(Some("start".to_string()), "字段1")
731            .length("mid".to_string(), 2, 10, "字段2")
732            .custom("end".to_string(), |v| v.len() < 10, "自定义校验");
733
734        // 注意:由于builder的消费性质,最后设置的value会覆盖之前的
735        // 这里需要理解builder的行为:每次调用都消耗self并返回新builder
736        let result = builder.build();
737        assert!(result.is_ok());
738    }
739
740    #[test]
741    fn test_default_validate_builder_multiple_errors() {
742        // 测试多错误累积
743        let builder = DefaultValidateBuilder::new()
744            .required(None, "字段1")
745            .required(Some("".to_string()), "字段2")
746            .length("a".to_string(), 5, 10, "字段3");
747
748        let result = builder.build();
749        assert!(result.is_err());
750        let errors = result.unwrap_err();
751        assert!(errors.len() >= 2); // 应该有多个错误
752    }
753
754    #[test]
755    fn test_default_validate_builder_custom_validator() {
756        // 测试自定义验证器的各种情况
757        let email_regex = |v: &str| v.contains('@') && v.contains('.');
758
759        // 通过的情况
760        let result = DefaultValidateBuilder::new()
761            .custom("test@example.com".to_string(), email_regex, "无效的邮箱")
762            .build();
763        assert!(result.is_ok());
764
765        // 失败的情况
766        let result = DefaultValidateBuilder::new()
767            .custom("invalid-email".to_string(), email_regex, "无效的邮箱")
768            .build();
769        assert!(result.is_err());
770        assert_eq!(result.unwrap_err(), vec!["无效的邮箱"]);
771    }
772
773    #[test]
774    fn test_default_validate_builder_length_exact_min_max() {
775        // 测试长度验证的精确边界
776        // 正好等于最小值
777        let result = DefaultValidateBuilder::new()
778            .length("abc".to_string(), 3, 10, "长度测试")
779            .build();
780        assert!(result.is_ok());
781
782        // 正好等于最大值
783        let result = DefaultValidateBuilder::new()
784            .length("abcdefghij".to_string(), 1, 10, "长度测试")
785            .build();
786        assert!(result.is_ok());
787
788        // 小于最小值
789        let result = DefaultValidateBuilder::new()
790            .length("ab".to_string(), 3, 10, "长度测试")
791            .build();
792        assert!(result.is_err());
793
794        // 大于最大值
795        let result = DefaultValidateBuilder::new()
796            .length("abcdefghijk".to_string(), 1, 10, "长度测试")
797            .build();
798        assert!(result.is_err());
799    }
800
801    #[test]
802    fn test_validation_result_edge_cases() {
803        // 测试 ValidationResult 的边缘情况
804        let valid = ValidationResult::Valid;
805        assert!(valid.is_valid());
806        assert_eq!(valid.error_message(), None);
807        assert_eq!(valid.sanitized_value(), None);
808        assert_eq!(valid.into_result(), Ok(String::new()));
809
810        // 空错误消息
811        let invalid_empty = ValidationResult::Invalid("".to_string());
812        assert!(!invalid_empty.is_valid());
813        assert_eq!(invalid_empty.error_message(), Some(&"".to_string()));
814
815        // 空清理值
816        let sanitized_empty = ValidationResult::Sanitized("".to_string());
817        assert!(!sanitized_empty.is_valid());
818        assert_eq!(sanitized_empty.sanitized_value(), Some(&"".to_string()));
819        assert_eq!(sanitized_empty.into_result(), Ok("".to_string()));
820    }
821}