Skip to content
This repository was archived by the owner on Dec 4, 2025. It is now read-only.

Commit d6e42e9

Browse files
authored
Merge pull request #1130 from linwumingshi/fix/issue-1129
fix(util): 🐛 improve parameter parsing logic
2 parents 761e9c6 + 4586a73 commit d6e42e9

File tree

3 files changed

+178
-8
lines changed

3 files changed

+178
-8
lines changed

pom.xml

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@
3737
<java.version>1.8</java.version>
3838
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
3939
<junit.jupiter.version>5.13.4</junit.jupiter.version>
40-
<beetl.version>3.19.2.RELEASE</beetl.version>
40+
<mockito.version>4.11.0</mockito.version>
41+
<beetl.version>3.19.2.RELEASE</beetl.version>
4142
<common-util.version>2.2.9</common-util.version>
4243
<qdox.version>2.0.3.5</qdox.version>
4344
<datafaker.version>1.9.0</datafaker.version>
@@ -61,6 +62,12 @@
6162
<version>${junit.jupiter.version}</version>
6263
<scope>test</scope>
6364
</dependency>
65+
<dependency>
66+
<groupId>org.mockito</groupId>
67+
<artifactId>mockito-junit-jupiter</artifactId>
68+
<version>${mockito.version}</version>
69+
<scope>test</scope>
70+
</dependency>
6471
<dependency>
6572
<groupId>com.ibeetl</groupId>
6673
<artifactId>beetl</artifactId>

src/main/java/com/ly/doc/utils/DocUtil.java

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (C) 2018-2024 smart-doc
2+
* Copyright (C) 2018-2025 smart-doc
33
*
44
* Licensed to the Apache Software Foundation (ASF) under one
55
* or more contributor license agreements. See the NOTICE file
@@ -18,6 +18,7 @@
1818
* specific language governing permissions and limitations
1919
* under the License.
2020
*/
21+
2122
package com.ly.doc.utils;
2223

