blob: 122f036dbef92a61bdc85ea8678d131962b67d0f [file] [log] [blame]
// 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.
// Tests of StructOf, ConstructorOf, VariantOf and OptionalOf.
#include <bitset>
#include <cctype>
#include <deque>
#include <iterator>
#include <list>
#include <optional>
#include <set>
#include <string>
#include <unordered_set>
#include <utility>
#include <variant>
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/random/random.h"
#include "./fuzztest/domain.h"
#include "./domain_tests/domain_testing.h"
namespace fuzztest {
namespace {
using ::testing::_;
using ::testing::AnyOf;
using ::testing::Eq;
using ::testing::Optional;
using ::testing::UnorderedElementsAre;
using ::testing::VariantWith;
struct MyStruct {
int a;
std::string s;
};
TEST(StructOf, InitGeneratesValidValues) {
auto domain =
StructOf<MyStruct>(ElementOf({5, 10}), Arbitrary<std::string>());
absl::BitGen bitgen;
Set<int> field_a;
Set<std::string> field_s;
while (field_a.size() < 2 && field_s.size() < 10) {
auto agg = Value(domain, bitgen).user_value;
EXPECT_THAT(agg.a, AnyOf(5, 10));
field_a.insert(agg.a);
field_s.insert(agg.s);
}
}
TEST(StructOf, MutateGeneratesValidValues) {
auto domain =
StructOf<MyStruct>(ElementOf({5, 10}), Arbitrary<std::string>());
absl::BitGen bitgen;
Set<int> field_a;
Set<std::string> field_s;
Value agg(domain, bitgen);
while (field_a.size() < 2 && field_s.size() < 10) {
agg.Mutate(domain, bitgen, false);
EXPECT_THAT(agg.user_value.a, AnyOf(5, 10));
field_a.insert(agg.user_value.a);
field_s.insert(agg.user_value.s);
}
}
TEST(StructOf, WorksWithStructWithUpTo16Fields) {
struct Agg16 {
uint32_t a, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p;
uint32_t sum() {
return a + b + c + d + e + f + g + h + i + j + k + l + m + n + o + p;
}
};
auto a = Arbitrary<uint32_t>();
absl::BitGen bitgen;
// Just check that we can create and mutate the value.
auto domain = StructOf<Agg16>(a, a, a, a, a, a, a, a, a, a, a, a, a, a, a, a);
Value value(domain, bitgen);
const uint32_t initial_sum = value.user_value.sum();
while (value.user_value.sum() == initial_sum) {
value.Mutate(domain, bitgen, false);
}
// Check that shrinking works too.
while (value.user_value.sum() != 0) {
value.Mutate(domain, bitgen, true);
}
}
class MyClass {
public:
MyClass(int a, double d, std::string s) : a_(a), d_(d), s_(std::move(s)) {}
int a() const { return a_; }
double d() const { return d_; }
std::string s() const { return s_; }
private:
int a_;
double d_;
std::string s_;
};
TEST(ConstructorOf, InitGeneratesValidValues) {
auto domain = ConstructorOf<MyClass>(ElementOf({5, 10}), Arbitrary<double>(),
Arbitrary<std::string>());
absl::BitGen bitgen;
Set<int> field_a;
Set<double> field_d;
Set<std::string> field_s;
while (field_a.size() < 2 && field_d.size() < 10 && field_s.size() < 10) {
auto agg = Value(domain, bitgen).user_value;
EXPECT_THAT(agg.a(), AnyOf(5, 10));
field_a.insert(agg.a());
field_d.insert(agg.d());
field_s.insert(agg.s());
}
}
TEST(ConstructorOf, MutateGeneratesValidValues) {
auto domain = ConstructorOf<MyClass>(ElementOf({5, 10}), Arbitrary<double>(),
Arbitrary<std::string>());
absl::BitGen bitgen;
Set<int> field_a;
Set<double> field_d;
Set<std::string> field_s;
Value agg(domain, bitgen);
while (field_a.size() < 2 && field_d.size() < 10 && field_s.size() < 10) {
agg.Mutate(domain, bitgen, false);
EXPECT_THAT(agg.user_value.a(), AnyOf(5, 10));
field_a.insert(agg.user_value.a());
field_d.insert(agg.user_value.d());
field_s.insert(agg.user_value.s());
}
}
class HasTemplatedConstructor {
public:
template <typename... Args>
HasTemplatedConstructor(Args... args) {
sum_ = (args + ...);
}
int sum() const { return sum_; }
private:
int sum_;
};
TEST(ConstructorOf, WorksWithTemplatedConstructors) {
auto a = Arbitrary<uint32_t>();
absl::BitGen bitgen;
// Just check that we can create and mutate the value.
auto domain = ConstructorOf<HasTemplatedConstructor>(a, a, a, a, a, a, a, a,
a, a, a, a, a, a, a, a);
Value value(domain, bitgen);
const uint32_t initial_sum = value.user_value.sum();
while (value.user_value.sum() == initial_sum) {
value.Mutate(domain, bitgen, false);
}
// Check that shrinking works too.
while (value.user_value.sum() != 0) {
value.Mutate(domain, bitgen, true);
}
}
TEST(VariantOf, InitGenerateValidValues) {
using X = std::variant<int, int, std::string>;
Domain<X> domain =
VariantOf(ElementOf({5, 10}), InRange(50, 500), PrintableAsciiString());
absl::BitGen bitgen;
std::vector<absl::flat_hash_set<int>> int_unique_value_arr(2);
absl::flat_hash_set<std::string> string_unique_values;
constexpr int n = 20;
while (int_unique_value_arr[0].size() < 2 ||
int_unique_value_arr[1].size() < n ||
string_unique_values.size() < n) {
X value = Value(domain, bitgen).user_value;
if (value.index() == 0) {
int val = std::get<0>(value);
EXPECT_THAT(val, AnyOf(5, 10));
int_unique_value_arr[0].insert(val);
} else if (value.index() == 1) {
int val = std::get<1>(value);
EXPECT_LE(val, 500);
EXPECT_GE(val, 50);
int_unique_value_arr[1].insert(val);
} else {
string_unique_values.insert(std::get<2>(value));
}
}
}
TEST(VariantOf, MutateGenerateValidValues) {
using X = std::variant<int, int, std::string, std::vector<int>>;
Domain<X> domain =
VariantOf(ElementOf({5, 10}), InRange(200, 500), PrintableAsciiString(),
ContainerOf<std::vector<int>>(InRange(1, 7)));
absl::BitGen bitgen;
std::vector<int> counter(4, 0);
absl::flat_hash_set<int> unique_values[2];
constexpr int n = 20;
Value value(domain, bitgen);
while (unique_values[0].size() < 2 || unique_values[1].size() < n ||
counter[2] < n || counter[3] < n) {
value.Mutate(domain, bitgen, false);
if (value.user_value.index() == 0) {
int val = std::get<0>(value.user_value);
EXPECT_THAT(val, AnyOf(5, 10));
unique_values[0].insert(val);
} else if (value.user_value.index() == 1) {
int val = std::get<1>(value.user_value);
EXPECT_LE(val, 500);
EXPECT_GE(val, 200);
unique_values[1].insert(val);
}
++counter[value.user_value.index()];
}
}
TEST(VariantOf, WorksWithACustomVariantType) {
auto domain = VariantOf<absl::variant<int, double>>(Arbitrary<int>(),
Arbitrary<double>());
absl::BitGen bitgen;
absl::variant<int, double> v = Value(domain, bitgen).user_value;
EXPECT_THAT(v, AnyOf(VariantWith<int>(_), VariantWith<double>(_)));
}
TEST(OptionalOf, InitCanMakeValuesOrNull) {
auto domain = OptionalOf(InRange(1, 3));
Set<std::optional<int>> values;
absl::BitGen bitgen;
while (values.size() < 4) {
values.insert(Value(domain, bitgen).user_value);
}
EXPECT_THAT(values, UnorderedElementsAre(std::nullopt, Optional(1),
Optional(2), Optional(3)));
}
TEST(OptionalOf, MutateCanMakeValuesOrNull) {
auto domain = OptionalOf(InRange(1, 3));
Set<std::optional<int>> values;
absl::BitGen bitgen;
Value value(domain, bitgen);
while (values.size() < 4) {
value.Mutate(domain, bitgen, false);
values.insert(value.user_value);
}
EXPECT_THAT(values, UnorderedElementsAre(std::nullopt, Optional(1),
Optional(2), Optional(3)));
}
TEST(OptionalOf, WorksWithACustomOptionalType) {
auto domain = OptionalOf<absl::optional<int>>(InRange(1, 3));
absl::BitGen bitgen;
absl::optional<int> v = Value(domain, bitgen).user_value;
EXPECT_THAT(v, AnyOf(absl::nullopt, Optional(_)));
}
TEST(OptionalOf, AlwaysGenerateNulloptWhenPolicySet) {
auto domain = NullOpt<int>();
absl::BitGen bitgen;
Value value(domain, bitgen);
for (int i = 0; i < 10000; ++i) {
EXPECT_TRUE(value == std::nullopt) << "Didn't expect non-null value!";
value.Mutate(domain, bitgen, false);
}
}
TEST(OptionalOf, DoesntGenerateNulloptWhenPolicySet) {
auto domain = NonNull(OptionalOf(Arbitrary<int>()));
absl::BitGen bitgen;
Value value(domain, bitgen);
for (int i = 0; i < 10000; ++i) {
EXPECT_TRUE(value != std::nullopt) << "Didn't expect null value!";
value.Mutate(domain, bitgen, false);
}
}
TEST(OptionalOfDeathTest, FromValueOnNulloptDiesWhenPolicySetToAlwaysSet) {
auto domain = NonNull(OptionalOf(Arbitrary<int>()));
EXPECT_DEATH(domain.FromValue(std::nullopt), "cannot be null");
}
} // namespace
} // namespace fuzztest