// Copyright (c) 2021, 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 twr.twrcloseresourceduplication;

import static com.android.tools.r8.synthesis.SyntheticItemsTestUtils.getMinimalSyntheticItemsTestUtils;
import static org.junit.Assert.assertEquals;

import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.ZipUtils;
import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
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 twr.twrcloseresourceduplication.asm.TwrCloseResourceDuplication$BarDump;
import twr.twrcloseresourceduplication.asm.TwrCloseResourceDuplication$FooDump;
import twr.twrcloseresourceduplication.asm.TwrCloseResourceDuplicationDump;

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

  protected static final String MAIN =
      "twr.twrcloseresourceduplication.TwrCloseResourceDuplication";
  protected static final String FOO =
      "twr.twrcloseresourceduplication.TwrCloseResourceDuplication$Foo";
  protected static final String BAR =
      "twr.twrcloseresourceduplication.TwrCloseResourceDuplication$Bar";

  static final int INPUT_CLASSES = 3;

  protected static final String EXPECTED =
      StringUtils.lines(
          "foo opened 1",
          "foo post close 1",
          "foo opened 2",
          "foo caught from 2: RuntimeException",
          "foo post close 2",
          "bar opened 1",
          "bar post close 1",
          "bar opened 2",
          "bar caught from 2: RuntimeException",
          "bar post close 2");

  @Parameter(0)
  public TestParameters parameters;

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

  protected boolean hasTwrCloseResourceSupport(boolean isDesugaring) {
    return !isDesugaring
        || parameters.getApiLevel().isGreaterThanOrEqualTo(apiLevelWithTwrCloseResourceSupport());
  }

  protected boolean hasTwrCloseResourceApiOutlines() {
    return parameters.isDexRuntime()
        && parameters.getApiLevel().isLessThan(apiLevelWithTwrCloseResourceSupport());
  }

  protected String getZipFile() throws IOException {
    return ZipUtils.ZipBuilder.builder(temp.newFile("file.zip").toPath())
        // DEX VMs from 4.4 up-to 9.0 including, will fail if no entry is added.
        .addBytes("entry", new byte[1])
        .build()
        .toString();
  }

  protected static List<byte[]> getProgramInputs() throws Exception {
    return ImmutableList.of(
        TwrCloseResourceDuplicationDump.dump(),
        TwrCloseResourceDuplication$FooDump.dump(),
        TwrCloseResourceDuplication$BarDump.dump());
  }

  @Test
  public void testJvm() throws Exception {
    parameters.assumeJvmTestParameters();
    testForJvm(parameters)
        .addProgramClassFileData(getProgramInputs())
        .run(parameters.getRuntime(), MAIN, getZipFile())
        .assertSuccessWithOutput(EXPECTED);
  }

  @Test
  public void testD8() throws Exception {
    testForD8(parameters.getBackend())
        .addProgramClassFileData(getProgramInputs())
        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.LATEST))
        .setMinApi(parameters)
        .run(parameters.getRuntime(), MAIN, getZipFile())
        .assertSuccessWithOutput(EXPECTED)
        .inspect(
            inspector -> {
              // NOTE: The $closeResource helper is _only_ generated by the JDK-9 compiler.
              //
              // There should be two synthetic classes besides the three program classes.
              // One for the desugar version of TWR $closeResource and one for the
              // Throwable.addSuppressed that is still present in the original $closeResource.
              // TODO(b/214329923): If the original $closeResource is pruned this will decrease.
              // TODO(b/168568827): Once we support a nested addSuppressed this will increase.
              int expectedSynthetics = 0;
              if (!hasTwrCloseResourceSupport(true)) {
                expectedSynthetics += 2;
              }
              if (hasTwrCloseResourceApiOutlines()) {
                expectedSynthetics += 1;
              }
              InternalOptions options = inspector.getApplication().options;
              options.setMinApiLevel(parameters.getApiLevel());
              if (options.shouldDesugarAutoCloseable()) {
                expectedSynthetics += 3;
              }
              assertEquals(INPUT_CLASSES + expectedSynthetics, inspector.allClasses().size());
            });
  }

  @Test
  public void testR8() throws Exception {
    parameters.assumeDexRuntime();
    testForR8(parameters.getBackend())
        .addProgramClassFileData(getProgramInputs())
        .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.LATEST))
        .addKeepMainRule(MAIN)
        .addKeepClassAndMembersRules(FOO, BAR)
        .addOptionsModification(
            options -> options.desugarSpecificOptions().minimizeSyntheticNames = true)
        .setMinApi(parameters)
        .addDontObfuscate()
        .run(parameters.getRuntime(), MAIN, getZipFile())
        .assertSuccessWithOutput(EXPECTED)
        .inspect(
            inspector -> {
              List<FoundClassSubject> foundClassSubjects = inspector.allClasses();
              Set<String> foundClasses =
                  foundClassSubjects.stream()
                      .map(FoundClassSubject::getFinalName)
                      .collect(Collectors.toSet());
              // R8 will optimize the generated methods for the two cases below where the thrown
              // exception is known or not, thus the synthetic methods will be 2.
              Set<String> nonSyntheticClassOutput = ImmutableSet.of(FOO, BAR, MAIN);
              if (!hasTwrCloseResourceSupport(parameters.isDexRuntime())) {
                Set<String> classOutputWithSynthetics = new HashSet<>(nonSyntheticClassOutput);
                classOutputWithSynthetics.add(
                    getMinimalSyntheticItemsTestUtils()
                        .syntheticApiOutlineClass(Reference.classFromTypeName(BAR), 0)
                        .getTypeName());
                assertEquals(classOutputWithSynthetics, foundClasses);
              } else {
                Set<String> classOutputWithSynthetics = new HashSet<>(nonSyntheticClassOutput);
                if (parameters.getApiLevel().isLessThan(AndroidApiLevel.N)) {
                  // Above N, the forwarder is inlined in the dispatcher.
                  classOutputWithSynthetics.add(
                      getMinimalSyntheticItemsTestUtils()
                          .syntheticAutoCloseableForwarderClass(Reference.classFromTypeName(BAR), 1)
                          .getTypeName());
                }
                if (!parameters.corelibWithExecutorServiceImplementingAutoClosable()) {
                  classOutputWithSynthetics.add(
                      getMinimalSyntheticItemsTestUtils()
                          .syntheticAutoCloseableDispatcherClass(
                              Reference.classFromTypeName(BAR), 0)
                          .getTypeName());
                }
                assertEquals(classOutputWithSynthetics, foundClasses);
              }
            });
  }
}