2324
import com.ly.doc.builder.WordDocBuilder;
@@ -745,12 +746,27 @@ private static Map<String, String> getCommentsByTag(List<DocletTag> paramTags, f
745746
if (DocTags.PARAM.equals(tagName) || DocTags.EXTENSION.equals(tagName)) {
746747
String pName = value;
747748
String pValue = DocGlobalConstants.NO_COMMENTS_FOUND;
748-
int idx = value.indexOf(" ");
749-
// existed \n
750-
if (idx > -1) {
751-
pName = value.substring(0, idx);
752-
pValue = value.substring(idx + 1);
749+
750+
// Fixed #1129
751+
// Split the value by the first sequence of whitespace
752+
// (space,newline,tab, etc.) only into two parts.
753+
String[] parts = value.trim().split("\\s+", 2);
754+
// Successfully split into parameter name and description
755+
if (parts.length == 2) {
756+
// Parameter name
757+
pName = parts[0];
758+
// Description, preserving internal newlines and formatting
759+
pValue = parts[1];
753760
}
761+
// Only one part found, likely just the parameter name
762+
// without a description, OR an empty/whitespace-only value after trim
763+
else if (parts.length == 1) {
764+
// Covers both "paramName" and "" cases
765+
// pValue remains DocGlobalConstants.NO_COMMENTS_FOUND
766+
// Set pName based on whether the single part is empty
767+
pName = parts[0];
768+
}
769+
754770
if ("|".equals(StringUtil.trim(pValue)) && StringUtil.isNotEmpty(className)) {
755771
throw new RuntimeException(tagValErrorMsg);
756772
}

src/test/java/com/ly/doc/util/DocUtilTest.java

Lines changed: 148 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,45 @@
11
package com.ly.doc.util;
22

33
import com.ly.doc.constants.DocGlobalConstants;
4+
import com.ly.doc.constants.DocLanguage;
5+
import com.ly.doc.constants.DocTags;
46
import com.ly.doc.enums.IEnum;
57
import com.ly.doc.enums.OrderEnum;
68
import com.ly.doc.utils.DocUtil;
7-
import com.ly.doc.constants.DocLanguage;
9+
import com.thoughtworks.qdox.model.DocletTag;
810
import org.junit.jupiter.api.Test;
11+
import org.mockito.Mockito;
912

13+
import java.util.Arrays;
14+
import java.util.Collections;
1015
import java.util.HashMap;
1116
import java.util.List;
1217
import java.util.Map;
1318

19+
import static org.junit.jupiter.api.Assertions.assertEquals;
20+
import static org.junit.jupiter.api.Assertions.assertTrue;
21+
import static org.mockito.Mockito.when;
22+
1423
/**
1524
* @author yu 2018/12/10.
1625
*/
1726
public class DocUtilTest {
1827

28+
/**
29+
* Assuming DocTags.PARAM is "param"
30+
*/
31+
private static final String TAG_NAME_PARAM = DocTags.PARAM;
32+
33+
/**
34+
* Assuming DocTags.EXTENSION is "extension"
35+
*/
36+
private static final String TAG_NAME_EXTENSION = DocTags.EXTENSION;
37+
38+
/**
39+
* Assuming DocGlobalConstants.NO_COMMENTS_FOUND
40+
*/
41+
private static final String NO_COMMENTS_FOUND = DocGlobalConstants.NO_COMMENTS_FOUND;
42+
1943
@Test
2044
public void test() {
2145
System.setProperty(DocGlobalConstants.DOC_LANGUAGE, DocLanguage.CHINESE.getCode());
@@ -80,4 +104,127 @@ public void testReplaceGenericParameter() {
80104
System.out.println(result); // Output: com.Test<List<Use
81105
}
82106

107+
// Helper method to create a mock DocletTag
108+
private DocletTag createMockTag(String value) {
109+
DocletTag mockTag = Mockito.mock(DocletTag.class);
110+
when(mockTag.getValue()).thenReturn(value);
111+
return mockTag;
112+
}
113+
114+
@Test
115+
public void testGetCommentsByTag_ParamWithNewlines() {
116+
// Scenario 1: Normal case - param name and description on same line
117+
DocletTag tag1 = createMockTag("id user identifier");
118+
// Scenario 2: Description starts on a new line with indentation
119+
DocletTag tag2 = createMockTag("name\n user's full name");
120+
// Scenario 3: Description has multiple newlines and complex formatting
121+
DocletTag tag3 = createMockTag(
122+
"age user's age in years\n Default is 25.\n NOTE: Must be > 0.");
123+
// Scenario 4: Only parameter name, no description
124+
DocletTag tag4 = createMockTag("flag");
125+
// Scenario 5: Parameter name with leading/trailing whitespace in the raw value
126+
// part that's not the name itself
127+
DocletTag tag5 = createMockTag(" email user's email address ");
128+
// Scenario 6: Description starts immediately after parameter name WITH A SPACE
129+
// (Standard Javadoc format)
130+
DocletTag tag6 = createMockTag("status Active user status flag");
131+
// Scenario 7: Description contains leading whitespace after the parameter name
132+
DocletTag tag7 = createMockTag("count Number of items to retrieve");
133+
134+
List<DocletTag> tags = Arrays.asList(tag1, tag2, tag3, tag4, tag5, tag6, tag7);
135+
136+
Map<String, String> result = DocUtil.getCommentsByTag(tags, TAG_NAME_PARAM);
137+
138+
// Verify results
139+
assertEquals("user identifier", result.get("id"), "Scenario 1: Description should be 'user identifier'");
140+
assertEquals("user's full name", result.get("name"),
141+
"Scenario 2: Description should be 'user's full name', preserving content after newline.");
142+
assertEquals("user's age in years\n Default is 25.\n NOTE: Must be > 0.",
143+
result.get("age"), "Scenario 3: Description should preserve newlines and formatting.");
144+
assertEquals(NO_COMMENTS_FOUND, result.get("flag"), "Scenario 4: Should return NO_COMMENTS_FOUND for 'flag'");
145+
assertEquals("user's email address", result.get("email"),
146+
"Scenario 5: Name should be 'email', description should be 'user's email address'");
147+
assertEquals("Active user status flag", result.get("status"),
148+
"Scenario 6: Description should be 'Active user status flag'");
149+
assertEquals("Number of items to retrieve", result.get("count"),
150+
"Scenario 7: Description should be 'Number of items to retrieve'");
151+
152+
}
153+
154+
@Test
155+
public void testGetCommentsByTag_ExtensionWithNewlines() {
156+
// Similar scenarios for @extension
157+
DocletTag tag1 = createMockTag("extId extension identifier");
158+
DocletTag tag2 = createMockTag("extName\n extension name");
159+
DocletTag tag3 = createMockTag("extConfig extension configuration details\n with multiple lines.");
160+
DocletTag tag4 = createMockTag("extFlag");
161+
162+
List<DocletTag> tags = Arrays.asList(tag1, tag2, tag3, tag4);
163+
164+
Map<String, String> result = DocUtil.getCommentsByTag(tags, TAG_NAME_EXTENSION);
165+
166+
// Verify results
167+
assertEquals("extension identifier", result.get("extId"));
168+
assertEquals("extension name", result.get("extName"));
169+
assertEquals("extension configuration details\n with multiple lines.", result.get("extConfig"));
170+
assertEquals(NO_COMMENTS_FOUND, result.get("extFlag"));
171+
}
172+
173+
@Test
174+
public void testGetCommentsByTag_ParamWithCarriageReturn() {
175+
// Scenario: Description has Windows-style CRLF (\r\n)
176+
String valueWithCRLF = "token\r\n Authentication token,\r\n required for access.";
177+
DocletTag tag = createMockTag(valueWithCRLF);
178+
179+
List<DocletTag> tags = Collections.singletonList(tag);
180+
Map<String, String> result = DocUtil.getCommentsByTag(tags, TAG_NAME_PARAM);
181+
182+
assertEquals("Authentication token,\r\n required for access.", result.get("token"),
183+
"Should handle CRLF correctly, preserving the newline and content.");
184+
}
185+
186+
@Test
187+
public void testGetCommentsByTag_ParamOnlyName() {
188+
// Scenario: Only parameter name exists, no space/description
189+
DocletTag tag = createMockTag("justParamName");
190+
List<DocletTag> tags = Collections.singletonList(tag);
191+
Map<String, String> result = DocUtil.getCommentsByTag(tags, TAG_NAME_PARAM);
192+
193+
assertEquals(NO_COMMENTS_FOUND, result.get("justParamName"),
194+
"Should return NO_COMMENTS_FOUND for 'justParamName'");
195+
}
196+
197+
@Test
198+
public void testGetCommentsByTag_ParamEmptyValue() {
199+
// Scenario: Empty value string
200+
DocletTag tag = createMockTag("");
201+
List<DocletTag> tags = Collections.singletonList(tag);
202+
Map<String, String> result = DocUtil.getCommentsByTag(tags, TAG_NAME_PARAM);
203+
204+
// An empty string after trim results in [""], so parts[0] is "", and parts.length
205+
// is 1.
206+
// The logic assigns pName = parts[0] (which is ""), and pValue remains the
207+
// default NO_COMMENTS_FOUND.
208+
// The map.put(pName.trim(), pValue) effectively does map.put("",
209+
// NO_COMMENTS_FOUND).
210+
assertEquals(NO_COMMENTS_FOUND, result.get(""), // 修正 NO_COMMENTS_FOUND 的值
211+
"Should handle empty value, key should be empty string.");
212+
assertTrue(result.containsKey(""), "Map should contain an entry with an empty string key.");
213+
}
214+
215+
@Test
216+
public void testGetCommentsByTag_ParamWhitespaceOnlyValue() {
217+
// Scenario: Value is only whitespace
218+
DocletTag tag = createMockTag(" \t \n ");
219+
List<DocletTag> tags = Collections.singletonList(tag);
220+
Map<String, String> result = DocUtil.getCommentsByTag(tags, TAG_NAME_PARAM);
221+
222+
// Whitespace-only string after trim becomes "", same as empty value scenario.
223+
// After trim and split, pName should be "" and pValue should be
224+
// NO_COMMENTS_FOUND.
225+
assertEquals(NO_COMMENTS_FOUND, result.get(""),
226+
"Should handle whitespace-only value, key should be empty string.");
227+
assertTrue(result.containsKey(""), "Map should contain an entry with an empty string key.");
228+
}
229+
83230
}

0 commit comments

Comments
 (0)