Files
rippled/src/tests/libxrpl/basics/Mutex.cpp
Pratik Mankawde f4555c80fe fix: revert all unrelated upstream develop changes from phase-7 PR
Reverts 259 files that carried unrelated upstream changes through the
phase-6 merge: enum class removals (cppcoreguidelines-use-enum-class),
scoped_lock→lock_guard conversions (modernize-use-scoped-lock),
nodestore Backend API changes (void const* key), .clang-tidy config,
test infrastructure deletions, and miscellaneous develop changes.

These changes belong on develop, not in the telemetry PR chain.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-30 16:59:24 +01:00

291 lines
6.1 KiB
C++

#include <xrpl/basics/Mutex.hpp>
#include <gtest/gtest.h>
#include <memory>
#include <mutex>
#include <shared_mutex>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
using namespace xrpl;
struct MutexMakeTest : ::testing::Test
{
};
TEST_F(MutexMakeTest, default_constructor)
{
auto m = Mutex<int>::make();
auto lock = m.lock();
EXPECT_EQ(*lock, 0);
}
TEST_F(MutexMakeTest, single_argument)
{
auto m = Mutex<int>::make(42);
auto lock = m.lock();
EXPECT_EQ(*lock, 42);
}
TEST_F(MutexMakeTest, string_argument)
{
auto m = Mutex<std::string>::make("test");
auto lock = m.lock();
EXPECT_EQ(*lock, "test");
}
TEST_F(MutexMakeTest, move_only_type)
{
auto m = Mutex<std::unique_ptr<int>>::make(std::make_unique<int>(100));
auto lock = m.lock();
EXPECT_NE(lock->get(), nullptr);
EXPECT_EQ(**lock, 100);
}
struct MutexDirectConstructionTest : ::testing::Test
{
};
TEST_F(MutexDirectConstructionTest, default_constructor)
{
// Test default construction with a type that has a non-trivial
// default constructor
Mutex<std::string> m;
auto lock = m.lock();
EXPECT_TRUE(lock->empty());
}
TEST_F(MutexDirectConstructionTest, default_initialization)
{
Mutex<int> m;
auto lock = m.lock();
EXPECT_EQ(*lock, 0);
}
TEST_F(MutexDirectConstructionTest, constructor_with_value)
{
Mutex<int> m(42);
auto lock = m.lock();
EXPECT_EQ(*lock, 42);
}
TEST_F(MutexDirectConstructionTest, constructor_with_string)
{
Mutex<std::string> m(std::string("hello"));
auto lock = m.lock();
EXPECT_EQ(*lock, "hello");
}
struct MutexLockNonConstTest : ::testing::Test
{
};
TEST_F(MutexLockNonConstTest, operator_star)
{
Mutex<int> m(10);
{
auto lock = m.lock();
EXPECT_EQ(*lock, 10);
*lock = 20;
}
auto lock = m.lock();
EXPECT_EQ(*lock, 20);
}
TEST_F(MutexLockNonConstTest, get_method)
{
Mutex<int> m(10);
{
auto lock = m.lock();
EXPECT_EQ(lock.get(), 10);
lock.get() = 30;
}
auto lock = m.lock();
EXPECT_EQ(lock.get(), 30);
}
TEST_F(MutexLockNonConstTest, operator_arrow)
{
Mutex<std::string> m(std::string("test"));
{
auto lock = m.lock();
EXPECT_EQ(lock->size(), 4);
lock->append(" string");
}
auto lock = m.lock();
EXPECT_EQ(*lock, "test string");
}
TEST_F(MutexLockNonConstTest, multiple_modifications)
{
Mutex<int> m(10);
{
auto lock = m.lock();
*lock = 20;
}
{
auto lock = m.lock();
EXPECT_EQ(lock.get(), 20);
lock.get() = 30;
}
{
auto lock = m.lock();
EXPECT_EQ(*lock, 30);
}
}
struct MutexLockConstTest : ::testing::Test
{
};
TEST_F(MutexLockConstTest, operator_star)
{
Mutex<int> const m(42);
auto lock = m.lock();
static_assert(std::is_const_v<std::remove_reference_t<decltype(*lock)>>);
EXPECT_EQ(*lock, 42);
}
TEST_F(MutexLockConstTest, get_method)
{
Mutex<int> const m(42);
auto lock = m.lock();
static_assert(std::is_const_v<std::remove_reference_t<decltype(lock.get())>>);
EXPECT_EQ(lock.get(), 42);
}
TEST_F(MutexLockConstTest, operator_arrow)
{
Mutex<std::string> const m(std::string("test"));
auto lock = m.lock();
static_assert(std::is_const_v<std::remove_reference_t<decltype(*lock)>>);
EXPECT_EQ(lock->size(), 4);
EXPECT_EQ(lock->at(0), 't');
}
struct MutexConstCorrectnessTest : ::testing::Test
{
};
TEST_F(MutexConstCorrectnessTest, non_const_allows_modification)
{
Mutex<std::vector<int>> m({1, 2, 3, 4, 5});
{
auto lock = m.lock();
EXPECT_EQ(lock->size(), 5);
lock->push_back(6);
}
auto lock = m.lock();
EXPECT_EQ(lock->size(), 6);
EXPECT_EQ(lock->back(), 6);
}
TEST_F(MutexConstCorrectnessTest, const_reference_provides_const_access)
{
Mutex<std::vector<int>> const m({1, 2, 3, 4, 5, 6});
Mutex<std::vector<int>> const& const_ref = m;
auto lock = const_ref.lock();
static_assert(std::is_const_v<std::remove_reference_t<decltype(*lock)>>);
EXPECT_EQ(lock->size(), 6);
EXPECT_EQ(lock->at(5), 6);
}
struct MutexDifferentLockTypesTest : ::testing::Test
{
};
TEST_F(MutexDifferentLockTypesTest, scoped_lock)
{
Mutex<int> m(0);
{
auto lock = m.lock();
*lock = 1;
}
auto lock = m.lock();
EXPECT_EQ(*lock, 1);
}
TEST_F(MutexDifferentLockTypesTest, unique_lock)
{
Mutex<int> m(0);
auto lock = m.lock<std::unique_lock>();
EXPECT_EQ(*lock, 0);
*lock = 2;
std::unique_lock<std::mutex>& ul = lock;
ul.unlock();
ul.lock();
EXPECT_EQ(*lock, 2);
}
struct MutexSharedMutexTest : ::testing::Test
{
};
TEST_F(MutexSharedMutexTest, shared_lock_for_const_access)
{
Mutex<int, std::shared_mutex> const m(100);
Mutex<int, std::shared_mutex> const& const_ref = m;
auto lock = const_ref.lock<std::shared_lock>();
EXPECT_EQ(*lock, 100);
}
TEST_F(MutexSharedMutexTest, unique_lock_for_mutable_access)
{
Mutex<int, std::shared_mutex> m(100);
{
auto lock = m.lock<std::unique_lock>();
*lock = 200;
}
auto lock = m.lock<std::shared_lock>();
EXPECT_EQ(*lock, 200);
}
struct MutexComplexTypeTest : ::testing::Test
{
struct Data
{
int x;
std::string y;
Data(int x_, std::string y_) : x(x_), y(std::move(y_))
{
}
};
};
TEST_F(MutexComplexTypeTest, construct_and_access)
{
auto m = Mutex<Data>::make(42, "hello");
auto lock = m.lock();
EXPECT_EQ(lock->x, 42);
EXPECT_EQ(lock->y, "hello");
}
TEST_F(MutexComplexTypeTest, modify_fields)
{
auto m = Mutex<Data>::make(42, "hello");
{
auto lock = m.lock();
lock->x = 100;
lock->y = "world";
}
{
auto lock = m.lock();
EXPECT_EQ(lock->x, 100);
EXPECT_EQ(lock->y, "world");
}
}
TEST_F(MutexComplexTypeTest, const_access_to_fields)
{
auto const m = Mutex<Data>::make(42, "hello");
auto lock = m.lock();
static_assert(std::is_const_v<std::remove_reference_t<decltype(*lock)>>);
EXPECT_EQ(lock->x, 42);
EXPECT_EQ(lock->y, "hello");
}