Jdk Time Tests Android 4

- JDK time tests partially working on Android 4

Bug: 134732760
Change-Id: Ic9752103e0784abb367fd1e16fdaaf2be6377736
diff --git a/build.gradle b/build.gradle
index 889620f..c409bef 100644
--- a/build.gradle
+++ b/build.gradle
@@ -46,6 +46,7 @@
     kotlinExtMetadataJVMVersion = '0.0.4'
     smaliVersion = '2.2b4'
     errorproneVersion = '2.3.2'
+    testngVersion = '6.10'
 }
 
 apply from: 'copyAdditionalJctfCommonFiles.gradle'
@@ -142,6 +143,20 @@
             include '**ExactArithTests.java'
         }
     }
+    jdk11TimeTests {
+        java {
+            srcDirs = [
+                    'third_party/openjdk/jdk-11-test/java/time/tck',
+                    'third_party/openjdk/jdk-11-test/java/time/test'
+            ]
+            exclude '**/TestZoneTextPrinterParser.java'
+        }
+    }
+    testNGRunner {
+        java {
+            srcDirs = ['src/test/testngrunner']
+        }
+    }
     examplesKotlin {
         java {
             srcDirs = ['src/test/examplesKotlin']
@@ -246,6 +261,8 @@
     implementation group: 'org.ow2.asm', name: 'asm-tree', version: asmVersion
     implementation group: 'org.ow2.asm', name: 'asm-analysis', version: asmVersion
     implementation group: 'org.ow2.asm', name: 'asm-util', version: asmVersion
+    jdk11TimeTestsCompile group: 'org.testng', name: 'testng', version: testngVersion
+    testNGRunnerCompile group: 'org.testng', name: 'testng', version: testngVersion
     testCompile sourceSets.examples.output
     testCompile "junit:junit:$junitVersion"
     testCompile group: 'org.smali', name: 'smali', version: smaliVersion
@@ -561,6 +578,8 @@
 setJava11Compilation(sourceSets.jdk11MathTests.compileJavaTaskName)
 setJava11Compilation(sourceSets.jdk11ObjectsTests.compileJavaTaskName)
 setJava11Compilation(sourceSets.jdk11StrictMathTests.compileJavaTaskName)
+setJava11Compilation(sourceSets.testNGRunner.compileJavaTaskName)
+setJava11Compilation(sourceSets.jdk11TimeTests.compileJavaTaskName)
 
 task compileMainWithJava11 (type: JavaCompile) {
     def jdkDir = 'third_party/openjdk/jdk-11/'
@@ -1464,6 +1483,28 @@
     }
 }
 
+task provideJdk11TestsDependencies(type: org.gradle.api.tasks.Copy) {
+    from sourceSets.jdk11TimeTests.compileClasspath
+    include "**/**.jar"
+    into file("build/test/jdk11Tests")
+}
+
+task buildJdk11TimeTestsJar {
+    def exampleOutputDir = file("build/test/jdk11Tests");
+    def jarName = "jdk11TimeTests.jar"
+    dependsOn "jar_jdk11TimeTests"
+    dependsOn provideJdk11TestsDependencies
+    task "jar_jdk11TimeTests"(type: Jar) {
+        archiveName = jarName
+        destinationDir = exampleOutputDir
+        from sourceSets.testNGRunner.output
+        include "**.class"
+        from sourceSets.jdk11TimeTests.output
+        include "**.class"
+        include "**/**.class"
+    }
+}
+
 task buildExamplesKotlin {
     if (OperatingSystem.current().isMacOsX() || OperatingSystem.current().isWindows()) {
         logger.lifecycle("WARNING: Testing (including building kotlin examples) is only partially" +
@@ -1870,6 +1911,7 @@
         dependsOn sourceSets.jdk11MathTests.output
         dependsOn sourceSets.jdk11ObjectsTests.output
         dependsOn sourceSets.jdk11StrictMathTests.output
+        dependsOn buildJdk11TimeTestsJar
     } else {
         logger.lifecycle("WARNING: Testing in not supported on your platform. Testing is only fully supported on " +
             "Linux and partially supported on Mac OS and Windows. Art does not run on other platforms.")
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 62ada86..661e72d 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -92,6 +92,7 @@
   public static final String EXAMPLES_ANDROID_P_DIR = TESTS_DIR + "examplesAndroidP/";
   public static final String EXAMPLES_KOTLIN_DIR = TESTS_DIR + "examplesKotlin/";
   public static final String TESTS_BUILD_DIR = BUILD_DIR + "test/";
+  public static final String JDK_TESTS_BUILD_DIR = TESTS_BUILD_DIR + "jdk11Tests/";
   public static final String EXAMPLES_BUILD_DIR = TESTS_BUILD_DIR + "examples/";
   public static final String EXAMPLES_CF_DIR = EXAMPLES_BUILD_DIR + "classes/";
   public static final String EXAMPLES_KOTLIN_BUILD_DIR = TESTS_BUILD_DIR + "examplesKotlin/";
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java b/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java
index cc0497a..2d57f24 100644
--- a/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/CoreLibDesugarTestBase.java
@@ -59,6 +59,7 @@
         // .put("java.lang.Integer8", "j$.lang.Integer8")
         // .put("java.lang.Long8", "j$.lang.Long8")
         // .put("java.lang.Math8", "j$.lang.Math8")
+        .put("java.time.", "j$.time.")
         .put("java.util.stream.", "j$.util.stream.")
         .put("java.util.function.", "j$.util.function.")
         .put("java.util.Desugar", "j$.util.Desugar")
diff --git a/src/test/java/com/android/tools/r8/desugar/corelib/corelibjdktests/Jdk11TimeTests.java b/src/test/java/com/android/tools/r8/desugar/corelib/corelibjdktests/Jdk11TimeTests.java
new file mode 100644
index 0000000..b21e826
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/corelib/corelibjdktests/Jdk11TimeTests.java
@@ -0,0 +1,165 @@
+// 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.corelib.corelibjdktests;
+
+import static com.android.tools.r8.ToolHelper.JDK_TESTS_BUILD_DIR;
+import static org.hamcrest.core.StringEndsWith.endsWith;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.D8TestCompileResult;
+import com.android.tools.r8.D8TestRunResult;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.corelib.CoreLibDesugarTestBase;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import java.nio.file.Paths;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class Jdk11TimeTests extends CoreLibDesugarTestBase {
+
+  private final TestParameters parameters;
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withDexRuntimes().build();
+  }
+
+  public Jdk11TimeTests(TestParameters parameters) {
+    this.parameters = parameters;
+  }
+
+  // Following tests are also failing on the Bazel build, they cannot be run easily on
+  // Android (difference in time precision, iAndroid printing, etc.).
+  private static String[] wontFixFailures =
+      new String[] {
+        "test.java.time.TestZoneTextPrinterParser.java",
+        // Removed by gradle (compile-time error).
+        "tck.java.time.TCKZoneId.java",
+        "tck.java.time.TCKZoneOffset.java",
+        "tck.java.time.TCKChronology.java",
+        "tck.java.time.chrono.TCKTestServiceLoader.java",
+        "tck.java.time.TCKCopticSerialization.java",
+        "tck.java.time.TCKFormatStyle.java",
+        "tck.java.time.TCKZoneRules.java",
+        "test.java.time.chrono.TestServiceLoader.java",
+        "test.java.time.TestJapaneseChronoImpl.java",
+        "test.java.time.TestThaiBuddhistChronoImpl.java",
+        "test.java.time.TestDateTimeFormatterBuilder.java",
+        "test.java.time.TestDateTimeTextProvider.java",
+        "test.java.time.TestNonIsoFormatter.java",
+        "test.java.time.TestTextParser.java",
+        "test.java.time.TestTextPrinter.java",
+        "test.java.time.TestChronoField.java",
+        "test.java.util.TestFormatter.java"
+      };
+  // TODO(b/134732760): Investigate why these tests fail.
+  private static String[] failuresToTriage =
+      new String[] {
+        "tck.java.time.TestIsoChronology",
+        "test.java.time.TestClock_System",
+        "test.java.time.chrono.TestChronologyPerf",
+        "test.java.time.chrono.TestExampleCode",
+        "test.java.time.chrono.TestChronoLocalDate",
+        "test.java.time.chrono.TestUmmAlQuraChronology",
+        "test.java.time.chrono.TestIsoChronoImpl",
+        "test.java.time.chrono.TestEraDisplayName",
+        "test.java.time.chrono.TestJapaneseChronology",
+        "test.java.time.temporal.TestIsoWeekFields",
+        "test.java.time.format.TestTextParserWithLocale",
+        "test.java.time.format.TestUnicodeExtension",
+        "test.java.time.format.TestDateTimeFormatterBuilderWithLocale",
+        "test.java.time.format.TestNarrowMonthNamesAndDayNames",
+        "test.java.time.format.TestTextPrinterWithLocale",
+        "test.java.time.format.TestDateTimeFormatter",
+        "test.java.time.format.TestReducedPrinter",
+        "test.java.time.format.TestCharLiteralParser",
+        "test.java.time.TestLocalDate"
+      };
+  private static String[] successes =
+      new String[] {
+        "test.java.time.TestYearMonth",
+        "test.java.time.TestZonedDateTime",
+        "test.java.time.TestClock_Tick",
+        "test.java.time.TestMonthDay",
+        "test.java.time.zone.TestFixedZoneRules",
+        "test.java.time.TestOffsetDateTime",
+        "test.java.time.TestInstant",
+        "test.java.time.TestDuration",
+        "test.java.time.TestZoneOffset",
+        "test.java.time.TestLocalDateTime",
+        "test.java.time.temporal.TestDateTimeBuilderCombinations",
+        "test.java.time.temporal.TestJulianFields",
+        "test.java.time.temporal.TestChronoUnit",
+        "test.java.time.temporal.TestDateTimeValueRange",
+        "test.java.time.TestClock_Fixed",
+        "test.java.time.TestYear",
+        "test.java.time.TestLocalTime",
+        "test.java.time.TestZoneId",
+        "test.java.time.TestOffsetTime",
+        "test.java.time.TestClock_Offset",
+        "test.java.time.TestPeriod",
+        "test.java.time.format.TestFractionPrinterParser",
+        "test.java.time.format.TestStringLiteralParser",
+        "test.java.time.format.TestZoneOffsetPrinter",
+        "test.java.time.format.TestDecimalStyle",
+        "test.java.time.format.TestCharLiteralPrinter",
+        "test.java.time.format.TestStringLiteralPrinter",
+        "test.java.time.format.TestPadPrinterDecorator",
+        "test.java.time.format.TestNumberPrinter",
+        "test.java.time.format.TestZoneOffsetParser",
+        "test.java.time.format.TestReducedParser",
+        "test.java.time.format.TestDateTimeParsing",
+        "test.java.time.format.TestDateTimeTextProviderWithLocale",
+        "test.java.time.format.TestSettingsParser",
+        "test.java.time.format.TestNumberParser",
+        "test.java.time.TestOffsetDateTime_instants",
+      };
+
+  @Test
+  public void testTime() throws Exception {
+    Assume.assumeTrue("TODO(b/134732760): Fix Android 7+.", requiresCoreLibDesugaring(parameters));
+    String verbosity = "0";
+    String[] mainParametersSuccesses = new String[successes.length + 1];
+    mainParametersSuccesses[0] = verbosity;
+    System.arraycopy(successes, 0, mainParametersSuccesses, 1, successes.length);
+    D8TestCompileResult compileResult =
+        testForD8()
+            .addProgramFiles(Paths.get(JDK_TESTS_BUILD_DIR + "jdk11TimeTests.jar"))
+            .addProgramFiles(Paths.get(JDK_TESTS_BUILD_DIR + "testng-6.10.jar"))
+            .addProgramFiles(Paths.get(JDK_TESTS_BUILD_DIR + "jcommander-1.48.jar"))
+            .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+            .setMinApi(parameters.getRuntime())
+            .addOptionsModification(this::configureCoreLibDesugarForProgramCompilation)
+            .compile()
+            .addRunClasspathFiles(buildDesugaredLibrary(parameters.getRuntime()));
+    for (String success : successes) {
+      D8TestRunResult result =
+          compileResult.run(parameters.getRuntime(), "TestNGMainRunner", verbosity, success);
+      if (parameters.getRuntime().asDex().getVm().getVersion() == Version.V4_0_4) {
+        result.assertSuccessWithOutputThatMatches(
+            endsWith(StringUtils.lines(success + ": SUCCESS")));
+      } else {
+        // TODO(b/134732760): flaky depending on Android versions, triage other versions.
+      }
+    }
+    for (String failure : failuresToTriage) {
+      // TODO(b/134732760): Investigate and fix these failures, fails for various reasons depending
+      // on Android versions (flaky).
+      D8TestRunResult result =
+          compileResult.run(parameters.getRuntime(), "TestNGMainRunner", verbosity, failure);
+      assertTrue(
+          endsWith(StringUtils.lines(failure + ": ERROR")).matches(result.getStdOut())
+              || endsWith(StringUtils.lines(failure + ": FAILURE")).matches(result.getStdOut())
+              || !(result.getStdErr().isEmpty()));
+    }
+  }
+}
diff --git a/src/test/testngrunner/TestNGMainRunner.java b/src/test/testngrunner/TestNGMainRunner.java
new file mode 100644
index 0000000..22d96ef
--- /dev/null
+++ b/src/test/testngrunner/TestNGMainRunner.java
@@ -0,0 +1,37 @@
+// 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.
+
+// This class is kept in a separate package because of the org.testng dependency.
+// R8 tests do not depend on testng, this class does.
+public class TestNGMainRunner {
+
+  private static void runTestNg(Class<?> testClass, int verbose) {
+    System.out.println("Running tests in " + testClass.getName());
+    org.testng.TestNG testng = new org.testng.TestNG(false);
+    testng.setTestClasses(new Class<?>[] {testClass});
+    testng.setVerbose(verbose);
+    // Deprecated API used because it works on Android unlike the recommended one.
+    testng.addListener(new org.testng.reporters.TextReporter(testClass.getName(), verbose));
+    try {
+      testng.run();
+      System.out.print("Tests result in " + testClass.getName() + ": ");
+      if (testng.hasFailure()) {
+        System.out.println("FAILURE");
+      } else {
+        System.out.println("SUCCESS");
+      }
+    } catch (RuntimeException | Error e) {
+      System.out.print("Tests result in " + testClass.getName() + ": ");
+      System.out.println("ERROR");
+      e.printStackTrace();
+    }
+  }
+
+  public static void main(String[] args) throws Exception {
+    // First arg is the verbosity level.
+    // Second arg is the class to run.
+    int verbose = Integer.parseInt(args[0]);
+    runTestNg(Class.forName(args[1]), verbose);
+  }
+}