2025-06-20 11:24:03 +08:00

59 lines
3.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from ddms_compliance_suite.test_framework_core import BaseAPITestCase, ValidationResult, APIResponseContext, APIRequestContext, TestSeverity
import re
from typing import Dict, Any, List, Optional
# TODO 获取资源的时候复数get方法list
class ResourceCollectionPluralCheckTestCase(BaseAPITestCase):
id = "TC-RESTful-004"
name = "资源集合复数命名检查"
description = "验证表示资源集合的路径是否使用复数形式。动词如push、send等不需要使用复数形式。"
severity = TestSeverity.MEDIUM
tags = ["normative", "restful", "url-structure"]
def __init__(self, endpoint_spec: Dict[str, Any], global_api_spec: Dict[str, Any], json_schema_validator: Optional[Any] = None, llm_service: Optional[Any] = None):
super().__init__(endpoint_spec, global_api_spec, json_schema_validator, llm_service=llm_service)
# 常见的API路径中的动词这些不需要使用复数形式
self.common_verbs = {
"push", "send", "publish", "subscribe", "create", "update", "delete",
"get", "set", "add", "remove", "search", "query", "find", "calculate",
"process", "validate", "verify", "check", "analyze", "export", "import",
"upload", "download", "sync", "login", "logout", "register", "activate",
"deactivate", "approve", "reject", "cancel", "confirm", "notify"
}
# 已知的单数形式名词,即使不以's'结尾也是正确的
self.known_singulars = {
"status", "gas", "analysis", "data", "info", "metadata", "media",
"equipment", "staff", "fish", "sheep", "deer", "series", "species",
"aircraft", "offspring", "feedback", "content", "news"
}
def validate_response(self, response_context: APIResponseContext, request_context: APIRequestContext) -> List[ValidationResult]:
path = self.endpoint_spec['path']
method = self.endpoint_spec['method']
# 这个检查通常适用于返回列表的GET请求或者创建资源的POST请求
if method.lower() not in ['get', 'post']:
return [self.passed(f"跳过检查:{method} 方法,不适用于资源集合复数检查。")]
path_segments = [seg for seg in path.strip('/').split('/') if '{' not in seg and not re.match(r'v\d+', seg)]
if not path_segments:
return [self.passed("跳过检查:路径不含有效分段。")]
resource_segment = path_segments[-1]
# 检查是否为动词
if resource_segment.lower() in self.common_verbs:
return [self.passed(f"路径 '{path}' 的最后一个路径分段 '{resource_segment}' 是动词,不需要使用复数形式。")]
# 检查是否为已知的单数形式名词
if resource_segment.lower() in self.known_singulars:
return [self.passed(f"路径 '{path}' 的资源名 '{resource_segment}' 是已知的单数形式名词,符合规范。")]
# 对于其他名词,检查是否使用复数形式
if not resource_segment.endswith('s'):
message = f"路径 '{path}' 的最后一个路径分段 '{resource_segment}' 可能不是复数形式,建议对资源集合使用复数命名。"
return [self.failed(message, details={'path': path, 'segment': resource_segment})]
message = f"路径 '{path}' 的资源集合命名 '{resource_segment}' 符合复数命名规范。"
return [self.passed(message)]