// Copyright 2016 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.android.desugar;

import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.devtools.build.lib.testutil.MoreAsserts.assertThrows;
import static java.lang.reflect.Modifier.isFinal;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.fail;

import com.google.common.collect.ImmutableList;
import com.google.common.io.ByteStreams;
import com.google.devtools.build.android.desugar.testdata.CaptureLambda;
import com.google.devtools.build.android.desugar.testdata.ConcreteFunction;
import com.google.devtools.build.android.desugar.testdata.ConstructorReference;
import com.google.devtools.build.android.desugar.testdata.GuavaLambda;
import com.google.devtools.build.android.desugar.testdata.InnerClassLambda;
import com.google.devtools.build.android.desugar.testdata.InterfaceWithLambda;
import com.google.devtools.build.android.desugar.testdata.Lambda;
import com.google.devtools.build.android.desugar.testdata.LambdaInOverride;
import com.google.devtools.build.android.desugar.testdata.MethodReference;
import com.google.devtools.build.android.desugar.testdata.MethodReferenceInSubclass;
import com.google.devtools.build.android.desugar.testdata.MethodReferenceSuperclass;
import com.google.devtools.build.android.desugar.testdata.OuterReferenceLambda;
import com.google.devtools.build.android.desugar.testdata.SpecializedFunction;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

/**
 * Test that exercises classes in the {@code testdata} package.  This is meant to be run against a
 * desugared version of those classes, which in turn exercise various desugaring features.
 */
@RunWith(JUnit4.class)
public class DesugarFunctionalTest {

  private final int expectedBridgesFromSameTarget;
  private final int expectedBridgesFromSeparateTarget;
  private final boolean expectLambdaMethodsInInterfaces;

  public DesugarFunctionalTest() {
    this(3, 1, false);
  }

  /** Constructor for testing desugar while allowing default and static interface methods. */
  protected DesugarFunctionalTest(
      boolean expectBridgesFromSeparateTarget, boolean expectDefaultMethods) {
    this(
        expectDefaultMethods ? 0 : 3,
        expectBridgesFromSeparateTarget ? 1 : 0,
        expectDefaultMethods);
  }

  private DesugarFunctionalTest(int bridgesFromSameTarget, int bridgesFromSeparateTarget,
      boolean lambdaMethodsInInterfaces) {
    this.expectedBridgesFromSameTarget = bridgesFromSameTarget;
    this.expectedBridgesFromSeparateTarget = bridgesFromSeparateTarget;
    this.expectLambdaMethodsInInterfaces = lambdaMethodsInInterfaces;
  }

  @Test
  public void testGuavaLambda() {
    GuavaLambda lambdaUse = new GuavaLambda(ImmutableList.of("Sergey", "Larry", "Alex"));
    assertThat(lambdaUse.as()).containsExactly("Alex");
  }

  @Test
  public void testJavaLambda() {
    Lambda lambdaUse = new Lambda(ImmutableList.of("Sergey", "Larry", "Alex"));
    assertThat(lambdaUse.as()).containsExactly("Alex");
  }

  @Test
  public void testLambdaForIntersectionType() throws Exception {
    assertThat(Lambda.hello().call()).isEqualTo("hello");
  }

  @Test
  public void testCapturingLambda() {
    CaptureLambda lambdaUse = new CaptureLambda(ImmutableList.of("Sergey", "Larry", "Alex"));
    assertThat(lambdaUse.prefixed("L")).containsExactly("Larry");
  }

  @Test
  public void testOuterReferenceLambda() throws Exception {
    OuterReferenceLambda lambdaUse = new OuterReferenceLambda(ImmutableList.of("Sergey", "Larry"));
    assertThat(lambdaUse.filter(ImmutableList.of("Larry", "Alex"))).containsExactly("Larry");
    assertThat(
        isFinal(
            OuterReferenceLambda.class
                .getDeclaredMethod("lambda$filter$0$OuterReferenceLambda", String.class)
                .getModifiers()))
        .isTrue();
  }

  /**
   * Tests a lambda in a subclass whose generated lambda$ method has the same name and signature
   * as a lambda$ method generated by Javac in a superclass and both of these methods are used
   * in the implementation of the subclass (by calling super).  Naively this leads to wrong
   * behavior (in this case, return a non-empty list) because the lambda$ in the superclass is never
   * used once its made non-private during desugaring.
   */
  @Test
  public void testOuterReferenceLambdaInOverride() throws Exception {
    OuterReferenceLambda lambdaUse = new LambdaInOverride(ImmutableList.of("Sergey", "Larry"));
    assertThat(lambdaUse.filter(ImmutableList.of("Larry", "Alex"))).isEmpty();
    assertThat(
        isFinal(
            LambdaInOverride.class
                .getDeclaredMethod("lambda$filter$0$LambdaInOverride", String.class)
                .getModifiers()))
        .isTrue();
  }

