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

import static com.android.tools.r8.startup.utils.StartupTestingMatchers.isEqualToClassDataLayout;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.notIf;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

import com.android.tools.r8.D8TestCompileResult;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.ir.desugar.LambdaClass;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.startup.profile.ExternalStartupClass;
import com.android.tools.r8.startup.profile.ExternalStartupItem;
import com.android.tools.r8.startup.profile.ExternalStartupMethod;
import com.android.tools.r8.startup.utils.MixedSectionLayoutInspector;
import com.android.tools.r8.startup.utils.StartupTestingUtils;
import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.MethodReferenceUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.nio.file.Path;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;

@RunWith(Parameterized.class)
public class StartupSyntheticPlacementTest extends TestBase {

  @Parameter(0)
  public TestParameters parameters;

  @Parameter(1)
  public boolean enableMinimalStartupDex;

  @Parameter(2)
  public boolean enableStartupCompletenessCheck;

  @Parameter(3)
  public boolean useLambda;

  @Parameters(name = "{0}, minimal startup dex: {1}, completeness check: {2}, use lambda: {3}")
  public static List<Object[]> data() {
    return buildParameters(
        // N so that java.util.function.Consumer is present.
        getTestParameters().withDexRuntimes().withApiLevel(AndroidApiLevel.N).build(),
        BooleanUtils.values(),
        BooleanUtils.values(),
        BooleanUtils.values());
  }

  @Test
  public void testLayoutUsingD8() throws Exception {
    // First build the app using R8.
    R8TestCompileResult r8CompileResult =
        testForR8(parameters.getBackend())
            .addInnerClasses(getClass())
            .addKeepMainRule(Main.class)
            .addKeepClassAndMembersRules(A.class, B.class, C.class)
            .addDontOptimize()
            .setMinApi(parameters)
            .compile();

    // Verify that the build works.
    r8CompileResult
        .run(parameters.getRuntime(), Main.class, Boolean.toString(useLambda))
        .assertSuccessWithOutputLines(getExpectedOutput());

    Path optimizedApp = r8CompileResult.writeToZip();

    // Then instrument the app to generate a startup list for the minified app.
    Set<ExternalStartupItem> startupList = new LinkedHashSet<>();
    testForD8(parameters.getBackend())
        .addProgramFiles(optimizedApp)
        .apply(
            StartupTestingUtils.enableStartupInstrumentationForOptimizedAppUsingLogcat(parameters))
        .release()
        .setMinApi(parameters)
        .compile()
        .addRunClasspathFiles(StartupTestingUtils.getAndroidUtilLog(temp))
        .run(parameters.getRuntime(), Main.class, Boolean.toString(useLambda))
        .apply(StartupTestingUtils.removeStartupListFromStdout(startupList::add))
        .assertSuccessWithOutputLines(getExpectedOutput())
        .apply(
            runResult ->
                assertEquals(
                    getExpectedStartupList(r8CompileResult.inspector(), false), startupList));

    // Finally rebuild the minified app using D8 and the startup list.
    testForD8(parameters.getBackend())
        .addProgramFiles(optimizedApp)
        .apply(
            testBuilder ->
                configureStartupOptions(testBuilder, r8CompileResult.inspector(), startupList))
        .release()
        .setMinApi(parameters)
        .compile()
        .inspectMultiDex(
            r8CompileResult.writeProguardMap(), this::inspectPrimaryDex, this::inspectSecondaryDex)
        .run(parameters.getRuntime(), Main.class, Boolean.toString(useLambda))
        .assertSuccessWithOutputLines(getExpectedOutput());
  }

