1 /*
  2  * Copyright (c) 2017, 2023, 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  * @enablePreview
 27  * @modules java.base/jdk.internal.module
 28  * @library /test/lib
 29  * @build jdk.test.lib.util.ModuleInfoWriter
 30  * @run testng ClassFileVersionsTest
 31  * @summary Test parsing of module-info.class with different class file versions
 32  */
 33 
 34 import java.lang.module.InvalidModuleDescriptorException;
 35 import java.lang.module.ModuleDescriptor;
 36 import java.lang.module.ModuleDescriptor.Requires.Modifier;
 37 import java.nio.ByteBuffer;
 38 import java.util.Set;
 39 
 40 import static java.lang.module.ModuleDescriptor.Requires.Modifier.*;
 41 
 42 import jdk.test.lib.util.ModuleInfoWriter;
 43 
 44 import org.testng.annotations.DataProvider;
 45 import org.testng.annotations.Test;
 46 import static org.testng.Assert.*;
 47 
 48 public class ClassFileVersionsTest {
 49     private static final int FEATURE;
 50     static {
 51         FEATURE = Runtime.version().feature();
 52         assert FEATURE >= 10;
 53     }
 54 
 55     // major, minor, modifiers for requires java.base
 56     @DataProvider(name = "supported")
 57     public Object[][] supported() {
 58         /*
 59          * There are four test cases for JDK 9 and then one test case
 60          * for each subsequent JDK version from JDK 10 to the current
 61          * feature release for a total of (4 + (FEATURE - 9) ) =>
 62          * (feature - 5) rows.
 63          */
 64         Object[][] result = new Object[(FEATURE - 5)][];
 65 
 66         // Class file version of JDK 9 is 53.0
 67         result[0] = new Object[]{ 53, 0, Set.of()};
 68         result[1] = new Object[]{ 53, 0, Set.of(STATIC) };
 69         result[2] = new Object[]{ 53, 0, Set.of(TRANSITIVE) };
 70         result[3] = new Object[]{ 53, 0, Set.of(STATIC, TRANSITIVE) };
 71 
 72         // Major class file version of JDK N is 44 + n. Create rows
 73         // for JDK 10 through FEATURE.
 74         for (int i = 4; i < (FEATURE - 5) ; i++) {
 75             result[i] = new Object[]{i + 50, 0, Set.of()};
 76         }
 77 
 78         return result;
 79     }
 80 
 81     // major, minor, modifiers for requires java.base
 82     @DataProvider(name = "unsupported")
 83     public Object[][] unsupported() {
 84         /*
 85          * There are three test cases for releases prior to JDK 9,
 86          * three test cases for each JDK version from JDK 10 to the
 87          * current feature release, plus one addition test case for
 88          * the next release for a total of (3 + (FEATURE - 9) * 3 + 1)
 89          * rows.
 90          */
 91         int unsupportedCount = 3 + (FEATURE - 9)*3 + 1;
 92         Object[][] result = new Object[unsupportedCount][];
 93 
 94         result[0] = new Object[]{50, 0, Set.of()}; // JDK 6
 95         result[1] = new Object[]{51, 0, Set.of()}; // JDK 7
 96         result[2] = new Object[]{52, 0, Set.of()}; // JDK 8
 97 
 98         for (int i = 10; i <= FEATURE ; i++) {
 99             int base = 3 + (i-10)*3;
100             // Major class file version of JDK N is 44+n
101             result[base]     = new Object[]{i + 44, 0, Set.of(STATIC)};
102             result[base + 1] = new Object[]{i + 44, 0, Set.of(TRANSITIVE)};
103             result[base + 2] = new Object[]{i + 44, 0, Set.of(STATIC, TRANSITIVE)};
104         }
105 
106         result[unsupportedCount - 1] = new Object[]{FEATURE+1+44, 0, Set.of()};
107         return result;
108     }
109 
110     @Test(dataProvider = "supported")
111     public void testSupported(int major, int minor, Set<Modifier> ms) {
112         ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo")
113                 .requires(ms, "java.base")
114                 .build();
115         ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor);
116         classFileVersion(bb, major, minor);
117         descriptor = ModuleDescriptor.read(bb);
118         assertEquals(descriptor.name(), "foo");
119     }
120 
121     @Test(dataProvider = "unsupported",
122           expectedExceptions = InvalidModuleDescriptorException.class)
123     public void testUnsupported(int major, int minor, Set<Modifier> ms) {
124         ModuleDescriptor descriptor = ModuleDescriptor.newModule("foo")
125                 .requires(ms, "java.base")
126                 .build();
127         ByteBuffer bb = ModuleInfoWriter.toByteBuffer(descriptor);
128         classFileVersion(bb, major, minor);
129 
130         // throws InvalidModuleDescriptorException
131         ModuleDescriptor.read(bb);
132     }
133 
134     private void classFileVersion(ByteBuffer bb, int major, int minor) {
135         bb.putShort(4, (short) minor);
136         bb.putShort(6, (short) major);
137     }
138 }