broken.h 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. // [Broken]
  2. // Lightweight Unit Testing for C++.
  3. //
  4. // [License]
  5. // Public Domain (Unlicense) or Zlib.
  6. #ifndef BROKEN_INTERNAL_H
  7. #define BROKEN_INTERNAL_H
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <utility>
  12. // Hide everything when using Doxygen. Ideally this can be protected by a macro,
  13. // but there is not globally and widely used one across multiple projects.
  14. //! \cond
  15. // ============================================================================
  16. // [Broken - API]
  17. // ============================================================================
  18. struct BrokenAPI {
  19. //! Entry point of a unit test defined by `UNIT` macro.
  20. typedef void (*Entry)(void);
  21. enum Flags : unsigned {
  22. kFlagFinished = 0x1
  23. };
  24. //! Test defined by `UNIT` macro.
  25. struct Unit {
  26. Entry entry;
  27. const char* name;
  28. int priority;
  29. unsigned flags;
  30. Unit* next;
  31. };
  32. //! Automatic unit registration by using static initialization.
  33. struct AutoUnit : Unit {
  34. inline AutoUnit(Entry entry_, const char* name_, int priority_ = 0, int dummy_ = 0) noexcept {
  35. // Not used, only to trick `UNIT()` macro.
  36. (void)dummy_;
  37. this->entry = entry_;
  38. this->name = name_;
  39. this->priority = priority_;
  40. this->flags = 0;
  41. this->next = nullptr;
  42. BrokenAPI::add(this);
  43. }
  44. };
  45. static bool hasArg(const char* name) noexcept;
  46. //! Register a new unit test (called automatically by `AutoUnit` and `UNIT`).
  47. static void add(Unit* unit) noexcept;
  48. //! Set output file to a `file`.
  49. static void setOutputFile(FILE* file) noexcept;
  50. //! Initialize `Broken` framework.
  51. //!
  52. //! Returns `true` if `run()` should be called.
  53. static int run(int argc, const char* argv[], Entry onBeforeRun = nullptr, Entry onAfterRun = nullptr);
  54. //! Log message, adds automatically new line if not present.
  55. static void info(const char* fmt, ...) noexcept;
  56. //! Called on `EXPECT()` failure.
  57. static void fail(const char* file, int line, const char* expression, const char* fmt, ...) noexcept;
  58. //! Used internally by `EXPECT` macro.
  59. template<typename T>
  60. static inline void expect(const char* file, int line, const char* expression, const T& result) noexcept {
  61. if (!result)
  62. fail(file, line, expression, nullptr);
  63. }
  64. //! Used internally by `EXPECT` macro.
  65. template<typename T, typename... Args>
  66. static inline void expect(const char* file, int line, const char* expression, const T& result, const char* fmt, Args&&... args) noexcept {
  67. if (!result)
  68. fail(file, line, expression, fmt, std::forward<Args>(args)...);
  69. }
  70. };
  71. // ============================================================================
  72. // [Broken - Macros]
  73. // ============================================================================
  74. //! Internal macro used by `UNIT()`.
  75. #define BROKEN_UNIT_INTERNAL(NAME, PRIORITY) \
  76. static void unit_##NAME##_entry(void); \
  77. static ::BrokenAPI::AutoUnit unit_##NAME##_autoinit(unit_##NAME##_entry, #NAME, PRIORITY); \
  78. static void unit_##NAME##_entry(void)
  79. //! Stringifies the expression used by EXPECT().
  80. #define BROKEN_STRINFIGY_EXPRESSION_INTERNAL(EXP, ...) #EXP
  81. //! \def UNIT(NAME [, PRIORITY])
  82. //!
  83. //! Define a unit test with an optional priority.
  84. //!
  85. //! `NAME` can only contain ASCII characters, numbers and underscore. It has
  86. //! the same rules as identifiers in C and C++.
  87. //!
  88. //! `PRIORITY` specifies the order in which unit tests are run. Lesses value
  89. //! increases the priority. At the moment all units are first sorted by
  90. //! priority and then by name - this makes the run always deterministic.
  91. #define UNIT(NAME, ...) BROKEN_UNIT_INTERNAL(NAME, __VA_ARGS__ + 0)
  92. //! #define INFO(FORMAT [, ...])
  93. //!
  94. //! Informative message printed to `stdout`.
  95. #define INFO(...) ::BrokenAPI::info(__VA_ARGS__)
  96. //! #define INFO(EXP [, FORMAT [, ...]])
  97. //!
  98. //! Expect `EXP` to be true or evaluates to true, fail otherwise.
  99. #define EXPECT(...) ::BrokenAPI::expect(__FILE__, __LINE__, BROKEN_STRINFIGY_EXPRESSION_INTERNAL(__VA_ARGS__), __VA_ARGS__)
  100. //! \endcond
  101. #endif // BROKEN_INTERNAL_H