-
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathvalidation_tests.rs
More file actions
112 lines (95 loc) · 3.44 KB
/
validation_tests.rs
File metadata and controls
112 lines (95 loc) · 3.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use rustapi_rs::prelude::*;
use rustapi_validate::v2::ValidationContext;
use serde::{Deserialize, Serialize};
// ============================================================================
// Sync Validation Tests (Legacy validator crate compatibility)
// ============================================================================
#[derive(Debug, Deserialize, Serialize, validator::Validate)]
#[cfg(feature = "legacy-validator")]
struct LegacyUser {
#[validate(length(min = 3))]
name: String,
}
#[test]
#[cfg(feature = "legacy-validator")]
fn test_legacy_validator_compat() {
let valid_user = LegacyUser {
name: "Bob".to_string(),
};
let invalid_user = LegacyUser {
name: "Bo".to_string(),
};
// Test direct Validatable implementation
assert!(valid_user.do_validate().is_ok());
let err = invalid_user.do_validate().unwrap_err();
assert_eq!(err.error_type, "validation_error");
assert!(err.fields.is_some());
let fields = err.fields.unwrap();
assert_eq!(fields[0].field, "name");
}
// ============================================================================
// V2 Validation Tests (New engine)
// ============================================================================
#[derive(Debug, Deserialize, Serialize, rustapi_macros::Validate)]
struct V2User {
#[validate(length(min = 3))]
name: String,
}
#[test]
fn test_v2_validate_macro() {
let valid_user = V2User {
name: "Alice".to_string(),
};
let invalid_user = V2User {
name: "Al".to_string(),
};
// Test direct Validatable implementation generated by macro
assert!(valid_user.do_validate().is_ok());
let err = invalid_user.do_validate().unwrap_err();
assert_eq!(err.error_type, "validation_error");
assert!(err.fields.is_some());
let fields = err.fields.unwrap();
assert_eq!(fields[0].field, "name");
}
// ============================================================================
// Async Validation Tests
// ============================================================================
#[derive(Debug, Deserialize, Serialize, rustapi_macros::Validate)]
struct AsyncUser {
#[validate(custom_async = "check_custom")]
name: String,
}
async fn check_custom(
val: &String,
_ctx: &ValidationContext,
) -> Result<(), rustapi_validate::v2::RuleError> {
if val == "taken" {
Err(rustapi_validate::v2::RuleError::new(
"taken",
"Name is taken",
))
} else {
Ok(())
}
}
#[tokio::test]
async fn test_async_validation() {
// We can't easily test AsyncValidatedJson extractor without constructing a full Request
// and setting up the app, but we can test the trait and manual usage if needed.
// However, since we updated AsyncValidatedJson to use validate_full, we should trust
// unit tests in rustapi-core if we had them.
// Here we verify that the macro generated the AsyncValidate impl correctly.
let user = AsyncUser {
name: "available".to_string(),
};
let ctx = ValidationContext::default();
assert!(user.validate_async(&ctx).await.is_ok());
let invalid_user = AsyncUser {
name: "taken".to_string(),
};
let err = invalid_user.validate_async(&ctx).await.unwrap_err();
// err here is ValidationErrors
assert!(!err.is_empty());
let name_errors = err.get("name").expect("Should have errors for name");
assert!(name_errors.iter().any(|e| e.code == "taken"));
}