blob: bb595336a839224cb20f85e129e11cf8d0839878 [file] [log] [blame]
// Copyright (c) 2019, 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.desugar.nestaccesscontrol;
import static com.android.tools.r8.desugar.nestaccesscontrol.NestAccessControlTestUtils.CLASSES_PATH;
import static com.android.tools.r8.desugar.nestaccesscontrol.NestAccessControlTestUtils.CLASS_NAMES;
import static com.android.tools.r8.desugar.nestaccesscontrol.NestAccessControlTestUtils.JAR;
import static com.android.tools.r8.desugar.nestaccesscontrol.NestAccessControlTestUtils.getExpectedResult;
import static com.android.tools.r8.desugar.nestaccesscontrol.NestAccessControlTestUtils.getMainClass;
import static com.android.tools.r8.utils.FileUtils.CLASS_EXTENSION;
import static java.util.stream.Collectors.toList;
import static org.hamcrest.core.StringContains.containsString;
import static org.hamcrest.core.StringEndsWith.endsWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.D8TestCompileResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
import java.nio.file.Path;
import java.util.List;
import org.hamcrest.Matcher;
import org.junit.Assume;
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 NestOnProgramAndClassPathTest extends TestBase {
public NestOnProgramAndClassPathTest(TestParameters parameters) {
this.parameters = parameters;
}
private final TestParameters parameters;
@Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withDexRuntimes().withAllApiLevels().build();
}
@Test
public void testD8MethodBridgesPresent() throws Exception {
Assume.assumeTrue(parameters.isDexRuntime());
// 1 inner class.
D8TestCompileResult singleInner =
compileClassesWithD8ProgramClassesMatching(
containsString("BasicNestHostWithInnerClassMethods$BasicNestedClass"));
singleInner.inspect(inspector -> assertThisNumberOfBridges(inspector, 2));
// Outer class.
D8TestCompileResult host =
compileClassesWithD8ProgramClassesMatching(endsWith("BasicNestHostWithInnerClassMethods"));
host.inspect(inspector -> assertThisNumberOfBridges(inspector, 2));
// 2 inner classes.
D8TestCompileResult multipleInner =
compileClassesWithD8ProgramClassesMatching(
containsString("NestHostExample$StaticNestMemberInner"));
multipleInner.inspect(inspector -> assertThisNumberOfBridges(inspector, 5));
}
@Test
public void testD8ConstructorBridgesPresent() throws Exception {
Assume.assumeTrue(parameters.isDexRuntime());
D8TestCompileResult inner =
compileClassesWithD8ProgramClassesMatching(
containsString("BasicNestHostWithInnerClassConstructors$BasicNestedClass"));
inner.inspect(
inspector -> {
assertThisNumberOfBridges(inspector, 3);
assertNestConstructor(inspector);
});
D8TestCompileResult host =
compileClassesWithD8ProgramClassesMatching(
endsWith("BasicNestHostWithInnerClassConstructors"));
host.inspect(
inspector -> {
assertThisNumberOfBridges(inspector, 1);
assertNestConstructor(inspector);
});
}
@Test
public void testD8ConstructorNestMergeCorrect() throws Exception {
// Multiple Nest Constructor classes have to be merged here.
Assume.assumeTrue(parameters.isDexRuntime());
D8TestCompileResult inner =
compileClassesWithD8ProgramClassesMatching(
containsString("BasicNestHostWithInnerClassConstructors$BasicNestedClass"));
D8TestCompileResult host =
compileClassesWithD8ProgramClassesMatching(
endsWith("BasicNestHostWithInnerClassConstructors"));
testForD8()
.addProgramFiles(inner.writeToZip(), host.writeToZip())
.setMinApi(parameters.getApiLevel())
.addOptionsModification(options -> options.enableNestBasedAccessDesugaring = true)
.compile()
.inspect(inspector -> assertEquals(3, inspector.allClasses().size()))
.run(parameters.getRuntime(), getMainClass("constructors"))
.assertSuccessWithOutput(getExpectedResult("constructors"));
}
private D8TestCompileResult compileClassesWithD8ProgramClassesMatching(Matcher<String> matcher)
throws Exception {
List<Path> matchingClasses =
CLASS_NAMES.stream()
.filter(matcher::matches)
.map(name -> CLASSES_PATH.resolve(name + CLASS_EXTENSION))
.collect(toList());
return testForD8()
.setMinApi(parameters.getApiLevel())
.addProgramFiles(matchingClasses)
.addClasspathFiles(JAR)
.addOptionsModification(options -> options.enableNestBasedAccessDesugaring = true)
.compile();
}
private static void assertNestConstructor(CodeInspector inspector) {
assertTrue(inspector.allClasses().stream().anyMatch(FoundClassSubject::isSynthetic));
}
private static void assertThisNumberOfBridges(CodeInspector inspector, int numBridges) {
for (FoundClassSubject clazz : inspector.allClasses()) {
if (!clazz.isSynthetic()) {
assertEquals(numBridges, clazz.allMethods(FoundMethodSubject::isSynthetic).size());
}
}
}
}