Files
UnrealEngine/Engine/Source/Programs/AutoRTFMTests/Private/Commit.cpp
2025-05-18 13:04:45 +08:00

467 lines
9.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "AutoRTFMTesting.h"
#include "Catch2Includes.h"
#include <map>
#include <vector>
TEST_CASE("Commit.Nop")
{
REQUIRE(AutoRTFM::ETransactionResult::Committed == AutoRTFM::Transact([&] () { }));
}
TEST_CASE("Commit")
{
int x = 42;
std::vector<int> v;
std::map<int, std::vector<int>> m;
v.push_back(100);
m[1].push_back(2);
m[1].push_back(3);
m[4].push_back(5);
m[6].push_back(7);
m[6].push_back(8);
m[6].push_back(9);
REQUIRE(
AutoRTFM::ETransactionResult::Committed ==
AutoRTFM::Transact([&] () {
x = 5;
for (size_t n = 10; n--;)
v.push_back(2 * n);
m.clear();
m[10].push_back(11);
m[12].push_back(13);
m[12].push_back(14);
}));
REQUIRE(x == 5);
REQUIRE(v.size() == 11);
REQUIRE(v[0] == 100);
REQUIRE(v[1] == 18);
REQUIRE(v[2] == 16);
REQUIRE(v[3] == 14);
REQUIRE(v[4] == 12);
REQUIRE(v[5] == 10);
REQUIRE(v[6] == 8);
REQUIRE(v[7] == 6);
REQUIRE(v[8] == 4);
REQUIRE(v[9] == 2);
REQUIRE(v[10] == 0);
REQUIRE(m.size() == 2);
REQUIRE(m[10].size() == 1);
REQUIRE(m[10][0] == 11);
REQUIRE(m[12].size() == 2);
REQUIRE(m[12][0] == 13);
REQUIRE(m[12][1] == 14);
}
TEST_CASE("Commit.Large")
{
std::vector<int> v;
std::map<int, std::vector<int>> m;
for (unsigned i = 0; i < 1000; ++i)
{
v.push_back(i);
}
for (unsigned i = 0; i < 1000; ++i)
{
for (unsigned j = 0; j < 10; ++j)
{
m[i + j].push_back(i + j);
}
}
AutoRTFM::Commit([&]
{
for (unsigned i = 0; i < 10000; ++i)
{
v.push_back(i);
}
for (unsigned i = 0; i < 10000; ++i)
{
for (unsigned j = 0; j < 5; ++j)
{
m[i + j].push_back(i + j);
}
}
});
}
static int SCommitKey;
TEST_CASE("Commit.PushOnCommitHandler_NoAbort")
{
int Value = 55;
AutoRTFM::Testing::Commit([&]
{
Value = 66;
AutoRTFM::PushOnCommitHandler(&SCommitKey, [&Value]() { Value = 77; });
Value = 88;
});
REQUIRE(Value == 77);
}
TEST_CASE("Commit.PushOnCommitHandler_WithAbort")
{
AutoRTFM::Testing::Abort([&]
{
AutoRTFM::PushOnCommitHandler(&SCommitKey, []() { FAIL("Unreachable"); });
AutoRTFM::AbortTransaction();
});
}
TEST_CASE("Commit.PushOnCommitHandler_MutableCapture")
{
FString Message = "Hello";
AutoRTFM::Testing::Commit([&]
{
AutoRTFM::PushOnCommitHandler(&SCommitKey, [&Message]() mutable
{
Message += " World!";
});
});
REQUIRE(Message == "Hello World!");
}
TEST_CASE("Commit.PushOnCommitHandler_WithPop_NoAbort")
{
AutoRTFM::Testing::Commit([&]
{
AutoRTFM::PushOnCommitHandler(&SCommitKey, []() { FAIL("Unreachable!"); });
AutoRTFM::PopOnCommitHandler(&SCommitKey);
});
}
TEST_CASE("Commit.PushOnCommitHandler_WithPopAll_NoAbort")
{
AutoRTFM::Commit([&]
{
AutoRTFM::PushOnCommitHandler(&SCommitKey, []() { FAIL("Unreachable!"); });
AutoRTFM::PopAllOnCommitHandlers(&SCommitKey);
});
}
TEST_CASE("Commit.PushOnCommitHandler_WithPop_WithAbort")
{
AutoRTFM::Testing::Abort([&]
{
AutoRTFM::PushOnCommitHandler(&SCommitKey, []() { FAIL("Unreachable!"); });
AutoRTFM::PopOnCommitHandler(&SCommitKey);
AutoRTFM::AbortTransaction();
});
}
TEST_CASE("Commit.PushOnCommitHandler_WithPopAll_WithAbort")
{
AutoRTFM::Testing::Abort([&]
{
AutoRTFM::PushOnCommitHandler(&SCommitKey, []() { FAIL("Unreachable!"); });
AutoRTFM::PopAllOnCommitHandlers(&SCommitKey);
AutoRTFM::AbortTransaction();
});
}
TEST_CASE("Commit.PushOnCommitHandler_Duplicates1")
{
bool bHit = false;
AutoRTFM::Testing::Commit([&]
{
AutoRTFM::PushOnCommitHandler(&SCommitKey, [&bHit]() { bHit = 77; });
AutoRTFM::PushOnCommitHandler(&SCommitKey, []() { FAIL("Unreachable!"); });
AutoRTFM::PopOnCommitHandler(&SCommitKey);
});
// The first push on commit will still go through.
REQUIRE(bHit);
}
TEST_CASE("Commit.PushOnCommitHandler_PopAll_Duplicates")
{
AutoRTFM::Testing::Commit([&]
{
AutoRTFM::PushOnCommitHandler(&SCommitKey, []() { FAIL("Unreachable!"); });
AutoRTFM::PushOnCommitHandler(&SCommitKey, []() { FAIL("Unreachable!"); });
AutoRTFM::PopAllOnCommitHandlers(&SCommitKey);
});
}
TEST_CASE("Commit.PushOnCommitHandler_Duplicates2")
{
int Value = 55;
AutoRTFM::Testing::Commit([&]
{
Value = 66;
AutoRTFM::PushOnCommitHandler(&SCommitKey, [&Value]() { Value += 13; });
AutoRTFM::PushOnCommitHandler(&SCommitKey, [&Value]() { Value *= 11; });
Value = 99;
});
REQUIRE(Value == 1232);
}
TEST_CASE("Commit.PushOnCommitHandler_Order")
{
SECTION("HandlerSandwich")
{
SECTION("WithoutPop")
{
int Value = 37;
AutoRTFM::Testing::Commit([&]
{
AutoRTFM::OnCommit([&Value] { REQUIRE(99 == Value); Value += 1; });
AutoRTFM::PushOnCommitHandler(&SCommitKey, [&Value]() { REQUIRE(100 == Value); Value += 2; });
AutoRTFM::OnCommit([&Value] { REQUIRE(102 == Value); Value += 3; });
Value = 99;
});
REQUIRE(Value == 105);
}
SECTION("WithPop")
{
int Value = 37;
AutoRTFM::Testing::Commit([&]
{
AutoRTFM::OnCommit([&Value] { REQUIRE(99 == Value); Value += 1; });
AutoRTFM::PushOnCommitHandler(&SCommitKey, [&Value]() { FAIL("Unreachable!"); });
AutoRTFM::OnCommit([&Value] { REQUIRE(100 == Value); Value += 3; });
AutoRTFM::PopOnCommitHandler(&SCommitKey);
Value = 99;
});
REQUIRE(Value == 103);
}
}
SECTION("HandlerInChild")
{
SECTION("WithoutPop")
{
int Value = 37;
AutoRTFM::Testing::Commit([&]
{
AutoRTFM::OnCommit([&Value]
{
REQUIRE(99 == Value);
Value += 1;
});
// Make a child transaction.
AutoRTFM::Testing::Commit([&]
{
AutoRTFM::PushOnCommitHandler(&SCommitKey, [&Value]()
{
REQUIRE(100 == Value);
Value += 2;
});
});
AutoRTFM::OnCommit([&Value]
{
REQUIRE(102 == Value);
Value += 3;
});
Value = 99;
});
REQUIRE(105 == Value);
}
SECTION("WithPop")
{
int Value = 37;
AutoRTFM::Testing::Commit([&]
{
AutoRTFM::OnCommit([&Value] { REQUIRE(99 == Value); Value += 1; });
// Make a child transaction.
AutoRTFM::Testing::Commit([&]
{
AutoRTFM::PushOnCommitHandler(&SCommitKey, [&Value]()
{
REQUIRE(false);
});
});
AutoRTFM::OnCommit([&Value] { REQUIRE(100 == Value); Value += 3; });
// Bit funky, but we can pop the child's push here!
AutoRTFM::PopOnCommitHandler(&SCommitKey);
Value = 99;
});
REQUIRE(Value == 103);
}
SECTION("AbortInChild")
{
int Value = 99;
AutoRTFM::Testing::Commit([&]
{
AutoRTFM::OnCommit([&Value] { REQUIRE(37 == Value); Value += 1; });
// Make a child transaction.
AutoRTFM::Testing::Abort([&]
{
AutoRTFM::PushOnCommitHandler(&SCommitKey, [&Value]() { FAIL("Unreachable!"); });
AutoRTFM::AbortTransaction();
});
AutoRTFM::OnCommit([&Value] { REQUIRE(38 == Value); Value += 3; });
Value = 37;
});
REQUIRE(Value == 41);
}
SECTION("PopInChild")
{
int Value = 99;
AutoRTFM::Testing::Commit([&]
{
AutoRTFM::PushOnCommitHandler(&SCommitKey, [&Value] { Value = 42; });
AutoRTFM::Testing::Commit([&]
{
AutoRTFM::PopOnCommitHandler(&SCommitKey);
});
});
REQUIRE(99 == Value);
}
SECTION("PopInChildAndAbort")
{
int Value = 99;
AutoRTFM::Testing::Commit([&]
{
AutoRTFM::PushOnCommitHandler(&SCommitKey, [&Value] { Value = 42; });
AutoRTFM::Testing::Abort([&]
{
AutoRTFM::PopOnCommitHandler(&SCommitKey);
AutoRTFM::AbortTransaction();
});
});
REQUIRE(42 == Value);
}
SECTION("PopInChildsChild")
{
int Value = 99;
AutoRTFM::Testing::Commit([&]
{
AutoRTFM::PushOnCommitHandler(&SCommitKey, [&Value] { Value = 42; });
AutoRTFM::Testing::Commit([&]
{
AutoRTFM::Testing::Commit([&]
{
AutoRTFM::PopOnCommitHandler(&SCommitKey);
});
});
});
REQUIRE(99 == Value);
}
SECTION("PopAllInChild")
{
int Value = 99;
AutoRTFM::Testing::Commit([&]
{
AutoRTFM::PushOnCommitHandler(&SCommitKey, [&Value] { Value = 42; });
AutoRTFM::Testing::Commit([&]
{
AutoRTFM::PushOnCommitHandler(&SCommitKey, [&Value] { Value = 13; });
AutoRTFM::PopAllOnCommitHandlers(&SCommitKey);
});
});
REQUIRE(99 == Value);
}
SECTION("PopAllInChildAbort")
{
int Value = 99;
AutoRTFM::Testing::Commit([&]
{
AutoRTFM::PushOnCommitHandler(&SCommitKey, [&Value] { Value = 42; });
AutoRTFM::Testing::Abort([&]
{
AutoRTFM::PushOnCommitHandler(&SCommitKey, [&Value] { Value = 13; });
AutoRTFM::PopAllOnCommitHandlers(&SCommitKey);
// This abort will ensure that the pop-all cannot affect the outer transactions
// push on commit!
AutoRTFM::AbortTransaction();
});
});
REQUIRE(42 == Value);
}
}
}
// Test functions that may have LLVM byval() attributed parameters
// This is to test for FORT-823033
TEST_CASE("Commit.LargeStruct")
{
struct FLargeStruct
{
int Ints[32];
static int Sum(FLargeStruct Struct)
{
int Result = 0;
for (int I : Struct.Ints)
{
Result += I;
}
return Result;
}
};
FLargeStruct Struct
{
{
0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,
0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,
0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,
}
};
const int Expected = FLargeStruct::Sum(Struct);
int Result = 0;
AutoRTFM::Testing::Commit([&]
{
Result = FLargeStruct::Sum(Struct);
});
REQUIRE(Expected == Result);
}