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::>(); 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::>(); 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::>(); 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")); } }