// 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.desugar.nestaccesscontrol;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;

import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRunResult;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.desugar.nestaccesscontrol.NestAttributesInDexTest.Host.Member1;
import com.android.tools.r8.desugar.nestaccesscontrol.NestAttributesInDexTest.Host.Member2;
import com.android.tools.r8.transformers.ClassFileTransformer;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.TypeSubject;
import com.google.common.collect.ImmutableList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
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;
import org.objectweb.asm.Opcodes;

@RunWith(Parameterized.class)
public class NestAttributesInDexTest extends NestAttributesInDexTestBase {

  @Parameter() public TestParameters parameters;

  @Parameters(name = "{0}")
  public static TestParametersCollection data() {
    return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
  }

  private static final String EXPECTED_OUTPUT =
      StringUtils.lines(
          "true", "true", "true", "true", "true", "true", "true", "true", "true", "false", "false",
          "true", "true", "true", "false", "false", "true", "true", "true", "false", "false",
          "true", "true", "true");

  // Right now R8 removes the nest attributes if they are not required for runtime execution, so
  // most reflective calls will return false.
  private static final String R8_EXPECTED_OUTPUT =
      StringUtils.lines(
          "false", "false", "false", "true", "false", "false", "true", "false", "false", "false",
          "false", "false", "true", "false", "false", "false", "false", "false", "true", "false",
          "false", "true", "true", "true");

  private void checkResult(TestRunResult<?> result) {
    if (isRuntimeWithNestSupport(parameters.getRuntime())) {
      result.assertSuccessWithOutput(EXPECTED_OUTPUT);
    } else if (parameters.isDexRuntimeVersionNewerThanOrEqual(Version.V14_0_0)) {
      // TODO(b/247047415): Partial DEX support in Android U DP1 (reflective APIs).
      result.assertSuccessWithOutput(R8_EXPECTED_OUTPUT);
    } else {
      result.assertFailureWithErrorThatThrows(NoSuchMethodError.class);
    }
  }

  private void checkResultR8(TestRunResult<?> result) {
    // TODO(b/247047415): Partial DEX support in Android U DP1 (reflective APIs).
    if (parameters.isDexRuntimeVersionNewerThanOrEqual(Version.V14_0_0)
        || isRuntimeWithNestSupport(parameters.getRuntime())) {
      result.assertSuccessWithOutput(R8_EXPECTED_OUTPUT);
    } else {
      result.assertFailureWithErrorThatThrows(NoSuchMethodError.class);
    }
  }

