|
18 | 18 |
|
19 | 19 | import com.android.tools.r8.D8;
|
20 | 20 | import com.android.tools.r8.D8Command;
|
| 21 | +import com.android.tools.r8.DiagnosticsHandler; |
21 | 22 | import com.android.tools.r8.OutputMode;
|
| 23 | +import com.google.common.cache.Cache; |
| 24 | +import com.google.common.cache.CacheBuilder; |
22 | 25 | import com.google.common.collect.ImmutableList;
|
23 | 26 | import com.google.devtools.common.options.OptionsParsingException;
|
24 | 27 | import java.io.BufferedReader;
|
25 | 28 | import java.io.IOException;
|
26 | 29 | import java.io.InputStreamReader;
|
| 30 | +import java.io.PrintWriter; |
27 | 31 | import java.nio.file.Files;
|
28 | 32 | import java.nio.file.Path;
|
| 33 | +import java.util.Arrays; |
29 | 34 | import java.util.HashSet;
|
30 | 35 | import java.util.Set;
|
31 | 36 | import java.util.concurrent.ExecutionException;
|
@@ -122,6 +127,54 @@ public void compileWithSyntheticLambdas() throws Exception {
|
122 | 127 | }
|
123 | 128 | }
|
124 | 129 |
|
| 130 | + @Test |
| 131 | + public void compileWithCachedSyntheticLambdas() throws Exception { |
| 132 | + // Test synthetic context information is cached alongside dexed classes |
| 133 | + CompatDexBuilder compatDexBuilder = new CompatDexBuilder(); |
| 134 | + Cache<CompatDexBuilder.DexingKeyR8, CompatDexBuilder.DexingEntryR8> dexCache = |
| 135 | + CacheBuilder.newBuilder().build(); |
| 136 | + DiagnosticsHandler diagnostics = new DiagnosticsHandler() {}; |
| 137 | + PrintWriter pw = new PrintWriter(System.err); |
| 138 | + |
| 139 | + final String contextName = "com/google/devtools/build/android/r8/testdata/lambda/Lambda"; |
| 140 | + final String inputJar = System.getProperty("CompatDexBuilderTests.lambda"); |
| 141 | + final Path outputZipA = temp.getRoot().toPath().resolve("outA.zip"); |
| 142 | + final Path outputZipB = temp.getRoot().toPath().resolve("outB.zip"); |
| 143 | + |
| 144 | + String[] args = new String[] {"--input_jar", inputJar, "--output_zip", outputZipA.toString()}; |
| 145 | + compatDexBuilder.processRequest(dexCache, diagnostics, Arrays.asList(args), pw); |
| 146 | + |
| 147 | + args = new String[] {"--input_jar", inputJar, "--output_zip", outputZipB.toString()}; |
| 148 | + compatDexBuilder.processRequest(dexCache, diagnostics, Arrays.asList(args), pw); |
| 149 | + |
| 150 | + Path[] outputZips = new Path[] {outputZipA, outputZipB}; |
| 151 | + for (Path outputZip: outputZips) { |
| 152 | + try (ZipFile zipFile = new ZipFile(outputZip.toFile(), UTF_8)) { |
| 153 | + assertThat(zipFile.getEntry(contextName + ".class.dex")).isNotNull(); |
| 154 | + ZipEntry entry = zipFile.getEntry("META-INF/synthetic-contexts.map"); |
| 155 | + assertThat(entry).isNotNull(); |
| 156 | + try (BufferedReader reader = |
| 157 | + new BufferedReader(new InputStreamReader(zipFile.getInputStream(entry), UTF_8))) { |
| 158 | + String line = reader.readLine(); |
| 159 | + assertThat(line).isNotNull(); |
| 160 | + // Format of mapping is: <synthetic-binary-name>;<context-binary-name>\n |
| 161 | + int sep = line.indexOf(';'); |
| 162 | + String syntheticNameInMap = line.substring(0, sep); |
| 163 | + String contextNameInMap = line.substring(sep + 1); |
| 164 | + // The synthetic will be prefixed by the context type. This checks the synthetic name |
| 165 | + // is larger than the context to avoid hardcoding the synthetic names, which may change. |
| 166 | + assertThat(syntheticNameInMap).startsWith(contextName); |
| 167 | + assertThat(syntheticNameInMap).isNotEqualTo(contextName); |
| 168 | + // Check expected context. |
| 169 | + assertThat(contextNameInMap).isEqualTo(contextName); |
| 170 | + // Only one synthetic and its context should be present. |
| 171 | + line = reader.readLine(); |
| 172 | + assertThat(line).isNull(); |
| 173 | + } |
| 174 | + } |
| 175 | + } |
| 176 | + } |
| 177 | + |
125 | 178 | @Test
|
126 | 179 | public void compileTwoClassesAndRun() throws Exception {
|
127 | 180 | // Run CompatDexBuilder on dexMergeSample.jar
|
|
0 commit comments