Files
weaseldb/tests/parser_comparison.cpp
2025-09-12 11:21:00 -04:00

148 lines
5.1 KiB
C++

#include "parser_comparison.hpp"
#include <sstream>
std::string ParserComparison::last_error_;
ParserComparison::ComparisonResult
ParserComparison::compare_parsers(const std::string &json_str) {
last_error_.clear();
// Parse with weaseljson parser
CommitRequest weasel_request;
JsonCommitRequestParser weasel_parser;
std::string mutable_json =
json_str; // JsonCommitRequestParser needs mutable data
auto weasel_result = weasel_parser.parse(weasel_request, mutable_json.data(),
mutable_json.size());
bool weasel_success =
(weasel_result == CommitRequestParser::ParseResult::Success);
// Parse with nlohmann reference parser
CommitRequest nlohmann_request;
NlohmannReferenceParser nlohmann_parser;
auto nlohmann_result = nlohmann_parser.parse(nlohmann_request, json_str);
bool nlohmann_success =
(nlohmann_result == NlohmannReferenceParser::ParseResult::Success);
// Compare results
if (weasel_success && nlohmann_success) {
// Both succeeded - check if they produce equivalent results
if (requests_equal(weasel_request, nlohmann_request)) {
return ComparisonResult::BothSuccess;
} else {
std::ostringstream oss;
oss << "Parsers produced different results. ";
oss << "Weasel: request_id="
<< (weasel_request.request_id().has_value()
? weasel_request.request_id().value()
: "none");
oss << ", leader_id='" << weasel_request.leader_id() << "'";
oss << ", read_version=" << weasel_request.read_version();
oss << ", preconditions=" << weasel_request.preconditions().size();
oss << ", operations=" << weasel_request.operations().size() << ". ";
oss << "Nlohmann: request_id="
<< (nlohmann_request.request_id().has_value()
? nlohmann_request.request_id().value()
: "none");
oss << ", leader_id='" << nlohmann_request.leader_id() << "'";
oss << ", read_version=" << nlohmann_request.read_version();
oss << ", preconditions=" << nlohmann_request.preconditions().size();
oss << ", operations=" << nlohmann_request.operations().size();
last_error_ = oss.str();
return ComparisonResult::DifferentResults;
}
} else if (!weasel_success && !nlohmann_success) {
// Both failed - this is expected for invalid JSON
return ComparisonResult::BothFailure;
} else if (weasel_success && !nlohmann_success) {
// Weasel succeeded but nlohmann failed
last_error_ = "Weasel parser succeeded but nlohmann failed: " +
nlohmann_parser.get_error();
return ComparisonResult::WeaselSuccessNlohmannFail;
} else {
// Nlohmann succeeded but weasel failed
last_error_ = "Nlohmann parser succeeded but weasel failed";
if (weasel_parser.get_parse_error()) {
last_error_ += ": " + std::string(weasel_parser.get_parse_error());
}
return ComparisonResult::NlohmannSuccessWeaselFail;
}
}
std::string ParserComparison::result_to_string(ComparisonResult result) {
switch (result) {
case ComparisonResult::BothSuccess:
return "Both parsers succeeded with equivalent results";
case ComparisonResult::BothFailure:
return "Both parsers failed (as expected)";
case ComparisonResult::WeaselSuccessNlohmannFail:
return "Weasel succeeded but nlohmann failed";
case ComparisonResult::NlohmannSuccessWeaselFail:
return "Nlohmann succeeded but weasel failed";
case ComparisonResult::DifferentResults:
return "Both succeeded but produced different results";
default:
return "Unknown result";
}
}
bool ParserComparison::requests_equal(const CommitRequest &req1,
const CommitRequest &req2) {
// Compare request_id
if (req1.request_id().has_value() != req2.request_id().has_value()) {
return false;
}
if (req1.request_id().has_value() &&
req1.request_id().value() != req2.request_id().value()) {
return false;
}
// Compare leader_id
if (req1.leader_id() != req2.leader_id()) {
return false;
}
// Compare read_version
if (req1.read_version() != req2.read_version()) {
return false;
}
// Compare preconditions
auto prec1 = req1.preconditions();
auto prec2 = req2.preconditions();
if (prec1.size() != prec2.size()) {
return false;
}
for (size_t i = 0; i < prec1.size(); ++i) {
if (!preconditions_equal(prec1[i], prec2[i])) {
return false;
}
}
// Compare operations
auto ops1 = req1.operations();
auto ops2 = req2.operations();
if (ops1.size() != ops2.size()) {
return false;
}
for (size_t i = 0; i < ops1.size(); ++i) {
if (!operations_equal(ops1[i], ops2[i])) {
return false;
}
}
return true;
}
bool ParserComparison::preconditions_equal(const Precondition &p1,
const Precondition &p2) {
return p1.type == p2.type && p1.version == p2.version &&
p1.begin == p2.begin && p1.end == p2.end;
}
bool ParserComparison::operations_equal(const Operation &op1,
const Operation &op2) {
return op1.type == op2.type && op1.param1 == op2.param1 &&
op1.param2 == op2.param2;
}