1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle.internal;
21
22 import static com.google.common.truth.Truth.assertWithMessage;
23 import static com.puppycrawl.tools.checkstyle.site.SiteUtil.SINCE_VERSION;
24
25 import java.io.File;
26 import java.net.URI;
27 import java.nio.file.Files;
28 import java.nio.file.Path;
29 import java.util.ArrayList;
30 import java.util.HashMap;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.regex.Pattern;
34
35 import javax.xml.parsers.ParserConfigurationException;
36
37 import org.junit.jupiter.api.BeforeEach;
38 import org.junit.jupiter.api.Test;
39 import org.w3c.dom.Document;
40 import org.w3c.dom.NamedNodeMap;
41 import org.w3c.dom.Node;
42 import org.w3c.dom.NodeList;
43
44 import com.google.common.collect.ImmutableMap;
45 import com.puppycrawl.tools.checkstyle.AbstractModuleTestSupport;
46 import com.puppycrawl.tools.checkstyle.Checker;
47 import com.puppycrawl.tools.checkstyle.DefaultConfiguration;
48 import com.puppycrawl.tools.checkstyle.ModuleFactory;
49 import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
50 import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
51 import com.puppycrawl.tools.checkstyle.api.DetailAST;
52 import com.puppycrawl.tools.checkstyle.api.Scope;
53 import com.puppycrawl.tools.checkstyle.api.SeverityLevel;
54 import com.puppycrawl.tools.checkstyle.api.TokenTypes;
55 import com.puppycrawl.tools.checkstyle.checks.LineSeparatorOption;
56 import com.puppycrawl.tools.checkstyle.checks.annotation.AnnotationUseStyleCheck;
57 import com.puppycrawl.tools.checkstyle.checks.blocks.BlockOption;
58 import com.puppycrawl.tools.checkstyle.checks.blocks.LeftCurlyOption;
59 import com.puppycrawl.tools.checkstyle.checks.blocks.RightCurlyOption;
60 import com.puppycrawl.tools.checkstyle.checks.imports.ImportOrderOption;
61 import com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocContentLocationOption;
62 import com.puppycrawl.tools.checkstyle.checks.javadoc.MissingJavadocMethodCheck;
63 import com.puppycrawl.tools.checkstyle.checks.naming.AccessModifierOption;
64 import com.puppycrawl.tools.checkstyle.checks.whitespace.PadOption;
65 import com.puppycrawl.tools.checkstyle.checks.whitespace.WrapOption;
66 import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
67 import com.puppycrawl.tools.checkstyle.internal.utils.XdocUtil;
68 import com.puppycrawl.tools.checkstyle.internal.utils.XmlUtil;
69 import com.puppycrawl.tools.checkstyle.site.PropertiesMacro;
70 import com.puppycrawl.tools.checkstyle.utils.JavadocUtil;
71 import com.puppycrawl.tools.checkstyle.utils.ScopeUtil;
72 import com.puppycrawl.tools.checkstyle.utils.TokenUtil;
73
74 public class XdocsJavaDocsTest extends AbstractModuleTestSupport {
75 private static final Map<String, Class<?>> FULLY_QUALIFIED_CLASS_NAMES =
76 ImmutableMap.<String, Class<?>>builder()
77 .put("int", int.class)
78 .put("int[]", int[].class)
79 .put("boolean", boolean.class)
80 .put("double", double.class)
81 .put("double[]", double[].class)
82 .put("String", String.class)
83 .put("String[]", String[].class)
84 .put("Pattern", Pattern.class)
85 .put("Pattern[]", Pattern[].class)
86 .put("AccessModifierOption[]", AccessModifierOption[].class)
87 .put("BlockOption", BlockOption.class)
88 .put("ClosingParensOption", AnnotationUseStyleCheck.ClosingParensOption.class)
89 .put("ElementStyleOption", AnnotationUseStyleCheck.ElementStyleOption.class)
90 .put("File", File.class)
91 .put("ImportOrderOption", ImportOrderOption.class)
92 .put("JavadocContentLocationOption", JavadocContentLocationOption.class)
93 .put("LeftCurlyOption", LeftCurlyOption.class)
94 .put("LineSeparatorOption", LineSeparatorOption.class)
95 .put("PadOption", PadOption.class)
96 .put("RightCurlyOption", RightCurlyOption.class)
97 .put("Scope", Scope.class)
98 .put("SeverityLevel", SeverityLevel.class)
99 .put("TrailingArrayCommaOption", AnnotationUseStyleCheck.TrailingArrayCommaOption.class)
100 .put("URI", URI.class)
101 .put("WrapOption", WrapOption.class)
102 .put("PARAM_LITERAL", int[].class).build();
103
104 private static final List<List<Node>> CHECK_PROPERTIES = new ArrayList<>();
105 private static final Map<String, String> CHECK_PROPERTY_DOC = new HashMap<>();
106 private static final Map<String, String> CHECK_TEXT = new HashMap<>();
107
108 private static Checker checker;
109
110 private static String checkName;
111
112 private static Path currentXdocPath;
113
114 @Override
115 protected String getPackageLocation() {
116 return "com.puppycrawl.tools.checkstyle.internal";
117 }
118
119 @BeforeEach
120 public void setUp() throws Exception {
121 final DefaultConfiguration checkConfig = new DefaultConfiguration(
122 JavaDocCapture.class.getName());
123 checker = createChecker(checkConfig);
124 }
125
126 @Test
127 public void testAllCheckSectionJavaDocs() throws Exception {
128 final ModuleFactory moduleFactory = TestUtil.getPackageObjectFactory();
129
130 for (Path path : XdocUtil.getXdocsConfigFilePaths(XdocUtil.getXdocsFilePaths())) {
131 currentXdocPath = path;
132 final File file = path.toFile();
133 final String fileName = file.getName();
134
135 if (XdocsPagesTest.isNonModulePage(fileName)) {
136 continue;
137 }
138
139 final String input = Files.readString(path);
140 final Document document = XmlUtil.getRawXml(fileName, input, input);
141 final NodeList sources = document.getElementsByTagName("section");
142
143 for (int position = 0; position < sources.getLength(); position++) {
144 final Node section = sources.item(position);
145 final String sectionName = XmlUtil.getNameAttributeOfNode(section);
146
147 if ("Content".equals(sectionName) || "Overview".equals(sectionName)) {
148 continue;
149 }
150
151 assertCheckSection(moduleFactory, fileName, sectionName, section);
152 }
153 }
154 }
155
156 private static void assertCheckSection(ModuleFactory moduleFactory, String fileName,
157 String sectionName, Node section) throws Exception {
158 final Object instance;
159
160 try {
161 instance = moduleFactory.createModule(sectionName);
162 }
163 catch (CheckstyleException exc) {
164 throw new CheckstyleException(fileName + " couldn't find class: " + sectionName, exc);
165 }
166
167 CHECK_TEXT.clear();
168 CHECK_PROPERTIES.clear();
169 CHECK_PROPERTY_DOC.clear();
170 checkName = sectionName;
171
172 assertCheckSectionChildren(section);
173
174 final List<File> files = new ArrayList<>();
175 files.add(new File("src/main/java/" + instance.getClass().getName().replace(".", "/")
176 + ".java"));
177
178 checker.process(files);
179 }
180
181 private static void assertCheckSectionChildren(Node section) {
182 for (Node subSection : XmlUtil.getChildrenElements(section)) {
183 if (!"subsection".equals(subSection.getNodeName())) {
184 final String text = getNodeText(subSection);
185 if (text.startsWith("Since Checkstyle")) {
186 CHECK_TEXT.put("since", text.substring(17));
187 }
188 continue;
189 }
190
191 final String subSectionName = XmlUtil.getNameAttributeOfNode(subSection);
192
193 examineCheckSubSection(subSection, subSectionName);
194 }
195 }
196
197 private static void examineCheckSubSection(Node subSection, String subSectionName) {
198 switch (subSectionName) {
199 case "Description":
200 case "Examples":
201 case "Notes":
202 case "Rule Description":
203 CHECK_TEXT.put(subSectionName, getNodeText(subSection).replace("\r", ""));
204 break;
205 case "Properties":
206 populateProperties(subSection);
207 CHECK_TEXT.put(subSectionName, createPropertiesText());
208 break;
209 case "Example of Usage":
210 case "Violation Messages":
211 CHECK_TEXT.put(subSectionName,
212 createViolationMessagesText(getViolationMessages(subSection)));
213 break;
214 case "Package":
215 case "Parent Module":
216 CHECK_TEXT.put(subSectionName, createParentText(subSection));
217 break;
218 default:
219 break;
220 }
221 }
222
223 private static List<String> getViolationMessages(Node subsection) {
224 final Node child = XmlUtil.getFirstChildElement(subsection);
225 final List<String> violationMessages = new ArrayList<>();
226 for (Node row : XmlUtil.getChildrenElements(child)) {
227 violationMessages.add(row.getTextContent().trim());
228 }
229 return violationMessages;
230 }
231
232 private static String createViolationMessagesText(List<String> violationMessages) {
233 final StringBuilder result = new StringBuilder(100);
234 result.append("\n<p>\nViolation Message Keys:\n</p>\n<ul>");
235
236 for (String msg : violationMessages) {
237 result.append("\n<li>\n{@code ").append(msg).append("}\n</li>");
238 }
239
240 result.append("\n</ul>");
241 return result.toString();
242 }
243
244 private static String createParentText(Node subsection) {
245 return "\n<p>\nParent is {@code com.puppycrawl.tools.checkstyle."
246 + XmlUtil.getFirstChildElement(subsection).getTextContent().trim() + "}\n</p>";
247 }
248
249 private static void populateProperties(Node subSection) {
250 boolean skip = true;
251
252
253
254
255 Node child = XmlUtil.getFirstChildElement(subSection);
256 if (child.hasAttributes() && child.getAttributes().getNamedItem("class") != null
257 && "wrapper".equals(child.getAttributes().getNamedItem("class")
258 .getTextContent())) {
259 child = XmlUtil.getFirstChildElement(child);
260 }
261 for (Node row : XmlUtil.getChildrenElements(child)) {
262 if (skip) {
263 skip = false;
264 continue;
265 }
266 CHECK_PROPERTIES.add(new ArrayList<>(XmlUtil.getChildrenElements(row)));
267 }
268 }
269
270 private static String createPropertiesText() {
271 final StringBuilder result = new StringBuilder(100);
272
273 result.append("\n<ul>");
274
275 for (List<Node> property : CHECK_PROPERTIES) {
276 final String propertyName = getNodeText(property.get(0));
277
278 result.append("\n<li>\nProperty {@code ");
279 result.append(propertyName);
280 result.append("} - ");
281
282 final String temp = getNodeText(property.get(1));
283
284 result.append(temp);
285 CHECK_PROPERTY_DOC.put(propertyName, temp);
286
287 String typeText = "java.lang.String[]";
288 final String propertyType = property.get(2).getTextContent();
289 final boolean isSpecialAllTokensType = propertyType.contains("set of any supported");
290 final boolean isPropertyTokenType = isSpecialAllTokensType
291 || propertyType.contains("subset of tokens")
292 || propertyType.contains("subset of javadoc tokens");
293 if (!isPropertyTokenType) {
294 final String typeName =
295 getCorrectNodeBasedOnPropertyType(property).getTextContent().trim();
296 typeText = FULLY_QUALIFIED_CLASS_NAMES.get(typeName).getTypeName();
297 }
298 if (isSpecialAllTokensType) {
299 typeText = "anyTokenTypesSet";
300 }
301 result.append(" Type is {@code ").append(typeText).append("}.");
302
303 if (!isSpecialAllTokensType) {
304 final String validationType = getValidationType(isPropertyTokenType, propertyName);
305 if (validationType != null) {
306 result.append(validationType);
307 }
308 }
309
310 result.append(getDefaultValueOfType(propertyName, isSpecialAllTokensType));
311
312 result.append(emptyStringArrayDefaultValue(property.get(3), isPropertyTokenType));
313
314 if (result.charAt(result.length() - 1) != '.') {
315 result.append('.');
316 }
317
318 result.append("\n</li>");
319 }
320
321 result.append("\n</ul>");
322
323 return result.toString();
324 }
325
326 private static Node getCorrectNodeBasedOnPropertyType(List<Node> property) {
327 final Node result;
328 if (property.get(2).getFirstChild().getFirstChild() == null) {
329 result = property.get(2).getFirstChild().getNextSibling();
330 }
331 else {
332 result = property.get(2).getFirstChild().getFirstChild();
333 }
334 return result;
335 }
336
337 private static String getDefaultValueOfType(String propertyName,
338 boolean isSpecialAllTokensType) {
339 final String result;
340 if (!isSpecialAllTokensType
341 && (propertyName.endsWith("token") || propertyName.endsWith(
342 "tokens"))) {
343 result = " Default value is: ";
344 }
345 else {
346 result = " Default value is ";
347 }
348 return result;
349 }
350
351 private static String getValidationType(boolean isPropertyTokenType, String propertyName) {
352 String result = null;
353 if (PropertiesMacro.NON_BASE_TOKEN_PROPERTIES.contains(checkName + " - " + propertyName)) {
354 result = " Validation type is {@code tokenTypesSet}.";
355 }
356 else if (isPropertyTokenType) {
357 result = " Validation type is {@code tokenSet}.";
358 }
359 return result;
360 }
361
362 private static String emptyStringArrayDefaultValue(Node defaultValueNode,
363 boolean isPropertyTokenType) {
364 String defaultValueText = getNodeText(defaultValueNode);
365 if ("{@code {}}".equals(defaultValueText)
366 || "{@code all files}".equals(defaultValueText)
367 || isPropertyTokenType && "{@code empty}".equals(defaultValueText)) {
368 defaultValueText = "{@code \"\"}";
369 }
370 return defaultValueText;
371 }
372
373 private static String getNodeText(Node node) {
374 final StringBuilder result = new StringBuilder(20);
375
376 for (Node child = node.getFirstChild(); child != null; child = child.getNextSibling()) {
377 if (child.getNodeType() == Node.TEXT_NODE) {
378 for (String temp : child.getTextContent().split("\n")) {
379 final String text = temp.trim();
380
381 if (!text.isEmpty()) {
382 if (shouldAppendSpace(result, text.charAt(0))) {
383 result.append(' ');
384 }
385
386 result.append(text);
387 }
388 }
389 }
390 else {
391 if (child.hasAttributes() && child.getAttributes().getNamedItem("class") != null
392 && "wrapper".equals(child.getAttributes().getNamedItem("class")
393 .getNodeValue())) {
394 appendNodeText(result, XmlUtil.getFirstChildElement(child));
395 }
396 else {
397 appendNodeText(result, child);
398 }
399 }
400 }
401
402 return result.toString();
403 }
404
405
406 private static void appendNodeText(StringBuilder result, Node node) {
407 final String name = transformXmlToJavaDocName(node.getNodeName());
408 final boolean list = "ol".equals(name) || "ul".equals(name);
409 final boolean newLineOpenBefore = list || "p".equals(name) || "pre".equals(name)
410 || "li".equals(name);
411 final boolean newLineOpenAfter = newLineOpenBefore && !list;
412 final boolean newLineClose = newLineOpenAfter || list;
413 final boolean sanitize = "pre".equals(name);
414 final boolean changeToTag = "code".equals(name);
415
416 if (newLineOpenBefore) {
417 result.append('\n');
418 }
419 else if (shouldAppendSpace(result, '<')) {
420 result.append(' ');
421 }
422
423 if (changeToTag) {
424 result.append("{@");
425 result.append(name);
426 result.append(' ');
427 }
428 else {
429 result.append('<');
430 result.append(name);
431 result.append(getAttributeText(name, node.getAttributes()));
432 result.append('>');
433 }
434
435 if (newLineOpenAfter) {
436 result.append('\n');
437 }
438
439 if (sanitize) {
440 result.append(XmlUtil.sanitizeXml(node.getTextContent()));
441 }
442 else {
443 result.append(getNodeText(node));
444 }
445
446 if (newLineClose) {
447 result.append('\n');
448 }
449
450 if (changeToTag) {
451 result.append('}');
452 }
453 else {
454 result.append("</");
455 result.append(name);
456 result.append('>');
457 }
458 }
459
460 private static boolean shouldAppendSpace(StringBuilder text, char firstCharToAppend) {
461 final boolean result;
462
463 if (text.length() == 0) {
464 result = false;
465 }
466 else {
467 final char last = text.charAt(text.length() - 1);
468
469 result = (firstCharToAppend == '@'
470 || Character.getType(firstCharToAppend) == Character.DASH_PUNCTUATION
471 || Character.getType(last) == Character.OTHER_PUNCTUATION
472 || Character.isAlphabetic(last)
473 || Character.isAlphabetic(firstCharToAppend)) && !Character.isWhitespace(last);
474 }
475
476 return result;
477 }
478
479 private static String transformXmlToJavaDocName(String name) {
480 final String result;
481
482 if ("source".equals(name)) {
483 result = "pre";
484 }
485 else if ("h4".equals(name)) {
486 result = "p";
487 }
488 else {
489 result = name;
490 }
491
492 return result;
493 }
494
495 private static String getAttributeText(String nodeName, NamedNodeMap attributes) {
496 final StringBuilder result = new StringBuilder(20);
497
498 for (int i = 0; i < attributes.getLength(); i++) {
499 result.append(' ');
500
501 final Node attribute = attributes.item(i);
502 final String attrName = attribute.getNodeName();
503 final String attrValue;
504
505 if ("a".equals(nodeName) && "href".equals(attrName)) {
506 final String value = attribute.getNodeValue();
507
508 assertWithMessage("links starting with '#' aren't supported: " + value)
509 .that(value.charAt(0))
510 .isNotEqualTo('#');
511
512 attrValue = getLinkValue(value);
513 }
514 else {
515 attrValue = attribute.getNodeValue();
516 }
517
518 result.append(attrName);
519 result.append("=\"");
520 result.append(attrValue);
521 result.append('"');
522 }
523
524 return result.toString();
525 }
526
527 private static String getLinkValue(String initialValue) {
528 String value = initialValue;
529 final String attrValue;
530 if (value.contains("://")) {
531 attrValue = value;
532 }
533 else {
534 if (value.charAt(0) == '/') {
535 value = value.substring(1);
536 }
537
538
539 if (!initialValue.startsWith("/dtds")) {
540 value = currentXdocPath
541 .getParent()
542 .resolve(Path.of(value))
543 .normalize()
544 .toString()
545 .replaceAll("src[\\\\/]site[\\\\/]xdoc[\\\\/]", "")
546 .replaceAll("\\\\", "/");
547 }
548
549 attrValue = "https://checkstyle.org/" + value;
550 }
551 return attrValue;
552 }
553
554 public static class JavaDocCapture extends AbstractCheck {
555 private static final Pattern SETTER_PATTERN = Pattern.compile("^set[A-Z].*");
556
557 @Override
558 public boolean isCommentNodesRequired() {
559 return true;
560 }
561
562 @Override
563 public int[] getRequiredTokens() {
564 return new int[] {
565 TokenTypes.BLOCK_COMMENT_BEGIN,
566 };
567 }
568
569 @Override
570 public int[] getDefaultTokens() {
571 return getRequiredTokens();
572 }
573
574 @Override
575 public int[] getAcceptableTokens() {
576 return getRequiredTokens();
577 }
578
579 @Override
580 public void visitToken(DetailAST ast) {
581 if (JavadocUtil.isJavadocComment(ast)) {
582 final DetailAST parentNode = getParent(ast);
583
584 switch (parentNode.getType()) {
585 case TokenTypes.CLASS_DEF:
586 visitClass(ast);
587 break;
588 case TokenTypes.METHOD_DEF:
589 visitMethod(ast, parentNode);
590 break;
591 case TokenTypes.VARIABLE_DEF:
592 visitField(ast, parentNode);
593 break;
594 case TokenTypes.CTOR_DEF:
595 case TokenTypes.ENUM_DEF:
596 case TokenTypes.ENUM_CONSTANT_DEF:
597
598 break;
599 default:
600 assertWithMessage(
601 "Unknown token '" + TokenUtil.getTokenName(parentNode.getType())
602 + "': " + ast.getLineNo()).fail();
603 break;
604 }
605 }
606 }
607
608 private static DetailAST getParent(DetailAST node) {
609 DetailAST result = node.getParent();
610 int type = result.getType();
611
612 while (type == TokenTypes.MODIFIERS || type == TokenTypes.ANNOTATION) {
613 result = result.getParent();
614 type = result.getType();
615 }
616
617 return result;
618 }
619
620 private static void visitClass(DetailAST node) {
621 String violationMessagesText = CHECK_TEXT.get("Violation Messages");
622
623 if (checkName.endsWith("Filter") || "SuppressWarningsHolder".equals(checkName)) {
624 violationMessagesText = "";
625 }
626
627 if (ScopeUtil.isInScope(node, Scope.PUBLIC)) {
628 final String expected = CHECK_TEXT.get("Description")
629 + CHECK_TEXT.computeIfAbsent("Rule Description", unused -> "")
630 + CHECK_TEXT.computeIfAbsent("Notes", unused -> "")
631 + CHECK_TEXT.computeIfAbsent("Properties", unused -> "")
632 + CHECK_TEXT.get("Parent Module")
633 + violationMessagesText + " @since "
634 + CHECK_TEXT.get("since");
635
636 assertWithMessage(checkName + "'s class-level JavaDoc")
637 .that(getJavaDocText(node))
638 .isEqualTo(expected);
639 }
640 }
641
642 private static void visitField(DetailAST node, DetailAST parentNode) {
643 if (ScopeUtil.isInScope(parentNode, Scope.PUBLIC)) {
644 final String propertyName = parentNode.findFirstToken(TokenTypes.IDENT).getText();
645 final String propertyDoc = CHECK_PROPERTY_DOC.get(propertyName);
646
647 if (propertyDoc != null) {
648 assertWithMessage(checkName + "'s class field-level JavaDoc for "
649 + propertyName)
650 .that(getJavaDocText(node))
651 .isEqualTo(makeFirstUpper(propertyDoc));
652 }
653 }
654 }
655
656 private static void visitMethod(DetailAST node, DetailAST parentNode) {
657 if (ScopeUtil.isInScope(node, Scope.PUBLIC) && isSetterMethod(parentNode)) {
658 final String propertyUpper = parentNode.findFirstToken(TokenTypes.IDENT)
659 .getText().substring(3);
660 final String propertyName = makeFirstLower(propertyUpper);
661 final String propertyDoc = CHECK_PROPERTY_DOC.get(propertyName);
662
663 if (propertyDoc != null) {
664 final String javaDoc = getJavaDocText(node);
665
666 assertWithMessage(checkName + "'s class method-level JavaDoc for "
667 + propertyName)
668 .that(javaDoc.substring(0, javaDoc.indexOf(" @param")))
669 .isEqualTo("Setter to " + makeFirstLower(propertyDoc));
670 }
671 }
672 }
673
674
675
676
677
678
679
680
681
682 private static boolean isSetterMethod(DetailAST ast) {
683 boolean setterMethod = false;
684
685 if (ast.getType() == TokenTypes.METHOD_DEF) {
686 final DetailAST type = ast.findFirstToken(TokenTypes.TYPE);
687 final String name = type.getNextSibling().getText();
688 final boolean matchesSetterFormat = SETTER_PATTERN.matcher(name).matches();
689 final boolean voidReturnType = type.findFirstToken(TokenTypes.LITERAL_VOID) != null;
690
691 final DetailAST params = ast.findFirstToken(TokenTypes.PARAMETERS);
692 final boolean singleParam = params.getChildCount(TokenTypes.PARAMETER_DEF) == 1;
693
694 if (matchesSetterFormat && voidReturnType && singleParam) {
695 final DetailAST slist = ast.findFirstToken(TokenTypes.SLIST);
696
697 setterMethod = slist != null;
698 }
699 }
700 return setterMethod;
701 }
702
703 private static String getJavaDocText(DetailAST node) {
704 String text = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<document>\n"
705 + node.getFirstChild().getText().replaceAll("(^|\\r?\\n)\\s*\\* ?", "\n")
706 .replaceAll("\\n?@noinspection.*\\r?\\n[^@]*", "\n")
707 .trim() + "\n</document>";
708 String result = null;
709
710
711 if (text.contains("\n" + SINCE_VERSION)) {
712 final String sinceVersionLine = "\n" + SINCE_VERSION + " .*";
713 text = text.replaceAll(sinceVersionLine, "");
714 }
715
716 try {
717 result = getNodeText(XmlUtil.getRawXml(checkName, text, text).getFirstChild())
718 .replace("\r", "");
719 }
720 catch (ParserConfigurationException exc) {
721 assertWithMessage("Exception: " + exc.getClass() + " - " + exc.getMessage()).fail();
722 }
723
724 return result;
725 }
726
727 private static String makeFirstUpper(String str) {
728 final char ch = str.charAt(0);
729 final String result;
730
731 if (Character.isLowerCase(ch)) {
732 result = Character.toUpperCase(ch) + str.substring(1);
733 }
734 else {
735 result = str;
736 }
737
738 return result;
739 }
740
741 private static String makeFirstLower(String str) {
742 return Character.toLowerCase(str.charAt(0)) + str.substring(1);
743 }
744 }
745 }