// Copyright (c) 2017, 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.checkdiscarded;

import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;

import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestDiagnosticMessages;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.NoneRuntime;
import com.android.tools.r8.checkdiscarded.testclasses.Main;
import com.android.tools.r8.checkdiscarded.testclasses.UnusedClass;
import com.android.tools.r8.checkdiscarded.testclasses.UsedClass;
import com.android.tools.r8.checkdiscarded.testclasses.WillBeGone;
import com.android.tools.r8.checkdiscarded.testclasses.WillStay;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.InternalOptions;
import java.util.List;
import java.util.function.Consumer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;

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

  @Parameters(name = "{0}, minify:{1}")
  public static List<Object[]> data() {
    return buildParameters(getTestParameters().withNoneRuntime().build(), BooleanUtils.values());
  }

  public final boolean minify;

  public CheckDiscardedTest(TestParameters parameters, boolean minify) {
    assertEquals(NoneRuntime.getInstance(), parameters.getRuntime());
    this.minify = minify;
  }

  private void compile(
      Class<?> annotation,
      boolean checkMembers,
      Consumer<TestDiagnosticMessages> onCompilationFailure) {
    R8FullTestBuilder builder = testForR8(Backend.DEX);
    TestDiagnosticMessages diagnostics = builder.getState().getDiagnosticsMessages();
    try {
      R8TestCompileResult result =
          builder
              .addProgramClasses(
                  UnusedClass.class, UsedClass.class, Main.class, WillBeGone.class, WillStay.class)
              .addKeepMainRule(Main.class)
              .addKeepRules(checkDiscardRule(checkMembers, annotation))
              .minification(minify)
              .addOptionsModification(this::noInlining)
              .compile();
      assertNull(onCompilationFailure);
      result.assertNoMessages();
    } catch (CompilationFailedException e) {
      onCompilationFailure.accept(diagnostics);
    }
  }

  private void noInlining(InternalOptions options) {
    options.inlinerOptions().enableInlining = false;
  }

  private String checkDiscardRule(boolean member, Class<?> annotation) {
    if (member) {
      return "-checkdiscard class * { @" + annotation.getName() + " *; }";
    } else {
      return "-checkdiscard @" + annotation.getName() + " class *";
    }
  }

  @Test
  public void classesAreGone() {
    compile(WillBeGone.class, false, null);
  }

  @Test
  public void classesAreNotGone() {
    Consumer<TestDiagnosticMessages> check =
        diagnostics ->
            diagnostics
                .assertNoInfos()
                .assertNoWarnings()
                .assertErrorsMatch(
                    diagnosticMessage(
                        allOf(
                            containsString("Discard checks failed"),
                            containsString("UsedClass was not discarded"),
                            containsString("is instantiated in"),
                            containsString("Main was not discarded"),
                            containsString("is referenced in keep rule"))));
    compile(WillStay.class, false, check);
  }

  @Test
  public void membersAreGone() {
    compile(WillBeGone.class, true, null);
  }

  @Test
  public void membersAreNotGone() {
    Consumer<TestDiagnosticMessages> check =
        diagnostics ->
            diagnostics
                .assertNoInfos()
                .assertNoWarnings()
                .assertErrorsMatch(
                    diagnosticMessage(
                        allOf(
                            containsString("Discard checks failed"),
                            containsString("was not discarded"),
                            containsString("is invoked from"))));
    compile(WillStay.class, true, check);
  }
}
