blob: 8168e338ea6c1a34e5ed8b19b79fcea86fb6fa91 [file] [log] [blame]
// Copyright (c) 2022, 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.desugaredlibrary.jdktests;
import static com.android.tools.r8.ToolHelper.JDK_TESTS_BUILD_DIR;
import static com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11SupportFiles.testNGSupportProgramFiles;
import static com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11TestLibraryDesugaringSpecification.EXTENSION_PATH;
import static com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11TestLibraryDesugaringSpecification.JDK11_PATH_JAVA_BASE_EXT;
import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8SHRINK;
import static com.android.tools.r8.utils.FileUtils.CLASS_EXTENSION;
import static com.android.tools.r8.utils.FileUtils.JAVA_EXTENSION;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.D8TestCompileResult;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
import com.android.tools.r8.desugar.desugaredlibrary.test.DesugaredLibraryTestCompileResult;
import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.transformers.ClassFileTransformer;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import org.jetbrains.annotations.NotNull;
import org.junit.Assume;
import org.junit.BeforeClass;
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 Jdk11NioFileTests extends DesugaredLibraryTestBase {
private static final Path JDK_11_NIO_TEST_FILES_DIR =
Paths.get(ToolHelper.JDK_11_TESTS_DIR).resolve("java/nio/file");
private static Path TEST_UTIL_JAR;
private static List<byte[]> TEST_PROGRAM_CLASS_DATA;
private final TestParameters parameters;
private final LibraryDesugaringSpecification libraryDesugaringSpecification;
private final CompilationSpecification compilationSpecification;
@Parameters(name = "{0}, spec: {1}, {2}")
public static List<Object[]> data() throws Exception {
List<LibraryDesugaringSpecification> specs;
if (ToolHelper.isWindows()) {
// The library configuration is not available on windows. Do not run anything.
specs = ImmutableList.of();
} else {
Jdk11TestLibraryDesugaringSpecification.setUp();
specs = ImmutableList.of(JDK11_PATH_JAVA_BASE_EXT);
}
return buildParameters(
// TODO(134732760): Support Dalvik VMs, currently fails because libjavacrypto is required
// and present only in ART runtimes.
getTestParameters()
.withDexRuntimesStartingFromIncluding(Version.V5_1_1)
.withAllApiLevels()
.build(),
specs,
ImmutableList.of(D8_L8DEBUG, D8_L8SHRINK));
}
public Jdk11NioFileTests(
TestParameters parameters,
LibraryDesugaringSpecification libraryDesugaringSpecification,
CompilationSpecification compilationSpecification) {
this.parameters = parameters;
this.libraryDesugaringSpecification = libraryDesugaringSpecification;
this.compilationSpecification = compilationSpecification;
}
private static final List<String> EXCLUDE_COMPILATION =
ImmutableList.copyOf(
new String[] {
// We cannot run these tests due to missing dependencies.
"java/nio/file/FileStore/Basic.java",
"java/nio/file/Path/MacPathTest.java",
"java/nio/file/WatchService/LotsOfEvents.java",
"java/nio/file/Files/StreamLinesTest.java",
"java/nio/file/Files/walkFileTree/FindTest.java",
"java/nio/file/Files/DeleteOnClose.java",
"java/nio/file/Files/CopyAndMove.java",
"java/nio/file/FileSystem/Basic.java",
// Skip module info not used on Android.
"module-info.java"
});
// We distinguish 2 kinds of tests:
// - Main tests, which are run by running the main method, and succeed if no error is raised.
// - TestNG tests, which are run using testNG.
private static final List<String> SUCCESSFUL_MAIN_TESTS =
ImmutableList.of(
"PathUriImportExport",
"PathMisc",
"probeContentTypeParallelProbes",
"probeContentTypeForceLoad",
"AclEntryEmptySet",
"DirectoryStreamBasic",
"DirectoryStreamSecureDS",
"DirectoryStreamDriveLetter",
"FileTimeBasic",
"BasicFileAttributeViewCreationTime",
"BasicFileAttributeViewBasic",
"etcExceptions",
"walkFileTreeTerminateWalk",
"walkFileTreeNulls",
"walkFileTreeCreateFileTree",
"walkFileTreeMaxDepth",
"walkFileTreeSkipSiblings",
"walkFileTreeSkipSubtree",
"FilesSBC",
"FilesNameLimits",
"FilesCustomOptions",
"FilesLinks",
"WatchServiceBasic",
"WatchServiceFileTreeModifier",
"WatchServiceDeleteInterference",
"WatchServiceLotsOfCancels",
"WatchServiceSensitivityModifier");
private static final List<String> FAILING_MAIN_TESTS =
ImmutableList.of(
"PathPathOps",
"PathMacPath",
"DosFileAttributeViewBasic",
"probeContentTypeBasic",
"AclFileAttributeViewBasic",
"UserDefinedFileAttributeViewBasic",
"PosixFileAttributeViewBasic",
"BasicFileAttributeViewUnixSocketFile",
"p/pMain",
"PathMatcherBasic",
"walkFileTreeWalkWithSecurity",
"FilesFileAttributes",
"FilesInterruptCopy",
"FilesTemporaryFiles",
"FilesCheckPermissions",
"FilesMisc",
"WatchServiceMayFlies", // Works but longest to run by far.
"WatchServiceWithSecurityManager",
"WatchServiceUpdateInterference",
"WatchServiceLotsOfCloses");
private static final List<String> SUCCESSFUL_TESTNG_TESTS =
ImmutableList.of("FilesStreamTest", "FilesBytesAndLines");
private static final List<String> FAILING_TESTNG_TESTS =
ImmutableList.of("spiSetDefaultProvider", "FilesReadWriteString");
@BeforeClass
public static void compileJdk11NioTests() throws Exception {
Map<String, List<Path>> nioTestFileBuckets = getSourceFileBuckets();
TEST_UTIL_JAR = jarTestUtils(nioTestFileBuckets.get("file"));
nioTestFileBuckets.remove("file");
TEST_PROGRAM_CLASS_DATA = new ArrayList<>();
for (Entry<String, List<Path>> entry : nioTestFileBuckets.entrySet()) {
Path[] compiledClasses = compile(entry.getKey(), entry.getValue(), TEST_UTIL_JAR);
assert compiledClasses.length > 0;
TEST_PROGRAM_CLASS_DATA.addAll(repackage(entry.getKey(), compiledClasses));
}
assert !TEST_PROGRAM_CLASS_DATA.isEmpty();
}
@NotNull
private static Map<String, List<Path>> getSourceFileBuckets() throws IOException {
Map<String, List<Path>> nioTestFileBuckets =
Files.walk(JDK_11_NIO_TEST_FILES_DIR)
.filter(path -> path.toString().endsWith(JAVA_EXTENSION))
.filter(
path ->
EXCLUDE_COMPILATION.stream().noneMatch(elem -> path.toString().endsWith(elem)))
.collect(Collectors.groupingBy(item -> item.getParent().getFileName().toString()));
assert nioTestFileBuckets.size() > 0;
return nioTestFileBuckets;
}
private static Path jarTestUtils(List<Path> sourceFiles) throws IOException {
Path[] fileCompiledClasses = compile("file", sourceFiles, null);
String jarName = "testUtils.jar";
Path output = fileCompiledClasses[0].getParent();
List<String> cmdline = new ArrayList<>();
cmdline.add(TestRuntime.getCheckedInJdk11().getJavaExecutable().getParent() + "/jar");
cmdline.add("cf");
cmdline.add(jarName);
for (Path compile : fileCompiledClasses) {
cmdline.add(output.relativize(compile).toString());
}
ProcessBuilder builder = new ProcessBuilder(cmdline);
builder.directory(output.toFile());
ProcessResult result = ToolHelper.runProcess(builder);
assert result.exitCode == 0;
return output.resolve(jarName);
}
private static List<byte[]> repackage(String prefix, Path[] compiledClasses) throws IOException {
List<byte[]> data = new ArrayList<>();
Map<String, String> rewrite = new HashMap<>();
for (Path compiledClass : compiledClasses) {
String fileName = compiledClass.getFileName().toString();
String basicName = fileName.substring(0, fileName.length() - CLASS_EXTENSION.length());
rewrite.put(basicName, prefix + basicName);
}
for (Path compiledClass : compiledClasses) {
String fileName = compiledClass.getFileName().toString();
String basicName = fileName.substring(0, fileName.length() - CLASS_EXTENSION.length());
ClassFileTransformer classFileTransformer =
transformer(compiledClass, Reference.classFromDescriptor("L" + basicName + ";"))
.setClassDescriptor("L" + rewrite.get(basicName) + ";")
.setSuper(type -> rewrite.getOrDefault(type, type))
.rewriteEnlosingAndNestAttributes(type -> rewrite.getOrDefault(type, type));
rewrite.forEach(
(key, val) -> {
classFileTransformer.replaceClassDescriptorInMethodInstructions(
"L" + key + ";", "L" + val + ";");
classFileTransformer.replaceClassDescriptorInMembers("L" + key + ";", "L" + val + ";");
});
data.add(classFileTransformer.transform());
}
return data;
}
private static Path[] compile(String name, List<Path> sourceFiles, Path cp) throws IOException {
List<String> options =
Arrays.asList(
"--add-reads",
"java.base=ALL-UNNAMED",
"--patch-module",
"java.base=" + EXTENSION_PATH);
Path tmpDirectory = getStaticTemp().newFolder(name).toPath();
List<Path> classpath = new ArrayList<>();
classpath.add(EXTENSION_PATH);
classpath.add(Paths.get(JDK_TESTS_BUILD_DIR + "testng-6.10.jar"));
if (cp != null) {
classpath.add(cp);
}
javac(TestRuntime.getCheckedInJdk11(), getStaticTemp())
.addOptions(options)
.addClasspathFiles(classpath)
.addSourceFiles(sourceFiles)
.setOutputPath(tmpDirectory)
.compile();
return getAllFilesWithSuffixInDirectory(tmpDirectory, CLASS_EXTENSION);
}
@Test
public void testNioFileDesugaredLib() throws Exception {
String verbosity = "2";
DesugaredLibraryTestCompileResult<?> compileResult =
testForDesugaredLibrary(
parameters, libraryDesugaringSpecification, compilationSpecification)
.addProgramFiles(TEST_UTIL_JAR)
.addProgramClassFileData(TEST_PROGRAM_CLASS_DATA)
.addProgramFiles(testNGSupportProgramFiles())
.compile()
.withArt6Plus64BitsLib();
int success = 0;
int failures = 0;
for (String mainTestClass : SUCCESSFUL_MAIN_TESTS) {
SingleTestRunResult<?> run = compileResult.run(parameters.getRuntime(), mainTestClass);
if (run.getExitCode() != 0) {
System.out.println("Main Fail " + mainTestClass);
failures++;
} else {
success++;
}
}
for (String testNGTestClass : SUCCESSFUL_TESTNG_TESTS) {
SingleTestRunResult<?> result =
compileResult.run(
parameters.getRuntime(), "TestNGMainRunner", verbosity, testNGTestClass);
if (!result.getStdOut().contains(StringUtils.lines(testNGTestClass + ": SUCCESS"))) {
System.out.println("TestNG Fail " + testNGTestClass);
failures++;
} else {
success++;
}
}
// TODO(b/234689867): Understand and fix these issues.
// Most issues seem to come from the missing secure.properties file. This file is not accessed
// in all tests on all API levels, hence a different number of failures on each level.
System.out.println("Successes :" + success + "; failures " + failures);
assertTrue(success >= 11);
assertTrue(failures <= 20);
}
@Test
public void testNioFileAndroid() throws Exception {
Assume.assumeFalse(
"The package java.nio was not present on older devices, all tests fail.",
parameters.getDexRuntimeVersion().isOlderThan(Version.V8_1_0));
String verbosity = "2";
D8TestCompileResult compileResult =
testForD8(parameters.getBackend())
.addProgramFiles(TEST_UTIL_JAR)
.addProgramClassFileData(TEST_PROGRAM_CLASS_DATA)
.addProgramFiles(testNGSupportProgramFiles())
.addLibraryFiles(libraryDesugaringSpecification.getLibraryFiles())
.compile()
.withArt6Plus64BitsLib();
for (String mainTestClass : SUCCESSFUL_MAIN_TESTS) {
compileResult.run(parameters.getRuntime(), mainTestClass).assertSuccess();
}
for (String testNGTestClass : SUCCESSFUL_TESTNG_TESTS) {
SingleTestRunResult<?> result =
compileResult.run(
parameters.getRuntime(), "TestNGMainRunner", verbosity, testNGTestClass);
assertTrue(
"Failure in " + testNGTestClass + "\n" + result,
result.getStdOut().contains(StringUtils.lines(testNGTestClass + ": SUCCESS")));
}
}
}