// 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.shaking.forceproguardcompatibility;

import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;

import com.android.tools.r8.ClassFileConsumer;
import com.android.tools.r8.CompatProguardCommandBuilder;
import com.android.tools.r8.DataResource;
import com.android.tools.r8.DexIndexedConsumer;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
import java.io.File;
import java.nio.file.Path;
import java.util.List;
import java.util.function.Consumer;

public class ProguardCompatibilityTestBase extends TestBase {

  protected Path proguardMap;

  public enum Shrinker {
    PROGUARD5,
    PROGUARD6,
    PROGUARD6_THEN_D8,
    R8_COMPAT,
    R8_COMPAT_CF,
    R8,
    R8_CF;

    public boolean isR8() {
      return this == R8_COMPAT
          || this == R8_COMPAT_CF
          || this == R8
          || this == R8_CF;
    }

    public boolean generatesDex() {
      return this == PROGUARD6_THEN_D8
          || this == R8_COMPAT
          || this == R8;
    }

    public boolean generatesCf() {
      return this == PROGUARD5
          || this == PROGUARD6
          || this == R8_COMPAT_CF
          || this == R8_CF;
    }

    public Backend toBackend() {
      if (generatesDex()) {
        return Backend.DEX;
      }
      assert generatesCf();
      return Backend.CF;
    }
  }

  protected AndroidApp runShrinker(
      Shrinker mode, List<Class> programClasses, Iterable<String> proguardConfigs)
      throws Exception {
    return runShrinker(mode, programClasses, String.join(System.lineSeparator(), proguardConfigs));
  }

  protected AndroidApp runShrinker(Shrinker mode, List<Class> programClasses, String proguardConfig)
      throws Exception {
    proguardMap = File.createTempFile("proguard", ".map", temp.getRoot()).toPath();
    switch (mode) {
      case PROGUARD5:
        return runProguard5(programClasses, proguardConfig, proguardMap);
      case PROGUARD6:
        return runProguard6(programClasses, proguardConfig, proguardMap);
      case PROGUARD6_THEN_D8:
        return runProguard6AndD8(programClasses, proguardConfig, proguardMap);
      case R8_COMPAT:
        return runR8Compat(programClasses, proguardConfig, Backend.DEX);
      case R8_COMPAT_CF:
        return runR8Compat(programClasses, proguardConfig, Backend.CF);
      case R8:
        return runR8(programClasses, proguardConfig, Backend.DEX);
      case R8_CF:
        return runR8(programClasses, proguardConfig, Backend.CF);
    }
    throw new IllegalArgumentException("Unknown shrinker: " + mode);
  }

  protected CodeInspector inspectAfterShrinking(
      Shrinker mode, List<Class> programClasses, List<String> proguardConfigs) throws Exception {
    return inspectAfterShrinking(
        mode, programClasses, String.join(System.lineSeparator(), proguardConfigs));
  }

  protected CodeInspector inspectAfterShrinking(
      Shrinker mode, List<Class> programClasses, String proguardConfig) throws Exception {
    switch (mode) {
      case PROGUARD5:
        return inspectProguard5Result(programClasses, proguardConfig);
      case PROGUARD6:
        return inspectProguard6Result(programClasses, proguardConfig);
      case PROGUARD6_THEN_D8:
        return inspectProguard6AndD8Result(programClasses, proguardConfig);
      case R8_COMPAT:
        return inspectR8CompatResult(programClasses, proguardConfig, Backend.DEX);
      case R8_COMPAT_CF:
        return inspectR8CompatResult(programClasses, proguardConfig, Backend.CF);
      case R8:
        return inspectR8Result(programClasses, proguardConfig, Backend.DEX);
      case R8_CF:
        return inspectR8Result(programClasses, proguardConfig, Backend.CF);
    }
    throw new IllegalArgumentException("Unknown shrinker: " + mode);
  }

  protected AndroidApp runR8(List<Class> programClasses, String proguardConfig, Backend backend)
      throws Exception {
    return runR8(programClasses, proguardConfig, null, backend);
  }

  protected AndroidApp runR8(
      List<Class> programClasses,
      String proguardConfig,
      Consumer<InternalOptions> configure,
      Backend backend)
      throws Exception {
    AndroidApp app = readClassesAndRuntimeJar(programClasses, backend);
    R8Command.Builder builder = ToolHelper.prepareR8CommandBuilder(app, emptyConsumer(backend));
    ToolHelper.allowTestProguardOptions(builder);
    builder.addProguardConfiguration(ImmutableList.of(proguardConfig), Origin.unknown());
    return ToolHelper.runR8(builder.build(), configure);
  }

  protected CodeInspector inspectR8Result(
      List<Class> programClasses, String proguardConfig, Backend backend) throws Exception {
    return new CodeInspector(runR8(programClasses, proguardConfig, backend));
  }

  protected AndroidApp runR8Compat(
      List<Class> programClasses, String proguardConfig, Backend backend) throws Exception {
    CompatProguardCommandBuilder builder = new CompatProguardCommandBuilder(true);
    ToolHelper.allowTestProguardOptions(builder);
    builder.addProguardConfiguration(ImmutableList.of(proguardConfig), Origin.unknown());
    programClasses.forEach(
        clazz -> builder.addProgramFiles(ToolHelper.getClassFileForTestClass(clazz)));
    if (backend == Backend.DEX) {
      builder.addLibraryFiles(ToolHelper.getAndroidJar(ToolHelper.getMinApiLevelForDexVm()));
      builder.setProgramConsumer(DexIndexedConsumer.emptyConsumer());
    } else {
      assert backend == Backend.CF;
      builder.addLibraryFiles(ToolHelper.getJava8RuntimeJar());
      builder.setProgramConsumer(ClassFileConsumer.emptyConsumer());
    }
    return ToolHelper.runR8(builder.build());
  }

