Precommit (#1)

* first commit

* cleanup
This commit is contained in:
tompzf
2025-11-04 13:28:06 +01:00
committed by GitHub
parent dba45dc636
commit 6ed4b1534e
898 changed files with 256340 additions and 0 deletions

View File

@@ -0,0 +1,45 @@
#include "../../global/exec_dir_helper.h"
#include <filesystem>
inline std::filesystem::path GetRootDirectory()
{
std::filesystem::path path = GetExecDirectory();
std::filesystem::path root = path.root_path();
// Check for three existing directories: sdv_services, export and tests. This is the root!
do
{
if (!std::filesystem::exists(path / "sdv_services"))
continue;
if (!std::filesystem::exists(path / "export"))
continue;
if (!std::filesystem::exists(path / "tests"))
continue;
// Root directory found
break;
} while ((path = path.parent_path()), path != root);
;
return path;
}
inline std::filesystem::path GetConfigFilePath(const std::filesystem::path& filename)
{
return GetExecDirectory() / "config" / filename;
}
inline std::string GetConfigFile(const std::filesystem::path& filename)
{
std::filesystem::path configPath = GetConfigFilePath(filename);
std::ifstream inputStream(configPath);
std::string configFileContent((std::istreambuf_iterator<char>(inputStream)), std::istreambuf_iterator<char>());
return configFileContent;
}
inline std::string GetRepositoryServiceModulePath()
{
std::filesystem::path currentPath = GetExecDirectory() / "../../bin/repository_service.sdv";
return currentPath.generic_u8string();
}

View File

@@ -0,0 +1,59 @@
#ifndef GTEST_CUSTOM_H
#define GTEST_CUSTOM_H
#ifdef _MSC_VER
#pragma warning(disable: 4102)
#endif
#define GTEST_HAS_EXCEPTIONS 1
#include <gtest/gtest.h>
#include <iostream>
#include <algorithm>
#include <math.h>
#ifndef countof
/**
* @brief Count the amount of elements in the array.
* @tparam T Array base type.
* @tparam N The amount of elements.
* @return The amount of elements in the array.
*/
template <typename T, int N>
constexpr int countof(T const (&)[N]) noexcept
{
return N;
}
#endif
/**
* @brief Equality test macro for container functions.
*/
#define EXPECT_ARREQ(val1, ...) { bool b = val1 == decltype(val1)({__VA_ARGS__}); EXPECT_TRUE(b); }
/**
* @brief Unequality test macro for container functions.
*/
#define EXPECT_ARRNE(val1, ...) { bool b = val1 == decltype(val1)({__VA_ARGS__}); EXPECT_FALSE(b); }
/**
* @brief Check for equality fo floating point values.
*/
#define EXPECT_FPEQ(val1, val2) EXPECT_TRUE(std::fabs(val1 - val2) < std::numeric_limits<decltype(val1)>::epsilon());
#include "simple_cpp_decomposer.h"
/**
* @brief Compare CPP code for equality.
*/
#define EXPECT_CPPEQ(s1, s2) \
EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperCPPEQ, s1, s2)
/**
* @brief Compare CPP code for inequality.
*/
#define EXPECT_CPPNE(s1, s2) \
EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperCPPNE, s1, s2)
#endif // ! defined GTEST_CUSTOM_H

View File

