| // Copyright 2026 Google LLC | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // https://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| // | |
| #include "jumbf/parse.h" | |
| #include <cstdint> | |
| #include <cstring> | |
| #include <string> | |
| #include <utility> | |
| #include "absl/status/status.h" | |
| #include "absl/status/status_matchers.h" | |
| #include "absl/strings/str_cat.h" | |
| #include "absl/strings/str_join.h" | |
| #include "absl/strings/string_view.h" | |
| #include "gmock/gmock.h" | |
| #include "gtest/gtest.h" | |
| #include "jumbf/box.h" | |
| #include "jumbf/constants.h" | |
| #include "jumbf/test_utils.h" | |
| #include "riegeli/endian/endian_writing.h" | |
| #include "uuid/uuid.h" | |
| namespace jumbf { | |
| namespace { | |
| using ::absl_testing::IsOkAndHolds; | |
| using ::absl_testing::StatusIs; | |
| using ::credentio::Uuid; | |
| using ::testing::Eq; | |
| using ::testing::IsEmpty; | |
| constexpr absl::string_view kFakeUuid = "DEADBEEF-F00D-BABE-B4DF-00D528013378"; | |
| std::string FakeDescriptionBoxContents() { | |
| // Can't use absl::string_view because the compiler warns against assuming it | |
| // is null terminated, even when it truly is null terminated. | |
| constexpr char kFakeLabel[] = "fakelabel"; | |
| const size_t description_content_length = /*uuid*/ 16 + /*toggles*/ 1 + | |
| strlen(kFakeLabel) + | |
| /*label null terminator*/ 1; | |
| std::string fake_description_contents(description_content_length, '\0'); | |
| char* content_cursor = fake_description_contents.data(); | |
| SerializeUuid(&content_cursor, Uuid::FromStringOrDie(kFakeUuid)); | |
| riegeli::WriteBigEndian<uint8_t>(kDescriptionToggleLabelPresent, | |
| content_cursor); | |
| content_cursor += sizeof(uint8_t); | |
| memcpy(content_cursor, kFakeLabel, strlen(kFakeLabel) + 1); | |
| content_cursor += strlen(kFakeLabel) + 1; | |
| return fake_description_contents; | |
| } | |
| TEST(ParseTest, InvalidSuperBoxFails) { | |
| absl::string_view empty; | |
| EXPECT_THAT( | |
| ConsumeSuperBox(&empty, /*recursion_limit=*/1), | |
| StatusIs( | |
| absl::StatusCode::kOutOfRange, | |
| R"(cannot unwrap super box: cannot read LBox value: not enough input bytes remaining; have 0 need 4)")); | |
| EXPECT_THAT(empty, IsEmpty()); | |
| } | |
| TEST(ParseTest, InvalidSuperBoxPayloadFails) { | |
| absl::string_view kContent = | |
| R"(This content doesn't really matter for this test case.)"; | |
| std::string serialized = WrapBox(kContent, 0xf00dbabe); | |
| absl::string_view serialized_view = serialized; | |
| EXPECT_THAT(ConsumeSuperBox(&serialized_view, /*recursion_limit=*/1), | |
| StatusIs(absl::StatusCode::kInvalidArgument, | |
| "box is not a super box: got type 0xf00dbabe need " | |
| "0x6a756d62 ('jumb')")); | |
| EXPECT_THAT(serialized_view, Eq(serialized)); | |
| } | |
| TEST(ParseTest, InvalidDescriptionBoxFails) { | |
| constexpr uint32_t kLBox = 5; | |
| constexpr uint32_t kTBox = 12345; | |
| std::string inner_box(8, '\0'); | |
| char* cursor = inner_box.data(); | |
| riegeli::WriteBigEndian<uint32_t>(kLBox, cursor); | |
| cursor += sizeof(uint32_t); | |
| riegeli::WriteBigEndian<uint32_t>(kTBox, cursor); | |
| cursor += sizeof(uint32_t); | |
| const std::string super_box = WrapBox(inner_box, kSuperBoxType); | |
| absl::string_view serialized_view = super_box; | |
| EXPECT_THAT(ConsumeSuperBox(&serialized_view, /*recursion_limit=*/1), | |
| StatusIs(absl::StatusCode::kInvalidArgument, | |
| "cannot unwrap description box: LBox is 5; LBox values " | |
| "2-7 are reserved by the standard")); | |
| EXPECT_THAT(serialized_view, Eq(super_box)); | |
| } | |
| TEST(ParseTest, InvalidDescriptionBoxPayloadFails) { | |
| constexpr absl::string_view kFakeCborData = | |
| R"(the function under test does not actually parse CBOR data so we'll just use a totally fake string here)"; | |
| std::string description_box = | |
| WrapBox(FakeDescriptionBoxContents(), /*tbox=*/12345); | |
| std::string content_box = WrapBox(kFakeCborData, kCborBoxType); | |
| std::string super_box = | |
| WrapBox(absl::StrCat(description_box, content_box), kSuperBoxType); | |
| absl::string_view serialized_view = super_box; | |
| EXPECT_THAT(ConsumeSuperBox(&serialized_view, /*recursion_limit=*/1), | |
| StatusIs(absl::StatusCode::kInvalidArgument, | |
| "cannot parse description box: box is not a description " | |
| "box; got type 0x3039 need 0x6a756d64 ('jumd')")); | |
| EXPECT_THAT(serialized_view, Eq(super_box)); | |
| } | |
| TEST(ParseTest, NegativeRecursionLimitCausesNoUnderflow) { | |
| absl::string_view box_from_fuzzer( | |
| "\000\000\000\000jumb\000\000\000\031jumd\000\000\000\000\000\000\000\000" | |
| "\000\000\000\000\000\000\000\000\000\000\000\000\000jumb\000\000\000\031" | |
| "jumd\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000" | |
| "\000\000\031\000\000\000\000\000\000\000\000\000", | |
| 78); | |
| EXPECT_THAT( | |
| ConsumeSuperBox(&box_from_fuzzer, /*recursion_limit=*/-2147483648), | |
| StatusIs(absl::StatusCode::kInvalidArgument)); | |
| } | |
| TEST(ParseToProtoTest, AllDescriptionBoxTogglesSucceeds) { | |
| constexpr absl::string_view kFakeCborData = | |
| R"(the function under test does not actually parse CBOR data so we'll just use a totally fake string here)"; | |
| constexpr absl::string_view kFakeSalt = R"(0123456701234567)"; | |
| const std::string private_box = jumbf::WrapBox(kFakeSalt, kC2paSaltBoxType); | |
| // Can't use absl::string_view because the compiler warns against assuming it | |
| // is null terminated, even when it truly is null terminated. | |
| constexpr char kFakeLabel[] = "fakelabel"; | |
| constexpr uint32_t kFakeId = 0xB33FD00D; | |
| const std::string fake_hash(32, 'X'); | |
| const size_t description_content_length = | |
| /*uuid*/ 16 + /*toggles*/ 1 + strlen(kFakeLabel) + | |
| /*label null terminator*/ 1 + /*id*/ 4 + fake_hash.length() + | |
| private_box.length(); | |
| std::string fake_description_contents(description_content_length, 'A'); | |
| char* content_cursor = fake_description_contents.data(); | |
| SerializeUuid(&content_cursor, Uuid::FromStringOrDie(kFakeUuid)); | |
| uint8_t toggles = jumbf::kDescriptionToggleRequestable | | |
| jumbf::kDescriptionToggleLabelPresent | | |
| jumbf::kDescriptionToggleIdPresent | | |
| jumbf::kDescriptionToggleHashPresent | | |
| jumbf::kDescriptionTogglePrivatePresent; | |
| riegeli::WriteBigEndian<uint8_t>(toggles, content_cursor); | |
| content_cursor += sizeof(uint8_t); | |
| memcpy(content_cursor, kFakeLabel, strlen(kFakeLabel) + 1); | |
| content_cursor += strlen(kFakeLabel) + 1; | |
| riegeli::WriteBigEndian<uint32_t>(kFakeId, content_cursor); | |
| content_cursor += sizeof(uint32_t); | |
| memcpy(content_cursor, fake_hash.data(), 32); | |
| content_cursor += 32; | |
| memcpy(content_cursor, private_box.data(), private_box.length()); | |
| std::string content_box = WrapBox(kFakeCborData, kCborBoxType); | |
| std::string super_box = WrapBox( | |
| absl::StrCat(WrapBox(fake_description_contents, kDescriptionBoxType), | |
| content_box), | |
| kSuperBoxType); | |
| absl::string_view serialized_view = super_box; | |
| EXPECT_THAT(ConsumeSuperBox(&serialized_view, /*recursion_limit=*/1), | |
| IsOkAndHolds(SuperBox{ | |
| .description = | |
| DescriptionBox{ | |
| .type_uuid = Uuid::FromStringOrDie(kFakeUuid), | |
| .requestable = true, | |
| .label = "fakelabel", | |
| .id = kFakeId, | |
| .unvalidated_hash = fake_hash, | |
| .private_content{ContentBox{.raw_bytes = private_box, | |
| .payload = | |
| C2paSaltBox{ | |
| .salt = kFakeSalt, | |
| }}}}, | |
| .contents = {ContentBox{.raw_bytes = content_box, | |
| .payload = | |
| CborBox{ | |
| .payload = kFakeCborData, | |
| }}}, | |
| .raw_bytes = super_box})); | |
| EXPECT_THAT(serialized_view, IsEmpty()); | |
| } | |
| TEST(ParseToProtoTest, DescriptionBoxMultiplePrivateContentSucceeds) { | |
| constexpr absl::string_view kFakeCborData = | |
| R"(the function under test does not actually parse CBOR data so we'll just use a totally fake string here)"; | |
| constexpr absl::string_view kFirstPrivatePayload = | |
| R"(The format of this data is unimportant for this test case.)"; | |
| constexpr absl::string_view kSecondPrivatePayload = | |
| R"(The format of this data is also unimportant for this test case.)"; | |
| const std::string private_box_payload[] = {WrapBox(kFirstPrivatePayload, 1), | |
| WrapBox(kSecondPrivatePayload, 2)}; | |
| const std::string private_box = | |
| WrapBox(absl::StrJoin(private_box_payload, ""), kPrivateContentBoxType); | |
| // Can't use absl::string_view because the compiler warns against assuming it | |
| // is null terminated, even when it truly is null terminated. | |
| constexpr char kFakeLabel[] = "fakelabel"; | |
| constexpr uint32_t kFakeId = 0xB33FD00D; | |
| const std::string fake_hash(32, 'X'); | |
| const size_t description_content_length = | |
| /*uuid*/ 16 + /*toggles*/ 1 + strlen(kFakeLabel) + | |
| /*label null terminator*/ 1 + /*id*/ 4 + fake_hash.length() + | |
| private_box.length(); | |
| std::string fake_description_contents(description_content_length, 'A'); | |
| char* content_cursor = fake_description_contents.data(); | |
| SerializeUuid(&content_cursor, Uuid::FromStringOrDie(kFakeUuid)); | |
| uint8_t toggles = | |
| kDescriptionToggleRequestable | kDescriptionToggleLabelPresent | | |
| kDescriptionToggleIdPresent | kDescriptionToggleHashPresent | | |
| kDescriptionTogglePrivatePresent; | |
| riegeli::WriteBigEndian<uint8_t>(toggles, content_cursor); | |
| content_cursor += sizeof(uint8_t); | |
| memcpy(content_cursor, kFakeLabel, strlen(kFakeLabel) + 1); | |
| content_cursor += strlen(kFakeLabel) + 1; | |
| riegeli::WriteBigEndian<uint32_t>(kFakeId, content_cursor); | |
| content_cursor += sizeof(uint32_t); | |
| memcpy(content_cursor, fake_hash.data(), 32); | |
| content_cursor += 32; | |
| memcpy(content_cursor, private_box.data(), private_box.length()); | |
| std::string content_box = WrapBox(kFakeCborData, kCborBoxType); | |
| std::string super_box = WrapBox( | |
| absl::StrCat(WrapBox(fake_description_contents, kDescriptionBoxType), | |
| content_box), | |
| kSuperBoxType); | |
| absl::string_view serialized_view = super_box; | |
| EXPECT_THAT( | |
| ConsumeSuperBox(&serialized_view, /*recursion_limit=*/1), | |
| IsOkAndHolds(SuperBox{ | |
| .description = | |
| DescriptionBox{ | |
| .type_uuid = Uuid::FromStringOrDie(kFakeUuid), | |
| .requestable = true, | |
| .label = "fakelabel", | |
| .id = kFakeId, | |
| .unvalidated_hash = fake_hash, | |
| .private_content{ | |
| ContentBox{ | |
| .raw_bytes = WrapBox(kFirstPrivatePayload, 1), | |
| .payload = | |
| UnknownBox{ | |
| .type = 1, | |
| .payload = kFirstPrivatePayload, | |
| }, | |
| }, | |
| ContentBox{ | |
| .raw_bytes = WrapBox(kSecondPrivatePayload, 2), | |
| .payload = | |
| UnknownBox{ | |
| .type = 2, | |
| .payload = kSecondPrivatePayload, | |
| }, | |
| }, | |
| }}, | |
| .contents = {ContentBox{.raw_bytes = content_box, | |
| .payload = | |
| CborBox{ | |
| .payload = kFakeCborData, | |
| }}}, | |
| .raw_bytes = super_box})); | |
| EXPECT_THAT(serialized_view, IsEmpty()); | |
| } | |
| TEST(ParseTest, SingleCborContentBoxSucceeds) { | |
| constexpr absl::string_view kFakeCborData = | |
| R"(the function under test does not actually parse CBOR data so we'll just use a totally fake string here)"; | |
| std::string description_box = | |
| WrapBox(FakeDescriptionBoxContents(), kDescriptionBoxType); | |
| std::string content_box = WrapBox(kFakeCborData, kCborBoxType); | |
| std::string super_box = | |
| WrapBox(absl::StrCat(description_box, content_box), kSuperBoxType); | |
| absl::string_view serialized_view = super_box; | |
| EXPECT_THAT(ConsumeSuperBox(&serialized_view, /*recursion_limit=*/1), | |
| IsOkAndHolds(SuperBox{ | |
| .description = | |
| DescriptionBox{ | |
| .type_uuid = Uuid::FromStringOrDie(kFakeUuid), | |
| .label = "fakelabel", | |
| }, | |
| .contents = {ContentBox{.raw_bytes = content_box, | |
| .payload = | |
| CborBox{ | |
| .payload = kFakeCborData, | |
| }}}, | |
| .raw_bytes = super_box})); | |
| EXPECT_THAT(serialized_view, IsEmpty()); | |
| } | |
| TEST(ParseTest, MultipleCborContentBoxSucceeds) { | |
| constexpr absl::string_view kFakeFirstCborData = | |
| R"(first content: the function under test does not actually parse CBOR data so we'll just use a totally fake string here)"; | |
| constexpr absl::string_view kFakeSecondCborData = | |
| R"(second content: the function under test does not actually parse CBOR data so we'll just use a totally fake string here)"; | |
| std::string description_box = | |
| WrapBox(FakeDescriptionBoxContents(), kDescriptionBoxType); | |
| std::string super_box = WrapBox( | |
| absl::StrCat(description_box, WrapBox(kFakeFirstCborData, kCborBoxType), | |
| WrapBox(kFakeSecondCborData, kCborBoxType)), | |
| kSuperBoxType); | |
| absl::string_view serialized_view = super_box; | |
| EXPECT_THAT(ConsumeSuperBox(&serialized_view, /*recursion_limit=*/1), | |
| IsOkAndHolds(SuperBox{ | |
| .description = | |
| DescriptionBox{ | |
| .type_uuid = Uuid::FromStringOrDie(kFakeUuid), | |
| .label = "fakelabel", | |
| }, | |
| .contents = | |
| { | |
| ContentBox{.raw_bytes = WrapBox(kFakeFirstCborData, | |
| kCborBoxType), | |
| .payload = | |
| CborBox{ | |
| .payload = kFakeFirstCborData, | |
| }}, | |
| ContentBox{.raw_bytes = WrapBox(kFakeSecondCborData, | |
| kCborBoxType), | |
| .payload = | |
| CborBox{ | |
| .payload = kFakeSecondCborData, | |
| }}, | |
| }, | |
| .raw_bytes = super_box})); | |
| EXPECT_THAT(serialized_view, IsEmpty()); | |
| } | |
| TEST(ParseTest, SingleEmbeddedFileDescriptionBoxSucceeds) { | |
| constexpr uint8_t kToggles = 0; | |
| constexpr const char kFakeMediatype[] = "media/MyFormat"; | |
| const size_t payload_length = 1 /*toggles*/ + sizeof(kFakeMediatype); | |
| std::string payload(payload_length, 'A'); | |
| char* cursor = payload.data(); | |
| riegeli::WriteBigEndian<uint8_t>(kToggles, cursor); | |
| cursor += sizeof(uint8_t); | |
| memcpy(cursor, kFakeMediatype, sizeof(kFakeMediatype)); | |
| cursor += sizeof(kFakeMediatype); | |
| std::string description_box = | |
| WrapBox(FakeDescriptionBoxContents(), kDescriptionBoxType); | |
| std::string content_box = WrapBox(payload, kEmbeddedFileDescriptionBoxType); | |
| std::string super_box = | |
| WrapBox(absl::StrCat(description_box, content_box), kSuperBoxType); | |
| absl::string_view serialized_view = super_box; | |
| EXPECT_THAT(ConsumeSuperBox(&serialized_view, /*recursion_limit=*/1), | |
| IsOkAndHolds(SuperBox{ | |
| .description = | |
| DescriptionBox{ | |
| .type_uuid = Uuid::FromStringOrDie(kFakeUuid), | |
| .label = "fakelabel", | |
| }, | |
| .contents = {ContentBox{.raw_bytes = content_box, | |
| .payload = | |
| EmbeddedFileDescriptionBox{ | |
| .media_type = kFakeMediatype, | |
| }}}, | |
| .raw_bytes = super_box})); | |
| EXPECT_THAT(serialized_view, IsEmpty()); | |
| } | |
| TEST(ParseTest, SingleBinaryDataBoxSucceeds) { | |
| constexpr absl::string_view kPayload = | |
| R"(blah blah blah blah this is just some data in no particular format)"; | |
| std::string description_box = | |
| WrapBox(FakeDescriptionBoxContents(), kDescriptionBoxType); | |
| std::string content_box = WrapBox(kPayload, kBinaryDataBoxType); | |
| std::string super_box = | |
| WrapBox(absl::StrCat(description_box, content_box), kSuperBoxType); | |
| absl::string_view serialized_view = super_box; | |
| EXPECT_THAT(ConsumeSuperBox(&serialized_view, /*recursion_limit=*/1), | |
| IsOkAndHolds(SuperBox{ | |
| .description = | |
| DescriptionBox{ | |
| .type_uuid = Uuid::FromStringOrDie(kFakeUuid), | |
| .label = "fakelabel", | |
| }, | |
| .contents = {ContentBox{.raw_bytes = content_box, | |
| .payload = | |
| BinaryDataBox{ | |
| .payload = kPayload, | |
| }}}, | |
| .raw_bytes = super_box})); | |
| EXPECT_THAT(serialized_view, IsEmpty()); | |
| } | |
| TEST(ParseTest, RecursiveSuperBoxUnderRecursionLimitSucceeds) { | |
| constexpr absl::string_view kFakeCborData = | |
| R"(the function under test does not actually parse CBOR data so we'll just use a totally fake string here)"; | |
| std::string description_box = | |
| WrapBox(FakeDescriptionBoxContents(), kDescriptionBoxType); | |
| std::string inner_content_box = WrapBox(kFakeCborData, kCborBoxType); | |
| std::string inner_super_box = | |
| WrapBox(absl::StrCat(description_box, inner_content_box), kSuperBoxType); | |
| std::string outer_super_box = | |
| WrapBox(absl::StrCat(description_box, inner_super_box), kSuperBoxType); | |
| absl::string_view serialized_view = outer_super_box; | |
| EXPECT_THAT( | |
| ConsumeSuperBox(&serialized_view, /*recursion_limit=*/1), | |
| IsOkAndHolds(SuperBox{ | |
| .description = | |
| DescriptionBox{ | |
| .type_uuid = Uuid::FromStringOrDie(kFakeUuid), | |
| .label = "fakelabel", | |
| }, | |
| .contents = {ContentBox{ | |
| .raw_bytes = inner_super_box, | |
| .payload = | |
| SuperBox{ | |
| .description = | |
| DescriptionBox{ | |
| .type_uuid = Uuid::FromStringOrDie(kFakeUuid), | |
| .label = "fakelabel", | |
| }, | |
| .contents = {ContentBox{.raw_bytes = inner_content_box, | |
| .payload = | |
| CborBox{ | |
| .payload = kFakeCborData, | |
| }}}, | |
| .raw_bytes = inner_super_box}}}, | |
| .raw_bytes = outer_super_box})); | |
| EXPECT_THAT(serialized_view, IsEmpty()); | |
| } | |
| TEST(ParseTest, RecursiveSuperBoxNoRecursionLimitSucceeds) { | |
| constexpr absl::string_view kFakeCborData = | |
| R"(the function under test does not actually parse CBOR data so we'll just use a totally fake string here)"; | |
| std::string description_box = | |
| WrapBox(FakeDescriptionBoxContents(), kDescriptionBoxType); | |
| std::string inner_content_box = WrapBox(kFakeCborData, kCborBoxType); | |
| std::string inner_super_box = | |
| WrapBox(absl::StrCat(description_box, inner_content_box), kSuperBoxType); | |
| std::string outer_super_box = | |
| WrapBox(absl::StrCat(description_box, inner_super_box), kSuperBoxType); | |
| absl::string_view serialized_view = outer_super_box; | |
| EXPECT_THAT( | |
| ConsumeSuperBox(&serialized_view, /*recursion_limit=*/-1), | |
| IsOkAndHolds(SuperBox{ | |
| .description = | |
| DescriptionBox{ | |
| .type_uuid = Uuid::FromStringOrDie(kFakeUuid), | |
| .label = "fakelabel", | |
| }, | |
| .contents = {ContentBox{ | |
| .raw_bytes = inner_super_box, | |
| .payload = | |
| SuperBox{ | |
| .description = | |
| DescriptionBox{ | |
| .type_uuid = Uuid::FromStringOrDie(kFakeUuid), | |
| .label = "fakelabel", | |
| }, | |
| .contents = {ContentBox{.raw_bytes = inner_content_box, | |
| .payload = | |
| CborBox{ | |
| .payload = kFakeCborData, | |
| }}}, | |
| .raw_bytes = inner_super_box}}}, | |
| .raw_bytes = outer_super_box})); | |
| EXPECT_THAT(serialized_view, IsEmpty()); | |
| } | |
| TEST(ParseTest, RecursiveSuperBoxExceedsZeroRecursionLimitSucceeds) { | |
| constexpr absl::string_view kFakeCborData = | |
| R"(the function under test does not actually parse CBOR data so we'll just use a totally fake string here)"; | |
| std::string description_box = | |
| WrapBox(FakeDescriptionBoxContents(), kDescriptionBoxType); | |
| std::string inner_content_box = WrapBox(kFakeCborData, kCborBoxType); | |
| std::string inner_super_box = | |
| WrapBox(absl::StrCat(description_box, inner_content_box), kSuperBoxType); | |
| std::string outer_super_box = | |
| WrapBox(absl::StrCat(description_box, inner_super_box), kSuperBoxType); | |
| absl::string_view serialized_view = outer_super_box; | |
| EXPECT_THAT(ConsumeSuperBox(&serialized_view, /*recursion_limit=*/0), | |
| IsOkAndHolds(SuperBox{ | |
| .description = | |
| DescriptionBox{ | |
| .type_uuid = Uuid::FromStringOrDie(kFakeUuid), | |
| .label = "fakelabel", | |
| }, | |
| .contents = {ContentBox{.raw_bytes = inner_super_box, | |
| .payload = | |
| SerializedSuperbox{ | |
| .serialized = inner_super_box, | |
| }}}, | |
| .raw_bytes = outer_super_box})); | |
| EXPECT_THAT(serialized_view, IsEmpty()); | |
| } | |
| TEST(ParseTest, RecursiveSuperBoxExceedsNonzeroRecursionLimitSucceeds) { | |
| constexpr absl::string_view kFakeCborData = | |
| R"(the function under test does not actually parse CBOR data so we'll just use a totally fake string here)"; | |
| std::string description_box = | |
| WrapBox(FakeDescriptionBoxContents(), kDescriptionBoxType); | |
| std::string inner_content_box = WrapBox(kFakeCborData, kCborBoxType); | |
| std::string inner_super_box = | |
| WrapBox(absl::StrCat(description_box, inner_content_box), kSuperBoxType); | |
| std::string middle_super_box = | |
| WrapBox(absl::StrCat(description_box, inner_super_box), kSuperBoxType); | |
| std::string outer_super_box = | |
| WrapBox(absl::StrCat(description_box, middle_super_box), kSuperBoxType); | |
| absl::string_view serialized_view = outer_super_box; | |
| EXPECT_THAT( | |
| ConsumeSuperBox(&serialized_view, /*recursion_limit=*/1), | |
| IsOkAndHolds(SuperBox{ | |
| .description = | |
| DescriptionBox{ | |
| .type_uuid = Uuid::FromStringOrDie(kFakeUuid), | |
| .label = "fakelabel", | |
| }, | |
| .contents = {ContentBox{ | |
| .raw_bytes = middle_super_box, | |
| .payload = SuperBox{.description = | |
| DescriptionBox{ | |
| .type_uuid = | |
| Uuid::FromStringOrDie(kFakeUuid), | |
| .label = "fakelabel", | |
| }, | |
| .contents = {ContentBox{ | |
| .raw_bytes = inner_super_box, | |
| .payload = | |
| SerializedSuperbox{ | |
| .serialized = inner_super_box, | |
| }}}, | |
| .raw_bytes = middle_super_box}}}, | |
| .raw_bytes = outer_super_box})); | |
| EXPECT_THAT(serialized_view, IsEmpty()); | |
| } | |
| TEST(ParseTest, SingleUnknownContentBoxSucceeds) { | |
| constexpr absl::string_view kUnknownContent = | |
| R"(this is some data in a format this parser does not understand)"; | |
| std::string description_box = | |
| WrapBox(FakeDescriptionBoxContents(), kDescriptionBoxType); | |
| std::string content_box = WrapBox(kUnknownContent, 12345678); | |
| std::string super_box = | |
| WrapBox(absl::StrCat(description_box, content_box), kSuperBoxType); | |
| absl::string_view serialized_view = super_box; | |
| EXPECT_THAT(ConsumeSuperBox(&serialized_view, /*recursion_limit=*/1), | |
| IsOkAndHolds(SuperBox{ | |
| .description = | |
| DescriptionBox{ | |
| .type_uuid = Uuid::FromStringOrDie(kFakeUuid), | |
| .label = "fakelabel", | |
| }, | |
| .contents = {ContentBox{.raw_bytes = content_box, | |
| .payload = | |
| UnknownBox{ | |
| .type = 12345678, | |
| .payload = kUnknownContent, | |
| }}}, | |
| .raw_bytes = super_box})); | |
| EXPECT_THAT(serialized_view, IsEmpty()); | |
| } | |
| TEST(ParseTest, ExcessContentSucceeds) { | |
| constexpr absl::string_view kFakeCborData = | |
| R"(the function under test does not actually parse CBOR data so we'll just use a totally fake string here)"; | |
| constexpr absl::string_view kExtraData = | |
| R"(this is some extra data in the input, the parser should not look at this)"; | |
| std::string description_box = | |
| WrapBox(FakeDescriptionBoxContents(), kDescriptionBoxType); | |
| std::string content_box = WrapBox(kFakeCborData, kCborBoxType); | |
| std::string super_box = absl::StrCat( | |
| WrapBox(absl::StrCat(description_box, content_box), kSuperBoxType), | |
| kExtraData); | |
| absl::string_view serialized_view = super_box; | |
| EXPECT_THAT(ConsumeSuperBox(&serialized_view, /*recursion_limit=*/1), | |
| IsOkAndHolds(SuperBox{ | |
| .description = | |
| DescriptionBox{ | |
| .type_uuid = Uuid::FromStringOrDie(kFakeUuid), | |
| .label = "fakelabel", | |
| }, | |
| .contents = {ContentBox{.raw_bytes = content_box, | |
| .payload = | |
| CborBox{ | |
| .payload = kFakeCborData, | |
| }}}, | |
| .raw_bytes = super_box.substr( | |
| 0, super_box.size() - kExtraData.size())})); | |
| EXPECT_THAT(serialized_view, Eq(kExtraData)); | |
| } | |
| TEST(ParseTest, SingleJsonDataBoxSucceeds) { | |
| constexpr absl::string_view kPayload = R"({"abc": "xyz"})"; | |
| std::string description_box = | |
| WrapBox(FakeDescriptionBoxContents(), kDescriptionBoxType); | |
| std::string content_box = WrapBox(kPayload, kJsonBoxType); | |
| std::string super_box = | |
| WrapBox(absl::StrCat(description_box, content_box), kSuperBoxType); | |
| absl::string_view serialized_view = super_box; | |
| auto superbox_or = ConsumeSuperBox(&serialized_view, /*recursion_limit=*/1); | |
| ASSERT_TRUE(superbox_or.ok()); | |
| auto superbox = std::move(*superbox_or); | |
| EXPECT_THAT(superbox, | |
| Eq(SuperBox{.description = | |
| DescriptionBox{ | |
| .type_uuid = Uuid::FromStringOrDie(kFakeUuid), | |
| .label = "fakelabel", | |
| }, | |
| .contents = {ContentBox{.raw_bytes = content_box, | |
| .payload = | |
| JsonBox{ | |
| .payload = kPayload, | |
| }}}, | |
| .raw_bytes = super_box})); | |
| EXPECT_THAT(serialized_view, IsEmpty()); | |
| } | |
| TEST(ParseTest, UuidBoxSucceeds) { | |
| std::string uuid_box_payload = jumbf::kC2PARedactionUuid.ToProtoBytes(); | |
| absl::string_view payload = uuid_box_payload; | |
| std::string description_box = | |
| WrapBox(FakeDescriptionBoxContents(), kDescriptionBoxType); | |
| std::string content_box = WrapBox(payload, kUuidBoxType); | |
| std::string super_box = | |
| WrapBox(absl::StrCat(description_box, content_box), kSuperBoxType); | |
| absl::string_view serialized_view = super_box; | |
| auto superbox_or = ConsumeSuperBox(&serialized_view, /*recursion_limit=*/1); | |
| ASSERT_TRUE(superbox_or.ok()); | |
| auto superbox = std::move(*superbox_or); | |
| EXPECT_THAT(superbox, | |
| Eq(SuperBox{.description = | |
| DescriptionBox{ | |
| .type_uuid = Uuid::FromStringOrDie(kFakeUuid), | |
| .label = "fakelabel", | |
| }, | |
| .contents = {ContentBox{.raw_bytes = content_box, | |
| .payload = | |
| UuidBox{ | |
| .payload = payload, | |
| }}}, | |
| .raw_bytes = super_box})); | |
| EXPECT_THAT(serialized_view, IsEmpty()); | |
| } | |
| } // namespace | |
| } // namespace jumbf |