Skip to content

Commit 7043255

Browse files
authored
Improve unit tests (#74)
* Move all common tests into cpp files from hpp * Add unit tests for scoped spinlock * Improve hex unit tests * Improve string unit tests * Improve address unit tests * Improve Win32 tests * Move imfont test to cpp file * Improve imfont tests * Exclude generated font awesome icons header from sonar
1 parent b745bda commit 7043255

25 files changed

+605
-467
lines changed

common/src/util/string.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66

77
namespace base::common::util::string {
88
std::string ReplaceAll(std::string str, const std::string& target_replace, const std::string& replace_val) {
9+
if (str.empty() || target_replace.empty())
10+
return str;
11+
912
size_t pos = 0;
1013
while ((pos = str.find(target_replace, pos)) != std::string::npos) {
1114
str.replace(pos, target_replace.length(), replace_val);

common/test/CMakeLists.txt

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,15 @@ set(CMAKE_CXX_STANDARD 23)
66
add_executable(${PROJECT_NAME}
77
src/main.cpp
88
src/win32/signal_test.cpp
9-
src/win32/signal_test.hpp
109
src/win32/misc_test.cpp
11-
src/win32/misc_test.hpp
1210
src/test_globals.hpp
1311
src/concurrency/spinlock_test.cpp
14-
src/concurrency/spinlock_test.hpp
1512
src/util/string_test.cpp
16-
src/util/string_test.hpp
1713
src/util/time_test.cpp
18-
src/util/time_test.hpp
1914
src/conversion/hex_test.cpp
20-
src/conversion/hex_test.hpp
2115
src/fmt/fs_formatter_test.cpp
22-
src/fmt/fs_formatter_test.hpp
2316
src/fs/vfs_test.cpp
24-
src/fs/vfs_test.hpp
2517
src/memory/address_test.cpp
26-
src/memory/address_test.hpp
2718
)
2819

2920
include(../../vendor/gtest.cmake)

common/test/src/concurrency/spinlock_test.cpp

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,119 @@
22
// Created by X-ray on 05/04/2025.
33
//
44

5-
#include "spinlock_test.hpp"
5+
#include <future>
6+
#include <base-common/concurrency/spinlock.hpp>
7+
#include <gtest/gtest.h>
8+
9+
inline std::atomic<bool> keep_lock = true;
10+
11+
template <class T> requires std::is_same_v<T, base::common::concurrency::Spinlock> or std::is_same_v<T, base::common::concurrency::RecursiveSpinlock>
12+
void WaitForUnlock(T& spinlock) {
13+
base::common::concurrency::ScopedSpinlock<T> lock(spinlock);
14+
15+
const auto start_time = std::chrono::steady_clock::now();
16+
constexpr auto timeout = std::chrono::seconds(5); // After 5 seconds we can safely say this isn't going to work
17+
18+
while (keep_lock) {
19+
std::this_thread::yield();
20+
21+
// Check if we've exceeded the timeout
22+
if (std::chrono::steady_clock::now() - start_time > timeout) {
23+
throw std::runtime_error("WaitForUnlock: Has timed out");
24+
}
25+
}
26+
}
27+
28+
TEST(SpinLock, TryLock) {
29+
base::common::concurrency::Spinlock spinlock;
30+
keep_lock = true;
31+
32+
const auto fut = std::async(std::launch::async, WaitForUnlock<base::common::concurrency::Spinlock>, std::ref(spinlock));
33+
std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // Need to make sure the new thread actually had time to take the lock
34+
35+
ASSERT_FALSE(spinlock.TryLock());
36+
keep_lock = false;
37+
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
38+
ASSERT_TRUE(spinlock.TryLock());
39+
}
40+
41+
TEST(SpinLock, LockUnlock) {
42+
base::common::concurrency::Spinlock spinlock;
43+
keep_lock = false;
44+
45+
spinlock.Lock();
46+
47+
const auto fut = std::async(std::launch::async, WaitForUnlock<base::common::concurrency::Spinlock>, std::ref(spinlock));
48+
49+
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
50+
ASSERT_NE(fut.wait_for(std::chrono::seconds(0)), std::future_status::ready);
51+
52+
spinlock.Unlock();
53+
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
54+
ASSERT_EQ(fut.wait_for(std::chrono::seconds(0)), std::future_status::ready);
55+
}
56+
57+
TEST(SpinLock, ScopedSpinlock) {
58+
base::common::concurrency::Spinlock spinlock;
59+
{
60+
base::common::concurrency::ScopedSpinlock lock(spinlock);
61+
ASSERT_FALSE(spinlock.TryLock()); // Should not be able to acquire the lock again
62+
}
63+
ASSERT_TRUE(spinlock.TryLock()); // The lock should now be released
64+
spinlock.Unlock();
65+
}
66+
67+
// Now for recursive spinlock
68+
TEST(RecursiveSpinLock, TryLock) {
69+
base::common::concurrency::RecursiveSpinlock spinlock;
70+
keep_lock = true;
71+
72+
auto fut = std::async(std::launch::async, WaitForUnlock<base::common::concurrency::RecursiveSpinlock>, std::ref(spinlock));
73+
std::this_thread::sleep_for(std::chrono::milliseconds(1000)); // Need to make sure the new thread actually had time to take the lock
74+
75+
ASSERT_FALSE(spinlock.TryLock());
76+
keep_lock = false;
77+
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
78+
ASSERT_EQ(fut.wait_for(std::chrono::seconds(0)), std::future_status::ready);
79+
80+
ASSERT_TRUE(spinlock.TryLock());
81+
ASSERT_TRUE(spinlock.TryLock());
82+
83+
fut = std::async(std::launch::async, WaitForUnlock<base::common::concurrency::RecursiveSpinlock>, std::ref(spinlock));
84+
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
85+
ASSERT_NE(fut.wait_for(std::chrono::seconds(0)), std::future_status::ready);
86+
87+
keep_lock = false;
88+
spinlock.Unlock();
89+
spinlock.Unlock();
90+
91+
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
92+
ASSERT_EQ(fut.wait_for(std::chrono::seconds(0)), std::future_status::ready);
93+
}
94+
95+
TEST(RecursiveSpinLock, LockUnlock) {
96+
base::common::concurrency::RecursiveSpinlock spinlock;
97+
keep_lock = false;
98+
99+
spinlock.Lock();
100+
101+
const auto fut = std::async(std::launch::async, WaitForUnlock<base::common::concurrency::RecursiveSpinlock>, std::ref(spinlock));
102+
103+
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
104+
ASSERT_NE(fut.wait_for(std::chrono::seconds(0)), std::future_status::ready);
105+
106+
spinlock.Unlock();
107+
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
108+
ASSERT_EQ(fut.wait_for(std::chrono::seconds(0)), std::future_status::ready);
109+
}
110+
111+
TEST(RecursiveSpinLock, ScopedSpinlock) {
112+
base::common::concurrency::RecursiveSpinlock spinlock;
113+
{
114+
base::common::concurrency::ScopedSpinlock lock(spinlock);
115+
ASSERT_TRUE(spinlock.TryLock()); // Should be able to acquire the lock again (recursive)
116+
spinlock.Unlock();
117+
}
118+
ASSERT_TRUE(spinlock.TryLock()); // The lock should now be released
119+
spinlock.Unlock();
120+
}

common/test/src/concurrency/spinlock_test.hpp

Lines changed: 0 additions & 103 deletions
This file was deleted.

common/test/src/conversion/hex_test.cpp

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,53 @@
22
// Created by X-ray on 06/04/2025.
33
//
44

5-
#include "hex_test.hpp"
5+
#include <base-common/conversion/hex.hpp>
6+
#include <gtest/gtest.h>
7+
8+
TEST(Hex, AddrToHex) {
9+
EXPECT_EQ(base::common::conversion::AddrToHex(0x0), "0x0");
10+
EXPECT_EQ(base::common::conversion::AddrToHex(0x1), "0x1");
11+
EXPECT_EQ(base::common::conversion::AddrToHex(0xA), "0xA");
12+
EXPECT_EQ(base::common::conversion::AddrToHex(0x10), "0x10");
13+
EXPECT_EQ(base::common::conversion::AddrToHex(0x100), "0x100");
14+
EXPECT_EQ(base::common::conversion::AddrToHex(0x1000), "0x1000");
15+
EXPECT_EQ(base::common::conversion::AddrToHex(0x10000), "0x10000");
16+
EXPECT_EQ(base::common::conversion::AddrToHex(0x100000), "0x100000");
17+
EXPECT_EQ(base::common::conversion::AddrToHex(0x1000000), "0x1000000");
18+
EXPECT_EQ(base::common::conversion::AddrToHex(0xFFFFFFFF), "0xFFFFFFFF");
19+
EXPECT_EQ(base::common::conversion::AddrToHex(0xFFFFFFFFFFFFFFFF), "0xFFFFFFFFFFFFFFFF");
20+
}
21+
22+
TEST(Hex, HexCharToInt) {
23+
EXPECT_EQ(base::common::conversion::HexCharToInt('0').value(), 0);
24+
EXPECT_EQ(base::common::conversion::HexCharToInt('1').value(), 1);
25+
EXPECT_EQ(base::common::conversion::HexCharToInt('2').value(), 2);
26+
EXPECT_EQ(base::common::conversion::HexCharToInt('3').value(), 3);
27+
EXPECT_EQ(base::common::conversion::HexCharToInt('4').value(), 4);
28+
EXPECT_EQ(base::common::conversion::HexCharToInt('5').value(), 5);
29+
EXPECT_EQ(base::common::conversion::HexCharToInt('6').value(), 6);
30+
EXPECT_EQ(base::common::conversion::HexCharToInt('7').value(), 7);
31+
EXPECT_EQ(base::common::conversion::HexCharToInt('8').value(), 8);
32+
EXPECT_EQ(base::common::conversion::HexCharToInt('9').value(), 9);
33+
EXPECT_EQ(base::common::conversion::HexCharToInt('A').value(), 10);
34+
EXPECT_EQ(base::common::conversion::HexCharToInt('B').value(), 11);
35+
EXPECT_EQ(base::common::conversion::HexCharToInt('C').value(), 12);
36+
EXPECT_EQ(base::common::conversion::HexCharToInt('D').value(), 13);
37+
EXPECT_EQ(base::common::conversion::HexCharToInt('E').value(), 14);
38+
EXPECT_EQ(base::common::conversion::HexCharToInt('F').value(), 15);
39+
EXPECT_EQ(base::common::conversion::HexCharToInt('a').value(), 10);
40+
EXPECT_EQ(base::common::conversion::HexCharToInt('b').value(), 11);
41+
EXPECT_EQ(base::common::conversion::HexCharToInt('c').value(), 12);
42+
EXPECT_EQ(base::common::conversion::HexCharToInt('d').value(), 13);
43+
EXPECT_EQ(base::common::conversion::HexCharToInt('e').value(), 14);
44+
EXPECT_EQ(base::common::conversion::HexCharToInt('f').value(), 15);
45+
46+
auto res = base::common::conversion::HexCharToInt('G');
47+
ASSERT_TRUE(res.error());
48+
auto res2 = base::common::conversion::HexCharToInt('g');
49+
ASSERT_TRUE(res2.error());
50+
auto res3 = base::common::conversion::HexCharToInt(' ');
51+
ASSERT_TRUE(res3.error());
52+
auto res4 = base::common::conversion::HexCharToInt('!');
53+
ASSERT_TRUE(res4.error());
54+
}

common/test/src/conversion/hex_test.hpp

Lines changed: 0 additions & 43 deletions
This file was deleted.

common/test/src/fmt/fs_formatter_test.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,13 @@
22
// Created by X-ray on 06/04/2025.
33
//
44

5-
#include "fs_formatter_test.hpp"
5+
#include <base-common/fmt/fs_formatter.hpp>
6+
#include <gtest/gtest.h>
7+
8+
TEST(FsFormatter, FormatPath) {
9+
const std::string str_path = "C:/Users/X-ray/Documents/test.txt";
10+
const std::filesystem::path path = str_path;
11+
12+
EXPECT_EQ(fmt::format("{}", path), str_path);
13+
EXPECT_EQ(fmt::format("{}", path), path.generic_string());
14+
}

common/test/src/fmt/fs_formatter_test.hpp

Lines changed: 0 additions & 18 deletions
This file was deleted.

0 commit comments

Comments
 (0)