diff --git a/pom.xml b/pom.xml index 3108a575a..4ed093d52 100644 --- a/pom.xml +++ b/pom.xml @@ -37,7 +37,8 @@ 1.8 UTF-8 5.13.4 - 3.19.2.RELEASE + 4.11.0 + 3.19.2.RELEASE 2.2.9 2.0.3.5 1.9.0 @@ -61,6 +62,12 @@ ${junit.jupiter.version} test + + org.mockito + mockito-junit-jupiter + ${mockito.version} + test + com.ibeetl beetl diff --git a/src/main/java/com/ly/doc/utils/DocUtil.java b/src/main/java/com/ly/doc/utils/DocUtil.java index 1945aab77..6ac6371f2 100644 --- a/src/main/java/com/ly/doc/utils/DocUtil.java +++ b/src/main/java/com/ly/doc/utils/DocUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018-2024 smart-doc + * Copyright (C) 2018-2025 smart-doc * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -18,6 +18,7 @@ * specific language governing permissions and limitations * under the License. */ + package com.ly.doc.utils; import com.ly.doc.builder.WordDocBuilder; @@ -745,12 +746,27 @@ private static Map getCommentsByTag(List paramTags, f if (DocTags.PARAM.equals(tagName) || DocTags.EXTENSION.equals(tagName)) { String pName = value; String pValue = DocGlobalConstants.NO_COMMENTS_FOUND; - int idx = value.indexOf(" "); - // existed \n - if (idx > -1) { - pName = value.substring(0, idx); - pValue = value.substring(idx + 1); + + // Fixed #1129 + // Split the value by the first sequence of whitespace + // (space,newline,tab, etc.) only into two parts. + String[] parts = value.trim().split("\\s+", 2); + // Successfully split into parameter name and description + if (parts.length == 2) { + // Parameter name + pName = parts[0]; + // Description, preserving internal newlines and formatting + pValue = parts[1]; } + // Only one part found, likely just the parameter name + // without a description, OR an empty/whitespace-only value after trim + else if (parts.length == 1) { + // Covers both "paramName" and "" cases + // pValue remains DocGlobalConstants.NO_COMMENTS_FOUND + // Set pName based on whether the single part is empty + pName = parts[0]; + } + if ("|".equals(StringUtil.trim(pValue)) && StringUtil.isNotEmpty(className)) { throw new RuntimeException(tagValErrorMsg); } diff --git a/src/test/java/com/ly/doc/util/DocUtilTest.java b/src/test/java/com/ly/doc/util/DocUtilTest.java index f444faee0..28c81ec6e 100644 --- a/src/test/java/com/ly/doc/util/DocUtilTest.java +++ b/src/test/java/com/ly/doc/util/DocUtilTest.java @@ -1,21 +1,45 @@ package com.ly.doc.util; import com.ly.doc.constants.DocGlobalConstants; +import com.ly.doc.constants.DocLanguage; +import com.ly.doc.constants.DocTags; import com.ly.doc.enums.IEnum; import com.ly.doc.enums.OrderEnum; import com.ly.doc.utils.DocUtil; -import com.ly.doc.constants.DocLanguage; +import com.thoughtworks.qdox.model.DocletTag; import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.when; + /** * @author yu 2018/12/10. */ public class DocUtilTest { + /** + * Assuming DocTags.PARAM is "param" + */ + private static final String TAG_NAME_PARAM = DocTags.PARAM; + + /** + * Assuming DocTags.EXTENSION is "extension" + */ + private static final String TAG_NAME_EXTENSION = DocTags.EXTENSION; + + /** + * Assuming DocGlobalConstants.NO_COMMENTS_FOUND + */ + private static final String NO_COMMENTS_FOUND = DocGlobalConstants.NO_COMMENTS_FOUND; + @Test public void test() { System.setProperty(DocGlobalConstants.DOC_LANGUAGE, DocLanguage.CHINESE.getCode()); @@ -80,4 +104,127 @@ public void testReplaceGenericParameter() { System.out.println(result); // Output: com.Test 0."); + // Scenario 4: Only parameter name, no description + DocletTag tag4 = createMockTag("flag"); + // Scenario 5: Parameter name with leading/trailing whitespace in the raw value + // part that's not the name itself + DocletTag tag5 = createMockTag(" email user's email address "); + // Scenario 6: Description starts immediately after parameter name WITH A SPACE + // (Standard Javadoc format) + DocletTag tag6 = createMockTag("status Active user status flag"); + // Scenario 7: Description contains leading whitespace after the parameter name + DocletTag tag7 = createMockTag("count Number of items to retrieve"); + + List tags = Arrays.asList(tag1, tag2, tag3, tag4, tag5, tag6, tag7); + + Map result = DocUtil.getCommentsByTag(tags, TAG_NAME_PARAM); + + // Verify results + assertEquals("user identifier", result.get("id"), "Scenario 1: Description should be 'user identifier'"); + assertEquals("user's full name", result.get("name"), + "Scenario 2: Description should be 'user's full name', preserving content after newline."); + assertEquals("user's age in years\n Default is 25.\n NOTE: Must be > 0.", + result.get("age"), "Scenario 3: Description should preserve newlines and formatting."); + assertEquals(NO_COMMENTS_FOUND, result.get("flag"), "Scenario 4: Should return NO_COMMENTS_FOUND for 'flag'"); + assertEquals("user's email address", result.get("email"), + "Scenario 5: Name should be 'email', description should be 'user's email address'"); + assertEquals("Active user status flag", result.get("status"), + "Scenario 6: Description should be 'Active user status flag'"); + assertEquals("Number of items to retrieve", result.get("count"), + "Scenario 7: Description should be 'Number of items to retrieve'"); + + } + + @Test + public void testGetCommentsByTag_ExtensionWithNewlines() { + // Similar scenarios for @extension + DocletTag tag1 = createMockTag("extId extension identifier"); + DocletTag tag2 = createMockTag("extName\n extension name"); + DocletTag tag3 = createMockTag("extConfig extension configuration details\n with multiple lines."); + DocletTag tag4 = createMockTag("extFlag"); + + List tags = Arrays.asList(tag1, tag2, tag3, tag4); + + Map result = DocUtil.getCommentsByTag(tags, TAG_NAME_EXTENSION); + + // Verify results + assertEquals("extension identifier", result.get("extId")); + assertEquals("extension name", result.get("extName")); + assertEquals("extension configuration details\n with multiple lines.", result.get("extConfig")); + assertEquals(NO_COMMENTS_FOUND, result.get("extFlag")); + } + + @Test + public void testGetCommentsByTag_ParamWithCarriageReturn() { + // Scenario: Description has Windows-style CRLF (\r\n) + String valueWithCRLF = "token\r\n Authentication token,\r\n required for access."; + DocletTag tag = createMockTag(valueWithCRLF); + + List tags = Collections.singletonList(tag); + Map result = DocUtil.getCommentsByTag(tags, TAG_NAME_PARAM); + + assertEquals("Authentication token,\r\n required for access.", result.get("token"), + "Should handle CRLF correctly, preserving the newline and content."); + } + + @Test + public void testGetCommentsByTag_ParamOnlyName() { + // Scenario: Only parameter name exists, no space/description + DocletTag tag = createMockTag("justParamName"); + List tags = Collections.singletonList(tag); + Map result = DocUtil.getCommentsByTag(tags, TAG_NAME_PARAM); + + assertEquals(NO_COMMENTS_FOUND, result.get("justParamName"), + "Should return NO_COMMENTS_FOUND for 'justParamName'"); + } + + @Test + public void testGetCommentsByTag_ParamEmptyValue() { + // Scenario: Empty value string + DocletTag tag = createMockTag(""); + List tags = Collections.singletonList(tag); + Map result = DocUtil.getCommentsByTag(tags, TAG_NAME_PARAM); + + // An empty string after trim results in [""], so parts[0] is "", and parts.length + // is 1. + // The logic assigns pName = parts[0] (which is ""), and pValue remains the + // default NO_COMMENTS_FOUND. + // The map.put(pName.trim(), pValue) effectively does map.put("", + // NO_COMMENTS_FOUND). + assertEquals(NO_COMMENTS_FOUND, result.get(""), // 修正 NO_COMMENTS_FOUND 的值 + "Should handle empty value, key should be empty string."); + assertTrue(result.containsKey(""), "Map should contain an entry with an empty string key."); + } + + @Test + public void testGetCommentsByTag_ParamWhitespaceOnlyValue() { + // Scenario: Value is only whitespace + DocletTag tag = createMockTag(" \t \n "); + List tags = Collections.singletonList(tag); + Map result = DocUtil.getCommentsByTag(tags, TAG_NAME_PARAM); + + // Whitespace-only string after trim becomes "", same as empty value scenario. + // After trim and split, pName should be "" and pValue should be + // NO_COMMENTS_FOUND. + assertEquals(NO_COMMENTS_FOUND, result.get(""), + "Should handle whitespace-only value, key should be empty string."); + assertTrue(result.containsKey(""), "Map should contain an entry with an empty string key."); + } + }