  // TODO(b/271822426): Reenable test.
  @Ignore("b/271822426")
  @Test
  public void testLayoutUsingR8() throws Exception {
    // First generate a startup list for the original app.
    Set<ExternalStartupItem> startupList = new LinkedHashSet<>();
    D8TestCompileResult instrumentationCompileResult =
        testForD8(parameters.getBackend())
            .addInnerClasses(getClass())
            .apply(
                StartupTestingUtils.enableStartupInstrumentationForOriginalAppUsingLogcat(
                    parameters))
            .release()
            .setMinApi(parameters)
            .compile();

    instrumentationCompileResult
        .addRunClasspathFiles(StartupTestingUtils.getAndroidUtilLog(temp))
        .run(parameters.getRuntime(), Main.class, Boolean.toString(useLambda))
        .apply(StartupTestingUtils.removeStartupListFromStdout(startupList::add))
        .assertSuccessWithOutputLines(getExpectedOutput())
        .apply(
            runResult ->
                assertEquals(getExpectedStartupList(runResult.inspector(), true), startupList));

    // Then build the app using the startup list that is based on original names.
    testForR8(parameters.getBackend())
        .addInnerClasses(getClass())
        .addKeepMainRule(Main.class)
        .addKeepClassAndMembersRules(A.class, B.class, C.class)
        .apply(
            testBuilder ->
                configureStartupOptions(
                    testBuilder, instrumentationCompileResult.inspector(), startupList))
        .setMinApi(parameters)
        .compile()
        .inspectMultiDex(this::inspectPrimaryDex, this::inspectSecondaryDex)
        .run(parameters.getRuntime(), Main.class, Boolean.toString(useLambda))
        .applyIf(
            enableStartupCompletenessCheck && useLambda,
            runResult -> runResult.assertFailureWithErrorThatThrows(NullPointerException.class),
            runResult -> runResult.assertSuccessWithOutputLines(getExpectedOutput()));
  }

  private void configureStartupOptions(
      TestCompilerBuilder<?, ?, ?, ?, ?> testBuilder,
      CodeInspector inspector,
      Collection<ExternalStartupItem> startupList) {
    testBuilder
        .addOptionsModification(
            options -> {
              options
                  .getStartupOptions()
                  .setEnableMinimalStartupDex(enableMinimalStartupDex)
                  .setEnableStartupCompletenessCheckForTesting(enableStartupCompletenessCheck);
              options
                  .getTestingOptions()
                  .setMixedSectionLayoutStrategyInspector(
                      getMixedSectionLayoutInspector(inspector));
            })
        .apply(ignore -> StartupTestingUtils.setStartupConfiguration(testBuilder, startupList));
  }

  private List<String> getExpectedOutput() {
    return ImmutableList.of("A", "B", "C");
  }

  @SuppressWarnings("unchecked")
  private Set<ExternalStartupItem> getExpectedStartupList(
      CodeInspector inspector, boolean isStartupListForOriginalApp) throws NoSuchMethodException {
    ImmutableSet.Builder<ExternalStartupItem> builder = ImmutableSet.builder();
    builder.add(
        ExternalStartupClass.builder()
            .setClassReference(Reference.classFromClass(Main.class))
            .build(),
        ExternalStartupMethod.builder()
            .setMethodReference(MethodReferenceUtils.mainMethod(Main.class))
            .build(),
        ExternalStartupClass.builder().setClassReference(Reference.classFromClass(A.class)).build(),
        ExternalStartupMethod.builder()
            .setMethodReference(Reference.methodFromMethod(A.class.getDeclaredMethod("a")))
            .build(),
        ExternalStartupClass.builder().setClassReference(Reference.classFromClass(B.class)).build(),
        ExternalStartupMethod.builder()
            .setMethodReference(
                Reference.methodFromMethod(B.class.getDeclaredMethod("b", boolean.class)))
            .build());
    if (useLambda) {
      if (isStartupListForOriginalApp) {
        // TODO(b/271822426): Update after rewriting startup profile.
        /*builder.add(
        ExternalSyntheticStartupMethod.builder()
            .setSyntheticContextReference(Reference.classFromClass(B.class))
            .build());*/
      } else {
        ClassSubject bClassSubject = inspector.clazz(B.class);

        MethodSubject syntheticLambdaAccessorMethod =
            bClassSubject.uniqueMethodThatMatches(
                method ->
                    method
                        .getOriginalName()
                        .startsWith(LambdaClass.R8_LAMBDA_ACCESSOR_METHOD_PREFIX));
        assertThat(syntheticLambdaAccessorMethod, isPresent());

        ClassSubject externalSyntheticLambdaClassSubject =
            inspector.clazz(getSyntheticLambdaClassReference());
        assertThat(externalSyntheticLambdaClassSubject, isPresent());

        ClassReference externalSyntheticLambdaClassReference =
            externalSyntheticLambdaClassSubject.getFinalReference();

        builder.add(
            ExternalStartupClass.builder()
                .setClassReference(externalSyntheticLambdaClassReference)
                .build(),
            ExternalStartupMethod.builder()
                .setMethodReference(
                    MethodReferenceUtils.instanceConstructor(externalSyntheticLambdaClassReference))
                .build(),
            ExternalStartupMethod.builder()
                .setMethodReference(
                    Reference.method(
                        externalSyntheticLambdaClassReference,
                        "accept",
                        ImmutableList.of(Reference.classFromClass(Object.class)),
                        null))
                .build(),
            ExternalStartupMethod.builder()
                .setMethodReference(
                    Reference.method(
                        Reference.classFromClass(B.class),
                        syntheticLambdaAccessorMethod.getFinalName(),
                        ImmutableList.of(Reference.classFromClass(Object.class)),
                        null))
                .build());
      }
      builder.add(
          ExternalStartupMethod.builder()
              .setMethodReference(
                  Reference.methodFromMethod(B.class.getDeclaredMethod("lambda$b$0", Object.class)))
              .build());
    }
    builder.add(
        ExternalStartupClass.builder().setClassReference(Reference.classFromClass(C.class)).build(),
        ExternalStartupMethod.builder()
            .setMethodReference(Reference.methodFromMethod(C.class.getDeclaredMethod("c")))
            .build());
    return builder.build();
  }

