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
24 import java.nio.file.Files;
25 import java.nio.file.Path;
26 import java.nio.file.Paths;
27 import java.util.HashMap;
28 import java.util.HashSet;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Set;
32 import java.util.regex.Matcher;
33 import java.util.regex.Pattern;
34 import java.util.stream.Collectors;
35
36 import org.junit.jupiter.api.Test;
37 import org.w3c.dom.Document;
38 import org.w3c.dom.Node;
39 import org.w3c.dom.NodeList;
40
41 import com.puppycrawl.tools.checkstyle.internal.utils.XmlUtil;
42 import picocli.CommandLine;
43 import picocli.CommandLine.Model.OptionSpec;
44
45 public class CliOptionsXdocsSyncTest {
46
47 @Test
48 public void validateCliDocSections() throws Exception {
49 final Map<String, String> cmdDesc = new HashMap<>();
50
51 final NodeList sections = getSectionsFromXdoc("src/xdocs/cmdline.xml.vm");
52 final Set<String> cmdOptions = getListById(sections.item(2), "CLI_Options");
53 for (String option : cmdOptions) {
54 final String text = option.trim().replaceAll("\\s+", " ");
55 cmdDesc.put(text.substring(0, 2), text.substring(text.indexOf(" - ") + 3));
56 }
57
58 final Class<?> cliOptions = Class.forName("com.puppycrawl.tools.checkstyle"
59 + ".Main$CliOptions");
60 final CommandLine commandLine = new CommandLine(cliOptions);
61 final List<OptionSpec> optionSpecList = commandLine.getCommandSpec().options();
62
63 for (OptionSpec opt : optionSpecList) {
64 final String option = opt.names()[0];
65 if ("-h".equals(option) || "-V".equals(option)) {
66 cmdDesc.remove(option);
67 continue;
68 }
69 final String descXdoc = cmdDesc.get(option);
70 final String descMain = opt.description()[0];
71 assertWithMessage("CLI Option: " + option + " present in "
72 + "Main.java but not documented in cmdline.xml.vm")
73 .that(descXdoc)
74 .isNotNull();
75 assertWithMessage("CLI options descriptions in xdoc: "
76 + " should match that of in Main.java")
77 .that(descMain)
78 .isEqualTo(descXdoc);
79 cmdDesc.remove(option);
80 }
81 assertWithMessage("CLI Options: %s present in cmdline.xml.vm, not documented in Main.java",
82 cmdDesc)
83 .that(cmdDesc)
84 .isEmpty();
85 }
86
87 @Test
88 public void validateCliUsageSection() throws Exception {
89 final NodeList sections = getSectionsFromXdoc("src/xdocs/cmdline.xml.vm");
90 final Node usageSource = XmlUtil.getFirstChildElement(sections.item(2));
91 final String usageText = XmlUtil.getFirstChildElement(usageSource).getTextContent();
92
93 final Set<String> shortParamsXdoc = getParameters(usageText, "-[a-zA-CE-X]\\b");
94 final Set<String> longParamsXdoc = getParameters(usageText, "-(-\\w+)+");
95
96 final Class<?> cliOptions = Class.forName("com.puppycrawl.tools.checkstyle"
97 + ".Main$CliOptions");
98 final CommandLine commandLine = new CommandLine(cliOptions);
99 final Set<String> shortParamsMain = commandLine.getCommandSpec().options()
100 .stream()
101 .map(OptionSpec::shortestName)
102 .collect(Collectors.toUnmodifiableSet());
103 final Set<String> longParamsMain = commandLine.getCommandSpec().options()
104 .stream()
105 .map(OptionSpec::longestName)
106 .filter(names -> names.length() != 2)
107 .collect(Collectors.toUnmodifiableSet());
108
109 assertWithMessage("Short parameters in Main.java and cmdline"
110 + ".xml.vm should match")
111 .that(shortParamsMain)
112 .isEqualTo(shortParamsXdoc);
113 assertWithMessage("Long parameters in Main.java and cmdline"
114 + ".xml.vm should match")
115 .that(longParamsMain)
116 .isEqualTo(longParamsXdoc);
117 }
118
119 private static Set<String> getParameters(String text, String regex) {
120 final Set<String> result = new HashSet<>();
121 final Pattern pattern = Pattern.compile(regex);
122 final Matcher matcher = pattern.matcher(text);
123 while (matcher.find()) {
124 result.add(matcher.group());
125 }
126 return result;
127 }
128
129 private static NodeList getSectionsFromXdoc(String xdocPath) throws Exception {
130 final Path path = Paths.get(xdocPath);
131 final String input = Files.readString(path);
132 final Document document = XmlUtil.getRawXml(path.getFileName().toString(), input, input);
133 return document.getElementsByTagName("section");
134 }
135
136 private static Set<String> getListById(Node subSection, String id) {
137 Set<String> result = null;
138 final Node node = XmlUtil.findChildElementById(subSection, id);
139 if (node != null) {
140 result = XmlUtil.getChildrenElements(node)
141 .stream()
142 .map(Node::getTextContent)
143 .collect(Collectors.toUnmodifiableSet());
144 }
145 return result;
146 }
147 }