blob: ff5d45ace01646b8f1e229a288ff3f6284b3d950 [file] [log] [blame]
// Copyright 2024 Google LLC
// SPDX-License-Identifier: BSD-2-Clause
#include <array>
#include <cstdint>
#include <cstring>
#include <memory>
#include <vector>
#include "avif/avif.h"
#include "avif/internal.h"
#include "avif_fuzztest_helpers.h"
#include "aviftest_helpers.h"
#include "fuzztest/fuzztest.h"
#include "gtest/gtest.h"
namespace avif {
namespace testutil {
namespace {
struct TestProp {
std::array<uint8_t, 4> fourcc;
std::array<uint8_t, 16> uuid;
std::vector<uint8_t> body;
};
void EncodeDecode(ImagePtr image, EncoderPtr encoder, DecoderPtr decoder,
const std::vector<TestProp>& test_props) {
ImagePtr decoded_image(avifImageCreateEmpty());
ASSERT_NE(image.get(), nullptr);
ASSERT_NE(encoder.get(), nullptr);
ASSERT_NE(decoder.get(), nullptr);
ASSERT_NE(decoded_image.get(), nullptr);
std::vector<TestProp> valid_test_properties;
for (const TestProp& testProp : test_props) {
if (testProp.fourcc == std::array<uint8_t, 4>{'u', 'u', 'i', 'd'}) {
const avifResult result =
avifImageAddUUIDProperty(image.get(), testProp.uuid.data(),
testProp.body.data(), testProp.body.size());
if (avifIsValidUUID(testProp.uuid.data())) {
valid_test_properties.push_back(testProp);
ASSERT_EQ(result, AVIF_RESULT_OK);
} else {
ASSERT_EQ(result, AVIF_RESULT_INVALID_ARGUMENT);
}
} else {
const avifResult result = avifImageAddOpaqueProperty(
image.get(), testProp.fourcc.data(), testProp.body.data(),
testProp.body.size());
if (avifIsKnownPropertyType(testProp.fourcc.data())) {
ASSERT_EQ(result, AVIF_RESULT_INVALID_ARGUMENT);
} else {
valid_test_properties.push_back(testProp);
ASSERT_EQ(result, AVIF_RESULT_OK);
}
}
}
AvifRwData encoded_data;
const avifResult encoder_result =
avifEncoderWrite(encoder.get(), image.get(), &encoded_data);
ASSERT_EQ(encoder_result, AVIF_RESULT_OK)
<< avifResultToString(encoder_result);
const avifResult decoder_result = avifDecoderReadMemory(
decoder.get(), decoded_image.get(), encoded_data.data, encoded_data.size);
ASSERT_EQ(decoder_result, AVIF_RESULT_OK)
<< avifResultToString(decoder_result);
ASSERT_EQ(decoder->image->numProperties, valid_test_properties.size());
for (size_t i = 0; i < valid_test_properties.size(); i++) {
const TestProp& testProp = valid_test_properties[i];
const avifImageItemProperty& decodeProp = decoder->image->properties[i];
EXPECT_EQ(std::string(decodeProp.boxtype, decodeProp.boxtype + 4),
std::string(testProp.fourcc.data(), testProp.fourcc.data() + 4));
EXPECT_EQ(std::vector<uint8_t>(
decodeProp.boxPayload.data,
decodeProp.boxPayload.data + decodeProp.boxPayload.size),
testProp.body);
}
}
inline auto ArbitraryProp() {
auto fourcc = fuzztest::Arbitrary<std::array<uint8_t, 4>>();
auto uuid = fuzztest::Arbitrary<std::array<uint8_t, 16>>(); // ignored
auto body = fuzztest::Arbitrary<std::vector<uint8_t>>();
return fuzztest::StructOf<TestProp>(fourcc, uuid, body);
}
inline auto ArbitraryUUIDProp() {
auto fourcc = fuzztest::Just(std::array<uint8_t, 4>{'u', 'u', 'i', 'd'});
auto uuid = fuzztest::Arbitrary<std::array<uint8_t, 16>>();
auto body = fuzztest::Arbitrary<std::vector<uint8_t>>();
return fuzztest::StructOf<TestProp>(fourcc, uuid, body);
}
inline auto ArbitraryProps() {
return fuzztest::VectorOf(
fuzztest::OneOf(ArbitraryProp(), ArbitraryUUIDProp()))
.WithMaxSize(
/*maximum unique property count for an avifEncoder instance*/ 127 -
/*maximum unique property count used by libavif*/ 16);
}
FUZZ_TEST(PropertiesAvifFuzzTest, EncodeDecode)
.WithDomains(ArbitraryAvifImage(), ArbitraryAvifEncoder(),
ArbitraryAvifDecoder(), ArbitraryProps());
} // namespace
} // namespace testutil
} // namespace avif