  protected CodeInspector inspectR8CompatResult(
      List<Class> programClasses, String proguardConfig, Backend backend) throws Exception {
    return new CodeInspector(runR8Compat(programClasses, proguardConfig, backend));
  }

  protected AndroidApp runProguard5(
      List<Class> programClasses, String proguardConfig, Path proguardMap) throws Exception {
    Path proguardedJar =
        File.createTempFile("proguarded", FileUtils.JAR_EXTENSION, temp.getRoot()).toPath();
    Path proguardConfigFile = File.createTempFile("proguard", ".config", temp.getRoot()).toPath();
    FileUtils.writeTextFile(proguardConfigFile, proguardConfig);
    ProcessResult result = ToolHelper.runProguardRaw(
        jarTestClasses(programClasses),
        proguardedJar,
        ToolHelper.getAndroidJar(AndroidApiLevel.N),
        proguardConfigFile,
        proguardMap);
    if (result.exitCode != 0) {
      fail("Proguard failed, exit code " + result.exitCode + ", stderr:\n" + result.stderr);
    }
    return readJar(proguardedJar);
  }

  protected CodeInspector inspectProguard5Result(List<Class> programClasses, String proguardConfig)
      throws Exception {
    proguardMap = File.createTempFile("proguard", ".map", temp.getRoot()).toPath();
    return new CodeInspector(
        runProguard5(programClasses, proguardConfig, proguardMap), proguardMap);
  }

  protected ProcessResult runProguard6Raw(
      Path destination,
      List<Class> programClasses,
      String proguardConfig,
      Path proguardMap,
      List<DataResource> dataResources)
      throws Exception {
    return runProguard6Raw(
        destination,
        jarTestClasses(programClasses, dataResources),
        proguardConfig,
        proguardMap,
        null);
  }

  protected ProcessResult runProguard6Raw(
      Path destination, Path jar, String proguardConfig, Path proguardMap) throws Exception {
    return runProguard6Raw(destination, jar, proguardConfig, proguardMap, null);
  }

  protected ProcessResult runProguard6Raw(
      Path destination,
      Path jar,
      String proguardConfig,
      Path proguardMap,
      Consumer<ProcessResult> processResultConsumer)
      throws Exception {
    Path proguardConfigFile = File.createTempFile("proguard", ".config", temp.getRoot()).toPath();
    FileUtils.writeTextFile(proguardConfigFile, proguardConfig);
    ProcessResult result =
        ToolHelper.runProguard6Raw(
            jar,
            destination,
            ToolHelper.getAndroidJar(AndroidApiLevel.N),
            proguardConfigFile,
            proguardMap);
    if (result.exitCode != 0) {
      fail("Proguard failed, exit code " + result.exitCode + ", stderr:\n" + result.stderr);
    }
    if (processResultConsumer != null) {
      processResultConsumer.accept(result);
    }
    return result;
  }

  protected AndroidApp runProguard6(
      List<Class> programClasses, String proguardConfig, Path proguardMap) throws Exception {
    return runProguard6(programClasses, proguardConfig, proguardMap, null);
  }

  protected AndroidApp runProguard6(
      List<Class> programClasses,
      String proguardConfig,
      Path proguardMap,
      List<DataResource> dataResources)
      throws Exception {
    Path proguardedJar =
        File.createTempFile("proguarded", FileUtils.JAR_EXTENSION, temp.getRoot()).toPath();
    runProguard6Raw(proguardedJar, programClasses, proguardConfig, proguardMap, dataResources);
    return readJar(proguardedJar);
  }

  protected CodeInspector inspectProguard6Result(List<Class> programClasses, String proguardConfig)
      throws Exception {
    proguardMap = File.createTempFile("proguard", ".map", temp.getRoot()).toPath();
    return new CodeInspector(
        runProguard6(programClasses, proguardConfig, proguardMap), proguardMap);
  }

  protected AndroidApp runProguard6AndD8(
      List<Class> programClasses, String proguardConfig, Path proguardMap) throws Exception {
    Path proguardedJar =
        File.createTempFile("proguarded", FileUtils.JAR_EXTENSION, temp.getRoot()).toPath();
    Path proguardConfigFile = File.createTempFile("proguard", ".config", temp.getRoot()).toPath();
    FileUtils.writeTextFile(proguardConfigFile, proguardConfig);
    ProcessResult result = ToolHelper.runProguard6Raw(
        jarTestClasses(programClasses),
        proguardedJar,
        ToolHelper.getAndroidJar(AndroidApiLevel.N),
        proguardConfigFile,
        proguardMap);
    if (result.exitCode != 0) {
      fail("Proguard failed, exit code " + result.exitCode + ", stderr:\n" + result.stderr);
    }
    return ToolHelper.runD8(readJar(proguardedJar));
  }

  protected CodeInspector inspectProguard6AndD8Result(
      List<Class> programClasses, String proguardConfig) throws Exception {
    proguardMap = File.createTempFile("proguard", ".map", temp.getRoot()).toPath();
    return new CodeInspector(
        runProguard6AndD8(programClasses, proguardConfig, proguardMap), proguardMap);
  }

  protected void verifyClassesPresent(
      CodeInspector codeInspector, Class<?>... classesOfInterest) {
    for (Class klass : classesOfInterest) {
      ClassSubject c = codeInspector.clazz(klass);
      assertThat(c, isPresent());
    }
  }

  protected void verifyClassesAbsent(
      CodeInspector codeInspector, Class<?>... classesOfInterest) {
    for (Class klass : classesOfInterest) {
      ClassSubject c = codeInspector.clazz(klass);
      assertThat(c, not(isPresent()));
    }
  }
}
