#define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN #include "../benchmarks/test_data.hpp" #include "parser_comparison.hpp" #include /** * @brief Test helper that uses parser comparison to validate both parsers. * * This function tests that either both parsers reject the input, or both * accept it and produce equivalent CommitRequest objects. */ void test_parser_comparison(const std::string &json_str, const std::string &test_name) { INFO("Testing: " << test_name); INFO("JSON: " << json_str); auto result = ParserComparison::compare_parsers(json_str); INFO("Comparison result: " << ParserComparison::result_to_string(result)); if (!ParserComparison::get_last_error().empty()) { INFO("Error details: " << ParserComparison::get_last_error()); } // Accept either both success or both failure - reject inconsistencies REQUIRE((result == ParserComparison::ComparisonResult::BothSuccess || result == ParserComparison::ComparisonResult::BothFailure)); } TEST_CASE("Parser Comparison - Basic Cases") { SUBCASE("Simple valid request") { test_parser_comparison(R"({ "request_id": "test123", "leader_id": "leader456", "read_version": 12345 })", "Simple valid request"); } SUBCASE("Minimal valid request (no request_id)") { test_parser_comparison(R"({ "leader_id": "leader456", "read_version": 12345 })", "Minimal valid request"); } SUBCASE("Request with preconditions") { test_parser_comparison(R"({ "leader_id": "leader456", "read_version": 12345, "preconditions": [ { "type": "point_read", "version": 12340, "key": "dGVzdA==" } ] })", "Request with preconditions"); } SUBCASE("Request with operations") { test_parser_comparison(R"({ "leader_id": "leader456", "read_version": 12345, "operations": [ { "type": "write", "key": "dGVzdA==", "value": "dmFsdWU=" }, { "type": "delete", "key": "dGVzdDI=" } ] })", "Request with operations"); } SUBCASE("Complex request with both preconditions and operations") { test_parser_comparison(R"({ "request_id": "complex-test", "leader_id": "leader789", "read_version": 98765, "preconditions": [ { "type": "point_read", "version": 98764, "key": "dGVzdEtleQ==" }, { "type": "range_read", "begin": "c3RhcnQ=", "end": "ZW5k" } ], "operations": [ { "type": "write", "key": "dGVzdEtleQ==", "value": "dGVzdFZhbHVl" }, { "type": "delete", "key": "ZGVsZXRlS2V5" }, { "type": "range_delete", "begin": "cmFuZ2VTdGFydA==", "end": "cmFuZ2VFbmQ=" } ] })", "Complex request"); } } TEST_CASE("Parser Comparison - Invalid Cases") { SUBCASE("Invalid JSON syntax") { test_parser_comparison(R"({ "leader_id": "leader456", "read_version": "not_a_number" })", "Invalid JSON - string for number"); } SUBCASE("Missing required leader_id") { test_parser_comparison(R"({ "request_id": "test123", "read_version": 12345 })", "Missing leader_id"); } SUBCASE("Missing required read_version") { test_parser_comparison(R"({ "request_id": "test123", "leader_id": "leader456" })", "Missing read_version"); } SUBCASE("Empty leader_id") { test_parser_comparison(R"({ "request_id": "test123", "leader_id": "", "read_version": 12345 })", "Empty leader_id"); } SUBCASE("Invalid precondition - missing key") { test_parser_comparison(R"({ "leader_id": "leader456", "read_version": 12345, "preconditions": [ { "type": "point_read" } ] })", "Invalid precondition - missing key"); } SUBCASE("Invalid precondition - missing begin for range_read") { test_parser_comparison(R"({ "leader_id": "leader456", "read_version": 12345, "preconditions": [ { "type": "range_read", "end": "dGVzdFo=" } ] })", "Invalid precondition - missing begin"); } SUBCASE("Invalid precondition - missing end for range_read") { test_parser_comparison(R"({ "leader_id": "leader456", "read_version": 12345, "preconditions": [ { "type": "range_read", "begin": "dGVzdA==" } ] })", "Invalid precondition - missing end"); } SUBCASE("Invalid operation - missing key for write") { test_parser_comparison(R"({ "leader_id": "leader456", "read_version": 12345, "operations": [ { "type": "write", "value": "dmFsdWU=" } ] })", "Invalid operation - missing key"); } SUBCASE("Invalid operation - missing value for write") { test_parser_comparison(R"({ "leader_id": "leader456", "read_version": 12345, "operations": [ { "type": "write", "key": "dGVzdA==" } ] })", "Invalid operation - missing value"); } SUBCASE("Invalid operation - missing key for delete") { test_parser_comparison(R"({ "leader_id": "leader456", "read_version": 12345, "operations": [ { "type": "delete" } ] })", "Invalid operation - missing key for delete"); } SUBCASE("Invalid operation - missing begin for range_delete") { test_parser_comparison( R"({ "leader_id": "leader456", "read_version": 12345, "operations": [ { "type": "range_delete", "end": "dGVzdFo=" } ] })", "Invalid operation - missing begin for range_delete"); } SUBCASE("Invalid operation - missing end for range_delete") { test_parser_comparison(R"({ "leader_id": "leader456", "read_version": 12345, "operations": [ { "type": "range_delete", "begin": "dGVzdA==" } ] })", "Invalid operation - missing end for range_delete"); } SUBCASE("Malformed JSON") { test_parser_comparison(R"({ "leader_id": "leader456" "read_version": 12345 })", "Malformed JSON - missing comma"); } SUBCASE("Invalid precondition type") { test_parser_comparison(R"({ "leader_id": "leader456", "read_version": 12345, "preconditions": [ { "type": "invalid_type", "key": "dGVzdA==" } ] })", "Invalid precondition type"); } SUBCASE("Invalid operation type") { test_parser_comparison(R"({ "leader_id": "leader456", "read_version": 12345, "operations": [ { "type": "invalid_operation", "key": "dGVzdA==" } ] })", "Invalid operation type"); } } TEST_CASE("Parser Comparison - Edge Cases") { SUBCASE("Empty arrays") { test_parser_comparison(R"({ "leader_id": "leader456", "read_version": 12345, "preconditions": [], "operations": [] })", "Empty arrays"); } SUBCASE("Empty base64 strings") { test_parser_comparison(R"({ "leader_id": "leader456", "read_version": 12345, "operations": [ { "type": "write", "key": "", "value": "" } ] })", "Empty base64 strings"); } SUBCASE("Zero read_version") { test_parser_comparison(R"({ "leader_id": "leader456", "read_version": 0 })", "Zero read_version"); } SUBCASE("Large read_version") { test_parser_comparison(R"({ "leader_id": "leader456", "read_version": 9223372036854775807 })", "Large read_version"); } SUBCASE("Precondition with zero version") { test_parser_comparison(R"({ "leader_id": "leader456", "read_version": 12345, "preconditions": [ { "type": "point_read", "version": 0, "key": "dGVzdA==" } ] })", "Precondition with zero version"); } SUBCASE("Range operations with empty keys") { test_parser_comparison(R"({ "leader_id": "leader456", "read_version": 12345, "preconditions": [ { "type": "range_read", "begin": "", "end": "" } ], "operations": [ { "type": "range_delete", "begin": "", "end": "" } ] })", "Range operations with empty keys"); } } TEST_CASE("Parser Comparison - Test Data") { SUBCASE("SIMPLE_JSON") { test_parser_comparison(weaseldb::test_data::SIMPLE_JSON, "SIMPLE_JSON test data"); } SUBCASE("MEDIUM_JSON") { test_parser_comparison(weaseldb::test_data::MEDIUM_JSON, "MEDIUM_JSON test data"); } SUBCASE("COMPLEX_JSON") { test_parser_comparison(weaseldb::test_data::COMPLEX_JSON, "COMPLEX_JSON test data"); } SUBCASE("Generated large JSON") { // Test with a reasonably sized generated JSON to avoid extremely long test // times std::string large_json = weaseldb::test_data::generate_large_json(100); test_parser_comparison(large_json, "Generated large JSON (100 operations)"); } } TEST_CASE("Parser Comparison - Stress Tests") { SUBCASE("Multiple operations of each type") { test_parser_comparison(R"({ "request_id": "stress-test-operations", "leader_id": "stress-leader", "read_version": 1000000, "operations": [ { "type": "write", "key": "a2V5MQ==", "value": "dmFsdWUx" }, { "type": "write", "key": "a2V5Mg==", "value": "dmFsdWUy" }, { "type": "delete", "key": "a2V5Mw==" }, { "type": "delete", "key": "a2V5NA==" }, { "type": "range_delete", "begin": "cmFuZ2UxX3N0YXJ0", "end": "cmFuZ2UxX2VuZA==" }, { "type": "range_delete", "begin": "cmFuZ2UyX3N0YXJ0", "end": "cmFuZ2UyX2VuZA==" } ] })", "Multiple operations of each type"); } SUBCASE("Multiple preconditions of each type") { test_parser_comparison(R"({ "leader_id": "stress-leader", "read_version": 2000000, "preconditions": [ { "type": "point_read", "version": 1999999, "key": "cG9pbnQx" }, { "type": "point_read", "version": 1999998, "key": "cG9pbnQy" }, { "type": "range_read", "version": 1999997, "begin": "cmFuZ2UxX3N0YXJ0", "end": "cmFuZ2UxX2VuZA==" }, { "type": "range_read", "begin": "cmFuZ2UyX3N0YXJ0", "end": "cmFuZ2UyX2VuZA==" } ] })", "Multiple preconditions of each type"); } SUBCASE("Deep nesting with many operations") { // Use the generate_large_json function which now properly encodes base64 std::string stress_json = weaseldb::test_data::generate_large_json(50); test_parser_comparison(stress_json, "Deep nesting with many operations"); } }