bleh
This commit is contained in:
parent
6e5045f1f4
commit
693fa17d10
266 changed files with 60543 additions and 1000 deletions
190
subprojects/quill-4.2.0/quill/test/misc/DocTestExtensions.cpp
Normal file
190
subprojects/quill-4.2.0/quill/test/misc/DocTestExtensions.cpp
Normal file
|
@ -0,0 +1,190 @@
|
|||
#include "DocTestExtensions.h"
|
||||
|
||||
#include <memory>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <cstdlib>
|
||||
#include <unistd.h>
|
||||
#else
|
||||
#if !defined(WIN32_LEAN_AND_MEAN)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
|
||||
#if !defined(NOMINMAX)
|
||||
// Mingw already defines this, so no need to redefine
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <codecvt>
|
||||
#include <io.h>
|
||||
#include <locale>
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
|
||||
namespace quill
|
||||
{
|
||||
namespace testing
|
||||
{
|
||||
|
||||
// The ctor redirects the stream to a temporary file.
|
||||
CapturedStream::CapturedStream(int fd) : fd_(fd), uncaptured_fd_(dup(fd))
|
||||
{
|
||||
#if defined(__MINGW__) || defined(__MINGW32__) || defined(__MINGW64__) || defined(_WIN32)
|
||||
char temp_dir_path[MAX_PATH + 1] = {'\0'}; // NOLINT
|
||||
char temp_file_path[MAX_PATH + 1] = {'\0'}; // NOLINT
|
||||
|
||||
::GetTempPathA(sizeof(temp_dir_path), temp_dir_path);
|
||||
const UINT success = ::GetTempFileNameA(temp_dir_path, "dtest_redir",
|
||||
0, // Generate unique file name.
|
||||
temp_file_path);
|
||||
if (success == 0)
|
||||
{
|
||||
FAIL("Unable to create a temporary file in " << temp_dir_path;);
|
||||
}
|
||||
|
||||
const int captured_fd = creat(temp_file_path, _S_IREAD | _S_IWRITE);
|
||||
if (captured_fd == -1)
|
||||
{
|
||||
FAIL("Unable to open_file temporary file " << temp_file_path);
|
||||
}
|
||||
filename_ = temp_file_path;
|
||||
#else
|
||||
// There's no guarantee that a test has write access to the current
|
||||
// directory, so we create the temporary file in the /tmp directory
|
||||
// instead.
|
||||
// We use /tmp on most systems, and /sdcard on Android.
|
||||
// That's because Android doesn't have /tmp.
|
||||
|
||||
#if defined(__ANDROID__)
|
||||
char name_template[] = "/data/local/tmp/doctest_captured_stream.XXXXXX";
|
||||
#else
|
||||
char name_template[] = "/tmp/captured_stream.XXXXXX";
|
||||
#endif // __ANDROID__
|
||||
|
||||
const int captured_fd = mkstemp(name_template);
|
||||
|
||||
if (captured_fd == -1)
|
||||
{
|
||||
FAIL("Failed to create tmp file "
|
||||
<< name_template << " for test; does the test have access to the /tmp directory?");
|
||||
}
|
||||
|
||||
filename_ = name_template;
|
||||
#endif // _WIN32
|
||||
|
||||
fflush(nullptr);
|
||||
dup2(captured_fd, fd_);
|
||||
close(captured_fd);
|
||||
}
|
||||
|
||||
CapturedStream::~CapturedStream() { remove(filename_.c_str()); }
|
||||
|
||||
std::string CapturedStream::GetCapturedString()
|
||||
{
|
||||
if (uncaptured_fd_ != -1)
|
||||
{
|
||||
// Restores the original stream.
|
||||
fflush(nullptr);
|
||||
dup2(uncaptured_fd_, fd_);
|
||||
close(uncaptured_fd_);
|
||||
uncaptured_fd_ = -1;
|
||||
}
|
||||
|
||||
FILE* const file = _fopen(filename_.c_str(), "r");
|
||||
if (file == nullptr)
|
||||
{
|
||||
// FAIL("Failed to open_file tmp file " << filename_ << " for capturing stream.");
|
||||
}
|
||||
|
||||
std::string content = _read_entire_file(file);
|
||||
_fclose(file);
|
||||
return content;
|
||||
}
|
||||
|
||||
std::string CapturedStream::_read_entire_file(FILE* file)
|
||||
{
|
||||
size_t const file_size = _get_file_size(file);
|
||||
std::unique_ptr<char[]> buffer{new char[file_size]};
|
||||
|
||||
size_t bytes_last_read = 0; // # of bytes read in the last fread()
|
||||
size_t bytes_read = 0; // # of bytes read so far
|
||||
|
||||
fseek(file, 0, SEEK_SET);
|
||||
|
||||
do
|
||||
{
|
||||
// Keeps reading the file until we cannot read further or the
|
||||
// pre-determined file size is reached.
|
||||
bytes_last_read = fread(buffer.get() + bytes_read, 1, file_size - bytes_read, file);
|
||||
bytes_read += bytes_last_read;
|
||||
} while (bytes_last_read > 0 && bytes_read < file_size);
|
||||
|
||||
std::string content{buffer.get(), bytes_read};
|
||||
return content;
|
||||
}
|
||||
|
||||
size_t CapturedStream::_get_file_size(FILE* file)
|
||||
{
|
||||
fseek(file, 0, SEEK_END);
|
||||
return static_cast<size_t>(ftell(file));
|
||||
}
|
||||
|
||||
FILE* CapturedStream::_fopen(char const* path, char const* mode)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
struct wchar_codecvt : public std::codecvt<wchar_t, char, std::mbstate_t>
|
||||
{
|
||||
};
|
||||
std::wstring_convert<wchar_codecvt> converter;
|
||||
std::wstring wide_path = converter.from_bytes(path);
|
||||
std::wstring wide_mode = converter.from_bytes(mode);
|
||||
return _wfopen(wide_path.c_str(), wide_mode.c_str());
|
||||
#else
|
||||
return fopen(path, mode);
|
||||
#endif // _WIN32
|
||||
}
|
||||
|
||||
int CapturedStream::_fclose(FILE* fp) { return fclose(fp); }
|
||||
|
||||
// Starts capturing an output stream (stdout/stderr).
|
||||
void CaptureStream(int fd, const char* stream_name, CapturedStream** stream)
|
||||
{
|
||||
if (*stream != nullptr)
|
||||
{
|
||||
FAIL("Only one " << stream_name << " capturer can exist at a time.");
|
||||
}
|
||||
*stream = new CapturedStream(fd);
|
||||
}
|
||||
|
||||
// Stops capturing the output stream and returns the captured string.
|
||||
std::string GetCapturedStream(CapturedStream** captured_stream)
|
||||
{
|
||||
std::string content = (*captured_stream)->GetCapturedString();
|
||||
|
||||
delete *captured_stream;
|
||||
*captured_stream = nullptr;
|
||||
|
||||
return content;
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
// MSVC and C++Builder do not provide a definition of STDERR_FILENO.
|
||||
const int kStdOutFileno = 1;
|
||||
const int kStdErrFileno = 2;
|
||||
#else
|
||||
const int kStdOutFileno = STDOUT_FILENO;
|
||||
const int kStdErrFileno = STDERR_FILENO;
|
||||
#endif // _MSC_VER
|
||||
|
||||
void CaptureStdout() { CaptureStream(kStdOutFileno, "stdout", &g_captured_stdout); }
|
||||
|
||||
void CaptureStderr() { CaptureStream(kStdErrFileno, "stderr", &g_captured_stderr); }
|
||||
|
||||
std::string GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); }
|
||||
|
||||
std::string GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); }
|
||||
|
||||
} // namespace testing
|
||||
} // namespace quill
|
97
subprojects/quill-4.2.0/quill/test/misc/DocTestExtensions.h
Normal file
97
subprojects/quill-4.2.0/quill/test/misc/DocTestExtensions.h
Normal file
|
@ -0,0 +1,97 @@
|
|||
#pragma once
|
||||
|
||||
#include "doctest/doctest.h"
|
||||
#include "quill/core/Attributes.h"
|
||||
|
||||
|
||||
#include <iostream>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#define REQUIRE_STREQ(str1, str2) \
|
||||
do \
|
||||
{ \
|
||||
if (strcmp(str1, str2) != 0) \
|
||||
{ \
|
||||
MESSAGE("Expected equality of these values: \n\t str1: " \
|
||||
<< std::string_view{str1} << "\n\t str2: " << std::string_view{str2}); \
|
||||
REQUIRE_UNARY(false); \
|
||||
}; \
|
||||
} while (0)
|
||||
|
||||
#define REQUIRE_WSTREQ(str1, str2) \
|
||||
do \
|
||||
{ \
|
||||
if (wcscmp(str1, str2) != 0) \
|
||||
{ \
|
||||
MESSAGE("Expected equality of these values: \n\t str1: " << str1 << "\n\t str2: " << str2); \
|
||||
REQUIRE_UNARY(false); \
|
||||
}; \
|
||||
} while (0)
|
||||
|
||||
#define REQUIRE_STRNEQ(str1, str2) \
|
||||
do \
|
||||
{ \
|
||||
if (strcmp(str1, str2) == 0) \
|
||||
{ \
|
||||
MESSAGE("Expected non-equality of these values: \n\t str1: " << str1 << "\n\t str2: " << str2); \
|
||||
REQUIRE_UNARY(false); \
|
||||
}; \
|
||||
} while (0)
|
||||
|
||||
namespace quill
|
||||
{
|
||||
namespace testing
|
||||
{
|
||||
/**
|
||||
* Object that captures an output stream (stdout/stderr).
|
||||
*/
|
||||
class CapturedStream
|
||||
{
|
||||
public:
|
||||
// The ctor redirects the stream to a temporary file.
|
||||
explicit CapturedStream(int fd);
|
||||
|
||||
~CapturedStream();
|
||||
|
||||
std::string GetCapturedString();
|
||||
|
||||
private:
|
||||
static std::string _read_entire_file(FILE* file);
|
||||
|
||||
static size_t _get_file_size(FILE* file);
|
||||
|
||||
static FILE* _fopen(char const* path, char const* mode);
|
||||
|
||||
static int _fclose(FILE* fp);
|
||||
|
||||
private:
|
||||
int fd_; // A stream to capture.
|
||||
int uncaptured_fd_;
|
||||
std::string filename_; // Name of the temporary file holding the stderr output.
|
||||
};
|
||||
|
||||
QUILL_MAYBE_UNUSED static CapturedStream* g_captured_stderr = nullptr;
|
||||
QUILL_MAYBE_UNUSED static CapturedStream* g_captured_stdout = nullptr;
|
||||
|
||||
// Starts capturing an output stream (stdout/stderr).
|
||||
void CaptureStream(int fd, const char* stream_name, CapturedStream** stream);
|
||||
|
||||
// Stops capturing the output stream and returns the captured string.
|
||||
std::string GetCapturedStream(CapturedStream** captured_stream);
|
||||
|
||||
// Starts capturing stdout.
|
||||
void CaptureStdout();
|
||||
|
||||
// Starts capturing stderr.
|
||||
void CaptureStderr();
|
||||
|
||||
// Stops capturing stdout and returns the captured string.
|
||||
std::string GetCapturedStdout();
|
||||
|
||||
// Stops capturing stderr and returns the captured string.
|
||||
std::string GetCapturedStderr();
|
||||
} // namespace testing
|
||||
} // namespace quill
|
2
subprojects/quill-4.2.0/quill/test/misc/TestMain.cpp
Normal file
2
subprojects/quill-4.2.0/quill/test/misc/TestMain.cpp
Normal file
|
@ -0,0 +1,2 @@
|
|||
#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN
|
||||
#include "doctest/doctest.h"
|
155
subprojects/quill-4.2.0/quill/test/misc/TestUtilities.cpp
Normal file
155
subprojects/quill-4.2.0/quill/test/misc/TestUtilities.cpp
Normal file
|
@ -0,0 +1,155 @@
|
|||
#include "TestUtilities.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <random>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <system_error>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace quill
|
||||
{
|
||||
namespace testing
|
||||
{
|
||||
// Convert the given file to a vector
|
||||
std::vector<std::string> file_contents(fs::path const& filename)
|
||||
{
|
||||
std::ifstream out_file(filename.string());
|
||||
|
||||
std::vector<std::string> lines;
|
||||
|
||||
for (std::string current_line; getline(out_file, current_line);)
|
||||
{
|
||||
lines.push_back(current_line);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
// Convert the given file to a vector
|
||||
std::vector<std::wstring> wfile_contents(fs::path const& filename)
|
||||
{
|
||||
std::wifstream out_file(filename.string());
|
||||
|
||||
std::vector<std::wstring> lines;
|
||||
|
||||
for (std::wstring current_line; getline(out_file, current_line);)
|
||||
{
|
||||
lines.push_back(current_line);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
// Search a vector for the given string
|
||||
bool file_contains(std::vector<std::string> const& file_vector, std::string const& search_string)
|
||||
{
|
||||
auto const search =
|
||||
std::find_if(file_vector.cbegin(), file_vector.cend(), [&search_string](std::string const& elem)
|
||||
{ return elem.find(search_string) != std::string::npos; });
|
||||
|
||||
bool const success = search != file_vector.cend();
|
||||
|
||||
if (!success)
|
||||
{
|
||||
// We failed to find and we will log for diagnostic reasons
|
||||
std::cout << "Failed to find '" << search_string << "' in:\n";
|
||||
for (auto const& line : file_vector)
|
||||
{
|
||||
std::cout << "'" << line << "'\n";
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void create_file(fs::path const& filename, std::string const& text)
|
||||
{
|
||||
if (std::ofstream file(filename); file.is_open())
|
||||
{
|
||||
if (!text.empty())
|
||||
{
|
||||
file << text;
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
|
||||
void remove_file(fs::path const& filename)
|
||||
{
|
||||
std::error_code ec;
|
||||
fs::remove(filename, ec);
|
||||
}
|
||||
|
||||
std::vector<std::string> gen_random_strings(size_t n, int min_len, int max_len)
|
||||
{
|
||||
// Generate random strings
|
||||
std::random_device rd;
|
||||
std::mt19937 mt(rd());
|
||||
std::uniform_int_distribution<int> dist_chars(32, 126);
|
||||
|
||||
// length of strings
|
||||
std::uniform_int_distribution<int> dist_len(min_len, max_len);
|
||||
|
||||
// Generate a vector of random strings of dist_len
|
||||
std::vector<std::string> random_strings_vec;
|
||||
random_strings_vec.reserve(n);
|
||||
|
||||
std::string result;
|
||||
for (size_t i = 0; i < n; ++i)
|
||||
{
|
||||
std::generate_n(std::back_inserter(result), dist_len(mt),
|
||||
[&] { return static_cast<char>(dist_chars(mt)); });
|
||||
random_strings_vec.emplace_back(std::move(result));
|
||||
}
|
||||
return random_strings_vec;
|
||||
}
|
||||
|
||||
uint64_t parse_timestamp(std::string const& timestamp_str)
|
||||
{
|
||||
std::tm tm = {};
|
||||
std::istringstream ss(timestamp_str);
|
||||
ss >> std::get_time(&tm, "%Y-%m-%d %H:%M:%S"); // Extract date and time
|
||||
|
||||
// Extract fractional seconds
|
||||
size_t pos = timestamp_str.find('.');
|
||||
std::string fractional_seconds_str = timestamp_str.substr(pos + 1, 9);
|
||||
uint64_t fractional_seconds = std::stoull(fractional_seconds_str);
|
||||
|
||||
auto time_point = std::chrono::system_clock::from_time_t(std::mktime(&tm));
|
||||
auto nanoseconds_since_epoch =
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(time_point.time_since_epoch()).count();
|
||||
return static_cast<uint64_t>(nanoseconds_since_epoch) + fractional_seconds;
|
||||
}
|
||||
|
||||
bool is_timestamp_ordered(std::vector<std::string> const& file_contents)
|
||||
{
|
||||
uint64_t previous_timestamp = 0;
|
||||
bool first = true;
|
||||
|
||||
for (auto const& line : file_contents)
|
||||
{
|
||||
uint64_t current_timestamp = parse_timestamp(line);
|
||||
|
||||
if (!first)
|
||||
{
|
||||
if (current_timestamp < previous_timestamp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
previous_timestamp = current_timestamp;
|
||||
first = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
} // namespace testing
|
||||
} // namespace quill
|
30
subprojects/quill-4.2.0/quill/test/misc/TestUtilities.h
Normal file
30
subprojects/quill-4.2.0/quill/test/misc/TestUtilities.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include "quill/core/Common.h"
|
||||
#include "quill/core/Filesystem.h"
|
||||
|
||||
#include "DocTestExtensions.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace quill
|
||||
{
|
||||
namespace testing
|
||||
{
|
||||
// Convert the given file to a vector
|
||||
std::vector<std::string> file_contents(fs::path const& filename);
|
||||
std::vector<std::wstring> wfile_contents(fs::path const& filename);
|
||||
|
||||
// Search a vector for the given string
|
||||
bool file_contains(std::vector<std::string> const& file_vector, std::string const& search_string);
|
||||
void create_file(fs::path const& filename, std::string const& text = std::string{});
|
||||
void remove_file(fs::path const& filename);
|
||||
|
||||
std::vector<std::string> gen_random_strings(size_t n, int min_len, int max_len);
|
||||
|
||||
uint64_t parse_timestamp(std::string const& timestamp_str);
|
||||
bool is_timestamp_ordered(std::vector<std::string> const& file_contents);
|
||||
} // namespace testing
|
||||
} // namespace quill
|
Loading…
Add table
Add a link
Reference in a new issue