mirror of
https://github.com/RetroAchievements/RAIntegration.git
synced 2026-10-12 02:09:25 +00:00
853 lines
35 KiB
C++
853 lines
35 KiB
C++
#include "CppUnitTest.h"
|
|
|
|
#include "ui\viewmodels\PointerFinderViewModel.hh"
|
|
|
|
#include "ui\viewmodels\FileDialogViewModel.hh"
|
|
#include "ui\viewmodels\MessageBoxViewModel.hh"
|
|
|
|
#include "tests\RA_UnitTestHelpers.h"
|
|
|
|
#include "tests\devkit\context\mocks\MockConsoleContext.hh"
|
|
#include "tests\devkit\context\mocks\MockEmulatorMemoryContext.hh"
|
|
#include "tests\devkit\context\mocks\MockRcClient.hh"
|
|
#include "tests\devkit\services\mocks\MockConfiguration.hh"
|
|
#include "tests\devkit\services\mocks\MockFileSystem.hh"
|
|
|
|
#include "tests\mocks\MockClipboard.hh"
|
|
#include "tests\mocks\MockGameContext.hh"
|
|
#include "tests\mocks\MockDesktop.hh"
|
|
#include "tests\mocks\MockWindowManager.hh"
|
|
|
|
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
|
|
|
namespace ra {
|
|
namespace ui {
|
|
namespace viewmodels {
|
|
namespace tests {
|
|
|
|
TEST_CLASS(PointerFinderViewModel_Tests)
|
|
{
|
|
private:
|
|
class PointerFinderViewModelHarness : public PointerFinderViewModel
|
|
{
|
|
public:
|
|
ra::context::mocks::MockConsoleContext mockConsoleContext;
|
|
ra::context::mocks::MockEmulatorMemoryContext mockEmulatorMemoryContext;
|
|
ra::data::context::mocks::MockGameContext mockGameContext;
|
|
ra::services::mocks::MockConfiguration mockConfiguration;
|
|
ra::services::mocks::MockFileSystem mockFileSystem;
|
|
ra::ui::mocks::MockDesktop mockDesktop;
|
|
ra::ui::viewmodels::mocks::MockWindowManager mockWindowManager;
|
|
|
|
GSL_SUPPRESS_F6 PointerFinderViewModelHarness() : PointerFinderViewModel()
|
|
{
|
|
SetValue(ShowProgressDialogProperty, false);
|
|
}
|
|
|
|
~PointerFinderViewModelHarness()
|
|
{
|
|
}
|
|
|
|
PointerFinderViewModelHarness(const PointerFinderViewModelHarness&) noexcept = delete;
|
|
PointerFinderViewModelHarness& operator=(const PointerFinderViewModelHarness&) noexcept = delete;
|
|
PointerFinderViewModelHarness(PointerFinderViewModelHarness&&) noexcept = delete;
|
|
PointerFinderViewModelHarness& operator=(PointerFinderViewModelHarness&&) noexcept = delete;
|
|
|
|
template <size_t N>
|
|
void MockMemory(std::array<uint8_t, N>& pMemory)
|
|
{
|
|
mockEmulatorMemoryContext.MockMemory(pMemory);
|
|
mockConsoleContext.AddMemoryRegion(0, gsl::narrow_cast<ra::data::ByteAddress>(pMemory.size()),
|
|
ra::data::MemoryRegion::Type::SystemRAM);
|
|
}
|
|
|
|
void AssertRow(gsl::index nIndex, const std::wstring& sPointerAddress, const std::wstring& sOffset,
|
|
const std::wstring& sPointerValue1, const std::wstring& sPointerValue2,
|
|
const std::wstring& sPointerValue3, const std::wstring& sPointerValue4)
|
|
{
|
|
const auto* pPointer = PotentialPointers().GetItemAt(nIndex);
|
|
Assert::IsNotNull(pPointer);
|
|
Ensures(pPointer != nullptr);
|
|
Assert::AreEqual(sPointerAddress, pPointer->GetPointerAddress());
|
|
Assert::AreEqual(sOffset, pPointer->GetOffset());
|
|
Assert::AreEqual(sPointerValue1, pPointer->GetPointerValue1());
|
|
Assert::AreEqual(sPointerValue2, pPointer->GetPointerValue2());
|
|
Assert::AreEqual(sPointerValue3, pPointer->GetPointerValue3());
|
|
Assert::AreEqual(sPointerValue4, pPointer->GetPointerValue4());
|
|
}
|
|
|
|
using PointerFinderViewModel::AddPotentialPointer;
|
|
};
|
|
|
|
public:
|
|
TEST_METHOD(TestCaptureNoGame)
|
|
{
|
|
PointerFinderViewModelHarness vmPointerFinder;
|
|
|
|
bool bDialogSeen = false;
|
|
vmPointerFinder.mockDesktop.ExpectWindow<MessageBoxViewModel>([&bDialogSeen](MessageBoxViewModel& vmMessageBox) {
|
|
bDialogSeen = true;
|
|
|
|
Assert::AreEqual(std::wstring(L"No game loaded."), vmMessageBox.GetHeader());
|
|
Assert::AreEqual(std::wstring(L"Cannot capture memory without a loaded game."), vmMessageBox.GetMessage());
|
|
|
|
return DialogResult::OK;
|
|
});
|
|
|
|
for (auto& pState : vmPointerFinder.States())
|
|
{
|
|
bDialogSeen = false;
|
|
|
|
Assert::IsTrue(pState.CanCapture());
|
|
Assert::AreEqual(std::wstring(L""), pState.GetAddress());
|
|
Assert::AreEqual(std::wstring(L"Capture"), pState.GetCaptureButtonText());
|
|
|
|
pState.ToggleCapture();
|
|
|
|
Assert::IsTrue(bDialogSeen);
|
|
|
|
Assert::IsTrue(pState.CanCapture());
|
|
Assert::AreEqual(std::wstring(L""), pState.GetAddress());
|
|
Assert::AreEqual(std::wstring(L"Capture"), pState.GetCaptureButtonText());
|
|
}
|
|
}
|
|
|
|
TEST_METHOD(TestCaptureNoAddress)
|
|
{
|
|
PointerFinderViewModelHarness vmPointerFinder;
|
|
vmPointerFinder.mockGameContext.SetGameId(1U);
|
|
std::array<unsigned char, 256> pMemory{};
|
|
vmPointerFinder.MockMemory(pMemory);
|
|
|
|
bool bDialogSeen = false;
|
|
vmPointerFinder.mockDesktop.ExpectWindow<MessageBoxViewModel>([&bDialogSeen](MessageBoxViewModel& vmMessageBox) {
|
|
bDialogSeen = true;
|
|
|
|
Assert::AreEqual(std::wstring(L"Invalid address."), vmMessageBox.GetMessage());
|
|
|
|
return DialogResult::OK;
|
|
});
|
|
|
|
for (auto& pState : vmPointerFinder.States())
|
|
{
|
|
bDialogSeen = false;
|
|
|
|
Assert::IsTrue(pState.CanCapture());
|
|
Assert::AreEqual(std::wstring(L""), pState.GetAddress());
|
|
Assert::AreEqual(std::wstring(L"Capture"), pState.GetCaptureButtonText());
|
|
|
|
pState.ToggleCapture();
|
|
Assert::IsTrue(bDialogSeen);
|
|
Assert::IsTrue(pState.CanCapture());
|
|
|
|
bDialogSeen = false;
|
|
pState.SetAddress(L"banana");
|
|
Assert::AreEqual(std::wstring(L"banana"), pState.GetAddress());
|
|
|
|
pState.ToggleCapture();
|
|
Assert::IsTrue(bDialogSeen);
|
|
Assert::IsTrue(pState.CanCapture());
|
|
|
|
bDialogSeen = false;
|
|
pState.SetAddress(L"0xyz");
|
|
Assert::AreEqual(std::wstring(L"0xyz"), pState.GetAddress());
|
|
|
|
pState.ToggleCapture();
|
|
Assert::IsTrue(bDialogSeen);
|
|
Assert::IsTrue(pState.CanCapture());
|
|
|
|
bDialogSeen = false;
|
|
pState.SetAddress(L"0x00");
|
|
Assert::AreEqual(std::wstring(L"0x00"), pState.GetAddress());
|
|
|
|
pState.ToggleCapture();
|
|
Assert::IsFalse(bDialogSeen);
|
|
Assert::IsFalse(pState.CanCapture());
|
|
}
|
|
}
|
|
|
|
TEST_METHOD(TestCaptureAndRelease)
|
|
{
|
|
PointerFinderViewModelHarness vmPointerFinder;
|
|
vmPointerFinder.mockGameContext.SetGameId(1U);
|
|
vmPointerFinder.mockEmulatorMemoryContext.MockTotalMemorySizeChanged(0x10000);
|
|
|
|
for (auto& pState : vmPointerFinder.States())
|
|
{
|
|
pState.SetAddress(L"0x1234");
|
|
Assert::IsTrue(pState.Viewer().IsAddressFixed());
|
|
Assert::AreEqual({ 0x1234U }, pState.Viewer().GetAddress());
|
|
Assert::AreEqual({ 0x1230U }, pState.Viewer().GetFirstAddress());
|
|
|
|
Assert::IsTrue(pState.CanCapture());
|
|
Assert::AreEqual(std::wstring(L"0x1234"), pState.GetAddress());
|
|
Assert::AreEqual(std::wstring(L"Capture"), pState.GetCaptureButtonText());
|
|
|
|
pState.ToggleCapture();
|
|
|
|
Assert::IsFalse(vmPointerFinder.mockDesktop.WasDialogShown());
|
|
|
|
Assert::IsFalse(pState.CanCapture());
|
|
Assert::AreEqual(std::wstring(L"0x1234"), pState.GetAddress());
|
|
Assert::AreEqual(std::wstring(L"Release"), pState.GetCaptureButtonText());
|
|
|
|
pState.ToggleCapture();
|
|
|
|
Assert::IsFalse(vmPointerFinder.mockDesktop.WasDialogShown());
|
|
|
|
Assert::IsTrue(pState.CanCapture());
|
|
Assert::AreEqual(std::wstring(L"0x1234"), pState.GetAddress());
|
|
Assert::AreEqual(std::wstring(L"Capture"), pState.GetCaptureButtonText());
|
|
}
|
|
}
|
|
|
|
TEST_METHOD(TestFindNoCaptures)
|
|
{
|
|
PointerFinderViewModelHarness vmPointerFinder;
|
|
vmPointerFinder.mockGameContext.SetGameId(1U);
|
|
|
|
bool bDialogSeen = false;
|
|
vmPointerFinder.mockDesktop.ExpectWindow<MessageBoxViewModel>([&bDialogSeen](MessageBoxViewModel& vmMessageBox) {
|
|
bDialogSeen = true;
|
|
|
|
Assert::AreEqual(std::wstring(L"Cannot find."), vmMessageBox.GetHeader());
|
|
Assert::AreEqual(std::wstring(L"At least two unique addresses must be captured before potential pointers can be located."), vmMessageBox.GetMessage());
|
|
|
|
return DialogResult::OK;
|
|
});
|
|
|
|
vmPointerFinder.Find();
|
|
|
|
Assert::IsTrue(bDialogSeen);
|
|
Assert::AreEqual({ 0U }, vmPointerFinder.PotentialPointers().Count());
|
|
}
|
|
|
|
TEST_METHOD(TestFindOneCapture)
|
|
{
|
|
PointerFinderViewModelHarness vmPointerFinder;
|
|
vmPointerFinder.mockGameContext.SetGameId(1U);
|
|
std::array<unsigned char, 256> pMemory{};
|
|
vmPointerFinder.MockMemory(pMemory);
|
|
|
|
bool bDialogSeen = false;
|
|
vmPointerFinder.mockDesktop.ExpectWindow<MessageBoxViewModel>([&bDialogSeen](MessageBoxViewModel& vmMessageBox) {
|
|
bDialogSeen = true;
|
|
|
|
Assert::AreEqual(std::wstring(L"Cannot find."), vmMessageBox.GetHeader());
|
|
Assert::AreEqual(std::wstring(L"At least two unique addresses must be captured before potential pointers can be located."), vmMessageBox.GetMessage());
|
|
|
|
return DialogResult::OK;
|
|
});
|
|
|
|
vmPointerFinder.States().at(0).SetAddress(L"0x1234");
|
|
vmPointerFinder.States().at(0).ToggleCapture();
|
|
vmPointerFinder.Find();
|
|
|
|
Assert::IsTrue(bDialogSeen);
|
|
Assert::AreEqual({ 0U }, vmPointerFinder.PotentialPointers().Count());
|
|
}
|
|
|
|
TEST_METHOD(TestFindTwoCapturesSameAddress)
|
|
{
|
|
PointerFinderViewModelHarness vmPointerFinder;
|
|
vmPointerFinder.mockGameContext.SetGameId(1U);
|
|
std::array<unsigned char, 256> pMemory{};
|
|
vmPointerFinder.MockMemory(pMemory);
|
|
|
|
bool bDialogSeen = false;
|
|
vmPointerFinder.mockDesktop.ExpectWindow<MessageBoxViewModel>([&bDialogSeen](MessageBoxViewModel& vmMessageBox) {
|
|
bDialogSeen = true;
|
|
|
|
Assert::AreEqual(std::wstring(L"Cannot find."), vmMessageBox.GetHeader());
|
|
Assert::AreEqual(std::wstring(L"At least two unique addresses must be captured before potential pointers can be located."), vmMessageBox.GetMessage());
|
|
|
|
return DialogResult::OK;
|
|
});
|
|
|
|
vmPointerFinder.States().at(0).SetAddress(L"0x1234");
|
|
vmPointerFinder.States().at(0).ToggleCapture();
|
|
vmPointerFinder.States().at(1).SetAddress(L"0x1234");
|
|
vmPointerFinder.States().at(1).ToggleCapture();
|
|
vmPointerFinder.Find();
|
|
|
|
Assert::IsTrue(bDialogSeen);
|
|
Assert::AreEqual({ 0U }, vmPointerFinder.PotentialPointers().Count());
|
|
}
|
|
|
|
TEST_METHOD(TestFindOffsetZero)
|
|
{
|
|
PointerFinderViewModelHarness vmPointerFinder;
|
|
vmPointerFinder.mockGameContext.SetGameId(1U);
|
|
vmPointerFinder.SetSearchType(ra::services::SearchType::SixteenBitAligned);
|
|
|
|
std::array<unsigned char, 256> pMemory{};
|
|
pMemory.at(0x08) = 0x1c;
|
|
pMemory.at(0x1c) = 0x55;
|
|
pMemory.at(0x1d) = 0x46;
|
|
vmPointerFinder.MockMemory(pMemory);
|
|
|
|
vmPointerFinder.States().at(0).SetAddress(L"0x1c");
|
|
vmPointerFinder.States().at(0).ToggleCapture();
|
|
|
|
pMemory.at(0x08) = 0x34;
|
|
pMemory.at(0x34) = 0x55;
|
|
pMemory.at(0x35) = 0x46;
|
|
|
|
vmPointerFinder.States().at(1).SetAddress(L"0x34");
|
|
vmPointerFinder.States().at(1).ToggleCapture();
|
|
vmPointerFinder.Find();
|
|
|
|
Assert::IsFalse(vmPointerFinder.mockDesktop.WasDialogShown());
|
|
Assert::AreEqual({ 1U }, vmPointerFinder.PotentialPointers().Count());
|
|
vmPointerFinder.AssertRow(0, L"0x0008", L"+0x00", L"001c", L"0034", L"", L"");
|
|
Assert::AreEqual(std::wstring(L"1"), vmPointerFinder.GetResultCountText());
|
|
}
|
|
|
|
TEST_METHOD(TestFindOffsetPositive)
|
|
{
|
|
PointerFinderViewModelHarness vmPointerFinder;
|
|
vmPointerFinder.mockGameContext.SetGameId(1U);
|
|
vmPointerFinder.SetSearchType(ra::services::SearchType::SixteenBitAligned);
|
|
|
|
std::array<unsigned char, 256> pMemory{};
|
|
pMemory.at(0x08) = 0x1c;
|
|
pMemory.at(0x1c) = 0x55;
|
|
pMemory.at(0x1d) = 0x46;
|
|
vmPointerFinder.MockMemory(pMemory);
|
|
|
|
vmPointerFinder.States().at(0).SetAddress(L"0x20");
|
|
vmPointerFinder.States().at(0).ToggleCapture();
|
|
|
|
pMemory.at(0x08) = 0x34;
|
|
pMemory.at(0x34) = 0x55;
|
|
pMemory.at(0x35) = 0x46;
|
|
|
|
vmPointerFinder.States().at(1).SetAddress(L"0x38");
|
|
vmPointerFinder.States().at(1).ToggleCapture();
|
|
vmPointerFinder.Find();
|
|
|
|
Assert::IsFalse(vmPointerFinder.mockDesktop.WasDialogShown());
|
|
Assert::AreEqual({ 1U }, vmPointerFinder.PotentialPointers().Count());
|
|
vmPointerFinder.AssertRow(0, L"0x0008", L"+0x04", L"001c", L"0034", L"", L""); // 1c+04=>20, 34+04=>38
|
|
Assert::AreEqual(std::wstring(L"1"), vmPointerFinder.GetResultCountText());
|
|
}
|
|
|
|
TEST_METHOD(TestFindOffsetNegative)
|
|
{
|
|
PointerFinderViewModelHarness vmPointerFinder;
|
|
vmPointerFinder.mockGameContext.SetGameId(1U);
|
|
vmPointerFinder.SetSearchType(ra::services::SearchType::SixteenBitAligned);
|
|
|
|
std::array<unsigned char, 256> pMemory{};
|
|
pMemory.at(0x08) = 0x1c;
|
|
pMemory.at(0x1c) = 0x55;
|
|
pMemory.at(0x1d) = 0x46;
|
|
vmPointerFinder.MockMemory(pMemory);
|
|
|
|
vmPointerFinder.States().at(0).SetAddress(L"0x18");
|
|
vmPointerFinder.States().at(0).ToggleCapture();
|
|
|
|
pMemory.at(0x08) = 0x34;
|
|
pMemory.at(0x34) = 0x55;
|
|
pMemory.at(0x35) = 0x46;
|
|
|
|
vmPointerFinder.States().at(1).SetAddress(L"0x30");
|
|
vmPointerFinder.States().at(1).ToggleCapture();
|
|
vmPointerFinder.Find();
|
|
|
|
Assert::IsFalse(vmPointerFinder.mockDesktop.WasDialogShown());
|
|
Assert::AreEqual({ 1U }, vmPointerFinder.PotentialPointers().Count());
|
|
vmPointerFinder.AssertRow(0, L"0x0008", L"+0xFFFFFFFC", L"001c", L"0034", L"", L""); // 1c-04=>18, 34-04=>30
|
|
Assert::AreEqual(std::wstring(L"1"), vmPointerFinder.GetResultCountText());
|
|
}
|
|
|
|
TEST_METHOD(TestFindOffsetMultiplePointers)
|
|
{
|
|
PointerFinderViewModelHarness vmPointerFinder;
|
|
vmPointerFinder.mockGameContext.SetGameId(1U);
|
|
vmPointerFinder.SetSearchType(ra::services::SearchType::SixteenBitAligned);
|
|
|
|
std::array<unsigned char, 256> pMemory{};
|
|
pMemory.at(0x08) = 0x1c;
|
|
pMemory.at(0x1c) = 0x55;
|
|
pMemory.at(0x1d) = 0x46;
|
|
pMemory.at(0x70) = 0x1c;
|
|
pMemory.at(0x9c) = 0x20;
|
|
vmPointerFinder.MockMemory(pMemory);
|
|
|
|
vmPointerFinder.States().at(0).SetAddress(L"0x20");
|
|
vmPointerFinder.States().at(0).ToggleCapture();
|
|
|
|
pMemory.at(0x08) = 0x34;
|
|
pMemory.at(0x34) = 0x55;
|
|
pMemory.at(0x35) = 0x46;
|
|
pMemory.at(0x70) = 0x34;
|
|
pMemory.at(0x9c) = 0x38;
|
|
|
|
vmPointerFinder.States().at(1).SetAddress(L"0x38");
|
|
vmPointerFinder.States().at(1).ToggleCapture();
|
|
vmPointerFinder.Find();
|
|
|
|
Assert::IsFalse(vmPointerFinder.mockDesktop.WasDialogShown());
|
|
Assert::AreEqual({ 3U }, vmPointerFinder.PotentialPointers().Count());
|
|
vmPointerFinder.AssertRow(0, L"0x009c", L"+0x00", L"0020", L"0038", L"", L""); // 20+00=>20, 38+00=>38
|
|
vmPointerFinder.AssertRow(1, L"0x0008", L"+0x04", L"001c", L"0034", L"", L""); // 1c+04=>20, 34+04=>38
|
|
vmPointerFinder.AssertRow(2, L"0x0070", L"+0x04", L"001c", L"0034", L"", L""); // 1c+04=>20, 34+04=>38
|
|
Assert::AreEqual(std::wstring(L"3"), vmPointerFinder.GetResultCountText());
|
|
}
|
|
|
|
TEST_METHOD(TestFindOffsetMultipleStates)
|
|
{
|
|
PointerFinderViewModelHarness vmPointerFinder;
|
|
vmPointerFinder.mockGameContext.SetGameId(1U);
|
|
vmPointerFinder.SetSearchType(ra::services::SearchType::SixteenBitAligned);
|
|
|
|
std::array<unsigned char, 256> pMemory{};
|
|
pMemory.at(0x08) = 0x1c;
|
|
pMemory.at(0x70) = 0x1c;
|
|
pMemory.at(0x9c) = 0x20;
|
|
pMemory.at(0xa4) = 0x20;
|
|
vmPointerFinder.MockMemory(pMemory);
|
|
|
|
vmPointerFinder.States().at(0).SetAddress(L"0x20");
|
|
vmPointerFinder.States().at(0).ToggleCapture();
|
|
|
|
pMemory.at(0x70) = 0x20; // pointer at $70 not valid
|
|
vmPointerFinder.States().at(1).SetAddress(L"0x20");
|
|
vmPointerFinder.States().at(1).ToggleCapture();
|
|
|
|
pMemory.at(0x08) = 0x34; // all pointers valid
|
|
pMemory.at(0x70) = 0x34;
|
|
pMemory.at(0x9c) = 0x38;
|
|
pMemory.at(0xa4) = 0x38;
|
|
|
|
vmPointerFinder.States().at(2).SetAddress(L"0x38");
|
|
vmPointerFinder.States().at(2).ToggleCapture();
|
|
|
|
pMemory.at(0x9c) = 0x20; // pointer at $9c not valid
|
|
vmPointerFinder.States().at(3).SetAddress(L"0x38");
|
|
vmPointerFinder.States().at(3).ToggleCapture();
|
|
|
|
vmPointerFinder.Find();
|
|
Assert::IsFalse(vmPointerFinder.mockDesktop.WasDialogShown());
|
|
Assert::AreEqual({ 2U }, vmPointerFinder.PotentialPointers().Count());
|
|
vmPointerFinder.AssertRow(0, L"0x00a4", L"+0x00", L"0020", L"0020", L"0038", L"0038"); // 20+00=>20, 38+00=>38
|
|
vmPointerFinder.AssertRow(1, L"0x0008", L"+0x04", L"001c", L"001c", L"0034", L"0034"); // 1c+04=>20, 34+04=>38
|
|
Assert::AreEqual(std::wstring(L"2"), vmPointerFinder.GetResultCountText());
|
|
}
|
|
|
|
TEST_METHOD(TestFindOffsetNoMatches)
|
|
{
|
|
PointerFinderViewModelHarness vmPointerFinder;
|
|
vmPointerFinder.mockGameContext.SetGameId(1U);
|
|
vmPointerFinder.SetSearchType(ra::services::SearchType::SixteenBitAligned);
|
|
|
|
std::array<unsigned char, 256> pMemory{};
|
|
pMemory.at(0x08) = 0x1c;
|
|
vmPointerFinder.MockMemory(pMemory);
|
|
|
|
vmPointerFinder.States().at(0).SetAddress(L"0x18");
|
|
vmPointerFinder.States().at(0).ToggleCapture();
|
|
|
|
pMemory.at(0x08) = 0x38;
|
|
|
|
vmPointerFinder.States().at(1).SetAddress(L"0x30");
|
|
vmPointerFinder.States().at(1).ToggleCapture();
|
|
vmPointerFinder.Find();
|
|
|
|
Assert::IsFalse(vmPointerFinder.mockDesktop.WasDialogShown());
|
|
Assert::AreEqual({ 1U }, vmPointerFinder.PotentialPointers().Count());
|
|
vmPointerFinder.AssertRow(0, L"No pointers found.", L"", L"", L"", L"", L"");
|
|
Assert::AreEqual(std::wstring(L"0"), vmPointerFinder.GetResultCountText());
|
|
}
|
|
|
|
TEST_METHOD(TestFindOffsetNested)
|
|
{
|
|
PointerFinderViewModelHarness vmPointerFinder;
|
|
vmPointerFinder.mockGameContext.SetGameId(1U);
|
|
vmPointerFinder.SetSearchType(ra::services::SearchType::SixteenBitAligned);
|
|
|
|
// 0008 + 4 + 12
|
|
std::array<unsigned char, 256> pMemory{};
|
|
pMemory.at(0x08) = 0x1c; // $0008 = 001C + 4 => 0020
|
|
pMemory.at(0x20) = 0x44; // $0020 = 0044 + 12 => 0x50
|
|
pMemory.at(0x21) = 0x00;
|
|
pMemory.at(0x50) = 0x55; // $0050
|
|
pMemory.at(0x51) = 0x46;
|
|
vmPointerFinder.MockMemory(pMemory);
|
|
|
|
vmPointerFinder.States().at(0).SetAddress(L"0x50");
|
|
vmPointerFinder.States().at(0).ToggleCapture();
|
|
|
|
pMemory.at(0x08) = 0x34; // $0008 = 0034 + 4 => 0038
|
|
pMemory.at(0x38) = 0x68; // $0038 = 0068 + 12 => 0074
|
|
pMemory.at(0x39) = 0x00;
|
|
pMemory.at(0x74) = 0x55;
|
|
pMemory.at(0x75) = 0x46;
|
|
|
|
vmPointerFinder.States().at(1).SetAddress(L"0x74");
|
|
vmPointerFinder.States().at(1).ToggleCapture();
|
|
vmPointerFinder.Find();
|
|
|
|
Assert::IsFalse(vmPointerFinder.mockDesktop.WasDialogShown());
|
|
Assert::AreEqual({ 2U }, vmPointerFinder.PotentialPointers().Count());
|
|
vmPointerFinder.AssertRow(0, L"0x0008", L"+0x04", L"001c", L"0034", L"", L""); // 1c+04=>20, 34+04=>38
|
|
vmPointerFinder.AssertRow(1, L"", L"+0x0C", L"0044", L"0068", L"", L""); // 44+0C=>50, 68+0C=>74
|
|
Assert::AreEqual(std::wstring(L"1"), vmPointerFinder.GetResultCountText());
|
|
|
|
|
|
}
|
|
|
|
TEST_METHOD(TestBookmarkSelected)
|
|
{
|
|
PointerFinderViewModelHarness vmPointerFinder;
|
|
ra::context::mocks::MockRcClient mockRcClient;
|
|
vmPointerFinder.mockGameContext.SetGameId(1U);
|
|
vmPointerFinder.SetSearchType(ra::services::SearchType::SixteenBitAligned);
|
|
|
|
// no results - bookmarks window will still be shown
|
|
vmPointerFinder.BookmarkSelected();
|
|
Assert::IsTrue(vmPointerFinder.mockWindowManager.MemoryBookmarks.IsVisible());
|
|
vmPointerFinder.mockDesktop.ResetExpectedWindows();
|
|
|
|
const auto& pBookmarks = vmPointerFinder.mockWindowManager.MemoryBookmarks.Bookmarks();
|
|
Assert::AreEqual({ 0U }, pBookmarks.Items().Count());
|
|
|
|
// initialize results
|
|
ra::services::PointerFinder::PotentialPointer pPointer;
|
|
pPointer.nRootAddress = 0x009c;
|
|
pPointer.vOffsets.at(0) = 0;
|
|
pPointer.nOffsetLength = 1;
|
|
vmPointerFinder.AddPotentialPointer(pPointer, ra::data::Memory::Size::SixteenBit);
|
|
|
|
pPointer.nRootAddress = 0x0008;
|
|
pPointer.vOffsets.at(0) = 4;
|
|
pPointer.nOffsetLength = 1;
|
|
vmPointerFinder.AddPotentialPointer(pPointer, ra::data::Memory::Size::SixteenBit);
|
|
|
|
pPointer.nRootAddress = 0x0020;
|
|
pPointer.vOffsets.at(0) = 8;
|
|
pPointer.vOffsets.at(1) = 0;
|
|
pPointer.vOffsets.at(2) = 4;
|
|
pPointer.nOffsetLength = 3;
|
|
vmPointerFinder.AddPotentialPointer(pPointer, ra::data::Memory::Size::SixteenBit);
|
|
|
|
pPointer.nRootAddress = 0x0070;
|
|
pPointer.vOffsets.at(0) = 4;
|
|
pPointer.nOffsetLength = 1;
|
|
vmPointerFinder.AddPotentialPointer(pPointer, ra::data::Memory::Size::SixteenBit);
|
|
|
|
// no selection
|
|
vmPointerFinder.BookmarkSelected();
|
|
Assert::AreEqual({ 0U }, pBookmarks.Items().Count());
|
|
|
|
// selection
|
|
vmPointerFinder.PotentialPointers().GetItemAt(1)->SetSelected(true);
|
|
vmPointerFinder.BookmarkSelected();
|
|
Assert::AreEqual({ 1U }, pBookmarks.Items().Count());
|
|
Assert::AreEqual(std::string("I:0x 0008_M:0x 0004"), pBookmarks.Items().GetItemAt(0)->GetIndirectAddress());
|
|
vmPointerFinder.PotentialPointers().GetItemAt(1)->SetSelected(false);
|
|
|
|
// first part of chain
|
|
vmPointerFinder.PotentialPointers().GetItemAt(2)->SetSelected(true);
|
|
vmPointerFinder.BookmarkSelected();
|
|
Assert::AreEqual({ 2U }, pBookmarks.Items().Count());
|
|
Assert::AreEqual(std::string("I:0x 0020_I:0x 0008_I:0x 0000_M:0x 0004"), pBookmarks.Items().GetItemAt(1)->GetIndirectAddress());
|
|
vmPointerFinder.PotentialPointers().GetItemAt(2)->SetSelected(false);
|
|
|
|
// middle part of chain
|
|
vmPointerFinder.PotentialPointers().GetItemAt(3)->SetSelected(true);
|
|
vmPointerFinder.BookmarkSelected();
|
|
Assert::AreEqual({ 3U }, pBookmarks.Items().Count());
|
|
Assert::AreEqual(std::string("I:0x 0020_I:0x 0008_I:0x 0000_M:0x 0004"), pBookmarks.Items().GetItemAt(2)->GetIndirectAddress());
|
|
vmPointerFinder.PotentialPointers().GetItemAt(3)->SetSelected(false);
|
|
|
|
// end part of chain
|
|
vmPointerFinder.PotentialPointers().GetItemAt(4)->SetSelected(true);
|
|
vmPointerFinder.BookmarkSelected();
|
|
Assert::AreEqual({ 4U }, pBookmarks.Items().Count());
|
|
Assert::AreEqual(std::string("I:0x 0020_I:0x 0008_I:0x 0000_M:0x 0004"), pBookmarks.Items().GetItemAt(3)->GetIndirectAddress());
|
|
|
|
// entire chain
|
|
vmPointerFinder.PotentialPointers().GetItemAt(3)->SetSelected(false);
|
|
vmPointerFinder.PotentialPointers().GetItemAt(2)->SetSelected(false);
|
|
vmPointerFinder.BookmarkSelected();
|
|
Assert::AreEqual({ 5U }, pBookmarks.Items().Count());
|
|
Assert::AreEqual(std::string("I:0x 0020_I:0x 0008_I:0x 0000_M:0x 0004"), pBookmarks.Items().GetItemAt(4)->GetIndirectAddress());
|
|
}
|
|
|
|
TEST_METHOD(TestCopySelectedToClipboard)
|
|
{
|
|
PointerFinderViewModelHarness vmPointerFinder;
|
|
ra::services::mocks::MockClipboard mockClipboard;
|
|
vmPointerFinder.mockGameContext.SetGameId(1U);
|
|
vmPointerFinder.SetSearchType(ra::services::SearchType::SixteenBitAligned);
|
|
|
|
// no results - nothing copied, no dialog shown
|
|
vmPointerFinder.CopySelectedToClipboard();
|
|
Assert::AreEqual(std::wstring(), mockClipboard.GetText());
|
|
Assert::IsFalse(vmPointerFinder.mockDesktop.WasDialogShown());
|
|
vmPointerFinder.mockDesktop.ResetExpectedWindows();
|
|
|
|
// initialize results
|
|
ra::services::PointerFinder::PotentialPointer pPointer;
|
|
pPointer.nRootAddress = 0x009c;
|
|
pPointer.vOffsets.at(0) = 0;
|
|
pPointer.nOffsetLength = 1;
|
|
vmPointerFinder.AddPotentialPointer(pPointer, ra::data::Memory::Size::SixteenBit);
|
|
|
|
pPointer.nRootAddress = 0x0008;
|
|
pPointer.vOffsets.at(0) = 4;
|
|
pPointer.nOffsetLength = 1;
|
|
vmPointerFinder.AddPotentialPointer(pPointer, ra::data::Memory::Size::SixteenBit);
|
|
|
|
pPointer.nRootAddress = 0x0020;
|
|
pPointer.vOffsets.at(0) = 8;
|
|
pPointer.vOffsets.at(1) = 0;
|
|
pPointer.vOffsets.at(2) = 4;
|
|
pPointer.nOffsetLength = 3;
|
|
vmPointerFinder.AddPotentialPointer(pPointer, ra::data::Memory::Size::SixteenBit);
|
|
|
|
pPointer.nRootAddress = 0x0070;
|
|
pPointer.vOffsets.at(0) = 4;
|
|
pPointer.nOffsetLength = 1;
|
|
vmPointerFinder.AddPotentialPointer(pPointer, ra::data::Memory::Size::SixteenBit);
|
|
|
|
// no selection
|
|
vmPointerFinder.CopySelectedToClipboard();
|
|
Assert::AreEqual(std::wstring(), mockClipboard.GetText());
|
|
Assert::IsFalse(vmPointerFinder.mockDesktop.WasDialogShown());
|
|
vmPointerFinder.mockDesktop.ResetExpectedWindows();
|
|
|
|
// selection
|
|
vmPointerFinder.PotentialPointers().GetItemAt(1)->SetSelected(true);
|
|
vmPointerFinder.CopySelectedToClipboard();
|
|
Assert::AreEqual(std::wstring(L"I:0x 0008_M:0x 0004"), mockClipboard.GetText());
|
|
Assert::IsFalse(vmPointerFinder.mockDesktop.WasDialogShown());
|
|
vmPointerFinder.mockDesktop.ResetExpectedWindows();
|
|
vmPointerFinder.PotentialPointers().GetItemAt(1)->SetSelected(false);
|
|
|
|
// first part of chain
|
|
vmPointerFinder.PotentialPointers().GetItemAt(2)->SetSelected(true);
|
|
vmPointerFinder.CopySelectedToClipboard();
|
|
Assert::AreEqual(std::wstring(L"I:0x 0020_I:0x 0008_I:0x 0000_M:0x 0004"), mockClipboard.GetText());
|
|
Assert::IsFalse(vmPointerFinder.mockDesktop.WasDialogShown());
|
|
vmPointerFinder.mockDesktop.ResetExpectedWindows();
|
|
vmPointerFinder.PotentialPointers().GetItemAt(2)->SetSelected(false);
|
|
mockClipboard.SetText(L"");
|
|
|
|
// middle part of chain
|
|
vmPointerFinder.PotentialPointers().GetItemAt(3)->SetSelected(true);
|
|
vmPointerFinder.CopySelectedToClipboard();
|
|
Assert::AreEqual(std::wstring(L"I:0x 0020_I:0x 0008_I:0x 0000_M:0x 0004"), mockClipboard.GetText());
|
|
Assert::IsFalse(vmPointerFinder.mockDesktop.WasDialogShown());
|
|
vmPointerFinder.mockDesktop.ResetExpectedWindows();
|
|
vmPointerFinder.PotentialPointers().GetItemAt(3)->SetSelected(false);
|
|
mockClipboard.SetText(L"");
|
|
|
|
// end part of chain
|
|
vmPointerFinder.PotentialPointers().GetItemAt(4)->SetSelected(true);
|
|
vmPointerFinder.CopySelectedToClipboard();
|
|
Assert::AreEqual(std::wstring(L"I:0x 0020_I:0x 0008_I:0x 0000_M:0x 0004"), mockClipboard.GetText());
|
|
Assert::IsFalse(vmPointerFinder.mockDesktop.WasDialogShown());
|
|
vmPointerFinder.mockDesktop.ResetExpectedWindows();
|
|
mockClipboard.SetText(L"");
|
|
|
|
// entire chain
|
|
vmPointerFinder.PotentialPointers().GetItemAt(3)->SetSelected(false);
|
|
vmPointerFinder.PotentialPointers().GetItemAt(2)->SetSelected(false);
|
|
vmPointerFinder.CopySelectedToClipboard();
|
|
Assert::AreEqual(std::wstring(L"I:0x 0020_I:0x 0008_I:0x 0000_M:0x 0004"), mockClipboard.GetText());
|
|
Assert::IsFalse(vmPointerFinder.mockDesktop.WasDialogShown());
|
|
vmPointerFinder.mockDesktop.ResetExpectedWindows();
|
|
}
|
|
|
|
TEST_METHOD(TestCopySelectedToClipboardMultipleSelections)
|
|
{
|
|
PointerFinderViewModelHarness vmPointerFinder;
|
|
ra::services::mocks::MockClipboard mockClipboard;
|
|
vmPointerFinder.mockGameContext.SetGameId(1U);
|
|
vmPointerFinder.SetSearchType(ra::services::SearchType::SixteenBitAligned);
|
|
|
|
// initialize results
|
|
ra::services::PointerFinder::PotentialPointer pPointer;
|
|
pPointer.nRootAddress = 0x009c;
|
|
pPointer.vOffsets.at(0) = 0;
|
|
pPointer.nOffsetLength = 1;
|
|
vmPointerFinder.AddPotentialPointer(pPointer, ra::data::Memory::Size::SixteenBit);
|
|
|
|
pPointer.nRootAddress = 0x0008;
|
|
pPointer.vOffsets.at(0) = 4;
|
|
pPointer.nOffsetLength = 1;
|
|
vmPointerFinder.AddPotentialPointer(pPointer, ra::data::Memory::Size::SixteenBit);
|
|
|
|
pPointer.nRootAddress = 0x0020;
|
|
pPointer.vOffsets.at(0) = 8;
|
|
pPointer.vOffsets.at(1) = 0;
|
|
pPointer.vOffsets.at(2) = 4;
|
|
pPointer.nOffsetLength = 3;
|
|
vmPointerFinder.AddPotentialPointer(pPointer, ra::data::Memory::Size::SixteenBit);
|
|
|
|
pPointer.nRootAddress = 0x0070;
|
|
pPointer.vOffsets.at(0) = 4;
|
|
pPointer.nOffsetLength = 1;
|
|
vmPointerFinder.AddPotentialPointer(pPointer, ra::data::Memory::Size::SixteenBit);
|
|
|
|
// selection
|
|
vmPointerFinder.PotentialPointers().GetItemAt(1)->SetSelected(true);
|
|
vmPointerFinder.PotentialPointers().GetItemAt(4)->SetSelected(true);
|
|
|
|
bool bDialogSeen = false;
|
|
vmPointerFinder.mockDesktop.ExpectWindow<ra::ui::viewmodels::MessageBoxViewModel>(
|
|
[&bDialogSeen](const ra::ui::viewmodels::MessageBoxViewModel& vmMessageBox) {
|
|
Assert::AreEqual(std::wstring(L"Multiple items selected"), vmMessageBox.GetHeader());
|
|
Assert::AreEqual(std::wstring(L"Only one item can be copied at a time."), vmMessageBox.GetMessage());
|
|
|
|
bDialogSeen = true;
|
|
return ra::ui::DialogResult::OK;
|
|
}
|
|
);
|
|
vmPointerFinder.CopySelectedToClipboard();
|
|
Assert::AreEqual(std::wstring(L""), mockClipboard.GetText());
|
|
Assert::IsTrue(bDialogSeen);
|
|
}
|
|
|
|
TEST_METHOD(TestExportResults)
|
|
{
|
|
PointerFinderViewModelHarness vmPointerFinder;
|
|
vmPointerFinder.mockGameContext.SetGameId(3U);
|
|
vmPointerFinder.SetSearchType(ra::services::SearchType::SixteenBitAligned);
|
|
|
|
// initialize results
|
|
std::array<unsigned char, 256> pMemory{};
|
|
pMemory.at(0x08) = 0x1c;
|
|
pMemory.at(0x70) = 0x1c;
|
|
pMemory.at(0x9c) = 0x20;
|
|
vmPointerFinder.MockMemory(pMemory);
|
|
|
|
vmPointerFinder.States().at(0).SetAddress(L"0x20");
|
|
vmPointerFinder.States().at(0).ToggleCapture();
|
|
|
|
pMemory.at(0x08) = 0x34;
|
|
pMemory.at(0x70) = 0x34;
|
|
pMemory.at(0x9c) = 0x38;
|
|
|
|
vmPointerFinder.States().at(1).SetAddress(L"0x38");
|
|
vmPointerFinder.States().at(1).ToggleCapture();
|
|
vmPointerFinder.Find();
|
|
|
|
Assert::IsFalse(vmPointerFinder.mockDesktop.WasDialogShown());
|
|
Assert::AreEqual({ 3U }, vmPointerFinder.PotentialPointers().Count());
|
|
vmPointerFinder.AssertRow(0, L"0x009c", L"+0x00", L"0020", L"0038", L"", L""); // 20+00=>20, 38+00=>38
|
|
vmPointerFinder.AssertRow(1, L"0x0008", L"+0x04", L"001c", L"0034", L"", L""); // 1c+04=>20, 34+04=>38
|
|
vmPointerFinder.AssertRow(2, L"0x0070", L"+0x04", L"001c", L"0034", L"", L""); // 1c+04=>20, 34+04=>38
|
|
|
|
bool bDialogSeen = false;
|
|
vmPointerFinder.mockDesktop.ExpectWindow<ra::ui::viewmodels::FileDialogViewModel>(
|
|
[&bDialogSeen](ra::ui::viewmodels::FileDialogViewModel& vmFileDialog) {
|
|
bDialogSeen = true;
|
|
|
|
Assert::AreEqual(std::wstring(L"Export Pointer Results"), vmFileDialog.GetWindowTitle());
|
|
Assert::AreEqual({1U}, vmFileDialog.GetFileTypes().size());
|
|
Assert::AreEqual(std::wstring(L"csv"), vmFileDialog.GetDefaultExtension());
|
|
Assert::AreEqual(std::wstring(L"3-Pointers.csv"), vmFileDialog.GetFileName());
|
|
|
|
vmFileDialog.SetFileName(L"E:\\Data\\3-Pointers.csv");
|
|
|
|
return DialogResult::OK;
|
|
});
|
|
|
|
vmPointerFinder.ExportResults();
|
|
|
|
Assert::IsTrue(bDialogSeen);
|
|
const std::string& sContents = vmPointerFinder.mockFileSystem.GetFileContents(L"E:\\Data\\3-Pointers.csv");
|
|
Assert::AreEqual(std::string("Address,Offset,State1,State2\n0x009c,+0x00,0020,0038\n0x0008,+0x04,001c,0034\n0x0070,+0x04,001c,0034\n"),
|
|
sContents);
|
|
}
|
|
|
|
TEST_METHOD(TestExportResultsCancel)
|
|
{
|
|
PointerFinderViewModelHarness vmPointerFinder;
|
|
vmPointerFinder.mockGameContext.SetGameId(3U);
|
|
vmPointerFinder.SetSearchType(ra::services::SearchType::SixteenBitAligned);
|
|
|
|
// initialize results
|
|
std::array<unsigned char, 256> pMemory{};
|
|
pMemory.at(0x08) = 0x1c;
|
|
pMemory.at(0x70) = 0x1c;
|
|
pMemory.at(0x9c) = 0x20;
|
|
vmPointerFinder.MockMemory(pMemory);
|
|
|
|
vmPointerFinder.States().at(0).SetAddress(L"0x20");
|
|
vmPointerFinder.States().at(0).ToggleCapture();
|
|
|
|
pMemory.at(0x08) = 0x34;
|
|
pMemory.at(0x70) = 0x34;
|
|
pMemory.at(0x9c) = 0x38;
|
|
|
|
vmPointerFinder.States().at(1).SetAddress(L"0x38");
|
|
vmPointerFinder.States().at(1).ToggleCapture();
|
|
vmPointerFinder.Find();
|
|
|
|
Assert::IsFalse(vmPointerFinder.mockDesktop.WasDialogShown());
|
|
Assert::AreEqual({ 3U }, vmPointerFinder.PotentialPointers().Count());
|
|
vmPointerFinder.AssertRow(0, L"0x009c", L"+0x00", L"0020", L"0038", L"", L""); // 20+00=>20, 38+00=>38
|
|
vmPointerFinder.AssertRow(1, L"0x0008", L"+0x04", L"001c", L"0034", L"", L""); // 1c+04=>20, 34+04=>38
|
|
vmPointerFinder.AssertRow(2, L"0x0070", L"+0x04", L"001c", L"0034", L"", L""); // 1c+04=>20, 34+04=>38
|
|
|
|
bool bDialogSeen = false;
|
|
vmPointerFinder.mockDesktop.ExpectWindow<ra::ui::viewmodels::FileDialogViewModel>(
|
|
[&bDialogSeen](ra::ui::viewmodels::FileDialogViewModel& vmFileDialog) {
|
|
bDialogSeen = true;
|
|
|
|
Assert::AreEqual(std::wstring(L"Export Pointer Results"), vmFileDialog.GetWindowTitle());
|
|
Assert::AreEqual({1U}, vmFileDialog.GetFileTypes().size());
|
|
Assert::AreEqual(std::wstring(L"csv"), vmFileDialog.GetDefaultExtension());
|
|
Assert::AreEqual(std::wstring(L"3-Pointers.csv"), vmFileDialog.GetFileName());
|
|
|
|
vmFileDialog.SetFileName(L"E:\\Data\\3-Pointers.csv");
|
|
|
|
return DialogResult::Cancel;
|
|
});
|
|
|
|
vmPointerFinder.ExportResults();
|
|
|
|
Assert::IsTrue(bDialogSeen);
|
|
const std::string& sContents = vmPointerFinder.mockFileSystem.GetFileContents(L"E:\\Data\\3-Pointers.csv");
|
|
Assert::AreEqual(std::string(), sContents);
|
|
}
|
|
|
|
TEST_METHOD(TestExportResultsNone)
|
|
{
|
|
PointerFinderViewModelHarness vmPointerFinder;
|
|
vmPointerFinder.mockGameContext.SetGameId(3U);
|
|
vmPointerFinder.SetSearchType(ra::services::SearchType::SixteenBitAligned);
|
|
|
|
bool bMessageSeen = false;
|
|
vmPointerFinder.mockDesktop.ExpectWindow<ra::ui::viewmodels::MessageBoxViewModel>(
|
|
[&bMessageSeen](ra::ui::viewmodels::MessageBoxViewModel& vmMessageBox) {
|
|
bMessageSeen = true;
|
|
Assert::AreEqual(std::wstring(L"Nothing to export"), vmMessageBox.GetMessage());
|
|
return ra::ui::DialogResult::OK;
|
|
});
|
|
|
|
bool bDialogSeen = false;
|
|
vmPointerFinder.mockDesktop.ExpectWindow<ra::ui::viewmodels::FileDialogViewModel>(
|
|
[&bDialogSeen](ra::ui::viewmodels::FileDialogViewModel&) {
|
|
bDialogSeen = true;
|
|
return DialogResult::Cancel;
|
|
});
|
|
|
|
// search not started
|
|
vmPointerFinder.ExportResults();
|
|
|
|
Assert::IsTrue(bMessageSeen);
|
|
Assert::IsFalse(bDialogSeen);
|
|
}
|
|
};
|
|
|
|
} // namespace tests
|
|
} // namespace viewmodels
|
|
} // namespace ui
|
|
} // namespace ra
|