// Copyright (c) 2019 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 #include "source/fuzz/equivalence_relation.h" #include "gmock/gmock.h" #include "gtest/gtest.h" namespace spvtools { namespace fuzz { namespace { struct UInt32Equals { bool operator()(const uint32_t* first, const uint32_t* second) const { return *first == *second; } }; struct UInt32Hash { size_t operator()(const uint32_t* element) const { return static_cast(*element); } }; std::vector ToUIntVector( const std::vector& pointers) { std::vector result; for (auto pointer : pointers) { result.push_back(*pointer); } return result; } TEST(EquivalenceRelationTest, BasicTest) { EquivalenceRelation relation; ASSERT_TRUE(relation.GetAllKnownValues().empty()); for (uint32_t element = 0; element < 100; element++) { relation.Register(element); } for (uint32_t element = 2; element < 80; element += 2) { relation.MakeEquivalent(0, element); relation.MakeEquivalent(element - 1, element + 1); } for (uint32_t element = 82; element < 100; element += 2) { relation.MakeEquivalent(80, element); relation.MakeEquivalent(element - 1, element + 1); } relation.MakeEquivalent(78, 80); std::vector class1; for (uint32_t element = 0; element < 98; element += 2) { ASSERT_TRUE(relation.IsEquivalent(0, element)); ASSERT_TRUE(relation.IsEquivalent(element, element + 2)); class1.push_back(element); } class1.push_back(98); ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(0)), testing::WhenSorted(class1)); ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(4)), testing::WhenSorted(class1)); ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(40)), testing::WhenSorted(class1)); std::vector class2; for (uint32_t element = 1; element < 79; element += 2) { ASSERT_TRUE(relation.IsEquivalent(1, element)); ASSERT_TRUE(relation.IsEquivalent(element, element + 2)); class2.push_back(element); } class2.push_back(79); ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(1)), testing::WhenSorted(class2)); ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(11)), testing::WhenSorted(class2)); ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(31)), testing::WhenSorted(class2)); std::vector class3; for (uint32_t element = 81; element < 99; element += 2) { ASSERT_TRUE(relation.IsEquivalent(81, element)); ASSERT_TRUE(relation.IsEquivalent(element, element + 2)); class3.push_back(element); } class3.push_back(99); ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(81)), testing::WhenSorted(class3)); ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(91)), testing::WhenSorted(class3)); ASSERT_THAT(ToUIntVector(relation.GetEquivalenceClass(99)), testing::WhenSorted(class3)); bool first = true; std::vector previous_class; for (auto representative : relation.GetEquivalenceClassRepresentatives()) { std::vector current_class = relation.GetEquivalenceClass(*representative); ASSERT_TRUE(std::find(current_class.begin(), current_class.end(), representative) != current_class.end()); if (!first) { ASSERT_TRUE(std::find(previous_class.begin(), previous_class.end(), representative) == previous_class.end()); } previous_class = current_class; first = false; } } TEST(EquivalenceRelationTest, DeterministicEquivalenceClassOrder) { EquivalenceRelation relation1; EquivalenceRelation relation2; for (uint32_t i = 0; i < 1000; ++i) { relation1.Register(i); relation2.Register(i); } for (uint32_t i = 0; i < 1000; ++i) { if (i >= 10) { relation1.MakeEquivalent(i, i - 10); relation2.MakeEquivalent(i, i - 10); } } // We constructed the equivalence relations in the same way, so we would like // them to have identical representatives, and identically-ordered equivalence // classes per representative. ASSERT_THAT(ToUIntVector(relation1.GetEquivalenceClassRepresentatives()), ToUIntVector(relation2.GetEquivalenceClassRepresentatives())); for (auto representative : relation1.GetEquivalenceClassRepresentatives()) { ASSERT_THAT(ToUIntVector(relation1.GetEquivalenceClass(*representative)), ToUIntVector(relation2.GetEquivalenceClass(*representative))); } } } // namespace } // namespace fuzz } // namespace spvtools