  private List<ClassReference> getExpectedClassDataLayout(
      CodeInspector inspector, int virtualFile) {
    ClassSubject syntheticLambdaClassSubject = inspector.clazz(getSyntheticLambdaClassReference());

    // The synthetic lambda should only be placed alongside its synthetic context (B) if it is used.
    // Otherwise, it should be last, or in the second dex file if compiling with minimal startup.
    ImmutableList.Builder<ClassReference> layoutBuilder = ImmutableList.builder();
    if (virtualFile == 0) {
      layoutBuilder.add(
          Reference.classFromClass(Main.class),
          Reference.classFromClass(A.class),
          Reference.classFromClass(B.class));
      if (useLambda) {
        layoutBuilder.add(syntheticLambdaClassSubject.getFinalReference());
      }
      layoutBuilder.add(Reference.classFromClass(C.class));
    }
    if (!useLambda) {
      if (!enableMinimalStartupDex || virtualFile == 1) {
        layoutBuilder.add(syntheticLambdaClassSubject.getFinalReference());
      }
    }
    return layoutBuilder.build();
  }

  private MixedSectionLayoutInspector getMixedSectionLayoutInspector(CodeInspector inspector) {
    return new MixedSectionLayoutInspector() {
      @Override
      public void inspectClassDataLayout(int virtualFile, Collection<DexProgramClass> layout) {
        assertThat(
            layout, isEqualToClassDataLayout(getExpectedClassDataLayout(inspector, virtualFile)));
      }
    };
  }

  private void inspectPrimaryDex(CodeInspector inspector) {
    assertThat(inspector.clazz(Main.class), isPresent());
    assertThat(inspector.clazz(A.class), isPresent());
    assertThat(inspector.clazz(B.class), isPresent());
    assertThat(inspector.clazz(C.class), isPresent());
    assertThat(
        inspector.clazz(getSyntheticLambdaClassReference()),
        notIf(isPresent(), enableMinimalStartupDex && !useLambda));
  }

  private void inspectSecondaryDex(CodeInspector inspector) {
    if (enableMinimalStartupDex && !useLambda) {
      assertEquals(1, inspector.allClasses().size());
      assertThat(inspector.clazz(getSyntheticLambdaClassReference()), isPresent());
    } else {
      assertTrue(inspector.allClasses().isEmpty());
    }
  }

  private static ClassReference getSyntheticLambdaClassReference() {
    return SyntheticItemsTestUtils.syntheticLambdaClass(B.class, 0);
  }

  static class Main {

    public static void main(String[] args) {
      boolean useLambda = args.length > 0 && args[0].equals("true");
      A.a();
      B.b(useLambda);
      C.c();
    }
  }

  static class A {

    static void a() {
      System.out.println("A");
    }
  }

  static class B {

    static void b(boolean useLambda) {
      String message = System.currentTimeMillis() > 0 ? "B" : null;
      if (useLambda) {
        Consumer<Object> consumer = obj -> {};
        consumer.accept(consumer);
      }
      System.out.println(message);
    }
  }

  static class C {

    static void c() {
      System.out.println("C");
    }
  }
}
