/src/libavif/tests/gtest/avif_fuzztest_properties.cc
Line | Count | Source |
1 | | // Copyright 2024 Google LLC |
2 | | // SPDX-License-Identifier: BSD-2-Clause |
3 | | |
4 | | #include <array> |
5 | | #include <cstdint> |
6 | | #include <cstring> |
7 | | #include <memory> |
8 | | #include <vector> |
9 | | |
10 | | #include "avif/avif.h" |
11 | | #include "avif/internal.h" |
12 | | #include "avif_fuzztest_helpers.h" |
13 | | #include "aviftest_helpers.h" |
14 | | #include "fuzztest/fuzztest.h" |
15 | | #include "gtest/gtest.h" |
16 | | |
17 | | namespace avif { |
18 | | namespace testutil { |
19 | | namespace { |
20 | | |
21 | | struct TestProp { |
22 | | std::array<uint8_t, 4> fourcc; |
23 | | std::array<uint8_t, 16> uuid; |
24 | | std::vector<uint8_t> body; |
25 | | }; |
26 | | |
27 | | void EncodeDecode(ImagePtr image, EncoderPtr encoder, DecoderPtr decoder, |
28 | 13.7k | const std::vector<TestProp>& test_props) { |
29 | 13.7k | ImagePtr decoded_image(avifImageCreateEmpty()); |
30 | 13.7k | ASSERT_NE(image.get(), nullptr); |
31 | 13.7k | ASSERT_NE(encoder.get(), nullptr); |
32 | 13.7k | ASSERT_NE(decoder.get(), nullptr); |
33 | 13.7k | ASSERT_NE(decoded_image.get(), nullptr); |
34 | | |
35 | 13.7k | std::vector<TestProp> valid_test_properties; |
36 | 13.7k | for (const TestProp& testProp : test_props) { |
37 | 3.74k | if (testProp.fourcc == std::array<uint8_t, 4>{'u', 'u', 'i', 'd'}) { |
38 | 2.49k | const avifResult result = |
39 | 2.49k | avifImageAddUUIDProperty(image.get(), testProp.uuid.data(), |
40 | 2.49k | testProp.body.data(), testProp.body.size()); |
41 | 2.49k | if (avifIsValidUUID(testProp.uuid.data())) { |
42 | 1.44k | valid_test_properties.push_back(testProp); |
43 | 1.44k | ASSERT_EQ(result, AVIF_RESULT_OK); |
44 | 1.44k | } else { |
45 | 1.04k | ASSERT_EQ(result, AVIF_RESULT_INVALID_ARGUMENT); |
46 | 1.04k | } |
47 | 2.49k | } else { |
48 | 1.25k | const avifResult result = avifImageAddOpaqueProperty( |
49 | 1.25k | image.get(), testProp.fourcc.data(), testProp.body.data(), |
50 | 1.25k | testProp.body.size()); |
51 | 1.25k | if (avifIsKnownPropertyType(testProp.fourcc.data())) { |
52 | 0 | ASSERT_EQ(result, AVIF_RESULT_INVALID_ARGUMENT); |
53 | 1.25k | } else { |
54 | 1.25k | valid_test_properties.push_back(testProp); |
55 | 1.25k | ASSERT_EQ(result, AVIF_RESULT_OK); |
56 | 1.25k | } |
57 | 1.25k | } |
58 | 3.74k | } |
59 | | |
60 | 13.7k | AvifRwData encoded_data; |
61 | 13.7k | const avifResult encoder_result = |
62 | 13.7k | avifEncoderWrite(encoder.get(), image.get(), &encoded_data); |
63 | 27.5k | ASSERT_EQ(encoder_result, AVIF_RESULT_OK) |
64 | 27.5k | << avifResultToString(encoder_result); |
65 | | |
66 | 13.7k | const avifResult decoder_result = avifDecoderReadMemory( |
67 | 13.7k | decoder.get(), decoded_image.get(), encoded_data.data, encoded_data.size); |
68 | 27.5k | ASSERT_EQ(decoder_result, AVIF_RESULT_OK) |
69 | 27.5k | << avifResultToString(decoder_result); |
70 | | |
71 | 13.7k | ASSERT_EQ(decoder->image->numProperties, valid_test_properties.size()); |
72 | 16.4k | for (size_t i = 0; i < valid_test_properties.size(); i++) { |
73 | 2.69k | const TestProp& testProp = valid_test_properties[i]; |
74 | 2.69k | const avifImageItemProperty& decodeProp = decoder->image->properties[i]; |
75 | 2.69k | EXPECT_EQ(std::string(decodeProp.boxtype, decodeProp.boxtype + 4), |
76 | 2.69k | std::string(testProp.fourcc.data(), testProp.fourcc.data() + 4)); |
77 | 2.69k | EXPECT_EQ(std::vector<uint8_t>( |
78 | 2.69k | decodeProp.boxPayload.data, |
79 | 2.69k | decodeProp.boxPayload.data + decodeProp.boxPayload.size), |
80 | 2.69k | testProp.body); |
81 | 2.69k | } |
82 | 13.7k | } |
83 | | |
84 | 2 | inline auto ArbitraryProp() { |
85 | 2 | auto fourcc = fuzztest::Arbitrary<std::array<uint8_t, 4>>(); |
86 | 2 | auto uuid = fuzztest::Arbitrary<std::array<uint8_t, 16>>(); // ignored |
87 | 2 | auto body = fuzztest::Arbitrary<std::vector<uint8_t>>(); |
88 | 2 | return fuzztest::StructOf<TestProp>(fourcc, uuid, body); |
89 | 2 | } |
90 | | |
91 | 2 | inline auto ArbitraryUUIDProp() { |
92 | 2 | auto fourcc = fuzztest::Just(std::array<uint8_t, 4>{'u', 'u', 'i', 'd'}); |
93 | 2 | auto uuid = fuzztest::Arbitrary<std::array<uint8_t, 16>>(); |
94 | 2 | auto body = fuzztest::Arbitrary<std::vector<uint8_t>>(); |
95 | 2 | return fuzztest::StructOf<TestProp>(fourcc, uuid, body); |
96 | 2 | } |
97 | | |
98 | 2 | inline auto ArbitraryProps() { |
99 | 2 | return fuzztest::VectorOf( |
100 | 2 | fuzztest::OneOf(ArbitraryProp(), ArbitraryUUIDProp())) |
101 | 2 | .WithMaxSize( |
102 | 2 | /*maximum unique property count for an avifEncoder instance*/ 127 - |
103 | 2 | /*maximum unique property count used by libavif*/ 16); |
104 | 2 | } |
105 | | |
106 | | FUZZ_TEST(PropertiesAvifFuzzTest, EncodeDecode) |
107 | | .WithDomains(ArbitraryAvifImage(), ArbitraryAvifEncoder(), |
108 | | ArbitraryAvifDecoder(), ArbitraryProps()); |
109 | | |
110 | | } // namespace |
111 | | } // namespace testutil |
112 | | } // namespace avif |