Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/jdk/tools/jar/multiRelease/ApiValidatorTest.java
41149 views
1
/*
2
* Copyright (c) 2017, 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 8196748
27
* @summary Tests for API validator.
28
* @library /test/lib
29
* @modules java.base/jdk.internal.misc
30
* jdk.compiler
31
* jdk.jartool
32
* @build jdk.test.lib.Utils
33
* jdk.test.lib.Asserts
34
* jdk.test.lib.JDKToolFinder
35
* jdk.test.lib.JDKToolLauncher
36
* jdk.test.lib.Platform
37
* jdk.test.lib.process.*
38
* MRTestBase
39
* @run testng/timeout=1200 ApiValidatorTest
40
*/
41
42
import jdk.test.lib.process.OutputAnalyzer;
43
import org.testng.annotations.BeforeMethod;
44
import org.testng.annotations.DataProvider;
45
import org.testng.annotations.Test;
46
47
import java.lang.reflect.Method;
48
import java.nio.file.Files;
49
import java.nio.file.Path;
50
import java.nio.file.Paths;
51
import java.util.regex.Matcher;
52
import java.util.regex.Pattern;
53
54
public class ApiValidatorTest extends MRTestBase {
55
56
static final Pattern MODULE_PATTERN = Pattern.compile("module (\\w+)");
57
static final Pattern CLASS_PATTERN = Pattern.compile("package (\\w+).*public class (\\w+)");
58
59
private Path root;
60
private Path classes;
61
62
@BeforeMethod
63
void testInit(Method method) {
64
root = Paths.get(method.getName());
65
classes = root.resolve("classes");
66
}
67
68
@Test(dataProvider = "signatureChange")
69
public void changeMethodSignature(String sigBase, String sigV10,
70
boolean isAcceptable) throws Throwable {
71
72
String METHOD_SIG = "#SIG";
73
String classTemplate =
74
"public class C { \n" +
75
" " + METHOD_SIG + "{ throw new RuntimeException(); };\n" +
76
"}\n";
77
String base = classTemplate.replace(METHOD_SIG, sigBase);
78
String v10 = classTemplate.replace(METHOD_SIG, sigV10);
79
80
compileTemplate(classes.resolve("base"), base);
81
compileTemplate(classes.resolve("v10"), v10);
82
83
String jarfile = root.resolve("test.jar").toString();
84
OutputAnalyzer result = jar("cf", jarfile,
85
"-C", classes.resolve("base").toString(), ".",
86
"--release", "10", "-C", classes.resolve("v10").toString(),
87
".");
88
if (isAcceptable) {
89
result.shouldHaveExitValue(SUCCESS)
90
.shouldBeEmptyIgnoreVMWarnings();
91
} else {
92
result.shouldNotHaveExitValue(SUCCESS)
93
.shouldContain("contains a class with different api from earlier version");
94
}
95
}
96
97
@DataProvider
98
Object[][] signatureChange() {
99
return new Object[][]{
100
{"public int m()", "protected int m()", false},
101
{"protected int m()", "public int m()", false},
102
{"public int m()", "int m()", false},
103
{"protected int m()", "private int m()", false},
104
{"private int m()", "int m()", true},
105
{"int m()", "private int m()", true},
106
{"int m()", "private int m(boolean b)", true},
107
{"public int m()", "public int m(int i)", false},
108
{"public int m()", "public int k()", false},
109
{"public int m()", "private int k()", false},
110
// @ignore JDK-8172147 {"public int m()", "public boolean m()", false},
111
// @ignore JDK-8172147 {"public boolean", "public Boolean", false},
112
// @ignore JDK-8172147 {"public <T> T", "public <T extends String> T", false},
113
};
114
}
115
116
@Test(dataProvider = "publicAPI")
117
public void introducingPublicMembers(String publicAPI) throws Throwable {
118
String API = "#API";
119
String classTemplate =
120
"public class C { \n" +
121
" " + API + "\n" +
122
" public void method(){ };\n" +
123
"}\n";
124
String base = classTemplate.replace(API, "");
125
String v10 = classTemplate.replace(API, publicAPI);
126
127
compileTemplate(classes.resolve("base"), base);
128
compileTemplate(classes.resolve("v10"), v10);
129
130
String jarfile = root.resolve("test.jar").toString();
131
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
132
"--release", "10", "-C", classes.resolve("v10").toString(), ".")
133
.shouldNotHaveExitValue(SUCCESS)
134
.shouldContain("contains a class with different api from earlier version");
135
}
136
137
@DataProvider
138
Object[][] publicAPI() {
139
return new Object[][]{
140
// @ignore JDK-8172148 {"protected class Inner { public void m(){ } } "}, // protected inner class
141
// @ignore JDK-8172148 {"public class Inner { public void m(){ } }"}, // public inner class
142
// @ignore JDK-8172148 {"public enum E { A; }"}, // public enum
143
{"public void m(){ }"}, // public method
144
{"protected void m(){ }"}, // protected method
145
};
146
}
147
148
@Test(dataProvider = "privateAPI")
149
public void introducingPrivateMembers(String privateAPI) throws Throwable {
150
String API = "#API";
151
String classTemplate =
152
"public class C { \n" +
153
" " + API + "\n" +
154
" public void method(){ };\n" +
155
"}\n";
156
String base = classTemplate.replace(API, "");
157
String v10 = classTemplate.replace(API, privateAPI);
158
159
compileTemplate(classes.resolve("base"), base);
160
compileTemplate(classes.resolve("v10"), v10);
161
162
String jarfile = root.resolve("test.jar").toString();
163
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
164
"--release", "10", "-C", classes.resolve("v10").toString(), ".")
165
.shouldHaveExitValue(SUCCESS);
166
// add release
167
jar("uf", jarfile,
168
"--release", "11", "-C", classes.resolve("v10").toString(), ".")
169
.shouldHaveExitValue(SUCCESS);
170
// replace release
171
jar("uf", jarfile,
172
"--release", "11", "-C", classes.resolve("v10").toString(), ".")
173
.shouldHaveExitValue(SUCCESS);
174
}
175
176
@DataProvider
177
Object[][] privateAPI() {
178
return new Object[][]{
179
{"private class Inner { public void m(){ } } "}, // private inner class
180
{"class Inner { public void m(){ } }"}, // package private inner class
181
{"enum E { A; }"}, // package private enum
182
// Local class and private method
183
{"private void m(){ class Inner { public void m(){} } Inner i = null; }"},
184
{"void m(){ }"}, // package private method
185
};
186
}
187
188
private void compileTemplate(Path classes, String template) throws Throwable {
189
Path classSourceFile = Files.createDirectories(
190
classes.getParent().resolve("src").resolve(classes.getFileName()))
191
.resolve("C.java");
192
Files.write(classSourceFile, template.getBytes());
193
javac(classes, classSourceFile);
194
}
195
196
/* Modular multi-release checks */
197
198
@Test
199
public void moduleNameHasChanged() throws Throwable {
200
201
compileModule(classes.resolve("base"), "module A { }");
202
compileModule(classes.resolve("v10"), "module B { }");
203
204
String jarfile = root.resolve("test.jar").toString();
205
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
206
"--release", "10", "-C", classes.resolve("v10").toString(), ".")
207
.shouldNotHaveExitValue(SUCCESS)
208
.shouldContain("incorrect name");
209
210
// update module-info release
211
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
212
"--release", "10", "-C", classes.resolve("base").toString(), ".")
213
.shouldHaveExitValue(SUCCESS);
214
jar("uf", jarfile,
215
"--release", "10", "-C", classes.resolve("v10").toString(), ".")
216
.shouldNotHaveExitValue(SUCCESS)
217
.shouldContain("incorrect name");
218
}
219
220
// @Test @ignore 8173370
221
public void moduleBecomeOpen() throws Throwable {
222
223
compileModule(classes.resolve("base"), "module A { }");
224
compileModule(classes.resolve("v10"), "open module A { }");
225
226
String jarfile = root.resolve("test.jar").toString();
227
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
228
"--release", "10", "-C", classes.resolve("v10").toString(), ".")
229
.shouldNotHaveExitValue(SUCCESS)
230
.shouldContain("FIX ME");
231
232
// update module-info release
233
jar("cf", jarfile, "-C", classes.resolve("base").toString(), ".",
234
"--release", "10", "-C", classes.resolve("base").toString(), ".")
235
.shouldHaveExitValue(SUCCESS);
236
jar("uf", jarfile,
237
"--release", "10", "-C", classes.resolve("v10").toString(), ".")
238
.shouldNotHaveExitValue(SUCCESS)
239
.shouldContain("FIX ME");
240
}
241
242
@Test
243
public void moduleRequires() throws Throwable {
244
245
String BASE_VERSION_DIRECTIVE = "requires jdk.compiler;";
246
// add transitive flag
247
moduleDirectivesCase(BASE_VERSION_DIRECTIVE,
248
"requires transitive jdk.compiler;",
249
false,
250
"contains additional \"requires transitive\"");
251
// remove requires
252
moduleDirectivesCase(BASE_VERSION_DIRECTIVE,
253
"",
254
true,
255
"");
256
// add requires
257
moduleDirectivesCase(BASE_VERSION_DIRECTIVE,
258
"requires jdk.compiler; requires jdk.jartool;",
259
true,
260
"");
261
// add requires transitive
262
moduleDirectivesCase(BASE_VERSION_DIRECTIVE,
263
"requires jdk.compiler; requires transitive jdk.jartool;",
264
false,
265
"contains additional \"requires transitive\"");
266
}
267
268
@Test
269
public void moduleExports() throws Throwable {
270
271
String BASE_VERSION_DIRECTIVE = "exports pkg1; exports pkg2 to jdk.compiler;";
272
// add export
273
moduleDirectivesCase(BASE_VERSION_DIRECTIVE,
274
BASE_VERSION_DIRECTIVE + " exports pkg3;",
275
false,
276
"contains different \"exports\"");
277
// change exports to qualified exports
278
moduleDirectivesCase(BASE_VERSION_DIRECTIVE,
279
"exports pkg1 to jdk.compiler; exports pkg2;",
280
false,
281
"contains different \"exports\"");
282
// remove exports
283
moduleDirectivesCase(BASE_VERSION_DIRECTIVE,
284
"exports pkg1;",
285
false,
286
"contains different \"exports\"");
287
// add qualified exports
288
moduleDirectivesCase(BASE_VERSION_DIRECTIVE,
289
BASE_VERSION_DIRECTIVE + " exports pkg3 to jdk.compiler;",
290
false,
291
"contains different \"exports\"");
292
}
293
294
@Test
295
public void moduleOpens() throws Throwable {
296
297
String BASE_VERSION_DIRECTIVE = "opens pkg1; opens pkg2 to jdk.compiler;";
298
// add opens
299
moduleDirectivesCase(BASE_VERSION_DIRECTIVE,
300
BASE_VERSION_DIRECTIVE + " opens pkg3;",
301
false,
302
"contains different \"opens\"");
303
// change opens to qualified opens
304
moduleDirectivesCase(BASE_VERSION_DIRECTIVE,
305
"opens pkg1 to jdk.compiler; opens pkg2;",
306
false,
307
"contains different \"opens\"");
308
// remove opens
309
moduleDirectivesCase(BASE_VERSION_DIRECTIVE,
310
"opens pkg1;",
311
false,
312
"contains different \"opens\"");
313
// add qualified opens
314
moduleDirectivesCase(BASE_VERSION_DIRECTIVE,
315
BASE_VERSION_DIRECTIVE + " opens pkg3 to jdk.compiler;",
316
false,
317
"contains different \"opens\"");
318
}
319
320
@Test
321
public void moduleProvides() throws Throwable {
322
323
String BASE_VERSION_DIRECTIVE = "provides pkg1.A with pkg1.A;";
324
// add provides
325
moduleDirectivesCase(BASE_VERSION_DIRECTIVE,
326
BASE_VERSION_DIRECTIVE + " provides pkg2.B with pkg2.B;",
327
false,
328
"contains different \"provides\"");
329
// change service impl
330
moduleDirectivesCase(BASE_VERSION_DIRECTIVE,
331
"provides pkg1.A with pkg2.B;",
332
false,
333
"contains different \"provides\"");
334
// remove provides
335
moduleDirectivesCase(BASE_VERSION_DIRECTIVE,
336
"",
337
false,
338
"contains different \"provides\"");
339
}
340
341
@Test
342
public void moduleUses() throws Throwable {
343
344
String BASE_VERSION_DIRECTIVE = "uses pkg1.A;";
345
// add
346
moduleDirectivesCase(BASE_VERSION_DIRECTIVE,
347
BASE_VERSION_DIRECTIVE + " uses pkg2.B;",
348
true,
349
"");
350
// replace
351
moduleDirectivesCase(BASE_VERSION_DIRECTIVE,
352
"uses pkg2.B;",
353
true,
354
"");
355
// remove
356
moduleDirectivesCase(BASE_VERSION_DIRECTIVE,
357
"",
358
true,
359
"");
360
}
361
362
private void moduleDirectivesCase(String baseDirectives,
363
String versionedDirectives,
364
boolean expectSuccess,
365
String expectedMessage) throws Throwable {
366
String[] moduleClasses = {
367
"package pkg1; public class A { }",
368
"package pkg2; public class B extends pkg1.A { }",
369
"package pkg3; public class C extends pkg2.B { }"};
370
compileModule(classes.resolve("base"),
371
"module A { " + baseDirectives + " }",
372
moduleClasses);
373
compileModule(classes.resolve("v10"),
374
"module A { " + versionedDirectives + " }",
375
moduleClasses);
376
377
String jarfile = root.resolve("test.jar").toString();
378
OutputAnalyzer output = jar("cf", jarfile,
379
"-C", classes.resolve("base").toString(), ".",
380
"--release", "10", "-C", classes.resolve("v10").toString(), ".");
381
if (expectSuccess) {
382
output.shouldHaveExitValue(SUCCESS);
383
} else {
384
output.shouldNotHaveExitValue(SUCCESS)
385
.shouldContain(expectedMessage);
386
}
387
}
388
389
private void compileModule(Path classes, String moduleSource,
390
String... classSources) throws Throwable {
391
Matcher moduleMatcher = MODULE_PATTERN.matcher(moduleSource);
392
moduleMatcher.find();
393
String name = moduleMatcher.group(1);
394
Path moduleinfo = Files.createDirectories(
395
classes.getParent().resolve("src").resolve(name))
396
.resolve("module-info.java");
397
Files.write(moduleinfo, moduleSource.getBytes());
398
399
Path[] sourceFiles = new Path[classSources.length + 1];
400
sourceFiles[0] = moduleinfo;
401
402
for (int i = 0; i < classSources.length; i++) {
403
String classSource = classSources[i];
404
Matcher classMatcher = CLASS_PATTERN.matcher(classSource);
405
classMatcher.find();
406
String packageName = classMatcher.group(1);
407
String className = classMatcher.group(2);
408
409
Path packagePath = moduleinfo.getParent()
410
.resolve(packageName.replace('.', '/'));
411
Path sourceFile = Files.createDirectories(packagePath)
412
.resolve(className + ".java");
413
Files.write(sourceFile, classSource.getBytes());
414
415
sourceFiles[i + 1] = sourceFile;
416
}
417
418
javac(classes, sourceFiles);
419
}
420
}
421
422