From 68a8916c9bda92df9fb31d4fa8988511a2294d04 Mon Sep 17 00:00:00 2001 From: Alexander Kriegisch Date: Sat, 26 Jun 2021 16:18:29 +0700 Subject: [PATCH] Add integration test for '--release N' compiler option Relates to #70 Signed-off-by: Alexander Kriegisch --- .../features198/compiler_release/Buffers.java | 20 +++++ .../systemtest/ajc198/AllTestsAspectJ198.java | 3 + .../ajc198/CompileWithReleaseTests.java | 73 +++++++++++++++++++ .../org/aspectj/systemtest/ajc198/ajc198.xml | 5 ++ 4 files changed, 101 insertions(+) create mode 100644 tests/features198/compiler_release/Buffers.java create mode 100644 tests/src/test/java/org/aspectj/systemtest/ajc198/CompileWithReleaseTests.java diff --git a/tests/features198/compiler_release/Buffers.java b/tests/features198/compiler_release/Buffers.java new file mode 100644 index 000000000..7245640c8 --- /dev/null +++ b/tests/features198/compiler_release/Buffers.java @@ -0,0 +1,20 @@ +import java.nio.Buffer; +import java.nio.ByteBuffer; + +public class Buffers { + /** + * Running this method will fail during runtime on JDK 8, if compiled on JDK 9+ with {@code -source 8 -target 8}, + * because the API has changed: In JDK 8 there was only {@code Buffer.flip()}, but since JDK 9 it is overloaded by + * {@code ByteBuffer.flip()}. + *

+ * Therefore, it is imperative to compile against the old API, using the correct boot classpath. On JDK 9+, the + * canonical way to do this is to use {@code --release 8}, because the JDK contains a compatibility layer exactly for + * this purpose. + *

+ * If incorrectly compiled against JDK 9+ API, this will fail with: + *

{@code java.lang.NoSuchMethodError: java.nio.ByteBuffer.flip()Ljava/nio/ByteBuffer; }
+ */ + public static Buffer flip(ByteBuffer buffer) { + return buffer.flip(); + } +} diff --git a/tests/src/test/java/org/aspectj/systemtest/ajc198/AllTestsAspectJ198.java b/tests/src/test/java/org/aspectj/systemtest/ajc198/AllTestsAspectJ198.java index 26d749222..d99042a3f 100644 --- a/tests/src/test/java/org/aspectj/systemtest/ajc198/AllTestsAspectJ198.java +++ b/tests/src/test/java/org/aspectj/systemtest/ajc198/AllTestsAspectJ198.java @@ -18,6 +18,9 @@ public class AllTestsAspectJ198 { public static Test suite() { TestSuite suite = new TestSuite("AspectJ 1.9.8 tests"); + if (LangUtil.is9VMOrGreater()) { + suite.addTest(org.aspectj.systemtest.ajc198.CompileWithReleaseTests.suite()); + } if (LangUtil.is17VMOrGreater()) { suite.addTest(SanityTestsJava17.suite()); suite.addTest(Ajc198TestsJava.suite()); diff --git a/tests/src/test/java/org/aspectj/systemtest/ajc198/CompileWithReleaseTests.java b/tests/src/test/java/org/aspectj/systemtest/ajc198/CompileWithReleaseTests.java new file mode 100644 index 000000000..c24c7e58e --- /dev/null +++ b/tests/src/test/java/org/aspectj/systemtest/ajc198/CompileWithReleaseTests.java @@ -0,0 +1,73 @@ +/******************************************************************************* + * Copyright (c) 2021 Contributors + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v 2.0 + * which accompanies this distribution, and is available at + * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.txt + *******************************************************************************/ +package org.aspectj.systemtest.ajc198; + +import junit.framework.Test; +import org.aspectj.apache.bcel.Constants; +import org.aspectj.apache.bcel.classfile.JavaClass; +import org.aspectj.apache.bcel.classfile.Method; +import org.aspectj.testing.XMLBasedAjcTestCase; +import org.aspectj.testing.XMLBasedAjcTestCaseForJava9OrLater; + +import java.util.Objects; + +/** + * @author Alexander Kriegisch + */ +public class CompileWithReleaseTests extends XMLBasedAjcTestCaseForJava9OrLater { + + /** + * In order to avoid a complicated test involving two different JDKs (9+ for compilation, 8 for runtime), we inspect + * the byte code of test class {@code Buffers} with BCEL, simply grepping on the disassembled byte code. If compiled + * correctly with {@code --release 8}, the byte code should contain the equivalent of a {@code Buffer.flip()} call, + * not a {@code ByteBuffer.flip()} one. + */ + public void testCompileToOlderJDKRelease() { + runTest("compile to older JDK release"); + + // Check compiled byte code version + String className = "Buffers"; + checkVersion(className, Constants.MAJOR_1_8, Constants.MINOR_1_8); + + // Disassemble method and check if Java 8 API is used as expected + JavaClass javaClass; + try { + javaClass = getClassFrom(ajc.getSandboxDirectory(), className); + } + catch (ClassNotFoundException e) { + throw new IllegalStateException("Cannot find class " + className, e); + } + Method method = Objects.requireNonNull(getMethodFromClass(javaClass, "flip")); + String disassembledMethod = method.getCode().toString(); + + final String JAVA8_API_CALL = "invokevirtual\tjava.nio.ByteBuffer.flip ()Ljava/nio/Buffer;"; + final String JAVA9_API_CALL = "invokevirtual\tjava.nio.ByteBuffer.flip ()Ljava/nio/ByteBuffer;"; + if (disassembledMethod.contains(JAVA9_API_CALL)) + fail( + "Class '" + className + "' was compiled against Java 9+ API. " + + "There seems to be a problem with the '--release' compiler option.\n" + + "Disassembled method:\n" + disassembledMethod + ); + else if (!disassembledMethod.contains(JAVA8_API_CALL)) + fail( + "Cannot determine if class '" + className + "' was compiled against Java 8 or 9+ API. " + + "This should never happen.\n" + + "Disassembled method:\n" + disassembledMethod + ); + } + + public static Test suite() { + return XMLBasedAjcTestCase.loadSuite(CompileWithReleaseTests.class); + } + + @Override + protected java.net.URL getSpecFile() { + return getClassResource("ajc198.xml"); + } + +} diff --git a/tests/src/test/resources/org/aspectj/systemtest/ajc198/ajc198.xml b/tests/src/test/resources/org/aspectj/systemtest/ajc198/ajc198.xml index e2dc9fe5d..06ca7d048 100644 --- a/tests/src/test/resources/org/aspectj/systemtest/ajc198/ajc198.xml +++ b/tests/src/test/resources/org/aspectj/systemtest/ajc198/ajc198.xml @@ -32,4 +32,9 @@ --> + + + + + -- 2.39.5