mirror of
https://github.com/revng/revng
synced 2026-06-21 14:07:57 +00:00
337 lines
9.1 KiB
C++
337 lines
9.1 KiB
C++
/// \file KeyedObjectsContainers.cpp
|
|
/// Tests for MutableSet and SortedVector.
|
|
|
|
//
|
|
// This file is distributed under the MIT License. See LICENSE.md for details.
|
|
//
|
|
|
|
#define BOOST_TEST_MODULE KeyedObjectsContainers
|
|
bool init_unit_test();
|
|
#include "boost/test/unit_test.hpp"
|
|
|
|
#include "revng/ADT/MutableSet.h"
|
|
#include "revng/ADT/SortedVector.h"
|
|
#include "revng/ADT/TrackingContainer.h"
|
|
#include "revng/Support/Assert.h"
|
|
|
|
#include "TestKeyedObject.h"
|
|
|
|
template<typename T>
|
|
static void assertInsert(T &Set, uint64_t Key, uint64_t Value) {
|
|
auto &&[It, Success] = Set.insert({ Key, Value });
|
|
revng_check(It->key() == Key and It->value() == Value);
|
|
revng_check(Success);
|
|
}
|
|
|
|
template<typename T>
|
|
void testSet() {
|
|
T Set;
|
|
revng_check(Set.empty());
|
|
|
|
// Test copy/move constructor/assign
|
|
{
|
|
T Original;
|
|
T Copy(Original);
|
|
Copy = Original;
|
|
Copy = std::move(Original);
|
|
|
|
T Moved(std::move(Copy));
|
|
}
|
|
|
|
// Test insertion
|
|
assertInsert(Set, 0x2000, 0xDEAD);
|
|
assertInsert(Set, 0x1000, 0xDEADDEAD);
|
|
assertInsert(Set, 0x3000, 0xDEADDEADDEAD);
|
|
|
|
revng_check(not Set.empty());
|
|
revng_check(Set.size() == 3);
|
|
|
|
using IterationResultType = std::vector<std::pair<uint64_t, uint64_t>>;
|
|
IterationResultType ExpectedResult{ { 0x1000, 0xDEADDEAD },
|
|
{ 0x2000, 0xDEAD },
|
|
{ 0x3000, 0xDEADDEADDEAD } };
|
|
|
|
// Test forward iteration
|
|
{
|
|
IterationResultType IterationResult;
|
|
for (const Element &SE : Set)
|
|
IterationResult.emplace_back(SE.key(), SE.value());
|
|
|
|
revng_check(IterationResult == ExpectedResult);
|
|
}
|
|
|
|
// Test backward iteration
|
|
{
|
|
IterationResultType IterationResult;
|
|
for (const Element &SE : llvm::make_range(Set.rbegin(), Set.rend()))
|
|
IterationResult.emplace_back(SE.key(), SE.value());
|
|
std::reverse(ExpectedResult.begin(), ExpectedResult.end());
|
|
revng_check(IterationResult == ExpectedResult);
|
|
std::reverse(ExpectedResult.begin(), ExpectedResult.end());
|
|
}
|
|
|
|
// Test erase
|
|
{
|
|
revng_check(!Set.contains(0x1500));
|
|
|
|
auto &&[It, Success] = Set.insert({ 0x1500, 0xEEEE });
|
|
revng_check(Success);
|
|
auto Next = Set.erase(It);
|
|
revng_check(Next == Set.find(0x2000));
|
|
|
|
revng_check(!Set.contains(0x1500));
|
|
|
|
IterationResultType IterationResult;
|
|
for (const Element &SE : Set)
|
|
IterationResult.emplace_back(SE.key(), SE.value());
|
|
revng_check(IterationResult == ExpectedResult);
|
|
}
|
|
|
|
// Test find
|
|
{
|
|
auto It = Set.find(0x1000);
|
|
revng_check(It != Set.end());
|
|
revng_check(It->key() == 0x1000);
|
|
revng_check(It->value() == 0xDEADDEAD);
|
|
}
|
|
|
|
// insert vs insert_or_assign
|
|
{
|
|
auto &&[It, Success] = Set.insert({ 0x1000, 0x5555 });
|
|
revng_check(Set.find(0x1000) == It);
|
|
revng_check(not Success);
|
|
revng_check(Set[0x1000].value() == 0xDEADDEAD);
|
|
}
|
|
|
|
{
|
|
auto &&[It, Success] = Set.insert_or_assign({ 0x1000, 0x6666 });
|
|
revng_check(not Success);
|
|
revng_check(Set[0x1000].value() == 0x6666);
|
|
Set.insert_or_assign({ 0x1000, 0xDEADDEAD });
|
|
}
|
|
|
|
// Test operator[] on existing element
|
|
revng_check(Set[0x1000].key() == 0x1000);
|
|
revng_check(Set[0x1000].value() == 0xDEADDEAD);
|
|
|
|
// Test operator[] on new element
|
|
revng_check(Set[0x2500].key() == 0x2500);
|
|
revng_check(Set.size() == 4);
|
|
revng_check(Set.contains(0x2500));
|
|
revng_check(Set[0x2500].value() == 0);
|
|
|
|
// Test elements are mutable
|
|
Set[0x2500].setValue(0x90);
|
|
revng_check(Set[0x2500].value() == 0x90);
|
|
|
|
// Test batch_insert
|
|
{
|
|
auto Inserter = Set.batch_insert();
|
|
Inserter.insert({ 0x1100, 0x2222 });
|
|
Inserter.insert({ 0x900, 0x1111 });
|
|
}
|
|
revng_check(Set[0x1000].value() == 0xDEADDEAD);
|
|
revng_check(Set[0x900].value() == 0x1111);
|
|
|
|
// Test batch_insert_or_assign
|
|
{
|
|
auto Inserter = Set.batch_insert_or_assign();
|
|
Inserter.insert_or_assign({ 0x1000, 0x2222 });
|
|
Inserter.insert_or_assign({ 0x900, 0x3333 });
|
|
}
|
|
revng_check(Set[0x1000].value() == 0x2222);
|
|
revng_check(Set[0x1100].value() == 0x2222);
|
|
revng_check(Set[0x900].value() == 0x3333);
|
|
|
|
// Test clear
|
|
Set.clear();
|
|
|
|
revng_check(Set.empty());
|
|
revng_check(Set.size() == 0);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(TestMutableSet) {
|
|
testSet<MutableSet<Element>>();
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(TestSortedVector) {
|
|
testSet<SortedVector<Element>>();
|
|
}
|
|
|
|
template<typename T>
|
|
bool isSerializationStable(T &&Original) {
|
|
std::string Buffer;
|
|
|
|
{
|
|
llvm::raw_string_ostream Stream(Buffer);
|
|
llvm::yaml::Output YAMLOutput(Stream);
|
|
YAMLOutput << Original;
|
|
}
|
|
|
|
T Deserialized;
|
|
llvm::yaml::Input YAMLInput(Buffer);
|
|
YAMLInput >> Deserialized;
|
|
|
|
return Original == Deserialized;
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(TestYAMLSerializationStability) {
|
|
revng_check(isSerializationStable(SortedVector<int>{ 4, 19, 7 }));
|
|
revng_check(isSerializationStable(MutableSet<int>{ 4, 19, 7 }));
|
|
|
|
SortedVector<Element> TestSV{ { 1, 2 }, { 2, 3 } };
|
|
revng_check(isSerializationStable(std::move(TestSV)));
|
|
|
|
MutableSet<Element> TestMS{ { 1, 2 }, { 2, 3 } };
|
|
revng_check(isSerializationStable(std::move(TestMS)));
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(TestUniqueLast) {
|
|
using IntPair = std::pair<int, int>;
|
|
using Vector = std::vector<IntPair>;
|
|
Vector TheVector = {
|
|
{ 1, 1 }, { 1, 2 }, { 1, 3 }, { 2, 1 }, { 2, 2 }, { 2, 3 },
|
|
};
|
|
|
|
auto Comparator = [](const IntPair &LHS, const IntPair &RHS) {
|
|
return LHS.first == RHS.first;
|
|
};
|
|
|
|
TheVector.erase(unique_last(TheVector.begin(), TheVector.end(), Comparator),
|
|
TheVector.end());
|
|
|
|
Vector Expected = { { 1, 3 }, { 2, 3 } };
|
|
revng_check(TheVector == Expected);
|
|
}
|
|
|
|
template<template<typename...> class T>
|
|
static void testAt() {
|
|
revng::TrackingContainer<T<int>> Vector;
|
|
int One(1);
|
|
Vector.insert(One);
|
|
Vector.clearTracking();
|
|
const auto &Reference = Vector;
|
|
Reference.at(One);
|
|
|
|
auto TrackingResult = Reference.getTrackingResult();
|
|
revng_check(TrackingResult.InspectedKeys.size() == 1);
|
|
revng_check(TrackingResult.InspectedKeys.contains(1));
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(TrackingContainerVectorAt) {
|
|
testAt<SortedVector>();
|
|
testAt<MutableSet>();
|
|
}
|
|
|
|
template<template<typename...> class T>
|
|
static void testVectorCount() {
|
|
revng::TrackingContainer<T<int>> Vector;
|
|
Vector.insert(1);
|
|
Vector.clearTracking();
|
|
const auto &Reference = Vector;
|
|
Reference.count(2);
|
|
|
|
auto TrackingResult = Reference.getTrackingResult();
|
|
revng_check(TrackingResult.InspectedKeys.size() == 1);
|
|
revng_check(not TrackingResult.Exact);
|
|
revng_check(TrackingResult.InspectedKeys.contains(2));
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(TrackingContainerVectorCount) {
|
|
testVectorCount<SortedVector>();
|
|
testVectorCount<MutableSet>();
|
|
}
|
|
|
|
template<template<typename...> class T>
|
|
static void testTryGet() {
|
|
revng::TrackingContainer<T<int>> Vector;
|
|
Vector.insert(1);
|
|
Vector.clearTracking();
|
|
const auto &Reference = Vector;
|
|
const int *Result = nullptr;
|
|
Result = Reference.tryGet(2);
|
|
revng_check(Result == nullptr);
|
|
Result = Reference.tryGet(1);
|
|
revng_check(Result != nullptr && *Result == 1);
|
|
|
|
auto TrackingResult = Reference.getTrackingResult();
|
|
revng_check(TrackingResult.InspectedKeys == std::set<int>({ 1, 2 }));
|
|
revng_check(not TrackingResult.Exact);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(TrackingContainerVectorTryGet) {
|
|
testTryGet<SortedVector>();
|
|
testTryGet<MutableSet>();
|
|
}
|
|
|
|
template<template<typename...> class T>
|
|
static void testBeginEnd() {
|
|
revng::TrackingContainer<SortedVector<int>> Vector;
|
|
Vector.insert(1);
|
|
Vector.clearTracking();
|
|
const auto &Reference = Vector;
|
|
llvm::find(Reference, 1);
|
|
|
|
auto TrackingResult = Reference.getTrackingResult();
|
|
revng_check(TrackingResult.InspectedKeys.size() == 0);
|
|
revng_check(TrackingResult.Exact);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(TrackingContainerVectorBeginEnd) {
|
|
testBeginEnd<SortedVector>();
|
|
testBeginEnd<MutableSet>();
|
|
}
|
|
|
|
template<template<typename...> class T>
|
|
static void testSetCount() {
|
|
revng::TrackingContainer<SortedVector<int>> Vector;
|
|
Vector.insert(1);
|
|
Vector.clearTracking();
|
|
const auto &Reference = Vector;
|
|
Reference.count(1);
|
|
|
|
auto TrackingResult = Reference.getTrackingResult();
|
|
revng_check(TrackingResult.InspectedKeys == std::set<int>({ 1 }));
|
|
revng_check(not TrackingResult.Exact);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(TrackingContainerSetCount) {
|
|
testSetCount<SortedVector>();
|
|
testSetCount<MutableSet>();
|
|
}
|
|
|
|
template<template<typename...> class T>
|
|
static void testPush() {
|
|
revng::TrackingContainer<SortedVector<int>> Vector;
|
|
Vector.insert(1);
|
|
Vector.clearTracking();
|
|
const auto &Reference = Vector;
|
|
Reference.count(1);
|
|
|
|
Reference.trackingPush();
|
|
|
|
auto TrackingResult = Reference.getTrackingResult();
|
|
revng_check(TrackingResult.InspectedKeys == std::set<int>({ 1 }));
|
|
revng_check(not TrackingResult.Exact);
|
|
|
|
Reference.trackingPop();
|
|
|
|
TrackingResult = Reference.getTrackingResult();
|
|
revng_check(TrackingResult.InspectedKeys == std::set<int>({ 1 }));
|
|
revng_check(not TrackingResult.Exact);
|
|
|
|
Reference.trackingPop();
|
|
|
|
TrackingResult = Reference.getTrackingResult();
|
|
revng_check(TrackingResult.InspectedKeys.empty());
|
|
revng_check(not TrackingResult.Exact);
|
|
}
|
|
|
|
BOOST_AUTO_TEST_CASE(TrackingContainerPush) {
|
|
testPush<SortedVector>();
|
|
testPush<MutableSet>();
|
|
}
|
|
|
|
static_assert(KeyedObjectContainer<TrackingSortedVector<int>>);
|
|
static_assert(KeyedObjectContainer<revng::TrackingContainer<MutableSet<int>>>);
|