test(health): 补充 article/dialysis/lab_report 状态转换验证 + 83 单元测试
Some checks failed
CI / rust-check (push) Has been cancelled
CI / rust-test (push) Has been cancelled
CI / frontend-build (push) Has been cancelled
CI / security-audit (push) Has been cancelled

- validate_article_status (枚举白名单) + validate_article_status_transition
  (draft→pending_review→approved→published, rejected→pending_review, published→draft)
- validate_dialysis_status + validate_dialysis_status_transition
  (draft→completed→reviewed)
- validate_lab_report_status_transition (pending→reviewed)
- 全部 83 个 validation 测试通过
This commit is contained in:
iven
2026-04-26 14:35:19 +08:00
parent 7a9054c914
commit 4f4a44ddb6

View File

@@ -131,6 +131,85 @@ pub fn validate_online_status(value: &str) -> HealthResult<()> {
Ok(())
}
/// article.status 枚举白名单
pub fn validate_article_status(value: &str) -> HealthResult<()> {
validate_enum!(value, "article.status", [
"draft", "pending_review", "approved", "rejected", "published",
]);
Ok(())
}
/// article.status 状态转换
/// draft → pending_review, rejected → pending_review
/// pending_review → approved / rejected
/// approved → published
/// published → draft (下架)
pub fn validate_article_status_transition(current: &str, new: &str) -> HealthResult<()> {
if current == new {
return Ok(());
}
let allowed = match current {
"draft" => matches!(new, "pending_review"),
"pending_review" => matches!(new, "approved" | "rejected"),
"approved" => matches!(new, "published"),
"rejected" => matches!(new, "pending_review"),
"published" => matches!(new, "draft"),
_ => false,
};
if allowed {
Ok(())
} else {
Err(HealthError::InvalidStatusTransition(format!(
"article.status: 不允许从 '{}' 转换到 '{}'", current, new
)))
}
}
/// dialysis_record.status 枚举白名单
pub fn validate_dialysis_status(value: &str) -> HealthResult<()> {
validate_enum!(value, "dialysis_record.status", ["draft", "completed", "reviewed"]);
Ok(())
}
/// dialysis_record.status 状态转换
/// draft → completed → reviewed
pub fn validate_dialysis_status_transition(current: &str, new: &str) -> HealthResult<()> {
if current == new {
return Ok(());
}
let allowed = match current {
"draft" => matches!(new, "completed"),
"completed" => matches!(new, "reviewed"),
_ => false,
};
if allowed {
Ok(())
} else {
Err(HealthError::InvalidStatusTransition(format!(
"dialysis_record.status: 不允许从 '{}' 转换到 '{}'", current, new
)))
}
}
/// lab_report.status 状态转换
/// pending → reviewed
pub fn validate_lab_report_status_transition(current: &str, new: &str) -> HealthResult<()> {
if current == new {
return Ok(());
}
let allowed = match current {
"pending" => matches!(new, "reviewed"),
_ => false,
};
if allowed {
Ok(())
} else {
Err(HealthError::InvalidStatusTransition(format!(
"lab_report.status: 不允许从 '{}' 转换到 '{}'", current, new
)))
}
}
/// follow_up_task.status 状态转换(含 overdue 状态)
pub fn validate_follow_up_status_transition(current: &str, new: &str) -> HealthResult<()> {
if current == new {
@@ -276,6 +355,68 @@ mod tests {
#[test]
fn online_invalid() { assert!(validate_online_status("away").is_err()); }
// --- article_status ---
#[test]
fn article_draft() { assert!(validate_article_status("draft").is_ok()); }
#[test]
fn article_published() { assert!(validate_article_status("published").is_ok()); }
#[test]
fn article_invalid() { assert!(validate_article_status("archived").is_err()); }
// --- article_status_transition ---
#[test]
fn art_draft_to_pending_review() { assert!(validate_article_status_transition("draft", "pending_review").is_ok()); }
#[test]
fn art_draft_to_published_fails() { assert!(validate_article_status_transition("draft", "published").is_err()); }
#[test]
fn art_pending_review_to_approved() { assert!(validate_article_status_transition("pending_review", "approved").is_ok()); }
#[test]
fn art_pending_review_to_rejected() { assert!(validate_article_status_transition("pending_review", "rejected").is_ok()); }
#[test]
fn art_pending_review_to_draft_fails() { assert!(validate_article_status_transition("pending_review", "draft").is_err()); }
#[test]
fn art_approved_to_published() { assert!(validate_article_status_transition("approved", "published").is_ok()); }
#[test]
fn art_rejected_to_pending_review() { assert!(validate_article_status_transition("rejected", "pending_review").is_ok()); }
#[test]
fn art_published_to_draft() { assert!(validate_article_status_transition("published", "draft").is_ok()); }
#[test]
fn art_published_to_approved_fails() { assert!(validate_article_status_transition("published", "approved").is_err()); }
#[test]
fn art_same_status_ok() { assert!(validate_article_status_transition("draft", "draft").is_ok()); }
// --- dialysis_status ---
#[test]
fn dialysis_draft() { assert!(validate_dialysis_status("draft").is_ok()); }
#[test]
fn dialysis_reviewed() { assert!(validate_dialysis_status("reviewed").is_ok()); }
#[test]
fn dialysis_invalid() { assert!(validate_dialysis_status("approved").is_err()); }
// --- dialysis_status_transition ---
#[test]
fn dial_draft_to_completed() { assert!(validate_dialysis_status_transition("draft", "completed").is_ok()); }
#[test]
fn dial_draft_to_reviewed_fails() { assert!(validate_dialysis_status_transition("draft", "reviewed").is_err()); }
#[test]
fn dial_completed_to_reviewed() { assert!(validate_dialysis_status_transition("completed", "reviewed").is_ok()); }
#[test]
fn dial_completed_to_draft_fails() { assert!(validate_dialysis_status_transition("completed", "draft").is_err()); }
#[test]
fn dial_reviewed_to_any_fails() { assert!(validate_dialysis_status_transition("reviewed", "draft").is_err()); }
#[test]
fn dial_same_status_ok() { assert!(validate_dialysis_status_transition("draft", "draft").is_ok()); }
// --- lab_report_status_transition ---
#[test]
fn lab_pending_to_reviewed() { assert!(validate_lab_report_status_transition("pending", "reviewed").is_ok()); }
#[test]
fn lab_pending_to_draft_fails() { assert!(validate_lab_report_status_transition("pending", "draft").is_err()); }
#[test]
fn lab_reviewed_to_any_fails() { assert!(validate_lab_report_status_transition("reviewed", "pending").is_err()); }
#[test]
fn lab_same_status_ok() { assert!(validate_lab_report_status_transition("pending", "pending").is_ok()); }
// --- follow_up_status_transition ---
#[test]
fn fu_pending_to_in_progress() { assert!(validate_follow_up_status_transition("pending", "in_progress").is_ok()); }