// Copyright (c) 2018, 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.cf.bootstrap;

import static com.android.tools.r8.graph.GenericSignatureIdentityTest.testParseSignaturesInJar;
import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
import static com.google.common.io.ByteStreams.toByteArray;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;

import com.android.tools.r8.ArchiveClassFileProvider;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.ExternalR8TestCompileResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRuntime;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.retrace.ProguardMapProducer;
import com.android.tools.r8.retrace.Retrace;
import com.android.tools.r8.retrace.RetraceCommand;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.collect.Lists;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
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.Collections;
import java.util.List;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

/**
 * This test relies on a freshly built build/libs/r8lib_with_deps.jar. If this test fails remove
 * build directory and rebuild r8lib_with_deps by calling test.py or gradle r8libWithdeps.
 */
@RunWith(Parameterized.class)
public class BootstrapCurrentEqualityTest extends TestBase {

  private static final Path MAIN_KEEP = Paths.get("src/main/keep.txt");

  private static final String HELLO_NAME = "hello.Hello";
  private static final String[] KEEP_HELLO = {
    "-keep class " + HELLO_NAME + " {", "  public static void main(...);", "}",
  };

  private static Pair<Path, Path> r8R8Debug;
  private static Pair<Path, Path> r8R8Release;

  private final TestParameters parameters;
  private static boolean testExternal = false;

  @ClassRule public static TemporaryFolder testFolder = new TemporaryFolder();

  @BeforeClass
  public static void beforeAll() throws Exception {
    if (data().stream().count() > 0) {
      r8R8Debug = compileR8(CompilationMode.DEBUG);
      r8R8Release = compileR8(CompilationMode.RELEASE);
    }
  }

  @Parameters(name = "{0}")
  public static TestParametersCollection data() {
    return getTestParameters().withCfRuntimes().build();
  }

  public BootstrapCurrentEqualityTest(TestParameters parameters) {
    this.parameters = parameters;
  }

  private static Pair<Path, Path> compileR8(CompilationMode mode) throws Exception {
    // Run R8 on r8.jar.
    final Path jar = testFolder.newFolder().toPath().resolve("out.jar");
    final Path map = testFolder.newFolder().toPath().resolve("out.map");
    if (testExternal) {
      testForExternalR8(newTempFolder(), Backend.CF, TestRuntime.getCheckedInJdk9())
          .useR8WithRelocatedDeps()
          .setMode(mode)
          .addProgramFiles(ToolHelper.R8_WITH_RELOCATED_DEPS_JAR)
          .addKeepRuleFiles(MAIN_KEEP)
          .compile()
          .apply(c -> FileUtils.writeTextFile(map, c.getProguardMap()))
          .writeToZip(jar);
    } else {
      testForR8(newTempFolder(), Backend.CF)
          .setMode(mode)
          .addProgramFiles(ToolHelper.R8_WITH_RELOCATED_DEPS_JAR)
          .addKeepRuleFiles(MAIN_KEEP)
          .compile()
          .apply(c -> FileUtils.writeTextFile(map, c.getProguardMap()))
          .writeToZip(jar);
    }
    return new Pair<>(jar, map);
  }

