77 lines
3.1 KiB
C++
77 lines
3.1 KiB
C++
#pragma once
|
|
#include "../vendor/json.hpp"
|
|
#include "platform.h"
|
|
#include <sstream>
|
|
|
|
namespace ks
|
|
{
|
|
using DiagnosticJson = nlohmann::json;
|
|
struct OperationLogRow
|
|
{
|
|
std::wstring time, process, command, source, target, outcome, details;
|
|
bool problem = true;
|
|
};
|
|
inline std::vector<OperationLogRow> parseOperationLog(const std::wstring &contents)
|
|
{
|
|
std::vector<OperationLogRow> rows;
|
|
std::wistringstream stream(contents);
|
|
std::wstring line;
|
|
OperationLogRow *legacy = nullptr;
|
|
while (std::getline(stream, line))
|
|
{
|
|
if (!line.empty() && line.back() == L'\r')
|
|
line.pop_back();
|
|
if (line.empty())
|
|
continue;
|
|
auto marker = line.find(L" Operation {");
|
|
if (marker != line.npos)
|
|
{
|
|
try
|
|
{
|
|
auto j = DiagnosticJson::parse(utf8(line.substr(marker + 11)));
|
|
auto field = [&](const char *key) { return wide(j.value(key, std::string{})); };
|
|
OperationLogRow row{line.substr(0, marker), field("process"), field("command"),
|
|
field("source"), field("target"), field("outcome")};
|
|
row.problem = j.value("problem", true);
|
|
row.details =
|
|
L"Operation: " + field("attempt") + L"\r\nResult: " + row.outcome +
|
|
L"\r\nVerification: " + field("verification") + L"\r\nElapsed: " +
|
|
std::to_wstring(j.value("elapsedMs", 0ULL)) + L" ms\r\n\r\nOriginal:\r\n" +
|
|
field("original") + L"\r\n\r\nExpected result:\r\n" + field("expected") +
|
|
L"\r\n\r\nRead back:\r\n" + field("actual") + L"\r\n\r\nForeground unchanged: " +
|
|
(j.value("foregroundSame", false) ? L"yes" : L"no") + L"\r\nInput context unchanged: " +
|
|
(j.value("inputSame", false) ? L"yes" : L"no") + L"\r\nText truncated: " +
|
|
(j.value("textTruncated", false) ? L"yes (4096 UTF-16 units per field)" : L"no") +
|
|
L"\r\n\r\nContext and stages:\r\n" + field("context");
|
|
for (size_t at = 0; (at = row.details.find(L'\n', at)) != row.details.npos; ++at)
|
|
if (at == 0 || row.details[at - 1] != L'\r')
|
|
row.details.insert(at++, 1, L'\r');
|
|
rows.push_back(std::move(row));
|
|
legacy = nullptr;
|
|
continue;
|
|
}
|
|
catch (...)
|
|
{
|
|
} // Preserve malformed and old records for diagnosis.
|
|
}
|
|
if (line.front() != L' ' || !legacy)
|
|
{
|
|
rows.push_back({L"", L"", L"Legacy / event", L"", L"", L"Unstructured event", line});
|
|
legacy = &rows.back();
|
|
}
|
|
else
|
|
legacy->details += L"\r\n" + line;
|
|
}
|
|
return rows;
|
|
}
|
|
inline std::wstring conversionReadbackOutcome(const std::wstring &actual, const std::wstring &original,
|
|
const std::wstring &expected)
|
|
{
|
|
if (actual == expected)
|
|
return L"Paste verified";
|
|
if (actual == original)
|
|
return L"Original text remained";
|
|
return L"Readback differs";
|
|
}
|
|
} // namespace ks
|