chromium/third_party/fuzztest/src/fuzztest/domain_core.h

// Copyright 2022 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
//
//      http://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.

// IWYU pragma: private, include "fuzztest/fuzztest.h"
// IWYU pragma: friend fuzztest/.*

#ifndef FUZZTEST_FUZZTEST_DOMAIN_CORE_H_
#define FUZZTEST_FUZZTEST_DOMAIN_CORE_H_

#include <array>
#include <cmath>
#include <deque>
#include <initializer_list>
#include <limits>
#include <list>
#include <map>
#include <memory>
#include <optional>
#include <set>
#include <string>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <variant>
#include <vector>

#include "absl/container/flat_hash_map.h"
#include "absl/random/bit_gen_ref.h"
#include "absl/status/status.h"
#include "absl/strings/string_view.h"
#include "absl/types/span.h"
#include "./fuzztest/internal/any.h"
#include "./fuzztest/internal/domains/aggregate_of_impl.h"
#include "./fuzztest/internal/domains/arbitrary_impl.h"
#include "./fuzztest/internal/domains/bit_flag_combination_of_impl.h"
#include "./fuzztest/internal/domains/container_of_impl.h"
#include "./fuzztest/internal/domains/domain.h"  // IWYU pragma: export
#include "./fuzztest/internal/domains/domain_base.h"  // IWYU pragma: export
#include "./fuzztest/internal/domains/element_of_impl.h"
#include "./fuzztest/internal/domains/filter_impl.h"
#include "./fuzztest/internal/domains/flat_map_impl.h"
#include "./fuzztest/internal/domains/in_range_impl.h"
#include "./fuzztest/internal/domains/map_impl.h"
#include "./fuzztest/internal/domains/one_of_impl.h"
#include "./fuzztest/internal/domains/optional_of_impl.h"
#include "./fuzztest/internal/domains/smart_pointer_of_impl.h"
#include "./fuzztest/internal/domains/unique_elements_container_of_impl.h"
#include "./fuzztest/internal/domains/variant_of_impl.h"
#include "./fuzztest/internal/logging.h"
#include "./fuzztest/internal/meta.h"
#include "./fuzztest/internal/printer.h"  // IWYU pragma: export
#include "./fuzztest/internal/serialization.h"
#include "./fuzztest/internal/type_support.h"

