blob: 306853752bf74ca1831abda3bb843d25ec59806b [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;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.DataResourceProvider.Visitor;
import com.android.tools.r8.ProgramResource.Kind;
import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.dump.DumpOptions;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class AndroidAppDumpsTest extends TestBase {
@Parameterized.Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withNoneRuntime().build();
}
public AndroidAppDumpsTest(TestParameters parameters) {
parameters.assertNoneRuntime();
}
@Test
public void test() throws Exception {
InternalOptions options = new InternalOptions();
options.dumpOptions = DumpOptions.builder(Tool.D8).setBackend(Marker.Backend.DEX).build();
String dataResourceName = "my-resource.bin";
byte[] dataResourceData = new byte[] {1, 2, 3};
Path dexForB =
testForD8().addProgramClasses(B.class).setMinApi(AndroidApiLevel.B).compile().writeToZip();
AndroidApp appIn =
AndroidApp.builder(options.reporter)
.addClassProgramData(ToolHelper.getClassAsBytes(A.class), origin("A"))
.addClassProgramData(ToolHelper.getClassAsBytes(A.class), origin("A"))
.addClassProgramData(ToolHelper.getClassAsBytes(A.class), origin("A"))
.addProgramFile(dexForB)
.addClasspathResourceProvider(provider(B.class))
.addClasspathResourceProvider(provider(B.class))
.addClasspathResourceProvider(provider(B.class))
.addLibraryResourceProvider(provider(C.class))
.addLibraryResourceProvider(provider(C.class))
.addLibraryResourceProvider(provider(C.class))
.addProgramResourceProvider(
createDataResourceProvider(
dataResourceName, dataResourceData, origin(dataResourceName)))
.build();
Path dumpFile = temp.newFolder().toPath().resolve("dump.zip");
appIn.dump(dumpFile, options.dumpOptions, options);
AndroidApp appOut = AndroidApp.builder(options.reporter).addDump(dumpFile).build();
assertEquals(1, appOut.getClassProgramResourcesForTesting().size());
assertEquals(
DescriptorUtils.javaTypeToDescriptor(A.class.getTypeName()),
appOut.getClassProgramResourcesForTesting().get(0).getClassDescriptors().iterator().next());
assertEquals(1, appOut.getDexProgramResourcesForTesting().size());
assertEquals(1, appOut.getClasspathResourceProviders().size());
assertEquals(
DescriptorUtils.javaTypeToDescriptor(B.class.getTypeName()),
appOut.getClasspathResourceProviders().get(0).getClassDescriptors().iterator().next());
assertEquals(1, appOut.getLibraryResourceProviders().size());
assertEquals(
DescriptorUtils.javaTypeToDescriptor(C.class.getTypeName()),
appOut.getLibraryResourceProviders().get(0).getClassDescriptors().iterator().next());
Box<Boolean> foundData = new Box<>(false);
for (ProgramResourceProvider provider : appOut.getProgramResourceProviders()) {
DataResourceProvider dataProvider = provider.getDataResourceProvider();
if (dataProvider != null) {
dataProvider.accept(
new Visitor() {
@Override
public void visit(DataDirectoryResource directory) {}
@Override
public void visit(DataEntryResource file) {
if (file.getName().equals(dataResourceName)) {
foundData.set(true);
}
}
});
}
}
assertTrue(foundData.get());
}
private ProgramResourceProvider createDataResourceProvider(
String name, byte[] content, Origin origin) {
return new ProgramResourceProvider() {
@Override
public Collection<ProgramResource> getProgramResources() {
return Collections.emptyList();
}
@Override
public DataResourceProvider getDataResourceProvider() {
return new DataResourceProvider() {
@Override
public void accept(Visitor visitor) {
visitor.visit(
new DataEntryResource() {
@Override
public InputStream getByteStream() {
return new ByteArrayInputStream(content);
}
@Override
public String getName() {
return name;
}
@Override
public Origin getOrigin() {
return origin;
}
});
}
};
}
};
}
private Origin origin(String name) {
return new Origin(Origin.root()) {
@Override
public String part() {
return name;
}
};
}
private ClassFileResourceProvider provider(Class<?> clazz) {
return new ClassFileResourceProvider() {
@Override
public Set<String> getClassDescriptors() {
return Collections.singleton(DescriptorUtils.javaTypeToDescriptor(clazz.getTypeName()));
}
@Override
public ProgramResource getProgramResource(String descriptor) {
try {
return ProgramResource.fromBytes(
origin(clazz.getTypeName()),
Kind.CF,
ToolHelper.getClassAsBytes(clazz),
getClassDescriptors());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
};
}
public static class A {}
public static class B {}
public static class C {}
}