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

import static com.android.tools.r8.utils.PredicateUtils.not;
import static junit.framework.TestCase.assertEquals;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;

import com.android.tools.r8.KotlinTestBase;
import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)
public class KotlinLambdaMergingSingletonTest extends KotlinTestBase {

  private final boolean allowAccessModification;
  private final TestParameters parameters;

  @Parameters(name = "{0}, {1}, allow access modification: {2}")
  public static Collection<Object[]> data() {
    return buildParameters(
        getTestParameters()
            .withCfRuntime(CfVm.last())
            .withDexRuntime(Version.last())
            .withAllApiLevels()
            .build(),
        getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
        BooleanUtils.values());
  }

  public KotlinLambdaMergingSingletonTest(
      TestParameters parameters,
      KotlinTestParameters kotlinParameters,
      boolean allowAccessModification) {
    super(kotlinParameters);
    this.allowAccessModification = allowAccessModification;
    this.parameters = parameters;
  }

  @Test
  public void testJVM() throws Exception {
    assumeFalse(allowAccessModification);
    assumeTrue(parameters.isCfRuntime());
    assumeTrue(kotlinParameters.isFirst());
    testForJvm()
        .addProgramFiles(getProgramFiles())
        .run(parameters.getRuntime(), getMainClassName())
        .assertSuccessWithOutput(getExpectedOutput());
  }

  @Test
  public void testR8() throws Exception {
    testForR8(parameters.getBackend())
        .addProgramFiles(getProgramFiles())
        .addKeepMainRule(getMainClassName())
        .addHorizontallyMergedClassesInspector(this::inspect)
        .allowAccessModification(allowAccessModification)
        .allowDiagnosticWarningMessages()
        .setMinApi(parameters.getApiLevel())
        .compile()
        .assertAllWarningMessagesMatch(
            containsString("Resource 'META-INF/MANIFEST.MF' already exists."))
        .run(parameters.getRuntime(), getMainClassName())
        .assertSuccessWithOutput(getExpectedOutput());
  }

  private void inspect(HorizontallyMergedClassesInspector inspector) throws IOException {
    // Get the Kotlin lambdas in the input.
    KotlinLambdasInInput lambdasInInput =
        KotlinLambdasInInput.create(getProgramFiles(), getTestName());
    assertEquals(2, lambdasInInput.getNumberOfJStyleLambdas());
    assertEquals(7, lambdasInInput.getNumberOfKStyleLambdas());

    // All J-style Kotlin lambdas should be merged into one class.
    inspector.assertIsCompleteMergeGroup(lambdasInInput.getJStyleLambdas());

    // A subset of the K-style Kotlin lambdas should be merged into one class.
    Set<ClassReference> kStyleLambdaMergeGroup =
        Sets.newHashSet(
            lambdasInInput.getKStyleLambdaReferenceFromTypeName(
                getTestName(), "MainKt$test2$$inlined$process$1"),
            lambdasInInput.getKStyleLambdaReferenceFromTypeName(
                getTestName(), "MainKt$test2$$inlined$process$2"),
            lambdasInInput.getKStyleLambdaReferenceFromTypeName(
                getTestName(), "MainKt$test2$$inlined$process$3"),
            lambdasInInput.getKStyleLambdaReferenceFromTypeName(
                getTestName(), "MainKt$test2$$inlined$process$4"));
    if (allowAccessModification) {
      kStyleLambdaMergeGroup.add(
          lambdasInInput.getKStyleLambdaReferenceFromTypeName(
              getTestName(), "MainKt$test2$lambda$1"));
    }
    inspector.assertIsCompleteMergeGroup(kStyleLambdaMergeGroup);

    // The remaining lambdas are not merged.
    inspector.assertClassReferencesNotMerged(
        lambdasInInput.getAllLambdas().stream()
            .filter(not(lambdasInInput::isJStyleLambda))
            .filter(not(kStyleLambdaMergeGroup::contains))
            .collect(Collectors.toSet()));
  }

  private String getExpectedOutput() {
    return StringUtils.lines(
        "(*000*001*002*003*004*005*006*007*008*009*)",
        "(*000*001*002*003*004*005*006*007*008*009*)",
        "(*010*011*)",
        "(*012*013*014*)",
        "(*015*016*)",
        "(*017*018*019*)");
  }

  private Path getJavaJarFile() {
    return getJavaJarFile(getTestName());
  }

  private String getMainClassName() {
    return getTestName() + ".MainKt";
  }

  private List<Path> getProgramFiles() {
    Path kotlinJarFile =
        getCompileMemoizer(getKotlinFilesInResource(getTestName()), getTestName())
            .configure(kotlinCompilerTool -> kotlinCompilerTool.includeRuntime().noReflect())
            .getForConfiguration(kotlinc, targetVersion);
    return ImmutableList.of(kotlinJarFile, getJavaJarFile(), kotlinc.getKotlinAnnotationJar());
  }

  private String getTestName() {
    return "lambdas_singleton";
  }
}
