// 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.kotlin;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import com.android.tools.r8.OutputMode;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.DexInspector;
import com.android.tools.r8.utils.DexInspector.ClassSubject;
import com.android.tools.r8.utils.DexInspector.MethodSubject;
import com.android.tools.r8.utils.FileUtils;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.junit.Assume;

// TODO(shertz) also run with backend 1.8
public abstract class AbstractR8KotlinTestBase extends TestBase {

  public static final String KOTLIN_R8_TEST_RESOURCES_BUILD_DIR =
      ToolHelper.TESTS_BUILD_DIR + "/kotlinR8TestResources";

  protected final boolean allowAccessModification;

  protected AbstractR8KotlinTestBase(boolean allowAccessModification) {
    this.allowAccessModification = allowAccessModification;
  }

  protected static void checkMethodIsInvokedAtLeastOnce(DexCode dexCode,
      MethodSignature... methodSignatures) {
    for (MethodSignature methodSignature : methodSignatures) {
      checkMethodIsInvokedAtLeastOnce(dexCode, methodSignature);
    }
  }

  private static void checkMethodIsInvokedAtLeastOnce(DexCode dexCode,
      MethodSignature methodSignature) {
    assertTrue("No invoke to '" + methodSignature.toString() + "'",
        Arrays.stream(dexCode.instructions)
            .filter((instr) -> instr.getMethod() != null)
            .anyMatch((instr) -> instr.getMethod().name.toString().equals(methodSignature.name)));
  }

  protected static void checkMethodIsNeverInvoked(DexCode dexCode,
      MethodSignature... methodSignatures) {
    for (MethodSignature methodSignature : methodSignatures) {
      checkMethodIsNeverInvoked(dexCode, methodSignature);
    }
  }

  private static void checkMethodIsNeverInvoked(DexCode dexCode,
      MethodSignature methodSignature) {
    assertTrue("At least one invoke to '" + methodSignature.toString() + "'",
        Arrays.stream(dexCode.instructions)
            .filter((instr) -> instr.getMethod() != null)
            .noneMatch((instr) -> instr.getMethod().name.toString().equals(methodSignature.name)));
  }

  protected static void checkMethodsPresence(ClassSubject classSubject,
      Map<MethodSignature, Boolean> presenceMap) {
    presenceMap.forEach(((methodSignature, isPresent) -> {
      MethodSubject methodSubject = classSubject.method(methodSignature);
      String methodDesc = methodSignature.toString();
      String failureMessage = isPresent
          ? "Method '" + methodDesc + "' should be present"
          : "Method '" + methodDesc + "' should not be present";

      assertEquals(failureMessage, isPresent, methodSubject.isPresent());
    }));
  }

  protected static ClassSubject checkClassExists(DexInspector inspector, String className) {
    ClassSubject classSubject = inspector.clazz(className);
    assertNotNull(classSubject);
    assertTrue("No class " + className, classSubject.isPresent());
    return classSubject;
  }

  private static MethodSubject checkMethod(ClassSubject classSubject, String methodName,
      String methodReturnType, List<String> methodParameterTypes, boolean isPresent) {
    return checkMethod(classSubject,
        new MethodSignature(methodName, methodReturnType, methodParameterTypes), isPresent);
  }

  protected static MethodSubject checkMethodIsPresent(ClassSubject classSubject,
      MethodSignature methodSignature) {
    return checkMethod(classSubject, methodSignature, true);
  }

  protected static MethodSubject checkMethod(ClassSubject classSubject,
      MethodSignature methodSignature, boolean isPresent) {
    MethodSubject methodSubject = classSubject.method(methodSignature);
    assertNotNull(methodSubject);

    if (isPresent) {
      assertTrue("No method " + methodSignature.name, methodSubject.isPresent());
    } else {
      assertFalse("Method " + methodSignature.name + " exists", methodSubject.isPresent());
    }
    return methodSubject;
  }

  protected static DexCode getDexCode(MethodSubject methodSubject) {
    Code code = methodSubject.getMethod().getCode();
    assertNotNull("No code for method " + methodSubject.getMethod().descriptor(), code);
    assertTrue(code.isDexCode());
    return code.asDexCode();
  }

  private static DexCode extractCodeFor(DexInspector dexInspector, String className,
      String methodName,
      String methodReturnType, List<String> methodParameterTypes) {
    ClassSubject classSubject = checkClassExists(dexInspector, className);
    MethodSubject methodSubject = checkMethodIsPresent(classSubject, methodName, methodReturnType,
        methodParameterTypes);
    return getDexCode(methodSubject);
  }

  protected static MethodSubject checkMethodIsPresent(ClassSubject classSubject, String methodName,
      String methodReturnType,
      List<String> methodParameterTypes) {
    return checkMethod(classSubject, methodName, methodReturnType, methodParameterTypes, true);
  }

  private String buildProguardRules(String mainClass) {
    ProguardRulesBuilder proguardRules = new ProguardRulesBuilder();
    proguardRules.appendWithLineSeparator(keepMainProguardConfiguration(mainClass));
    proguardRules.dontObfuscate();
    if (allowAccessModification) {
      proguardRules.allowAccessModification();
    }
    return proguardRules.toString();
  }

  protected String keepClassMethod(String className, MethodSignature methodSignature) {
    return "-keep class " + className + " {" + System.lineSeparator() +
        methodSignature.toString() + ";" + System.lineSeparator() + "}";
  }

  protected void runTest(String folder, String mainClass, AndroidAppInspector inspector)
      throws Exception {
    runTest(folder, mainClass, null, inspector);
  }

  protected void runTest(String folder, String mainClass, String extraProguardRules,
      AndroidAppInspector inspector) throws Exception {
    Assume.assumeTrue(ToolHelper.artSupported());

    Path jarFile =
        Paths.get(KOTLIN_R8_TEST_RESOURCES_BUILD_DIR, folder + FileUtils.JAR_EXTENSION);

    String proguardRules = buildProguardRules(mainClass);
    if (extraProguardRules != null) {
      proguardRules += extraProguardRules;
    }

    // Build with R8
    AndroidApp.Builder builder = AndroidApp.builder();
    builder.addProgramFiles(jarFile);
    AndroidApp app = compileWithR8(builder.build(), proguardRules.toString());

    // Materialize file for execution.
    Path generatedDexFile = temp.getRoot().toPath().resolve("classes.jar");
    app.writeToZip(generatedDexFile, OutputMode.DexIndexed);

    // Run with ART.
    String artOutput =
        ToolHelper.runArtNoVerificationErrors(generatedDexFile.toString(), mainClass);

    // Compare with Java.
    ToolHelper.ProcessResult javaResult = ToolHelper.runJava(jarFile, mainClass);
    if (javaResult.exitCode != 0) {
      System.out.println(javaResult.stdout);
      System.err.println(javaResult.stderr);
      fail("JVM failed for: " + mainClass);
    }
    assertEquals("JVM and ART output differ", javaResult.stdout, artOutput);

    inspector.inspectApp(app);
  }

  @FunctionalInterface
  interface AndroidAppInspector {

    void inspectApp(AndroidApp androidApp) throws Exception;
  }
}
