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