@@ -0,0 +1,112 @@
#if defined(_WIN32)
#include "../../global/exec_dir_helper.h"
inline int GetLoggerFilesCount(const std::string& prefix)
{
int count = 0;
std::string path = GetExecDirectory().generic_string();
for (const auto& entry : std::filesystem::directory_iterator(path))
{
std::string filename = entry.path().filename().generic_string().c_str();
if (filename.rfind(prefix, 0) == 0)
{
count++;
}
}
return count;
}
inline void DeleteLoggerFile(const std::string& filename)
{
auto path = GetExecDirectory() / filename;
try
{
std::filesystem::remove(path);
} catch (const std::filesystem::filesystem_error&)
{}
}
inline uint32_t GetErrorCountFromLogFile(const std::string& filename)
{
uint32_t errorCount = 0;
auto path = GetExecDirectory() / filename;
std::ifstream infile(path);
if (infile.is_open())
{
std::string line;
while (std::getline(infile, line))
{
size_t foundStart = line.find("Error;");
if (foundStart != std::string::npos)
{
std::cout << line << std::endl;
errorCount++;
}
}
}
if (errorCount != 0)
{
std::cout << "Checking " << filename << ", found: " << std::to_string(errorCount) << std::endl;
}
return errorCount;
}
inline bool FileNameStartsWith(const std::string& fileName, const std::string& startOfLogName)
{
if (!startOfLogName.empty())
{
if (fileName.rfind(startOfLogName, 0) != 0) // returns std::string::npos (i.e. not found)
{
return false;
}
}
return true;
}
inline uint32_t GetStringCountFromLogFiles(const std::string& startOfLogName, const std::string& subString)
{
uint32_t errorCount = 0;
auto path = GetExecDirectory();
for (const auto& entry : std::filesystem::directory_iterator(path))
{
if ((entry.path().extension() == ".log") &&
(FileNameStartsWith(entry.path().filename().string(), startOfLogName)))
{
std::ifstream infile(entry.path());
if (infile.is_open())
{
std::string line;
while (std::getline(infile, line))
{
size_t foundStart = line.find(subString);
if (foundStart != std::string::npos)
{
errorCount++;
}
}
infile.close();
}
}
}
return errorCount;
}
inline uint32_t GetErrorCountFromLogFiles(const std::string& logName) { return GetStringCountFromLogFiles(logName, ";Error;"); }
inline uint32_t GetWarningCountFromLogFiles(const std::string& logName) { return GetStringCountFromLogFiles(logName, "Warning;"); }
inline uint32_t GetTraceCountFromLogFiles(const std::string& logName) { return GetStringCountFromLogFiles(logName, "Trace;"); }
#else
inline int GetLoggerFilesCount(const std::string& ) { return 0; }
inline void DeleteLoggerFile(const std::string& ) { return; }
inline uint32_t GetErrorCountFromLogFile(const std::string&) { return 0; }
inline uint32_t GetErrorCountFromLogFiles(const std::string&) { return 0; }
inline uint32_t GetWarningCountFromLogFiles(const std::string&) { return 0; }
inline uint32_t GetTraceCountFromLogFiles(const std::string&) { return 0; }
#endif

View File

@@ -0,0 +1,96 @@
#ifndef SIMPLE_CPP_DECOMPOSER_H
#define SIMPLE_CPP_DECOMPOSER_H
#include <list>
#include <string>
/**
* @brief Decomposes C++ code into text chunks. Supports simple grammar.
*/
class CSimpleCppDecomposer
{
public:
/**
* @brief Constructor
* @param[in] rssCppCode Reference to the source code to decompose.
*/
CSimpleCppDecomposer(const std::string& rssCppCode);
/**
* @brief Get the list of decomposed source code chunks.
* @return A reference to the list of source code chunks.
*/
const std::list<std::string>& GetDecomposedCode() const;
/**
* @brief Compare with another decomposed code for equality.
* @param[in] rdecompChunk Reference to the decomposed chunk of code to use for this comparison.
* @return Returns 'true' when equal; 'false' when not.
*/
bool operator==(const CSimpleCppDecomposer& rdecompChunk) const;
/**
* @brief Compare with another decomposed code for un-equality.
* @param[in] rdecompChunk Reference to the decomposed chunk of code to use for this comparison.
* @return Returns 'true' when not equal; 'false' when equal.
*/
bool operator!=(const CSimpleCppDecomposer& rdecompChunk) const;
private:
/**
* @brief Iterate through the source code collecting the source code chunks.
*/
void Process();
/**
* @brief Skip whitespace
*/
void SkipWhitespace();
/**
* @brief Skip the rest of the line.
*/
void SkipLine();
/**
*@brief Skip C-comments.
*/
void SkipComment();
/**
* @brief Process text and numbers
*/
void ProcessText();
/**
* @brief Process strings
*/
void ProcessString();
/**
* @brief Process symbols.
*/
void ProcessSymbol();
std::string m_ssCode; ///< Current position within the source code.
size_t m_nPos = 0; ///< The current position.
std::list<std::string> m_lstCode; ///< Decomposed code.
bool m_bNewLine = true; ///< Set when a new line has occurred (ignoring any whitespace).
};
namespace testing::internal
{
// Additional helpers for testing C++ code
GTEST_API_ AssertionResult CmpHelperCPPEQ(const char* szLeftExpression, const char* szRightExpression,
const char* szLeft, const char* szRight);
GTEST_API_ AssertionResult CmpHelperCPPNE(const char* szLeftExpression, const char* szRightExpression,
const char* szLeft, const char* szRight);
GTEST_API_ AssertionResult CmpHelperCPPEQ(const char* szLeftExpression, const char* szRightExpression,
const std::string& rssLeft, const std::string& rssRight);
GTEST_API_ AssertionResult CmpHelperCPPNE(const char* szLeftExpression, const char* szRightExpression,
const std::string& rssLeft, const std::string& rssRight);
}
#include "simple_cpp_decomposer.inl"
#endif //! SIMPLE_CPP_DECOMPOSER_H