  @Test
  public void testRetrace() throws IOException {
    ProcessResult processResult =
        ToolHelper.runProcess(
            new ProcessBuilder()
                .command(
                    parameters.getRuntime().asCf().getJavaExecutable().toString(),
                    "-DR8_THROW_EXCEPTION_FOR_TESTING_RETRACE=1",
                    "-cp",
                    r8R8Release.getFirst().toString(),
                    "com.android.tools.r8.R8",
                    "--help"));
    assertNotEquals(0, processResult.exitCode);
    assertThat(processResult.stderr, not(containsString("SelfRetraceTest")));

    List<String> expectedStackTrace =
        Lists.newArrayList(
            "Intentional exception for testing retrace.",
            "com.android.tools.r8.utils.SelfRetraceTest.foo3(SelfRetraceTest.java:13)",
            "com.android.tools.r8.utils.SelfRetraceTest.foo2(SelfRetraceTest.java:17)",
            "com.android.tools.r8.utils.SelfRetraceTest.foo1(SelfRetraceTest.java:21)",
            "com.android.tools.r8.utils.SelfRetraceTest.test(SelfRetraceTest.java:26)",
            "com.android.tools.r8.R8.run(R8.java:");

    RetraceCommand retraceCommand =
        RetraceCommand.builder()
            .setStackTrace(StringUtils.splitLines(processResult.stderr))
            .setProguardMapProducer(ProguardMapProducer.fromPath(r8R8Release.getSecond()))
            .setRetracedStackTraceConsumer(
                retraced -> {
                  int expectedIndex = -1;
                  for (String line : retraced) {
                    if (expectedIndex >= expectedStackTrace.size()) {
                      break;
                    } else if (expectedIndex == -1 && line.contains("java.lang.RuntimeException")) {
                      expectedIndex = 0;
                    }
                    if (expectedIndex > -1) {
                      assertThat(line, containsString(expectedStackTrace.get(expectedIndex++)));
                    }
                  }
                  assertEquals(expectedStackTrace.size(), expectedIndex);
                })
            .build();
    Retrace.run(retraceCommand);
  }

  @Test
  public void testR8LibCompatibility() throws IOException, CompilationFailedException {
    // Produce r81 = R8Lib(R8WithDeps) and r82 = R8LibNoDeps + Deps(R8WithDeps) and test that r81 is
    // equal to r82. This test should only run if we are testing r8lib and we expect both R8libs to
    // be built by gradle. If we are not testing with R8Lib, do not run this test.
    if (!ToolHelper.isTestingR8Lib()) {
      return;
    }
    Path runR81 =
        testForExternalR8(parameters.getBackend(), parameters.getRuntime())
            .useProvidedR8(ToolHelper.R8LIB_JAR)
            .addProgramFiles(ToolHelper.R8_WITH_RELOCATED_DEPS_JAR)
            .addKeepRuleFiles(MAIN_KEEP)
            .setMode(CompilationMode.RELEASE)
            .compile()
            .outputJar();
    Path runR82 =
        testForExternalR8(parameters.getBackend(), parameters.getRuntime())
            .useProvidedR8(ToolHelper.R8LIB_EXCLUDE_DEPS_JAR)
            .addR8ExternalDepsToClasspath()
            .addProgramFiles(ToolHelper.R8_WITH_RELOCATED_DEPS_JAR)
            .addKeepRuleFiles(MAIN_KEEP)
            .setMode(CompilationMode.RELEASE)
            .compile()
            .outputJar();
    assert filesAreEqual(runR81, runR82);
  }

  @Test
  public void testSignatures() throws Exception {
    testParseSignaturesInJar(r8R8Release.getFirst());
  }

  @Test
  public void test() throws Exception {
    Path helloJar = Paths.get(ToolHelper.EXAMPLES_BUILD_DIR, "hello" + JAR_EXTENSION);
    ProcessResult runResult = ToolHelper.runJava(helloJar, "hello.Hello");
    assertEquals(0, runResult.exitCode);
    compareR8(helloJar, runResult, KEEP_HELLO, "hello.Hello");
  }

