Files
2026-06-23 21:03:03 +00:00

244 lines
6.8 KiB
Rust

mod unit {
use crank_core::HttpMethod;
use crank_import::rest::preview_document;
const OPENAPI3: &str = r#"
openapi: 3.0.3
info:
title: Frankfurter API
servers:
- url: https://api.frankfurter.dev
paths:
/v2/latest:
get:
operationId: getLatestRates
summary: Получить последние курсы
description: Возвращает последние курсы валют для базовой валюты.
tags: [currency]
parameters:
- name: base
in: query
required: true
schema:
type: string
- name: symbols
in: query
schema:
type: string
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
required: [amount, base]
properties:
amount:
type: number
base:
type: string
"#;
const SWAGGER2: &str = r#"
swagger: "2.0"
info:
title: Pet API
host: petstore.example.com
basePath: /api
schemes: [https]
paths:
/pets/{id}:
get:
operationId: getPet
summary: Получить питомца
tags: [pets]
parameters:
- name: id
in: path
required: true
type: string
responses:
'200':
description: OK
schema:
$ref: '#/definitions/Pet'
definitions:
Pet:
type: object
required: [id, name]
properties:
id:
type: string
name:
type: string
"#;
#[test]
fn previews_openapi3_rest_operations_grouped_by_tag() {
let preview = preview_document(OPENAPI3).unwrap();
assert_eq!(preview.source.format, "openapi");
assert_eq!(preview.source.servers, vec!["https://api.frankfurter.dev"]);
assert_eq!(preview.groups.len(), 1);
assert_eq!(preview.groups[0].key, "currency");
let operation = &preview.groups[0].operations[0];
assert_eq!(operation.method, HttpMethod::Get);
assert_eq!(operation.suggested_name, "get_latest_rates");
assert_eq!(operation.input_fields, 2);
assert_eq!(operation.output_fields, 2);
assert_eq!(operation.draft.target.path_template, "/v2/latest");
assert_eq!(operation.draft.input_mapping.rules.len(), 2);
}
#[test]
fn previews_swagger2_and_resolves_definitions() {
let preview = preview_document(SWAGGER2).unwrap();
assert_eq!(preview.source.format, "swagger");
assert_eq!(
preview.source.servers,
vec!["https://petstore.example.com/api"]
);
let operation = &preview.groups[0].operations[0];
assert_eq!(operation.suggested_name, "get_pet");
assert_eq!(operation.input_fields, 1);
assert_eq!(operation.output_fields, 2);
assert_eq!(operation.draft.target.path_template, "/pets/{id}");
assert_eq!(
operation.draft.input_mapping.rules[0].target,
"$.request.path.id"
);
}
#[test]
fn reports_missing_descriptions_as_recommendations() {
let document = r#"
openapi: 3.0.3
info: { title: Minimal API }
paths:
/items:
get:
responses:
'204': { description: Empty }
"#;
let preview = preview_document(document).unwrap();
let operation = &preview.groups[0].operations[0];
let codes = operation
.findings
.iter()
.map(|finding| finding.code.as_str())
.collect::<Vec<_>>();
assert!(codes.contains(&"missing_operation_id"));
assert!(codes.contains(&"missing_summary"));
assert!(codes.contains(&"missing_description"));
assert!(codes.contains(&"missing_response_schema"));
}
#[test]
fn expands_json_request_body_object_into_tool_inputs() {
let document = r#"
openapi: 3.0.3
info: { title: CRM API }
servers:
- url: https://crm.example.test
paths:
/leads:
post:
operationId: createLead
summary: Создать лид
description: Создает лид в CRM.
tags: [crm]
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [email]
properties:
email: { type: string }
name: { type: string }
responses:
'201':
description: Created
content:
application/json:
schema:
type: object
properties:
id: { type: string }
"#;
let preview = preview_document(document).unwrap();
let operation = &preview.groups[0].operations[0];
let input_fields = &operation.draft.input_schema.fields;
let targets = operation
.draft
.input_mapping
.rules
.iter()
.map(|rule| rule.target.as_str())
.collect::<Vec<_>>();
assert!(input_fields.contains_key("email"));
assert!(input_fields.contains_key("name"));
assert!(targets.contains(&"$.request.body.email"));
assert!(targets.contains(&"$.request.body.name"));
}
#[test]
fn reports_tool_quality_recommendations_for_imported_operations() {
let document = r#"
openapi: 3.0.3
info: { title: Wide API }
paths:
/items:
get:
operationId: getItems
summary: Get items
description: Get items.
parameters:
- name: page
in: query
schema: { type: integer }
responses:
'200':
description: OK
content:
application/json:
schema:
type: object
properties:
field01: { type: string }
field02: { type: string }
field03: { type: string }
field04: { type: string }
field05: { type: string }
field06: { type: string }
field07: { type: string }
field08: { type: string }
field09: { type: string }
field10: { type: string }
field11: { type: string }
field12: { type: string }
field13: { type: string }
"#;
let preview = preview_document(document).unwrap();
let operation = &preview.groups[0].operations[0];
let codes = operation
.findings
.iter()
.map(|finding| finding.code.as_str())
.collect::<Vec<_>>();
assert!(codes.contains(&"parameter_descriptions_missing"));
assert!(codes.contains(&"weak_tool_description"));
assert!(codes.contains(&"weak_tool_name"));
assert!(codes.contains(&"too_many_output_fields"));
}
}