// Copyright (c) 2021, 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.constantdynamic;

import static com.android.tools.r8.utils.DescriptorUtils.JAVA_PACKAGE_SEPARATOR;
import static com.android.tools.r8.utils.FileUtils.CLASS_EXTENSION;
import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assume.assumeTrue;

import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.cf.CfVersion;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.ZipUtils;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)
public class JacocoConstantDynamicTest extends TestBase {

  @Parameter() public TestParameters parameters;

  @Parameter(1)
  public boolean useConstantDynamic;

  @Parameters(name = "{0}, useConstantDynamic: {1}")
  public static List<Object[]> data() {
    return buildParameters(
        getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(),
        BooleanUtils.values());
  }

  public static JacocoClasses testClassesNoConstantDynamic;
  public static JacocoClasses testClassesConstantDynamic;

  public JacocoClasses testClasses;

  private static final String MAIN_CLASS = TestRunner.class.getTypeName();
  private static final String EXPECTED_OUTPUT = StringUtils.lines("Hello, world!");

  @BeforeClass
  public static void setUpInput() throws IOException {
    testClassesNoConstantDynamic = testClasses(getStaticTemp(), CfVersion.V1_8);
    testClassesConstantDynamic = testClasses(getStaticTemp(), CfVersion.V11);
  }

  @Before
  public void setUp() throws IOException {
    testClasses = useConstantDynamic ? testClassesConstantDynamic : testClassesNoConstantDynamic;
  }

  @Test
  public void testJvm() throws Exception {
    assumeTrue(
        parameters.isCfRuntime()
            && (parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11)
                || !useConstantDynamic));

    // Run non-instrumented code.
    testForRuntime(parameters)
        .addProgramFiles(testClasses.getOriginal())
        .run(parameters.getRuntime(), MAIN_CLASS)
        .assertSuccessWithOutput(EXPECTED_OUTPUT);

    // Run non-instrumented code with an agent causing on the fly instrumentation on the JVM.
    Path output = temp.newFolder().toPath();
    Path agentOutputOnTheFly = output.resolve("on-the-fly");
    testForJvm()
        .addProgramFiles(testClasses.getOriginal())
        .enableJaCoCoAgent(ToolHelper.JACOCO_AGENT, agentOutputOnTheFly)
        .run(parameters.getRuntime(), MAIN_CLASS)
        .assertSuccessWithOutput(EXPECTED_OUTPUT);
    List<String> onTheFlyReport = testClasses.generateReport(agentOutputOnTheFly);
    assertEquals(2, onTheFlyReport.size());

    // Run the instrumented code.
    Path agentOutputOffline = output.resolve("offline");
    testForJvm()
        .addProgramFiles(testClasses.getInstrumented())
        .configureJaCoCoAgentForOfflineInstrumentedCode(ToolHelper.JACOCO_AGENT, agentOutputOffline)
        .run(parameters.getRuntime(), MAIN_CLASS)
        .assertSuccessWithOutput(EXPECTED_OUTPUT);
    List<String> offlineReport = testClasses.generateReport(agentOutputOffline);
    assertEquals(onTheFlyReport, offlineReport);
  }

  @Test
  public void testD8() throws Exception {
    assumeTrue(parameters.getRuntime().isDex());
    if (!useConstantDynamic) {
      Path output = temp.newFolder().toPath();
      Path agentOutput = output.resolve("jacoco.exec");
      testForD8(parameters.getBackend())
          .addProgramFiles(testClasses.getInstrumented())
          .addProgramFiles(ToolHelper.JACOCO_AGENT)
          .setMinApi(parameters.getApiLevel())
          .compile()
          .runWithJaCoCo(agentOutput, parameters.getRuntime(), MAIN_CLASS)
          .assertSuccessWithOutput(EXPECTED_OUTPUT);
      // TODO(sgjesse): Need to figure out why there is no instrumentation output for newer VMs.
      if (parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
        List<String> report = testClasses.generateReport(agentOutput);
        assertEquals(2, report.size());
      } else {
        assertFalse(Files.exists(agentOutput));
      }
    } else {
      testForD8(parameters.getBackend())
          .addProgramFiles(testClasses.getInstrumented())
          .addProgramFiles(ToolHelper.JACOCO_AGENT)
          .setMinApi(parameters.getApiLevel())
          .compile();
    }
  }

  private static JacocoClasses testClasses(TemporaryFolder temp, CfVersion version)
      throws IOException {
    return new JacocoClasses(
        transformer(TestRunner.class)
            .setVersion(version) /*.setClassDescriptor("LTestRunner;")*/
            .transform(),
        temp);
  }

  // Two sets of class files with and without JaCoCo off line instrumentation.
  private static class JacocoClasses {
    private final Path dir;

    private final Path originalJar;
    private final Path instrumentedJar;

    // Create JacocoClasses with just one class provided as bytes.
    private JacocoClasses(byte[] clazz, TemporaryFolder temp) throws IOException {
      dir = temp.newFolder().toPath();

      // Write the class to a .class file with package sub-directories.
      String typeName = extractClassName(clazz);
      int lastDotIndex = typeName.lastIndexOf('.');
      String pkg = typeName.substring(0, lastDotIndex);
      String baseFileName = typeName.substring(lastDotIndex + 1) + CLASS_EXTENSION;
      Path original = dir.resolve("original");
      Files.createDirectories(original);
      Path packageDir = original.resolve(pkg.replace(JAVA_PACKAGE_SEPARATOR, File.separatorChar));
      Files.createDirectories(packageDir);
      Path classFile = packageDir.resolve(baseFileName);
      Files.write(classFile, clazz);

      // Run offline instrumentation.
      Path instrumented = dir.resolve("instrumented");
      Files.createDirectories(instrumented);
      runJacocoInstrumentation(original, instrumented);
      originalJar = dir.resolve("original" + JAR_EXTENSION);
      ZipUtils.zip(originalJar, original);
      instrumentedJar = dir.resolve("instrumented" + JAR_EXTENSION);
      ZipUtils.zip(instrumentedJar, instrumented);
    }

    public Path getOriginal() {
      return originalJar;
    }

    public Path getInstrumented() {
      return instrumentedJar;
    }

    public List<String> generateReport(Path jacocoExec) throws IOException {
      Path report = dir.resolve("report.scv");
      ProcessResult result = ToolHelper.runJaCoCoReport(originalJar, jacocoExec, report);
      assertEquals(result.toString(), 0, result.exitCode);
      return Files.readAllLines(report);
    }

    private void runJacocoInstrumentation(Path input, Path outdir) throws IOException {
      ProcessResult result = ToolHelper.runJaCoCoInstrument(input, outdir);
      assertEquals(result.toString(), 0, result.exitCode);
    }
  }

  static class TestRunner {

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