• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2024 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef BASE_TEST_FUZZTEST_SUPPORT_H_
6 #define BASE_TEST_FUZZTEST_SUPPORT_H_
7 
8 #include <optional>
9 #include <string>
10 #include <tuple>
11 #include <vector>
12 
13 #include "base/containers/to_vector.h"
14 #include "base/types/optional_ref.h"
15 #include "base/values.h"
16 #include "third_party/fuzztest/src/fuzztest/fuzztest.h"
17 
18 namespace {
19 
20 template <typename T>
21   requires std::copy_constructible<T>
Wrap(base::optional_ref<const T> maybe_value)22 std::optional<std::tuple<T>> Wrap(base::optional_ref<const T> maybe_value) {
23   return maybe_value.has_value() ? std::optional(std::tuple<T>{*maybe_value})
24                                  : std::nullopt;
25 }
26 
ArbitraryValueNull()27 auto ArbitraryValueNull() {
28   return fuzztest::ReversibleMap(
29       [] { return base::Value(); },
30       [](const base::Value& value) { return std::optional<std::tuple<>>{}; });
31 }
32 
ArbitraryValueBool()33 auto ArbitraryValueBool() {
34   return fuzztest::ReversibleMap(
35       [](bool boolean) { return base::Value(boolean); },
36       [](const base::Value& value) { return Wrap<bool>(value.GetIfBool()); },
37       fuzztest::Arbitrary<bool>());
38 }
39 
ArbitraryValueInt()40 auto ArbitraryValueInt() {
41   return fuzztest::ReversibleMap(
42       [](int number) { return base::Value(number); },
43       [](const base::Value& value) { return Wrap<int>(value.GetIfInt()); },
44       fuzztest::Arbitrary<int>());
45 }
46 
ArbitraryValueDouble()47 auto ArbitraryValueDouble() {
48   return fuzztest::ReversibleMap(
49       [](double number) { return base::Value(number); },
50       [](const base::Value& value) {
51         return Wrap<double>(value.GetIfDouble());
52       },
53       fuzztest::Finite<double>());
54 }
55 
ArbitraryValueString()56 auto ArbitraryValueString() {
57   return fuzztest::ReversibleMap(
58       [](std::string string) { return base::Value(string); },
59       [](const base::Value& value) {
60         return Wrap<std::string>(value.GetIfString());
61       },
62       fuzztest::String());
63 }
64 
ArbitraryValueBlob()65 auto ArbitraryValueBlob() {
66   return fuzztest::ReversibleMap(
67       [](std::vector<uint8_t> blob) { return base::Value(blob); },
68       [](const base::Value& value) {
69         return Wrap<std::vector<uint8_t>>(value.GetIfBlob());
70       },
71       fuzztest::Arbitrary<std::vector<uint8_t>>());
72 }
73 
ArbitraryValueList(fuzztest::Domain<base::Value> entry_domain)74 auto ArbitraryValueList(fuzztest::Domain<base::Value> entry_domain) {
75   return fuzztest::ReversibleMap(
76       [](std::vector<base::Value> values) {
77         base::Value::List list;
78         for (auto& value : values) {
79           list.Append(std::move(value));
80         }
81         return base::Value(std::move(list));
82       },
83       [](const base::Value& value) {
84         auto maybe_list = base::optional_ref(value.GetIfList());
85         return maybe_list.has_value()
86                    ? std::make_optional(std::tuple{
87                          base::ToVector(*maybe_list, &base::Value::Clone)})
88                    : std::nullopt;
89       },
90       fuzztest::ContainerOf<std::vector<base::Value>>(entry_domain));
91 }
92 
ArbitraryValueDict(fuzztest::Domain<base::Value> value_domain)93 auto ArbitraryValueDict(fuzztest::Domain<base::Value> value_domain) {
94   return fuzztest::ReversibleMap(
95       [](std::vector<std::pair<std::string, base::Value>> e) {
96         return base::Value(base::Value::Dict(std::make_move_iterator(e.begin()),
97                                              std::make_move_iterator(e.end())));
98       },
99       [](const base::Value& value) {
100         auto maybe_dict = base::optional_ref(value.GetIfDict());
101         return maybe_dict.has_value()
102                    ? std::make_optional(std::tuple{base::ToVector(
103                          *maybe_dict,
104                          [](const auto& entry) {
105                            return std::make_pair(entry.first,
106                                                  entry.second.Clone());
107                          })})
108                    : std::nullopt;
109       },
110       fuzztest::ContainerOf<std::vector<std::pair<std::string, base::Value>>>(
111           fuzztest::PairOf(fuzztest::String(), value_domain)));
112 }
113 
ArbitraryValue()114 fuzztest::Domain<base::Value> ArbitraryValue() {
115   fuzztest::DomainBuilder builder;
116   builder.Set<base::Value>(
117       "value",
118       fuzztest::OneOf(ArbitraryValueNull(), ArbitraryValueBool(),
119                       ArbitraryValueInt(), ArbitraryValueDouble(),
120                       ArbitraryValueString(), ArbitraryValueBlob(),
121                       ArbitraryValueList(builder.Get<base::Value>("value")),
122                       ArbitraryValueDict(builder.Get<base::Value>("value"))));
123   return std::move(builder).Finalize<base::Value>("value");
124 }
125 
126 }  // namespace
127 
128 template <>
129 class fuzztest::internal::ArbitraryImpl<base::Value>
130     : public fuzztest::Domain<base::Value> {
131  public:
ArbitraryImpl()132   ArbitraryImpl() : fuzztest::Domain<base::Value>(ArbitraryValue()) {}
133 };
134 
135 template <>
136 class fuzztest::internal::ArbitraryImpl<base::Value::Dict>
137     : public fuzztest::internal::ReversibleMapImpl<
138           base::Value::Dict (*)(
139               std::vector<std::pair<std::string, base::Value>>),
140           std::optional<
141               std::tuple<std::vector<std::pair<std::string, base::Value>>>> (*)(
142               const base::Value::Dict&),
143           fuzztest::internal::ArbitraryImpl<
144               std::vector<std::pair<std::string, base::Value>>>> {
145  public:
ArbitraryImpl()146   ArbitraryImpl()
147       : fuzztest::internal::ReversibleMapImpl<
148             base::Value::Dict (*)(
149                 std::vector<std::pair<std::string, base::Value>>),
150             std::optional<std::tuple<
151                 std::vector<std::pair<std::string, base::Value>>>> (*)(
152                 const base::Value::Dict&),
153             fuzztest::internal::ArbitraryImpl<
154                 std::vector<std::pair<std::string, base::Value>>>>(
155             [](std::vector<std::pair<std::string, base::Value>> e) {
156               return base::Value::Dict(std::make_move_iterator(e.begin()),
157                                        std::make_move_iterator(e.end()));
158             },
159             [](const base::Value::Dict& value) {
160               return std::make_optional(
161                   std::tuple{base::ToVector(value, [](const auto& entry) {
162                     return std::make_pair(entry.first, entry.second.Clone());
163                   })});
164             },
165             fuzztest::internal::ArbitraryImpl<
166                 std::vector<std::pair<std::string, base::Value>>>()) {}
167 };
168 
169 #endif  // BASE_TEST_FUZZTEST_SUPPORT_H_
170