text: // Copyright 2019 The Fuchsia Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #ifndef ZXTEST_CPP_ZXTEST_H_
  #define ZXTEST_CPP_ZXTEST_H_
  
  #include <cstdlib>
  #include <type_traits>
  
  #include <fbl/string.h>
  #include <fbl/string_printf.h>
  #include <zxtest/base/assertion.h>
  #include <zxtest/base/runner.h>
  #include <zxtest/base/test.h>
  #include <zxtest/cpp/internal.h>
  
  #ifdef __Fuchsia__
  #include <zircon/status.h>
  
  #include <zxtest/base/death-statement.h>
  #endif
  
  // Macro definitions for usage within CPP.
  #define RUN_ALL_TESTS(argc, argv) zxtest::RunAllTests(argc, argv)
  
  #define _ZXTEST_TEST_REF(TestCase, Test) TestCase##_##Test##_Ref
  
  #define _ZXTEST_DEFAULT_FIXTURE ::zxtest::Test
  
  #define _ZXTEST_TEST_CLASS(TestCase, Test) TestCase##_##Test##_Class
  
  #define _ZXTEST_TEST_CLASS_DECL(Fixture, TestClass) \
    class TestClass final : public Fixture {          \
     public:                                          \
      TestClass() = default;                          \
      ~TestClass() final = default;                   \
                                                      \
     private:                                         \
      void TestBody() final;                          \
    }
  
  #define _ZXTEST_BEGIN_TEST_BODY(TestClass) void TestClass::TestBody()
  
  #define _ZXTEST_REGISTER(TestCase, Test, Fixture)                                               \
    _ZXTEST_TEST_CLASS_DECL(Fixture, _ZXTEST_TEST_CLASS(TestCase, Test));                         \
    [[maybe_unused]] static zxtest::TestRef _ZXTEST_TEST_REF(TestCase, Test) =                    \
        zxtest::Runner::GetInstance()->RegisterTest<Fixture, _ZXTEST_TEST_CLASS(TestCase, Test)>( \
            #TestCase, #Test, __FILE__, __LINE__);                                                \
    _ZXTEST_BEGIN_TEST_BODY(_ZXTEST_TEST_CLASS(TestCase, Test))
  
  #define TEST(TestCase, Test) _ZXTEST_REGISTER(TestCase, Test, _ZXTEST_DEFAULT_FIXTURE)
  
  #define TEST_F(TestCase, Test) _ZXTEST_REGISTER(TestCase, Test, TestCase)
  
  #define _ZXTEST_NULLPTR nullptr
  
  #define _ZXTEST_ABORT_IF_ERROR zxtest::Runner::GetInstance()->CurrentTestHasFatalFailures()
  
  #define _ZXTEST_STRCMP(actual, expected) zxtest::StrCmp(actual, expected)
  
  #define _ZXTEST_AUTO_VAR_TYPE(var) decltype(var)
  
  #define _ZXTEST_TEST_HAS_ERRORS zxtest::Runner::GetInstance()->CurrentTestHasFailures()
  
  // Pre-processor magic to allow EXPECT_ macros not enforce a return type on helper functions.
  #define _RETURN_IF_FATAL_true     \
    do {                            \
      unittest_fails();             \
      if (_ZXTEST_ABORT_IF_ERROR) { \
        return;                     \
      }                             \
    } while (0)
  
  #define _RETURN_IF_FATAL_false \
    do {                         \
      unittest_fails();          \
    } while (0)
  
  #define _RETURN_IF_FATAL(fatal) _RETURN_IF_FATAL_##fatal
  
  // Definition of operations used to evaluate assertion conditions.
  #define _EQ(actual, expected) \
    zxtest::internal::Compare(actual, expected, [](const auto& a, const auto& b) { return a == b; })
  #define _NE(actual, expected) !_EQ(actual, expected)
  #define _BOOL(actual, expected) (static_cast<bool>(actual) == static_cast<bool>(expected))
  #define _LT(actual, expected) \
    zxtest::internal::Compare(actual, expected, [](const auto& a, const auto& b) { return a < b; })
  #define _LE(actual, expected) \
    zxtest::internal::Compare(actual, expected, [](const auto& a, const auto& b) { return a <= b; })
  #define _GT(actual, expected) \
    zxtest::internal::Compare(actual, expected, [](const auto& a, const auto& b) { return a > b; })
  #define _GE(actual, expected) \
    zxtest::internal::Compare(actual, expected, [](const auto& a, const auto& b) { return a >= b; })
  #define _STREQ(actual, expected) zxtest::StrCmp(actual, expected)
  #define _STRNE(actual, expected) !_STREQ(actual, expected)
  #define _SUBSTR(str, substr) zxtest::StrContain(str, substr)
  #define _BYTEEQ(actual, expected, size) \
    (memcmp(static_cast<const void*>(actual), static_cast<const void*>(expected), size) == 0)
  #define _BYTENE(actual, expected, size) !(_BYTEEQ(actual, expected, size))
  
  // Functions used as arguments for EvaluateCondition.
  #define _DESC_PROVIDER(desc, ...)                                    \
    [&]() -> fbl::String {                                             \
      fbl::String out_desc;                                            \
      auto format_msg = fbl::StringPrintf(" " __VA_ARGS__);            \
      out_desc = fbl::String::Concat({fbl::String(desc), format_msg}); \
      return out_desc;                                                 \
    }
  
  #define _COMPARE_FN(op) \
    [](const auto& expected_, const auto& actual_) { return op(expected_, actual_); }
  
  #define _COMPARE_3_FN(op, third_param)                        \
    [third_param](const auto& expected_, const auto& actual_) { \
      return op(expected_, actual_, third_param);               \
    }
  
  // Printers for converting values into readable strings.
  #define _DEFAULT_PRINTER [](const auto& val) { return zxtest::PrintValue(val); }
  
  #ifdef __Fuchsia__
  #define _STATUS_PRINTER [](zx_status_t status) { return zxtest::PrintStatus(status); }
  #else
  #define _STATUS_PRINTER _DEFAULT_PRINTER
  #endif
  
  #define _HEXDUMP_PRINTER(size)                                                 \
    [size](const auto& val) {                                                    \
      return zxtest::internal::ToHex(static_cast<const void*>(val), byte_count); \
    }
  
  // Basic assert macro implementation.
  #define _ASSERT_VAR(op, expected, actual, fatal, file, line, desc, ...)                          \
    do {                                                                                           \
      if (!zxtest::internal::EvaluateCondition(actual, expected, #actual, #expected,               \
                                               {.filename = file, .line_number = line}, fatal,     \
                                               _DESC_PROVIDER(desc, __VA_ARGS__), _COMPARE_FN(op), \
                                               _DEFAULT_PRINTER, _DEFAULT_PRINTER)) {              \
        _RETURN_IF_FATAL(fatal);                                                                   \
      }                                                                                            \
    } while (0)
  
  #define _ASSERT_VAR_STATUS(op, expected, actual, fatal, file, line, desc, ...)                    \
    do {                                                                                            \
      if (!zxtest::internal::EvaluateStatusCondition(                                               \
              actual, expected, #actual, #expected, {.filename = file, .line_number = line}, fatal, \
              _DESC_PROVIDER(desc, __VA_ARGS__), _COMPARE_FN(op), _STATUS_PRINTER,                  \
              _STATUS_PRINTER)) {                                                                   \
        _RETURN_IF_FATAL(fatal);                                                                    \
      }                                                                                             \
    } while (0)
  
  #define _ASSERT_VAR_COERCE(op, expected, actual, coerce_type, fatal, file, line, desc, ...)        \
    do {                                                                                             \
      auto buffer_compare = [&](const auto& expected_, const auto& actual_) {                        \
        using DecayType = typename std::decay<coerce_type>::type;                                    \
        return op(static_cast<const DecayType&>(actual_), static_cast<const DecayType&>(expected_)); \
      };                                                                                             \
      if (!zxtest::internal::EvaluateCondition(actual, expected, #actual, #expected,                 \
                                               {.filename = file, .line_number = line}, fatal,       \
                                               _DESC_PROVIDER(desc, __VA_ARGS__), buffer_compare,    \
                                               _DEFAULT_PRINTER, _DEFAULT_PRINTER)) {                \
        _RETURN_IF_FATAL(fatal);                                                                     \
      }                                                                                              \
    } while (0)
  
  #define _ASSERT_VAR_BYTES(op, expected, actual, size, fatal, file, line, desc, ...)              \
    do {                                                                                           \
      size_t byte_count = size;                                                                    \
      if (!zxtest::internal::EvaluateCondition(                                                    \
              zxtest::internal::ToPointer(actual), zxtest::internal::ToPointer(expected), #actual, \
              #expected, {.filename = file, .line_number = line}, fatal,                           \
              _DESC_PROVIDER(desc, __VA_ARGS__), _COMPARE_3_FN(op, byte_count),                    \
              _HEXDUMP_PRINTER(byte_count), _HEXDUMP_PRINTER(byte_count))) {                       \
        _RETURN_IF_FATAL(fatal);                                                                   \
      }                                                                                            \
    } while (0)
  
  #define _ZXTEST_FAIL_NO_RETURN(fatal, desc, ...)                                    \
    do {                                                                              \
      zxtest::Runner::GetInstance()->NotifyAssertion(                                 \
          zxtest::Assertion(_DESC_PROVIDER(desc, __VA_ARGS__)(),                      \
                            {.filename = __FILE__, .line_number = __LINE__}, fatal)); \
    } while (0)
  
  #define _ZXTEST_ASSERT_ERROR(has_errors, fatal, desc, ...) \
    do {                                                     \
      if (has_errors) {                                      \
        _ZXTEST_FAIL_NO_RETURN(fatal, desc, ##__VA_ARGS__);  \
        _RETURN_IF_FATAL(fatal);                             \
      }                                                      \
    } while (0)
  
  #define ZXTEST_SKIP(desc, ...)                                                                  \
    do {                                                                                          \
      zxtest::Runner::GetInstance()->SkipCurrent(zxtest::Message(                                 \
          _DESC_PROVIDER(desc, __VA_ARGS__)(), {.filename = __FILE__, .line_number = __LINE__})); \
      return;                                                                                     \
    } while (0)
  
  #ifdef __Fuchsia__
  #define _ZXTEST_DEATH_STATUS_COMPLETE zxtest::internal::DeathStatement::State::kSuccess
  #define _ZXTEST_DEATH_STATUS_EXCEPTION zxtest::internal::DeathStatement::State::kException
  #define _ZXTEST_DEATH_STATEMENT(statement, expected_result, desc, ...)                     \
    do {                                                                                     \
      zxtest::internal::DeathStatement death_statement(statement);                           \
      death_statement.Execute();                                                             \
      if (death_statement.state() != expected_result) {                                      \
        if (death_statement.state() == zxtest::internal::DeathStatement::State::kBadState) { \
          zxtest::Runner::GetInstance()->NotifyFatalError();                                 \
        }                                                                                    \
        if (!death_statement.error_message().empty()) {                                      \
          _ZXTEST_ASSERT_ERROR(true, true, death_statement.error_message().data());          \
        } else {                                                                             \
          _ZXTEST_ASSERT_ERROR(true, true, desc, ##__VA_ARGS__);                             \
        }                                                                                    \
      }                                                                                      \
    } while (0)
  #endif
  
  #endif  // ZXTEST_CPP_ZXTEST_H_
  