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

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.NeverInline;
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.graph.DexMethod;
import com.android.tools.r8.utils.InternalOptions;
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 org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

class NameThenLengthTestClass {

  private static final String NAME;
  private static final int LENGTH;
  private static final int NAME_LENGTH;

  static {
    NAME = NameThenLengthTestClass.class.getSimpleName();
    LENGTH = "NameThenLengthTestClass".length();
    NAME_LENGTH = NameThenLengthTestClass.class.getSimpleName().length();
  }

  public static void main(String... args) {
    System.out.println(NAME);
    System.out.println(LENGTH);
    System.out.println(NAME_LENGTH);

    new NameThenLengthTestClass().instanceMethod();
  }

  @NeverInline
  void instanceMethod() {
    // Note that the computed constants will be canonicalized.
    System.out.println(NameThenLengthTestClass.class.getSimpleName());
    System.out.println("NameThenLengthTestClass".length());
    System.out.println(NameThenLengthTestClass.class.getSimpleName().length());
  }
}

@RunWith(Parameterized.class)
public class NameThenLengthTest extends TestBase {
  private static final String JAVA_OUTPUT = StringUtils.lines(
      "NameThenLengthTestClass",
      "23",
      "23",
      "NameThenLengthTestClass",
      "23",
      "23"
  );
  private static final Class<?> MAIN = NameThenLengthTestClass.class;

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

  private final TestParameters parameters;

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

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

  private static boolean isStringLength(DexMethod method) {
    return method.toSourceString().equals("int java.lang.String.length()");
  }

  private long countStringLength(MethodSubject method) {
    return Streams.stream(method.iterateInstructions(instructionSubject -> {
      if (instructionSubject.isInvoke()) {
        return isStringLength(instructionSubject.getMethod());
      }
      return false;
    })).count();
  }

  private long countNonZeroConstNumber(MethodSubject method) {
    return Streams.stream(method.iterateInstructions(InstructionSubject::isConstNumber)).count()
        - Streams.stream(method.iterateInstructions(instr -> instr.isConstNumber(0))).count();
  }

  private void test(
      TestRunResult result,
      int expectedStringLengthCountInClinit,
      int expectedConstNumberCountInClinit,
      int expectedStringLengthCountInInstanceMethod,
      int expectedConstNumberCountInInstanceMethod)
      throws Exception {
    CodeInspector codeInspector = result.inspector();
    ClassSubject mainClass = codeInspector.clazz(MAIN);

    MethodSubject clinit = mainClass.clinit();
    assertThat(clinit, isPresent());
    assertEquals(expectedStringLengthCountInClinit, countStringLength(clinit));
    assertEquals(expectedConstNumberCountInClinit, countNonZeroConstNumber(clinit));

    MethodSubject m = mainClass.uniqueMethodWithName("instanceMethod");
    assertThat(m, isPresent());
    assertEquals(expectedStringLengthCountInInstanceMethod, countStringLength(m));
    assertEquals(expectedConstNumberCountInInstanceMethod, countNonZeroConstNumber(m));
  }

  void configure(InternalOptions options) {
    options.testing.forceNameReflectionOptimization = true;
  }

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

    D8TestRunResult result =
        testForD8()
            .debug()
            .addProgramClasses(MAIN)
            .addOptionsModification(this::configure)
            .setMinApi(parameters.getRuntime())
            .run(parameters.getRuntime(), MAIN)
            .assertSuccessWithOutput(JAVA_OUTPUT);
    test(result, 2, 0, 2, 0);

    result =
        testForD8()
            .release()
            .addProgramClasses(MAIN)
            .addOptionsModification(this::configure)
            .setMinApi(parameters.getRuntime())
            .run(parameters.getRuntime(), MAIN)
            .assertSuccessWithOutput(JAVA_OUTPUT);
    // TODO(b/125303292): NAME_LENGTH is still not computed at compile time.
    test(result, 1, 0, 0, 1);
  }

  @Test
  public void testR8() throws Exception {
    R8TestRunResult result =
        testForR8(parameters.getBackend())
            .addProgramClasses(MAIN)
            .enableInliningAnnotations()
            .addKeepMainRule(MAIN)
            .noMinification()
            .addOptionsModification(this::configure)
            .setMinApi(parameters.getRuntime())
            .run(parameters.getRuntime(), MAIN)
            .assertSuccessWithOutput(JAVA_OUTPUT);
    // No canonicalization in CF.
    int expectedConstNumber = parameters.isCfRuntime() ? 2 : 1;
    // TODO(b/125303292): NAME_LENGTH is still not computed at compile time.
    test(result, 1, 0, 0, expectedConstNumber);
  }
}
