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 }