blob: 16137d2a27dd89d1ca8be74622decc72d248351e [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 "formats/registry.h"
#include <memory>
#include <optional>
#include <string>
#include <utility>
#include <vector>
#include "absl/status/status.h"
#include "absl/status/status_macros.h" // IWYU pragma: keep
#include "absl/status/status_matchers.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "formats/assessor.h"
#include "formats/asset_box.h"
#include "formats/byte_range.h"
#include "formats/extractor.h"
#include "formats/format.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "riegeli/bytes/reader.h"
#include "riegeli/bytes/string_reader.h"
namespace credentio {
namespace {
using ::absl_testing::IsOkAndHolds;
using ::absl_testing::StatusIs;
using ::testing::HasSubstr;
class ErrorAssessor : public FormatAssessor {
public:
ErrorAssessor() = default;
~ErrorAssessor() override = default;
absl::StatusOr<bool> IsSupported(riegeli::Reader& input) const override {
return absl::UnimplementedError("Not implemented");
}
};
class PassAssessor : public FormatAssessor {
public:
PassAssessor() = default;
~PassAssessor() override = default;
absl::StatusOr<bool> IsSupported(riegeli::Reader& input) const override {
return true;
}
};
class FailAssessor : public FormatAssessor {
public:
FailAssessor() = default;
~FailAssessor() override = default;
absl::StatusOr<bool> IsSupported(riegeli::Reader& input) const override {
return false;
}
};
class FakeExtractor : public FormatExtractor {
public:
FakeExtractor() = default;
~FakeExtractor() override = default;
absl::StatusOr<std::string> ExtractManifestStore(
riegeli::Reader& input) const override {
return absl::UnimplementedError("Not implemented");
}
absl::StatusOr<std::optional<ByteRange>> ExtractManifestStoreLocation(
riegeli::Reader& input, ExtractOptions options) const override {
return absl::UnimplementedError("Not implemented");
}
absl::StatusOr<std::vector<AssetBox>> ExtractBoxes(
riegeli::Reader& input, ExtractOptions options) const override {
return absl::UnimplementedError("Not implemented");
}
bool MightBeC2paManifestStore(absl::string_view payload) const override {
return true;
}
};
class FormatRegistryTest : public ::testing::Test {
protected:
void SetUp() override { registry_ = std::make_unique<FormatRegistry>(); }
void RegisterErrorFormat(std::vector<std::string> mime_types) {
auto format = Format::Create(FormatOptions{
.assessor = std::make_unique<ErrorAssessor>(),
.extractor = std::make_unique<FakeExtractor>(),
.mime_types = std::move(mime_types),
});
ABSL_ASSERT_OK(format);
registry_->Register(*std::move(format));
}
void RegisterSuccessFormat(std::vector<std::string> mime_types) {
auto format = Format::Create(FormatOptions{
.assessor = std::make_unique<PassAssessor>(),
.extractor = std::make_unique<FakeExtractor>(),
.mime_types = std::move(mime_types),
});
ABSL_ASSERT_OK(format);
registry_->Register(*std::move(format));
}
void RegisterFailFormat(std::vector<std::string> mime_types) {
auto format = Format::Create(FormatOptions{
.assessor = std::make_unique<FailAssessor>(),
.extractor = std::make_unique<FakeExtractor>(),
.mime_types = std::move(mime_types),
});
ABSL_ASSERT_OK(format);
registry_->Register(*std::move(format));
}
std::unique_ptr<FormatRegistry> registry_;
};
TEST_F(FormatRegistryTest, MediaTypeNotFound) {
EXPECT_THAT(registry_->GetFormat("jpeg"),
StatusIs(absl::StatusCode::kUnimplemented,
HasSubstr("Unsupported media type: jpeg")));
}
TEST_F(FormatRegistryTest, MediaTypeWithSingleFormat) {
RegisterSuccessFormat({"jpeg"});
EXPECT_THAT(registry_->GetFormat("jpeg"), IsOkAndHolds(testing::NotNull()));
}
TEST_F(FormatRegistryTest, MediaTypeWithMultipleFormats) {
RegisterSuccessFormat({"jpeg"});
RegisterSuccessFormat({"jpeg"});
EXPECT_THAT(registry_->GetFormat("jpeg"),
StatusIs(absl::StatusCode::kUnimplemented,
HasSubstr("Multiple formats support media type: jpeg")));
}
TEST_F(FormatRegistryTest, AssetNotSupported) {
RegisterFailFormat({"jpeg"});
std::string asset = "asset";
riegeli::StringReader<> input(asset);
EXPECT_THAT(registry_->GetFormat(input),
StatusIs(absl::StatusCode::kUnimplemented,
HasSubstr("No applicable Format found")));
}
TEST_F(FormatRegistryTest, AssetSupported) {
RegisterSuccessFormat({"jpeg"});
std::string asset = "asset";
riegeli::StringReader<> input(asset);
EXPECT_THAT(registry_->GetFormat(input), IsOkAndHolds(testing::NotNull()));
}
TEST_F(FormatRegistryTest, AssetFailsThenSupports) {
RegisterFailFormat({"other"});
RegisterSuccessFormat({"jpeg"});
std::string asset = "asset";
riegeli::StringReader<> input(asset);
EXPECT_THAT(registry_->GetFormat(input), IsOkAndHolds(testing::NotNull()));
}
TEST_F(FormatRegistryTest, MediaTypeAndAssetNotSupported) {
RegisterSuccessFormat({"other"});
std::string asset = "asset";
riegeli::StringReader<> input(asset);
EXPECT_THAT(registry_->GetFormat("jpeg", input),
StatusIs(absl::StatusCode::kUnimplemented,
HasSubstr("Unsupported media type: jpeg")));
}
TEST_F(FormatRegistryTest, MediaTypeAndAssetSingleFormat) {
RegisterSuccessFormat({"other"});
RegisterFailFormat({"jpeg"});
std::string asset = "asset";
riegeli::StringReader<> input(asset);
EXPECT_THAT(registry_->GetFormat("jpeg", input),
IsOkAndHolds(testing::NotNull()));
}
TEST_F(FormatRegistryTest, MediaTypeAndAssetMultipleFormat) {
RegisterSuccessFormat({"other"});
RegisterFailFormat({"jpeg"});
RegisterSuccessFormat({"jpeg"});
std::string asset = "asset";
riegeli::StringReader<> input(asset);
EXPECT_THAT(registry_->GetFormat("jpeg", input),
IsOkAndHolds(testing::NotNull()));
}
TEST_F(FormatRegistryTest, MediaTypeAndAssetNoApplicableFormats) {
RegisterSuccessFormat({"other"});
RegisterFailFormat({"jpeg"});
RegisterFailFormat({"jpeg"});
std::string asset = "asset";
riegeli::StringReader<> input(asset);
EXPECT_THAT(registry_->GetFormat("jpeg", input),
StatusIs(absl::StatusCode::kUnimplemented,
HasSubstr("No applicable Format found")));
}
} // namespace
} // namespace credentio