odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

broken.h (7577B)


      1 // Broken - Lightweight unit testing for C++
      2 //
      3 // This is free and unencumbered software released into the public domain.
      4 //
      5 // Anyone is free to copy, modify, publish, use, compile, sell, or
      6 // distribute this software, either in source code form or as a compiled
      7 // binary, for any purpose, commercial or non-commercial, and by any
      8 // means.
      9 //
     10 // In jurisdictions that recognize copyright laws, the author or authors
     11 // of this software dedicate any and all copyright interest in the
     12 // software to the public domain. We make this dedication for the benefit
     13 // of the public at large and to the detriment of our heirs and
     14 // successors. We intend this dedication to be an overt act of
     15 // relinquishment in perpetuity of all present and future rights to this
     16 // software under copyright law.
     17 //
     18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     19 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     20 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     21 // IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
     22 // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     23 // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     24 // OTHER DEALINGS IN THE SOFTWARE.
     25 //
     26 // For more information, please refer to <http://unlicense.org>
     27 
     28 #ifndef BROKEN_H_INCLUDED
     29 #define BROKEN_H_INCLUDED
     30 
     31 #include <stdio.h>
     32 #include <stdlib.h>
     33 #include <string.h>
     34 #include <utility>
     35 
     36 // Hide everything when using Doxygen. Ideally this can be protected by a macro,
     37 // but there is not globally and widely used one across multiple projects.
     38 
     39 //! \cond
     40 
     41 // Broken - API
     42 // ============
     43 
     44 namespace BrokenAPI {
     45 
     46 //! Entry point of a unit test defined by `UNIT` macro.
     47 typedef void (*Entry)(void);
     48 
     49 enum Flags : unsigned {
     50   kFlagFinished = 0x1
     51 };
     52 
     53 struct Unit;
     54 
     55 bool has_arg(const char* name) noexcept;
     56 
     57 //! Register a new unit test (called automatically by `AutoUnit` and `UNIT`).
     58 void add_unit(Unit* unit) noexcept;
     59 
     60 //! Set output file to a `file`.
     61 void set_output_file(FILE* file) noexcept;
     62 
     63 //! Initialize `Broken` framework.
     64 //!
     65 //! Returns `true` if `run()` should be called.
     66 int run(int argc, const char* argv[], Entry on_before_run = nullptr, Entry on_after_run = nullptr);
     67 
     68 //! Log message, adds automatically new line if not present.
     69 void info(const char* fmt, ...) noexcept;
     70 
     71 //! Called on `EXPECT()` failure.
     72 void fail(const char* file, int line, const char* expression, const char* fmt, ...) noexcept;
     73 
     74 //! Test defined by `UNIT` macro.
     75 struct Unit {
     76   Entry entry;
     77   const char* name;
     78   int priority;
     79   unsigned flags;
     80   Unit* next;
     81 };
     82 
     83 //! Automatic unit registration by using static initialization.
     84 class AutoUnit : public Unit {
     85 public:
     86   inline AutoUnit(Entry entry_, const char* name_, int priority_ = 0, int dummy_ = 0) noexcept {
     87     // Not used, only to trick `UNIT()` macro.
     88     (void)dummy_;
     89 
     90     this->entry = entry_;
     91     this->name = name_;
     92     this->priority = priority_;
     93     this->flags = 0;
     94     this->next = nullptr;
     95     add_unit(this);
     96   }
     97 };
     98 
     99 class Failure {
    100 public:
    101   const char* _file = nullptr;
    102   const char* _expression = nullptr;
    103   int _line = 0;
    104   bool _handled = false;
    105 
    106   inline Failure(const char* file, int line, const char* expression) noexcept
    107     : _file(file),
    108       _expression(expression),
    109       _line(line) {}
    110 
    111   inline ~Failure() noexcept {
    112     if (!_handled)
    113       fail(_file, _line, _expression, nullptr);
    114   }
    115 
    116   template<typename... Args>
    117   inline void message(const char* fmt, Args&&... args) noexcept {
    118     fail(_file, _line, _expression, fmt, std::forward<Args>(args)...);
    119     _handled = true;
    120   }
    121 };
    122 
    123 template<typename Result>
    124 static inline bool check(Result&& result) noexcept { return !!result; }
    125 
    126 template<typename LHS, typename RHS>
    127 static inline bool check_eq(LHS&& lhs, RHS&& rhs) noexcept { return lhs == rhs; }
    128 
    129 template<typename LHS, typename RHS>
    130 static inline bool check_ne(LHS&& lhs, RHS&& rhs) noexcept { return lhs != rhs; }
    131 
    132 template<typename LHS, typename RHS>
    133 static inline bool check_gt(LHS&& lhs, RHS&& rhs) noexcept { return lhs >  rhs; }
    134 
    135 template<typename LHS, typename RHS>
    136 static inline bool check_ge(LHS&& lhs, RHS&& rhs) noexcept { return lhs >= rhs; }
    137 
    138 template<typename LHS, typename RHS>
    139 static inline bool check_lt(LHS&& lhs, RHS&& rhs) noexcept { return lhs <  rhs; }
    140 
    141 template<typename LHS, typename RHS>
    142 static inline bool check_le(LHS&& lhs, RHS&& rhs) noexcept { return lhs <= rhs; }
    143 
    144 template<typename Result>
    145 static inline bool check_true(Result&& result) noexcept { return !!result; }
    146 
    147 template<typename Result>
    148 static inline bool check_false(Result&& result) noexcept { return !result; }
    149 
    150 template<typename Result>
    151 static inline bool check_null(Result&& result) noexcept { return result == nullptr; }
    152 
    153 template<typename Result>
    154 static inline bool check_not_null(Result&& result) noexcept { return result != nullptr; }
    155 
    156 } // {BrokenAPI}
    157 
    158 // Broken - Macros
    159 // ===============
    160 
    161 //! Internal macro used by `UNIT()`.
    162 #define BROKEN_UNIT_INTERNAL(NAME, PRIORITY) \
    163   static void unit_##NAME##_entry(void); \
    164   static ::BrokenAPI::AutoUnit unit_##NAME##_autoinit(unit_##NAME##_entry, #NAME, PRIORITY); \
    165   static void unit_##NAME##_entry(void)
    166 
    167 //! \def UNIT(NAME [, PRIORITY])
    168 //!
    169 //! Define a unit test with an optional priority.
    170 //!
    171 //! `NAME` can only contain ASCII characters, numbers and underscore. It has the same rules as identifiers in C and C++.
    172 //!
    173 //! `PRIORITY` specifies the order in which unit tests are run. Lesses value increases the priority. At the moment all
    174 //!units are first sorted by priority and then by name - this makes the run always deterministic.
    175 #define UNIT(NAME, ...) BROKEN_UNIT_INTERNAL(NAME, __VA_ARGS__ + 0)
    176 
    177 //! #define INFO(FORMAT [, ...])
    178 //!
    179 //! Informative message printed to `stdout`.
    180 #define INFO(...) ::BrokenAPI::info(__VA_ARGS__)
    181 
    182 #define BROKEN_EXPECT_INTERNAL(file, line, expression, result) \
    183   for (bool _test_internal_result = (result); !_test_internal_result; _test_internal_result = true) \
    184     ::BrokenAPI::Failure(file, line, expression)
    185 
    186 #define EXPECT(...) BROKEN_EXPECT_INTERNAL(__FILE__, __LINE__, "EXPECT(" #__VA_ARGS__ ")", !!(__VA_ARGS__))
    187 #define EXPECT_EQ(...) BROKEN_EXPECT_INTERNAL(__FILE__, __LINE__, "EXPECT_EQ(" #__VA_ARGS__ ")", ::BrokenAPI::check_eq(__VA_ARGS__))
    188 #define EXPECT_NE(...) BROKEN_EXPECT_INTERNAL(__FILE__, __LINE__, "EXPECT_NE(" #__VA_ARGS__ ")", ::BrokenAPI::check_ne(__VA_ARGS__))
    189 #define EXPECT_GT(...) BROKEN_EXPECT_INTERNAL(__FILE__, __LINE__, "EXPECT_GT(" #__VA_ARGS__ ")", ::BrokenAPI::check_gt(__VA_ARGS__))
    190 #define EXPECT_GE(...) BROKEN_EXPECT_INTERNAL(__FILE__, __LINE__, "EXPECT_GE(" #__VA_ARGS__ ")", ::BrokenAPI::check_ge(__VA_ARGS__))
    191 #define EXPECT_LT(...) BROKEN_EXPECT_INTERNAL(__FILE__, __LINE__, "EXPECT_LT(" #__VA_ARGS__ ")", ::BrokenAPI::check_lt(__VA_ARGS__))
    192 #define EXPECT_LE(...) BROKEN_EXPECT_INTERNAL(__FILE__, __LINE__, "EXPECT_LE(" #__VA_ARGS__ ")", ::BrokenAPI::check_le(__VA_ARGS__))
    193 #define EXPECT_TRUE(...) BROKEN_EXPECT_INTERNAL(__FILE__, __LINE__, "EXPECT_TRUE(" #__VA_ARGS__ ")", ::BrokenAPI::check_true(__VA_ARGS__))
    194 #define EXPECT_FALSE(...) BROKEN_EXPECT_INTERNAL(__FILE__, __LINE__, "EXPECT_FALSE(" #__VA_ARGS__ ")", ::BrokenAPI::check_false(__VA_ARGS__))
    195 #define EXPECT_NULL(...) BROKEN_EXPECT_INTERNAL(__FILE__, __LINE__, "EXPECT_NULL(" #__VA_ARGS__ ")", ::BrokenAPI::check_null(__VA_ARGS__))
    196 #define EXPECT_NOT_NULL(...) BROKEN_EXPECT_INTERNAL(__FILE__, __LINE__, "EXPECT_NOT_NULL(" #__VA_ARGS__ ")", ::BrokenAPI::check_not_null(__VA_ARGS__))
    197 
    198 //! \endcond
    199 
    200 #endif // BROKEN_H_INCLUDED