mirror of
https://github.com/asmjit/asmjit.git
synced 2025-12-17 12:34:35 +03:00
Codebase update and improvements, instruction DB update
* Denested src folder to root, renamed testing to asmjit-testing
* Refactored how headers are included into <asmjit/...> form. This
is necessary as compilers would never simplify a path once a ..
appears in include directory - then paths such as ../core/../core
appeared in asserts, which was ugly
* Moved support utilities into asmjit/support/... (still included
by asmjit/core.h for convenience and compatibility)
* Added CMakePresets.json for making it easy to develop AsmJit
* Reworked CMakeLists to be shorter and use CMake option(),
etc... This simplifies it and makes it using more standard
features
* ASMJIT_EMBED now creates asmjit_embed INTERFACE library,
which is accessible via asmjit::asmjit target - this simplifies
embedding and makes it the same as library targets from a CMake
perspective
* Removed ASMJIT_DEPS - this is now provided by cmake target
aliases - 'asmjit::asmjit' so users should not need this variable
* Changed meaning of ASMJIT_LIBS - this now contains only AsmJit
dependencies without asmjit::asmjit target alias. Don't rely on
ASMJIT_LIBS anymore as it's only used internally
* Removed ASMJIT_NO_DEPRECATED option - AsmJit is not going
to provide controllable deprecations in the future
* Removed ASMJIT_NO_VALIDATION in favor of ASMJIT_NO_INTROSPECTION,
which now controls query, features, and validation API presence
* Removed ASMJIT_DIR option - it was never really needed
* Removed AMX_TRANSPOSE feature from instruction database (X86).
Intel has removed it as well, so it's a feature that won't
be siliconized
This commit is contained in:
310
asmjit-testing/tests/broken.cpp
Normal file
310
asmjit-testing/tests/broken.cpp
Normal file
@@ -0,0 +1,310 @@
|
||||
// Broken - Lightweight unit testing for C++
|
||||
//
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
//
|
||||
// Anyone is free to copy, modify, publish, use, compile, sell, or
|
||||
// distribute this software, either in source code form or as a compiled
|
||||
// binary, for any purpose, commercial or non-commercial, and by any
|
||||
// means.
|
||||
//
|
||||
// In jurisdictions that recognize copyright laws, the author or authors
|
||||
// of this software dedicate any and all copyright interest in the
|
||||
// software to the public domain. We make this dedication for the benefit
|
||||
// of the public at large and to the detriment of our heirs and
|
||||
// successors. We intend this dedication to be an overt act of
|
||||
// relinquishment in perpetuity of all present and future rights to this
|
||||
// software under copyright law.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
// OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// For more information, please refer to <http://unlicense.org>
|
||||
|
||||
#include "broken.h"
|
||||
#include <stdarg.h>
|
||||
|
||||
// Broken - Globals
|
||||
// ================
|
||||
|
||||
// Zero initialized globals.
|
||||
struct BrokenGlobal {
|
||||
// Application arguments.
|
||||
int _argc;
|
||||
const char** _argv;
|
||||
|
||||
// Output file.
|
||||
FILE* _file;
|
||||
|
||||
// Unit tests.
|
||||
BrokenAPI::Unit* _unitList;
|
||||
BrokenAPI::Unit* _unitRunning;
|
||||
|
||||
bool has_arg(const char* a) const noexcept {
|
||||
for (int i = 1; i < _argc; i++)
|
||||
if (strcmp(_argv[i], a) == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
inline FILE* file() const noexcept { return _file ? _file : stdout; }
|
||||
};
|
||||
static BrokenGlobal _brokenGlobal;
|
||||
|
||||
// Broken - API
|
||||
// ============
|
||||
|
||||
// Get whether the string `a` starts with string `b`.
|
||||
static bool BrokenAPI_startsWith(const char* a, const char* b) noexcept {
|
||||
for (size_t i = 0; ; i++) {
|
||||
if (b[i] == '\0') return true;
|
||||
if (a[i] != b[i]) return false;
|
||||
}
|
||||
}
|
||||
|
||||
//! Compares names and priority of two unit tests.
|
||||
static int BrokenAPI_compareUnits(const BrokenAPI::Unit* a, const BrokenAPI::Unit* b) noexcept {
|
||||
if (a->priority == b->priority)
|
||||
return strcmp(a->name, b->name);
|
||||
else
|
||||
return a->priority > b->priority ? 1 : -1;
|
||||
}
|
||||
|
||||
// Get whether the strings `a` and `b` are equal, ignoring case and treating
|
||||
// `-` as `_`.
|
||||
static bool BrokenAPI_matchesFilter(const char* a, const char* b) noexcept {
|
||||
for (size_t i = 0; ; i++) {
|
||||
int ca = (unsigned char)a[i];
|
||||
int cb = (unsigned char)b[i];
|
||||
|
||||
// If filter is defined as wildcard the rest automatically matches.
|
||||
if (cb == '*')
|
||||
return true;
|
||||
|
||||
if (ca == '-') ca = '_';
|
||||
if (cb == '-') cb = '_';
|
||||
|
||||
if (ca >= 'A' && ca <= 'Z') ca += 'a' - 'A';
|
||||
if (cb >= 'A' && cb <= 'Z') cb += 'a' - 'A';
|
||||
|
||||
if (ca != cb)
|
||||
return false;
|
||||
|
||||
if (ca == '\0')
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool BrokenAPI_canRun(BrokenAPI::Unit* unit) noexcept {
|
||||
BrokenGlobal& global = _brokenGlobal;
|
||||
|
||||
int i, argc = global._argc;
|
||||
const char** argv = global._argv;
|
||||
|
||||
const char* unitName = unit->name;
|
||||
bool has_filter = false;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
const char* arg = argv[i];
|
||||
|
||||
if (BrokenAPI_startsWith(arg, "--run-") && strcmp(arg, "--run-all") != 0) {
|
||||
has_filter = true;
|
||||
|
||||
if (BrokenAPI_matchesFilter(unitName, arg + 6))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// If no filter has been specified the default is to run.
|
||||
return !has_filter;
|
||||
}
|
||||
|
||||
static void BrokenAPI_runUnit(BrokenAPI::Unit* unit) noexcept {
|
||||
BrokenAPI::info("Running %s", unit->name);
|
||||
|
||||
_brokenGlobal._unitRunning = unit;
|
||||
unit->entry();
|
||||
_brokenGlobal._unitRunning = NULL;
|
||||
}
|
||||
|
||||
static void BrokenAPI_runAll() noexcept {
|
||||
BrokenAPI::Unit* unit = _brokenGlobal._unitList;
|
||||
|
||||
bool has_units = unit != NULL;
|
||||
size_t count = 0;
|
||||
int currentPriority = 0;
|
||||
|
||||
while (unit != NULL) {
|
||||
if (BrokenAPI_canRun(unit)) {
|
||||
if (currentPriority != unit->priority) {
|
||||
if (count)
|
||||
INFO("");
|
||||
INFO("[[Priority=%d]]", unit->priority);
|
||||
}
|
||||
|
||||
currentPriority = unit->priority;
|
||||
BrokenAPI_runUnit(unit);
|
||||
count++;
|
||||
}
|
||||
unit = unit->next;
|
||||
}
|
||||
|
||||
if (count) {
|
||||
INFO("\nSuccess:");
|
||||
INFO(" All tests passed!");
|
||||
}
|
||||
else {
|
||||
INFO("\nWarning:");
|
||||
INFO(" No units %s!", has_units ? "matched the filter" : "defined");
|
||||
}
|
||||
}
|
||||
|
||||
static void BrokenAPI_listAll() noexcept {
|
||||
BrokenAPI::Unit* unit = _brokenGlobal._unitList;
|
||||
|
||||
if (unit != NULL) {
|
||||
INFO("Units:");
|
||||
do {
|
||||
INFO(" %s [priority=%d]", unit->name, unit->priority);
|
||||
unit = unit->next;
|
||||
} while (unit != NULL);
|
||||
}
|
||||
else {
|
||||
INFO("Warning:");
|
||||
INFO(" No units defined!");
|
||||
}
|
||||
}
|
||||
|
||||
bool BrokenAPI::has_arg(const char* name) noexcept {
|
||||
return _brokenGlobal.has_arg(name);
|
||||
}
|
||||
|
||||
void BrokenAPI::addUnit(Unit* unit) noexcept {
|
||||
Unit** pPrev = &_brokenGlobal._unitList;
|
||||
Unit* current = *pPrev;
|
||||
|
||||
// C++ static initialization doesn't guarantee anything. We sort all units by
|
||||
// name so the execution will always happen in deterministic order.
|
||||
while (current != NULL) {
|
||||
if (BrokenAPI_compareUnits(current, unit) >= 0)
|
||||
break;
|
||||
|
||||
pPrev = ¤t->next;
|
||||
current = *pPrev;
|
||||
}
|
||||
|
||||
*pPrev = unit;
|
||||
unit->next = current;
|
||||
}
|
||||
|
||||
void BrokenAPI::setOutputFile(FILE* file) noexcept {
|
||||
BrokenGlobal& global = _brokenGlobal;
|
||||
|
||||
global._file = file;
|
||||
}
|
||||
|
||||
int BrokenAPI::run(int argc, const char* argv[], Entry on_before_run, Entry onAfterRun) {
|
||||
BrokenGlobal& global = _brokenGlobal;
|
||||
|
||||
global._argc = argc;
|
||||
global._argv = argv;
|
||||
|
||||
if (global.has_arg("--help")) {
|
||||
INFO("Options:");
|
||||
INFO(" --help - print this usage");
|
||||
INFO(" --list - list all tests");
|
||||
INFO(" --run-... - run a test(s), trailing wildcards supported");
|
||||
INFO(" --run-all - run all tests (default)");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (global.has_arg("--list")) {
|
||||
BrokenAPI_listAll();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (on_before_run)
|
||||
on_before_run();
|
||||
|
||||
// We don't care about filters here, it's implemented by `runAll`.
|
||||
BrokenAPI_runAll();
|
||||
|
||||
if (onAfterRun)
|
||||
onAfterRun();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void BrokenAPI_printMessage(const char* prefix, const char* fmt, va_list ap) noexcept {
|
||||
BrokenGlobal& global = _brokenGlobal;
|
||||
FILE* dst = global.file();
|
||||
|
||||
if (!fmt || fmt[0] == '\0') {
|
||||
fprintf(dst, "\n");
|
||||
}
|
||||
else {
|
||||
// This looks scary, but we really want to use only a single call to vfprintf()
|
||||
// in multithreaded code. So we change the format a bit if necessary.
|
||||
enum : unsigned { kBufferSize = 512 };
|
||||
char staticBuffer[512];
|
||||
|
||||
size_t fmtSize = strlen(fmt);
|
||||
size_t prefix_size = strlen(prefix);
|
||||
|
||||
char* fmtBuf = staticBuffer;
|
||||
if (fmtSize > kBufferSize - 2 - prefix_size)
|
||||
fmtBuf = static_cast<char*>(malloc(fmtSize + prefix_size + 2));
|
||||
|
||||
if (!fmtBuf) {
|
||||
fprintf(dst, "%sCannot allocate buffer for vfprintf()\n", prefix);
|
||||
}
|
||||
else {
|
||||
memcpy(fmtBuf, prefix, prefix_size);
|
||||
memcpy(fmtBuf + prefix_size, fmt, fmtSize);
|
||||
|
||||
fmtSize += prefix_size;
|
||||
if (fmtBuf[fmtSize - 1] != '\n')
|
||||
fmtBuf[fmtSize++] = '\n';
|
||||
fmtBuf[fmtSize] = '\0';
|
||||
|
||||
vfprintf(dst, fmtBuf, ap);
|
||||
|
||||
if (fmtBuf != staticBuffer)
|
||||
free(fmtBuf);
|
||||
}
|
||||
}
|
||||
|
||||
fflush(dst);
|
||||
}
|
||||
|
||||
void BrokenAPI::info(const char* fmt, ...) noexcept {
|
||||
BrokenGlobal& global = _brokenGlobal;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
BrokenAPI_printMessage(global._unitRunning ? " " : "", fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
void BrokenAPI::fail(const char* file, int line, const char* expression, const char* fmt, ...) noexcept {
|
||||
BrokenGlobal& global = _brokenGlobal;
|
||||
FILE* dst = global.file();
|
||||
|
||||
fprintf(dst, " FAILED: %s\n", expression);
|
||||
|
||||
if (fmt) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
BrokenAPI_printMessage(" REASON: ", fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
fprintf(dst, " SOURCE: %s (Line: %d)\n", file, line);
|
||||
fflush(dst);
|
||||
|
||||
abort();
|
||||
}
|
||||
Reference in New Issue
Block a user