155 lines
3.7 KiB
C++
155 lines
3.7 KiB
C++
|
#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
|