blob: e2414559926ec49d994275b77bbd97bc44c5bf38 [file] [log] [blame]
Morten Krogh-Jespersendc0d5912022-05-11 10:41:26 +02001// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5package com.android.tools.r8.apimodel;
6
7import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForClass;
8import static com.android.tools.r8.apimodel.ApiModelingTestHelper.setMockApiLevelForMethod;
Morten Krogh-Jespersendc0d5912022-05-11 10:41:26 +02009import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
Morten Krogh-Jespersendc0d5912022-05-11 10:41:26 +020010import static org.hamcrest.MatcherAssert.assertThat;
11import static org.junit.Assert.assertEquals;
12import static org.junit.Assert.assertFalse;
13
14import com.android.tools.r8.CompilationMode;
15import com.android.tools.r8.OutputMode;
16import com.android.tools.r8.SingleTestRunResult;
17import com.android.tools.r8.TestBase;
18import com.android.tools.r8.TestCompilerBuilder;
19import com.android.tools.r8.TestParameters;
20import com.android.tools.r8.TestParametersCollection;
21import com.android.tools.r8.synthesis.globals.GlobalSyntheticsTestingConsumer;
22import com.android.tools.r8.utils.AndroidApiLevel;
23import com.android.tools.r8.utils.codeinspector.ClassSubject;
24import com.android.tools.r8.utils.codeinspector.CodeInspector;
Morten Krogh-Jespersen1aaf9c82022-05-11 10:46:20 +020025import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
Morten Krogh-Jespersendc0d5912022-05-11 10:41:26 +020026import java.nio.file.Path;
27import java.util.ArrayList;
28import java.util.List;
29import org.junit.Test;
30import org.junit.runner.RunWith;
31import org.junit.runners.Parameterized;
32import org.junit.runners.Parameterized.Parameter;
33import org.junit.runners.Parameterized.Parameters;
34
35@RunWith(Parameterized.class)
36public class ApiModelNoHorizontalMergeAndD8MergeTest extends TestBase {
37
38 private final AndroidApiLevel oneMockLevel = AndroidApiLevel.M;
39 private final AndroidApiLevel otherMockLevel = AndroidApiLevel.N;
40
41 @Parameter() public TestParameters parameters;
42
43 @Parameters(name = "{0}")
44 public static TestParametersCollection data() {
45 return getTestParameters().withDexRuntimes().withAllApiLevels().build();
46 }
47
48 private boolean isGreaterOrEqualToMockLevel() {
49 return parameters.isDexRuntime()
50 && parameters.getApiLevel().isGreaterThanOrEqualTo(oneMockLevel);
51 }
52
53 private void setupTestCompileBuilder(TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder)
54 throws NoSuchMethodException {
55 testBuilder
56 .addLibraryClasses(LibraryClass.class)
57 .addDefaultRuntimeLibrary(parameters)
58 .setMinApi(parameters.getApiLevel())
59 .apply(ApiModelingTestHelper::enableApiCallerIdentification)
60 .apply(ApiModelingTestHelper::enableOutliningOfMethods)
61 .apply(setMockApiLevelForClass(LibraryClass.class, oneMockLevel))
62 .apply(setMockApiLevelForMethod(LibraryClass.class.getDeclaredMethod("foo"), oneMockLevel))
63 .apply(
64 setMockApiLevelForMethod(LibraryClass.class.getDeclaredMethod("bar"), otherMockLevel));
65 }
66
67 private boolean addToBootClasspath() {
68 return parameters.isDexRuntime()
69 && parameters.getRuntime().maxSupportedApiLevel().isGreaterThanOrEqualTo(oneMockLevel);
70 }
71
72 @Test
73 public void testD8DebugDexFilePerClassFile() throws Exception {
74 testD8Merge(CompilationMode.DEBUG);
75 }
76
77 @Test
78 public void testD8ReleaseDexFilePerClassFile() throws Exception {
79 testD8Merge(CompilationMode.RELEASE);
80 }
81
82 private Path runD8ForClass(
83 Class<?> clazz, GlobalSyntheticsTestingConsumer global, CompilationMode mode)
84 throws Exception {
85 return testForD8()
86 .addProgramClasses(clazz)
87 .setMode(mode)
88 .setOutputMode(OutputMode.DexFilePerClassFile)
89 .apply(b -> b.getBuilder().setGlobalSyntheticsConsumer(global))
90 .apply(this::setupTestCompileBuilder)
91 .compile()
92 .writeToZip();
93 }
94
95 public void testD8Merge(CompilationMode mode) throws Exception {
96 List<Path> paths = new ArrayList<>();
97 GlobalSyntheticsTestingConsumer mainGlobals = new GlobalSyntheticsTestingConsumer();
98 GlobalSyntheticsTestingConsumer testCallingFooGlobals = new GlobalSyntheticsTestingConsumer();
99 GlobalSyntheticsTestingConsumer testCallingBarGlobals = new GlobalSyntheticsTestingConsumer();
100 paths.add(runD8ForClass(Main.class, mainGlobals, mode));
101 paths.add(runD8ForClass(TestCallingFoo.class, testCallingFooGlobals, mode));
102 paths.add(runD8ForClass(TestCallingBar.class, testCallingBarGlobals, mode));
103 assertFalse(mainGlobals.hasGlobals());
104 assertFalse(testCallingFooGlobals.hasGlobals());
105 assertFalse(testCallingBarGlobals.hasGlobals());
Morten Krogh-Jespersen1aaf9c82022-05-11 10:46:20 +0200106 testForD8()
107 .setMode(mode)
108 .addProgramFiles(paths)
109 .apply(this::setupTestCompileBuilder)
110 .addHorizontallyMergedClassesInspector(
111 HorizontallyMergedClassesInspector::assertNoClassesMerged)
112 .compile()
113 .inspect(inspector -> inspect(inspector, mode))
114 .applyIf(addToBootClasspath(), b -> b.addBootClasspathClasses(LibraryClass.class))
115 .run(parameters.getRuntime(), Main.class)
116 .apply(this::checkOutput);
Morten Krogh-Jespersendc0d5912022-05-11 10:41:26 +0200117 }
118
119 private void inspect(CodeInspector inspector, CompilationMode mode) {
120 ClassSubject libraryClassSubject = inspector.clazz(LibraryClass.class);
121 if (isGreaterOrEqualToMockLevel()) {
122 assertThat(libraryClassSubject, isAbsent());
123 } else {
Morten Krogh-Jespersen1aaf9c82022-05-11 10:46:20 +0200124 assertEquals(5, inspector.allClasses().size());
Morten Krogh-Jespersendc0d5912022-05-11 10:41:26 +0200125 }
126 }
127
128 private void checkOutput(SingleTestRunResult<?> runResult) {
129 runResult.assertSuccessWithOutputLinesIf(
130 addToBootClasspath(), "LibraryClass::foo", "LibraryClass::bar");
131 runResult.assertFailureWithErrorThatThrowsIf(!addToBootClasspath(), NoClassDefFoundError.class);
132 }
133
134 // Only present form api level 23.
135 public static class LibraryClass {
136
137 public static void foo() {
138 System.out.println("LibraryClass::foo");
139 }
140
141 public static void bar() {
142 System.out.println("LibraryClass::bar");
143 }
144 }
145
146 public static class TestCallingFoo {
147
148 public static void callFoo() {
149 LibraryClass.foo();
150 }
151 }
152
153 public static class TestCallingBar {
154
155 public static void callBar() {
156 LibraryClass.bar();
157 }
158 }
159
160 public static class Main {
161
162 public static void main(String[] args) {
163 TestCallingFoo.callFoo();
164 TestCallingBar.callBar();
165 }
166 }
167}