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

import static org.junit.Assert.assertTrue;

import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestBase.MinifyMode;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.debug.DebugTestConfig.RuntimeKind;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.DexInspector;
import com.android.tools.r8.utils.DexInspector.ClassSubject;
import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
import com.google.common.collect.ImmutableList;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

/** Tests renaming of class and method names and corresponding proguard map output. */
@RunWith(Parameterized.class)
public class MinificationTest extends DebugTestBase {

  private static final String SOURCE_FILE = "Minified.java";

  @Parameterized.Parameters(name = "backend:{0} minification:{1} proguardMap:{2}")
  public static Collection minificationControl() {
    ImmutableList.Builder<Object> builder = ImmutableList.builder();
    for (RuntimeKind kind : RuntimeKind.values()) {
      for (MinifyMode mode : MinifyMode.values()) {
        builder.add((Object) new Object[] {kind, mode, false});
        if (mode.isMinify()) {
          builder.add((Object) new Object[] {kind, mode, true});
        }
      }
    }
    return builder.build();
  }

  @Rule
  public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();

  private final RuntimeKind runtimeKind;
  private final MinifyMode minificationMode;
  private final boolean writeProguardMap;

  public MinificationTest(
      RuntimeKind runtimeKind, MinifyMode minificationMode, boolean writeProguardMap) {
    this.runtimeKind = runtimeKind;
    this.minificationMode = minificationMode;
    this.writeProguardMap = writeProguardMap;
  }

  private boolean minifiedNames() {
    return minificationMode.isMinify() && !writeProguardMap;
  }

  private DebugTestConfig getTestConfig() throws Throwable {
    List<String> proguardConfigurations = Collections.emptyList();
    if (minificationMode.isMinify()) {
      ImmutableList.Builder<String> builder = ImmutableList.builder();
      builder.add("-keep public class Minified { public static void main(java.lang.String[]); }");
      builder.add("-keepattributes SourceFile");
      builder.add("-keepattributes LineNumberTable");
      if (minificationMode == MinifyMode.AGGRESSIVE) {
        builder.add("-overloadaggressively");
      }
      proguardConfigurations = builder.build();
    }

    AndroidApiLevel minSdk = ToolHelper.getMinApiLevelForDexVm();
    Path outputPath = temp.getRoot().toPath().resolve("classes.zip");
    Path proguardMap = writeProguardMap ? temp.getRoot().toPath().resolve("proguard.map") : null;
    OutputMode outputMode =
        runtimeKind == RuntimeKind.CF ? OutputMode.ClassFile : OutputMode.DexIndexed;
    R8Command.Builder builder =
        R8Command.builder()
            .addProgramFiles(DEBUGGEE_JAR)
            .setOutput(outputPath, outputMode)
            .setMode(CompilationMode.DEBUG)
            .addLibraryFiles(ToolHelper.getAndroidJar(minSdk));
    if (runtimeKind != RuntimeKind.CF) {
      builder.setMinApiLevel(minSdk.getLevel());
    }
    if (proguardMap != null) {
      builder.setProguardMapOutputPath(proguardMap);
    }
    if (!proguardConfigurations.isEmpty()) {
      builder.addProguardConfiguration(proguardConfigurations, Origin.unknown());
    }
    // Disable line number optimization if we're not using a Proguard map.
    ToolHelper.runR8(
        builder.build(),
        proguardMap == null
            ? (oc -> oc.lineNumberOptimization = LineNumberOptimization.OFF)
            : null);

    switch (runtimeKind) {
      case CF:
        {
          CfDebugTestConfig config = new CfDebugTestConfig(outputPath);
          config.setProguardMap(proguardMap);
          return config;
        }
      case DEX:
        {
          DexDebugTestConfig config = new DexDebugTestConfig(outputPath);
          config.setProguardMap(proguardMap);
          return config;
        }
      default:
        throw new Unreachable();
    }
  }

  @Test
  public void testBreakInMainClass() throws Throwable {
    final String className = "Minified";
    final String methodName = minifiedNames() ? "a" : "test";
    final String signature = "()V";
    final String innerClassName = minifiedNames() ? "a" : "Minified$Inner";
    final String innerMethodName = minifiedNames() ? "a" : "innerTest";
    final String innerSignature = "()I";
    DebugTestConfig config = getTestConfig();
    checkStructure(
        config,
        className,
        MethodSignature.fromSignature(methodName, signature),
        innerClassName,
        MethodSignature.fromSignature(innerMethodName, innerSignature));
    runDebugTest(
        config,
        className,
        breakpoint(className, methodName, signature),
        run(),
        checkMethod(className, methodName, signature),
        checkLine(SOURCE_FILE, 14),
        stepOver(INTELLIJ_FILTER),
        checkMethod(className, methodName, signature),
        checkLine(SOURCE_FILE, 15),
        stepInto(INTELLIJ_FILTER),
        checkMethod(innerClassName, innerMethodName, innerSignature),
        checkLine(SOURCE_FILE, 8),
        run());
  }

  @Test
  public void testBreakInPossiblyRenamedClass() throws Throwable {
    final String className = "Minified";
    final String innerClassName = minifiedNames() ? "a" : "Minified$Inner";
    final String innerMethodName = minifiedNames() ? "a" : "innerTest";
    final String innerSignature = "()I";
    DebugTestConfig config = getTestConfig();
    checkStructure(
        config,
        className,
        innerClassName,
        MethodSignature.fromSignature(innerMethodName, innerSignature));
    runDebugTest(
        config,
        className,
        breakpoint(innerClassName, innerMethodName, innerSignature),
        run(),
        checkMethod(innerClassName, innerMethodName, innerSignature),
        checkLine(SOURCE_FILE, 8),
        run());
  }

  private void checkStructure(
      DebugTestConfig config,
      String className,
      MethodSignature method,
      String innerClassName,
      MethodSignature innerMethod)
      throws Throwable {
    Path proguardMap = config.getProguardMap();
    String mappingFile = proguardMap == null ? null : proguardMap.toString();
    DexInspector inspector = new DexInspector(config.getPaths(), mappingFile);
    ClassSubject clazz = inspector.clazz(className);
    assertTrue(clazz.isPresent());
    if (method != null) {
      assertTrue(clazz.method(method).isPresent());
    }
    ClassSubject innerClass = inspector.clazz(innerClassName);
    assertTrue(innerClass.isPresent());
    assertTrue(innerClass.method(innerMethod).isPresent());
  }

  private void checkStructure(
      DebugTestConfig config, String className, String innerClassName, MethodSignature innerMethod)
      throws Throwable {
    checkStructure(config, className, null, innerClassName, innerMethod);
  }
}
