mirror of
https://github.com/vczh-libraries/Release.git
synced 2026-02-06 12:01:39 +08:00
1503 lines
38 KiB
C++
1503 lines
38 KiB
C++
/***********************************************************************
|
|
THIS FILE IS AUTOMATICALLY GENERATED. DO NOT MODIFY
|
|
DEVELOPER: Zihan Chen(vczh)
|
|
***********************************************************************/
|
|
#include "Vlpp.h"
|
|
|
|
/***********************************************************************
|
|
.\BASIC.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#include <time.h>
|
|
#if defined VCZH_MSVC
|
|
#include <Windows.h>
|
|
#elif defined VCZH_GCC
|
|
#include <sys/time.h>
|
|
#endif
|
|
|
|
namespace vl
|
|
{
|
|
|
|
/***********************************************************************
|
|
NotCopyable
|
|
***********************************************************************/
|
|
|
|
NotCopyable::NotCopyable()
|
|
{
|
|
}
|
|
|
|
NotCopyable::NotCopyable(const NotCopyable&)
|
|
{
|
|
}
|
|
|
|
NotCopyable& NotCopyable::operator=(const NotCopyable&)
|
|
{
|
|
return *this;
|
|
}
|
|
|
|
/***********************************************************************
|
|
Error
|
|
***********************************************************************/
|
|
|
|
Error::Error(const wchar_t* _description)
|
|
{
|
|
description=_description;
|
|
}
|
|
|
|
const wchar_t* Error::Description()const
|
|
{
|
|
return description;
|
|
}
|
|
|
|
/***********************************************************************
|
|
Object
|
|
***********************************************************************/
|
|
|
|
Object::~Object()
|
|
{
|
|
}
|
|
|
|
/***********************************************************************
|
|
DateTime
|
|
***********************************************************************/
|
|
|
|
#if defined VCZH_MSVC
|
|
DateTime SystemTimeToDateTime(const SYSTEMTIME& systemTime)
|
|
{
|
|
DateTime dateTime;
|
|
dateTime.year=systemTime.wYear;
|
|
dateTime.month=systemTime.wMonth;
|
|
dateTime.dayOfWeek=systemTime.wDayOfWeek;
|
|
dateTime.day=systemTime.wDay;
|
|
dateTime.hour=systemTime.wHour;
|
|
dateTime.minute=systemTime.wMinute;
|
|
dateTime.second=systemTime.wSecond;
|
|
dateTime.milliseconds=systemTime.wMilliseconds;
|
|
|
|
FILETIME fileTime;
|
|
SystemTimeToFileTime(&systemTime, &fileTime);
|
|
ULARGE_INTEGER largeInteger;
|
|
largeInteger.HighPart=fileTime.dwHighDateTime;
|
|
largeInteger.LowPart=fileTime.dwLowDateTime;
|
|
dateTime.filetime=largeInteger.QuadPart;
|
|
dateTime.totalMilliseconds=dateTime.filetime/10000;
|
|
|
|
return dateTime;
|
|
}
|
|
|
|
SYSTEMTIME DateTimeToSystemTime(const DateTime& dateTime)
|
|
{
|
|
ULARGE_INTEGER largeInteger;
|
|
largeInteger.QuadPart=dateTime.filetime;
|
|
FILETIME fileTime;
|
|
fileTime.dwHighDateTime=largeInteger.HighPart;
|
|
fileTime.dwLowDateTime=largeInteger.LowPart;
|
|
|
|
SYSTEMTIME systemTime;
|
|
FileTimeToSystemTime(&fileTime, &systemTime);
|
|
return systemTime;
|
|
}
|
|
#elif defined VCZH_GCC
|
|
DateTime ConvertTMToDateTime(tm* timeinfo, vint milliseconds)
|
|
{
|
|
time_t timer = mktime(timeinfo);
|
|
DateTime dt;
|
|
dt.year = timeinfo->tm_year+1900;
|
|
dt.month = timeinfo->tm_mon+1;
|
|
dt.day = timeinfo->tm_mday;
|
|
dt.dayOfWeek = timeinfo->tm_wday;
|
|
dt.hour = timeinfo->tm_hour;
|
|
dt.minute = timeinfo->tm_min;
|
|
dt.second = timeinfo->tm_sec;
|
|
dt.milliseconds = milliseconds;
|
|
|
|
// in Linux and macOS, filetime will be mktime(t) * 1000 + gettimeofday().tv_usec / 1000
|
|
dt.filetime = (vuint64_t)timer * 1000 + milliseconds;
|
|
dt.totalMilliseconds = (vuint64_t)timer * 1000 + milliseconds;
|
|
return dt;
|
|
}
|
|
#endif
|
|
|
|
DateTime DateTime::LocalTime()
|
|
{
|
|
#if defined VCZH_MSVC
|
|
SYSTEMTIME systemTime;
|
|
GetLocalTime(&systemTime);
|
|
return SystemTimeToDateTime(systemTime);
|
|
#elif defined VCZH_GCC
|
|
struct timeval tv;
|
|
gettimeofday(&tv, nullptr);
|
|
tm* timeinfo = localtime(&tv.tv_sec);
|
|
return ConvertTMToDateTime(timeinfo, tv.tv_usec / 1000);
|
|
#endif
|
|
}
|
|
|
|
DateTime DateTime::UtcTime()
|
|
{
|
|
#if defined VCZH_MSVC
|
|
SYSTEMTIME utcTime;
|
|
GetSystemTime(&utcTime);
|
|
return SystemTimeToDateTime(utcTime);
|
|
#elif defined VCZH_GCC
|
|
struct timeval tv;
|
|
gettimeofday(&tv, nullptr);
|
|
tm* timeinfo = gmtime(&tv.tv_sec);
|
|
return ConvertTMToDateTime(timeinfo, tv.tv_usec / 1000);
|
|
#endif
|
|
}
|
|
|
|
DateTime DateTime::FromDateTime(vint _year, vint _month, vint _day, vint _hour, vint _minute, vint _second, vint _milliseconds)
|
|
{
|
|
#if defined VCZH_MSVC
|
|
SYSTEMTIME systemTime;
|
|
memset(&systemTime, 0, sizeof(systemTime));
|
|
systemTime.wYear=(WORD)_year;
|
|
systemTime.wMonth=(WORD)_month;
|
|
systemTime.wDay=(WORD)_day;
|
|
systemTime.wHour=(WORD)_hour;
|
|
systemTime.wMinute=(WORD)_minute;
|
|
systemTime.wSecond=(WORD)_second;
|
|
systemTime.wMilliseconds=(WORD)_milliseconds;
|
|
|
|
FILETIME fileTime;
|
|
SystemTimeToFileTime(&systemTime, &fileTime);
|
|
FileTimeToSystemTime(&fileTime, &systemTime);
|
|
return SystemTimeToDateTime(systemTime);
|
|
#elif defined VCZH_GCC
|
|
tm timeinfo;
|
|
memset(&timeinfo, 0, sizeof(timeinfo));
|
|
timeinfo.tm_year = _year-1900;
|
|
timeinfo.tm_mon = _month-1;
|
|
timeinfo.tm_mday = _day;
|
|
timeinfo.tm_hour = _hour;
|
|
timeinfo.tm_min = _minute;
|
|
timeinfo.tm_sec = _second;
|
|
timeinfo.tm_isdst = -1;
|
|
|
|
return ConvertTMToDateTime(&timeinfo, _milliseconds);
|
|
#endif
|
|
}
|
|
|
|
DateTime DateTime::FromFileTime(vuint64_t filetime)
|
|
{
|
|
#if defined VCZH_MSVC
|
|
ULARGE_INTEGER largeInteger;
|
|
largeInteger.QuadPart=filetime;
|
|
FILETIME fileTime;
|
|
fileTime.dwHighDateTime=largeInteger.HighPart;
|
|
fileTime.dwLowDateTime=largeInteger.LowPart;
|
|
|
|
SYSTEMTIME systemTime;
|
|
FileTimeToSystemTime(&fileTime, &systemTime);
|
|
return SystemTimeToDateTime(systemTime);
|
|
#elif defined VCZH_GCC
|
|
time_t timer = (time_t)(filetime / 1000);
|
|
tm* timeinfo = localtime(&timer);
|
|
return ConvertTMToDateTime(timeinfo, filetime % 1000);
|
|
#endif
|
|
}
|
|
|
|
DateTime::DateTime()
|
|
:year(0)
|
|
,month(0)
|
|
,day(0)
|
|
,hour(0)
|
|
,minute(0)
|
|
,second(0)
|
|
,milliseconds(0)
|
|
,filetime(0)
|
|
{
|
|
}
|
|
|
|
DateTime DateTime::ToLocalTime()
|
|
{
|
|
#if defined VCZH_MSVC
|
|
SYSTEMTIME utcTime=DateTimeToSystemTime(*this);
|
|
SYSTEMTIME localTime;
|
|
SystemTimeToTzSpecificLocalTime(NULL, &utcTime, &localTime);
|
|
return SystemTimeToDateTime(localTime);
|
|
#elif defined VCZH_GCC
|
|
time_t localTimer = time(nullptr);
|
|
time_t utcTimer = mktime(gmtime(&localTimer));
|
|
time_t timer = (time_t)(filetime / 1000) + localTimer - utcTimer;
|
|
tm* timeinfo = localtime(&timer);
|
|
|
|
return ConvertTMToDateTime(timeinfo, milliseconds);
|
|
#endif
|
|
}
|
|
|
|
DateTime DateTime::ToUtcTime()
|
|
{
|
|
#if defined VCZH_MSVC
|
|
SYSTEMTIME localTime=DateTimeToSystemTime(*this);
|
|
SYSTEMTIME utcTime;
|
|
TzSpecificLocalTimeToSystemTime(NULL, &localTime, &utcTime);
|
|
return SystemTimeToDateTime(utcTime);
|
|
#elif defined VCZH_GCC
|
|
time_t timer = (time_t)(filetime / 1000);
|
|
tm* timeinfo = gmtime(&timer);
|
|
|
|
return ConvertTMToDateTime(timeinfo, milliseconds);
|
|
#endif
|
|
}
|
|
|
|
DateTime DateTime::Forward(vuint64_t milliseconds)
|
|
{
|
|
#if defined VCZH_MSVC
|
|
return FromFileTime(filetime+milliseconds*10000);
|
|
#elif defined VCZH_GCC
|
|
return FromFileTime(filetime+milliseconds);
|
|
#endif
|
|
}
|
|
|
|
DateTime DateTime::Backward(vuint64_t milliseconds)
|
|
{
|
|
#if defined VCZH_MSVC
|
|
return FromFileTime(filetime-milliseconds*10000);
|
|
#elif defined VCZH_GCC
|
|
return FromFileTime(filetime-milliseconds);
|
|
#endif
|
|
}
|
|
|
|
/***********************************************************************
|
|
Interface
|
|
***********************************************************************/
|
|
|
|
Interface::~Interface()
|
|
{
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\CONSOLE.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#if defined VCZH_MSVC
|
|
#elif defined VCZH_GCC
|
|
#include <iostream>
|
|
#include <string>
|
|
using namespace std;
|
|
#endif
|
|
|
|
namespace vl
|
|
{
|
|
namespace console
|
|
{
|
|
|
|
/***********************************************************************
|
|
Console
|
|
***********************************************************************/
|
|
|
|
void Console::Write(const wchar_t* string, vint length)
|
|
{
|
|
#if defined VCZH_MSVC
|
|
HANDLE outHandle=GetStdHandle(STD_OUTPUT_HANDLE);
|
|
DWORD fileMode=0;
|
|
DWORD written=0;
|
|
if((GetFileType(outHandle) & FILE_TYPE_CHAR) && GetConsoleMode(outHandle, &fileMode))
|
|
{
|
|
WriteConsole(outHandle, string, (int)length, &written,0);
|
|
}
|
|
else
|
|
{
|
|
int codePage = GetConsoleOutputCP();
|
|
int charCount = WideCharToMultiByte(codePage, 0, string, -1, 0, 0, 0, 0);
|
|
char* codePageBuffer = new char[charCount];
|
|
WideCharToMultiByte(codePage, 0, string, -1, codePageBuffer, charCount, 0, 0);
|
|
WriteFile(outHandle, codePageBuffer, charCount-1, &written, 0);
|
|
delete[] codePageBuffer;
|
|
}
|
|
#elif defined VCZH_GCC
|
|
wstring s(string, string+length);
|
|
wcout<<s<<ends;
|
|
#endif
|
|
}
|
|
|
|
void Console::Write(const wchar_t* string)
|
|
{
|
|
Write(string, wcslen(string));
|
|
}
|
|
|
|
void Console::Write(const WString& string)
|
|
{
|
|
Write(string.Buffer(), string.Length());
|
|
}
|
|
|
|
void Console::WriteLine(const WString& string)
|
|
{
|
|
Write(string);
|
|
Write(L"\r\n");
|
|
}
|
|
|
|
WString Console::Read()
|
|
{
|
|
#if defined VCZH_MSVC
|
|
WString result;
|
|
DWORD count;
|
|
for(;;)
|
|
{
|
|
wchar_t buffer;
|
|
ReadConsole(GetStdHandle(STD_INPUT_HANDLE),&buffer,1,&count,0);
|
|
if(buffer==L'\r')
|
|
{
|
|
ReadConsole(GetStdHandle(STD_INPUT_HANDLE),&buffer,1,&count,0);
|
|
break;
|
|
}
|
|
else if(buffer==L'\n')
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
result=result+buffer;
|
|
}
|
|
}
|
|
return result;
|
|
#elif defined VCZH_GCC
|
|
wstring s;
|
|
getline(wcin, s, L'\n');
|
|
return s.c_str();
|
|
#endif
|
|
}
|
|
|
|
void Console::SetColor(bool red, bool green, bool blue, bool light)
|
|
{
|
|
#if defined VCZH_MSVC
|
|
WORD attribute=0;
|
|
if(red)attribute |=FOREGROUND_RED;
|
|
if(green)attribute |=FOREGROUND_GREEN;
|
|
if(blue)attribute |=FOREGROUND_BLUE;
|
|
if(light)attribute |=FOREGROUND_INTENSITY;
|
|
SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE),attribute);
|
|
SetConsoleTextAttribute(GetStdHandle(STD_INPUT_HANDLE),attribute);
|
|
#elif defined VCZH_GCC
|
|
int color = (blue?1:0)*4 + (green?1:0)*2 + (red?1:0);
|
|
if(light)
|
|
wprintf(L"\x1B[00;3%dm", color);
|
|
else
|
|
wprintf(L"\x1B[01;3%dm", color);
|
|
#endif
|
|
}
|
|
|
|
void Console::SetTitle(const WString& string)
|
|
{
|
|
#if defined VCZH_MSVC
|
|
SetConsoleTitle(string.Buffer());
|
|
#endif
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\EXCEPTION.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
|
|
/***********************************************************************
|
|
Exception
|
|
***********************************************************************/
|
|
Exception::Exception(const WString& _message)
|
|
:message(_message)
|
|
{
|
|
}
|
|
|
|
const WString& Exception::Message()const
|
|
{
|
|
return message;
|
|
}
|
|
|
|
/***********************************************************************
|
|
ArgumentException
|
|
***********************************************************************/
|
|
|
|
ArgumentException::ArgumentException(const WString& _message, const WString& _function, const WString& _name)
|
|
:Exception(_message)
|
|
,function(_function)
|
|
,name(_name)
|
|
{
|
|
}
|
|
|
|
const WString& ArgumentException::GetFunction()const
|
|
{
|
|
return function;
|
|
}
|
|
|
|
const WString& ArgumentException::GetName()const
|
|
{
|
|
return name;
|
|
}
|
|
|
|
/***********************************************************************
|
|
ParsingException
|
|
***********************************************************************/
|
|
|
|
ParsingException::ParsingException(const WString& _message, const WString& _expression, vint _position)
|
|
:Exception(_message)
|
|
,expression(_expression)
|
|
,position(_position)
|
|
{
|
|
}
|
|
|
|
const WString& ParsingException::GetExpression()const
|
|
{
|
|
return expression;
|
|
}
|
|
|
|
vint ParsingException::GetPosition()const
|
|
{
|
|
return position;
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\GLOBALSTORAGE.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
using namespace collections;
|
|
|
|
class GlobalStorageManager
|
|
{
|
|
public:
|
|
Ptr<Dictionary<WString, GlobalStorage*>> storages;
|
|
|
|
GlobalStorageManager()
|
|
{
|
|
}
|
|
};
|
|
|
|
GlobalStorageManager& GetGlobalStorageManager()
|
|
{
|
|
static GlobalStorageManager globalStorageManager;
|
|
return globalStorageManager;
|
|
}
|
|
|
|
/***********************************************************************
|
|
GlobalStorage
|
|
***********************************************************************/
|
|
|
|
GlobalStorage::GlobalStorage(const wchar_t* key)
|
|
{
|
|
InitializeGlobalStorage();
|
|
GetGlobalStorageManager().storages->Add(key, this);
|
|
}
|
|
|
|
GlobalStorage::~GlobalStorage()
|
|
{
|
|
}
|
|
|
|
bool GlobalStorage::Cleared()
|
|
{
|
|
return cleared;
|
|
}
|
|
|
|
/***********************************************************************
|
|
Helper Functions
|
|
***********************************************************************/
|
|
|
|
GlobalStorage* GetGlobalStorage(const wchar_t* key)
|
|
{
|
|
return GetGlobalStorage(WString(key, false));
|
|
}
|
|
|
|
GlobalStorage* GetGlobalStorage(const WString& key)
|
|
{
|
|
return GetGlobalStorageManager().storages->Get(key);
|
|
}
|
|
|
|
void InitializeGlobalStorage()
|
|
{
|
|
if (!GetGlobalStorageManager().storages)
|
|
{
|
|
GetGlobalStorageManager().storages = new Dictionary<WString, GlobalStorage*>;
|
|
}
|
|
}
|
|
|
|
void FinalizeGlobalStorage()
|
|
{
|
|
if (GetGlobalStorageManager().storages)
|
|
{
|
|
for (vint i = 0; i < GetGlobalStorageManager().storages->Count(); i++)
|
|
{
|
|
GetGlobalStorageManager().storages->Values().Get(i)->ClearResource();
|
|
}
|
|
GetGlobalStorageManager().storages = nullptr;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\STRING.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#if defined VCZH_MSVC
|
|
#elif defined VCZH_GCC
|
|
#include <stdio.h>
|
|
#include <ctype.h>
|
|
#include <wctype.h>
|
|
#define _strtoi64 strtoll
|
|
#define _strtoui64 strtoull
|
|
#define _wcstoi64 wcstoll
|
|
#define _wcstoui64 wcstoull
|
|
#endif
|
|
|
|
namespace vl
|
|
{
|
|
#if defined VCZH_GCC
|
|
void _itoa_s(vint32_t value, char* buffer, size_t size, vint radix)
|
|
{
|
|
sprintf(buffer, "%d", value);
|
|
}
|
|
|
|
void _itow_s(vint32_t value, wchar_t* buffer, size_t size, vint radix)
|
|
{
|
|
swprintf(buffer, size - 1, L"%d", value);
|
|
}
|
|
|
|
void _i64toa_s(vint64_t value, char* buffer, size_t size, vint radix)
|
|
{
|
|
sprintf(buffer, "%ld", value);
|
|
}
|
|
|
|
void _i64tow_s(vint64_t value, wchar_t* buffer, size_t size, vint radix)
|
|
{
|
|
swprintf(buffer, size - 1, L"%ld", value);
|
|
}
|
|
|
|
void _uitoa_s(vuint32_t value, char* buffer, size_t size, vint radix)
|
|
{
|
|
sprintf(buffer, "%u", value);
|
|
}
|
|
|
|
void _uitow_s(vuint32_t value, wchar_t* buffer, size_t size, vint radix)
|
|
{
|
|
swprintf(buffer, size - 1, L"%u", value);
|
|
}
|
|
|
|
void _ui64toa_s(vuint64_t value, char* buffer, size_t size, vint radix)
|
|
{
|
|
sprintf(buffer, "%lu", value);
|
|
}
|
|
|
|
void _ui64tow_s(vuint64_t value, wchar_t* buffer, size_t size, vint radix)
|
|
{
|
|
swprintf(buffer, size - 1, L"%lu", value);
|
|
}
|
|
|
|
void _gcvt_s(char* buffer, size_t size, double value, vint numberOfDigits)
|
|
{
|
|
sprintf(buffer, "%f", value);
|
|
char* point = strchr(buffer, '.');
|
|
if(!point) return;
|
|
char* zero = buffer + strlen(buffer);
|
|
while(zero[-1] == '0')
|
|
{
|
|
*--zero = '\0';
|
|
}
|
|
if(zero[-1] == '.') *--zero = '\0';
|
|
}
|
|
|
|
void _strlwr_s(char* buffer, size_t size)
|
|
{
|
|
while(*buffer)
|
|
{
|
|
*buffer=(char)tolower(*buffer);
|
|
buffer++;
|
|
}
|
|
}
|
|
|
|
void _strupr_s(char* buffer, size_t size)
|
|
{
|
|
while(*buffer)
|
|
{
|
|
*buffer=(char)toupper(*buffer);
|
|
buffer++;
|
|
}
|
|
}
|
|
|
|
void _wcslwr_s(wchar_t* buffer, size_t size)
|
|
{
|
|
while(*buffer)
|
|
{
|
|
*buffer=(char)towlower(*buffer);
|
|
buffer++;
|
|
}
|
|
}
|
|
|
|
void _wcsupr_s(wchar_t* buffer, size_t size)
|
|
{
|
|
while(*buffer)
|
|
{
|
|
*buffer=(char)towupper(*buffer);
|
|
buffer++;
|
|
}
|
|
}
|
|
|
|
void wcscpy_s(wchar_t* buffer, size_t size, const wchar_t* text)
|
|
{
|
|
wcscpy(buffer, text);
|
|
}
|
|
#endif
|
|
|
|
vint atoi_test(const AString& string, bool& success)
|
|
{
|
|
char* endptr = 0;
|
|
vint result = strtol(string.Buffer(), &endptr, 10);
|
|
success = endptr == string.Buffer() + string.Length() && itoa(result) == string;
|
|
return result;
|
|
}
|
|
|
|
vint wtoi_test(const WString& string, bool& success)
|
|
{
|
|
wchar_t* endptr = 0;
|
|
vint result = wcstol(string.Buffer(), &endptr, 10);
|
|
success = endptr == string.Buffer() + string.Length() && itow(result) == string;
|
|
return result;
|
|
}
|
|
|
|
vint64_t atoi64_test(const AString& string, bool& success)
|
|
{
|
|
char* endptr = 0;
|
|
vint64_t result = _strtoi64(string.Buffer(), &endptr, 10);
|
|
success = endptr == string.Buffer() + string.Length() && i64toa(result) == string;
|
|
return result;
|
|
}
|
|
|
|
vint64_t wtoi64_test(const WString& string, bool& success)
|
|
{
|
|
wchar_t* endptr = 0;
|
|
vint64_t result = _wcstoi64(string.Buffer(), &endptr, 10);
|
|
success = endptr == string.Buffer() + string.Length() && i64tow(result) == string;
|
|
return result;
|
|
}
|
|
|
|
vuint atou_test(const AString& string, bool& success)
|
|
{
|
|
char* endptr = 0;
|
|
vuint result = strtoul(string.Buffer(), &endptr, 10);
|
|
success = endptr == string.Buffer() + string.Length() && utoa(result) == string;
|
|
return result;
|
|
}
|
|
|
|
vuint wtou_test(const WString& string, bool& success)
|
|
{
|
|
wchar_t* endptr = 0;
|
|
vuint result = wcstoul(string.Buffer(), &endptr, 10);
|
|
success = endptr == string.Buffer() + string.Length() && utow(result) == string;
|
|
return result;
|
|
}
|
|
|
|
vuint64_t atou64_test(const AString& string, bool& success)
|
|
{
|
|
char* endptr = 0;
|
|
vuint64_t result = _strtoui64(string.Buffer(), &endptr, 10);
|
|
success = endptr == string.Buffer() + string.Length() && u64toa(result) == string;
|
|
return result;
|
|
}
|
|
|
|
vuint64_t wtou64_test(const WString& string, bool& success)
|
|
{
|
|
wchar_t* endptr = 0;
|
|
vuint64_t result = _wcstoui64(string.Buffer(), &endptr, 10);
|
|
success = endptr == string.Buffer() + string.Length() && u64tow(result) == string;
|
|
return result;
|
|
}
|
|
|
|
double atof_test(const AString& string, bool& success)
|
|
{
|
|
char* endptr = 0;
|
|
double result = strtod(string.Buffer(), &endptr);
|
|
success = endptr == string.Buffer() + string.Length();
|
|
return result;
|
|
}
|
|
|
|
double wtof_test(const WString& string, bool& success)
|
|
{
|
|
wchar_t* endptr = 0;
|
|
double result = wcstod(string.Buffer(), &endptr);
|
|
success = endptr == string.Buffer() + string.Length();
|
|
return result;
|
|
}
|
|
|
|
vint atoi(const AString& string)
|
|
{
|
|
bool success = false;
|
|
return atoi_test(string, success);
|
|
}
|
|
|
|
vint wtoi(const WString& string)
|
|
{
|
|
bool success = false;
|
|
return wtoi_test(string, success);
|
|
}
|
|
|
|
vint64_t atoi64(const AString& string)
|
|
{
|
|
bool success = false;
|
|
return atoi64_test(string, success);
|
|
}
|
|
|
|
vint64_t wtoi64(const WString& string)
|
|
{
|
|
bool success = false;
|
|
return wtoi64_test(string, success);
|
|
}
|
|
|
|
vuint atou(const AString& string)
|
|
{
|
|
bool success = false;
|
|
return atou_test(string, success);
|
|
}
|
|
|
|
vuint wtou(const WString& string)
|
|
{
|
|
bool success = false;
|
|
return wtou_test(string, success);
|
|
}
|
|
|
|
vuint64_t atou64(const AString& string)
|
|
{
|
|
bool success = false;
|
|
return atou64_test(string, success);
|
|
}
|
|
|
|
vuint64_t wtou64(const WString& string)
|
|
{
|
|
bool success = false;
|
|
return wtou64_test(string, success);
|
|
}
|
|
|
|
double atof(const AString& string)
|
|
{
|
|
bool success = false;
|
|
return atof_test(string, success);
|
|
}
|
|
|
|
double wtof(const WString& string)
|
|
{
|
|
bool success = false;
|
|
return wtof_test(string, success);
|
|
}
|
|
|
|
AString itoa(vint number)
|
|
{
|
|
char buffer[100];
|
|
ITOA_S(number, buffer, sizeof(buffer) / sizeof(*buffer), 10);
|
|
return buffer;
|
|
}
|
|
|
|
WString itow(vint number)
|
|
{
|
|
wchar_t buffer[100];
|
|
ITOW_S(number, buffer, sizeof(buffer) / sizeof(*buffer), 10);
|
|
return buffer;
|
|
}
|
|
|
|
AString i64toa(vint64_t number)
|
|
{
|
|
char buffer[100];
|
|
I64TOA_S(number, buffer, sizeof(buffer) / sizeof(*buffer), 10);
|
|
return buffer;
|
|
}
|
|
|
|
WString i64tow(vint64_t number)
|
|
{
|
|
wchar_t buffer[100];
|
|
I64TOW_S(number, buffer, sizeof(buffer) / sizeof(*buffer), 10);
|
|
return buffer;
|
|
}
|
|
|
|
AString utoa(vuint number)
|
|
{
|
|
char buffer[100];
|
|
UITOA_S(number, buffer, sizeof(buffer) / sizeof(*buffer), 10);
|
|
return buffer;
|
|
}
|
|
|
|
WString utow(vuint number)
|
|
{
|
|
wchar_t buffer[100];
|
|
UITOW_S(number, buffer, sizeof(buffer) / sizeof(*buffer), 10);
|
|
return buffer;
|
|
}
|
|
|
|
AString u64toa(vuint64_t number)
|
|
{
|
|
char buffer[100];
|
|
UI64TOA_S(number, buffer, sizeof(buffer) / sizeof(*buffer), 10);
|
|
return buffer;
|
|
}
|
|
|
|
WString u64tow(vuint64_t number)
|
|
{
|
|
wchar_t buffer[100];
|
|
UI64TOW_S(number, buffer, sizeof(buffer) / sizeof(*buffer), 10);
|
|
return buffer;
|
|
}
|
|
|
|
AString ftoa(double number)
|
|
{
|
|
char buffer[320];
|
|
_gcvt_s(buffer, 320, number, 30);
|
|
vint len = (vint)strlen(buffer);
|
|
if (buffer[len - 1] == '.')
|
|
{
|
|
buffer[len - 1] = '\0';
|
|
}
|
|
return buffer;
|
|
}
|
|
|
|
WString ftow(double number)
|
|
{
|
|
return atow(ftoa(number));
|
|
}
|
|
|
|
vint _wtoa(const wchar_t* w, char* a, vint chars)
|
|
{
|
|
#if defined VCZH_MSVC
|
|
return WideCharToMultiByte(CP_THREAD_ACP, 0, w, -1, a, (int)(a ? chars : 0), 0, 0);
|
|
#elif defined VCZH_GCC
|
|
return wcstombs(a, w, chars-1)+1;
|
|
#endif
|
|
}
|
|
|
|
AString wtoa(const WString& string)
|
|
{
|
|
vint len = _wtoa(string.Buffer(), 0, 0);
|
|
char* buffer = new char[len];
|
|
memset(buffer, 0, len*sizeof(*buffer));
|
|
_wtoa(string.Buffer(), buffer, (int)len);
|
|
AString s = buffer;
|
|
delete[] buffer;
|
|
return s;
|
|
}
|
|
|
|
vint _atow(const char* a, wchar_t* w, vint chars)
|
|
{
|
|
#if defined VCZH_MSVC
|
|
return MultiByteToWideChar(CP_THREAD_ACP, 0, a, -1, w, (int)(w ? chars : 0));
|
|
#elif defined VCZH_GCC
|
|
return mbstowcs(w, a, chars-1)+1;
|
|
#endif
|
|
}
|
|
|
|
WString atow(const AString& string)
|
|
{
|
|
vint len = _atow(string.Buffer(), 0, 0);
|
|
wchar_t* buffer = new wchar_t[len];
|
|
memset(buffer, 0, len*sizeof(*buffer));
|
|
_atow(string.Buffer(), buffer, (int)len);
|
|
WString s = buffer;
|
|
delete[] buffer;
|
|
return s;
|
|
}
|
|
|
|
AString alower(const AString& string)
|
|
{
|
|
AString result = string.Buffer();
|
|
_strlwr_s((char*)result.Buffer(), result.Length() + 1);
|
|
return result;
|
|
}
|
|
|
|
WString wlower(const WString& string)
|
|
{
|
|
WString result = string.Buffer();
|
|
_wcslwr_s((wchar_t*)result.Buffer(), result.Length() + 1);
|
|
return result;
|
|
}
|
|
|
|
AString aupper(const AString& string)
|
|
{
|
|
AString result = string.Buffer();
|
|
_strupr_s((char*)result.Buffer(), result.Length() + 1);
|
|
return result;
|
|
}
|
|
|
|
WString wupper(const WString& string)
|
|
{
|
|
WString result = string.Buffer();
|
|
_wcsupr_s((wchar_t*)result.Buffer(), result.Length() + 1);
|
|
return result;
|
|
}
|
|
|
|
WString LoremIpsum(vint bestLength, LoremIpsumCasing casing)
|
|
{
|
|
static const wchar_t* words[] =
|
|
{
|
|
L"lorem", L"ipsum", L"dolor", L"sit", L"amet", L"consectetur", L"adipiscing", L"elit", L"integer",
|
|
L"nec", L"odio", L"praesent", L"libero", L"sed", L"cursus", L"ante", L"dapibus", L"diam",
|
|
L"sed", L"nisi", L"nulla", L"quis", L"sem", L"at", L"nibh", L"elementum", L"imperdiet", L"duis",
|
|
L"sagittis", L"ipsum", L"praesent", L"mauris", L"fusce", L"nec", L"tellus", L"sed", L"augue",
|
|
L"semper", L"porta", L"mauris", L"massa", L"vestibulum", L"lacinia", L"arcu", L"eget", L"nulla",
|
|
L"class", L"aptent", L"taciti", L"sociosqu", L"ad", L"litora", L"torquent", L"per", L"conubia",
|
|
L"nostra", L"per", L"inceptos", L"himenaeos", L"curabitur", L"sodales", L"ligula", L"in",
|
|
L"libero", L"sed", L"dignissim", L"lacinia", L"nunc", L"curabitur", L"tortor", L"pellentesque",
|
|
L"nibh", L"aenean", L"quam", L"in", L"scelerisque", L"sem", L"at", L"dolor", L"maecenas",
|
|
L"mattis", L"sed", L"convallis", L"tristique", L"sem", L"proin", L"ut", L"ligula", L"vel",
|
|
L"nunc", L"egestas", L"porttitor", L"morbi", L"lectus", L"risus", L"iaculis", L"vel", L"suscipit",
|
|
L"quis", L"luctus", L"non", L"massa", L"fusce", L"ac", L"turpis", L"quis", L"ligula", L"lacinia",
|
|
L"aliquet", L"mauris", L"ipsum", L"nulla", L"metus", L"metus", L"ullamcorper", L"vel", L"tincidunt",
|
|
L"sed", L"euismod", L"in", L"nibh", L"quisque", L"volutpat", L"condimentum", L"velit", L"class",
|
|
L"aptent", L"taciti", L"sociosqu", L"ad", L"litora", L"torquent", L"per", L"conubia", L"nostra",
|
|
L"per", L"inceptos", L"himenaeos", L"nam", L"nec", L"ante", L"sed", L"lacinia", L"urna",
|
|
L"non", L"tincidunt", L"mattis", L"tortor", L"neque", L"adipiscing", L"diam", L"a", L"cursus",
|
|
L"ipsum", L"ante", L"quis", L"turpis", L"nulla", L"facilisi", L"ut", L"fringilla", L"suspendisse",
|
|
L"potenti", L"nunc", L"feugiat", L"mi", L"a", L"tellus", L"consequat", L"imperdiet", L"vestibulum",
|
|
L"sapien", L"proin", L"quam", L"etiam", L"ultrices", L"suspendisse", L"in", L"justo", L"eu",
|
|
L"magna", L"luctus", L"suscipit", L"sed", L"lectus", L"integer", L"euismod", L"lacus", L"luctus",
|
|
L"magna", L"quisque", L"cursus", L"metus", L"vitae", L"pharetra", L"auctor", L"sem", L"massa",
|
|
L"mattis", L"sem", L"at", L"interdum", L"magna", L"augue", L"eget", L"diam", L"vestibulum",
|
|
L"ante", L"ipsum", L"primis", L"in", L"faucibus", L"orci", L"luctus", L"et", L"ultrices",
|
|
L"posuere", L"cubilia", L"curae;", L"morbi", L"lacinia", L"molestie", L"dui", L"praesent",
|
|
L"blandit", L"dolor", L"sed", L"non", L"quam", L"in", L"vel", L"mi", L"sit", L"amet", L"augue",
|
|
L"congue", L"elementum", L"morbi", L"in", L"ipsum", L"sit", L"amet", L"pede", L"facilisis",
|
|
L"laoreet", L"donec", L"lacus", L"nunc", L"viverra", L"nec", L"blandit", L"vel", L"egestas",
|
|
L"et", L"augue", L"vestibulum", L"tincidunt", L"malesuada", L"tellus", L"ut", L"ultrices",
|
|
L"ultrices", L"enim", L"curabitur", L"sit", L"amet", L"mauris", L"morbi", L"in", L"dui",
|
|
L"quis", L"est", L"pulvinar", L"ullamcorper", L"nulla", L"facilisi", L"integer", L"lacinia",
|
|
L"sollicitudin", L"massa", L"cras", L"metus", L"sed", L"aliquet", L"risus", L"a", L"tortor",
|
|
L"integer", L"id", L"quam", L"morbi", L"mi", L"quisque", L"nisl", L"felis", L"venenatis",
|
|
L"tristique", L"dignissim", L"in", L"ultrices", L"sit", L"amet", L"augue", L"proin", L"sodales",
|
|
L"libero", L"eget", L"ante", L"nulla", L"quam", L"aenean", L"laoreet", L"vestibulum", L"nisi",
|
|
L"lectus", L"commodo", L"ac", L"facilisis", L"ac", L"ultricies", L"eu", L"pede", L"ut", L"orci",
|
|
L"risus", L"accumsan", L"porttitor", L"cursus", L"quis", L"aliquet", L"eget", L"justo",
|
|
L"sed", L"pretium", L"blandit", L"orci", L"ut", L"eu", L"diam", L"at", L"pede", L"suscipit",
|
|
L"sodales", L"aenean", L"lectus", L"elit", L"fermentum", L"non", L"convallis", L"id", L"sagittis",
|
|
L"at", L"neque", L"nullam", L"mauris", L"orci", L"aliquet", L"et", L"iaculis", L"et", L"viverra",
|
|
L"vitae", L"ligula", L"nulla", L"ut", L"felis", L"in", L"purus", L"aliquam", L"imperdiet",
|
|
L"maecenas", L"aliquet", L"mollis", L"lectus", L"vivamus", L"consectetuer", L"risus", L"et",
|
|
L"tortor"
|
|
};
|
|
static vint index = 0;
|
|
const vint WordCount = sizeof(words) / sizeof(*words);
|
|
|
|
if (bestLength < 0) bestLength = 0;
|
|
vint bufferLength = bestLength + 20;
|
|
wchar_t* buffer = new wchar_t[bufferLength + 1];
|
|
|
|
buffer[0] = 0;
|
|
vint used = 0;
|
|
wchar_t* writing = buffer;
|
|
while (used < bestLength)
|
|
{
|
|
if (used != 0)
|
|
{
|
|
*writing++ = L' ';
|
|
used++;
|
|
}
|
|
|
|
vint wordSize = (vint)wcslen(words[index]);
|
|
wcscpy_s(writing, bufferLength - used, words[index]);
|
|
if (casing == LoremIpsumCasing::AllWordsUpperCase || (casing == LoremIpsumCasing::FirstWordUpperCase && used == 0))
|
|
{
|
|
*writing -= L'a' - L'A';
|
|
}
|
|
|
|
if (used != 0 && used + wordSize > bestLength)
|
|
{
|
|
vint deltaShort = bestLength - used + 1;
|
|
vint deltaLong = used + wordSize - bestLength;
|
|
if (deltaShort < deltaLong)
|
|
{
|
|
*--writing = 0;
|
|
used--;
|
|
break;
|
|
}
|
|
}
|
|
writing += wordSize;
|
|
used += wordSize;
|
|
index = (index + 1) % WordCount;
|
|
}
|
|
|
|
WString result = buffer;
|
|
delete[] buffer;
|
|
return result;
|
|
}
|
|
|
|
WString LoremIpsumTitle(vint bestLength)
|
|
{
|
|
return LoremIpsum(bestLength, LoremIpsumCasing::AllWordsUpperCase);
|
|
}
|
|
|
|
WString LoremIpsumSentence(vint bestLength)
|
|
{
|
|
return LoremIpsum(bestLength, LoremIpsumCasing::FirstWordUpperCase) + L".";
|
|
}
|
|
|
|
WString LoremIpsumParagraph(vint bestLength)
|
|
{
|
|
srand((unsigned)time(0));
|
|
auto casing = LoremIpsumCasing::FirstWordUpperCase;
|
|
vint comma = 0;
|
|
WString result;
|
|
while (result.Length() < bestLength)
|
|
{
|
|
vint offset = bestLength - result.Length();
|
|
if (comma == 0)
|
|
{
|
|
comma = rand() % 4 + 1;
|
|
}
|
|
vint length = rand() % 45 + 15;
|
|
if (offset < 20)
|
|
{
|
|
comma = 0;
|
|
length = offset - 1;
|
|
}
|
|
else if (length > offset)
|
|
{
|
|
comma = 0;
|
|
length = offset + rand() % 11 - 5;
|
|
}
|
|
|
|
result += LoremIpsum(length, casing);
|
|
if (comma == 0)
|
|
{
|
|
result += L".";
|
|
break;
|
|
}
|
|
else if (comma == 1)
|
|
{
|
|
result += L". ";
|
|
casing = LoremIpsumCasing::FirstWordUpperCase;
|
|
}
|
|
else
|
|
{
|
|
result += L", ";
|
|
casing = LoremIpsumCasing::AllWordsLowerCase;
|
|
}
|
|
comma--;
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
|
|
|
|
/***********************************************************************
|
|
.\COLLECTIONS\PARTIALORDERING.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
|
|
namespace vl
|
|
{
|
|
namespace collections
|
|
{
|
|
using namespace po;
|
|
|
|
/***********************************************************************
|
|
PartialOrderingProcessor
|
|
***********************************************************************/
|
|
|
|
void PartialOrderingProcessor::InitNodes(vint itemCount)
|
|
{
|
|
nodes.Resize(itemCount);
|
|
|
|
for (vint i = 0; i < itemCount; i++)
|
|
{
|
|
auto& node = nodes[i];
|
|
node.ins = &emptyList;
|
|
node.outs = &emptyList;
|
|
|
|
vint inIndex = ins.Keys().IndexOf(i);
|
|
vint outIndex = outs.Keys().IndexOf(i);
|
|
|
|
if (inIndex != -1)
|
|
{
|
|
node.ins = &ins.GetByIndex(inIndex);
|
|
}
|
|
if (outIndex != -1)
|
|
{
|
|
node.outs = &outs.GetByIndex(outIndex);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PartialOrderingProcessor::VisitUnvisitedNode(po::Node& node, Array<vint>& reversedOrder, vint& used)
|
|
{
|
|
node.visited = true;
|
|
for (vint i = node.outs->Count() - 1; i >= 0; i--)
|
|
{
|
|
auto& outNode = nodes[node.outs->Get(i)];
|
|
if (!outNode.visited)
|
|
{
|
|
VisitUnvisitedNode(outNode, reversedOrder, used);
|
|
}
|
|
}
|
|
reversedOrder[used++] = (vint)(&node - &nodes[0]);
|
|
}
|
|
|
|
void PartialOrderingProcessor::AssignUnassignedNode(po::Node& node, vint componentIndex, vint& used)
|
|
{
|
|
node.component = componentIndex;
|
|
firstNodesBuffer[used++] = (vint)(&node - &nodes[0]);
|
|
for (vint i = 0; i < node.ins->Count(); i++)
|
|
{
|
|
auto& inNode = nodes[node.ins->Get(i)];
|
|
if (inNode.component == -1)
|
|
{
|
|
AssignUnassignedNode(inNode, componentIndex, used);
|
|
}
|
|
}
|
|
}
|
|
|
|
void PartialOrderingProcessor::Sort()
|
|
{
|
|
// Kosaraju's Algorithm
|
|
CHECK_ERROR(components.Count() == 0, L"PartialOrdering::Sort()#Sorting twice is not allowed.");
|
|
|
|
Array<vint> reversedOrder(nodes.Count());
|
|
{
|
|
vint used = 0;
|
|
for (vint i = nodes.Count() - 1; i >= 0; i--)
|
|
{
|
|
auto& node = nodes[i];
|
|
if (!node.visited)
|
|
{
|
|
VisitUnvisitedNode(node, reversedOrder, used);
|
|
}
|
|
}
|
|
}
|
|
|
|
firstNodesBuffer.Resize(nodes.Count());
|
|
{
|
|
vint lastUsed = 0;
|
|
vint used = 0;
|
|
for (vint i = reversedOrder.Count() - 1; i >= 0; i--)
|
|
{
|
|
auto& node = nodes[reversedOrder[i]];
|
|
if (node.component == -1)
|
|
{
|
|
AssignUnassignedNode(node, components.Count(), used);
|
|
|
|
Component component;
|
|
component.firstNode = &firstNodesBuffer[lastUsed];
|
|
component.nodeCount = used - lastUsed;
|
|
lastUsed = used;
|
|
components.Add(component);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/***********************************************************************
|
|
.\UNITTEST\UNITTEST.CPP
|
|
***********************************************************************/
|
|
/***********************************************************************
|
|
Author: Zihan Chen (vczh)
|
|
Licensed under https://github.com/vczh-libraries/License
|
|
***********************************************************************/
|
|
|
|
#ifdef VCZH_MSVC
|
|
#endif
|
|
|
|
namespace vl
|
|
{
|
|
namespace unittest
|
|
{
|
|
using namespace vl::console;
|
|
|
|
/***********************************************************************
|
|
UnitTest
|
|
***********************************************************************/
|
|
|
|
namespace execution_impl
|
|
{
|
|
struct UnitTestLink
|
|
{
|
|
const char* fileName;
|
|
UnitTestFileProc testProc = nullptr;
|
|
UnitTestLink* next = nullptr;
|
|
};
|
|
UnitTestLink* testHead = nullptr;
|
|
UnitTestLink** testTail = &testHead;
|
|
|
|
enum class UnitTestContextKind
|
|
{
|
|
File,
|
|
Category,
|
|
Case,
|
|
};
|
|
|
|
struct UnitTestContext
|
|
{
|
|
UnitTestContext* parent = nullptr;
|
|
WString indentation;
|
|
UnitTestContextKind kind = UnitTestContextKind::File;
|
|
bool failed = false;
|
|
};
|
|
|
|
UnitTestContext* testContext = nullptr;
|
|
vint totalFiles = 0;
|
|
vint passedFiles = 0;
|
|
vint totalCases = 0;
|
|
vint passedCases = 0;
|
|
bool suppressFailure = false;
|
|
|
|
template<typename TMessage>
|
|
void RecordFailure(TMessage errorMessage)
|
|
{
|
|
UnitTest::PrintMessage(errorMessage, UnitTest::MessageKind::Error);
|
|
auto current = testContext;
|
|
while (current)
|
|
{
|
|
current->failed = true;
|
|
current = current->parent;
|
|
}
|
|
}
|
|
|
|
template<typename TCallback>
|
|
void SuppressCppFailure(TCallback&& callback)
|
|
{
|
|
try
|
|
{
|
|
callback();
|
|
}
|
|
catch (const UnitTestAssertError& e)
|
|
{
|
|
RecordFailure(e.message);
|
|
}
|
|
catch (const UnitTestConfigError& e)
|
|
{
|
|
RecordFailure(e.message);
|
|
}
|
|
catch (const Error& e)
|
|
{
|
|
RecordFailure(e.Description());
|
|
}
|
|
catch (const Exception& e)
|
|
{
|
|
RecordFailure(e.Message());
|
|
}
|
|
catch (...)
|
|
{
|
|
RecordFailure(L"Unknown exception occurred!");
|
|
}
|
|
}
|
|
|
|
template<typename TCallback>
|
|
void SuppressCFailure(TCallback&& callback)
|
|
{
|
|
#ifdef VCZH_MSVC
|
|
__try
|
|
{
|
|
SuppressCppFailure(ForwardValue<TCallback&&>(callback));
|
|
}
|
|
__except (EXCEPTION_EXECUTE_HANDLER)
|
|
{
|
|
RecordFailure(L"Runtime exception occurred!");
|
|
}
|
|
#else
|
|
SuppressCppFailure(callback);
|
|
#endif
|
|
}
|
|
|
|
template<typename TCallback>
|
|
void ExecuteAndSuppressFailure(TCallback&& callback)
|
|
{
|
|
if (suppressFailure)
|
|
{
|
|
SuppressCFailure(ForwardValue<TCallback&&>(callback));
|
|
}
|
|
else
|
|
{
|
|
callback();
|
|
}
|
|
}
|
|
}
|
|
using namespace execution_impl;
|
|
|
|
void UnitTest::PrintMessage(const WString& string, MessageKind kind)
|
|
{
|
|
if (kind != MessageKind::Error && !testContext)
|
|
{
|
|
throw UnitTestConfigError(L"Cannot print message when unit test is not running.");
|
|
}
|
|
|
|
switch (kind)
|
|
{
|
|
case MessageKind::Error:
|
|
Console::SetColor(true, false, false, true);
|
|
break;
|
|
case MessageKind::Info:
|
|
Console::SetColor(true, true, true, true);
|
|
break;
|
|
case MessageKind::File:
|
|
Console::SetColor(true, false, true, true);
|
|
break;
|
|
case MessageKind::Category:
|
|
Console::SetColor(true, true, false, true);
|
|
break;
|
|
case MessageKind::Case:
|
|
Console::SetColor(false, true, false, true);
|
|
break;
|
|
}
|
|
Console::WriteLine((testContext ? testContext->indentation : L"") + string);
|
|
Console::SetColor(true, true, true, false);
|
|
}
|
|
|
|
#ifdef VCZH_MSVC
|
|
int UnitTest::RunAndDisposeTests(int argc, wchar_t* argv[])
|
|
#else
|
|
int UnitTest::RunAndDisposeTests(int argc, char* argv[])
|
|
#endif
|
|
{
|
|
if (argc < 3)
|
|
{
|
|
if (argc == 2)
|
|
{
|
|
#ifdef VCZH_MSVC
|
|
WString option = argv[1];
|
|
#else
|
|
WString option = atow(argv[1]);
|
|
#endif
|
|
if (option == L"/D")
|
|
{
|
|
suppressFailure = false;
|
|
}
|
|
else if (option == L"/R")
|
|
{
|
|
suppressFailure = true;
|
|
}
|
|
else
|
|
{
|
|
goto PRINT_USAGE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef VCZH_MSVC
|
|
if (IsDebuggerPresent())
|
|
{
|
|
suppressFailure = false;
|
|
}
|
|
else
|
|
{
|
|
suppressFailure = true;
|
|
}
|
|
#else
|
|
suppressFailure = true;
|
|
#endif
|
|
}
|
|
|
|
auto current = testHead;
|
|
testHead = nullptr;
|
|
testTail = nullptr;
|
|
|
|
UnitTestContext context;
|
|
testContext = &context;
|
|
totalFiles = 0;
|
|
passedFiles = 0;
|
|
totalCases = 0;
|
|
passedCases = 0;
|
|
|
|
if (suppressFailure)
|
|
{
|
|
PrintMessage(L"Failures are suppressed.", MessageKind::Info);
|
|
}
|
|
else
|
|
{
|
|
PrintMessage(L"Failures are not suppressed.", MessageKind::Info);
|
|
}
|
|
|
|
while (current)
|
|
{
|
|
context.failed = false;
|
|
PrintMessage(atow(current->fileName), MessageKind::File);
|
|
context.indentation = L" ";
|
|
ExecuteAndSuppressFailure(current->testProc);
|
|
if (!testContext->failed) passedFiles++;
|
|
totalFiles++;
|
|
context.indentation = L"";
|
|
auto temp = current;
|
|
current = current->next;
|
|
delete temp;
|
|
}
|
|
|
|
bool passed = totalFiles == passedFiles;
|
|
auto messageKind = passed ? MessageKind::Case : MessageKind::Error;
|
|
PrintMessage(L"Passed test files: " + itow(passedFiles) + L"/" + itow(totalFiles), messageKind);
|
|
PrintMessage(L"Passed test cases: " + itow(passedCases) + L"/" + itow(totalCases), messageKind);
|
|
testContext = nullptr;
|
|
return passed ? 0 : 1;
|
|
}
|
|
PRINT_USAGE:
|
|
PrintMessage(L"Usage: [/D | /R]", MessageKind::Error);
|
|
return 1;
|
|
}
|
|
|
|
void UnitTest::RegisterTestFile(const char* fileName, UnitTestFileProc testProc)
|
|
{
|
|
auto link = new UnitTestLink;
|
|
link->fileName = fileName;
|
|
link->testProc = testProc;
|
|
*testTail = link;
|
|
testTail = &link->next;
|
|
}
|
|
|
|
void UnitTest::RunCategoryOrCase(const WString& description, bool isCategory, Func<void()>&& callback)
|
|
{
|
|
if (!testContext) throw UnitTestConfigError(L"TEST_CATEGORY is not allowed to execute outside of TEST_FILE.");
|
|
if (testContext->kind == UnitTestContextKind::Case) throw UnitTestConfigError(
|
|
isCategory ?
|
|
L"TEST_CATEGORY is not allowed to execute inside TEST_CASE" :
|
|
L"TEST_CASE is not allowed to execute inside TEST_CASE");
|
|
|
|
PrintMessage(description, (isCategory ? MessageKind::Category : MessageKind::Case));
|
|
|
|
UnitTestContext context;
|
|
context.parent = testContext;
|
|
context.indentation = testContext->indentation + L" ";
|
|
context.kind = isCategory ? UnitTestContextKind::Category : UnitTestContextKind::Case;
|
|
|
|
testContext = &context;
|
|
ExecuteAndSuppressFailure(callback);
|
|
if (!isCategory)
|
|
{
|
|
if (!testContext->failed) passedCases++;
|
|
totalCases++;
|
|
}
|
|
testContext = context.parent;
|
|
}
|
|
|
|
void UnitTest::EnsureLegalToAssert()
|
|
{
|
|
if (!testContext) throw UnitTestConfigError(L"Assertion is not allowed to execute outside of TEST_CASE.");
|
|
if (testContext->kind != UnitTestContextKind::Case) throw UnitTestConfigError(L"Assertion is not allowed to execute outside of TEST_CASE.");
|
|
}
|
|
}
|
|
}
|
|
|