chromium/third_party/fuzztest/src/fuzztest/internal/fixture_driver.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.

#ifndef FUZZTEST_FUZZTEST_INTERNAL_FIXTURE_DRIVER_H_
#define FUZZTEST_FUZZTEST_INTERNAL_FIXTURE_DRIVER_H_

#include <functional>
#include <iostream>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>

#include "absl/status/status.h"
#include "absl/strings/str_format.h"
#include "absl/types/span.h"
#include "./fuzztest/internal/any.h"
#include "./fuzztest/internal/domains/domain.h"
#include "./fuzztest/internal/logging.h"
#include "./fuzztest/internal/meta.h"
#include "./fuzztest/internal/printer.h"
#include "./fuzztest/internal/registration.h"
#include "./fuzztest/internal/type_support.h"

namespace fuzztest::internal {

// The interface for test fixtures with setup and teardown methods that need to
// be explicitly called by the testing framework.
class FixtureWithExplicitSetUp {};

// Marker interfaces for specifying the fixture's instantiation semantics:
//
// -  Per-iteration semantics: The fixture object is instantiated and discarded
//    once per fuzz test iteration.
//
// -  Per-fuzz-test semantics: The fixture object is instantiated and discarded
//    once per fuzz test. The same  object is reused in all fuzz test
//    iterations.
class PerIterationFixture : public FixtureWithExplicitSetUp {};
class PerFuzzTestFixture : public FixtureWithExplicitSetUp {};

class UntypedFixtureDriver {};

// Typed subinterface with functionality that depends on knowing `ValueType`.
// `SeedProvider` is the type of the function returning dynamically initialized
// seeds.
template <typename ValueType, typename SeedProvider>
class TypedFixtureDriver : public UntypedFixtureDriver {};

// ForceVectorForStringView is a temporary hack for reliably
// finding buffer overflows. ASAN cannot detect small overflows in
// std::string-s. See related bug at
// https://bugs.llvm.org/show_bug.cgi?id=26380. As a temporary
// workaround, we enable finding overflows by copying the contents
// of the original string into a separate temporary heap buffer.
// TODO(b/194687521): Remove this when we (or ASAN) detect overflows
// in strings.
struct ForceVector {};

template <typename Dest, typename Src>
decltype(auto) ForceVectorForStringView(Src&& src) {}

// The base class for fixture drivers.
//
// A fixture driver is used for maintaining a fixture -- constructing it,
// setting it up, tearing it down, and destructing it -- during a fuzz test. It
// also acts as a proxy to the fixture's target function.
//
// The type parameters are:
//   - `DomainT`        -- the type of the domain. Eg `Domain<std::tuple<int>>`.
//   - `Fixture`        -- the type of the test fixture.
//   - `TargetFunction` -- the type of the fixture's target function.
//   - `SeedProvider`   -- the type of the function returning dynamically
//                         initialized seeds.
template <typename DomainT, typename Fixture, typename TargetFunction,
          typename SeedProvider>
class FixtureDriver;

// Specialization for `TargetFunction = void(BaseFixture::*)(Args...)`
//
// The new type parameters are:
//   - `BaseFixture` -- the class from which `Fixture` is derived and which has
//                      the target function.
//   - `Args...` -- the types of the target function's parameters.
FixtureDriver<DomainT, Fixture, void (BaseFixture::*)(Args...), SeedProvider>;

// Specialization for `Fixture = NoFixture`.
// This is used for FUZZ_TEST invocations that do not require a fixture.
// TargetFunction must be `void(*)(Args...)`
//
// The new type parameters are:
//   - `Args...` -- the types of the target function's parameters.
FixtureDriver<DomainT, NoFixture, void (*)(Args...), SeedProvider>;

template <typename DomainT, typename Fixture, typename TargetFunction,
          typename SeedProvider, typename = void>
class FixtureDriverImpl;

// The fixture driver for "NoFixture", which is the tag used for the FUZZ_TEST
// macro that uses no fixtures. No fixture is created.
FixtureDriverImpl<DomainT, NoFixture, TargetFunction, SeedProvider>;

// The fixture driver for default-constructible classes that act like fixtures:
// their setup is in the constructor, teardown is in the destructor, and they
// have a target function. Such fixtures are instantiated and destructed once
// per fuzz test.
FixtureDriverImpl<DomainT, Fixture, TargetFunction, SeedProvider, std::enable_if_t<std::conjunction_v<std::is_default_constructible<Fixture>, std::negation<std::is_base_of<FixtureWithExplicitSetUp, Fixture>>>>>;

// The fixture driver for test fixtures with explicit setup that assume the
// "per-iteration" semantics.
FixtureDriverImpl<DomainT, Fixture, void (BaseFixture::*)(Args...), SeedProvider, std::enable_if_t<std::conjunction_v<std::is_default_constructible<Fixture>, std::is_base_of<BaseFixture, Fixture>, std::is_base_of<PerIterationFixture, Fixture>>>>;

// The fixture driver for test fixtures with explicit setup that assume the
// "per-fuzz-test" semantics.
FixtureDriverImpl<DomainT, Fixture, void (BaseFixture::*)(Args...), SeedProvider, std::enable_if_t<std::conjunction_v<std::is_default_constructible<Fixture>, std::is_base_of<BaseFixture, Fixture>, std::is_base_of<PerFuzzTestFixture, Fixture>>>>;

}  // namespace fuzztest::internal

#endif  // FUZZTEST_FUZZTEST_INTERNAL_FIXTURE_DRIVER_H_