#include "doctest/parts/private/prelude.h"
#include "doctest/parts/private/reporter.h"
#include "doctest/parts/private/exception_translator.h"
#include "doctest/parts/private/assert/handler.h"

DOCTEST_SUPPRESS_PRIVATE_WARNINGS_PUSH

#ifndef DOCTEST_CONFIG_DISABLE

namespace doctest {
namespace detail {

Result::Result(bool passed, const String &decomposition)
    : m_passed(passed), m_decomp(decomposition) {}

ResultBuilder::ResultBuilder(
    assertType::Enum at,
    const char *file,
    int line,
    const char *expr,
    const char *exception_type,
    const String &exception_string
)
    : AssertData(at, file, line, expr, exception_type, exception_string) {
} // NOLINT(clang-analyzer-cplusplus.NewDeleteLeaks)

ResultBuilder::ResultBuilder(
    assertType::Enum at,
    const char *file,
    int line,
    const char *expr,
    const char *exception_type,
    const Contains &exception_string
)
    : AssertData(at, file, line, expr, exception_type, exception_string) {}

void ResultBuilder::setResult(const Result &res) {
    m_decomp = res.m_decomp;
    m_failed = !res.m_passed;
}

void ResultBuilder::translateException() {
    m_threw = true;
    m_exception = translateActiveException();
}

bool ResultBuilder::log() {
    if (m_at & assertType::is_throws) {
        m_failed = !m_threw;
    } else if ((m_at & assertType::is_throws_as) && (m_at & assertType::is_throws_with)) {
        m_failed = !m_threw_as || !m_exception_string.check(m_exception);
    } else if (m_at & assertType::is_throws_as) {
        m_failed = !m_threw_as;
    } else if (m_at & assertType::is_throws_with) {
        m_failed = !m_exception_string.check(m_exception);
    } else if (m_at & assertType::is_nothrow) {
        m_failed = m_threw;
    }

    if (m_exception.size())
        m_exception = "\"" + m_exception + "\"";

    if (is_running_in_test) {
        addAssert(m_at);
        DOCTEST_ITERATE_THROUGH_REPORTERS(log_assert, *this);

        if (m_failed)
            addFailedAssert(m_at);
    } else if (m_failed) {
        failed_out_of_a_testing_context(*this);
    }

    return m_failed && isDebuggerActive() && !getContextOptions()->no_breaks &&
           (g_cs->currentTest == nullptr || !g_cs->currentTest->m_no_breaks); // break into debugger
}

void ResultBuilder::react() const {
    if (m_failed && checkIfShouldThrow(m_at))
        throwException();
}

} // namespace detail
} // namespace doctest

#endif // DOCTEST_CONFIG_DISABLE

DOCTEST_SUPPRESS_PRIVATE_WARNINGS_POP
