aboutsummaryrefslogtreecommitdiff
path: root/src/tests/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/tests/core')
-rw-r--r--src/tests/core/core_timing.cpp3
-rw-r--r--src/tests/core/nup_writer.cpp5
-rw-r--r--src/tests/core/priority_queue.cpp111
3 files changed, 118 insertions, 1 deletions
diff --git a/src/tests/core/core_timing.cpp b/src/tests/core/core_timing.cpp
index 81898a1d38..6b424cc52c 100644
--- a/src/tests/core/core_timing.cpp
+++ b/src/tests/core/core_timing.cpp
@@ -33,6 +33,9 @@ std::optional<std::chrono::nanoseconds> HostCallbackTemplate(s64 time,
struct ScopeInit final {
ScopeInit() {
+ callbacks_ran_flags.reset();
+ delays.fill(0);
+ expected_callback = 0;
core_timing.SetMulticore(true);
core_timing.Initialize([]() {});
}
diff --git a/src/tests/core/nup_writer.cpp b/src/tests/core/nup_writer.cpp
index 48e14daaef..3167a28baf 100644
--- a/src/tests/core/nup_writer.cpp
+++ b/src/tests/core/nup_writer.cpp
@@ -215,9 +215,11 @@ TEST_CASE("NUP packs base, updates and add-ons and reads back through NupContain
REQUIRE(packages[0].kind == NupContainer::PackageKind::Base);
REQUIRE(packages[0].title_id == TitleId);
REQUIRE(packages[0].version == 0);
+ REQUIRE(packages[0].display_version == "1.0.0");
REQUIRE(packages[0].npdm.size() == 0x100);
REQUIRE(packages[1].kind == NupContainer::PackageKind::Update);
REQUIRE(packages[1].version == 65536);
+ REQUIRE(packages[1].display_version == "1.1.0");
REQUIRE(packages[1].title_id == TitleId);
REQUIRE_FALSE(packages[1].standalone_update);
REQUIRE(packages[2].kind == NupContainer::PackageKind::Update);
@@ -502,7 +504,8 @@ TEST_CASE("NUP output is reproducible", "[nup]") {
for (const u8 b : Sha256(ReadAll(archive))) {
hex += fmt::format("{:02x}", b);
}
- REQUIRE(hex == "df8446903ab2c39a51af0304935eb4aa5d8ead105440976ceae7ab97133f6143");
+ // The mixed-case Base/RomFS directory supplies base version 1.0.0 on every platform.
+ REQUIRE(hex == "718231e0974ca04c7be7bd6ed4334015b777c6e5f1ed51de23f899f81ee004ab");
}
TEST_CASE("NUP writes metadata overrides to the base and the newest update", "[nup]") {
diff --git a/src/tests/core/priority_queue.cpp b/src/tests/core/priority_queue.cpp
new file mode 100644
index 0000000000..0d7174f793
--- /dev/null
+++ b/src/tests/core/priority_queue.cpp
@@ -0,0 +1,111 @@
+// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include <algorithm>
+#include <array>
+#include <random>
+#include <vector>
+#include <catch2/catch_test_macros.hpp>
+#include "core/hle/kernel/k_priority_queue.h"
+
+namespace {
+struct Affinity {
+ u64 GetAffinityMask() const {
+ return 3;
+ }
+ void SetAffinityMask(u64) {}
+ bool GetAffinity(s32) const {
+ return true;
+ }
+ void SetAffinity(s32, bool) {}
+ void SetAll() {}
+};
+
+struct Member {
+ struct QueueEntry {
+ Member* prev{};
+ Member* next{};
+ void Initialize() {
+ prev = next = nullptr;
+ }
+ void SetPrev(Member* value) {
+ prev = value;
+ }
+ void SetNext(Member* value) {
+ next = value;
+ }
+ Member* GetNext() const {
+ return next;
+ }
+ Member* GetPrev() const {
+ return prev;
+ }
+ };
+ std::array<QueueEntry, 2> entries{};
+ s32 priority{};
+ QueueEntry& GetPriorityQueueEntry(s32 core) {
+ return entries[core];
+ }
+ const QueueEntry& GetPriorityQueueEntry(s32 core) const {
+ return entries[core];
+ }
+ Affinity GetAffinityMask() const {
+ return {};
+ }
+ s32 GetActiveCore() const {
+ return 0;
+ }
+ s32 GetPriority() const {
+ return priority;
+ }
+ bool IsDummyThread() const {
+ return false;
+ }
+};
+
+template <size_t Priorities>
+void CheckQueue() {
+ using Queue = Kernel::KPriorityQueue<Member, 2, Priorities - 1, 0>;
+ typename Queue::KPriorityQueueImpl queue;
+ std::array<Member, 160> members{};
+ std::array<std::array<bool, 2>, 160> present{};
+ std::array<std::array<std::vector<Member*>, Priorities>, 2> model{};
+ std::mt19937 random{6152};
+ for (size_t i = 0; i < members.size(); ++i) {
+ members[i].priority = static_cast<s32>(i % Priorities);
+ }
+ REQUIRE(queue.GetFront(0) == nullptr);
+ for (u32 operation = 0; operation < 3000; ++operation) {
+ const size_t index = random() % members.size();
+ const s32 core = random() % 2;
+ auto& member = members[index];
+ auto& expected = model[core][member.priority];
+ if (present[index][core]) {
+ queue.Remove(member.priority, core, &member);
+ std::erase(expected, &member);
+ } else if ((random() & 1) != 0) {
+ queue.PushFront(member.priority, core, &member);
+ expected.insert(expected.begin(), &member);
+ } else {
+ queue.PushBack(member.priority, core, &member);
+ expected.push_back(&member);
+ }
+ present[index][core] = !present[index][core];
+ for (s32 checked_core = 0; checked_core < 2; ++checked_core) {
+ Member* actual = queue.GetFront(checked_core);
+ for (const auto& priority : model[checked_core]) {
+ for (Member* wanted : priority) {
+ REQUIRE(actual == wanted);
+ actual = queue.GetNext(checked_core, actual);
+ }
+ }
+ REQUIRE(actual == nullptr);
+ }
+ }
+}
+} // namespace
+
+TEST_CASE("Priority queue bitmap traversal preserves thread order", "[core]") {
+ CheckQueue<64>();
+ CheckQueue<128>();
+}