// 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 com.android.tools.r8.CompilationMode;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.debug.DebugTestBase.JUnit3Wrapper.Command;
import com.android.tools.r8.debug.DebugTestConfig.RuntimeKind;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
import com.google.common.collect.ImmutableList;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

/** Tests source file and line numbers on inlined methods. */
@RunWith(Parameterized.class)
public class DebugInfoWhenInliningTest extends DebugTestBase {

  public enum Config {
    CF,
    DEX_NO_FORCE_JUMBO,
    DEX_FORCE_JUMBO
  };

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

  private DebugTestConfig makeConfig(
      LineNumberOptimization lineNumberOptimization,
      boolean writeProguardMap,
      RuntimeKind runtimeKind)
      throws Exception {
    DebugTestConfig config = null;
    Path outdir = temp.newFolder().toPath();
    Path outjar = outdir.resolve("r8_compiled.jar");
    R8Command.Builder builder =
        R8Command.builder().addProgramFiles(DEBUGGEE_JAR).setMode(CompilationMode.RELEASE);

    if (runtimeKind == RuntimeKind.DEX) {
      AndroidApiLevel minSdk = ToolHelper.getMinApiLevelForDexVm();
      builder
          .setMinApiLevel(minSdk.getLevel())
          .addLibraryFiles(ToolHelper.getAndroidJar(minSdk))
          .setOutput(outjar, OutputMode.DexIndexed);
      config = new DexDebugTestConfig(outjar);
    } else {
      assert (runtimeKind == RuntimeKind.CF);
      builder.setOutput(outjar, OutputMode.ClassFile);
      config = new CfDebugTestConfig(outjar);
    }

    if (writeProguardMap) {
      Path proguardMapPath = outdir.resolve("proguard.map");
      builder.setProguardMapOutputPath(proguardMapPath);
      config.setProguardMap(proguardMapPath);
    }

    ToolHelper.runR8(
        builder.build(), options -> {
          options.lineNumberOptimization = lineNumberOptimization;
          options.testing.forceJumboStringProcessing = forceJumboStringProcessing;
        });

    return config;
  }

  private boolean forceJumboStringProcessing;
  private RuntimeKind runtimeKind;

  @Parameters(name = "config: {0}")
  public static Collection<Config> data() {
    return Arrays.asList(Config.values());
  }

  public DebugInfoWhenInliningTest(Config config) {
    this.forceJumboStringProcessing = config == Config.DEX_FORCE_JUMBO;
    this.runtimeKind = config == Config.CF ? RuntimeKind.CF : RuntimeKind.DEX;
  }

  @Test
  public void testEachLineNotOptimized() throws Throwable {
    // The reason why the not-optimized test contains half as many line numbers as the optimized
    // one:
    //
    // In the Java source (Inlining1) each call is duplicated. Since they end up on the same line
    // (innermost callee) the line numbers are actually 7, 7, 32, 32, ... but even if the positions
    // are emitted duplicated in the dex code, the debugger stops only when there's a change.
    int[] lineNumbers = {7, 32, 11, 7};
    testEachLine(makeConfig(LineNumberOptimization.OFF, false, runtimeKind), lineNumbers);
  }

  @Test
  public void testEachLineNotOptimizedWithMap() throws Throwable {
    // The reason why the not-optimized test contains half as many line numbers as the optimized
    // one:
    //
    // In the Java source (Inlining1) each call is duplicated. Since they end up on the same line
    // (innermost callee) the line numbers are actually 7, 7, 32, 32, ... but even if the positions
    // are emitted duplicated in the dex code, the debugger stops only when there's a change.
    int[] lineNumbers = {7, 32, 11, 7};
    testEachLine(makeConfig(LineNumberOptimization.OFF, true, runtimeKind), lineNumbers);
  }

  @Test
  public void testEachLineOptimized() throws Throwable {
    int[] lineNumbers = {1, 2, 3, 4, 5, 6, 7, 8};
    testEachLine(makeConfig(LineNumberOptimization.ON, false, runtimeKind), lineNumbers);
  }

  @Test
  public void testEachLineOptimizedWithMap() throws Throwable {
    int[] lineNumbers = {7, 7, 32, 32, 11, 11, 7, 7};
    List<List<SignatureAndLine>> inlineFramesList =
        ImmutableList.of(
            ImmutableList.of(
                new SignatureAndLine("void inlineThisFromSameFile()", 7),
                new SignatureAndLine("void main(java.lang.String[])", 19)),
            ImmutableList.of(
                new SignatureAndLine("void inlineThisFromSameFile()", 7),
                new SignatureAndLine("void main(java.lang.String[])", 20)),
            ImmutableList.of(
                new SignatureAndLine("void Inlining2.inlineThisFromAnotherFile()", 32),
                new SignatureAndLine("void main(java.lang.String[])", 21)),
            ImmutableList.of(
                new SignatureAndLine("void Inlining2.inlineThisFromAnotherFile()", 32),
                new SignatureAndLine("void main(java.lang.String[])", 22)),
            ImmutableList.of(
                new SignatureAndLine("void sameFileMultilevelInliningLevel2()", 11),
                new SignatureAndLine("void sameFileMultilevelInliningLevel1()", 15),
                new SignatureAndLine("void main(java.lang.String[])", 23)),
            ImmutableList.of(
                new SignatureAndLine("void sameFileMultilevelInliningLevel2()", 11),
                new SignatureAndLine("void sameFileMultilevelInliningLevel1()", 15),
                new SignatureAndLine("void main(java.lang.String[])", 24)),
            ImmutableList.of(
                new SignatureAndLine("void Inlining3.differentFileMultilevelInliningLevel2()", 7),
                new SignatureAndLine("void Inlining2.differentFileMultilevelInliningLevel1()", 36),
                new SignatureAndLine("void main(java.lang.String[])", 25)),
            ImmutableList.of(
                new SignatureAndLine("void Inlining3.differentFileMultilevelInliningLevel2()", 7),
                new SignatureAndLine("void Inlining2.differentFileMultilevelInliningLevel1()", 36),
                new SignatureAndLine("void main(java.lang.String[])", 26)));
    testEachLine(
        makeConfig(LineNumberOptimization.ON, true, runtimeKind), lineNumbers, inlineFramesList);
  }

  private void testEachLine(DebugTestConfig config, int[] lineNumbers) throws Throwable {
    testEachLine(config, lineNumbers, null);
  }

  private void testEachLine(
      DebugTestConfig config, int[] lineNumbers, List<List<SignatureAndLine>> inlineFramesList)
      throws Throwable {
    final String className = "Inlining1";
    final String mainSignature = "([Ljava/lang/String;)V";

    List<Command> commands = new ArrayList<Command>();
    commands.add(breakpoint(className, "main", mainSignature));
    commands.add(run());
    boolean first = true;
    assert inlineFramesList == null || inlineFramesList.size() == lineNumbers.length;
    for (int idx = 0; idx < lineNumbers.length; ++idx) {
      if (first) {
        first = false;
      } else {
        commands.add(stepOver());
      }
      commands.add(checkMethod(className, "main", mainSignature));
      commands.add(checkLine(SOURCE_FILE, lineNumbers[idx]));
      if (inlineFramesList != null) {
        commands.add(checkInlineFrames(inlineFramesList.get(idx)));
      }
    }
    commands.add(run());
    runDebugTest(config, className, commands);
  }
}
