| // 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.globalsynthetics; |
| |
| import static org.junit.Assert.assertEquals; |
| |
| import com.android.tools.r8.DexIndexedConsumer; |
| import com.android.tools.r8.GlobalSyntheticsGenerator; |
| import com.android.tools.r8.GlobalSyntheticsGeneratorCommand; |
| import com.android.tools.r8.TestBase; |
| import com.android.tools.r8.TestParameters; |
| import com.android.tools.r8.TestParametersCollection; |
| import com.android.tools.r8.ToolHelper; |
| import com.android.tools.r8.graph.DexItemFactory; |
| import com.android.tools.r8.references.Reference; |
| import com.android.tools.r8.utils.AndroidApiLevel; |
| import com.android.tools.r8.utils.SetUtils; |
| import com.android.tools.r8.utils.codeinspector.CodeInspector; |
| import com.android.tools.r8.utils.codeinspector.FoundClassSubject; |
| import java.nio.file.Path; |
| import java.util.HashSet; |
| import java.util.Set; |
| import java.util.stream.Collectors; |
| import org.junit.Test; |
| import org.junit.runner.RunWith; |
| import org.junit.runners.Parameterized; |
| import org.junit.runners.Parameterized.Parameters; |
| |
| @RunWith(Parameterized.class) |
| public class GlobalSyntheticsEnsureClassesOutputTest extends TestBase { |
| |
| @Parameters(name = "{0}") |
| public static TestParametersCollection data() { |
| return getTestParameters().withNoneRuntime().build(); |
| } |
| |
| public GlobalSyntheticsEnsureClassesOutputTest(TestParameters parameters) { |
| parameters.assertNoneRuntime(); |
| } |
| |
| @Test |
| public void testNumberOfClassesOnK() throws Exception { |
| Path output = temp.newFolder().toPath().resolve("output.zip"); |
| GlobalSyntheticsGenerator.run( |
| GlobalSyntheticsGeneratorCommand.builder() |
| .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.API_DATABASE_LEVEL)) |
| .setMinApiLevel(AndroidApiLevel.K.getLevel()) |
| .setProgramConsumer(new DexIndexedConsumer.ArchiveConsumer(output)) |
| .build()); |
| CodeInspector inspector = new CodeInspector(output); |
| assertEquals(1044, inspector.allClasses().size()); |
| } |
| |
| @Test |
| public void testNumberOfClassesOnLatest() throws Exception { |
| Path output = temp.newFolder().toPath().resolve("output.zip"); |
| GlobalSyntheticsGenerator.run( |
| GlobalSyntheticsGeneratorCommand.builder() |
| .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.API_DATABASE_LEVEL)) |
| .setMinApiLevel(AndroidApiLevel.LATEST.getLevel()) |
| .setProgramConsumer(new DexIndexedConsumer.ArchiveConsumer(output)) |
| .build()); |
| Set<String> expectedInOutput = new HashSet<>(); |
| // The output contains a RecordTag type that is mapped back to the original java.lang.Record by |
| // our codeinspector. |
| expectedInOutput.add("Ljava/lang/Record;"); |
| expectedInOutput.add("Ljava/lang/invoke/VarHandle;"); |
| expectedInOutput.add("Ljava/lang/invoke/MethodHandles$Lookup;"); |
| assertEquals( |
| expectedInOutput, |
| new CodeInspector(output) |
| .allClasses().stream() |
| .map(FoundClassSubject::getFinalDescriptor) |
| .collect(Collectors.toSet())); |
| } |
| |
| @Test |
| public void testClassFileListOutput() throws Exception { |
| Set<String> generatedGlobalSynthetics = SetUtils.newConcurrentHashSet(); |
| Path output = temp.newFolder().toPath().resolve("output.zip"); |
| runGlobalSyntheticsGenerator( |
| GlobalSyntheticsGeneratorCommand.builder() |
| .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.API_DATABASE_LEVEL)) |
| .setMinApiLevel(AndroidApiLevel.K.getLevel()) |
| .setProgramConsumer(new DexIndexedConsumer.ArchiveConsumer(output)) |
| .build(), |
| options -> |
| options.testing.globalSyntheticCreatedCallback = |
| programClass -> { |
| if (programClass |
| .getClassReference() |
| .getDescriptor() |
| .equals(DexItemFactory.varHandleDescriptorString)) { |
| // We emit a desugared var handle. Rewrite it here to allow checking for final |
| // type names. |
| generatedGlobalSynthetics.add( |
| Reference.classFromDescriptor( |
| DexItemFactory.desugarVarHandleDescriptorString) |
| .getTypeName()); |
| } else if (programClass |
| .getClassReference() |
| .getDescriptor() |
| .equals(DexItemFactory.methodHandlesLookupDescriptorString)) { |
| // We emit a desugared var handle. Rewrite it here to allow checking for final |
| // type names. |
| generatedGlobalSynthetics.add( |
| Reference.classFromDescriptor( |
| DexItemFactory.desugarMethodHandlesLookupDescriptorString) |
| .getTypeName()); |
| } else { |
| generatedGlobalSynthetics.add(programClass.getTypeName()); |
| } |
| }); |
| Set<String> readGlobalSynthetics = |
| new CodeInspector(output) |
| .allClasses().stream().map(FoundClassSubject::getFinalName).collect(Collectors.toSet()); |
| assertEquals(generatedGlobalSynthetics, readGlobalSynthetics); |
| } |
| } |