test: add 149 unit tests across core, auth, config, message crates

Test coverage increased from ~34 to 183 tests (zero failures):

- erp-core (21): version check, pagination, API response, error mapping
- erp-auth (39): org tree building, DTO validation, error conversion,
  password hashing, user model mapping
- erp-config (57): DTO validation, numbering reset logic, menu tree
  building, error conversion. Fixed BatchSaveMenusReq nested validation
- erp-message (50): DTO validation, template rendering, query defaults,
  error conversion
- erp-workflow (16): unchanged (parser + expression tests)

All tests are pure unit tests requiring no database.
This commit is contained in:
iven
2026-04-15 01:06:34 +08:00
parent 9568dd7875
commit ee65b6e3c9
13 changed files with 1995 additions and 4 deletions

View File

@@ -176,3 +176,319 @@ pub struct UpdateSubscriptionReq {
pub dnd_end: Option<String>,
pub version: i32,
}
#[cfg(test)]
mod tests {
use super::*;
use uuid::Uuid;
use validator::Validate;
// ============ SendMessageReq 测试 ============
fn valid_send_message_req() -> SendMessageReq {
SendMessageReq {
title: "系统通知".to_string(),
body: "您有一条新消息".to_string(),
recipient_id: Uuid::now_v7(),
recipient_type: "user".to_string(),
priority: "normal".to_string(),
template_id: None,
business_type: None,
business_id: None,
}
}
#[test]
fn send_message_req_valid() {
let req = valid_send_message_req();
assert!(req.validate().is_ok());
}
#[test]
fn send_message_req_empty_title_fails() {
let mut req = valid_send_message_req();
req.title = "".to_string();
assert!(req.validate().is_err());
}
#[test]
fn send_message_req_title_too_long_fails() {
let mut req = valid_send_message_req();
req.title = "x".repeat(201);
assert!(req.validate().is_err());
}
#[test]
fn send_message_req_title_max_length_ok() {
let mut req = valid_send_message_req();
req.title = "x".repeat(200);
assert!(req.validate().is_ok());
}
#[test]
fn send_message_req_empty_body_fails() {
let mut req = valid_send_message_req();
req.body = "".to_string();
assert!(req.validate().is_err());
}
#[test]
fn send_message_req_valid_recipient_types() {
for rt in &["user", "role", "department", "all"] {
let mut req = valid_send_message_req();
req.recipient_type = rt.to_string();
assert!(req.validate().is_ok(), "recipient_type '{}' should be valid", rt);
}
}
#[test]
fn send_message_req_invalid_recipient_type_fails() {
let mut req = valid_send_message_req();
req.recipient_type = "invalid".to_string();
assert!(req.validate().is_err());
}
#[test]
fn send_message_req_valid_priorities() {
for p in &["normal", "important", "urgent"] {
let mut req = valid_send_message_req();
req.priority = p.to_string();
assert!(req.validate().is_ok(), "priority '{}' should be valid", p);
}
}
#[test]
fn send_message_req_invalid_priority_fails() {
let mut req = valid_send_message_req();
req.priority = "critical".to_string();
assert!(req.validate().is_err());
}
#[test]
fn send_message_req_default_recipient_type_is_user() {
assert_eq!(default_recipient_type(), "user");
}
#[test]
fn send_message_req_default_priority_is_normal() {
assert_eq!(default_priority(), "normal");
}
// ============ MessageQuery 测试 ============
#[test]
fn message_query_safe_page_size_default() {
let query = MessageQuery {
page: None,
page_size: None,
is_read: None,
priority: None,
business_type: None,
status: None,
};
assert_eq!(query.safe_page_size(), 20);
}
#[test]
fn message_query_safe_page_size_custom() {
let query = MessageQuery {
page: None,
page_size: Some(50),
is_read: None,
priority: None,
business_type: None,
status: None,
};
assert_eq!(query.safe_page_size(), 50);
}
#[test]
fn message_query_safe_page_size_capped_at_100() {
let query = MessageQuery {
page: None,
page_size: Some(200),
is_read: None,
priority: None,
business_type: None,
status: None,
};
assert_eq!(query.safe_page_size(), 100);
}
#[test]
fn message_query_safe_page_size_exactly_100() {
let query = MessageQuery {
page: None,
page_size: Some(100),
is_read: None,
priority: None,
business_type: None,
status: None,
};
assert_eq!(query.safe_page_size(), 100);
}
// ============ CreateTemplateReq 测试 ============
fn valid_create_template_req() -> CreateTemplateReq {
CreateTemplateReq {
name: "欢迎模板".to_string(),
code: "WELCOME".to_string(),
channel: "in_app".to_string(),
title_template: "欢迎加入".to_string(),
body_template: "您好,{{name}},欢迎加入平台".to_string(),
language: "zh-CN".to_string(),
}
}
#[test]
fn create_template_req_valid() {
let req = valid_create_template_req();
assert!(req.validate().is_ok());
}
#[test]
fn create_template_req_empty_name_fails() {
let mut req = valid_create_template_req();
req.name = "".to_string();
assert!(req.validate().is_err());
}
#[test]
fn create_template_req_name_too_long_fails() {
let mut req = valid_create_template_req();
req.name = "x".repeat(101);
assert!(req.validate().is_err());
}
#[test]
fn create_template_req_name_max_length_ok() {
let mut req = valid_create_template_req();
req.name = "x".repeat(100);
assert!(req.validate().is_ok());
}
#[test]
fn create_template_req_empty_code_fails() {
let mut req = valid_create_template_req();
req.code = "".to_string();
assert!(req.validate().is_err());
}
#[test]
fn create_template_req_code_too_long_fails() {
let mut req = valid_create_template_req();
req.code = "X".repeat(51);
assert!(req.validate().is_err());
}
#[test]
fn create_template_req_code_max_length_ok() {
let mut req = valid_create_template_req();
req.code = "X".repeat(50);
assert!(req.validate().is_ok());
}
#[test]
fn create_template_req_valid_channels() {
for ch in &["in_app", "email", "sms", "wechat"] {
let mut req = valid_create_template_req();
req.channel = ch.to_string();
assert!(req.validate().is_ok(), "channel '{}' should be valid", ch);
}
}
#[test]
fn create_template_req_invalid_channel_fails() {
let mut req = valid_create_template_req();
req.channel = "telegram".to_string();
assert!(req.validate().is_err());
}
#[test]
fn create_template_req_empty_title_template_fails() {
let mut req = valid_create_template_req();
req.title_template = "".to_string();
assert!(req.validate().is_err());
}
#[test]
fn create_template_req_title_template_too_long_fails() {
let mut req = valid_create_template_req();
req.title_template = "x".repeat(201);
assert!(req.validate().is_err());
}
#[test]
fn create_template_req_empty_body_template_fails() {
let mut req = valid_create_template_req();
req.body_template = "".to_string();
assert!(req.validate().is_err());
}
#[test]
fn create_template_req_default_channel_is_in_app() {
assert_eq!(default_channel(), "in_app");
}
#[test]
fn create_template_req_default_language_is_zh_cn() {
assert_eq!(default_language(), "zh-CN");
}
// ============ 自定义验证函数测试 ============
#[test]
fn validate_recipient_type_valid() {
for rt in &["user", "role", "department", "all"] {
assert!(
validate_recipient_type(rt).is_ok(),
"'{}' should be a valid recipient type",
rt
);
}
}
#[test]
fn validate_recipient_type_invalid() {
assert!(validate_recipient_type("invalid").is_err());
assert!(validate_recipient_type("").is_err());
assert!(validate_recipient_type("USER").is_err());
}
#[test]
fn validate_priority_valid() {
for p in &["normal", "important", "urgent"] {
assert!(
validate_priority(p).is_ok(),
"'{}' should be a valid priority",
p
);
}
}
#[test]
fn validate_priority_invalid() {
assert!(validate_priority("critical").is_err());
assert!(validate_priority("").is_err());
assert!(validate_priority("NORMAL").is_err());
}
#[test]
fn validate_channel_valid() {
for ch in &["in_app", "email", "sms", "wechat"] {
assert!(
validate_channel(ch).is_ok(),
"'{}' should be a valid channel",
ch
);
}
}
#[test]
fn validate_channel_invalid() {
assert!(validate_channel("slack").is_err());
assert!(validate_channel("").is_err());
assert!(validate_channel("EMAIL").is_err());
}
}