AssertionsConfigurationTest: Split into three test classes
Bug: b/270028969
Change-Id: I39ad0a0a932f464ae464a4b148791ba75d10173f
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinCfTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinCfTest.java
new file mode 100644
index 0000000..5cbe1b1
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinCfTest.java
@@ -0,0 +1,95 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.rewrite.assertions;
+
+import com.android.tools.r8.AssertionsConfiguration;
+import com.android.tools.r8.KotlinCompilerTool.KotlinTargetVersion;
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.BooleanUtils;
+import java.util.Collection;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class AssertionConfigurationKotlinCfTest extends AssertionConfigurationKotlinTestBase {
+
+ @Parameterized.Parameters(
+ name =
+ "{0}, {1}, kotlin-stdlib as library: {2}, -Xassertions=jvm: {3}, enableJvmAssertions:"
+ + " {4}")
+ public static Collection<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withCfRuntimes().build(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
+ BooleanUtils.values(),
+ BooleanUtils.values(),
+ BooleanUtils.values());
+ }
+
+ private final boolean enableJvmAssertions;
+
+ public AssertionConfigurationKotlinCfTest(
+ TestParameters parameters,
+ KotlinTestParameters kotlinParameters,
+ boolean kotlinStdlibAsClasspath,
+ boolean useJvmAssertions,
+ boolean enableJvmAssertions) {
+ super(parameters, kotlinParameters, kotlinStdlibAsClasspath, useJvmAssertions);
+ this.enableJvmAssertions = enableJvmAssertions;
+ }
+
+ @Test
+ public void testAssertionsForCfEnableWithStackMap() throws Exception {
+ Assume.assumeTrue(useJvmAssertions);
+ Assume.assumeTrue(targetVersion == KotlinTargetVersion.JAVA_8);
+ // Compile time enabling or disabling assertions means the -ea flag has no effect.
+ runR8Test(
+ builder -> {
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::compileTimeEnableAllAssertions);
+ },
+ inspector -> checkAssertionCodeEnabled(inspector, true),
+ allAssertionsExpectedLines(),
+ enableJvmAssertions);
+ }
+
+ @Test
+ public void testAssertionsForCfPassThrough() throws Exception {
+ // Leaving assertion code means assertions are controlled by the -ea flag.
+ runR8Test(
+ builder ->
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::passthroughAllAssertions),
+ inspector -> checkAssertionCodeLeft(inspector, true),
+ enableJvmAssertions ? allAssertionsExpectedLines() : noAllAssertionsExpectedLines(),
+ enableJvmAssertions);
+ }
+
+ @Test
+ public void testAssertionsForCfEnable() throws Exception {
+ // Compile time enabling or disabling assertions means the -ea flag has no effect.
+ runR8Test(
+ builder ->
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::compileTimeEnableAllAssertions),
+ inspector -> checkAssertionCodeEnabled(inspector, true),
+ allAssertionsExpectedLines(),
+ enableJvmAssertions);
+ }
+
+ @Test
+ public void testAssertionsForCfDisable() throws Exception {
+ runR8Test(
+ builder ->
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::compileTimeDisableAllAssertions),
+ inspector -> checkAssertionCodeRemoved(inspector, true),
+ noAllAssertionsExpectedLines(),
+ enableJvmAssertions);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinDexTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinDexTest.java
new file mode 100644
index 0000000..e5ab25b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinDexTest.java
@@ -0,0 +1,211 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.rewrite.assertions;
+
+import com.android.tools.r8.AssertionsConfiguration;
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.BooleanUtils;
+import java.util.Collection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class AssertionConfigurationKotlinDexTest extends AssertionConfigurationKotlinTestBase {
+
+ @Parameterized.Parameters(name = "{0}, {1}, kotlin-stdlib as library: {2}, -Xassertions=jvm: {3}")
+ public static Collection<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withDexRuntimesAndAllApiLevels().build(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
+ BooleanUtils.values(),
+ BooleanUtils.values());
+ }
+
+ public AssertionConfigurationKotlinDexTest(
+ TestParameters parameters,
+ KotlinTestParameters kotlinParameters,
+ boolean kotlinStdlibAsClasspath,
+ boolean useJvmAssertions) {
+ super(parameters, kotlinParameters, kotlinStdlibAsClasspath, useJvmAssertions);
+ }
+
+ @Test
+ public void testD8PassthroughAllAssertions() throws Exception {
+ runD8Test(
+ builder ->
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::passthroughAllAssertions),
+ inspector -> checkAssertionCodeLeft(inspector, false),
+ // Leaving assertions in on Dalvik/Art means no assertions.
+ noAllAssertionsExpectedLines());
+ }
+
+ @Test
+ public void testR8PassthroughAllAssertions() throws Exception {
+ runR8Test(
+ builder ->
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::passthroughAllAssertions),
+ inspector -> checkAssertionCodeLeft(inspector, true),
+ // Leaving assertions in on Dalvik/Art means no assertions.
+ noAllAssertionsExpectedLines());
+ }
+
+ @Test
+ public void testD8CompileTimeDisableAllAssertions() throws Exception {
+ runD8Test(
+ builder ->
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::compileTimeDisableAllAssertions),
+ inspector -> checkAssertionCodeRemoved(inspector, false),
+ // Compile time disabling assertions on Dalvik/Art means no assertions.
+ noAllAssertionsExpectedLines());
+ }
+
+ @Test
+ public void testR8CompileTimeDisableAllAssertions() throws Exception {
+ runR8Test(
+ builder ->
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::compileTimeDisableAllAssertions),
+ inspector -> checkAssertionCodeRemoved(inspector, true),
+ // Compile time disabling assertions on Dalvik/Art means no assertions.
+ noAllAssertionsExpectedLines());
+ }
+
+ @Test
+ public void testD8CompileTimeEnableAllAssertions() throws Exception {
+ runD8Test(
+ builder ->
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::compileTimeEnableAllAssertions),
+ inspector -> checkAssertionCodeEnabled(inspector, false),
+ // Compile time enabling assertions gives assertions on Dalvik/Art.
+ allAssertionsExpectedLines());
+ }
+
+ @Test
+ public void testR8CompileTimeEnableAllAssertions() throws Exception {
+ runR8Test(
+ builder ->
+ builder.addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::compileTimeEnableAllAssertions),
+ inspector -> checkAssertionCodeEnabled(inspector, true),
+ // Compile time enabling assertions gives assertions on Dalvik/Art.
+ allAssertionsExpectedLines());
+ }
+
+ @Test
+ public void testD8CompileTimeEnableForAllClasses() throws Exception {
+ if (useJvmAssertions) {
+ // Enabling for the kotlin generated Java classes should enable all.
+ runD8Test(
+ builder ->
+ builder
+ .addAssertionsConfiguration(
+ b -> b.setCompileTimeEnable().setScopeClass(class1).build())
+ .addAssertionsConfiguration(
+ b -> b.setCompileTimeEnable().setScopeClass(class2).build()),
+ inspector -> {
+ // The default is applied to kotlin._Assertions (which for DEX is remove).
+ if (!kotlinStdlibAsLibrary) {
+ checkAssertionCodeRemoved(inspector, "kotlin._Assertions", false);
+ }
+ checkAssertionCodeEnabled(inspector, class1, false);
+ checkAssertionCodeEnabled(inspector, class2, false);
+ },
+ allAssertionsExpectedLines());
+ } else {
+ // Enabling for the class kotlin._Assertions should enable all.
+ runD8Test(
+ builder ->
+ builder.addAssertionsConfiguration(
+ b -> b.setCompileTimeEnable().setScopeClass("kotlin._Assertions").build()),
+ inspector -> checkAssertionCodeEnabled(inspector, false),
+ allAssertionsExpectedLines());
+ }
+ }
+
+ @Test
+ public void testR8CompileTimeEnableForAllClasses() throws Exception {
+ if (useJvmAssertions) {
+ runR8Test(
+ builder ->
+ builder
+ .addAssertionsConfiguration(
+ b -> b.setCompileTimeEnable().setScopeClass(class1).build())
+ .addAssertionsConfiguration(
+ b -> b.setCompileTimeEnable().setScopeClass(class2).build()),
+ inspector -> checkAssertionCodeEnabled(inspector, true),
+ // When kotlinc generate JVM assertions compile time enabling assertions for the kotlinc
+ // generated Java classes should enable all.
+ allAssertionsExpectedLines());
+ } else {
+ runR8Test(
+ builder ->
+ builder.addAssertionsConfiguration(
+ b -> b.setCompileTimeEnable().setScopeClass("kotlin._Assertions").build()),
+ inspector -> checkAssertionCodeEnabled(inspector, true),
+ // When kotlinc generate Kotlin assertions compile time enabling assertions the class
+ // kotlin._Assertions should enable all.
+ allAssertionsExpectedLines());
+ }
+ }
+
+ @Test
+ public void testD8CompileTimeEnableForPackage() throws Exception {
+ if (useJvmAssertions) {
+ runD8Test(
+ builder ->
+ builder.addAssertionsConfiguration(
+ b -> b.setCompileTimeEnable().setScopePackage(kotlintestclasesPackage).build()),
+ inspector -> {
+ // The default is applied to kotlin._Assertions (which for DEX is remove).
+ if (!kotlinStdlibAsLibrary) {
+ checkAssertionCodeRemoved(inspector, "kotlin._Assertions", false);
+ }
+ checkAssertionCodeEnabled(inspector, class1, false);
+ checkAssertionCodeEnabled(inspector, class2, false);
+ },
+ // When kotlinc generate JVM assertions compile time enabling assertions for the kotlinc
+ // generated test classes package should enable all.
+ allAssertionsExpectedLines());
+ } else {
+ runD8Test(
+ builder ->
+ builder.addAssertionsConfiguration(
+ b -> b.setCompileTimeEnable().setScopePackage("kotlin").build()),
+ inspector -> checkAssertionCodeEnabled(inspector, false),
+ // When kotlinc generate Kotlin assertions compile time enabling assertions the package
+ // kotlin should enable all.
+ allAssertionsExpectedLines());
+ }
+ }
+
+ @Test
+ public void testR8CompileTimeEnableForPackage() throws Exception {
+ if (useJvmAssertions) {
+ runR8Test(
+ builder ->
+ builder.addAssertionsConfiguration(
+ b -> b.setCompileTimeEnable().setScopePackage(kotlintestclasesPackage).build()),
+ inspector -> checkAssertionCodeEnabled(inspector, true),
+ // When kotlinc generate JVM assertions compile time enabling assertions for the kotlinc
+ // generated test classes package should enable all.
+ allAssertionsExpectedLines());
+ } else {
+ // When kotlinc generate Kotlin assertions compile time enabling assertions the package
+ // kotlin should enable all.
+ runR8Test(
+ builder ->
+ builder.addAssertionsConfiguration(
+ b -> b.setCompileTimeEnable().setScopePackage("kotlin").build()),
+ inspector -> checkAssertionCodeEnabled(inspector, true),
+ allAssertionsExpectedLines());
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTest.java
deleted file mode 100644
index 99f55e1..0000000
--- a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTest.java
+++ /dev/null
@@ -1,704 +0,0 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.rewrite.assertions;
-
-import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.CoreMatchers.equalTo;
-import static org.hamcrest.CoreMatchers.not;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertTrue;
-
-import com.android.tools.r8.AssertionsConfiguration;
-import com.android.tools.r8.D8TestBuilder;
-import com.android.tools.r8.KotlinCompilerTool.KotlinTargetVersion;
-import com.android.tools.r8.KotlinTestBase;
-import com.android.tools.r8.KotlinTestParameters;
-import com.android.tools.r8.R8FullTestBuilder;
-import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ThrowableConsumer;
-import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.ThrowingConsumer;
-import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import com.android.tools.r8.utils.codeinspector.InstructionSubject;
-import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import com.google.common.collect.ImmutableList;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Collection;
-import java.util.List;
-import org.junit.Assume;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.objectweb.asm.ClassWriter;
-import org.objectweb.asm.FieldVisitor;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-
-@RunWith(Parameterized.class)
-public class AssertionConfigurationKotlinTest extends KotlinTestBase implements Opcodes {
-
- private static final Package pkg = AssertionConfigurationKotlinTest.class.getPackage();
- private static final String kotlintestclasesPackage = pkg.getName() + ".kotlintestclasses";
- private static final String testClassKt = kotlintestclasesPackage + ".TestClassKt";
- private static final String class1 = kotlintestclasesPackage + ".Class1";
- private static final String class2 = kotlintestclasesPackage + ".Class2";
-
- private static final KotlinCompileMemoizer kotlinWithJvmAssertions =
- getCompileMemoizer(getKotlinFilesForPackage())
- .configure(kotlinCompilerTool -> kotlinCompilerTool.setUseJvmAssertions(true));
- private static final KotlinCompileMemoizer kotlinWithoutJvmAssertions =
- getCompileMemoizer(getKotlinFilesForPackage())
- .configure(kotlinCompilerTool -> kotlinCompilerTool.setUseJvmAssertions(false));
-
- private final TestParameters parameters;
- private final boolean kotlinStdlibAsLibrary;
- private final boolean useJvmAssertions;
- private final KotlinCompileMemoizer compiledForAssertions;
-
- @Parameterized.Parameters(name = "{0}, {1}, kotlin-stdlib as library: {2}, -Xassertions=jvm: {3}")
- public static Collection<Object[]> data() {
- return buildParameters(
- getTestParameters().withAllRuntimesAndApiLevels().build(),
- getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
- BooleanUtils.values(),
- BooleanUtils.values());
- }
-
- public AssertionConfigurationKotlinTest(
- TestParameters parameters,
- KotlinTestParameters kotlinParameters,
- boolean kotlinStdlibAsClasspath,
- boolean useJvmAssertions) {
- super(kotlinParameters);
- this.parameters = parameters;
- this.kotlinStdlibAsLibrary = kotlinStdlibAsClasspath;
- this.useJvmAssertions = useJvmAssertions;
- this.compiledForAssertions =
- useJvmAssertions ? kotlinWithJvmAssertions : kotlinWithoutJvmAssertions;
- }
-
- private static List<Path> getKotlinFilesForPackage() {
- try {
- return getKotlinFilesInTestPackage(pkg);
- } catch (IOException e) {
- throw new RuntimeException(e);
- }
- }
-
- private Path kotlinStdlibLibraryForRuntime() throws Exception {
- Path kotlinStdlibCf = kotlinc.getKotlinStdlibJar();
- if (parameters.getRuntime().isCf()) {
- return kotlinStdlibCf;
- }
-
- Path kotlinStdlibDex = temp.newFolder().toPath().resolve("kotlin-stdlib-dex.jar");
- testForD8()
- .addProgramFiles(kotlinStdlibCf)
- .setMinApi(parameters)
- .compile()
- .writeToZip(kotlinStdlibDex);
- return kotlinStdlibDex;
- }
-
- private void runD8Test(
- ThrowableConsumer<D8TestBuilder> builderConsumer,
- ThrowingConsumer<CodeInspector, RuntimeException> inspector,
- List<String> outputLines)
- throws Exception {
- if (kotlinStdlibAsLibrary) {
- testForD8()
- .addClasspathFiles(kotlinc.getKotlinStdlibJar())
- .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
- .setMinApi(parameters)
- .apply(builderConsumer)
- .addRunClasspathFiles(kotlinStdlibLibraryForRuntime())
- .run(
- parameters.getRuntime(),
- getClass().getPackage().getName() + ".kotlintestclasses.TestClassKt")
- .inspect(inspector)
- .assertSuccessWithOutputLines(outputLines);
- } else {
- testForD8()
- .addProgramFiles(kotlinc.getKotlinStdlibJar())
- .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
- .setMinApi(parameters)
- .apply(builderConsumer)
- .run(
- parameters.getRuntime(),
- getClass().getPackage().getName() + ".kotlintestclasses.TestClassKt")
- .inspect(inspector)
- .assertSuccessWithOutputLines(outputLines);
- }
- }
-
- public void runR8Test(
- ThrowableConsumer<R8FullTestBuilder> builderConsumer,
- ThrowingConsumer<CodeInspector, RuntimeException> inspector,
- List<String> outputLines)
- throws Exception {
- runR8Test(builderConsumer, inspector, outputLines, false);
- }
-
- public void runR8Test(
- ThrowableConsumer<R8FullTestBuilder> builderConsumer,
- ThrowingConsumer<CodeInspector, RuntimeException> inspector,
- List<String> outputLines,
- boolean enableJvmAssertions)
- throws Exception {
-
- testForR8(parameters.getBackend())
- .applyIf(
- kotlinStdlibAsLibrary,
- b -> {
- b.addClasspathFiles(kotlinc.getKotlinStdlibJar());
- b.addRunClasspathFiles(kotlinStdlibLibraryForRuntime());
- },
- b -> b.addProgramFiles(kotlinc.getKotlinStdlibJar()))
- .addClasspathFiles(kotlinc.getKotlinAnnotationJar())
- .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
- .addKeepMainRule(testClassKt)
- .addKeepClassAndMembersRules(class1, class2)
- .setMinApi(parameters)
- .apply(builderConsumer)
- .allowDiagnosticWarningMessages(!kotlinStdlibAsLibrary)
- .addRunClasspathFiles(kotlinStdlibLibraryForRuntime())
- .compile()
- .applyIf(
- !kotlinStdlibAsLibrary,
- result ->
- result.assertAllWarningMessagesMatch(
- equalTo("Resource 'META-INF/MANIFEST.MF' already exists.")))
- .enableRuntimeAssertions(enableJvmAssertions)
- .run(parameters.getRuntime(), testClassKt)
- .inspect(inspector)
- .assertSuccessWithOutputLines(outputLines);
- }
-
- private List<String> allAssertionsExpectedLines() {
- return ImmutableList.of("AssertionError in Class1", "AssertionError in Class2", "DONE");
- }
-
- private List<String> noAllAssertionsExpectedLines() {
- return ImmutableList.of("DONE");
- }
-
- private void checkAssertionCodeRemoved(ClassSubject subject, boolean isR8) {
- assertThat(subject, isPresent());
- if (subject.getOriginalName().equals("kotlin._Assertions")) {
- assert !kotlinStdlibAsLibrary;
- // With R8 the static-put of the kotlin._Assertions.INSTANCE field is removed as well,
- // as is not used.
- assertEquals(
- (isR8 ? 0 : 1),
- subject
- .uniqueMethodWithOriginalName("<clinit>")
- .streamInstructions()
- .filter(InstructionSubject::isStaticPut)
- .count());
- assertFalse(
- subject
- .uniqueMethodWithOriginalName("<clinit>")
- .streamInstructions()
- .anyMatch(InstructionSubject::isConstNumber));
- } else {
- // The value of kotlin._Assertions.ENABLED is propagated from the assertions configuration
- // for the class kotlin._Assertions.
- assertFalse(
- subject
- .uniqueMethodWithOriginalName("m")
- .streamInstructions()
- .anyMatch(InstructionSubject::isThrow));
- }
- }
-
- private void checkAssertionCodeRemoved(CodeInspector inspector, String clazz, boolean isR8) {
- checkAssertionCodeRemoved(inspector.clazz(clazz), isR8);
- }
-
- private void checkAssertionCodeEnabled(ClassSubject subject, boolean isR8) {
- assertThat(subject, isPresent());
- if (subject.getOriginalName().equals("kotlin._Assertions")) {
- assert !kotlinStdlibAsLibrary;
- // With R8 the static-put of the kotlin._Assertions.INSTANCE field is removed as is not used.
- assertEquals(
- isR8 ? 1 : 2,
- subject
- .uniqueMethodWithOriginalName("<clinit>")
- .streamInstructions()
- .filter(InstructionSubject::isStaticPut)
- .count());
- assertTrue(
- subject
- .uniqueMethodWithOriginalName("<clinit>")
- .streamInstructions()
- .anyMatch(instruction -> instruction.isConstNumber(1)));
- } else {
- assertTrue(
- subject
- .uniqueMethodWithOriginalName("m")
- .streamInstructions()
- .anyMatch(InstructionSubject::isThrow));
- }
- }
-
- private void checkAssertionCodeEnabled(CodeInspector inspector, String clazz, boolean isR8) {
-
- checkAssertionCodeEnabled(inspector.clazz(clazz), isR8);
- }
-
- private void checkAssertionCodeLeft(CodeInspector inspector, String clazz, boolean isR8) {
- ClassSubject subject = inspector.clazz(clazz);
- if (clazz.equals("kotlin._Assertions")) {
- assert !kotlinStdlibAsLibrary;
- if (isR8 && useJvmAssertions) {
- // When JVM assertions are used the class kotlin._Assertions is unused.
- assertThat(subject, not(isPresent()));
- return;
- }
- assertThat(subject, isPresent());
- // With R8 the static-put of the kotlin._Assertions.INSTANCE field is removed as is not used.
- assertEquals(
- isR8 ? 1 : 2,
- subject
- .uniqueMethodWithOriginalName("<clinit>")
- .streamInstructions()
- .filter(InstructionSubject::isStaticPut)
- .count());
- assertFalse(
- subject
- .uniqueMethodWithOriginalName("<clinit>")
- .streamInstructions()
- .anyMatch(InstructionSubject::isConstNumber));
- } else {
- assertThat(subject, isPresent());
- MethodSubject clinit = subject.uniqueMethodWithOriginalName("<clinit>");
- if (useJvmAssertions) {
- assertTrue(clinit.streamInstructions().anyMatch(InstructionSubject::isStaticPut));
- } else {
- assertThat(clinit, not(isPresent()));
- }
- assertTrue(
- subject
- .uniqueMethodWithOriginalName("m")
- .streamInstructions()
- .anyMatch(InstructionSubject::isThrow));
- }
- }
-
- private void checkAssertionCodeRemoved(CodeInspector inspector, boolean isR8) {
- if (isR8) {
- assertThat(inspector.clazz("kotlin._Assertions"), not(isPresent()));
- } else if (!kotlinStdlibAsLibrary) {
- checkAssertionCodeRemoved(inspector, "kotlin._Assertions", isR8);
- }
- checkAssertionCodeRemoved(inspector, class1, isR8);
- checkAssertionCodeRemoved(inspector, class2, isR8);
- }
-
- private void checkAssertionCodeEnabled(CodeInspector inspector, boolean isR8) {
- if (isR8) {
- assertThat(inspector.clazz("kotlin._Assertions"), not(isPresent()));
- } else if (!kotlinStdlibAsLibrary) {
- checkAssertionCodeEnabled(inspector, "kotlin._Assertions", isR8);
- }
- checkAssertionCodeEnabled(inspector, class1, isR8);
- checkAssertionCodeEnabled(inspector, class2, isR8);
- }
-
- private void checkAssertionCodeLeft(CodeInspector inspector, boolean isR8) {
- if (!kotlinStdlibAsLibrary) {
- checkAssertionCodeLeft(inspector, "kotlin._Assertions", isR8);
- }
- checkAssertionCodeLeft(inspector, class1, isR8);
- checkAssertionCodeLeft(inspector, class2, isR8);
- }
-
- @Test
- public void testD8PassthroughAllAssertions() throws Exception {
- parameters.assumeDexRuntime();
- runD8Test(
- builder ->
- builder.addAssertionsConfiguration(
- AssertionsConfiguration.Builder::passthroughAllAssertions),
- inspector -> checkAssertionCodeLeft(inspector, false),
- // Leaving assertions in on Dalvik/Art means no assertions.
- noAllAssertionsExpectedLines());
- }
-
- @Test
- public void testR8PassthroughAllAssertions() throws Exception {
- parameters.assumeDexRuntime();
- runR8Test(
- builder ->
- builder.addAssertionsConfiguration(
- AssertionsConfiguration.Builder::passthroughAllAssertions),
- inspector -> checkAssertionCodeLeft(inspector, true),
- // Leaving assertions in on Dalvik/Art means no assertions.
- noAllAssertionsExpectedLines());
- }
-
- @Test
- public void testD8CompileTimeDisableAllAssertions() throws Exception {
- parameters.assumeDexRuntime();
- runD8Test(
- builder ->
- builder.addAssertionsConfiguration(
- AssertionsConfiguration.Builder::compileTimeDisableAllAssertions),
- inspector -> checkAssertionCodeRemoved(inspector, false),
- // Compile time disabling assertions on Dalvik/Art means no assertions.
- noAllAssertionsExpectedLines());
- }
-
- @Test
- public void testR8CompileTimeDisableAllAssertions() throws Exception {
- parameters.assumeDexRuntime();
- runR8Test(
- builder ->
- builder.addAssertionsConfiguration(
- AssertionsConfiguration.Builder::compileTimeDisableAllAssertions),
- inspector -> checkAssertionCodeRemoved(inspector, true),
- // Compile time disabling assertions on Dalvik/Art means no assertions.
- noAllAssertionsExpectedLines());
- }
-
- @Test
- public void testD8CompileTimeEnableAllAssertions() throws Exception {
- parameters.assumeDexRuntime();
- runD8Test(
- builder ->
- builder.addAssertionsConfiguration(
- AssertionsConfiguration.Builder::compileTimeEnableAllAssertions),
- inspector -> checkAssertionCodeEnabled(inspector, false),
- // Compile time enabling assertions gives assertions on Dalvik/Art.
- allAssertionsExpectedLines());
- }
-
- @Test
- public void testR8CompileTimeEnableAllAssertions() throws Exception {
- parameters.assumeDexRuntime();
- runR8Test(
- builder ->
- builder.addAssertionsConfiguration(
- AssertionsConfiguration.Builder::compileTimeEnableAllAssertions),
- inspector -> checkAssertionCodeEnabled(inspector, true),
- // Compile time enabling assertions gives assertions on Dalvik/Art.
- allAssertionsExpectedLines());
- }
-
- @Test
- public void testD8CompileTimeEnableForAllClasses() throws Exception {
- parameters.assumeDexRuntime();
- if (useJvmAssertions) {
- // Enabling for the kotlin generated Java classes should enable all.
- runD8Test(
- builder ->
- builder
- .addAssertionsConfiguration(
- b -> b.setCompileTimeEnable().setScopeClass(class1).build())
- .addAssertionsConfiguration(
- b -> b.setCompileTimeEnable().setScopeClass(class2).build()),
- inspector -> {
- // The default is applied to kotlin._Assertions (which for DEX is remove).
- if (!kotlinStdlibAsLibrary) {
- checkAssertionCodeRemoved(inspector, "kotlin._Assertions", false);
- }
- checkAssertionCodeEnabled(inspector, class1, false);
- checkAssertionCodeEnabled(inspector, class2, false);
- },
- allAssertionsExpectedLines());
- } else {
- // Enabling for the class kotlin._Assertions should enable all.
- runD8Test(
- builder ->
- builder.addAssertionsConfiguration(
- b -> b.setCompileTimeEnable().setScopeClass("kotlin._Assertions").build()),
- inspector -> checkAssertionCodeEnabled(inspector, false),
- allAssertionsExpectedLines());
- }
- }
-
- @Test
- public void testR8CompileTimeEnableForAllClasses() throws Exception {
- parameters.assumeDexRuntime();
- if (useJvmAssertions) {
- runR8Test(
- builder ->
- builder
- .addAssertionsConfiguration(
- b -> b.setCompileTimeEnable().setScopeClass(class1).build())
- .addAssertionsConfiguration(
- b -> b.setCompileTimeEnable().setScopeClass(class2).build()),
- inspector -> checkAssertionCodeEnabled(inspector, true),
- // When kotlinc generate JVM assertions compile time enabling assertions for the kotlinc
- // generated Java classes should enable all.
- allAssertionsExpectedLines());
- } else {
- runR8Test(
- builder ->
- builder.addAssertionsConfiguration(
- b -> b.setCompileTimeEnable().setScopeClass("kotlin._Assertions").build()),
- inspector -> checkAssertionCodeEnabled(inspector, true),
- // When kotlinc generate Kotlin assertions compile time enabling assertions the class
- // kotlin._Assertions should enable all.
- allAssertionsExpectedLines());
- }
- }
-
- @Test
- public void testD8CompileTimeEnableForPackage() throws Exception {
- parameters.assumeDexRuntime();
- if (useJvmAssertions) {
- runD8Test(
- builder ->
- builder.addAssertionsConfiguration(
- b -> b.setCompileTimeEnable().setScopePackage(kotlintestclasesPackage).build()),
- inspector -> {
- // The default is applied to kotlin._Assertions (which for DEX is remove).
- if (!kotlinStdlibAsLibrary) {
- checkAssertionCodeRemoved(inspector, "kotlin._Assertions", false);
- }
- checkAssertionCodeEnabled(inspector, class1, false);
- checkAssertionCodeEnabled(inspector, class2, false);
- },
- // When kotlinc generate JVM assertions compile time enabling assertions for the kotlinc
- // generated test classes package should enable all.
- allAssertionsExpectedLines());
- } else {
- runD8Test(
- builder ->
- builder.addAssertionsConfiguration(
- b -> b.setCompileTimeEnable().setScopePackage("kotlin").build()),
- inspector -> checkAssertionCodeEnabled(inspector, false),
- // When kotlinc generate Kotlin assertions compile time enabling assertions the package
- // kotlin should enable all.
- allAssertionsExpectedLines());
- }
- }
-
- @Test
- public void testR8CompileTimeEnableForPackage() throws Exception {
- parameters.assumeDexRuntime();
- if (useJvmAssertions) {
- runR8Test(
- builder ->
- builder.addAssertionsConfiguration(
- b -> b.setCompileTimeEnable().setScopePackage(kotlintestclasesPackage).build()),
- inspector -> checkAssertionCodeEnabled(inspector, true),
- // When kotlinc generate JVM assertions compile time enabling assertions for the kotlinc
- // generated test classes package should enable all.
- allAssertionsExpectedLines());
- } else {
- // When kotlinc generate Kotlin assertions compile time enabling assertions the package
- // kotlin should enable all.
- runR8Test(
- builder ->
- builder.addAssertionsConfiguration(
- b -> b.setCompileTimeEnable().setScopePackage("kotlin").build()),
- inspector -> checkAssertionCodeEnabled(inspector, true),
- allAssertionsExpectedLines());
- }
- }
-
- @Test
- public void testAssertionsForCfEnableWithStackMap() throws Exception {
- parameters.assumeCfRuntime();
- Assume.assumeTrue(useJvmAssertions);
- Assume.assumeTrue(targetVersion == KotlinTargetVersion.JAVA_8);
- // Compile time enabling or disabling assertions means the -ea flag has no effect.
- runR8Test(
- builder -> {
- builder.addAssertionsConfiguration(
- AssertionsConfiguration.Builder::compileTimeEnableAllAssertions);
- },
- inspector -> checkAssertionCodeEnabled(inspector, true),
- allAssertionsExpectedLines());
- runR8Test(
- builder -> {
- builder.addAssertionsConfiguration(
- AssertionsConfiguration.Builder::compileTimeEnableAllAssertions);
- },
- inspector -> checkAssertionCodeEnabled(inspector, true),
- allAssertionsExpectedLines(),
- true);
- }
-
- @Test
- public void testAssertionsForCfPassThrough() throws Exception {
- parameters.assumeCfRuntime();
- // Leaving assertion code means assertions are controlled by the -ea flag.
- runR8Test(
- builder ->
- builder.addAssertionsConfiguration(
- AssertionsConfiguration.Builder::passthroughAllAssertions),
- inspector -> checkAssertionCodeLeft(inspector, true),
- noAllAssertionsExpectedLines());
- runR8Test(
- builder ->
- builder.addAssertionsConfiguration(
- AssertionsConfiguration.Builder::passthroughAllAssertions),
- inspector -> checkAssertionCodeLeft(inspector, true),
- allAssertionsExpectedLines(),
- true);
- }
-
- @Test
- public void testAssertionsForCfEnable() throws Exception {
- parameters.assumeCfRuntime();
- // Compile time enabling or disabling assertions means the -ea flag has no effect.
- runR8Test(
- builder ->
- builder.addAssertionsConfiguration(
- AssertionsConfiguration.Builder::compileTimeEnableAllAssertions),
- inspector -> checkAssertionCodeEnabled(inspector, true),
- allAssertionsExpectedLines());
- runR8Test(
- builder ->
- builder.addAssertionsConfiguration(
- AssertionsConfiguration.Builder::compileTimeEnableAllAssertions),
- inspector -> checkAssertionCodeEnabled(inspector, true),
- allAssertionsExpectedLines(),
- true);
- }
-
- @Test
- public void testAssertionsForCfDisable() throws Exception {
- parameters.assumeCfRuntime();
- runR8Test(
- builder ->
- builder.addAssertionsConfiguration(
- AssertionsConfiguration.Builder::compileTimeDisableAllAssertions),
- inspector -> checkAssertionCodeRemoved(inspector, true),
- noAllAssertionsExpectedLines());
- runR8Test(
- builder ->
- builder.addAssertionsConfiguration(
- AssertionsConfiguration.Builder::compileTimeDisableAllAssertions),
- inspector -> checkAssertionCodeRemoved(inspector, true),
- noAllAssertionsExpectedLines(),
- true);
- }
-
- @Test
- public void TestWithModifiedKotlinAssertions() throws Exception {
- parameters.assumeCfRuntime();
- testForD8()
- .addProgramClassFileData(dumpModifiedKotlinAssertions())
- .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
- .setMinApi(parameters)
- .addAssertionsConfiguration(AssertionsConfiguration.Builder::passthroughAllAssertions)
- .run(
- parameters.getRuntime(),
- getClass().getPackage().getName() + ".kotlintestclasses.TestClassKt")
- .assertSuccessWithOutputLines(noAllAssertionsExpectedLines());
- testForD8()
- .addProgramClassFileData(dumpModifiedKotlinAssertions())
- .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
- .setMinApi(parameters)
- .addAssertionsConfiguration(AssertionsConfiguration.Builder::compileTimeEnableAllAssertions)
- .run(
- parameters.getRuntime(),
- getClass().getPackage().getName() + ".kotlintestclasses.TestClassKt")
- .assertSuccessWithOutputLines(allAssertionsExpectedLines());
- testForD8()
- .addProgramClassFileData(dumpModifiedKotlinAssertions())
- .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
- .setMinApi(parameters)
- .addAssertionsConfiguration(
- AssertionsConfiguration.Builder::compileTimeDisableAllAssertions)
- .run(
- parameters.getRuntime(),
- getClass().getPackage().getName() + ".kotlintestclasses.TestClassKt")
- .assertSuccessWithOutputLines(noAllAssertionsExpectedLines());
- }
-
- // Slightly modified version of kotlin._Assertions to hit all code paths in the assertion
- // rewriter. See "Code added" below.
- public static byte[] dumpModifiedKotlinAssertions() {
-
- ClassWriter classWriter = new ClassWriter(0);
- FieldVisitor fieldVisitor;
- MethodVisitor methodVisitor;
-
- classWriter.visit(
- V1_6,
- ACC_PUBLIC | ACC_FINAL | ACC_SUPER,
- "kotlin/_Assertions",
- null,
- "java/lang/Object",
- null);
-
- {
- fieldVisitor =
- classWriter.visitField(ACC_PUBLIC | ACC_FINAL | ACC_STATIC, "ENABLED", "Z", null, null);
- fieldVisitor.visitEnd();
- }
- {
- fieldVisitor =
- classWriter.visitField(
- ACC_PUBLIC | ACC_FINAL | ACC_STATIC, "INSTANCE", "Lkotlin/_Assertions;", null, null);
- fieldVisitor.visitEnd();
- }
- {
- methodVisitor =
- classWriter.visitMethod(
- ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC | ACC_DEPRECATED,
- "ENABLED$annotations",
- "()V",
- null,
- null);
- methodVisitor.visitCode();
- methodVisitor.visitInsn(RETURN);
- methodVisitor.visitMaxs(0, 0);
- methodVisitor.visitEnd();
- }
- {
- methodVisitor = classWriter.visitMethod(ACC_PRIVATE, "<init>", "()V", null, null);
- methodVisitor.visitCode();
- methodVisitor.visitVarInsn(ALOAD, 0);
- methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
- methodVisitor.visitInsn(RETURN);
- methodVisitor.visitMaxs(1, 1);
- methodVisitor.visitEnd();
- }
- {
- methodVisitor = classWriter.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
- methodVisitor.visitCode();
- methodVisitor.visitTypeInsn(NEW, "kotlin/_Assertions");
- methodVisitor.visitInsn(DUP);
- methodVisitor.visitMethodInsn(INVOKESPECIAL, "kotlin/_Assertions", "<init>", "()V", false);
- methodVisitor.visitVarInsn(ASTORE, 0);
- methodVisitor.visitVarInsn(ALOAD, 0);
- methodVisitor.visitFieldInsn(
- PUTSTATIC, "kotlin/_Assertions", "INSTANCE", "Lkotlin/_Assertions;");
-
- // Code added (added an additional call to getClass().desiredAssertionStatus() which
- // result is not assigned to ENABLED).
- methodVisitor.visitVarInsn(ALOAD, 0);
- methodVisitor.visitMethodInsn(
- INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
- methodVisitor.visitMethodInsn(
- INVOKEVIRTUAL, "java/lang/Class", "desiredAssertionStatus", "()Z", false);
- methodVisitor.visitInsn(POP);
- // End code added.
-
- methodVisitor.visitVarInsn(ALOAD, 0);
- methodVisitor.visitMethodInsn(
- INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
- methodVisitor.visitMethodInsn(
- INVOKEVIRTUAL, "java/lang/Class", "desiredAssertionStatus", "()Z", false);
- methodVisitor.visitFieldInsn(PUTSTATIC, "kotlin/_Assertions", "ENABLED", "Z");
- methodVisitor.visitInsn(RETURN);
- methodVisitor.visitMaxs(2, 1);
- methodVisitor.visitEnd();
- }
- classWriter.visitEnd();
-
- return classWriter.toByteArray();
- }
-}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTestBase.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTestBase.java
new file mode 100644
index 0000000..999ca31
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTestBase.java
@@ -0,0 +1,299 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.rewrite.assertions;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.D8TestBuilder;
+import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ThrowableConsumer;
+import com.android.tools.r8.utils.ThrowingConsumer;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.List;
+import org.objectweb.asm.Opcodes;
+
+public class AssertionConfigurationKotlinTestBase extends KotlinTestBase implements Opcodes {
+
+ protected static final Package pkg = AssertionConfigurationKotlinTestBase.class.getPackage();
+ protected static final String kotlintestclasesPackage = pkg.getName() + ".kotlintestclasses";
+ protected static final String testClassKt = kotlintestclasesPackage + ".TestClassKt";
+ protected static final String class1 = kotlintestclasesPackage + ".Class1";
+ protected static final String class2 = kotlintestclasesPackage + ".Class2";
+
+ private static final KotlinCompileMemoizer kotlinWithJvmAssertions =
+ getCompileMemoizer(getKotlinFilesForPackage())
+ .configure(kotlinCompilerTool -> kotlinCompilerTool.setUseJvmAssertions(true));
+ private static final KotlinCompileMemoizer kotlinWithoutJvmAssertions =
+ getCompileMemoizer(getKotlinFilesForPackage())
+ .configure(kotlinCompilerTool -> kotlinCompilerTool.setUseJvmAssertions(false));
+
+ protected final TestParameters parameters;
+ protected final boolean kotlinStdlibAsLibrary;
+ protected final boolean useJvmAssertions;
+ protected final KotlinCompileMemoizer compiledForAssertions;
+
+ public AssertionConfigurationKotlinTestBase(
+ TestParameters parameters,
+ KotlinTestParameters kotlinParameters,
+ boolean kotlinStdlibAsClasspath,
+ boolean useJvmAssertions) {
+ super(kotlinParameters);
+ this.parameters = parameters;
+ this.kotlinStdlibAsLibrary = kotlinStdlibAsClasspath;
+ this.useJvmAssertions = useJvmAssertions;
+ this.compiledForAssertions =
+ useJvmAssertions ? kotlinWithJvmAssertions : kotlinWithoutJvmAssertions;
+ }
+
+ private static List<Path> getKotlinFilesForPackage() {
+ try {
+ return getKotlinFilesInTestPackage(pkg);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private Path kotlinStdlibLibraryForRuntime() throws Exception {
+ Path kotlinStdlibCf = kotlinc.getKotlinStdlibJar();
+ if (parameters.getRuntime().isCf()) {
+ return kotlinStdlibCf;
+ }
+
+ Path kotlinStdlibDex = temp.newFolder().toPath().resolve("kotlin-stdlib-dex.jar");
+ testForD8()
+ .addProgramFiles(kotlinStdlibCf)
+ .setMinApi(parameters)
+ .compile()
+ .writeToZip(kotlinStdlibDex);
+ return kotlinStdlibDex;
+ }
+
+ protected void runD8Test(
+ ThrowableConsumer<D8TestBuilder> builderConsumer,
+ ThrowingConsumer<CodeInspector, RuntimeException> inspector,
+ List<String> outputLines)
+ throws Exception {
+ if (kotlinStdlibAsLibrary) {
+ testForD8()
+ .addClasspathFiles(kotlinc.getKotlinStdlibJar())
+ .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
+ .setMinApi(parameters)
+ .apply(builderConsumer)
+ .addRunClasspathFiles(kotlinStdlibLibraryForRuntime())
+ .run(
+ parameters.getRuntime(),
+ getClass().getPackage().getName() + ".kotlintestclasses.TestClassKt")
+ .inspect(inspector)
+ .assertSuccessWithOutputLines(outputLines);
+ } else {
+ testForD8()
+ .addProgramFiles(kotlinc.getKotlinStdlibJar())
+ .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
+ .setMinApi(parameters)
+ .apply(builderConsumer)
+ .run(
+ parameters.getRuntime(),
+ getClass().getPackage().getName() + ".kotlintestclasses.TestClassKt")
+ .inspect(inspector)
+ .assertSuccessWithOutputLines(outputLines);
+ }
+ }
+
+ protected void runR8Test(
+ ThrowableConsumer<R8FullTestBuilder> builderConsumer,
+ ThrowingConsumer<CodeInspector, RuntimeException> inspector,
+ List<String> outputLines)
+ throws Exception {
+ runR8Test(builderConsumer, inspector, outputLines, false);
+ }
+
+ protected void runR8Test(
+ ThrowableConsumer<R8FullTestBuilder> builderConsumer,
+ ThrowingConsumer<CodeInspector, RuntimeException> inspector,
+ List<String> outputLines,
+ boolean enableJvmAssertions)
+ throws Exception {
+
+ testForR8(parameters.getBackend())
+ .applyIf(
+ kotlinStdlibAsLibrary,
+ b -> {
+ b.addClasspathFiles(kotlinc.getKotlinStdlibJar());
+ b.addRunClasspathFiles(kotlinStdlibLibraryForRuntime());
+ },
+ b -> b.addProgramFiles(kotlinc.getKotlinStdlibJar()))
+ .addClasspathFiles(kotlinc.getKotlinAnnotationJar())
+ .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
+ .addKeepMainRule(testClassKt)
+ .addKeepClassAndMembersRules(class1, class2)
+ .setMinApi(parameters)
+ .apply(builderConsumer)
+ .allowDiagnosticWarningMessages(!kotlinStdlibAsLibrary)
+ .addRunClasspathFiles(kotlinStdlibLibraryForRuntime())
+ .compile()
+ .applyIf(
+ !kotlinStdlibAsLibrary,
+ result ->
+ result.assertAllWarningMessagesMatch(
+ equalTo("Resource 'META-INF/MANIFEST.MF' already exists.")))
+ .enableRuntimeAssertions(enableJvmAssertions)
+ .run(parameters.getRuntime(), testClassKt)
+ .inspect(inspector)
+ .assertSuccessWithOutputLines(outputLines);
+ }
+
+ protected List<String> allAssertionsExpectedLines() {
+ return ImmutableList.of("AssertionError in Class1", "AssertionError in Class2", "DONE");
+ }
+
+ protected List<String> noAllAssertionsExpectedLines() {
+ return ImmutableList.of("DONE");
+ }
+
+ protected void checkAssertionCodeRemoved(ClassSubject subject, boolean isR8) {
+ assertThat(subject, isPresent());
+ if (subject.getOriginalName().equals("kotlin._Assertions")) {
+ assert !kotlinStdlibAsLibrary;
+ // With R8 the static-put of the kotlin._Assertions.INSTANCE field is removed as well,
+ // as is not used.
+ assertEquals(
+ (isR8 ? 0 : 1),
+ subject
+ .uniqueMethodWithOriginalName("<clinit>")
+ .streamInstructions()
+ .filter(InstructionSubject::isStaticPut)
+ .count());
+ assertFalse(
+ subject
+ .uniqueMethodWithOriginalName("<clinit>")
+ .streamInstructions()
+ .anyMatch(InstructionSubject::isConstNumber));
+ } else {
+ // The value of kotlin._Assertions.ENABLED is propagated from the assertions configuration
+ // for the class kotlin._Assertions.
+ assertFalse(
+ subject
+ .uniqueMethodWithOriginalName("m")
+ .streamInstructions()
+ .anyMatch(InstructionSubject::isThrow));
+ }
+ }
+
+ protected void checkAssertionCodeRemoved(CodeInspector inspector, String clazz, boolean isR8) {
+ checkAssertionCodeRemoved(inspector.clazz(clazz), isR8);
+ }
+
+ protected void checkAssertionCodeEnabled(ClassSubject subject, boolean isR8) {
+ assertThat(subject, isPresent());
+ if (subject.getOriginalName().equals("kotlin._Assertions")) {
+ assert !kotlinStdlibAsLibrary;
+ // With R8 the static-put of the kotlin._Assertions.INSTANCE field is removed as is not used.
+ assertEquals(
+ isR8 ? 1 : 2,
+ subject
+ .uniqueMethodWithOriginalName("<clinit>")
+ .streamInstructions()
+ .filter(InstructionSubject::isStaticPut)
+ .count());
+ assertTrue(
+ subject
+ .uniqueMethodWithOriginalName("<clinit>")
+ .streamInstructions()
+ .anyMatch(instruction -> instruction.isConstNumber(1)));
+ } else {
+ assertTrue(
+ subject
+ .uniqueMethodWithOriginalName("m")
+ .streamInstructions()
+ .anyMatch(InstructionSubject::isThrow));
+ }
+ }
+
+ protected void checkAssertionCodeEnabled(CodeInspector inspector, String clazz, boolean isR8) {
+ checkAssertionCodeEnabled(inspector.clazz(clazz), isR8);
+ }
+
+ protected void checkAssertionCodeLeft(CodeInspector inspector, String clazz, boolean isR8) {
+ ClassSubject subject = inspector.clazz(clazz);
+ if (clazz.equals("kotlin._Assertions")) {
+ assert !kotlinStdlibAsLibrary;
+ if (isR8 && useJvmAssertions) {
+ // When JVM assertions are used the class kotlin._Assertions is unused.
+ assertThat(subject, not(isPresent()));
+ return;
+ }
+ assertThat(subject, isPresent());
+ // With R8 the static-put of the kotlin._Assertions.INSTANCE field is removed as is not used.
+ assertEquals(
+ isR8 ? 1 : 2,
+ subject
+ .uniqueMethodWithOriginalName("<clinit>")
+ .streamInstructions()
+ .filter(InstructionSubject::isStaticPut)
+ .count());
+ assertFalse(
+ subject
+ .uniqueMethodWithOriginalName("<clinit>")
+ .streamInstructions()
+ .anyMatch(InstructionSubject::isConstNumber));
+ } else {
+ assertThat(subject, isPresent());
+ MethodSubject clinit = subject.uniqueMethodWithOriginalName("<clinit>");
+ if (useJvmAssertions) {
+ assertTrue(clinit.streamInstructions().anyMatch(InstructionSubject::isStaticPut));
+ } else {
+ assertThat(clinit, not(isPresent()));
+ }
+ assertTrue(
+ subject
+ .uniqueMethodWithOriginalName("m")
+ .streamInstructions()
+ .anyMatch(InstructionSubject::isThrow));
+ }
+ }
+
+ protected void checkAssertionCodeRemoved(CodeInspector inspector, boolean isR8) {
+ if (isR8) {
+ assertThat(inspector.clazz("kotlin._Assertions"), not(isPresent()));
+ } else if (!kotlinStdlibAsLibrary) {
+ checkAssertionCodeRemoved(inspector, "kotlin._Assertions", isR8);
+ }
+ checkAssertionCodeRemoved(inspector, class1, isR8);
+ checkAssertionCodeRemoved(inspector, class2, isR8);
+ }
+
+ protected void checkAssertionCodeEnabled(CodeInspector inspector, boolean isR8) {
+ if (isR8) {
+ assertThat(inspector.clazz("kotlin._Assertions"), not(isPresent()));
+ } else if (!kotlinStdlibAsLibrary) {
+ checkAssertionCodeEnabled(inspector, "kotlin._Assertions", isR8);
+ }
+ checkAssertionCodeEnabled(inspector, class1, isR8);
+ checkAssertionCodeEnabled(inspector, class2, isR8);
+ }
+
+ protected void checkAssertionCodeLeft(CodeInspector inspector, boolean isR8) {
+ if (!kotlinStdlibAsLibrary) {
+ checkAssertionCodeLeft(inspector, "kotlin._Assertions", isR8);
+ }
+ checkAssertionCodeLeft(inspector, class1, isR8);
+ checkAssertionCodeLeft(inspector, class2, isR8);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinWithModifiedKotlinAssertionsTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinWithModifiedKotlinAssertionsTest.java
new file mode 100644
index 0000000..32c29d7
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinWithModifiedKotlinAssertionsTest.java
@@ -0,0 +1,165 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.rewrite.assertions;
+
+import com.android.tools.r8.AssertionsConfiguration;
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.BooleanUtils;
+import java.util.Collection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+@RunWith(Parameterized.class)
+public class AssertionConfigurationKotlinWithModifiedKotlinAssertionsTest
+ extends AssertionConfigurationKotlinTestBase implements Opcodes {
+
+ @Parameterized.Parameters(name = "{0}, {1}, kotlin-stdlib as library: {2}, -Xassertions=jvm: {3}")
+ public static Collection<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withDexRuntimesAndAllApiLevels().build(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
+ BooleanUtils.values(),
+ BooleanUtils.values());
+ }
+
+ public AssertionConfigurationKotlinWithModifiedKotlinAssertionsTest(
+ TestParameters parameters,
+ KotlinTestParameters kotlinParameters,
+ boolean kotlinStdlibAsClasspath,
+ boolean useJvmAssertions) {
+ super(parameters, kotlinParameters, kotlinStdlibAsClasspath, useJvmAssertions);
+ }
+
+ @Test
+ public void testPassthroughAllAssertions() throws Exception {
+ testForD8()
+ .addProgramClassFileData(dumpModifiedKotlinAssertions())
+ .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
+ .setMinApi(parameters)
+ .addAssertionsConfiguration(AssertionsConfiguration.Builder::passthroughAllAssertions)
+ .run(
+ parameters.getRuntime(),
+ getClass().getPackage().getName() + ".kotlintestclasses.TestClassKt")
+ .assertSuccessWithOutputLines(noAllAssertionsExpectedLines());
+ }
+
+ @Test
+ public void testCompileTimeEnableAllAssertions() throws Exception {
+ testForD8()
+ .addProgramClassFileData(dumpModifiedKotlinAssertions())
+ .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
+ .setMinApi(parameters)
+ .addAssertionsConfiguration(AssertionsConfiguration.Builder::compileTimeEnableAllAssertions)
+ .run(
+ parameters.getRuntime(),
+ getClass().getPackage().getName() + ".kotlintestclasses.TestClassKt")
+ .assertSuccessWithOutputLines(allAssertionsExpectedLines());
+ }
+
+ @Test
+ public void testCompileTimeDisableAllAssertions() throws Exception {
+ testForD8()
+ .addProgramClassFileData(dumpModifiedKotlinAssertions())
+ .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
+ .setMinApi(parameters)
+ .addAssertionsConfiguration(
+ AssertionsConfiguration.Builder::compileTimeDisableAllAssertions)
+ .run(
+ parameters.getRuntime(),
+ getClass().getPackage().getName() + ".kotlintestclasses.TestClassKt")
+ .assertSuccessWithOutputLines(noAllAssertionsExpectedLines());
+ }
+
+ // Slightly modified version of kotlin._Assertions to hit all code paths in the assertion
+ // rewriter. See "Code added" below.
+ public static byte[] dumpModifiedKotlinAssertions() {
+
+ ClassWriter classWriter = new ClassWriter(0);
+ FieldVisitor fieldVisitor;
+ MethodVisitor methodVisitor;
+
+ classWriter.visit(
+ V1_6,
+ ACC_PUBLIC | ACC_FINAL | ACC_SUPER,
+ "kotlin/_Assertions",
+ null,
+ "java/lang/Object",
+ null);
+
+ {
+ fieldVisitor =
+ classWriter.visitField(ACC_PUBLIC | ACC_FINAL | ACC_STATIC, "ENABLED", "Z", null, null);
+ fieldVisitor.visitEnd();
+ }
+ {
+ fieldVisitor =
+ classWriter.visitField(
+ ACC_PUBLIC | ACC_FINAL | ACC_STATIC, "INSTANCE", "Lkotlin/_Assertions;", null, null);
+ fieldVisitor.visitEnd();
+ }
+ {
+ methodVisitor =
+ classWriter.visitMethod(
+ ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC | ACC_DEPRECATED,
+ "ENABLED$annotations",
+ "()V",
+ null,
+ null);
+ methodVisitor.visitCode();
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(0, 0);
+ methodVisitor.visitEnd();
+ }
+ {
+ methodVisitor = classWriter.visitMethod(ACC_PRIVATE, "<init>", "()V", null, null);
+ methodVisitor.visitCode();
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(1, 1);
+ methodVisitor.visitEnd();
+ }
+ {
+ methodVisitor = classWriter.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
+ methodVisitor.visitCode();
+ methodVisitor.visitTypeInsn(NEW, "kotlin/_Assertions");
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitMethodInsn(INVOKESPECIAL, "kotlin/_Assertions", "<init>", "()V", false);
+ methodVisitor.visitVarInsn(ASTORE, 0);
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitFieldInsn(
+ PUTSTATIC, "kotlin/_Assertions", "INSTANCE", "Lkotlin/_Assertions;");
+
+ // Code added (added an additional call to getClass().desiredAssertionStatus() which
+ // result is not assigned to ENABLED).
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL, "java/lang/Class", "desiredAssertionStatus", "()Z", false);
+ methodVisitor.visitInsn(POP);
+ // End code added.
+
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;", false);
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL, "java/lang/Class", "desiredAssertionStatus", "()Z", false);
+ methodVisitor.visitFieldInsn(PUTSTATIC, "kotlin/_Assertions", "ENABLED", "Z");
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(2, 1);
+ methodVisitor.visitEnd();
+ }
+ classWriter.visitEnd();
+
+ return classWriter.toByteArray();
+ }
+}