blob: 5d1d76f25fc070be6cf692d1bebf7ca37da2b2c6 [file]
// 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