|
13 | 13 | #include "eventide/zest/zest.h" |
14 | 14 | #include "eventide/serde/json/deserializer.h" |
15 | 15 | #include "eventide/serde/json/serializer.h" |
| 16 | +#include "eventide/serde/serde/annotation.h" |
16 | 17 | #include "eventide/serde/serde/serde.h" |
17 | 18 |
|
18 | 19 | namespace eventide::serde { |
@@ -379,6 +380,81 @@ TEST_CASE(misc_behavior) { |
379 | 380 |
|
380 | 381 | }; // TEST_SUITE(serde_simdjson) |
381 | 382 |
|
| 383 | +// ═══════════════════════════════════════════════════════════════════════ |
| 384 | +// Required field checks |
| 385 | +// ═══════════════════════════════════════════════════════════════════════ |
| 386 | + |
| 387 | +struct StrictStruct { |
| 388 | + int x{}; |
| 389 | + std::string name; |
| 390 | +}; |
| 391 | + |
| 392 | +struct MixedStruct { |
| 393 | + int required_field{}; |
| 394 | + std::optional<int> optional_field; |
| 395 | + defaulted<std::string> defaulted_field; |
| 396 | +}; |
| 397 | + |
| 398 | +struct AllOptional { |
| 399 | + std::optional<int> a; |
| 400 | + std::optional<std::string> b; |
| 401 | +}; |
| 402 | + |
| 403 | +TEST_SUITE(serde_required_fields) { |
| 404 | + |
| 405 | +TEST_CASE(missing_required_field_fails) { |
| 406 | + // "name" is required (non-optional), missing → error |
| 407 | + auto result = from_json<StrictStruct>(R"({"x": 42})"); |
| 408 | + EXPECT_FALSE(result.has_value()); |
| 409 | +} |
| 410 | + |
| 411 | +TEST_CASE(all_required_fields_present_succeeds) { |
| 412 | + auto result = from_json<StrictStruct>(R"({"x": 42, "name": "hello"})"); |
| 413 | + ASSERT_TRUE(result.has_value()); |
| 414 | + EXPECT_EQ(result->x, 42); |
| 415 | + EXPECT_EQ(result->name, "hello"); |
| 416 | +} |
| 417 | + |
| 418 | +TEST_CASE(empty_json_object_fails_if_required_fields) { |
| 419 | + auto result = from_json<StrictStruct>(R"({})"); |
| 420 | + EXPECT_FALSE(result.has_value()); |
| 421 | +} |
| 422 | + |
| 423 | +TEST_CASE(optional_field_can_be_absent) { |
| 424 | + auto result = from_json<MixedStruct>(R"({"required_field": 7})"); |
| 425 | + ASSERT_TRUE(result.has_value()); |
| 426 | + EXPECT_EQ(result->required_field, 7); |
| 427 | + EXPECT_FALSE(result->optional_field.has_value()); |
| 428 | + EXPECT_EQ(result->defaulted_field, std::string{}); |
| 429 | +} |
| 430 | + |
| 431 | +TEST_CASE(defaulted_field_can_be_absent) { |
| 432 | + auto result = from_json<MixedStruct>(R"({"required_field": 1})"); |
| 433 | + ASSERT_TRUE(result.has_value()); |
| 434 | + EXPECT_EQ(result->defaulted_field, std::string{}); |
| 435 | +} |
| 436 | + |
| 437 | +TEST_CASE(defaulted_field_present_is_used) { |
| 438 | + auto result = from_json<MixedStruct>(R"({"required_field": 1, "defaulted_field": "hi"})"); |
| 439 | + ASSERT_TRUE(result.has_value()); |
| 440 | + EXPECT_EQ(result->defaulted_field, std::string{"hi"}); |
| 441 | +} |
| 442 | + |
| 443 | +TEST_CASE(all_optional_struct_empty_object_succeeds) { |
| 444 | + auto result = from_json<AllOptional>(R"({})"); |
| 445 | + ASSERT_TRUE(result.has_value()); |
| 446 | + EXPECT_FALSE(result->a.has_value()); |
| 447 | + EXPECT_FALSE(result->b.has_value()); |
| 448 | +} |
| 449 | + |
| 450 | +TEST_CASE(unknown_fields_ignored_by_default) { |
| 451 | + auto result = from_json<StrictStruct>(R"({"x": 1, "name": "ok", "extra": true})"); |
| 452 | + ASSERT_TRUE(result.has_value()); |
| 453 | + EXPECT_EQ(result->x, 1); |
| 454 | +} |
| 455 | + |
| 456 | +}; // TEST_SUITE(serde_required_fields) |
| 457 | + |
382 | 458 | } // namespace |
383 | 459 |
|
384 | 460 | } // namespace eventide::serde |
0 commit comments