diff --git a/backend/framework/sdk/src/main/resources/i18n/case.properties b/backend/framework/sdk/src/main/resources/i18n/case.properties index f132266419..32f2bd6f25 100644 --- a/backend/framework/sdk/src/main/resources/i18n/case.properties +++ b/backend/framework/sdk/src/main/resources/i18n/case.properties @@ -12,6 +12,9 @@ permission.case_review.end_time=评审周期结束时间不得早于当前时间 #module:FunctionalCase functional_case.module.default.name=未规划用例 functional_case.module.default.name.add_error=未规划用例模块下不支持新增模块 +functional_case.module.default.name.cut_error=未规划用例模块不能被移动 +all.module.default.name.cut_error=全部用例不能被移动 + review.module.default.name=未规划评审 functional_case.id.not_blank=ID不能为空 functional_case.num.not_blank=业务ID不能为空 diff --git a/backend/framework/sdk/src/main/resources/i18n/case_en_US.properties b/backend/framework/sdk/src/main/resources/i18n/case_en_US.properties index bf68e142a0..61f8d920c3 100644 --- a/backend/framework/sdk/src/main/resources/i18n/case_en_US.properties +++ b/backend/framework/sdk/src/main/resources/i18n/case_en_US.properties @@ -12,6 +12,8 @@ permission.case_review.endTime=The review cycle end time cannot be earlier than #module:FunctionalCase functional_case.module.default.name=Unplanned case functional_case.module.default.name.add_error=New modules are not supported under unplanned use case modules. +functional_case.module.default.name.cut_error=Unplanned use case modules cannot be moved +all.module.default.name.cut_error=All use cases cannot be moved review.module.default.name=Unplanned review functional_case.id.not_blank=ID cannot be empty functional_case.num.not_blank=Business ID cannot be empty diff --git a/backend/framework/sdk/src/main/resources/i18n/case_zh_CN.properties b/backend/framework/sdk/src/main/resources/i18n/case_zh_CN.properties index 84e5f1fdb6..79b588a562 100644 --- a/backend/framework/sdk/src/main/resources/i18n/case_zh_CN.properties +++ b/backend/framework/sdk/src/main/resources/i18n/case_zh_CN.properties @@ -11,6 +11,8 @@ permission.case_review.end_time=评审周期结束时间不得早于当前时间 #module:FunctionalCase functional_case.module.default.name=未规划用例 functional_case.module.default.name.add_error=未规划用例模块下不支持新增模块 +functional_case.module.default.name.cut_error=未规划用例模块不能被移动 +all.module.default.name.cut_error=全部用例不能被移动 review.module.default.name=未规划评审 functional_case.id.not_blank=ID不能为空 functional_case.num.not_blank=业务ID不能为空 diff --git a/backend/framework/sdk/src/main/resources/i18n/case_zh_TW.properties b/backend/framework/sdk/src/main/resources/i18n/case_zh_TW.properties index eeb6683466..783e9945cb 100644 --- a/backend/framework/sdk/src/main/resources/i18n/case_zh_TW.properties +++ b/backend/framework/sdk/src/main/resources/i18n/case_zh_TW.properties @@ -12,6 +12,8 @@ permission.case_review.end_time=評審週期結束時間不得早於目前時間 #module:FunctionalCase functional_case.module.default.name=未規劃用例 functional_case.module.default.name.add_error=未規劃用例模組下不支援新增模組 +functional_case.module.default.name.cut_error=未規劃用例模組不能被移動 +all.module.default.name.cut_error=全部用例不能被移動 review.module.default.name=未規劃評審 functional_case.id.not_blank=ID不能為空 functional_case.num.not_blank=业务ID不能為空 diff --git a/backend/framework/sdk/src/main/resources/i18n/commons_en_US.properties b/backend/framework/sdk/src/main/resources/i18n/commons_en_US.properties index d6c9ac3a16..f02f350bd2 100644 --- a/backend/framework/sdk/src/main/resources/i18n/commons_en_US.properties +++ b/backend/framework/sdk/src/main/resources/i18n/commons_en_US.properties @@ -324,7 +324,7 @@ scenario_name_is_null=Scenario name cannot be empty create_user=Create user test_case_status=Case status id_not_rightful=ID is not rightful -tags_count=Tags count can not exceed 15 +tags_count=Tags count can not exceed 10 tag_length=Tag length cannot exceed 64 characters step_length=Step length cannot exceed 1000 characters result_length=Result length cannot exceed 1000 characters diff --git a/backend/framework/sdk/src/main/resources/i18n/commons_zh_CN.properties b/backend/framework/sdk/src/main/resources/i18n/commons_zh_CN.properties index d0930f0a5b..fc01fccc8e 100644 --- a/backend/framework/sdk/src/main/resources/i18n/commons_zh_CN.properties +++ b/backend/framework/sdk/src/main/resources/i18n/commons_zh_CN.properties @@ -325,7 +325,7 @@ test_case_status_saved=已保存 create_user=创建人 test_case_status=用例状态 id_not_rightful=ID 不合法 -tags_count=标签数量不能超过15个 +tags_count=标签数量不能超过10个 tag_length=标签长度不能超过64个字符 step_length=用例步骤不能超过1000个字符 result_length=预期结果不能超过1000个字符 diff --git a/backend/framework/sdk/src/main/resources/i18n/commons_zh_TW.properties b/backend/framework/sdk/src/main/resources/i18n/commons_zh_TW.properties index 09ad968178..2a13d07c2e 100644 --- a/backend/framework/sdk/src/main/resources/i18n/commons_zh_TW.properties +++ b/backend/framework/sdk/src/main/resources/i18n/commons_zh_TW.properties @@ -324,7 +324,7 @@ test_case_status_saved=已保存 create_user=創建人 test_case_status=用例狀態 id_not_rightful=ID 不合法 -tags_count=標簽數量不能超過15個 +tags_count=標簽數量不能超過10個 tag_length=標簽長度不能超過64個字符 step_length=用例步驟長度不能超過1000個字符 result_length=預期結果長度不能超過1000個字符 diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/excel/listener/FunctionalCaseCheckEventListener.java b/backend/services/case-management/src/main/java/io/metersphere/functional/excel/listener/FunctionalCaseCheckEventListener.java index 93f7ea3c4e..1d7bff2845 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/excel/listener/FunctionalCaseCheckEventListener.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/excel/listener/FunctionalCaseCheckEventListener.java @@ -61,7 +61,7 @@ public class FunctionalCaseCheckEventListener extends AnalysisEventListener> errList = new ArrayList<>(); private static final String ERROR_MSG_SEPARATOR = ";"; private HashMap customFieldValidatorMap; - protected static final int TAGS_COUNT = 15; + protected static final int TAGS_COUNT = 10; protected static final int TAG_LENGTH = 64; protected static final int STEP_LENGTH = 1000; private FunctionalCaseService functionalCaseService; diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/excel/listener/FunctionalCaseImportEventListener.java b/backend/services/case-management/src/main/java/io/metersphere/functional/excel/listener/FunctionalCaseImportEventListener.java index 090e79a57a..6db149a349 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/excel/listener/FunctionalCaseImportEventListener.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/excel/listener/FunctionalCaseImportEventListener.java @@ -82,7 +82,7 @@ public class FunctionalCaseImportEventListener extends AnalysisEventListener pathMap = new HashMap<>(); - protected static final int TAGS_COUNT = 15; + protected static final int TAGS_COUNT = 10; protected static final int TAG_LENGTH = 64; private AtomicLong lastPos; diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseMinderService.java b/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseMinderService.java index 9a183f117c..fd662f8763 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseMinderService.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/service/FunctionalCaseMinderService.java @@ -1184,7 +1184,13 @@ public class FunctionalCaseMinderService { } List caseModuleOptionDTOS = resourceMap.get(Translator.get("minder_extra_node.module")); if (CollectionUtils.isNotEmpty(caseModuleOptionDTOS)) { - List moduleIds = caseModuleOptionDTOS.stream().map(MinderOptionDTO::getId).toList(); + List moduleIds = new ArrayList<>(caseModuleOptionDTOS.stream().map(MinderOptionDTO::getId).toList()); + if (moduleIds.contains("NONE")) { + throw new MSException(Translator.get("all.module.default.name.cut_error")); + } + if (moduleIds.contains("root")) { + throw new MSException(Translator.get("functional_case.module.default.name.cut_error")); + } List functionalCases = functionalCaseModuleService.deleteModuleByIds(moduleIds, new ArrayList<>(), userId); functionalCaseModuleService.batchDelLog(functionalCases, request.getProjectId()); List finalCaseIds = caseIds; diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/xmind/parser/XMindCaseParser.java b/backend/services/case-management/src/main/java/io/metersphere/functional/xmind/parser/XMindCaseParser.java index 6f98addfc5..39e131ea6c 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/xmind/parser/XMindCaseParser.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/xmind/parser/XMindCaseParser.java @@ -56,7 +56,7 @@ public class XMindCaseParser { private List moduleTree; private SessionUser user; private Map pathMap = new HashMap<>(); - protected static final int TAGS_COUNT = 15; + protected static final int TAGS_COUNT = 10; protected static final int TAG_LENGTH = 64; protected static final int STEP_LENGTH = 1000; private AtomicLong lastPos; @@ -80,8 +80,8 @@ public class XMindCaseParser { private final List priorityList = Arrays.asList("P0", "P1", "P2", "P3"); - private static final String ID = "(?:id:|id:)"; - private static final String CASE = "(?:CASE-|case-)"; + private static final String ID = "(?:id:|id:|Id:|Id:|iD:|iD:)"; + private static final String CASE = "((?i)case)"; private static final String PREREQUISITE = "(?:" + Translator.get("xmind_prerequisite") + ":|" + Translator.get("xmind_prerequisite") + ":)"; private static final String STEP = "(?:" + Translator.get("xmind_step") + ":|" + Translator.get("xmind_step") + ":)"; private static final String STEP_DESCRIPTION = Translator.get("xmind_stepDescription"); @@ -129,6 +129,10 @@ public class XMindCaseParser { // 格式化一个用例 this.formatTestCase(item.getTitle(), parent.getPath(), item.getChildren() != null ? item.getChildren().getAttached() : null); } else { + if (StringUtils.equalsIgnoreCase(parent.getPath().trim(), Translator.get("functional_case.module.default.name"))) { + process.parse(replace(item.getTitle(), CASE) + ":" + Translator.get("functional_case.module.default.name.add_error")); + return; + } String nodePath = parent.getPath().trim() + "/" + item.getTitle().trim(); item.setPath(nodePath); item.setParent(parent); @@ -250,7 +254,11 @@ public class XMindCaseParser { private boolean validateCustomField(FunctionalCaseExcelData data) { boolean validate = true; Map customData = data.getCustomData(); + boolean hasPriority = false; for (String fieldName : customData.keySet()) { + if (StringUtils.equalsIgnoreCase(fieldName, Translator.get("custom_field.functional_priority"))) { + hasPriority = true; + } Object value = customData.get(fieldName); TemplateCustomFieldDTO templateCustomFieldDTO = customFieldsMap.get(fieldName); if (templateCustomFieldDTO == null) { @@ -268,6 +276,10 @@ public class XMindCaseParser { process.add(data.getName(), e.getMessage()); } } + if (!hasPriority) { + validate = false; + process.add(data.getName(), Translator.get("priority_is_null")); + } return validate; } @@ -307,6 +319,10 @@ public class XMindCaseParser { } // 用例名称 String name = title.replace(tcArrs[0] + ":", StringUtils.EMPTY).replace(tcArrs[0] + ":", StringUtils.EMPTY); + if (name.length()>=255) { + process.add(Translator.get("test_case_name") + Translator.get("length.too.large"), title); + return; + } testCase.setName(name); nodePath = nodePath.trim(); if (!nodePath.startsWith("/")) { @@ -316,22 +332,6 @@ public class XMindCaseParser { nodePath = nodePath.substring(0, nodePath.length() - 1); } testCase.setModule(nodePath); - // 用例等级和用例性质处理 - if (tcArrs[0].contains("-")) { - for (String item : tcArrs[0].split("-")) { - if (item.toUpperCase().startsWith("P")) { - Map customData = new LinkedHashMap<>(); - // 用例等级和用例性质处理 - if (!priorityList.contains(item.toUpperCase())) { - process.add(title, Translator.get("test_case_priority") + Translator.get("incorrect_format")); - customData.put("priority", "P0"); - } else { - customData.put("priority", item.toUpperCase()); - } - testCase.setCustomData(customData); - } - } - } // 用例id, blobs, tags, 自定义字段处理 StringBuilder customId = new StringBuilder(); @@ -346,8 +346,11 @@ public class XMindCaseParser { } else if (isAvailable(item.getTitle(), TEXT_DESCRIPTION)) { testCase.setTextDescription(replace(item.getTitle(), TEXT_DESCRIPTION)); testCase.setCaseEditType(FunctionalCaseTypeConstants.CaseEditType.TEXT.name()); + if (item.getChildren() != null) { + testCase.setExpectedResult(getTextSteps(item.getChildren().getAttached())); + } } else if (isAvailable(item.getTitle(), DESCRIPTION)) { - testCase.setTextDescription(replace(item.getTitle(), DESCRIPTION)); + testCase.setDescription(replace(item.getTitle(), DESCRIPTION)); } else if (isAvailable(item.getTitle(), TAGS)) { String tag = replace(item.getTitle(), TAGS); if (StringUtils.isBlank(tag)) { @@ -366,16 +369,16 @@ public class XMindCaseParser { } } else { //自定义字段 - String[] customFiled = item.getTitle().split("(?::|:)"); + String[] customFiled = item.getTitle().split("(?:\\s*:|:)"); Map stringObjectMap = testCase.getCustomData(); if (customFiled.length > 1) { TemplateCustomFieldDTO templateCustomFieldDTO = customFieldsMap.get(customFiled[0]); - if (templateCustomFieldDTO == null) { - stringObjectMap.put(customFiled[0], customFiled[1]); + if (templateCustomFieldDTO != null) { + stringObjectMap.put(customFiled[0], customFiled[1].replaceAll("^\\s+", "")); } } else { TemplateCustomFieldDTO templateCustomFieldDTO = customFieldsMap.get(customFiled[0]); - if (templateCustomFieldDTO == null) { + if (templateCustomFieldDTO != null) { stringObjectMap.put(customFiled[0], StringUtils.EMPTY); } } @@ -423,6 +426,7 @@ public class XMindCaseParser { } if (functionalCaseStepDTO.getDesc().length() > STEP_LENGTH) { process.add(caseName, Translator.get("step_length")); + functionalCaseStepDTO.setResult(StringUtils.EMPTY); return JSON.toJSONString(functionalCaseStepDTOS); } if (attacheds.get(i) != null && attacheds.get(i).getChildren() != null && attacheds.get(i).getChildren().getAttached() != null) { @@ -435,7 +439,7 @@ public class XMindCaseParser { functionalCaseStepDTO.setResult(StringUtils.EMPTY); } } - if (functionalCaseStepDTO.getResult().length() > STEP_LENGTH) { + if (StringUtils.isNotBlank(functionalCaseStepDTO.getResult()) && functionalCaseStepDTO.getResult().length() > STEP_LENGTH) { process.add(caseName, Translator.get("result_length")); return JSON.toJSONString(functionalCaseStepDTOS); } @@ -452,6 +456,24 @@ public class XMindCaseParser { } return JSON.toJSONString(functionalCaseStepDTOS); } + /** + * 获取步骤数据 + */ + private String getTextSteps(List attacheds) { + if (attacheds.get(0) != null) { + String title = attacheds.get(0).getTitle(); + if (isAvailable(title, EXPECTED_RESULT)) { + String stepDesc = title.replace(":", ":"); + String[] stepDescArrs = stepDesc.split(":"); + return StringUtils.isNotBlank(stepDescArrs[1]) ? stepDescArrs[1] : StringUtils.EMPTY; + } else { + return StringUtils.EMPTY; + } + } else { + return StringUtils.EMPTY; + } + + } /** * 导入思维导图处理 @@ -469,6 +491,9 @@ public class XMindCaseParser { return process.parse(replace(item.getTitle(), CASE) + ":" + Translator.get("test_case_create_module_fail")); } else { String modulePath = item.getTitle(); + if (StringUtils.isBlank(modulePath)) { + return process.parse(replace(item.getTitle(), CASE) + ":" + Translator.get("module_not_null")); + } item.setPath(modulePath); if (item.getChildren() != null && !item.getChildren().getAttached().isEmpty()) { // 递归处理案例数据 diff --git a/backend/services/case-management/src/main/java/io/metersphere/functional/xmind/parser/XMindParser.java b/backend/services/case-management/src/main/java/io/metersphere/functional/xmind/parser/XMindParser.java index f31e1c1991..ed2645c864 100644 --- a/backend/services/case-management/src/main/java/io/metersphere/functional/xmind/parser/XMindParser.java +++ b/backend/services/case-management/src/main/java/io/metersphere/functional/xmind/parser/XMindParser.java @@ -66,7 +66,7 @@ public class XMindParser { List jsonRootBeans = new ArrayList<>(); if (contents != null) { for (String content : contents) { - caseCount += content.split("(?:case-|CASE-)").length; + caseCount += content.split("((?i)case)").length; JsonRootBean jsonRootBean = JSON.parseObject(content, JsonRootBean.class); jsonRootBeans.add(jsonRootBean); } diff --git a/backend/services/case-management/src/test/resources/file/2module.xmind b/backend/services/case-management/src/test/resources/file/2module.xmind index 0941716de3..f9f7bc5fef 100644 Binary files a/backend/services/case-management/src/test/resources/file/2module.xmind and b/backend/services/case-management/src/test/resources/file/2module.xmind differ diff --git a/backend/services/case-management/src/test/resources/file/3erro.xmind b/backend/services/case-management/src/test/resources/file/3erro.xmind index 51f7b7a703..ba619a4b2c 100644 Binary files a/backend/services/case-management/src/test/resources/file/3erro.xmind and b/backend/services/case-management/src/test/resources/file/3erro.xmind differ