blob: 2a1bcedf2e136b14f23465245b432454eb3ceef1 [file] [edit]
// 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/internal/parse_embedded_file_description_box.h"
#include <cstdint>
#include <cstring>
#include <string>
#include "absl/status/status.h"
#include "absl/status/status_matchers.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "jumbf/box.h"
#include "jumbf/constants.h"
#include "jumbf/internal/intermediate.h"
#include "riegeli/endian/endian_writing.h"
namespace jumbf_internal {
namespace {
using ::absl_testing::IsOkAndHolds;
using ::absl_testing::StatusIs;
TEST(ParseEmbeddedFileDescriptionBoxTest, ParseOkAllToggles) {
constexpr uint8_t kToggles =
jumbf::kEfdbToggleFileNamePresent | jumbf::kEfdbToggleExternal;
// Can't use absl::string_view because the linter does not believe it is
// null terminated, even when the underlying string definitely is.
constexpr const char kFakeMediatype[] = "media/MyFormat";
constexpr const char kFakePath[] = "path/to/some/file";
const size_t payload_length =
1 /*toggles*/ + sizeof(kFakeMediatype) + sizeof(kFakePath);
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);
memcpy(cursor, kFakePath, sizeof(kFakePath));
cursor += sizeof(kFakePath);
const IntermediateBox unwrapped_box{
.payload = payload,
.type = jumbf::kEmbeddedFileDescriptionBoxType,
};
auto efdb = ParseEmbeddedFileDescriptionBox(unwrapped_box);
EXPECT_THAT(efdb, IsOkAndHolds(jumbf::EmbeddedFileDescriptionBox{
.media_type = kFakeMediatype,
.external = true,
.file_name = kFakePath,
}));
}
TEST(ParseEmbeddedFileDescriptionBoxTest, ParseOkFileNamePresent) {
constexpr uint8_t kToggles = jumbf::kEfdbToggleFileNamePresent;
// Can't use absl::string_view because the linter does not believe it is
// null terminated, even when the underlying string definitely is.
constexpr const char kFakeMediatype[] = "media/MyFormat";
constexpr const char kFakePath[] = "path/to/some/file";
const size_t payload_length =
1 /*toggles*/ + sizeof(kFakeMediatype) + sizeof(kFakePath);
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);
memcpy(cursor, kFakePath, sizeof(kFakePath));
cursor += sizeof(kFakePath);
const IntermediateBox unwrapped_box{
.payload = payload,
.type = jumbf::kEmbeddedFileDescriptionBoxType,
};
auto efdb = ParseEmbeddedFileDescriptionBox(unwrapped_box);
EXPECT_THAT(efdb, IsOkAndHolds(jumbf::EmbeddedFileDescriptionBox{
.media_type = kFakeMediatype,
.external = false,
.file_name = kFakePath,
}));
}
TEST(ParseEmbeddedFileDescriptionBoxTest, ParseOkExternal) {
constexpr uint8_t kToggles = jumbf::kEfdbToggleExternal;
// Can't use absl::string_view because the linter does not believe it is
// null terminated, even when the underlying string definitely is.
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);
const IntermediateBox unwrapped_box{
.payload = payload,
.type = jumbf::kEmbeddedFileDescriptionBoxType,
};
auto efdb = ParseEmbeddedFileDescriptionBox(unwrapped_box);
EXPECT_THAT(efdb, IsOkAndHolds(jumbf::EmbeddedFileDescriptionBox{
.media_type = kFakeMediatype,
.external = true,
}));
}
TEST(ParseEmbeddedFileDescriptionBoxTest, ParseOkNoTogglesl) {
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);
const IntermediateBox unwrapped_box{
.payload = payload,
.type = jumbf::kEmbeddedFileDescriptionBoxType,
};
auto efdb = ParseEmbeddedFileDescriptionBox(unwrapped_box);
EXPECT_THAT(efdb, IsOkAndHolds(jumbf::EmbeddedFileDescriptionBox{
.media_type = kFakeMediatype,
.external = false,
}));
}
TEST(ParseEmbeddedFileDescriptionBoxTest, WrongTypeFails) {
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);
const IntermediateBox unwrapped_box{
.payload = payload,
.type = jumbf::kSuperBoxType,
};
auto efdb = ParseEmbeddedFileDescriptionBox(unwrapped_box);
EXPECT_THAT(efdb, StatusIs(absl::StatusCode::kInvalidArgument,
"box is not an embedded file description box; got "
"type 0x6a756d62 need 0x62666462 ('bfdb')"));
}
TEST(ParseEmbeddedFileDescriptionBoxTest, ExtraDataFails) {
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);
payload.append("some extra data nobody asked for");
const IntermediateBox unwrapped_box{
.payload = payload,
.type = jumbf::kEmbeddedFileDescriptionBoxType,
};
auto efdb = ParseEmbeddedFileDescriptionBox(unwrapped_box);
EXPECT_THAT(
efdb,
StatusIs(absl::StatusCode::kInvalidArgument,
"excess data in embedded file description box payload; after "
"parsing complete, valid payload, 32 bytes were remaining"));
}
} // namespace
} // namespace jumbf_internal