// 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.utils.FileUtils.JAR_EXTENSION;
import static com.google.common.io.ByteStreams.toByteArray;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;

import com.android.tools.r8.ArchiveClassFileProvider;
import com.android.tools.r8.ClassFileConsumer;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.FileUtils;
import com.google.common.base.Charsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
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 BootstrapTest extends TestBase {

  private static final Path R8_STABLE_JAR = Paths.get("third_party/r8/r8.jar");

  private static final String R8_NAME = "com.android.tools.r8.R8";
  private static final String[] KEEP_R8 = {
    "-keep public class " + R8_NAME + " {", "  public static void main(...);", "}",
  };
  private static final Path DONTWARN_R8 = Paths.get("src/main/dontwarn.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 class R8Result {

    final ProcessResult processResult;
    final Path outputJar;
    final String pgMap;

    R8Result(ProcessResult processResult, Path outputJar, String pgMap) {
      this.processResult = processResult;
      this.outputJar = outputJar;
      this.pgMap = pgMap;
    }

    @Override
    public String toString() {
      return processResult.toString() + "\n\n" + pgMap;
    }
  }

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

  public BootstrapTest(TestParameters parameters) {
    // TODO: use parameters to fork the right Java.
    parameters.assertNoneRuntime();
  }

  @Test
  public void test() throws Exception {
    // Run hello.jar to ensure it exists and is valid.
    Path hello = Paths.get(ToolHelper.EXAMPLES_BUILD_DIR, "hello" + JAR_EXTENSION);
    ProcessResult runHello = ToolHelper.runJava(hello, "hello.Hello");
    assertEquals(0, runHello.exitCode);

    // Run r8.jar on hello.jar to ensure that r8.jar is a working compiler.
    R8Result runInputR8 = runExternalR8(R8_STABLE_JAR, hello, "input", KEEP_HELLO, "--debug");
    ProcessResult runHelloR8 = ToolHelper.runJava(runInputR8.outputJar, "hello.Hello");
    assertEquals(runHello.toString(), runHelloR8.toString());

    compareR8(hello, runInputR8, CompilationMode.RELEASE, "r8-r8-rel", "--release", "output-rel");
    compareR8(hello, runInputR8, CompilationMode.DEBUG, "r8-r8", "--debug", "output");
  }

  private void compareR8(
      Path hello,
      R8Result runInputR8,
      CompilationMode internalMode,
      String internalOutput,
      String externalMode,
      String externalOutput)
      throws Exception {
    // Run R8 on r8.jar.
    Path output = runR8(internalOutput, internalMode);
    // Run the resulting compiler on hello.jar.
    R8Result runR8R8 = runExternalR8(output, hello, externalOutput, KEEP_HELLO, externalMode);
    // Check that the process outputs (exit code, stdout, stderr) are the same.
    assertEquals(runInputR8.toString(), runR8R8.toString());
    // Check that the output jars are the same.
    assertProgramsEqual(runInputR8.outputJar, runR8R8.outputJar);
  }

  private Path runR8(String outputFolder, CompilationMode mode) throws Exception {
    Path outputPath = temp.newFolder(outputFolder).toPath();
    Path outputJar = outputPath.resolve("output.jar");
    Path pgConfigFile = outputPath.resolve("keep.rules");
    FileUtils.writeTextFile(pgConfigFile, BootstrapTest.KEEP_R8);
    ToolHelper.runR8(
        R8Command.builder()
            .setMode(mode)
            .addLibraryFiles(ToolHelper.getJava8RuntimeJar())
            .setProgramConsumer(new ClassFileConsumer.ArchiveConsumer(outputJar, true))
            .addProgramFiles(R8_STABLE_JAR)
            .addProguardConfigurationFiles(pgConfigFile, DONTWARN_R8)
            .build());
    return outputJar;
  }

  private R8Result runExternalR8(
      Path r8Jar, Path inputJar, String outputFolder, String[] keepRules, String mode)
      throws Exception {
    Path outputPath = temp.newFolder(outputFolder).toPath();
    Path pgConfigFile = outputPath.resolve("keep.rules");
    Path outputJar = outputPath.resolve("output.jar");
    Path pgMapFile = outputPath.resolve("map.txt");
    FileUtils.writeTextFile(pgConfigFile, keepRules);
    ProcessResult processResult =
        ToolHelper.runJava(
            r8Jar,
            R8_NAME,
            "--lib",
            ToolHelper.JAVA_8_RUNTIME,
            "--classfile",
            inputJar.toString(),
            "--output",
            outputJar.toString(),
            "--pg-conf",
            pgConfigFile.toString(),
            mode,
            "--pg-map-output",
            pgMapFile.toString());
    if (processResult.exitCode != 0) {
      System.out.println(processResult);
    }
    assertEquals(processResult.stderr, 0, processResult.exitCode);
    String pgMap = FileUtils.readTextFile(pgMapFile, Charsets.UTF_8);
    return new R8Result(processResult, outputJar, pgMap);
  }

  private static void assertProgramsEqual(Path expectedJar, Path actualJar) throws Exception {
    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));
    }
  }

  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());
  }
}