namespace fuzztest {

class DomainBuilder {};

// This namespace is here only as a way to disable ADL (argument-dependent
// lookup). Names should be used from the fuzztest:: namespace.
namespace internal_no_adl {

// Arbitrary<T>() represents any value of type T.
//
// Example usage:
//
//   Arbitrary<int>()  // Any `int` value.
//
// The Arbitrary<T>() domain is implemented for all native C++ types and for
// protocol buffers. E.g.,:
//
//   Arbitrary<absl::flat_hash_map<uint32_t, MyProtoMessage>>()
//
template <typename T>
auto Arbitrary() {}

// ElementOf(values) represents the input domain composed of the explicitly
// listed `values`.
//
// Example usage:
//
//   ElementOf({0xDEADBEEF, 0xBADDCAFE, 0xFEEDFACE})
//
template <typename T>
auto ElementOf(std::initializer_list<T> values) {}

template <typename T>
auto ElementOf(std::vector<T> values) {}

template <typename T>
auto Just(T val) {}

template <int&... ExplicitArgumentBarrier, typename... Inner>
auto OneOf(Inner... domains) {}

// Filter(predicate, inner) combinator creates a domain that filters out values
// with `predicate` from an `inner` domain.
//
// IMPORTANT: Use this only to filter out a small subset of the original domain,
// otherwise fuzzing won't be effective.
//
// Example usage:
//
//   Filter([](int x) { return x != kSentinel; }, Arbitrary<int>())
//
template <int&... ExplicitArgumentBarrier, typename Inner, typename Pred>
auto Filter(Pred predicate, Inner inner) {}

// InRange(min, max) represents any value between [min, max], closed interval.
// Supports integral and floating point types.
//
// Example usage:
//
//   InRange(0.0, 1.0)  // Any probability value.
//
template <typename T>
auto InRange(T min, T max) {}

// Finite() represents any floating point number, that is not infinite or NaN.
//
// Example usage:
//
//   Finite<double>()  // Any finite double.
//
template <typename T>
auto Finite() {}

// Positive() represents any number greater than zero.
//
// Example usage:
//
//   Positive<float>()  // Any positive float value.
//
template <typename T>
auto Positive() {}

// NonNegative() represents any number not smaller than zero.
//
// Example usage:
//
//   NonNegative<float>()
//
template <typename T>
auto NonNegative() {}

// Negative() represents any number less than zero.
//
// Example usage:
//
//   Negative<float>()  // Any negative float value.
//
template <typename T>
auto Negative() {}

// NonPositive() represents any number not greater than zero.
//
// Example usage:
//
//   NonPositive<float>()
//
template <typename T>
auto NonPositive() {}

// NonZero() represents any number except zero.
//
// Example usage:
//
//   NonZero<float>()        // Any non-zero float value.
//
// If the type is unsigned, then the domain represents positive values. For
// example:
//
//   NonZero<unsigned int>() // Any positive int value.
//
template <typename T>
auto NonZero() {}

// BitFlagCombinationOf(flags) represents any combination of binary `flags` via
// bitwise operations.
//
// Example usage:
//
//   enum Options {
//     kFirst  = 1 << 0,
//     kSecond = 1 << 1,
//     kThird  = 1 << 2,
//   };
//
//   BitFlagCombinationOf({kFirst, kThird})
//
// will includes {0, kFirst, kThird,  kFirst | kThird}.
template <typename T>
auto BitFlagCombinationOf(std::initializer_list<T> flags) {}

template <typename T>
auto BitFlagCombinationOf(const std::vector<T>& flags) {}

// ContainerOf<T>(inner) combinator creates a domain for a container T (eg, a
// std::vector, std::set, etc) where elements are created from `inner`.
//
// Example usage:
//
//   ContainerOf<std::vector<int>>(InRange(1, 2021))
//
// The domain also supports customizing the minimum and maximum size via the
// `WithSize`, `WithMinSize` and `WithMaxSize` functions. Eg:
//
//   ContainerOf<std::vector<int>>(Arbitrary<int>()).WithMaxSize(5)
//
template <typename T, int&... ExplicitArgumentBarrier, typename Inner>
auto ContainerOf(Inner inner) {}

// If the container type `T` is a class template whose first template parameter
// is the type of values stored in the container, and whose other template
// parameters, if any, are optional, the template parameters of `T` may be
// omitted, in which case `ContainerOf` will use the `value_type` of the
// `elements_domain` as the first template parameter for T. For example:
//
//   ContainerOf<std::vector>(Positive<int>()).WithSize(3);
//
template <template <typename, typename...> class T,
          int&... ExplicitArgumentBarrier, typename Inner,
          typename C = T<internal::value_type_t<Inner>>>
auto ContainerOf(Inner inner) {}

// ASCII character domains.
inline auto NonZeroChar() {}
inline auto AsciiChar() {}
inline auto PrintableAsciiChar() {}
inline auto NumericChar() {}
inline auto LowerChar() {}
inline auto UpperChar() {}
inline auto AlphaChar() {}
inline auto AlphaNumericChar() {}

// String() is shorthand for Arbitrary<std::string>().
inline auto String() {}

// StringOf(inner) combinator creates a `std::string` domain with characters of
// the `inner` domain.
//
// Example usage:
//
//   StringOf(AsciiChar())
//
template <int&... ExplicitArgumentBarrier, typename Inner>
inline auto StringOf(Inner inner) {}

// AsciiString() represents `std::string`-s composed of ASCII characters.
inline auto AsciiString() {}

// PrintableAsciiString() represents `std::string`-s composed of printable ASCII
// characters.
inline auto PrintableAsciiString() {}

// StructOf<T>(inner...) combinator creates a user-defined type `T` domain with
// fields of the `inner...` domains.
//
// Example usage:
//
//   struct Thing {
//     int id;
//     std::string name;
//   };
//
//   StructOf<MyType>(InRange(0, 10), Arbitrary<std::string>())
//
template <typename T, int&... ExplicitArgumentBarrier, typename... Inner>
auto StructOf(Inner... inner) {}

// PairOf(inner1, inner2) combinator creates a `std::pair` domain where the
// first element is of `inner1` domain, and the second element is of `inner2`
// domain.
//
// Example usage:
//
//   PairOf(InRange(0, 10), Arbitrary<std::string>())
//
template <int&... ExplicitArgumentBarrier, typename Inner1, typename Inner2>
auto PairOf(Inner1 inner1, Inner2 inner2) {}

// TupleOf(inner...) combinator creates a `std::tuple` domain with elements of
// `inner...` domains.
//
// Example usage:
//
//   TupleOf(InRange(0, 10), Arbitrary<std::string>())
//
template <int&... ExplicitArgumentBarrier, typename... Inner>
auto TupleOf(Inner... inner) {}

// VariantOf(inner...) combinator creates a `std::variant` domain with elements
// of `inner...` domains.
//
// Example usage:
//
//   VariantOf(InRange(0, 10), Arbitrary<std::string>())
//
// VariantOf<T>(inner...) allows specifying a custom variant type `T`.
//
// Example usage:
//
//   VariantOf<absl::variant<int,std::string>>(InRange(0, 10),
//                                             Arbitrary<std::string>())
//
// `T` can be an instantiation of `std::variant` or any other class that matches
// its API. E.g., `absl::variant`.
template <typename T, int&... ExplicitArgumentBarrier, typename... Inner>
auto VariantOf(Inner... inner) {}

template <int&... ExplicitArgumentBarrier, typename... Inner>
auto VariantOf(Inner... inner) {}

// OptionalOf(inner) combinator creates a `std::optional` domain with the
// underlying value of the `inner` domain.
//
// Example usage:
//
//   OptionalOf(InRange(0, 10))
//
//
// OptionalOf<OptionalT>(inner) allows specifying a custom optional type
// `OptionalT`.
//
// Example usage:
//
//   OptionalOf<absl::optional<int>>(InRange(0, 10))
//
// `OptionalT` can be an instantiation of `std::optional` or any other class
// that matches its API. E.g., `absl::optional`.

template <typename OptionalT, int&... ExplicitArgumentBarrier, typename Inner>
auto OptionalOf(Inner inner) {}

template <int&... ExplicitArgumentBarrier, typename Inner>
auto OptionalOf(Inner inner) {}

// NullOpt<T>() creates an optional<T> domain with a single value std::nullopt.
template <typename T>
auto NullOpt() {}

// NonNull(inner) excludes `std::nullopt` from `inner` which needs to be
// an optional domain.
//
// Example usage:
//
//   NonNull(OptionalOf(InRange(0, 10)))
//
template <int&... ExplicitArgumentBarrier, typename Inner>
auto NonNull(Inner inner) {}

// SmartPointerOf<Ptr>(inner) combinator creates a domain for a smart pointer
// type `Ptr` to the object of `inner` domain.
//
// Example usage:
//
//   SmartPointerOf<std::unique_ptr<int>>(InRange(0, 10))
//
// The inner object will be created via `new` through the `inner` domain.
//
// Compatible with std::unique_ptr, std::shared_ptr, and other smart pointers of
// similar API. For std::unique_ptr and std::shared_ptr, use UniquePtrOf() and
// SharedPtrOf() instead.
template <typename Ptr, int&... ExplicitArgumentBarrier, typename Inner>
auto SmartPointerOf(Inner inner) {}

// UniquePtrOf(inner) combinator creates a `std::unique_ptr` domain with the
// pointed object of the `inner` domain.
//
// Example usage:
//
//   UniquePtrOf(InRange(0, 10))
//
template <int&... ExplicitArgumentBarrier, typename Inner>
auto UniquePtrOf(Inner inner) {}

// SharedPtrOf(inner) combinator creates a `std::shared_ptr` domain with the
// pointed object of the `inner` domain.
//
// Example usage:
//
//   SharedPtrOf(InRange(0, 10))
//
template <int&... ExplicitArgumentBarrier, typename Inner>
auto SharedPtrOf(Inner inner) {}

// Map(mapper, inner...) combinator creates a domain that uses the `mapper`
// function to map the values created by the `inner...` domains.
// Example usage:
//
//   Map([](int i) { return 2 * i; }, Arbitrary<int>())
//
// Note: `Map` doesn't support seeds. See `ReversibleMap` if you needs seeds.
template <int&... ExplicitArgumentBarrier, typename Mapper, typename... Inner>
auto Map(Mapper mapper, Inner... inner) {}

// ReversibleMap(mapper, inv_mapper, inner...) combinator creates a domain that
// uses the `mapper` function to map the values created by the `inner...`
// domains, and it uses the `inv_mapper` function to map the domain values back
// into the `inner...` domains. This enables seed support via the `.WithSeeds()`
// methods.
//
// The return type of `inv_mapper` should be `std::optional<std::tuple<T...>>`,
// where `T...` are the input types of `mapper`. Note that `std::tuple` is
// necessary even if `mapper` has a single parameter.
//
// Example:
//
//   ReversibleMap(
//       [](double real, double imag) {
//         return std::complex<double>{real, imag};
//       },
//       [](std::complex<double> z) {
//         return std::optional{std::tuple{z.real(), z.imag()}};
//       },
//       Arbitrary<double>(), Arbitrary<double>())
//
// The function `mapper` doesn't necessarily need to be one-to-one. If it isn't
// and it maps several inner domain tuples to the same value `y`, then
// `inv_mapper` can map `y` back to any of these inner domain tuples.
//
// Example:
//
//   ReversibleMap([](int a, int b) { return std::max(a, b); },
//                 [](int c) {
//                   return std::optional{std::tuple{c, c}};
//                 },
//                 Arbitrary<int>(), Arbitrary<int>())
//
// Importantly, if `inv_mapper` maps `y` to `std::tuple{x...}` and all values
// `x...` are in the respective inner domains, then `mapper` must map `x...` to
// `y`. By slightly abusing the notation, we can write this as
// `mapper(inv_mapper(y)) == y`.
//
// To ensure this property, `inv_mapper` may need to return `std::nullopt`.
//
// Example:
//
//   ReversibleMap(
//       [](int a, int b) {
//         return a > b ? std::pair{a, b} : std::pair{b, a};
//       },
//       [](std::pair<int, int> p) {
//         auto [a, b] = p;
//         return a >= b ? std::optional{std::tuple{a, b}} : std::nullopt;
//       },
//       Arbitrary<int>(), Arbitrary<int>())
//
// In this example, `mapper` always returns a pair `(a, b)` such that `a >= b`.
// Thus, when `a < b`, `inv_mapper` must return `std::nullopt` because there is
// no possible value it could return so that
//
//   `mapper(inv_mapper(std::pair{a, b})) == std::pair{a, b}`.
//
template <int&... ExplicitArgumentBarrier, typename Mapper, typename InvMapper,
          typename... Inner>
auto ReversibleMap(Mapper mapper, InvMapper inv_mapper, Inner... inner) {}

// `FlatMap(flat_mapper, inner...)` combinator creates a domain that uses the
// `flat_mapper` function to map the values created by the `inner...` domains.
// Unlike `Map`, however, `FlatMap` maps these into a new _domain_, instead of
// into a value. This domain can then be used as an argument to a fuzz test, or
// to another domain. This can be useful for generating values that depend on
// each other. Example usage:
//
//   // Generate domain of two equal-sized strings
//   FlatMap(
//     [](int size) {
//       return PairOf(Arbitrary<std::string>().WithSize(size),
//                     Arbitrary<std::string>().WithSize(size)); },
//     InRange(0, 10));
//
// Note: `FlatMap` doesn't support seeds.
template <int&... ExplicitArgumentBarrier, typename FlatMapper,
          typename... Inner>
auto FlatMap(FlatMapper flat_mapper, Inner... inner) {}

// VectorOf(inner) combinator creates a `std::vector` domain with elements of
// the `inner` domain.
//
// Example usage:
//
//   VectorOf(InRange(1, 2021))  // std::vector of years.
//
template <int&... ExplicitArgumentBarrier, typename Inner>
auto VectorOf(Inner inner) {}

// DequeOf(inner) combinator creates a `std::deque` domain with elements of the
// `inner` domain.
//
// Example usage:
//
//   DequeOf(InRange(1, 2021))
//
template <int&... ExplicitArgumentBarrier, typename Inner>
auto DequeOf(Inner inner) {}

// ListOf(inner) combinator creates a `std::list` domain with elements of the
// `inner` domain.
//
// Example usage:
//
//   ListOf(InRange(1, 2021))
//
template <int&... ExplicitArgumentBarrier, typename Inner>
auto ListOf(Inner inner) {}

// SetOf(inner) combinator creates a `std::set` domain with elements of the
// `inner` domain.
//
// Example usage:
//
//   SetOf(InRange(1, 2021))
//
template <int&... ExplicitArgumentBarrier, typename Inner>
auto SetOf(Inner inner) {}

// MapOf(key_domain, value_domain) combinator creates a `std::map` domain with
// keys from the `key_domain` domain, and values from the `value_domain` domain.
//
// Example usage:
//
//   MapOf(InRange(1, 100), Arbitrary<std::string>())
//
template <int&... ExplicitArgumentBarrier, typename KeyDomain,
          typename ValueDomain>
auto MapOf(KeyDomain key_domain, ValueDomain value_domain) {}

// UnorderedSetOf(inner) combinator creates a `std::unordered_set` domain with
// elements of the `inner` domain.
//
// Example usage:
//
//   UnorderedSetOf(InRange(1, 2021))
//
template <int&... ExplicitArgumentBarrier, typename Inner>
auto UnorderedSetOf(Inner inner) {}

// UnorderedMapOf(key_domain, value_domain) combinator creates a
// `std::unordered_map` domain with keys from the `key_domain` domain, and
// values from the `value_domain` domain.
//
// Example usage:
//
//   UnorderedMapOf(InRange(1, 100), Arbitrary<std::string>())
//
template <int&... ExplicitArgumentBarrier, typename KeyDomain,
          typename ValueDomain>
auto UnorderedMapOf(KeyDomain key_domain, ValueDomain value_domain) {}

// ArrayOf(inner...) combinator creates a `std::array` domain with N elements,
// one for each of the N domains of `inner...`. ArrayOf<N>(inner) is an overload
// for the case where a single domain `inner` generates values for all the `N`
// elements in the `std::array`.
//
// Example usage:
//
//   ArrayOf(InRange(1, 2021), InRange(1, 12))
//
// Generates `std::array<int, 2>` instances, where the values might represent
// year and month.
//
//   ArrayOf<3>(InRange(0.0, 1.0))
//
// Generates `std::array<double, 3>` instances, where the values might represent
// corrdinates in a unit cube.
//
template <int&... ExplicitArgumentBarrier, typename... Inner>
auto ArrayOf(Inner... inner) {}

template <int N, int&... ExplicitArgumentBarrier, typename Inner>
auto ArrayOf(const Inner& inner) {}

// UniqueElementsContainerOf(inner) combinator is similar to:
//
//   Map([](absl::flat_hash_set<value_type> unique_values) {
//        return T(unique_values.begin(), unique_values.end());
//     }, UnorderedSetOf(inner))
//
// Where `value_type` is the type of values produced by domain `inner`.
// UniqueElementsContainerOf creates an intermediate domain similar to:
//
//   ContainerOf<absl::flat_hash_set>(inner)
//
// That domain produces collections of instances of `value_type`, where each
// value in the collection is unique; this means that `value_type` must meet the
// type constraints necessary to create an instance of:
//
//   absl::flat_hash_set<value_type>
//
// Example usage:
//
//   UniqueElementsContainerOf<std::vector<int>>(InRange(1, 2021))
//
// The domain supports customizing the minimum and maximum size via the same
// functions as other container combinators: `WithSize`, `WithMinSize` and
// `WithMaxSize`. For example:
//
//   UniqueElementsContainerOf<std::vector<int>>(Arbitrary<int>()).WithSize(5)
//
template <typename T, int&... ExplicitArgumentBarrier, typename Inner>
auto UniqueElementsContainerOf(Inner inner) {}

// UniqueElementsVectorOf(inner) combinator is a shorthand for:
//
//   UniqueElementsContainerOf<std::vector<ElementT>>(inner)
//
// Where `ElementT` is the type of value produced by the domain `inner`.
//
// Example usage:
//
//   UniqueElementsVectorOf(InRange(1, 2021))
//
template <typename Inner>
auto UniqueElementsVectorOf(Inner inner) {}

// ConstructorOf<T>(inner...) combinator creates a user-defined type `T` domain
// by passing values from the `inner...` domains to T's constructor.
//
// Example usage:
//
//   class Thing {
//    public:
//     Thing(int a, std::string b);
//   };
//
//   ConstructorOf<Thing>(InRange(0, 5), Arbitrary<std::string>())
//
template <typename T, int&... ExplicitArgumentBarrier, typename... Inner>
auto ConstructorOf(Inner... inner) {}

// NonEmpty(inner) is shorthand for domain.WithMinSize(1).
//
// To represent any non-empty container one can use NonEmpty(), e.g.,
// NonEmpty(Arbitrary<std::vector<int>>()) or NonEmpty(VectorOf(String())).
//
// Example usage:
//
//   NonEmpty(String())
//
template <int&... ExplicitArgumentBarrier, typename Inner>
auto NonEmpty(Inner inner) {}

}  // namespace internal_no_adl

// Inject the names from internal_no_adl into fuzztest, without allowing for
// ADL. Note that an `inline` namespace would not have this effect (ie it would
// still allow ADL to trigger).
usingnamespaceinternal_no_adl;  // NOLINT

}  // namespace fuzztest

#endif  // FUZZTEST_FUZZTEST_DOMAIN_CORE_H_