Remove fuzztest support from OR-Tools (#4938)
* Remove fuzztest support from OR-Tools
This commit is contained in:
committed by
Corentin Le Molgat
parent
e09ed7a33a
commit
7345481dfe
@@ -435,3 +435,20 @@ cc_library(
|
||||
"@abseil-cpp//absl/time",
|
||||
],
|
||||
)
|
||||
|
||||
cc_test(
|
||||
name = "n_choose_k_test",
|
||||
srcs = ["n_choose_k_test.cc"],
|
||||
deps = [
|
||||
":n_choose_k",
|
||||
"//ortools/base:dump_vars",
|
||||
"//ortools/base:gmock_main",
|
||||
"//ortools/util:flat_matrix",
|
||||
"@abseil-cpp//absl/numeric:int128",
|
||||
"@abseil-cpp//absl/random",
|
||||
"@abseil-cpp//absl/random:distributions",
|
||||
"@abseil-cpp//absl/status",
|
||||
"@abseil-cpp//absl/status:statusor",
|
||||
"@google_benchmark//:benchmark",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -52,20 +52,6 @@ if(BUILD_TESTING)
|
||||
GTest::gmock
|
||||
)
|
||||
endforeach()
|
||||
if(USE_fuzztest)
|
||||
ortools_cxx_test(
|
||||
NAME
|
||||
algorithms_n_choose_k_test
|
||||
SOURCES
|
||||
"./n_choose_k_test.cc"
|
||||
LINK_LIBRARIES
|
||||
benchmark::benchmark
|
||||
fuzztest::fuzztest
|
||||
fuzztest::fuzztest_gtest_main
|
||||
GTest::gmock
|
||||
)
|
||||
endif()
|
||||
|
||||
# These tests are too long so we disable them.
|
||||
set_tests_properties(
|
||||
cxx_algorithms_radix_sort_test
|
||||
|
||||
@@ -16,26 +16,19 @@
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <random>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "absl/numeric/int128.h"
|
||||
#include "absl/random/distributions.h"
|
||||
#include "absl/random/random.h"
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "benchmark/benchmark.h"
|
||||
#include "gtest/gtest.h"
|
||||
#include "ortools/base/dump_vars.h"
|
||||
//#include "ortools/base/fuzztest.h"
|
||||
#include "ortools/base/gmock.h"
|
||||
#include "ortools/base/mathutil.h"
|
||||
#include "ortools/util/flat_matrix.h"
|
||||
|
||||
namespace operations_research {
|
||||
namespace {
|
||||
//using ::fuzztest::NonNegative;
|
||||
using ::testing::HasSubstr;
|
||||
using ::testing::status::IsOkAndHolds;
|
||||
using ::testing::status::StatusIs;
|
||||
@@ -248,74 +241,5 @@ TEST(NChooseKTest, ComparisonAgainstPascalTriangleForK5OrAbove) {
|
||||
}
|
||||
}
|
||||
|
||||
void MatchesLogCombinations(int n, int k) {
|
||||
if (n < k) {
|
||||
std::swap(k, n);
|
||||
}
|
||||
const auto exact = NChooseK(n, k);
|
||||
const double log_approx = MathUtil::LogCombinations(n, k);
|
||||
if (exact.ok()) {
|
||||
// We accepted to compute the exact value, make sure that it matches the
|
||||
// approximation.
|
||||
ASSERT_NEAR(log(exact.value()), log_approx, 0.0001);
|
||||
} else {
|
||||
// We declined to compute the exact value, make sure that we had a good
|
||||
// reason to, i.e. that the result did indeed overflow.
|
||||
ASSERT_THAT(exact, StatusIs(absl::StatusCode::kInvalidArgument,
|
||||
HasSubstr("overflows int64")));
|
||||
const double approx = exp(log_approx);
|
||||
ASSERT_GE(std::nextafter(approx, std::numeric_limits<double>::infinity()),
|
||||
std::numeric_limits<int64_t>::max())
|
||||
<< "we declined to compute the exact value of NChooseK(" << n << ", "
|
||||
<< k << "), but the log value is " << log_approx
|
||||
<< " (value: " << approx << "), which fits in int64_t";
|
||||
}
|
||||
}
|
||||
/*
|
||||
FUZZ_TEST(NChooseKTest, MatchesLogCombinations)
|
||||
// Ideally we'd test with `uint64_t`, but `LogCombinations` only accepts
|
||||
// `int`.
|
||||
.WithDomains(NonNegative<int>(), NonNegative<int>());
|
||||
*/
|
||||
template <int kMaxN, auto algo>
|
||||
void BM_NChooseK(benchmark::State& state) {
|
||||
static constexpr int kNumInputs = 1000;
|
||||
// Use deterministic random numbers to avoid noise.
|
||||
std::mt19937 gen(42);
|
||||
std::uniform_int_distribution<int64_t> random(0, kMaxN);
|
||||
std::vector<std::pair<int64_t, int64_t>> inputs;
|
||||
inputs.reserve(kNumInputs);
|
||||
for (int i = 0; i < kNumInputs; ++i) {
|
||||
int64_t n = random(gen);
|
||||
int64_t k = random(gen);
|
||||
if (n < k) {
|
||||
std::swap(n, k);
|
||||
}
|
||||
inputs.emplace_back(n, k);
|
||||
}
|
||||
// Force the one-time, costly static initializations of NChooseK() to happen
|
||||
// before the benchmark starts.
|
||||
auto result = NChooseK(62, 31);
|
||||
benchmark::DoNotOptimize(result);
|
||||
|
||||
// Start the benchmark.
|
||||
for (auto _ : state) {
|
||||
for (const auto [n, k] : inputs) {
|
||||
auto result = algo(n, k);
|
||||
benchmark::DoNotOptimize(result);
|
||||
}
|
||||
}
|
||||
state.SetItemsProcessed(state.iterations() * kNumInputs);
|
||||
}
|
||||
// int32_t domain.
|
||||
BENCHMARK(BM_NChooseK<30, operations_research::NChooseK>);
|
||||
|
||||
// int{32,64} domain.
|
||||
BENCHMARK(BM_NChooseK<60, operations_research::NChooseK>);
|
||||
|
||||
// int{32,64,128} domain.
|
||||
BENCHMARK(BM_NChooseK<100, operations_research::NChooseK>);
|
||||
BENCHMARK(BM_NChooseK<100, MathUtil::LogCombinations>);
|
||||
|
||||
} // namespace
|
||||
} // namespace operations_research
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
// Copyright 2010-2025 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 ORTOOLS_BASE_FUZZTEST_H_
|
||||
#define ORTOOLS_BASE_FUZZTEST_H_
|
||||
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
// #include "fuzztest/googletest_fixture_adapter.h"
|
||||
#include "fuzztest/domain.h"
|
||||
#include "fuzztest/fuzztest.h"
|
||||
#include "fuzztest/init_fuzztest.h"
|
||||
#include "google/protobuf/text_format.h"
|
||||
|
||||
namespace fuzztest {
|
||||
|
||||
// Reads protos from directory and returns a vector usable by the .WithSeeds()
|
||||
// function to aid in fuzz test migrations. `is_text_format` should be true iff
|
||||
// the protos are in text format.
|
||||
template <class ProtoType>
|
||||
std::vector<std::tuple<ProtoType>> ReadFilesFromDirectory(
|
||||
std::string_view dir) {
|
||||
std::vector<std::tuple<ProtoType>> corpus;
|
||||
|
||||
for (std::tuple<std::string>& proto_tuple : ReadFilesFromDirectory(dir)) {
|
||||
std::string text_proto = std::get<0>(proto_tuple);
|
||||
ProtoType proto;
|
||||
bool was_parsed =
|
||||
google::protobuf::TextFormat::ParseFromString(text_proto, &proto);
|
||||
if (was_parsed) {
|
||||
corpus.push_back(std::make_tuple(proto));
|
||||
}
|
||||
}
|
||||
return corpus;
|
||||
}
|
||||
|
||||
} // namespace fuzztest
|
||||
|
||||
#endif // ORTOOLS_BASE_FUZZTEST_H_
|
||||
@@ -50,8 +50,6 @@ if(BUILD_TESTING)
|
||||
file(GLOB _TEST_SRCS "*_test.cc")
|
||||
list(FILTER _TEST_SRCS
|
||||
EXCLUDE REGEX "elemental_export_model_update_test.cc$")
|
||||
list(FILTER _TEST_SRCS
|
||||
EXCLUDE REGEX "elemental_from_proto_fuzz_test.cc$") # need fuzztest
|
||||
foreach(_FULL_FILE_NAME IN LISTS _TEST_SRCS)
|
||||
get_filename_component(_NAME ${_FULL_FILE_NAME} NAME_WE)
|
||||
get_filename_component(_FILE_NAME ${_FULL_FILE_NAME} NAME)
|
||||
|
||||
@@ -1,81 +0,0 @@
|
||||
// Copyright 2010-2025 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.
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "absl/status/statusor.h"
|
||||
#include "ortools/base/fuzztest.h"
|
||||
#include "ortools/base/gmock.h"
|
||||
#include "ortools/math_opt/elemental/elemental.h"
|
||||
#include "ortools/math_opt/elemental/elemental_matcher.h"
|
||||
#include "ortools/math_opt/model_update.pb.h"
|
||||
|
||||
namespace operations_research::math_opt {
|
||||
namespace {
|
||||
|
||||
using ::testing::status::IsOkAndHolds;
|
||||
|
||||
void FromProtoNeverCrashes(const ModelProto& proto) {
|
||||
Elemental::FromModelProto(proto).IgnoreError();
|
||||
}
|
||||
|
||||
FUZZ_TEST(ElementalFromProtoNoCrashTest, FromProtoNeverCrashes);
|
||||
|
||||
void RoundTripsIfParses(const ModelProto& proto) {
|
||||
absl::StatusOr<Elemental> e1 = Elemental::FromModelProto(proto);
|
||||
if (!e1.ok()) {
|
||||
return;
|
||||
}
|
||||
ASSERT_OK_AND_ASSIGN(ModelProto p2, e1->ExportModel());
|
||||
EXPECT_THAT(Elemental::FromModelProto(p2),
|
||||
IsOkAndHolds(EquivToElemental(*e1)));
|
||||
}
|
||||
|
||||
FUZZ_TEST(ElementalRoundTripTest, RoundTripsIfParses);
|
||||
|
||||
void ApplyUpdateProtoNoCrash(const ModelProto& proto,
|
||||
const ModelUpdateProto& u1,
|
||||
const ModelUpdateProto& u2) {
|
||||
absl::StatusOr<Elemental> elemental = Elemental::FromModelProto(proto);
|
||||
if (!elemental.ok()) {
|
||||
return;
|
||||
}
|
||||
elemental->ApplyUpdateProto(u1).IgnoreError();
|
||||
elemental->ApplyUpdateProto(u2).IgnoreError();
|
||||
}
|
||||
|
||||
FUZZ_TEST(ElementalApplyUpdateProtoNoCrashTest, ApplyUpdateProtoNoCrash);
|
||||
|
||||
void UpdateRoundTripsIfParses(const ModelProto& proto,
|
||||
const ModelUpdateProto& update) {
|
||||
absl::StatusOr<Elemental> model = Elemental::FromModelProto(proto);
|
||||
if (!model.ok()) {
|
||||
return;
|
||||
}
|
||||
const Elemental::DiffHandle diff = model->AddDiff();
|
||||
if (!model->ApplyUpdateProto(update).ok()) {
|
||||
return;
|
||||
}
|
||||
ASSERT_OK_AND_ASSIGN(const std::optional<ModelUpdateProto> canonical_update,
|
||||
model->ExportModelUpdate(diff));
|
||||
if (canonical_update.has_value()) {
|
||||
ASSERT_OK_AND_ASSIGN(Elemental model2, Elemental::FromModelProto(proto));
|
||||
ASSERT_OK(model2.ApplyUpdateProto(*canonical_update));
|
||||
EXPECT_THAT(*model, EquivToElemental(model2));
|
||||
}
|
||||
}
|
||||
|
||||
FUZZ_TEST(ElementalUpdateRoundTripTest, UpdateRoundTripsIfParses);
|
||||
|
||||
} // namespace
|
||||
} // namespace operations_research::math_opt
|
||||
@@ -3843,6 +3843,7 @@ cc_test(
|
||||
":integer_base",
|
||||
":util",
|
||||
"//ortools/base:gmock",
|
||||
"//ortools/base:gmock_main",
|
||||
"//ortools/base:logging",
|
||||
"//ortools/graph:connected_components",
|
||||
"//ortools/graph:strongly_connected_components",
|
||||
@@ -3856,7 +3857,6 @@ cc_test(
|
||||
"@abseil-cpp//absl/random:distributions",
|
||||
"@abseil-cpp//absl/strings",
|
||||
"@abseil-cpp//absl/types:span",
|
||||
"@fuzztest//fuzztest:fuzztest_gtest_main",
|
||||
"@google_benchmark//:benchmark",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -1105,27 +1105,6 @@ TEST(FindPartialIntersections, Random) {
|
||||
}
|
||||
}
|
||||
|
||||
void CheckFuzzedRectangles(
|
||||
absl::Span<const std::tuple<int64_t, int64_t, int64_t, int64_t>> tuples) {
|
||||
std::vector<Rectangle> rectangles;
|
||||
rectangles.reserve(tuples.size());
|
||||
for (const auto& [x_min, x_size, y_min, y_size] : tuples) {
|
||||
rectangles.push_back({.x_min = x_min,
|
||||
.x_max = CapAdd(x_min, x_size),
|
||||
.y_min = y_min,
|
||||
.y_max = CapAdd(y_min, y_size)});
|
||||
}
|
||||
const std::vector<std::pair<int, int>> result =
|
||||
FindPartialRectangleIntersections(rectangles);
|
||||
for (const auto& [i, j] : result) {
|
||||
CHECK(!rectangles[i].IsDisjoint(rectangles[j])) << i << " " << j;
|
||||
}
|
||||
const std::vector<std::pair<int, int>> naive_result =
|
||||
GetAllIntersections(rectangles);
|
||||
CHECK(GraphsDefineSameConnectedComponents(naive_result, result))
|
||||
<< RenderRectGraph(std::nullopt, rectangles, result);
|
||||
}
|
||||
|
||||
void BM_FindRectangles(benchmark::State& state) {
|
||||
absl::BitGen random;
|
||||
std::vector<std::vector<RectangleInRange>> problems;
|
||||
|
||||
Reference in New Issue
Block a user