// 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.codeinspector.Matchers.isAbsent;
import static org.hamcrest.MatcherAssert.assertThat;
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.TestParametersCollection;
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.DexVm.Version;
import com.android.tools.r8.cf.CfVersion;
import com.android.tools.r8.jacoco.JacocoClasses;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.StringUtils;
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Path;
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 JacocoConstantDynamicGetDeclaredMethods extends TestBase {

  @Parameter(0)
  public TestParameters parameters;

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

  public static final String jacocoBootstrapMethodName = "$jacocoInit";

  public static JacocoClasses testClasses;

  private static final String MAIN_CLASS = TestRunner.class.getTypeName();
  private static final String EXPECTED_OUTPUT =
      StringUtils.lines(
          jacocoBootstrapMethodName,
          "3",
          "java.lang.invoke.MethodHandles$Lookup",
          "java.lang.String",
          "java.lang.Class");

  @BeforeClass
  public static void setUpInput() throws IOException {
    testClasses = testClasses(getStaticTemp());
  }

  private void checkJacocoReport(Path agentOutput) throws IOException {
    // TODO(sgjesse): Need to figure out why there is no instrumentation output for newer VMs.
    if (parameters.isCfRuntime()
        || parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
      assertEquals(2, testClasses.generateReport(agentOutput).size());
    } else {
      assertFalse(Files.exists(agentOutput));
    }
  }

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

    // 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);
    checkJacocoReport(agentOutputOnTheFly);

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

  @Test
  public void testD8() throws Exception {
    assumeTrue(parameters.getRuntime().isDex());
    Path agentOutput = temp.newFolder().toPath().resolve("jacoco.exec");
    testForD8(parameters.getBackend())
        .addProgramFiles(testClasses.getInstrumented())
        .addProgramFiles(ToolHelper.JACOCO_AGENT)
        .setMinApi(parameters.getApiLevel())
        .compile()
        .runWithJaCoCo(agentOutput, parameters.getRuntime(), MAIN_CLASS)
        // TODO(b/210485236): This should never fail.
        .applyIf(
            parameters.getDexRuntimeVersion().isOlderThan(Version.V8_1_0),
            b -> b.assertFailureWithErrorThatThrows(ClassNotFoundException.class),
            b -> b.assertSuccessWithOutput(EXPECTED_OUTPUT));
    checkJacocoReport(agentOutput);
  }

  @Test
  public void testR8() throws Exception {
    assumeTrue(parameters.getRuntime().isDex());
    Path agentOutput = temp.newFolder().toPath().resolve("jacoco.exec");
    testForR8(parameters.getBackend())
        .addProgramFiles(testClasses.getInstrumented())
        .addProgramFiles(ToolHelper.JACOCO_AGENT)
        .setMinApi(parameters.getApiLevel())
        .addKeepMainRules(TestRunner.class)
        .applyIf(
            parameters.getApiLevel().isLessThan(AndroidApiLevel.O),
            b -> b.addDontWarn(MethodHandles.Lookup.class))
        .addDontWarn("java.lang.management.ManagementFactory", "javax.management.**")
        .compile()
        .runWithJaCoCo(agentOutput, parameters.getRuntime(), MAIN_CLASS)
        .inspect(
            inspector -> {
              assertThat(
                  inspector.clazz(TestRunner.class).uniqueMethodWithName(jacocoBootstrapMethodName),
                  isAbsent());
            })
        .assertSuccessWithOutputLines("No " + jacocoBootstrapMethodName + " method");
    checkJacocoReport(agentOutput);
  }

  @Test
  public void testR8KeepingJacocoInit() throws Exception {
    assumeTrue(parameters.getRuntime().isDex());
    Path agentOutput = temp.newFolder().toPath().resolve("jacoco.exec");
    testForR8(parameters.getBackend())
        .addProgramFiles(testClasses.getInstrumented())
        .addProgramFiles(ToolHelper.JACOCO_AGENT)
        .setMinApi(parameters.getApiLevel())
        .addKeepMainRules(TestRunner.class)
        .addKeepRules("-keep class ** { *** " + jacocoBootstrapMethodName + "(...); }")
        .applyIf(
            parameters.getApiLevel().isLessThan(AndroidApiLevel.O),
            b -> b.addDontWarn(MethodHandles.Lookup.class))
        .addDontWarn(
            "java.lang.instrument.ClassFileTransformer",
            "java.lang.management.ManagementFactory",
            "javax.management.**")
        .compile()
        .runWithJaCoCo(agentOutput, parameters.getRuntime(), MAIN_CLASS)
        // TODO(b/210485236): This should never fail.
        .applyIf(
            parameters.getDexRuntimeVersion().isOlderThan(Version.V8_1_0),
            b -> b.assertFailureWithErrorThatThrows(ClassNotFoundException.class),
            b -> b.assertSuccessWithOutput(EXPECTED_OUTPUT));
    checkJacocoReport(agentOutput);
  }

  private static JacocoClasses testClasses(TemporaryFolder temp) throws IOException {
    return new JacocoClasses(
        transformer(TestRunner.class).setVersion(CfVersion.V11).transform(), temp);
  }

  static class TestRunner {

    public static void main(String[] args) {
      Method[] methods = TestRunner.class.getDeclaredMethods();
      for (Method method : methods) {
        if (method.getName().equals(jacocoBootstrapMethodName)) {
          System.out.println(method.getName());
          System.out.println(method.getParameterTypes().length);
          for (int j = 0; j < method.getParameterTypes().length; j++) {
            System.out.println(method.getParameterTypes()[j].getName());
          }
          return;
        }
      }
      System.out.println("No " + jacocoBootstrapMethodName + " method");
    }
  }
}
