1 #include "minitest.h"
2 
3 #include <stdarg.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <wchar.h>
7 
8 namespace {
9 
10 struct TestInfo {
11   const char* test_name;
12   const char* case_name;
13   minitest::TestFunction* test_function;
14   TestInfo* next;
15 };
16 
17 TestInfo* g_test_infos;
18 TestInfo** g_test_infos_tail;
19 
20 }  // namespace
21 
22 namespace minitest {
23 
24 namespace internal {
25 
String(const char * str,size_t len)26 String::String(const char* str, size_t len) {
27   Resize(len);
28   ::memcpy(str_, str, len);
29   size_ = len;
30 }
31 
operator +=(const String & other)32 String& String::operator+=(const String& other) {
33   size_t old_size = size_;
34   Resize(old_size + other.size_);
35   ::memcpy(str_ + old_size, other.str_, other.size_);
36   return *this;
37 }
38 
operator +=(const char * str)39 String& String::operator+=(const char* str) {
40   size_t len = ::strlen(str);
41   size_t old_size = size_;
42   Resize(old_size + len);
43   ::memcpy(str_ + old_size, str, len);
44   return *this;
45 }
46 
operator +=(char ch)47 String& String::operator+=(char ch) {
48   Resize(size_ + 1);
49   str_[size_ - 1] = ch;
50   return *this;
51 }
52 
operator <<(const String & other)53 String& String::operator<<(const String& other) {
54   (*this) += other;
55   return *this;
56 }
57 
operator <<(const char * str)58 String& String::operator<<(const char* str) {
59   (*this) += str;
60   return *this;
61 }
62 
operator <<(char ch)63 String& String::operator<<(char ch) {
64   (*this) += ch;
65   return *this;
66 }
67 
operator <<(bool v)68 String& String::operator<<(bool v) {
69   (*this) += (v ? "true" : "false");
70   return *this;
71 }
72 
73 #define MINITEST_STRING_OPERATOR_LL_(ParamType, Format) \
74   String& String::operator<<(ParamType v) {             \
75     char buf[20];                                       \
76     ::snprintf(buf, sizeof(buf), Format, v);            \
77     (*this) += buf;                                     \
78     return *this;                                       \
79   }
80 
81 MINITEST_STRING_OPERATOR_LL_(signed char, "%hhd")
82 MINITEST_STRING_OPERATOR_LL_(unsigned char, "%hhu")
83 MINITEST_STRING_OPERATOR_LL_(short, "%hd")
84 MINITEST_STRING_OPERATOR_LL_(unsigned short, "%hu");
85 MINITEST_STRING_OPERATOR_LL_(int, "%d")
86 MINITEST_STRING_OPERATOR_LL_(unsigned, "%u")
87 MINITEST_STRING_OPERATOR_LL_(long, "%ld")
88 MINITEST_STRING_OPERATOR_LL_(unsigned long, "%lu")
89 MINITEST_STRING_OPERATOR_LL_(long long, "%lld")
90 MINITEST_STRING_OPERATOR_LL_(unsigned long long, "%llu")
91 MINITEST_STRING_OPERATOR_LL_(float, "%f")
92 MINITEST_STRING_OPERATOR_LL_(double, "%f")
93 MINITEST_STRING_OPERATOR_LL_(long double, "%Lf")
94 MINITEST_STRING_OPERATOR_LL_(const void*, "%p")
95 
96 #undef MINITEST_STRING_OPERATOR_LL_
97 
Clear()98 void String::Clear() {
99   ::free(str_);
100   str_ = NULL;
101   size_ = 0;
102   capacity_ = 0;
103 }
104 
Resize(size_t new_size)105 void String::Resize(size_t new_size) {
106   if (new_size > capacity_) {
107     size_t new_capacity = capacity_;
108     while (new_capacity < new_size)
109       new_capacity += (new_capacity >> 1) + 8;
110 
111     Reserve(new_capacity);
112   }
113   str_[new_size] = '\0';
114   size_ = new_size;
115 }
116 
Reserve(size_t new_capacity)117 void String::Reserve(size_t new_capacity) {
118   str_ = reinterpret_cast<char*>(::realloc(str_, new_capacity + 1));
119   if (new_capacity > capacity_)
120     ::memset(str_ + capacity_, '\0', new_capacity - capacity_);
121   capacity_ = new_capacity;
122 }
123 
124 }  // namespace internal
125 
Format(const char * format,...)126 internal::String Format(const char* format, ...) {
127   internal::String result;
128   va_list args, args2;
129   va_start(args, format);
130   // Note: Resize(n) allocates at least n+1 bytes.
131   result.Resize(100);
132   int len;
133   for (;;) {
134     va_copy(args2, args);
135     len = vsnprintf(&result[0], result.size(), format, args2);
136     va_end(args2);
137     // On Windows, snprintf() returns -1 on truncation. On other
138     // platforms, it returns the size of the string, without truncation.
139     if (len >= 0 && static_cast<size_t>(len) <= result.size())
140       break;
141     result.Resize(result.size() * 2);
142   }
143   va_end(args);
144   return result;
145 }
146 
Failure()147 void TestCase::Failure() {
148   if (result_ == PASS)
149     result_ = FAIL;
150   if (!text_.empty())
151     printf("%s\n", text_.c_str());
152 }
153 
FatalFailure()154 void TestCase::FatalFailure() {
155   result_ = FATAL;
156   if (!text_.empty())
157     printf("%s\n", text_.c_str());
158 }
159 
GetText()160 internal::String& TestCase::GetText() {
161   text_.Clear();
162   return text_;
163 }
164 
RegisterTest(const char * test_name,const char * case_name,TestFunction * test_function)165 void RegisterTest(const char* test_name,
166                   const char* case_name,
167                   TestFunction* test_function) {
168   if (g_test_infos_tail == NULL)
169     g_test_infos_tail = &g_test_infos;
170 
171   TestInfo* info = reinterpret_cast<TestInfo*>(::malloc(sizeof(*info)));
172 
173   info->test_name = test_name;
174   info->case_name = case_name;
175   info->test_function = test_function;
176 
177   *g_test_infos_tail = info;
178   g_test_infos_tail = &info->next;
179 }
180 
181 }  // namespace minitest
182 
main(void)183 int main(void) {
184   printf("--- TESTS STARTING ---\n");
185   TestInfo* info = g_test_infos;
186   unsigned num_failures = 0;
187   unsigned num_tests = 0;
188   for (; info != NULL; info = info->next) {
189     minitest::TestCase testcase;
190     printf("[ RUNNING   ] %s.%s\n", info->test_name, info->case_name);
191     num_tests += 1;
192     info->test_function(&testcase);
193     const char* status;
194     switch (testcase.result()) {
195       case minitest::TestCase::PASS:
196         status = "OK";
197         break;
198       case minitest::TestCase::FAIL:
199       case minitest::TestCase::FATAL:
200         status = "FAIL";
201         num_failures += 1;
202         break;
203     }
204     printf("[ %9s ] %s.%s\n", status, info->test_name, info->case_name);
205   }
206   printf("--- TESTS COMPLETED ---\n");
207   printf("tests completed: %d\n", num_tests);
208   printf("tests passed: %d\n", num_tests - num_failures);
209   printf("tests failed: %d\n", num_failures);
210 
211   return (num_failures > 0);
212 }
213