  private void compareR8(Path program, ProcessResult runResult, String[] keep, String... args)
      throws Exception {
    ExternalR8TestCompileResult runR8Debug =
        testForExternalR8(newTempFolder(), parameters.getBackend(), parameters.getRuntime())
            .useR8WithRelocatedDeps()
            .addProgramFiles(program)
            .addKeepRules(keep)
            .setMode(CompilationMode.DEBUG)
            .compile();
    assertEquals(runResult.toString(), ToolHelper.runJava(runR8Debug.outputJar(), args).toString());
    ExternalR8TestCompileResult runR8Release =
        testForExternalR8(newTempFolder(), parameters.getBackend(), parameters.getRuntime())
            .useR8WithRelocatedDeps()
            .addProgramFiles(program)
            .addKeepRules(keep)
            .setMode(CompilationMode.RELEASE)
            .compile();
    assertEquals(
        runResult.toString(), ToolHelper.runJava(runR8Release.outputJar(), args).toString());
    RunR8AndCheck(r8R8Debug, program, runR8Debug, keep, CompilationMode.DEBUG);
    RunR8AndCheck(r8R8Debug, program, runR8Release, keep, CompilationMode.RELEASE);
    RunR8AndCheck(r8R8Release, program, runR8Debug, keep, CompilationMode.DEBUG);
    RunR8AndCheck(r8R8Release, program, runR8Release, keep, CompilationMode.RELEASE);
  }

  private void RunR8AndCheck(
      Pair<Path, Path> r8,
      Path program,
      ExternalR8TestCompileResult result,
      String[] keep,
      CompilationMode mode)
      throws Exception {
    ExternalR8TestCompileResult runR8R8 =
        testForExternalR8(newTempFolder(), parameters.getBackend(), parameters.getRuntime())
            .useProvidedR8(r8.getFirst())
            .addProgramFiles(program)
            .addKeepRules(keep)
            .setMode(mode)
            .compile();
    // Check that the process outputs (exit code, stdout, stderr) are the same.
    assertEquals(result.getStdout(), runR8R8.getStdout());
    assertEquals(result.getStderr(), runR8R8.getStderr());
    // Check that the output jars are the same.
    assertProgramsEqual(result.outputJar(), runR8R8.outputJar());
  }

  public static void assertProgramsEqual(Path expectedJar, Path actualJar) throws Exception {
    if (filesAreEqual(expectedJar, actualJar)) {
      return;
    }
    ArchiveClassFileProvider expected = new ArchiveClassFileProvider(expectedJar);
    ArchiveClassFileProvider actual = new ArchiveClassFileProvider(actualJar);
    assertEquals(getSortedDescriptorList(expected), getSortedDescriptorList(actual));
    for (String descriptor : expected.getClassDescriptors()) {
      assertArrayEquals(
          "Class " + descriptor + " differs",
          getClassAsBytes(expected, descriptor),
          getClassAsBytes(actual, descriptor));
    }
  }

  public static boolean filesAreEqual(Path file1, Path file2) throws IOException {
    long size = Files.size(file1);
    long sizeOther = Files.size(file2);
    if (size != sizeOther) {
      return false;
    }
    if (size < 4096) {
      return Arrays.equals(Files.readAllBytes(file1), Files.readAllBytes(file2));
    }
    int byteRead1 = 0;
    int byteRead2 = 0;
    try (FileInputStream fs1 = new FileInputStream(file1.toString());
        FileInputStream fs2 = new FileInputStream(file2.toString())) {
      BufferedInputStream bs1 = new BufferedInputStream(fs1);
      BufferedInputStream bs2 = new BufferedInputStream(fs2);
      while (byteRead1 == byteRead2 && byteRead1 != -1) {
        byteRead1 = bs1.read();
        byteRead2 = bs2.read();
      }
    }
    return byteRead1 == byteRead2;
  }

  private static List<String> getSortedDescriptorList(ArchiveClassFileProvider inputJar) {
    ArrayList<String> descriptorList = new ArrayList<>(inputJar.getClassDescriptors());
    Collections.sort(descriptorList);
    return descriptorList;
  }

  private static byte[] getClassAsBytes(ArchiveClassFileProvider inputJar, String descriptor)
      throws Exception {
    return toByteArray(inputJar.getProgramResource(descriptor).getByteStream());
  }

  private static TemporaryFolder newTempFolder() throws IOException {
    TemporaryFolder tempFolder = new TemporaryFolder(testFolder.newFolder());
    tempFolder.create();
    return tempFolder;
  }
}
