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