  @Test
  public void testLambdaInAnonymousClassReferencesSurroundingMethodParameter() throws Exception {
    assertThat(Lambda.mult(21).apply(2).call()).isEqualTo(42);
  }

  /** Tests a lambda that accesses a method parameter across 2 nested anonymous classes. */
  @Test
  public void testLambdaInNestedAnonymousClass() throws Exception {
    InnerClassLambda lambdaUse = new InnerClassLambda(ImmutableList.of("Sergey", "Larry"));
    assertThat(lambdaUse.prefixFilter("L").apply(ImmutableList.of("Lois", "Larry")).call())
        .containsExactly("Larry");
  }

  @Test
  public void testClassMethodReference() {
    MethodReference methodrefUse = new MethodReference(ImmutableList.of("Sergey", "Larry", "Alex"));
    StringBuilder dest = new StringBuilder();
    methodrefUse.appendAll(dest);
    assertThat(dest.toString()).isEqualTo("SergeyLarryAlex");
  }

  // Regression test for b/33378312
  @Test
  public void testHiddenMethodReference() {
    MethodReference methodrefUse = new MethodReference(ImmutableList.of("Sergey", "Larry", "Alex"));
    assertThat(methodrefUse.intersect(ImmutableList.of("Alex", "Sundar"))).containsExactly("Alex");
  }

  // Regression test for b/33378312
  @Test
  public void testHiddenStaticMethodReference() {
    MethodReference methodrefUse =
        new MethodReference(ImmutableList.of("Sergey", "Larry", "Sundar"));
    assertThat(methodrefUse.some()).containsExactly("Sergey", "Sundar");
  }

  @Test
  public void testDuplicateHiddenMethodReference() {
    MethodReference methodrefUse = new MethodReference(ImmutableList.of("Sergey", "Larry", "Alex"));
    assertThat(methodrefUse.onlyIn(ImmutableList.of("Alex", "Sundar"))).containsExactly("Sundar");
  }

  // Regression test for b/36201257
  @Test
  public void testMethodReferenceThatNeedsBridgeInSubclass() {
    MethodReferenceInSubclass methodrefUse =
        new MethodReferenceInSubclass(ImmutableList.of("Sergey", "Larry", "Alex"));
    assertThat(methodrefUse.containsE()).containsExactly("Sergey", "Alex");
    assertThat(methodrefUse.startsWithL()).containsExactly("Larry");
    // Test sanity: make sure sub- and superclass have bridge methods with matching descriptors but
    // different names
    Method superclassBridge = findOnlyBridge(MethodReferenceSuperclass.class);
    Method subclassBridge = findOnlyBridge(MethodReferenceInSubclass.class);
    assertThat(superclassBridge.getName()).isNotEqualTo(subclassBridge.getName());
    assertThat(superclassBridge.getParameterTypes()).isEqualTo(subclassBridge.getParameterTypes());
  }

  private Method findOnlyBridge(Class<?> clazz) {
    Method result = null;
    for (Method m : clazz.getDeclaredMethods()) {
      if (m.getName().startsWith("bridge$")) {
        assertWithMessage(m.getName()).that(result).isNull();
        result = m;
      }
    }
    assertWithMessage(clazz.getSimpleName()).that(result).isNotNull();
    return result;
  }

  // Regression test for b/33378312
  @Test
  public void testThrowingPrivateMethodReference() throws Exception {
    MethodReference methodrefUse = new MethodReference(ImmutableList.of("Sergey", "Larry"));
    Callable<?> stringer = methodrefUse.stringer();
    try {
      stringer.call();
      fail("IOException expected");
    } catch (IOException expected) {
      assertThat(expected).hasMessageThat().isEqualTo("SergeyLarry");
    } catch (Exception e) {
      throw e;
    }
  }

  // Regression test for b/33304582
  @Test
  public void testInterfaceMethodReference() {
    MethodReference methodrefUse = new MethodReference(ImmutableList.of("Sergey", "Larry", "Alex"));
    MethodReference.Transformer<String> transform = new MethodReference.Transformer<String>() {
      @Override
      public String transform(String input) {
        return input.substring(1);
      }
    };
    assertThat(methodrefUse.transform(transform)).containsExactly("ergey", "arry", "lex");
  }

  @Test
  public void testConstructorReference() {
    ConstructorReference initRefUse = new ConstructorReference(ImmutableList.of("1", "2", "42"));
    assertThat(initRefUse.toInt()).containsExactly(1, 2, 42);
  }

