Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/langtools/jdk/javadoc/tool/8224613/OptionProcessingFailureTest.java
40971 views
1
/*
2
* Copyright (c) 2020, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation.
8
*
9
* This code is distributed in the hope that it will be useful, but WITHOUT
10
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12
* version 2 for more details (a copy is included in the LICENSE file that
13
* accompanied this code).
14
*
15
* You should have received a copy of the GNU General Public License version
16
* 2 along with this work; if not, write to the Free Software Foundation,
17
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18
*
19
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20
* or visit www.oracle.com if you need additional information or have any
21
* questions.
22
*/
23
24
/*
25
* @test
26
* @bug 8224613
27
* @library /tools/lib ../../lib
28
* @modules jdk.javadoc/jdk.javadoc.internal.tool
29
* @build javadoc.tester.* toolbox.ToolBox builder.ClassBuilder
30
* @run main/othervm OptionProcessingFailureTest
31
*/
32
33
import builder.ClassBuilder;
34
import javadoc.tester.JavadocTester;
35
import jdk.javadoc.doclet.Doclet;
36
import jdk.javadoc.doclet.DocletEnvironment;
37
import jdk.javadoc.doclet.Reporter;
38
import toolbox.ToolBox;
39
40
import javax.lang.model.SourceVersion;
41
import javax.tools.Diagnostic;
42
import java.io.IOException;
43
import java.nio.file.Path;
44
import java.nio.file.Paths;
45
import java.util.ArrayList;
46
import java.util.Collection;
47
import java.util.HashSet;
48
import java.util.List;
49
import java.util.Locale;
50
import java.util.Objects;
51
import java.util.Set;
52
import java.util.stream.Collectors;
53
54
/*
55
* Tests that a particular error is raised only if a doclet has not reported any
56
* errors (to Reporter), and yet at least one of that Doclet's options returned
57
* `false` from the `Doclet.Option.process` method.
58
*
59
* This test explores scenarios generated by combining a few independent factors
60
* involved in failing a doclet run. These factors are:
61
*
62
* 1. Reporting errors in Doclet.init(...)
63
* 2. Reporting errors in Doclet.Option.process(...)
64
* 3. Returning `false` from Doclet.Option.process(...)
65
*
66
* A doclet that behaves according to a scenario is run by the javadoc tool. An
67
* output of that run is then examined for presence of a particular error. That
68
* error must be in the output if and only if one or more options returned
69
* `false` from Doclet.Option.process(...) and no other errors were reported.
70
*
71
* Configuration of the doclet is performed out-of-band, using System Properties
72
* (when running the javadoc tool from the command line this could be achieved
73
* using -J-Dsystem.property.name=value syntax). The "puppet" doclet is
74
* instructed on which options is has, how many errors it should report,
75
* and how each individual option should be processed.
76
*/
77
public class OptionProcessingFailureTest extends JavadocTester {
78
79
private final ToolBox tb = new ToolBox();
80
81
public static void main(String... args) throws Exception {
82
new OptionProcessingFailureTest().runTests(m -> new Object[]{Paths.get(m.getName())});
83
}
84
85
@Test
86
public void test(Path base) throws IOException {
87
Path srcDir = base.resolve("src");
88
89
// Since the minimal successful run of the javadoc tool with a custom
90
// doclet involves source files, a package with a class in it is generated:
91
new ClassBuilder(tb, "pkg.A")
92
.setModifiers("public", "class")
93
.write(srcDir);
94
95
generateScenarios(base, this::testScenario);
96
}
97
98
private static void generateScenarios(Path base, ScenarioConsumer consumer) {
99
for (int nInitErrors : List.of(0, 1)) { // the number of errors the Doclet.init method should report
100
for (int nOptions : List.of(0, 1, 2)) { // the number of options a doclet should have
101
generateOptionsCombinations(base, nInitErrors, nOptions, consumer);
102
}
103
}
104
}
105
106
private static void generateOptionsCombinations(Path base,
107
int nInitErrors,
108
int nOptions,
109
ScenarioConsumer consumer) {
110
var emptyDescriptions = new PuppetOption.Description[nOptions];
111
generateOptionsCombinations(base, nInitErrors, 0, emptyDescriptions, consumer);
112
}
113
114
115
private static void generateOptionsCombinations(Path base,
116
int nInitErrors,
117
int descriptionsIndex,
118
PuppetOption.Description[] descriptions,
119
ScenarioConsumer consumer) {
120
if (descriptionsIndex >= descriptions.length) {
121
consumer.consume(base, nInitErrors, List.of(descriptions));
122
return;
123
}
124
for (boolean success : List.of(true, false)) { // return values of Doclet.Options.process
125
for (int nErrors : List.of(0, 1)) { // the number of errors Doclet.Options.process should report
126
String optionName = "--doclet-option-" + descriptionsIndex;
127
descriptions[descriptionsIndex] = new PuppetOption.Description(optionName, success, nErrors);
128
generateOptionsCombinations(base, nInitErrors, descriptionsIndex + 1, descriptions, consumer);
129
}
130
}
131
}
132
133
private void testScenario(Path base,
134
int nInitErrors,
135
List<PuppetOption.Description> optionDescriptions) {
136
System.out.printf("nInitErrors=%s, optionDescriptions=%s%n", nInitErrors, optionDescriptions);
137
138
List<String> args = new ArrayList<>(
139
List.of("-doclet", PuppetDoclet.class.getName(),
140
"-docletpath", System.getProperty("test.classes", "."),
141
"-sourcepath", base.resolve("src").toString(),
142
"pkg"));
143
144
optionDescriptions.forEach(d -> args.add(d.name)); // options passed to the doclet
145
146
/* The puppet doclet does not create any output directories, so there is
147
no need for any related checks; other checks are disabled to speed up
148
the processing and reduce the size of the output. */
149
150
setOutputDirectoryCheck(DirectoryCheck.NONE);
151
setAutomaticCheckAccessibility(false);
152
setAutomaticCheckLinks(false);
153
154
/* Ideally, the system properties should've been passed to the `javadoc`
155
method below. However, since there's no such option, the system
156
properties are manipulated in an external fashion. */
157
158
String descriptions = System.getProperty("puppet.descriptions");
159
if (descriptions != null) {
160
throw new IllegalStateException(descriptions);
161
}
162
String errors = System.getProperty("puppet.errors");
163
if (errors != null) {
164
throw new IllegalStateException(errors);
165
}
166
try {
167
System.setProperty("puppet.descriptions", PuppetDoclet.descriptionsToString(optionDescriptions));
168
System.setProperty("puppet.errors", String.valueOf(nInitErrors));
169
javadoc(args.toArray(new String[0]));
170
} finally {
171
System.clearProperty("puppet.descriptions");
172
System.clearProperty("puppet.errors");
173
}
174
175
long sumErrors = optionDescriptions.stream().mapToLong(d -> d.nProcessErrors).sum() + nInitErrors;
176
boolean success = optionDescriptions.stream().allMatch(d -> d.success);
177
178
checkOutput(Output.OUT, sumErrors != 0 || !success, "error: ");
179
}
180
181
/* Creating a specialized consumer is even more lightweight than creating a POJO */
182
@FunctionalInterface
183
public interface ScenarioConsumer {
184
void consume(Path src, int nInitErrors, List<PuppetOption.Description> optionDescriptions);
185
}
186
187
public static final class PuppetDoclet implements Doclet {
188
189
private final int nErrorsInInit;
190
private final Set<PuppetOption.Description> descriptions;
191
private Set<Option> options;
192
private Reporter reporter;
193
194
public PuppetDoclet() {
195
this(nInitErrorsFromString(System.getProperty("puppet.errors")),
196
descriptionsFromString(System.getProperty("puppet.descriptions")));
197
}
198
199
private static Collection<PuppetOption.Description> descriptionsFromString(String value) {
200
if (value.isEmpty())
201
return List.of(); // special case of description of zero-length
202
String[] split = value.split(",");
203
List<PuppetOption.Description> descriptions = new ArrayList<>();
204
for (int i = 0; i < split.length; i += 3) {
205
String name = split[i];
206
boolean success = Boolean.parseBoolean(split[i + 1]);
207
int nErrors = Integer.parseInt(split[i + 2]);
208
descriptions.add(new PuppetOption.Description(name, success, nErrors));
209
}
210
return descriptions;
211
}
212
213
public static String descriptionsToString(Collection<? extends PuppetOption.Description> descriptions) {
214
return descriptions.stream()
215
.map(d -> d.name + "," + d.success + "," + d.nProcessErrors)
216
.collect(Collectors.joining(","));
217
}
218
219
private static int nInitErrorsFromString(String value) {
220
return Integer.parseInt(Objects.requireNonNull(value));
221
}
222
223
public PuppetDoclet(int nErrorsInInit, Collection<PuppetOption.Description> descriptions) {
224
if (nErrorsInInit < 0) {
225
throw new IllegalArgumentException();
226
}
227
this.nErrorsInInit = nErrorsInInit;
228
this.descriptions = Set.copyOf(descriptions);
229
}
230
231
@Override
232
public void init(Locale locale, Reporter reporter) {
233
this.reporter = reporter;
234
for (int i = 0; i < nErrorsInInit; i++) {
235
reporter.print(Diagnostic.Kind.ERROR, "init error #%s".formatted(i));
236
}
237
}
238
239
@Override
240
public String getName() {
241
return getClass().getSimpleName();
242
}
243
244
@Override
245
public Set<? extends Option> getSupportedOptions() {
246
if (options == null) {
247
options = new HashSet<>();
248
for (PuppetOption.Description d : descriptions) {
249
options.add(new PuppetOption(d, reporter));
250
}
251
}
252
return options;
253
}
254
255
@Override
256
public SourceVersion getSupportedSourceVersion() {
257
return SourceVersion.latestSupported();
258
}
259
260
@Override
261
public boolean run(DocletEnvironment environment) {
262
return true;
263
}
264
}
265
266
private static final class PuppetOption implements Doclet.Option {
267
268
private final Reporter reporter;
269
private final Description description;
270
271
public PuppetOption(Description description, Reporter reporter) {
272
this.description = description;
273
this.reporter = reporter;
274
}
275
276
@Override
277
public int getArgumentCount() {
278
return 0;
279
}
280
281
@Override
282
public String getDescription() {
283
return description.name
284
+ ": success=" + description.success
285
+ ", nProcessErrors=" + description.nProcessErrors;
286
}
287
288
@Override
289
public Kind getKind() {
290
return Kind.STANDARD;
291
}
292
293
@Override
294
public List<String> getNames() {
295
return List.of(description.name);
296
}
297
298
@Override
299
public String getParameters() {
300
return "";
301
}
302
303
@Override
304
public boolean process(String option, List<String> arguments) {
305
for (int i = 0; i < description.nProcessErrors; i++) {
306
reporter.print(Diagnostic.Kind.ERROR,
307
"option: '%s', process error #%s".formatted(description.name, i));
308
}
309
return description.success;
310
}
311
312
public final static class Description {
313
314
public final String name;
315
public final boolean success;
316
public final int nProcessErrors;
317
318
Description(String name, boolean success, int nErrors) {
319
this.name = name;
320
this.success = success;
321
this.nProcessErrors = nErrors;
322
}
323
324
@Override
325
public String toString() {
326
return "Description{" +
327
"name='" + name + '\'' +
328
", success=" + success +
329
", nProcessErrors=" + nProcessErrors +
330
'}';
331
}
332
}
333
}
334
}
335
336
337