summaryrefslogtreecommitdiff
path: root/src/tests
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests')
-rw-r--r--src/tests/CMakeLists.txt3
-rw-r--r--src/tests/common/bit_field.cpp4
-rw-r--r--src/tests/common/fibers.cpp75
-rw-r--r--src/tests/common/multi_level_queue.cpp55
-rw-r--r--src/tests/common/ring_buffer.cpp30
-rw-r--r--src/tests/core/arm/arm_test_common.cpp145
-rw-r--r--src/tests/core/arm/arm_test_common.h93
7 files changed, 59 insertions, 346 deletions
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
index 47ef30aa9..8a606b448 100644
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -2,11 +2,8 @@ add_executable(tests
2 common/bit_field.cpp 2 common/bit_field.cpp
3 common/bit_utils.cpp 3 common/bit_utils.cpp
4 common/fibers.cpp 4 common/fibers.cpp
5 common/multi_level_queue.cpp
6 common/param_package.cpp 5 common/param_package.cpp
7 common/ring_buffer.cpp 6 common/ring_buffer.cpp
8 core/arm/arm_test_common.cpp
9 core/arm/arm_test_common.h
10 core/core_timing.cpp 7 core/core_timing.cpp
11 tests.cpp 8 tests.cpp
12) 9)
diff --git a/src/tests/common/bit_field.cpp b/src/tests/common/bit_field.cpp
index 8ca1889f9..182638000 100644
--- a/src/tests/common/bit_field.cpp
+++ b/src/tests/common/bit_field.cpp
@@ -68,7 +68,7 @@ TEST_CASE("BitField", "[common]") {
68 }}); 68 }});
69 69
70 // bit fields: 01101100111101'10101110'1011'101100 70 // bit fields: 01101100111101'10101110'1011'101100
71 REQUIRE(be_bitfield.raw == 0b01101100'11110110'10111010'11101100); 71 REQUIRE(be_bitfield.raw == 0b01101100'11110110'10111010'11101100U);
72 REQUIRE(be_bitfield.a == 0b101100); 72 REQUIRE(be_bitfield.a == 0b101100);
73 REQUIRE(be_bitfield.b == -5); // 1011 as two's complement 73 REQUIRE(be_bitfield.b == -5); // 1011 as two's complement
74 REQUIRE(be_bitfield.c == TestEnum::B); 74 REQUIRE(be_bitfield.c == TestEnum::B);
@@ -80,7 +80,7 @@ TEST_CASE("BitField", "[common]") {
80 be_bitfield.d.Assign(0b01010101010101); 80 be_bitfield.d.Assign(0b01010101010101);
81 std::memcpy(&raw, &be_bitfield, sizeof(raw)); 81 std::memcpy(&raw, &be_bitfield, sizeof(raw));
82 // bit fields: 01010101010101'00001111'1111'000111 82 // bit fields: 01010101010101'00001111'1111'000111
83 REQUIRE(be_bitfield.raw == 0b01010101'01010100'00111111'11000111); 83 REQUIRE(be_bitfield.raw == 0b01010101'01010100'00111111'11000111U);
84 REQUIRE(raw == std::array<u8, 4>{{ 84 REQUIRE(raw == std::array<u8, 4>{{
85 0b01010101, 85 0b01010101,
86 0b01010100, 86 0b01010100,
diff --git a/src/tests/common/fibers.cpp b/src/tests/common/fibers.cpp
index 4fd92428f..d94492fc6 100644
--- a/src/tests/common/fibers.cpp
+++ b/src/tests/common/fibers.cpp
@@ -6,18 +6,40 @@
6#include <cstdlib> 6#include <cstdlib>
7#include <functional> 7#include <functional>
8#include <memory> 8#include <memory>
9#include <mutex>
10#include <stdexcept>
9#include <thread> 11#include <thread>
10#include <unordered_map> 12#include <unordered_map>
11#include <vector> 13#include <vector>
12 14
13#include <catch2/catch.hpp> 15#include <catch2/catch.hpp>
14#include <math.h> 16
15#include "common/common_types.h" 17#include "common/common_types.h"
16#include "common/fiber.h" 18#include "common/fiber.h"
17#include "common/spin_lock.h"
18 19
19namespace Common { 20namespace Common {
20 21
22class ThreadIds {
23public:
24 void Register(u32 id) {
25 const auto thread_id = std::this_thread::get_id();
26 std::scoped_lock lock{mutex};
27 if (ids.contains(thread_id)) {
28 throw std::logic_error{"Registering the same thread twice"};
29 }
30 ids.emplace(thread_id, id);
31 }
32
33 [[nodiscard]] u32 Get() const {
34 std::scoped_lock lock{mutex};
35 return ids.at(std::this_thread::get_id());
36 }
37
38private:
39 mutable std::mutex mutex;
40 std::unordered_map<std::thread::id, u32> ids;
41};
42
21class TestControl1 { 43class TestControl1 {
22public: 44public:
23 TestControl1() = default; 45 TestControl1() = default;
@@ -26,7 +48,7 @@ public:
26 48
27 void ExecuteThread(u32 id); 49 void ExecuteThread(u32 id);
28 50
29 std::unordered_map<std::thread::id, u32> ids; 51 ThreadIds thread_ids;
30 std::vector<std::shared_ptr<Common::Fiber>> thread_fibers; 52 std::vector<std::shared_ptr<Common::Fiber>> thread_fibers;
31 std::vector<std::shared_ptr<Common::Fiber>> work_fibers; 53 std::vector<std::shared_ptr<Common::Fiber>> work_fibers;
32 std::vector<u32> items; 54 std::vector<u32> items;
@@ -39,8 +61,7 @@ static void WorkControl1(void* control) {
39} 61}
40 62
41void TestControl1::DoWork() { 63void TestControl1::DoWork() {
42 std::thread::id this_id = std::this_thread::get_id(); 64 const u32 id = thread_ids.Get();
43 u32 id = ids[this_id];
44 u32 value = items[id]; 65 u32 value = items[id];
45 for (u32 i = 0; i < id; i++) { 66 for (u32 i = 0; i < id; i++) {
46 value++; 67 value++;
@@ -50,8 +71,7 @@ void TestControl1::DoWork() {
50} 71}
51 72
52void TestControl1::ExecuteThread(u32 id) { 73void TestControl1::ExecuteThread(u32 id) {
53 std::thread::id this_id = std::this_thread::get_id(); 74 thread_ids.Register(id);
54 ids[this_id] = id;
55 auto thread_fiber = Fiber::ThreadToFiber(); 75 auto thread_fiber = Fiber::ThreadToFiber();
56 thread_fibers[id] = thread_fiber; 76 thread_fibers[id] = thread_fiber;
57 work_fibers[id] = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl1}, this); 77 work_fibers[id] = std::make_shared<Fiber>(std::function<void(void*)>{WorkControl1}, this);
@@ -98,8 +118,7 @@ public:
98 value1 += i; 118 value1 += i;
99 } 119 }
100 Fiber::YieldTo(fiber1, fiber3); 120 Fiber::YieldTo(fiber1, fiber3);
101 std::thread::id this_id = std::this_thread::get_id(); 121 const u32 id = thread_ids.Get();
102 u32 id = ids[this_id];
103 assert1 = id == 1; 122 assert1 = id == 1;
104 value2 += 5000; 123 value2 += 5000;
105 Fiber::YieldTo(fiber1, thread_fibers[id]); 124 Fiber::YieldTo(fiber1, thread_fibers[id]);
@@ -115,8 +134,7 @@ public:
115 } 134 }
116 135
117 void DoWork3() { 136 void DoWork3() {
118 std::thread::id this_id = std::this_thread::get_id(); 137 const u32 id = thread_ids.Get();
119 u32 id = ids[this_id];
120 assert2 = id == 0; 138 assert2 = id == 0;
121 value1 += 1000; 139 value1 += 1000;
122 Fiber::YieldTo(fiber3, thread_fibers[id]); 140 Fiber::YieldTo(fiber3, thread_fibers[id]);
@@ -125,14 +143,12 @@ public:
125 void ExecuteThread(u32 id); 143 void ExecuteThread(u32 id);
126 144
127 void CallFiber1() { 145 void CallFiber1() {
128 std::thread::id this_id = std::this_thread::get_id(); 146 const u32 id = thread_ids.Get();
129 u32 id = ids[this_id];
130 Fiber::YieldTo(thread_fibers[id], fiber1); 147 Fiber::YieldTo(thread_fibers[id], fiber1);
131 } 148 }
132 149
133 void CallFiber2() { 150 void CallFiber2() {
134 std::thread::id this_id = std::this_thread::get_id(); 151 const u32 id = thread_ids.Get();
135 u32 id = ids[this_id];
136 Fiber::YieldTo(thread_fibers[id], fiber2); 152 Fiber::YieldTo(thread_fibers[id], fiber2);
137 } 153 }
138 154
@@ -145,7 +161,7 @@ public:
145 u32 value2{}; 161 u32 value2{};
146 std::atomic<bool> trap{true}; 162 std::atomic<bool> trap{true};
147 std::atomic<bool> trap2{true}; 163 std::atomic<bool> trap2{true};
148 std::unordered_map<std::thread::id, u32> ids; 164 ThreadIds thread_ids;
149 std::vector<std::shared_ptr<Common::Fiber>> thread_fibers; 165 std::vector<std::shared_ptr<Common::Fiber>> thread_fibers;
150 std::shared_ptr<Common::Fiber> fiber1; 166 std::shared_ptr<Common::Fiber> fiber1;
151 std::shared_ptr<Common::Fiber> fiber2; 167 std::shared_ptr<Common::Fiber> fiber2;
@@ -168,15 +184,13 @@ static void WorkControl2_3(void* control) {
168} 184}
169 185
170void TestControl2::ExecuteThread(u32 id) { 186void TestControl2::ExecuteThread(u32 id) {
171 std::thread::id this_id = std::this_thread::get_id(); 187 thread_ids.Register(id);
172 ids[this_id] = id;
173 auto thread_fiber = Fiber::ThreadToFiber(); 188 auto thread_fiber = Fiber::ThreadToFiber();
174 thread_fibers[id] = thread_fiber; 189 thread_fibers[id] = thread_fiber;
175} 190}
176 191
177void TestControl2::Exit() { 192void TestControl2::Exit() {
178 std::thread::id this_id = std::this_thread::get_id(); 193 const u32 id = thread_ids.Get();
179 u32 id = ids[this_id];
180 thread_fibers[id]->Exit(); 194 thread_fibers[id]->Exit();
181} 195}
182 196
@@ -193,7 +207,7 @@ static void ThreadStart2_2(u32 id, TestControl2& test_control) {
193} 207}
194 208
195/** This test checks for fiber thread exchange configuration and validates that fibers are 209/** This test checks for fiber thread exchange configuration and validates that fibers are
196 * that a fiber has been succesfully transfered from one thread to another and that the TLS 210 * that a fiber has been successfully transferred from one thread to another and that the TLS
197 * region of the thread is kept while changing fibers. 211 * region of the thread is kept while changing fibers.
198 */ 212 */
199TEST_CASE("Fibers::InterExchange", "[common]") { 213TEST_CASE("Fibers::InterExchange", "[common]") {
@@ -228,24 +242,21 @@ public:
228 void DoWork1() { 242 void DoWork1() {
229 value1 += 1; 243 value1 += 1;
230 Fiber::YieldTo(fiber1, fiber2); 244 Fiber::YieldTo(fiber1, fiber2);
231 std::thread::id this_id = std::this_thread::get_id(); 245 const u32 id = thread_ids.Get();
232 u32 id = ids[this_id];
233 value3 += 1; 246 value3 += 1;
234 Fiber::YieldTo(fiber1, thread_fibers[id]); 247 Fiber::YieldTo(fiber1, thread_fibers[id]);
235 } 248 }
236 249
237 void DoWork2() { 250 void DoWork2() {
238 value2 += 1; 251 value2 += 1;
239 std::thread::id this_id = std::this_thread::get_id(); 252 const u32 id = thread_ids.Get();
240 u32 id = ids[this_id];
241 Fiber::YieldTo(fiber2, thread_fibers[id]); 253 Fiber::YieldTo(fiber2, thread_fibers[id]);
242 } 254 }
243 255
244 void ExecuteThread(u32 id); 256 void ExecuteThread(u32 id);
245 257
246 void CallFiber1() { 258 void CallFiber1() {
247 std::thread::id this_id = std::this_thread::get_id(); 259 const u32 id = thread_ids.Get();
248 u32 id = ids[this_id];
249 Fiber::YieldTo(thread_fibers[id], fiber1); 260 Fiber::YieldTo(thread_fibers[id], fiber1);
250 } 261 }
251 262
@@ -254,7 +265,7 @@ public:
254 u32 value1{}; 265 u32 value1{};
255 u32 value2{}; 266 u32 value2{};
256 u32 value3{}; 267 u32 value3{};
257 std::unordered_map<std::thread::id, u32> ids; 268 ThreadIds thread_ids;
258 std::vector<std::shared_ptr<Common::Fiber>> thread_fibers; 269 std::vector<std::shared_ptr<Common::Fiber>> thread_fibers;
259 std::shared_ptr<Common::Fiber> fiber1; 270 std::shared_ptr<Common::Fiber> fiber1;
260 std::shared_ptr<Common::Fiber> fiber2; 271 std::shared_ptr<Common::Fiber> fiber2;
@@ -271,15 +282,13 @@ static void WorkControl3_2(void* control) {
271} 282}
272 283
273void TestControl3::ExecuteThread(u32 id) { 284void TestControl3::ExecuteThread(u32 id) {
274 std::thread::id this_id = std::this_thread::get_id(); 285 thread_ids.Register(id);
275 ids[this_id] = id;
276 auto thread_fiber = Fiber::ThreadToFiber(); 286 auto thread_fiber = Fiber::ThreadToFiber();
277 thread_fibers[id] = thread_fiber; 287 thread_fibers[id] = thread_fiber;
278} 288}
279 289
280void TestControl3::Exit() { 290void TestControl3::Exit() {
281 std::thread::id this_id = std::this_thread::get_id(); 291 const u32 id = thread_ids.Get();
282 u32 id = ids[this_id];
283 thread_fibers[id]->Exit(); 292 thread_fibers[id]->Exit();
284} 293}
285 294
@@ -290,7 +299,7 @@ static void ThreadStart3(u32 id, TestControl3& test_control) {
290} 299}
291 300
292/** This test checks for one two threads racing for starting the same fiber. 301/** This test checks for one two threads racing for starting the same fiber.
293 * It checks execution occured in an ordered manner and by no time there were 302 * It checks execution occurred in an ordered manner and by no time there were
294 * two contexts at the same time. 303 * two contexts at the same time.
295 */ 304 */
296TEST_CASE("Fibers::StartRace", "[common]") { 305TEST_CASE("Fibers::StartRace", "[common]") {
diff --git a/src/tests/common/multi_level_queue.cpp b/src/tests/common/multi_level_queue.cpp
deleted file mode 100644
index cca7ec7da..000000000
--- a/src/tests/common/multi_level_queue.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
1// Copyright 2019 Yuzu Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <catch2/catch.hpp>
6#include <math.h>
7#include "common/common_types.h"
8#include "common/multi_level_queue.h"
9
10namespace Common {
11
12TEST_CASE("MultiLevelQueue", "[common]") {
13 std::array<f32, 8> values = {0.0, 5.0, 1.0, 9.0, 8.0, 2.0, 6.0, 7.0};
14 Common::MultiLevelQueue<f32, 64> mlq;
15 REQUIRE(mlq.empty());
16 mlq.add(values[2], 2);
17 mlq.add(values[7], 7);
18 mlq.add(values[3], 3);
19 mlq.add(values[4], 4);
20 mlq.add(values[0], 0);
21 mlq.add(values[5], 5);
22 mlq.add(values[6], 6);
23 mlq.add(values[1], 1);
24 u32 index = 0;
25 bool all_set = true;
26 for (auto& f : mlq) {
27 all_set &= (f == values[index]);
28 index++;
29 }
30 REQUIRE(all_set);
31 REQUIRE(!mlq.empty());
32 f32 v = 8.0;
33 mlq.add(v, 2);
34 v = -7.0;
35 mlq.add(v, 2, false);
36 REQUIRE(mlq.front(2) == -7.0);
37 mlq.yield(2);
38 REQUIRE(mlq.front(2) == values[2]);
39 REQUIRE(mlq.back(2) == -7.0);
40 REQUIRE(mlq.empty(8));
41 v = 10.0;
42 mlq.add(v, 8);
43 mlq.adjust(v, 8, 9);
44 REQUIRE(mlq.front(9) == v);
45 REQUIRE(mlq.empty(8));
46 REQUIRE(!mlq.empty(9));
47 mlq.adjust(values[0], 0, 9);
48 REQUIRE(mlq.highest_priority_set() == 1);
49 REQUIRE(mlq.lowest_priority_set() == 9);
50 mlq.remove(values[1], 1);
51 REQUIRE(mlq.highest_priority_set() == 2);
52 REQUIRE(mlq.empty(1));
53}
54
55} // namespace Common
diff --git a/src/tests/common/ring_buffer.cpp b/src/tests/common/ring_buffer.cpp
index c883c4d56..54def22da 100644
--- a/src/tests/common/ring_buffer.cpp
+++ b/src/tests/common/ring_buffer.cpp
@@ -20,60 +20,60 @@ TEST_CASE("RingBuffer: Basic Tests", "[common]") {
20 for (std::size_t i = 0; i < 4; i++) { 20 for (std::size_t i = 0; i < 4; i++) {
21 const char elem = static_cast<char>(i); 21 const char elem = static_cast<char>(i);
22 const std::size_t count = buf.Push(&elem, 1); 22 const std::size_t count = buf.Push(&elem, 1);
23 REQUIRE(count == 1); 23 REQUIRE(count == 1U);
24 } 24 }
25 25
26 REQUIRE(buf.Size() == 4); 26 REQUIRE(buf.Size() == 4U);
27 27
28 // Pushing values into a full ring buffer should fail. 28 // Pushing values into a full ring buffer should fail.
29 { 29 {
30 const char elem = static_cast<char>(42); 30 const char elem = static_cast<char>(42);
31 const std::size_t count = buf.Push(&elem, 1); 31 const std::size_t count = buf.Push(&elem, 1);
32 REQUIRE(count == 0); 32 REQUIRE(count == 0U);
33 } 33 }
34 34
35 REQUIRE(buf.Size() == 4); 35 REQUIRE(buf.Size() == 4U);
36 36
37 // Popping multiple values from a ring buffer with values should succeed. 37 // Popping multiple values from a ring buffer with values should succeed.
38 { 38 {
39 const std::vector<char> popped = buf.Pop(2); 39 const std::vector<char> popped = buf.Pop(2);
40 REQUIRE(popped.size() == 2); 40 REQUIRE(popped.size() == 2U);
41 REQUIRE(popped[0] == 0); 41 REQUIRE(popped[0] == 0);
42 REQUIRE(popped[1] == 1); 42 REQUIRE(popped[1] == 1);
43 } 43 }
44 44
45 REQUIRE(buf.Size() == 2); 45 REQUIRE(buf.Size() == 2U);
46 46
47 // Popping a single value from a ring buffer with values should succeed. 47 // Popping a single value from a ring buffer with values should succeed.
48 { 48 {
49 const std::vector<char> popped = buf.Pop(1); 49 const std::vector<char> popped = buf.Pop(1);
50 REQUIRE(popped.size() == 1); 50 REQUIRE(popped.size() == 1U);
51 REQUIRE(popped[0] == 2); 51 REQUIRE(popped[0] == 2);
52 } 52 }
53 53
54 REQUIRE(buf.Size() == 1); 54 REQUIRE(buf.Size() == 1U);
55 55
56 // Pushing more values than space available should partially suceed. 56 // Pushing more values than space available should partially suceed.
57 { 57 {
58 std::vector<char> to_push(6); 58 std::vector<char> to_push(6);
59 std::iota(to_push.begin(), to_push.end(), 88); 59 std::iota(to_push.begin(), to_push.end(), 88);
60 const std::size_t count = buf.Push(to_push); 60 const std::size_t count = buf.Push(to_push);
61 REQUIRE(count == 3); 61 REQUIRE(count == 3U);
62 } 62 }
63 63
64 REQUIRE(buf.Size() == 4); 64 REQUIRE(buf.Size() == 4U);
65 65
66 // Doing an unlimited pop should pop all values. 66 // Doing an unlimited pop should pop all values.
67 { 67 {
68 const std::vector<char> popped = buf.Pop(); 68 const std::vector<char> popped = buf.Pop();
69 REQUIRE(popped.size() == 4); 69 REQUIRE(popped.size() == 4U);
70 REQUIRE(popped[0] == 3); 70 REQUIRE(popped[0] == 3);
71 REQUIRE(popped[1] == 88); 71 REQUIRE(popped[1] == 88);
72 REQUIRE(popped[2] == 89); 72 REQUIRE(popped[2] == 89);
73 REQUIRE(popped[3] == 90); 73 REQUIRE(popped[3] == 90);
74 } 74 }
75 75
76 REQUIRE(buf.Size() == 0); 76 REQUIRE(buf.Size() == 0U);
77} 77}
78 78
79TEST_CASE("RingBuffer: Threaded Test", "[common]") { 79TEST_CASE("RingBuffer: Threaded Test", "[common]") {
@@ -93,7 +93,7 @@ TEST_CASE("RingBuffer: Threaded Test", "[common]") {
93 std::size_t i = 0; 93 std::size_t i = 0;
94 while (i < count) { 94 while (i < count) {
95 if (const std::size_t c = buf.Push(&value[0], 1); c > 0) { 95 if (const std::size_t c = buf.Push(&value[0], 1); c > 0) {
96 REQUIRE(c == 1); 96 REQUIRE(c == 1U);
97 i++; 97 i++;
98 next_value(value); 98 next_value(value);
99 } else { 99 } else {
@@ -108,7 +108,7 @@ TEST_CASE("RingBuffer: Threaded Test", "[common]") {
108 std::size_t i = 0; 108 std::size_t i = 0;
109 while (i < count) { 109 while (i < count) {
110 if (const std::vector<char> v = buf.Pop(1); v.size() > 0) { 110 if (const std::vector<char> v = buf.Pop(1); v.size() > 0) {
111 REQUIRE(v.size() == 2); 111 REQUIRE(v.size() == 2U);
112 REQUIRE(v[0] == value[0]); 112 REQUIRE(v[0] == value[0]);
113 REQUIRE(v[1] == value[1]); 113 REQUIRE(v[1] == value[1]);
114 i++; 114 i++;
@@ -123,7 +123,7 @@ TEST_CASE("RingBuffer: Threaded Test", "[common]") {
123 producer.join(); 123 producer.join();
124 consumer.join(); 124 consumer.join();
125 125
126 REQUIRE(buf.Size() == 0); 126 REQUIRE(buf.Size() == 0U);
127 printf("RingBuffer: Threaded Test: full: %zu, empty: %zu\n", full, empty); 127 printf("RingBuffer: Threaded Test: full: %zu, empty: %zu\n", full, empty);
128} 128}
129 129
diff --git a/src/tests/core/arm/arm_test_common.cpp b/src/tests/core/arm/arm_test_common.cpp
deleted file mode 100644
index e54674d11..000000000
--- a/src/tests/core/arm/arm_test_common.cpp
+++ /dev/null
@@ -1,145 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <algorithm>
6
7#include "common/page_table.h"
8#include "core/core.h"
9#include "core/hle/kernel/memory/page_table.h"
10#include "core/hle/kernel/process.h"
11#include "core/memory.h"
12#include "tests/core/arm/arm_test_common.h"
13
14namespace ArmTests {
15
16TestEnvironment::TestEnvironment(bool mutable_memory_)
17 : mutable_memory(mutable_memory_),
18 test_memory(std::make_shared<TestMemory>(this)), kernel{Core::System::GetInstance()} {
19 auto& system = Core::System::GetInstance();
20
21 auto process = Kernel::Process::Create(system, "", Kernel::Process::ProcessType::Userland);
22 page_table = &process->PageTable().PageTableImpl();
23
24 system.Memory().MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory);
25 system.Memory().MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory);
26
27 kernel.MakeCurrentProcess(process.get());
28}
29
30TestEnvironment::~TestEnvironment() {
31 auto& system = Core::System::GetInstance();
32 system.Memory().UnmapRegion(*page_table, 0x80000000, 0x80000000);
33 system.Memory().UnmapRegion(*page_table, 0x00000000, 0x80000000);
34}
35
36void TestEnvironment::SetMemory64(VAddr vaddr, u64 value) {
37 SetMemory32(vaddr + 0, static_cast<u32>(value));
38 SetMemory32(vaddr + 4, static_cast<u32>(value >> 32));
39}
40
41void TestEnvironment::SetMemory32(VAddr vaddr, u32 value) {
42 SetMemory16(vaddr + 0, static_cast<u16>(value));
43 SetMemory16(vaddr + 2, static_cast<u16>(value >> 16));
44}
45
46void TestEnvironment::SetMemory16(VAddr vaddr, u16 value) {
47 SetMemory8(vaddr + 0, static_cast<u8>(value));
48 SetMemory8(vaddr + 1, static_cast<u8>(value >> 8));
49}
50
51void TestEnvironment::SetMemory8(VAddr vaddr, u8 value) {
52 test_memory->data[vaddr] = value;
53}
54
55std::vector<WriteRecord> TestEnvironment::GetWriteRecords() const {
56 return write_records;
57}
58
59void TestEnvironment::ClearWriteRecords() {
60 write_records.clear();
61}
62
63TestEnvironment::TestMemory::~TestMemory() {}
64
65std::optional<bool> TestEnvironment::TestMemory::IsValidAddress(VAddr addr) {
66 return true;
67}
68
69std::optional<u8> TestEnvironment::TestMemory::Read8(VAddr addr) {
70 const auto iter = data.find(addr);
71
72 if (iter == data.end()) {
73 // Some arbitrary data
74 return static_cast<u8>(addr);
75 }
76
77 return iter->second;
78}
79
80std::optional<u16> TestEnvironment::TestMemory::Read16(VAddr addr) {
81 return *Read8(addr) | static_cast<u16>(*Read8(addr + 1)) << 8;
82}
83
84std::optional<u32> TestEnvironment::TestMemory::Read32(VAddr addr) {
85 return *Read16(addr) | static_cast<u32>(*Read16(addr + 2)) << 16;
86}
87
88std::optional<u64> TestEnvironment::TestMemory::Read64(VAddr addr) {
89 return *Read32(addr) | static_cast<u64>(*Read32(addr + 4)) << 32;
90}
91
92bool TestEnvironment::TestMemory::ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) {
93 VAddr addr = src_addr;
94 u8* data = static_cast<u8*>(dest_buffer);
95
96 for (std::size_t i = 0; i < size; i++, addr++, data++) {
97 *data = *Read8(addr);
98 }
99
100 return true;
101}
102
103bool TestEnvironment::TestMemory::Write8(VAddr addr, u8 data) {
104 env->write_records.emplace_back(8, addr, data);
105 if (env->mutable_memory)
106 env->SetMemory8(addr, data);
107 return true;
108}
109
110bool TestEnvironment::TestMemory::Write16(VAddr addr, u16 data) {
111 env->write_records.emplace_back(16, addr, data);
112 if (env->mutable_memory)
113 env->SetMemory16(addr, data);
114 return true;
115}
116
117bool TestEnvironment::TestMemory::Write32(VAddr addr, u32 data) {
118 env->write_records.emplace_back(32, addr, data);
119 if (env->mutable_memory)
120 env->SetMemory32(addr, data);
121 return true;
122}
123
124bool TestEnvironment::TestMemory::Write64(VAddr addr, u64 data) {
125 env->write_records.emplace_back(64, addr, data);
126 if (env->mutable_memory)
127 env->SetMemory64(addr, data);
128 return true;
129}
130
131bool TestEnvironment::TestMemory::WriteBlock(VAddr dest_addr, const void* src_buffer,
132 std::size_t size) {
133 VAddr addr = dest_addr;
134 const u8* data = static_cast<const u8*>(src_buffer);
135
136 for (std::size_t i = 0; i < size; i++, addr++, data++) {
137 env->write_records.emplace_back(8, addr, *data);
138 if (env->mutable_memory)
139 env->SetMemory8(addr, *data);
140 }
141
142 return true;
143}
144
145} // namespace ArmTests
diff --git a/src/tests/core/arm/arm_test_common.h b/src/tests/core/arm/arm_test_common.h
deleted file mode 100644
index d145dbfcc..000000000
--- a/src/tests/core/arm/arm_test_common.h
+++ /dev/null
@@ -1,93 +0,0 @@
1// Copyright 2016 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <tuple>
8#include <unordered_map>
9#include <vector>
10
11#include "common/common_types.h"
12#include "common/memory_hook.h"
13#include "core/hle/kernel/kernel.h"
14
15namespace Common {
16struct PageTable;
17}
18
19namespace ArmTests {
20
21struct WriteRecord {
22 WriteRecord(std::size_t size, VAddr addr, u64 data) : size(size), addr(addr), data(data) {}
23 std::size_t size;
24 VAddr addr;
25 u64 data;
26 bool operator==(const WriteRecord& o) const {
27 return std::tie(size, addr, data) == std::tie(o.size, o.addr, o.data);
28 }
29};
30
31class TestEnvironment final {
32public:
33 /*
34 * Inititalise test environment
35 * @param mutable_memory If false, writes to memory can never be read back.
36 * (Memory is immutable.)
37 */
38 explicit TestEnvironment(bool mutable_memory = false);
39
40 /// Shutdown test environment
41 ~TestEnvironment();
42
43 /// Sets value at memory location vaddr.
44 void SetMemory8(VAddr vaddr, u8 value);
45 void SetMemory16(VAddr vaddr, u16 value);
46 void SetMemory32(VAddr vaddr, u32 value);
47 void SetMemory64(VAddr vaddr, u64 value);
48
49 /**
50 * Whenever Memory::Write{8,16,32,64} is called within the test environment,
51 * a new write-record is made.
52 * @returns A vector of write records made since they were last cleared.
53 */
54 std::vector<WriteRecord> GetWriteRecords() const;
55
56 /// Empties the internal write-record store.
57 void ClearWriteRecords();
58
59private:
60 friend struct TestMemory;
61 struct TestMemory final : Common::MemoryHook {
62 explicit TestMemory(TestEnvironment* env_) : env(env_) {}
63 TestEnvironment* env;
64
65 ~TestMemory() override;
66
67 std::optional<bool> IsValidAddress(VAddr addr) override;
68
69 std::optional<u8> Read8(VAddr addr) override;
70 std::optional<u16> Read16(VAddr addr) override;
71 std::optional<u32> Read32(VAddr addr) override;
72 std::optional<u64> Read64(VAddr addr) override;
73
74 bool ReadBlock(VAddr src_addr, void* dest_buffer, std::size_t size) override;
75
76 bool Write8(VAddr addr, u8 data) override;
77 bool Write16(VAddr addr, u16 data) override;
78 bool Write32(VAddr addr, u32 data) override;
79 bool Write64(VAddr addr, u64 data) override;
80
81 bool WriteBlock(VAddr dest_addr, const void* src_buffer, std::size_t size) override;
82
83 std::unordered_map<VAddr, u8> data;
84 };
85
86 bool mutable_memory;
87 std::shared_ptr<TestMemory> test_memory;
88 std::vector<WriteRecord> write_records;
89 Common::PageTable* page_table = nullptr;
90 Kernel::KernelCore kernel;
91};
92
93} // namespace ArmTests