// Copyright (c) 2019, 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.ir.optimize;

import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue;

import com.android.tools.r8.D8TestRunResult;
import com.android.tools.r8.DexIndexedConsumer.ArchiveConsumer;
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRunResult;
import com.android.tools.r8.ir.optimize.ConstClassMain.Outer;
import com.android.tools.r8.ir.optimize.ConstClassMain.Outer.Inner;
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.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.Streams;
import java.nio.file.Path;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

class IncrementalA {
}

class IncrementalMain {
  public static void main(String... args) {
    System.out.println(IncrementalA.class.getSimpleName());
    System.out.println(IncrementalA.class.getSimpleName());
    System.out.println(IncrementalA.class.getSimpleName());
  }
}

class ConstClassMain {

  static class Outer {
    Outer() {
      System.out.println("Outer::<init>");
    }

    static class Inner {
      Inner() {
        System.out.println("Inner::<init>");
      }
    }
  }

  public static void main(String... args) {
    Class outer = Inner.class.getDeclaringClass();
    System.out.println(outer.getSimpleName());
    for (Class<?> inner : outer.getDeclaredClasses()) {
      System.out.println(inner.getSimpleName());
    }
    System.out.println(ConstClassMain.class.getSimpleName());
    System.out.println(Outer.class.getSimpleName());
    System.out.println(Inner.class.getSimpleName());
    System.out.println(ConstClassMain.class.getSimpleName().length());
    System.out.println(Outer.class.getSimpleName().length());
    System.out.println(Inner.class.getSimpleName().length());
  }
}

@RunWith(Parameterized.class)
public class ConstClassCanonicalizationTest extends TestBase {
  private static final String INCREMENTAL_OUTPUT = StringUtils.lines(
      "IncrementalA",
      "IncrementalA",
      "IncrementalA"
  );

  private static final Class<?> MAIN = ConstClassMain.class;
  private static final String JAVA_OUTPUT = StringUtils.lines(
      "Outer",
      "Inner",
      "ConstClassMain",
      "Outer",
      "Inner",
      "14",
      "5",
      "5"
  );
  private static final int ORIGINAL_MAIN_COUNT = 2;
  private static final int ORIGINAL_OUTER_COUNT = 2;
  private static final int ORIGINAL_INNER_COUNT = 3;
  private static final int CANONICALIZED_MAIN_COUNT = 1;
  private static final int CANONICALIZED_OUTER_COUNT = 1;
  private static final int CANONICALIZED_INNER_COUNT = 1;

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

  private final TestParameters parameters;

  public ConstClassCanonicalizationTest(TestParameters parameters) {
    this.parameters = parameters;
  }

  @Test
  public void testJVMOutput() throws Exception {
    assumeTrue(
        "Only run JVM reference once (for CF backend)",
        parameters.getBackend() == Backend.CF);
    testForJvm()
        .addTestClasspath()
        .run(parameters.getRuntime(), MAIN)
        .assertSuccessWithOutput(JAVA_OUTPUT);
  }

  @Test
  public void testD8_incremental() throws Exception {
    assumeTrue("Only run D8 for Dex backend", parameters.getBackend() == Backend.DEX);

    Path zipA = temp.newFile("a.zip").toPath().toAbsolutePath();
    testForD8()
        .release()
        .addProgramClasses(IncrementalA.class)
        .setMinApi(parameters.getRuntime())
        .setProgramConsumer(new ArchiveConsumer(zipA))
        .compile();
    testForD8()
        .release()
        .addProgramClasses(IncrementalMain.class)
        .setMinApi(parameters.getRuntime())
        .compile()
        .addRunClasspathFiles(zipA)
        .run(parameters.getRuntime(), IncrementalMain.class)
        .assertSuccessWithOutput(INCREMENTAL_OUTPUT)
        .inspect(inspector -> {
          ClassSubject main = inspector.clazz(IncrementalMain.class);
          assertThat(main, isPresent());
          MethodSubject mainMethod = main.mainMethod();
          assertThat(mainMethod, isPresent());
          assertEquals(
              3,
              Streams.stream(
                  mainMethod.iterateInstructions(InstructionSubject::isConstClass))
              .count());
        });
  }

  private void test(
      TestRunResult result, int mainCount, int outerCount, int innerCount) throws Exception {
    CodeInspector codeInspector = result.inspector();
    ClassSubject mainClass = codeInspector.clazz(MAIN);
    MethodSubject mainMethod = mainClass.mainMethod();
    assertThat(mainMethod, isPresent());
    assertEquals(
        mainCount,
        Streams.stream(
            mainMethod.iterateInstructions(i -> i.isConstClass(MAIN.getTypeName())))
            .count());
    assertEquals(
        outerCount,
        Streams.stream(
            mainMethod.iterateInstructions(i -> i.isConstClass(Outer.class.getTypeName())))
            .count());
    assertEquals(
        innerCount,
        Streams.stream(
            mainMethod.iterateInstructions(i -> i.isConstClass(Inner.class.getTypeName())))
            .count());
  }

  @Test
  public void testD8() throws Exception {
    assumeTrue("Only run D8 for Dex backend", parameters.getBackend() == Backend.DEX);

    D8TestRunResult result =
        testForD8()
            .debug()
            .addProgramClassesAndInnerClasses(MAIN)
            .setMinApi(parameters.getRuntime())
            .run(parameters.getRuntime(), MAIN)
            .assertSuccessWithOutput(JAVA_OUTPUT);
    test(result, CANONICALIZED_MAIN_COUNT, ORIGINAL_OUTER_COUNT, ORIGINAL_INNER_COUNT);

    result =
        testForD8()
            .release()
            .addProgramClassesAndInnerClasses(MAIN)
            .setMinApi(parameters.getRuntime())
            .run(parameters.getRuntime(), MAIN)
            .assertSuccessWithOutput(JAVA_OUTPUT);
    test(result, CANONICALIZED_MAIN_COUNT, ORIGINAL_OUTER_COUNT, ORIGINAL_INNER_COUNT);
  }

  @Test
  public void testR8() throws Exception {
    R8TestRunResult result =
        testForR8(parameters.getBackend())
            .addProgramClassesAndInnerClasses(MAIN)
            .addKeepMainRule(MAIN)
            .addKeepAllAttributes()
            .noMinification()
            .setMinApi(parameters.getRuntime())
            .run(parameters.getRuntime(), MAIN)
            .assertSuccessWithOutput(JAVA_OUTPUT);
    // The number of expected const-class instructions differs because constant canonicalization is
    // only enabled for the DEX backend.
    int expectedMainCount =
        parameters.getBackend() == Backend.CF ? ORIGINAL_MAIN_COUNT : CANONICALIZED_MAIN_COUNT;
    int expectedOuterCount =
        parameters.getBackend() == Backend.CF ? ORIGINAL_OUTER_COUNT : CANONICALIZED_OUTER_COUNT;
    int expectedInnerCount =
        parameters.getBackend() == Backend.CF ? ORIGINAL_INNER_COUNT : CANONICALIZED_INNER_COUNT;
    test(result, expectedMainCount, expectedOuterCount, expectedInnerCount);
  }

}