View File

@@ -0,0 +1,241 @@
#ifndef SIMPLE_CPP_DECOMPOSER_INL
#define SIMPLE_CPP_DECOMPOSER_INL
#ifndef SIMPLE_CPP_DECOMPOSER_H
#error Do not include "simple_cpp_composer.inl" directly. Include "simple_cpp_composer.h" instead!
#endif
#include <cassert>
namespace testing::internal
{
// Additional helpers for testing C++ code
inline GTEST_API_ AssertionResult CmpHelperCPPEQ(const char* szLeftExpression, const char* szRightExpression,
const char* szLeft, const char* szRight)
{
if (CSimpleCppDecomposer(szLeft) == CSimpleCppDecomposer(szRight))
{
return AssertionSuccess();
}
return EqFailure(szLeftExpression, szRightExpression, PrintToString(szLeft), PrintToString(szRight), false);
}
inline GTEST_API_ AssertionResult CmpHelperCPPNE(const char* szLeftExpression, const char* szRightExpression,
const char* szLeft, const char* szRight)
{
if (CSimpleCppDecomposer(szLeft) != CSimpleCppDecomposer(szRight))
{
return AssertionSuccess();
}
return EqFailure(szLeftExpression, szRightExpression, PrintToString(szLeft), PrintToString(szRight), false);
}
inline GTEST_API_ AssertionResult CmpHelperCPPEQ(const char* szLeftExpression, const char* szRightExpression,
const std::string& rssLeft, const std::string& rssRight)
{
if (CSimpleCppDecomposer(rssLeft) == CSimpleCppDecomposer(rssRight))
{
return AssertionSuccess();
}
return EqFailure(szLeftExpression, szRightExpression, PrintToString(rssLeft), PrintToString(rssRight), false);
}
inline GTEST_API_ AssertionResult CmpHelperCPPNE(const char* szLeftExpression, const char* szRightExpression,
const std::string& rssLeft, const std::string& rssRight)
{
if (CSimpleCppDecomposer(rssLeft) != CSimpleCppDecomposer(rssRight))
{
return AssertionSuccess();
}
return EqFailure(szLeftExpression, szRightExpression, PrintToString(rssLeft), PrintToString(rssRight), false);
}
}
inline CSimpleCppDecomposer::CSimpleCppDecomposer(const std::string& rssCppCode) : m_ssCode(rssCppCode)
{
Process();
}
inline const std::list<std::string>& CSimpleCppDecomposer::GetDecomposedCode() const
{
return m_lstCode;
}
inline bool CSimpleCppDecomposer::operator==(const CSimpleCppDecomposer& rdecompChunk) const
{
return m_lstCode == rdecompChunk.GetDecomposedCode();
}
inline bool CSimpleCppDecomposer::operator!=(const CSimpleCppDecomposer& rdecompChunk) const
{
return m_lstCode != rdecompChunk.GetDecomposedCode();
}
inline void CSimpleCppDecomposer::Process()
{
while (m_nPos < m_ssCode.size())
{
// First skip whitespace...
SkipWhitespace();
if (m_nPos >= m_ssCode.size()) break;
// Check for preproc directives... skip those
if (m_ssCode[m_nPos] == '#')
{
SkipLine();
continue;
}
// Check for comment
if (m_ssCode[m_nPos] == '/' && (m_ssCode[m_nPos + 1] == '/' || m_ssCode[m_nPos + 1] == '*'))
{
SkipComment();
continue;
}
// If the current character represents an underscore a string or a number, it is a keyword, variable, prefix or a number.
if (std::isalnum(m_ssCode[m_nPos]) || m_ssCode[m_nPos] == '_')
{
ProcessText();
continue;
}
// If the current character represents a quote (single or double), it is a string or a character.
// NOTE: Cannot deal with raw strings
if (m_ssCode[m_nPos] == '\"' || m_ssCode[m_nPos] == '\'')
{
ProcessString();
continue;
}
// If the current character is anything else, it represents a symbol.
ProcessSymbol();
}
}
inline void CSimpleCppDecomposer::SkipWhitespace()
{
while (m_nPos < m_ssCode.size() && std::isspace(m_ssCode[m_nPos]))
{
// Skip concatinating lines (not setting the new line flag).
if (m_ssCode[m_nPos] == '\\' && m_ssCode[m_nPos + 1] == '\r' && m_ssCode[m_nPos + 2] == '\n')
{
m_nPos += 3;
continue;
}
else if (m_ssCode[m_nPos] == '\\' && m_ssCode[m_nPos + 2] == '\n')
{
m_nPos += 2;
continue;
}
// Remember the new line
if (m_ssCode[m_nPos] == '\n') m_bNewLine = true;
// Skip the whitespace
m_nPos++;
}
}
inline void CSimpleCppDecomposer::SkipLine()
{
while (m_nPos < m_ssCode.size())
{
// Ignore the line ending with concatinating lines
if (m_ssCode[m_nPos] == '\\' && m_ssCode[m_nPos + 1] == '\r' && m_ssCode[m_nPos + 2] == '\n')
{
m_nPos += 3;
continue;
}
else if (m_ssCode[m_nPos] == '\\' && m_ssCode[m_nPos + 2] == '\n')
{
m_nPos += 2;
continue;
}
// Finished when a new line has been reached
if (m_ssCode[m_nPos] == '\n')
{
m_nPos++; // Skip the newline
m_bNewLine = true;
break;
}
// Skip the character
m_nPos++;
}
}
inline void CSimpleCppDecomposer::SkipComment()
{
if (m_nPos >= m_ssCode.size()) return;
if (m_ssCode[m_nPos] != '/') return;
if (m_ssCode[m_nPos + 1] == '/') // C++ comment
{
SkipLine();
return;
}
if (m_ssCode[m_nPos + 1] != '*') return;
// C comment
m_nPos += 2;
while (m_nPos < m_ssCode.size())
{
// End of comment
if (m_ssCode[m_nPos] == '*' && m_ssCode[m_nPos + 1] == '/')
{
m_nPos += 2;
break;
}
// Ignore the line ending with concatinating lines
if (m_ssCode[m_nPos] == '\\' && m_ssCode[m_nPos + 1] == '\r' && m_ssCode[m_nPos + 2] == '\n')
{
m_nPos += 3;
continue;
}
else if (m_ssCode[m_nPos] == '\\' && m_ssCode[m_nPos + 2] == '\n')
{
m_nPos += 2;
continue;
}
// Detect a new line
if (m_ssCode[m_nPos] == '\n') m_bNewLine = true;
// Skip the character
m_nPos++;
}
}
inline void CSimpleCppDecomposer::ProcessText()
{
m_bNewLine = false;
size_t nStart = m_nPos;
while (m_nPos < m_ssCode.size() && (std::isalnum(m_ssCode[m_nPos]) || m_ssCode[m_nPos] == '_'))
m_nPos++;
if (m_nPos == nStart) return;
m_lstCode.push_back(m_ssCode.substr(nStart, m_nPos - nStart));
}
inline void CSimpleCppDecomposer::ProcessString()
{
m_bNewLine = false;
size_t nStart = m_nPos;
m_nPos++; // Skip quote
while (m_nPos < m_ssCode.size() && m_ssCode[m_nPos] != '\"' && m_ssCode[m_nPos] == '\'') m_nPos++;
if (m_nPos < m_ssCode.size()) m_nPos++; // Skip quote
if (m_nPos == nStart) return;
m_lstCode.push_back(m_ssCode.substr(nStart, m_nPos - nStart));
}
inline void CSimpleCppDecomposer::ProcessSymbol()
{
m_bNewLine = false;
if (m_nPos >= m_ssCode.size()) return;
m_lstCode.push_back(std::string(1, m_ssCode[m_nPos]));
m_nPos++; // Skip symbol
}
#endif // !defined SIMPLE_CPP_DECOMPOSER_INL

