Files
crank/crates/crank-core/tests/unit/tool_quality.rs
T
github-ops 2719c5f7bf
Deploy / deploy (push) Successful in 1m34s
CI / Rust Checks (push) Successful in 5m0s
CI / UI Checks (push) Successful in 4s
CI / Deployment Manifests (push) Successful in 7s
CI / Frontend E2E (push) Successful in 4m36s
Add tool identity quality checks
2026-06-20 19:53:42 +00:00

123 lines
3.9 KiB
Rust

use crank_core::{
ToolDescription, ToolQualityFinding, ToolQualityReport, ToolQualitySeverity,
analyze_tool_identity_quality,
};
#[test]
fn serializes_tool_quality_finding_contract() {
let finding = ToolQualityFinding {
severity: ToolQualitySeverity::Warning,
code: "tool_description_too_short".to_owned(),
message: "Описание инструмента слишком короткое.".to_owned(),
suggested_action: Some("Добавьте назначение и условия применения инструмента.".to_owned()),
field_path: Some("tool_description.description".to_owned()),
};
let value = serde_json::to_value(finding).unwrap();
assert_eq!(value["severity"], "warning");
assert_eq!(value["code"], "tool_description_too_short");
assert_eq!(value["field_path"], "tool_description.description");
}
#[test]
fn report_is_blocking_when_error_finding_exists() {
let report = ToolQualityReport::new(vec![ToolQualityFinding {
severity: ToolQualitySeverity::Error,
code: "tool_name_missing".to_owned(),
message: "Имя инструмента обязательно.".to_owned(),
suggested_action: None,
field_path: Some("name".to_owned()),
}]);
assert!(report.blocking);
assert_eq!(report.findings.len(), 1);
}
#[test]
fn reports_missing_tool_name_as_blocking_error() {
let report = analyze_tool_identity_quality(
" ",
&ToolDescription {
title: "Create lead".to_owned(),
description: "Создает новый лид в CRM, когда пользователь просит добавить потенциального клиента.".to_owned(),
tags: Vec::new(),
examples: Vec::new(),
},
);
assert!(report.blocking);
assert!(has_finding(
&report,
"tool_name_missing",
ToolQualitySeverity::Error
));
}
#[test]
fn warns_about_generic_tool_name() {
let report = analyze_tool_identity_quality(
"call_api",
&ToolDescription {
title: "Call API".to_owned(),
description: "Получает данные клиента по идентификатору, когда пользователю нужна карточка клиента.".to_owned(),
tags: Vec::new(),
examples: Vec::new(),
},
);
assert!(!report.blocking);
assert!(has_finding(
&report,
"tool_name_too_generic",
ToolQualitySeverity::Warning
));
}
#[test]
fn reports_unsafe_tool_name_format_as_blocking_error() {
let report = analyze_tool_identity_quality(
"Create Lead!",
&ToolDescription {
title: "Create lead".to_owned(),
description: "Создает новый лид в CRM, когда пользователь просит добавить потенциального клиента.".to_owned(),
tags: Vec::new(),
examples: Vec::new(),
},
);
assert!(report.blocking);
assert!(has_finding(
&report,
"tool_name_invalid_format",
ToolQualitySeverity::Error
));
}
#[test]
fn warns_about_short_description() {
let report = analyze_tool_identity_quality(
"create_lead",
&ToolDescription {
title: "Create lead".to_owned(),
description: "Создает лид.".to_owned(),
tags: Vec::new(),
examples: Vec::new(),
},
);
assert!(!report.blocking);
assert!(has_finding(
&report,
"tool_description_too_short",
ToolQualitySeverity::Warning
));
}
fn has_finding(report: &ToolQualityReport, code: &str, severity: ToolQualitySeverity) -> bool {
report
.findings
.iter()
.any(|finding| finding.code == code && finding.severity == severity)
}