blob: ca272dd0e3290459fa1c8b5a580ea6de22d72db4 [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 ElementOf and Just, which are domains that yield values from an
// explicitly specified set of values.
#include <vector>
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "absl/container/flat_hash_set.h"
#include "absl/random/random.h"
#include "absl/types/span.h"
#include "./fuzztest/domain.h"
#include "./domain_tests/domain_testing.h"
namespace fuzztest {
namespace {
using ::testing::Contains;
using ::testing::Ge;
using ::testing::SizeIs;
using ::testing::UnorderedElementsAreArray;
TEST(ElementOfTest, TwoOptions) {
absl::BitGen bitgen;
Domain<int> domain = ElementOf({0, 1});
absl::flat_hash_set<Value<Domain<int>>> found;
for (int i = 0; i < 20; ++i) {
found.insert(Value(domain, bitgen));
}
ASSERT_THAT(found, SizeIs(2));
for (const auto& v : found) {
auto copy = v;
copy.Mutate(domain, bitgen, false);
EXPECT_NE(v, copy);
}
}
TEST(ElementOfTest, InitGeneratesSeeds) {
Domain<int> domain = ElementOf({0, 1}).WithSeeds(std::vector{0});
EXPECT_THAT(GenerateInitialValues(domain, 1000),
Contains(Value(domain, 0))
// Since there are only two possible values, the seed will
// surely appear at least once. To make the test meaningful,
// we expect to see it much more often than the other value.
.Times(Ge(650)));
}
TEST(ElementOfTest, InvalidInputReportsErrors) {
EXPECT_DEATH_IF_SUPPORTED(ElementOf<int>({}),
"ElementOf requires a non empty list.");
}
enum class Color : int { Red, Green, Blue, Yellow };
TEST(ElementOfTest, Colors) {
absl::BitGen bitgen;
std::vector<Color> all_colors{Color::Red, Color::Green, Color::Blue,
Color::Yellow};
auto domain = ElementOf(all_colors);
absl::flat_hash_set<Color> found;
while (found.size() < all_colors.size()) {
found.insert(Value(domain, bitgen).user_value);
}
ASSERT_THAT(found, UnorderedElementsAreArray(all_colors));
found.clear();
Value c(domain, bitgen);
while (found.size() < all_colors.size()) {
c.Mutate(domain, bitgen, false);
found.insert(c.user_value);
VerifyRoundTripThroughConversion(c, domain);
}
ASSERT_THAT(found, UnorderedElementsAreArray(all_colors));
c = Value(domain, bitgen);
while (c.user_value != Color::Red) {
auto prev = c.user_value;
c.Mutate(domain, bitgen, true);
ASSERT_LE(c.user_value, prev);
}
ASSERT_THAT(found, UnorderedElementsAreArray(all_colors));
}
TEST(ElementOfTest, ValidationRejectsInvalidValue) {
auto domain_a = ElementOf({'a', 'b'});
auto domain_b = ElementOf({'a', 'b', 'c'});
auto corpus_value_a = domain_a.FromValue('a');
auto corpus_value_b = domain_b.FromValue('c');
ASSERT_TRUE(domain_a.ValidateCorpusValue(*corpus_value_a));
ASSERT_TRUE(domain_b.ValidateCorpusValue(*corpus_value_b));
EXPECT_FALSE(domain_a.ValidateCorpusValue(*corpus_value_b));
}
TEST(Just, Basic) {
absl::BitGen bitgen;
auto domain = Just(3);
for (int i = 0; i < 10; ++i) {
Value v(domain, bitgen);
EXPECT_EQ(v.user_value, 3);
}
int n = 3;
for (int i = 0; i < 10; ++i) {
Value v(domain, bitgen);
v.Mutate(domain, bitgen, false);
VerifyRoundTripThroughConversion(v, domain);
EXPECT_EQ(n, 3);
}
}
} // namespace
} // namespace fuzztest