blob: 486c38df633cdaa493c2c44f096b4783dd84dfae [file] [log] [blame]
// Copyright 2023 The Pigweed Authors
//
// 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
//
// https://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.
#pragma once
#include <cstddef>
#include "pw_allocator/test_harness.h"
#include "pw_fuzzer/fuzztest.h"
namespace pw::allocator::test {
/// Returns a FuzzTest domain for producing arbitrary allocator requests.
///
/// This method integrates with FuzzTest to use code coverage to produce guided
/// mutations.
///
/// See https://github.com/google/fuzztest/blob/main/doc/domains-reference.md
///
/// @param max_size Size of the largest allocation that can be requested.
fuzzer::Domain<AllocatorRequest> ArbitraryAllocatorRequest(size_t max_size);
/// Returns a FuzzTest domain for producing sequences of arbitrary allocator
/// requests.
///
/// This method can be used to drive an `AllocatorTestHarness` as part of a
/// fuzz test.
///
/// See https://github.com/google/fuzztest/blob/main/doc/domains-reference.md
///
/// @param max_size Size of the largest allocation that can be requested.
template <size_t kMaxRequests, size_t kMaxSize>
auto ArbitraryAllocatorRequests() {
return fuzzer::VectorOf<kMaxRequests>(ArbitraryAllocatorRequest(kMaxSize));
}
/// Builds an AllocatorRequest from an index and values.
///
/// Unfortunately, the reproducer emitted by FuzzTest for vectors of
/// AllocatorRequests cannot simply be copied and pasted. To create a
/// reproducer, create a `pw::Vector` of the appropriate size, and populate it
/// using this method with the correct index.
///
/// For example, consider the following sample output:
/// @code
/// The test fails with input:
/// argument 0: {(index=0, value={0, 1}), (index=0, value={1209, 8}),
/// (index=2, value={9223372036854775807, 2048})}
///
/// =================================================================
/// === Reproducer test
///
/// TEST(MyAllocatorFuzzTest, NeverCrashesU16Regression) {
/// NeverCrashes(
/// {{0, 1}, {1209, 8}, {9223372036854775807, 2048},
/// );
/// }
/// @endcode
///
/// A valid reproducer might be:
/// @code{.cpp}
/// TEST(MyAllocatorFuzzTest, NeverCrashesU16Regression) {
/// Vector<test::AllocatorRequest, 3> input({
/// test::MakeAllocatorRequest<0>(0u, 1u),
/// test::MakeAllocatorRequest<0>(1209u, 8u),
/// test::MakeAllocatorRequest<2>(9223372036854775807u, 2048u),
/// });
/// NeverCrashes(input);
// }
/// @endcode
template <size_t kIndex, typename... Args>
AllocatorRequest MakeAllocatorRequest(Args... args) {
if constexpr (kIndex == 0) {
return AllocationRequest{static_cast<size_t>(args)...};
}
if constexpr (kIndex == 1) {
return DeallocationRequest{static_cast<size_t>(args)...};
}
if constexpr (kIndex == 2) {
return ReallocationRequest{static_cast<size_t>(args)...};
}
return AllocatorRequest();
}
} // namespace pw::allocator::test