  @Test
  public void testRuntime() throws Exception {
    assumeTrue(
        parameters.isCfRuntime()
            && isRuntimeWithNestSupport(parameters.asCfRuntime())
            && parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
    testForJvm(parameters)
        .addProgramClassFileData(getTransformedClasses())
        .addProgramClasses(OtherHost.class)
        .run(parameters.getRuntime(), TestClass.class)
        .assertSuccessWithOutput(EXPECTED_OUTPUT);
  }

  private void inspect(CodeInspector inspector, boolean emitNestAnnotationsInDex) {
    ClassSubject host = inspector.clazz(Host.class);
    ClassSubject member1 = inspector.clazz(Member1.class);
    ClassSubject member2 = inspector.clazz(Member2.class);
    assertEquals(
        emitNestAnnotationsInDex
            ? ImmutableList.of(member1.asTypeSubject(), member2.asTypeSubject())
            : Collections.emptyList(),
        host.getFinalNestMembersAttribute());
    TypeSubject expectedNestHostAttribute = emitNestAnnotationsInDex ? host.asTypeSubject() : null;
    assertEquals(expectedNestHostAttribute, member1.getFinalNestHostAttribute());
    assertEquals(expectedNestHostAttribute, member2.getFinalNestHostAttribute());
    ClassSubject otherHost = inspector.clazz(OtherHost.class);
    assertNull(otherHost.getFinalNestHostAttribute());
    assertEquals(0, otherHost.getFinalNestMembersAttribute().size());
  }

  @Test
  public void testD8() throws Exception {
    parameters.assumeDexRuntime();
    testForD8()
        .addProgramClassFileData(getTransformedClasses())
        .addProgramClasses(OtherHost.class)
        .setMinApi(parameters)
        .addOptionsModification(options -> options.emitNestAnnotationsInDex = true)
        .compile()
        .inspect(inspector -> inspect(inspector, true))
        .run(parameters.getRuntime(), TestClass.class)
        .apply(this::checkResult);
  }

  @Test
  public void testD8NoDesugar() throws Exception {
    assumeTrue(parameters.isDexRuntime());
    testForD8(parameters.getBackend())
        .addProgramClassFileData(getTransformedClasses())
        .addProgramClasses(OtherHost.class)
        .disableDesugaring()
        .setMinApi(parameters)
        .addOptionsModification(options -> assertFalse(options.emitNestAnnotationsInDex))
        .compile()
        .inspect(inspector -> inspect(inspector, false))
        .run(parameters.getRuntime(), TestClass.class)
        .apply(this::checkResult);
  }

  @Test
  public void testR8NoKeep() throws Exception {
    parameters.assumeR8TestParameters();
    assumeTrue(parameters.isDexRuntime() || isRuntimeWithNestSupport(parameters.asCfRuntime()));
    testForR8(parameters.getBackend())
        .addProgramClassFileData(getTransformedClasses())
        .addProgramClasses(OtherHost.class)
        .setMinApi(parameters)
        .addOptionsModification(options -> options.emitNestAnnotationsInDex = true)
        .addKeepMainRule(TestClass.class)
        .compile()
        // Don't expect any nest info. The classes Host, Member1, Member2 and OtherHost remains
        // due to the use of class constants in the code, but they have no methods so no nest
        // attributes are required for runtime execution.
        .inspect(inspector -> inspect(inspector, false))
        .run(parameters.getRuntime(), TestClass.class)
        .apply(this::checkResultR8);
  }

  @Test
  public void testR8KeepHost() throws Exception {
    parameters.assumeR8TestParameters();
    assumeTrue(parameters.isDexRuntime() || isRuntimeWithNestSupport(parameters.asCfRuntime()));
    testForR8(parameters.getBackend())
        .addProgramClassFileData(getTransformedClasses())
        .addProgramClasses(OtherHost.class)
        .setMinApi(parameters)
        .addOptionsModification(options -> options.emitNestAnnotationsInDex = true)
        .addKeepMainRule(TestClass.class)
        .addKeepClassRules(Host.class)
        .compile()
        // Don't expect any nest info. Class Host is kept and the classes Member1, Members and
        // OtherHost remains due to the use of class constants in the code, but they have no methods
        // so no nest attributes are required for runtime execution.
        // TODO(b/130716228#comment5): How to keep nest attributes?
        .inspect(inspector -> inspect(inspector, false))
        .run(parameters.getRuntime(), TestClass.class)
        .apply(this::checkResultR8);
  }

  @Test
  public void testR8KeepMembers() throws Exception {
    parameters.assumeR8TestParameters();
    assumeTrue(parameters.isDexRuntime() || isRuntimeWithNestSupport(parameters.asCfRuntime()));
    testForR8(parameters.getBackend())
        .addProgramClassFileData(getTransformedClasses())
        .addProgramClasses(OtherHost.class)
        .setMinApi(parameters)
        .addOptionsModification(options -> options.emitNestAnnotationsInDex = true)
        .addKeepMainRule(TestClass.class)
        .addKeepClassRules(Member1.class, Member2.class)
        .compile()
        // Don't expect any nest info. Member1 and Member2 are kept and the classes Host and
        // OtherHost remains due to the use of class constants in the code, but they have no
        // methods so no nest attributes are required for runtime execution.
        // TODO(b/130716228#comment5): How to keep nest attributes?
        .inspect(inspector -> inspect(inspector, false))
        .run(parameters.getRuntime(), TestClass.class)
        .apply(this::checkResultR8);
  }

  @Test
  public void testR8KeepBoth() throws Exception {
    parameters.assumeR8TestParameters();
    assumeTrue(parameters.isDexRuntime() || isRuntimeWithNestSupport(parameters.asCfRuntime()));
    testForR8(parameters.getBackend())
        .addProgramClassFileData(getTransformedClasses())
        .addProgramClasses(OtherHost.class)
        .setMinApi(parameters)
        .addOptionsModification(options -> options.emitNestAnnotationsInDex = true)
        .addKeepMainRule(TestClass.class)
        .addKeepClassRules(Host.class, Member1.class, Member2.class)
        .compile()
        // Don't expect any nest info. All of Host, Member1 and Member2 are kept,
        // but they have no methods so no nest attributes are required for runtime execution.
        // TODO(b/130716228#comment5): How to keep nest attributes?
        .inspect(inspector -> inspect(inspector, false))
        .run(parameters.getRuntime(), TestClass.class)
        .apply(this::checkResultR8);
  }

  public Collection<byte[]> getTransformedClasses() throws Exception {
    ClassFileTransformer transformer =
        transformer(TestClass.class)
            .setMinVersion(CfVm.JDK11)
            .transformMethodInsnInMethod(
                "main",
                ((opcode, owner, name, descriptor, isInterface, continuation) -> {
                  if (owner.equals(DescriptorUtils.getClassBinaryName(AdditionalClassAPIs.class))) {
                    if (name.equals("getNestMembers")) {
                      continuation.visitMethodInsn(
                          Opcodes.INVOKEVIRTUAL,
                          "java/lang/Class",
                          "getNestMembers",
                          "()[Ljava/lang/Class;",
                          false);
                    } else if (name.equals("getNestHost")) {
                      continuation.visitMethodInsn(
                          Opcodes.INVOKEVIRTUAL,
                          "java/lang/Class",
                          "getNestHost",
                          "()Ljava/lang/Class;",
                          false);
                    } else if (name.equals("isNestmateOf")) {
                      continuation.visitMethodInsn(
                          Opcodes.INVOKEVIRTUAL,
                          "java/lang/Class",
                          "isNestmateOf",
                          "(Ljava/lang/Class;)Z",
                          false);
                    } else {
                      fail("Unsupported rewriting of API " + owner + "." + name + descriptor);
                    }
                  } else {
                    continuation.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
                  }
                }));

    return ImmutableList.of(
        transformer.transform(),
        withNest(Host.class).transform(),
        withNest(Member1.class).transform(),
        withNest(Member2.class).transform());
  }

  private ClassFileTransformer withNest(Class<?> clazz) throws Exception {
    return transformer(clazz).setNest(Host.class, Member1.class, Member2.class);
  }

  static class AdditionalClassAPIs {
    public static Class<?>[] getNestMembers(Class<?> clazz) {
      throw new RuntimeException();
    }

    public static Class<?> getNestHost(Class<?> clazz) {
      throw new RuntimeException();
    }

    public static boolean isNestmateOf(Class<?> class1, Class<?> class2) {
      throw new RuntimeException();
    }
  }

  static class TestClass {

    public static boolean sameArrayContent(Class<?>[] array1, Class<?>[] array2) {
      Set<Class<?>> expected = new HashSet<>(Arrays.asList(array1));
      for (Class<?> clazz : array2) {
        if (!expected.remove(clazz)) {
          return false;
        }
      }
      return expected.isEmpty();
    }

    public static void main(String[] args) {
      Class<?>[] nestMembers = new Class<?>[] {Host.class, Member1.class, Member2.class};
      System.out.println(
          sameArrayContent(nestMembers, AdditionalClassAPIs.getNestMembers(Host.class)));
      System.out.println(
          sameArrayContent(nestMembers, AdditionalClassAPIs.getNestMembers(Member1.class)));
      System.out.println(
          sameArrayContent(nestMembers, AdditionalClassAPIs.getNestMembers(Member2.class)));
      System.out.println(AdditionalClassAPIs.getNestHost(Host.class).equals(Host.class));
      System.out.println(AdditionalClassAPIs.getNestHost(Member1.class).equals(Host.class));
      System.out.println(AdditionalClassAPIs.getNestHost(Member2.class).equals(Host.class));
      for (Class<?> class1 : nestMembers) {
        for (Class<?> class2 : nestMembers) {
          System.out.println(AdditionalClassAPIs.isNestmateOf(class1, class2));
        }
        System.out.println(AdditionalClassAPIs.isNestmateOf(OtherHost.class, class1));
        System.out.println(AdditionalClassAPIs.isNestmateOf(class1, OtherHost.class));
      }
      System.out.println(AdditionalClassAPIs.getNestHost(OtherHost.class).equals(OtherHost.class));
      System.out.println(
          sameArrayContent(
              new Class<?>[] {OtherHost.class},
              AdditionalClassAPIs.getNestMembers(OtherHost.class)));
      System.out.println(AdditionalClassAPIs.isNestmateOf(OtherHost.class, OtherHost.class));
    }
  }

  static class OtherHost {}

  static class Host {
    static class Member1 {}

    static class Member2 {}
  }
}
