// 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 org.junit.Assert.assertEquals;

import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.R8;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.StringUtils;
import com.google.common.base.Charsets;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
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-releases", "3.2.54", "r8.jar");

  private static final String HELLO_EXPECTED = StringUtils.lines("Hello World!");

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

  private static CfRuntime getHostRuntime() {
    return CfRuntime.getSystemRuntime();
  }

  public BootstrapTest(TestParameters parameters) {
    parameters.assertNoneRuntime();
  }

  private Path getHelloInputs() {
    return ToolHelper.getClassFileForTestClass(Hello.class);
  }

  private String getHelloKeepRules() {
    return TestBase.keepMainProguardConfiguration(Hello.class);
  }

  @Test
  public void reference() throws Exception {
    testForJvm()
        .addProgramFiles(getHelloInputs())
        .run(getHostRuntime(), Hello.class)
        .assertSuccessWithOutput(HELLO_EXPECTED);
  }

  @Test
  public void testDebug() throws Exception {
    compareForMode(CompilationMode.DEBUG);
  }

  @Test
  public void testRelease() throws Exception {
    compareForMode(CompilationMode.RELEASE);
  }

  private R8Result compareForMode(CompilationMode mode) throws Exception {
    // Run r8.jar on hello.jar to ensure that r8.jar is a working compiler.
    R8Result helloCompiledWithR8 =
        runExternalR8(R8_STABLE_JAR, getHelloInputs(), getHelloKeepRules(), mode);
    testForJvm()
        .addProgramFiles(helloCompiledWithR8.outputJar)
        .run(getHostRuntime(), Hello.class)
        .assertSuccessWithOutput(HELLO_EXPECTED);

    compareR8(helloCompiledWithR8, mode);
    return helloCompiledWithR8;
  }

  private void compareR8(R8Result referenceCompilation, CompilationMode mode) throws Exception {
    // Run R8 on r8.jar.
    Path r8CompiledByR8 = compileR8WithR8(mode);
    // Run the resulting compiler on hello.jar.
    R8Result runR8R8 = runExternalR8(r8CompiledByR8, getHelloInputs(), getHelloKeepRules(), mode);
    // Check that the process outputs (exit code, stdout, stderr) are the same.
    assertEquals(referenceCompilation.toString(), runR8R8.toString());
    // Check that the output jars are the same.
    assertProgramsEqual(referenceCompilation.outputJar, runR8R8.outputJar);
  }

  private Path compileR8WithR8(CompilationMode mode) throws Exception {
    return testForR8(Backend.CF)
        .setMode(mode)
        .addProgramFiles(R8_STABLE_JAR)
        .addKeepRules(TestBase.keepMainProguardConfiguration(R8.class))
        // The r8 stable/release hits open interface issues.
        .addOptionsModification(o -> o.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces())
        // The r8 stable/release contains missing com.google.errorprone annotation references.
        .addDontWarnGoogle()
        .compile()
        .writeToZip();
  }

  private R8Result runExternalR8(Path r8Jar, Path inputJar, String keepRules, CompilationMode mode)
      throws Exception {
    Path outputPath = temp.newFolder().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(
            getHostRuntime(),
            Collections.singletonList(r8Jar),
            R8.class.getTypeName(),
            "--lib",
            ToolHelper.getJava8RuntimeJar().toString(),
            "--classfile",
            inputJar.toString(),
            "--output",
            outputJar.toString(),
            "--pg-conf",
            pgConfigFile.toString(),
            mode == CompilationMode.DEBUG ? "--debug" : "--release",
            "--pg-map-output",
            pgMapFile.toString());
    if (processResult.exitCode != 0) {
      System.out.println(processResult);
    }
    assertEquals(processResult.toString(), 0, processResult.exitCode);
    String pgMap = FileUtils.readTextFile(pgMapFile, Charsets.UTF_8);
    return new R8Result(processResult, outputJar, pgMap);
  }

  public static class Hello {

    public static void main(String[] args) {
      System.out.println("Hello World!");
    }
  }
}
