CMSDK 2.0.1
Cross-platform C++ base library and SDK for the Psyclone AIOS platform
Loading...
Searching...
No Matches
UnitTestFramework.h
Go to the documentation of this file.
1
79#if !defined(_UNITTESTFRAMEWORK_H_)
80#define _UNITTESTFRAMEWORK_H_
81
82#include "Standard.h"
83#include "Types.h"
84#include "Utils.h"
85
86#include <string>
87#include <vector>
88#include <map>
89
90// --- Instrumentation-aware time budgets -------------------------------------
91// AddressSanitizer/TSan slow execution by roughly 2-4x, which blows every FIXED
92// wall-clock deadline in the suite. Two real cases, same root cause but different
93// symptoms on different platforms:
94// Linux - builder_golden exceeded the framework's 30 s per-test cap. It runs
95// three node start/stop cycles, and under ASan each node startup
96// ("PsySpace 'Root' has shut down" -> "Success synchronising ID
97// Manager") costs ~11.8 s versus well under a second bare, so ~35 s of
98// legitimate work hit a 30 s ceiling.
99// macOS - the same test failed at ~1.2 s on an in-test elapsed-time assertion
100// instead, because that box is fast enough to stay inside the cap.
101// Both are budget problems, not defects: the suite is 55/55 bare on both
102// platforms with zero memory reports.
103//
104// Scale time budgets by UT_TIME_SCALE rather than widening constants outright, so
105// bare runs keep their original (tight, meaningful) deadlines and only
106// instrumented runs get slack. Deliberately NOT applied to product timeouts -
107// only to test/framework budgets.
108#if defined(__SANITIZE_ADDRESS__) || defined(__SANITIZE_THREAD__)
109 #define UT_SANITIZED 1
110#elif defined(__has_feature)
111 #if __has_feature(address_sanitizer) || __has_feature(thread_sanitizer)
112 #define UT_SANITIZED 1
113 #endif
114#endif
115#ifdef UT_SANITIZED
116 #define UT_TIME_SCALE 5
117#else
118 #define UT_TIME_SCALE 1
119#endif
120
121namespace cmlabs {
122
126typedef bool (*UnitTestFunc)();
127
133namespace unittest {
134
140 void progress(int percent, const char* action);
142 void progressf(int percent, const char* fmt, ...);
143
154 void metric(const char* name, double value, const char* unit = "", bool higherIsBetter = true);
155
157 void detail(const char* fmt, ...);
158
161 void fail(const char* fmt, ...);
162
164 bool verbose();
165
166} // namespace unittest
167
171 std::string name;
172 double value;
173 std::string unit;
175};
176
180 std::string name;
181 std::string description;
182 std::string category;
185
186 // Filled in at run time
187 bool ran;
188 bool passed;
189 uint64 durationUs;
190 std::string failReason;
191 std::string endNote;
192 std::vector<UnitTestMetric> metrics;
200 std::vector<std::string> detailLog;
201
203 UnitTestRecord() : func(NULL), inDefaultRun(true), ran(false), passed(false), durationUs(0) {}
204};
205
214class UnitTestRunner {
215public:
217 static UnitTestRunner& instance();
218
225 void registerTest(const char* name, UnitTestFunc func,
226 const char* description = "", const char* category = "",
227 bool inDefaultRun = true);
228
230 void setVerbose(bool v);
232 void setCompareFile(const char* path);
234 void setOutputFile(const char* path);
236 void setOutputDir(const char* dir);
238 void setWriteJSON(bool v);
240 void setForkPerTest(bool v);
241
243 bool hasTest(const char* name) const;
245 std::vector<std::string> testNames() const;
247 void listTests() const;
248
251 bool runAll();
254 bool runOne(const char* name);
255
257 void hookProgress(int percent, const char* action);
259 void hookMetric(const char* name, double value, const char* unit, bool higherIsBetter);
261 void hookDetail(const char* text);
263 void hookFail(const char* text);
265 bool hookVerbose() const;
266
267private:
268 UnitTestRunner();
269
271 bool runRecords(std::vector<UnitTestRecord*>& records);
273 bool executeRecord(UnitTestRecord* rec);
275 void beginTest(UnitTestRecord* rec);
277 void finishTest(UnitTestRecord* rec);
279 void clearProgressLine();
281 void printStatusLine(const UnitTestRecord* rec);
283 void printMetricLines(const UnitTestRecord* rec);
285 void writeResults(const std::vector<UnitTestRecord*>& records,
286 uint64 totalUs, int passed, int failed);
288 void loadComparison();
290 bool comparisonValue(const std::string& key, double& out) const;
292 static std::string timestampForFilename(uint64 t);
293
294 std::vector<UnitTestRecord> tests;
295 UnitTestRecord* current;
296
297 bool verboseFlag;
298 bool writeJSONFlag;
299 bool forkPerTest;
300 bool isTTY;
301 int lastProgressLen;
302 std::string progressPath;
304
305 std::string compareFile;
306 std::string outputFile;
307 std::string outputDir;
308
309 bool compareLoaded;
310 std::map<std::string, double> compareMetrics;
311
312 utils::Mutex lock;
313};
314
315} // namespace cmlabs
316
317#endif // _UNITTESTFRAMEWORK_H_
Platform/compiler detection and base portability macros for all of CMSDK.
Core fixed-width scalar typedefs and the PsyType / PsyContext hierarchical identifiers.
Cross-platform utility toolbox for CMSDK: threading, synchronization, shared memory,...
std::vector< std::string > testNames() const
void hookDetail(const char *text)
Hook behind unittest::detail() for the current test.
void setForkPerTest(bool v)
Run each test in its own process (default: on where supported) so crashes/hangs are isolated.
void setWriteJSON(bool v)
Enable/disable writing the perf JSON file at all.
void listTests() const
Print the registered tests (name, category, description) to stdout.
void hookProgress(int percent, const char *action)
Hook behind unittest::progress()/progressf() for the current test.
void setOutputFile(const char *path)
Set an explicit perf JSON output path (overrides the timestamped default).
bool hasTest(const char *name) const
void hookMetric(const char *name, double value, const char *unit, bool higherIsBetter)
Hook behind unittest::metric() for the current test.
static UnitTestRunner & instance()
Access the singleton (created on first use).
void setVerbose(bool v)
Enable/disable verbose diagnostics (unittest::detail output).
bool hookVerbose() const
Hook behind unittest::verbose().
void setCompareFile(const char *path)
Set a previous perf JSON file to compare metrics against.
bool runAll()
Run every test marked inDefaultRun.
void registerTest(const char *name, UnitTestFunc func, const char *description="", const char *category="", bool inDefaultRun=true)
Register a test with the runner.
bool runOne(const char *name)
Run a single named test in isolation.
void setOutputDir(const char *dir)
Set the directory for the default (timestamped + latest) output files.
void hookFail(const char *text)
Hook behind unittest::fail() for the current test.
Recursive mutual-exclusion lock, optionally named for cross-process use.
Definition Utils.h:463
bool(* UnitTestFunc)()
Signature every unit test uses.
API used by the body of a unit test.
void fail(const char *fmt,...)
Set an explanatory reason shown on the FAIL line.
void progressf(int percent, const char *fmt,...)
printf-style variant of progress().
void metric(const char *name, double value, const char *unit="", bool higherIsBetter=true)
Record a performance metric.
void detail(const char *fmt,...)
Verbose-only indented diagnostic line (shown only when verbose=1).
void progress(int percent, const char *action)
Report progress with a short description of the current action.
One recorded performance metric of a test run.
bool higherIsBetter
Delta-direction hint for compare mode.
std::string unit
Unit label (e.g.
double value
Measured value.
std::string name
Metric name (unique within the test).
Registration and result record for a single unit test.
UnitTestFunc func
The test function itself.
UnitTestRecord()
Default: unregistered, not run, in the default suite.
bool passed
Outcome (only meaningful when ran).
std::vector< UnitTestMetric > metrics
Metrics recorded via unittest::metric().
std::string failReason
Reason set by the test via unittest::fail() (printed immediately).
bool inDefaultRun
Included when running the whole suite (test=cmsdk).
std::string description
One-line human description.
std::string name
Canonical name, used by test=<name>.
std::string endNote
Framework outcome note (timed out / crashed / no test function).
std::string category
Grouping label (e.g.
uint64 durationUs
Wall-clock duration in microseconds.
std::vector< std::string > detailLog
Ring of the most recent unittest::detail() lines, kept even when NOT verbose so they can be printed i...
bool ran
True once the runner attempted this test.