View File

@@ -0,0 +1,103 @@
#ifndef TEST_WATCHDOG_H
#define TEST_WATCHDOG_H
#include <thread>
#include <cstdint>
#include <iostream>
#ifdef _WIN32
// Prevent reassignment of "interface"
#pragma push_macro("interface")
#undef interface
#ifndef NOMINMAX
#define NOMINMAX
#endif
// Include windows headers
#include <WinSock2.h>
#include <Windows.h>
#include <objbase.h>
// Use previous assignment of "interface"
#pragma pop_macro("interface")
// Remove "GetObject" assignment
#ifdef GetObject
#undef GetObject
#endif
// Remove "GetClassInfo" assignment
#ifdef GetClassInfo
#undef GetClassInfo
#endif
#elif defined __unix__
#include <signal.h>
#include <unistd.h>
#else
#error The OS is not supported!
#endif
/**
* @brief Test watchdog class; ends test process when runtime duration has superseded.
*/
class CProcessWatchdog
{
public:
/**
* @brief Constructor
* @param[in] m_iWatchdogTimeS The duration the watchdog is monitoring before process termination in seconds (default 300s).
*/
CProcessWatchdog(int64_t iWatchdogTimeS = 300ll)
{
m_threadWatchdog = std::thread(&CProcessWatchdog::WatchdogThreadFunc, this, iWatchdogTimeS );
}
/**
* @breif Destructor; cancels the watch thread.
*/
~CProcessWatchdog()
{
m_bTerminateWatchdog = true;
if (m_threadWatchdog.joinable())
m_threadWatchdog.join();
}
private:
/**
* @brief Watch thread function.
* @param[in] iWatchdogTimeS The duration the watchdog is monitoring before process termination in seconds (default 120s).
*/
void WatchdogThreadFunc(int64_t iWatchdogTimeS = 120ll)
{
// Run for the most the set time; then terminate...
auto tpStart = std::chrono::steady_clock::now();
while (!m_bTerminateWatchdog)
{
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
auto tpNow = std::chrono::steady_clock::now();
if (std::chrono::duration_cast<std::chrono::seconds>(tpNow - tpStart).count() > iWatchdogTimeS)
{
std::cerr << "ERROR PROCESS WATCHDOG: POTENTIAL DEADLOCK DETECTED - TERMINATION ENFORCED!!!" << std::endl;
std::cerr.flush();
#ifdef _WIN32
// Get the current process handle
HANDLE hProcess = GetCurrentProcess();
// Terminate the current process with exit code -100
TerminateProcess(hProcess, static_cast<UINT>(-100));
#elif defined __unix__
// Send SIGTERM signal to the current process
kill(getpid(), SIGTERM);
#else
#error The OS is not supported!
#endif
}
}
}
bool m_bTerminateWatchdog = false; ///< When set, allows the thread to terminate.
std::thread m_threadWatchdog; ///< The watchdog thread.
};
#endif // !defined TEST_WATCHDOG_H