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)]