1 /*
2 * Copyright (c) 2024, 2026, 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 8335770 8375740
27 * @summary improve javap code coverage for value classes
28 * @enablePreview
29 * @library /tools/lib
30 * @modules jdk.jdeps/com.sun.tools.javap
31 * @build toolbox.ToolBox toolbox.JavapTask
32 * @run main ValueClassesJavapTest
33 */
34
35 import java.nio.file.*;
36 import java.util.*;
37
38 import toolbox.JavapTask;
39 import toolbox.TestRunner;
40 import toolbox.ToolBox;
41 import toolbox.Task;
42
43 public class ValueClassesJavapTest extends TestRunner {
44 ToolBox tb = new ToolBox();
45
46 abstract value class AbstractValueClass {}
47 value class ValueClass {}
48 class IdentityClass {
49 ValueClass val;
50 }
51 class IdentityClass2 {
52 void m(ValueClass param) {}
53 }
54
55 private static final List<String> expectedValueClassOutput = List.of(
56 "Compiled from \"ValueClassesJavapTest.java\"",
57 "final value class ValueClassesJavapTest$ValueClass {",
58 " ValueClassesJavapTest$ValueClass(ValueClassesJavapTest);",
59 "}");
60 private static final List<String> expectedAbstractValueClassOutput = List.of(
61 "Compiled from \"ValueClassesJavapTest.java\"",
62 "abstract value class ValueClassesJavapTest$AbstractValueClass {",
63 " ValueClassesJavapTest$AbstractValueClass(ValueClassesJavapTest);",
64 "}");
65 private static final List<String> expectedLoadableDescriptorOutput = List.of(
66 "LoadableDescriptors:",
67 " LValueClassesJavapTest$ValueClass;"
68 );
69 private static final List<String> expectedIdentityClassOutput = """
70 Compiled from "ValueClassesJavapTest.java"
71 class ValueClassesJavapTest$IdentityClass {
72 ValueClassesJavapTest$ValueClass val;
73 ValueClassesJavapTest$IdentityClass(ValueClassesJavapTest);
74 }
75 """.lines().toList();
76 private static final List<String> expectedIdentityClass2Output = """
77 Compiled from "ValueClassesJavapTest.java"
78 class ValueClassesJavapTest$IdentityClass2 {
79 ValueClassesJavapTest$IdentityClass2(ValueClassesJavapTest);
80 void m(ValueClassesJavapTest$ValueClass);
81 }
82 """.lines().toList();
83
84 ValueClassesJavapTest() throws Exception {
85 super(System.err);
86 }
87
88 public static void main(String... args) throws Exception {
89 ValueClassesJavapTest tester = new ValueClassesJavapTest();
90 tester.runTests();
91 }
92
93 protected void runTests() throws Exception {
94 runTests(m -> new Object[] { Paths.get(m.getName()) });
95 }
96
97 @Test
98 public void testMain(Path base) throws Exception {
99 Path testClassesPath = Paths.get(System.getProperty("test.classes"));
100 List<String> output = new JavapTask(tb)
101 .options("-p", testClassesPath.resolve(this.getClass().getSimpleName() + "$ValueClass.class").toString())
102 .run()
103 .writeAll()
104 .getOutputLines(Task.OutputKind.DIRECT);
105 System.out.println(output);
106 if (!output.equals(expectedValueClassOutput)) {
107 throw new AssertionError(String.format("unexpected output:\n %s", output));
108 }
109
110 output = new JavapTask(tb)
111 .options("-p", testClassesPath.resolve(this.getClass().getSimpleName() + "$AbstractValueClass.class").toString())
112 .run()
113 .writeAll()
114 .getOutputLines(Task.OutputKind.DIRECT);
115 System.out.println(output);
116 if (!output.equals(expectedAbstractValueClassOutput)) {
117 throw new AssertionError(String.format("unexpected output:\n %s", output));
118 }
119
120 output = new JavapTask(tb)
121 .options("-p", testClassesPath.resolve(this.getClass().getSimpleName() + "$IdentityClass.class").toString())
122 .run()
123 .writeAll()
124 .getOutputLines(Task.OutputKind.DIRECT);
125 System.out.println(output);
126 if (!output.equals(expectedIdentityClassOutput)) {
127 throw new AssertionError(String.format("unexpected output:\n %s", output));
128 }
129
130 output = new JavapTask(tb)
131 .options("-p", "-v", testClassesPath.resolve(this.getClass().getSimpleName() + "$IdentityClass.class").toString())
132 .run()
133 .writeAll()
134 .getOutputLines(Task.OutputKind.DIRECT);
135 System.out.println(output);
136 if (!output.containsAll(expectedLoadableDescriptorOutput)) {
137 throw new AssertionError(String.format("unexpected output:\n %s", output));
138 }
139
140 output = new JavapTask(tb)
141 .options("-p", testClassesPath.resolve(this.getClass().getSimpleName() + "$IdentityClass2.class").toString())
142 .run()
143 .writeAll()
144 .getOutputLines(Task.OutputKind.DIRECT);
145 System.out.println(output);
146 if (!output.equals(expectedIdentityClass2Output)) {
147 throw new AssertionError(String.format("unexpected output:\n %s", output));
148 }
149
150 output = new JavapTask(tb)
151 .options("-p", "-v", testClassesPath.resolve(this.getClass().getSimpleName() + "$IdentityClass2.class").toString())
152 .run()
153 .writeAll()
154 .getOutputLines(Task.OutputKind.DIRECT);
155 System.out.println(output);
156 if (!output.containsAll(expectedLoadableDescriptorOutput)) {
157 throw new AssertionError(String.format("unexpected output:\n %s", output));
158 }
159 }
160 }