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

import static com.android.tools.r8.DiagnosticsMatcher.diagnosticException;
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticOrigin;
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.anyOf;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.fail;

import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.D8TestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ThrowableConsumer;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.StringUtils;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.concurrent.atomic.AtomicBoolean;
import org.hamcrest.Matcher;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;

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

  static final String EXPECTED = StringUtils.lines("Hello, world");

  static final Origin ORIGIN =
      new Origin(Origin.root()) {
        @Override
        public String part() {
          return "<test-origin>";
        }
      };

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

  public ErrorDuringIrConversionTest(TestParameters parameters) {}

  private ThrowableConsumer<D8TestBuilder> addTestClassWithOrigin() {
    return b ->
        b.getBuilder().addClassProgramData(ToolHelper.getClassAsBytes(TestClass.class), ORIGIN);
  }

  private void checkCompilationFailedException(
      CompilationFailedException e, Matcher<String> messageMatcher, Matcher<String> stackMatcher) {
    // Check that the failure exception exiting the compiler contains origin info in the message.
    assertThat(e.getMessage(), messageMatcher);
    // Check that the stack trace has the version marker.
    StringWriter writer = new StringWriter();
    e.printStackTrace(new PrintWriter(writer));
    assertThat(writer.toString(), stackMatcher);
  }

  private static void throwNPE() {
    throw new NullPointerException("A test NPE");
  }

  @Test
  public void testNPE() throws Exception {
    try {
      testForD8()
          .apply(addTestClassWithOrigin())
          .addOptionsModification(options -> options.testing.hookInIrConversion = () -> throwNPE())
          .compileWithExpectedDiagnostics(
              diagnostics -> {
                // Check that the error is reported as an error to the diagnostics handler.
                diagnostics
                    .assertOnlyErrors()
                    .assertErrorsMatch(
                        allOf(
                            diagnosticOrigin(ORIGIN),
                            diagnosticException(NullPointerException.class),
                            diagnosticMessage(containsString("A test NPE"))));
              });
    } catch (CompilationFailedException e) {
      checkCompilationFailedException(
          e,
          containsString(ORIGIN.toString()),
          allOf(containsString("fakeStackEntry"), containsString("throwNPE")));
      return;
    }
    fail("Expected compilation to fail");
  }

  @Test
  public void testFatalError() throws Exception {
    try {
      testForD8()
          .apply(addTestClassWithOrigin())
          .addOptionsModification(
              options ->
                  options.testing.hookInIrConversion =
                      () -> options.reporter.fatalError("My Fatal Error!"))
          .compileWithExpectedDiagnostics(
              diagnostics -> {
                // Check that the error is reported as an error to the diagnostics handler.
                diagnostics.assertOnlyErrors();
                diagnostics.assertErrorsMatch(
                    allOf(
                        diagnosticType(StringDiagnostic.class),
                        diagnosticMessage(containsString("My Fatal Error")),
                        // The fatal error is not given an origin, so it can't provide it.
                        // Note: This could be fixed by delaying reporting and associate the info
                        //  at the top-level handler. It would require mangling of the diagnostic,
                        //  so maybe not that elegant.
                        diagnosticOrigin(Origin.unknown())));
              });
    } catch (CompilationFailedException e) {
      checkCompilationFailedException(
          e, containsString(ORIGIN.toString()), containsString("fakeStackEntry"));
      return;
    }
    fail("Expected compilation to fail");
  }

  private static void reportErrors(Reporter reporter) {
    reporter.error("FOO!");
    reporter.error("BAR!");
    reporter.error("BAZ!");
  }

  @Test
  public void testThreeErrors() throws Exception {
    AtomicBoolean doError = new AtomicBoolean(true);
    try {
      testForD8()
          .apply(addTestClassWithOrigin())
          .addOptionsModification(
              options ->
                  options.testing.hookInIrConversion =
                      () -> {
                        // Ensure that the errors are reported just once as IR conversion is
                        // threaded.
                        if (doError.getAndSet(false)) {
                          reportErrors(options.reporter);
                        }
                      })
          .compileWithExpectedDiagnostics(
              diagnostics -> {
                // Check that the error is reported as an error to the diagnostics handler.
                diagnostics
                    .assertOnlyErrors()
                    .assertErrorsCount(3)
                    .assertAllErrorsMatch(
                        allOf(
                            diagnosticOrigin(Origin.unknown()),
                            diagnosticType(StringDiagnostic.class),
                            diagnosticMessage(
                                anyOf(
                                    containsString("FOO!"),
                                    containsString("BAR!"),
                                    containsString("BAZ!")))));
              });
    } catch (CompilationFailedException e) {
      checkCompilationFailedException(
          e,
          // There may be no fail-if-error barrier inside any origin association, thus only the
          // top level message can be expected here.
          containsString("Compilation failed to complete"),
          // The stack trace must contain both the version, the frame for the hook above, and one
          // of the error messages.
          allOf(
              containsString("fakeStackEntry"),
              containsString("reportErrors"),
              anyOf(containsString("FOO!"), containsString("BAR!"), containsString("BAZ!"))));
      return;
    }
    fail("Expected compilation to fail");
  }

  static class TestClass {

    public static void main(String[] args) {
      System.out.println("Hello, world");
    }
  }
}