  // Regression test for b/33304582
  @Test
  public void testPrivateConstructorReference() {
    ConstructorReference initRefUse = ConstructorReference.singleton().apply("17");
    assertThat(initRefUse.toInt()).containsExactly(17);
  }

  // This test is similar to testPrivateConstructorReference but the private constructor of an inner
  // class is used as a method reference.  That causes Javac to generate a bridge constructor and
  // a lambda body method that calls it, so the desugaring step doesn't need to do anything to make
  // the private constructor visible.  This is mostly to double-check that we don't interfere with
  // this "already-working" scenario.
  @Test
  public void testPrivateConstructorAccessedThroughJavacGeneratedBridge() {
    @SuppressWarnings("ReturnValueIgnored")
    RuntimeException expected =
        assertThrows(
            RuntimeException.class,
            () -> ConstructorReference.emptyThroughJavacGeneratedBridge().get());
    assertThat(expected).hasMessageThat().isEqualTo("got it!");
  }

  @Test
  public void testExpressionMethodReference() {
    assertThat(
            MethodReference.stringChars(new StringBuilder().append("Larry").append("Sergey"))
                .apply(5))
        .isEqualTo('S');
  }

  @Test
  public void testFieldMethodReference() {
    MethodReference methodrefUse = new MethodReference(ImmutableList.of("Sergey", "Larry", "Alex"));
    assertThat(methodrefUse.toPredicate().test("Larry")).isTrue();
    assertThat(methodrefUse.toPredicate().test("Sundar")).isFalse();
  }

  @Test
  public void testConcreteFunctionWithInheritedBridgeMethods() {
    assertThat(new ConcreteFunction().apply("1234567890987654321")).isEqualTo(1234567890987654321L);
    assertThat(ConcreteFunction.parseAll(ImmutableList.of("5", "17"), new ConcreteFunction()))
        .containsExactly(5L, 17L);
  }

  @Test
  public void testLambdaWithInheritedBridgeMethods() throws Exception {
    assertThat(ConcreteFunction.toInt().apply("123456789")).isEqualTo(123456789);
    assertThat(ConcreteFunction.parseAll(ImmutableList.of("5", "17"), ConcreteFunction.toInt()))
        .containsExactly(5, 17);
    // Expect String apply(Number) and any expected bridges
    assertThat(ConcreteFunction.toInt().getClass().getDeclaredMethods())
        .hasLength(expectedBridgesFromSameTarget + 1);
    // Sanity check that we only copied over methods, no fields, from the functional interface
    assertThrows(
        NoSuchFieldException.class,
        () ->
            ConcreteFunction.toInt()
                .getClass()
                .getDeclaredField("DO_NOT_COPY_INTO_LAMBDA_CLASSES"));
    assertThat(SpecializedFunction.class.getDeclaredField("DO_NOT_COPY_INTO_LAMBDA_CLASSES"))
        .isNotNull(); // test sanity
  }

  /** Tests lambdas with bridge methods when the implemented interface is in a separate target.*/
  @Test
  public void testLambdaWithBridgeMethodsForInterfaceInSeparateTarget() {
    assertThat(ConcreteFunction.isInt().test(123456789L)).isTrue();
    assertThat(
        ConcreteFunction.doFilter(
            ImmutableList.of(123456789L, 1234567890987654321L),
            ConcreteFunction.isInt()))
        .containsExactly(123456789L);
    // Expect test(Number) and any expected bridges
    assertThat(ConcreteFunction.isInt().getClass().getDeclaredMethods())
        .hasLength(expectedBridgesFromSeparateTarget + 1);
  }

  @Test
  public void testLambdaInInterfaceStaticInitializer() {
    assertThat(InterfaceWithLambda.DIGITS).containsExactly("0", "1").inOrder();
    // <clinit> doesn't count but if there's a lambda method then Jacoco adds more methods
    assertThat(InterfaceWithLambda.class.getDeclaredMethods().length != 0)
        .isEqualTo(expectLambdaMethodsInInterfaces);
  }

  /**
   * Sanity-checks that the resource file included in the original Jar is still there unchanged.
   */
  @Test
  public void testResourcePreserved() throws Exception {
    try (InputStream content = Lambda.class.getResource("testresource.txt").openStream()) {
      assertThat(new String(ByteStreams.toByteArray(content), UTF_8)).isEqualTo("test");
    }
  }

  /**
   * Test for b/62456849. After desugar, the method {@code lambda$mult$0} should still be in the
   * class.
   */
  @Test
  public void testCallMethodWithLambdaNamingConvention()
      throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
    Method method = Lambda.class.getDeclaredMethod("lambda$mult$0");
    Object value = method.invoke(null);
    assertThat(value).isInstanceOf(Integer.class);
    assertThat((Integer) value).isEqualTo(0);
  }
}
