// Copyright (c) 2017, 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 com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
import static com.android.tools.r8.utils.FileUtils.ZIP_EXTENSION;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeFalse;

import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.TestDescriptionWatcher;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.UnaryOperator;
import java.util.stream.Collectors;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TemporaryFolder;

public abstract class RunExamplesJava9Test
    <B extends BaseCommand.Builder<? extends BaseCommand, B>> {

  private static final String EXAMPLE_DIR = ToolHelper.EXAMPLES_JAVA9_BUILD_DIR;

  abstract class TestRunner<C extends TestRunner<C>> {
    final String testName;
    final String packageName;
    final String mainClass;
    final List<String> args = new ArrayList<>();

    Integer androidJarVersion = null;

    final List<Consumer<InternalOptions>> optionConsumers = new ArrayList<>();
    final List<Consumer<CodeInspector>> dexInspectorChecks = new ArrayList<>();
    final List<UnaryOperator<B>> builderTransformations = new ArrayList<>();

    TestRunner(String testName, String packageName, String mainClass) {
      this.testName = testName;
      this.packageName = packageName;
      this.mainClass = mainClass;
    }

    abstract C self();

    C withDexCheck(Consumer<CodeInspector> check) {
      dexInspectorChecks.add(check);
      return self();
    }

    C withArg(String arg) {
      args.add(arg);
      return self();
    }

    void combinedOptionConsumer(InternalOptions options) {
      for (Consumer<InternalOptions> consumer : optionConsumers) {
        consumer.accept(options);
      }
    }

    C withBuilderTransformation(UnaryOperator<B> builderTransformation) {
      builderTransformations.add(builderTransformation);
      return self();
    }

    Path build() throws Throwable {
      Path inputFile = getInputJar();
      Path out = temp.getRoot().toPath().resolve(testName + ZIP_EXTENSION);

      build(inputFile, out);
      return out;
    }

    Path getInputJar() {
      return Paths.get(EXAMPLE_DIR, packageName + JAR_EXTENSION);
    }

    void run() throws Throwable {
      if (minSdkErrorExpected(testName)) {
        thrown.expect(CompilationFailedException.class);
      }

      String qualifiedMainClass = packageName + "." + mainClass;
      Path inputFile = getInputJar();
      Path out = temp.getRoot().toPath().resolve(testName + ZIP_EXTENSION);

      build(inputFile, out);

      if (!ToolHelper.artSupported() && !ToolHelper.dealsWithGoldenFiles()) {
        return;
      }

      if (!dexInspectorChecks.isEmpty()) {
        CodeInspector inspector = new CodeInspector(out);
        for (Consumer<CodeInspector> check : dexInspectorChecks) {
          check.accept(inspector);
        }
      }

      execute(testName, qualifiedMainClass, new Path[]{inputFile}, new Path[]{out}, args);
    }

    abstract C withMinApiLevel(int minApiLevel);

    C withKeepAll() {
      return self();
    }

    C withAndroidJar(int androidJarVersion) {
      assert this.androidJarVersion == null;
      this.androidJarVersion = androidJarVersion;
      return self();
    }

    abstract void build(Path inputFile, Path out) throws Throwable;
  }

  private static List<String> minSdkErrorExpected =
      ImmutableList.of("varhandle-error-due-to-min-sdk");

  private static Map<DexVm.Version, List<String>> failsOn;

  static {
    ImmutableMap.Builder<DexVm.Version, List<String>> builder = ImmutableMap.builder();
    builder
        .put(DexVm.Version.V4_0_4, ImmutableList.of(
            "native-private-interface-methods", // Dex version not supported
            "varhandle"
        ))
        .put(DexVm.Version.V4_4_4, ImmutableList.of(
            "native-private-interface-methods", // Dex version not supported
            "varhandle"
        ))
        .put(DexVm.Version.V5_1_1, ImmutableList.of(
            "native-private-interface-methods", // Dex version not supported
            "varhandle"
        ))
        .put(DexVm.Version.V6_0_1, ImmutableList.of(
            "native-private-interface-methods", // Dex version not supported
            "varhandle"
        ))
        .put(DexVm.Version.V7_0_0, ImmutableList.of(
            // Dex version not supported
            "varhandle"
        ))
        .put(DexVm.Version.V8_1_0, ImmutableList.of(
            // Dex version not supported
            "varhandle"
        ))
        .put(DexVm.Version.DEFAULT, ImmutableList.of(
            // TODO(b/72536415): Update runtime when the support will be ready
            "varhandle"
        ));
    failsOn = builder.build();
  }

  // Defines methods failing on JVM, specifies the output to be used for comparison.
  private static Map<String, String> expectedJvmResult =
      ImmutableMap.of(
          "twr-close-resource",
          "A\nE\nG\nH\nI\nJ\nK\n"
              + "iA\niE\niG\niH\niI\niJ\niK\n"
              + "1\n2\n3\n4\n5\n6\n7\n8\n99\n"
              + "i1\ni2\ni3\ni4\ni5\ni6\ni7\ni8\ni99\n",
          "native-private-interface-methods",
          "0: s>i>a\n"
              + "1: d>i>s>i>a\n"
              + "2: l>i>s>i>a\n"
              + "3: x>s\n"
              + "4: c>d>i>s>i>a\n",
          "desugared-private-interface-methods",
          "0: s>i>a\n"
              + "1: d>i>s>i>a\n"
              + "2: l>i>s>i>a\n"
              + "3: x>s\n"
              + "4: c>d>i>s>i>a\n",
          "varhandle",
          "true\nfalse\n"
      );

  @Rule
  public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();

  @Rule
  public ExpectedException thrown = ExpectedException.none();

  @Rule
  public TestDescriptionWatcher watcher = new TestDescriptionWatcher();

  private boolean failsOn(Map<DexVm.Version, List<String>> failsOn, String name) {
    DexVm.Version vmVersion = ToolHelper.getDexVm().getVersion();
    return failsOn.containsKey(vmVersion)
        && failsOn.get(vmVersion).contains(name);
  }

  private boolean expectedToFail(String name) {
    return failsOn(failsOn, name);
  }

  private boolean minSdkErrorExpected(String testName) {
    return minSdkErrorExpected.contains(testName);
  }

  @Test
  public void nativePrivateInterfaceMethods() throws Throwable {
    test("native-private-interface-methods",
        "privateinterfacemethods", "PrivateInterfaceMethods")
        .withMinApiLevel(AndroidApiLevel.N.getLevel())
        .withKeepAll()
        .run();
  }

  @Test
  public void desugaredPrivateInterfaceMethods() throws Throwable {
    assumeFalse("CF backend does not desugar", this instanceof R8CFRunExamplesJava9Test);
    final String iName = "privateinterfacemethods.I";
    test("desugared-private-interface-methods",
        "privateinterfacemethods", "PrivateInterfaceMethods")
        .withMinApiLevel(AndroidApiLevel.M.getLevel())
        .withKeepAll()
        .withDexCheck(dexInspector -> {
          ClassSubject companion = dexInspector.clazz(
              iName + InterfaceMethodRewriter.COMPANION_CLASS_NAME_SUFFIX);
          assertThat(companion, isPresent());
          MethodSubject iFoo = companion.method(
              "java.lang.String",
              InterfaceMethodRewriter.PRIVATE_METHOD_PREFIX + "iFoo",
              ImmutableList.of(iName, "boolean"));
          assertThat(iFoo, isPresent());
          assertTrue(iFoo.getMethod().isPublicMethod());
        })
        .run();
  }

  @Test
  public void varHandle() throws Throwable {
    test("varhandle", "varhandle", "VarHandleTests")
        .withMinApiLevel(AndroidApiLevel.P.getLevel())
        .withKeepAll()
        .run();
  }

  @Test
  public void varHandleErrorDueToMinSdk() throws Throwable {
    test("varhandle-error-due-to-min-sdk", "varhandle", "VarHandleTests")
        .withMinApiLevel(AndroidApiLevel.O.getLevel())
        .withKeepAll()
        .run();
  }

  @Test
  public void testTwrCloseResourceMethod() throws Throwable {
    TestRunner<?> test = test("twr-close-resource", "twrcloseresource", "TwrCloseResourceTest");
    test
        .withMinApiLevel(AndroidApiLevel.I.getLevel())
        .withKeepAll()
        .withAndroidJar(AndroidApiLevel.K.getLevel())
        .withArg(test.getInputJar().toAbsolutePath().toString())
        .run();
  }

  abstract RunExamplesJava9Test<B>.TestRunner<?> test(String testName, String packageName,
      String mainClass);

  void execute(String testName,
      String qualifiedMainClass, Path[] jars, Path[] dexes, List<String> args) throws IOException {

    boolean expectedToFail = expectedToFail(testName);
    if (expectedToFail) {
      thrown.expect(Throwable.class);
    }
    String output = ToolHelper.runArtNoVerificationErrors(
        Arrays.stream(dexes).map(Path::toString).collect(Collectors.toList()),
        qualifiedMainClass,
        builder -> {
          for (String arg : args) {
            builder.appendProgramArgument(arg);
          }
        });
    String jvmResult = null;
    if (expectedJvmResult.containsKey(testName)) {
      jvmResult = expectedJvmResult.get(testName);
    } else if (!expectedToFail) {
      ToolHelper.ProcessResult javaResult =
          ToolHelper.runJava(ImmutableList.copyOf(jars), qualifiedMainClass);
      assertEquals("JVM run failed", javaResult.exitCode, 0);
      jvmResult = javaResult.stdout;
    }

    if (jvmResult != null) {
      assertTrue(
          "JVM output does not match art output.\n\tjvm: "
              + jvmResult
              + "\n\tart: "
              + output.replace("\r", ""),
          output.equals(jvmResult.replace("\r", "")));
    }
  }

}
