diff --git a/src/RA_Integration.vcxproj b/src/RA_Integration.vcxproj index e409f6c9..4745629e 100644 --- a/src/RA_Integration.vcxproj +++ b/src/RA_Integration.vcxproj @@ -80,8 +80,6 @@ - - Create @@ -213,8 +211,6 @@ - - diff --git a/src/RA_Integration.vcxproj.filters b/src/RA_Integration.vcxproj.filters index aeeb4943..42217004 100644 --- a/src/RA_Integration.vcxproj.filters +++ b/src/RA_Integration.vcxproj.filters @@ -46,9 +46,6 @@ {d29ae560-83b6-496b-b1ba-bc0b0c5978af} - - {c9c038f9-c4bb-436c-8416-12f91df44904} - {e978c08c-fedb-4ead-af63-0420b26291bb} @@ -315,9 +312,6 @@ Data\Context - - Data\Models - Data\Context @@ -333,9 +327,6 @@ UI\ViewModels - - Data\Models - UI\ViewModels @@ -806,9 +797,6 @@ Data\Context - - Data\Models - Data\Context @@ -830,9 +818,6 @@ UI\ViewModels - - Data\Models - UI\ViewModels diff --git a/src/data/context/GameContext.hh b/src/data/context/GameContext.hh index 4ecf4050..745e270c 100644 --- a/src/data/context/GameContext.hh +++ b/src/data/context/GameContext.hh @@ -4,6 +4,8 @@ #include "context/IGameContext.hh" +#include "data/models/LocalBadgesModel.hh" + #include "services/ServiceLocator.hh" #include "GameAssets.hh" @@ -178,6 +180,17 @@ public: return pNotes ? *pNotes : m_oDefaultNotes; } + ra::data::models::LocalBadgesModel& LocalBadges() override + { + auto* pLocalBadges = dynamic_cast(m_vAssets.FindAsset(ra::data::models::AssetType::LocalBadges, 0)); + return pLocalBadges ? *pLocalBadges : m_oDefaultLocalBadges; + } + const ra::data::models::LocalBadgesModel& LocalBadges() const override + { + auto* pLocalBadges = dynamic_cast(m_vAssets.FindAsset(ra::data::models::AssetType::LocalBadges, 0)); + return pLocalBadges ? *pLocalBadges : m_oDefaultLocalBadges; + } + private: void FinishLoadGame(int nResult, const char* sErrorMessage, bool bWasPaused); void MigrateSubsetUserFiles(); @@ -211,6 +224,7 @@ private: // use the mock helper to register as both GameContext and IGameContext ra::services::ServiceLocator::ServiceOverride m_IGameContextOverride; ra::data::models::MemoryNotesModel m_oDefaultNotes; + ra::data::models::LocalBadgesModel m_oDefaultLocalBadges; }; } // namespace context diff --git a/src/devkit/RADevKit.vcxproj b/src/devkit/RADevKit.vcxproj index 9aa7102e..b72d6a91 100644 --- a/src/devkit/RADevKit.vcxproj +++ b/src/devkit/RADevKit.vcxproj @@ -67,7 +67,9 @@ + + @@ -99,7 +101,9 @@ + + diff --git a/src/devkit/RADevKit.vcxproj.filters b/src/devkit/RADevKit.vcxproj.filters index 485f77cf..05637bdb 100644 --- a/src/devkit/RADevKit.vcxproj.filters +++ b/src/devkit/RADevKit.vcxproj.filters @@ -195,6 +195,12 @@ data\models + + data\models + + + data\models + @@ -272,5 +278,11 @@ data\models + + data\models + + + data\models + \ No newline at end of file diff --git a/src/devkit/context/IGameContext.hh b/src/devkit/context/IGameContext.hh index ac8043bb..74e2454a 100644 --- a/src/devkit/context/IGameContext.hh +++ b/src/devkit/context/IGameContext.hh @@ -12,6 +12,7 @@ namespace ra { namespace data { namespace models { class MemoryNotesModel; + class LocalBadgesModel; } // namespace models } // namespace data @@ -71,6 +72,16 @@ public: /// virtual const ra::data::models::MemoryNotesModel& MemoryNotes() const noexcept(false) = 0; + /// + /// Gets the s for the currently loaded game. + /// + virtual ra::data::models::LocalBadgesModel& LocalBadges() noexcept(false) = 0; + + /// + /// Gets the s for the currently loaded game. + /// + virtual const ra::data::models::LocalBadgesModel& LocalBadges() const noexcept(false) = 0; + protected: uint32_t m_nGameId = 0; uint32_t m_nActiveGameId = 0; diff --git a/src/data/models/AchievementModel.cpp b/src/devkit/data/models/AchievementModel.cpp similarity index 94% rename from src/data/models/AchievementModel.cpp rename to src/devkit/data/models/AchievementModel.cpp index 21a99fd2..4a81d89c 100644 --- a/src/data/models/AchievementModel.cpp +++ b/src/devkit/data/models/AchievementModel.cpp @@ -1,20 +1,21 @@ #include "AchievementModel.hh" -#include "context\IRcClient.hh" +#include "context/IGameContext.hh" +#include "context/IRcClient.hh" -#include "util\Log.hh" +#include "data/context/GameAssets.hh" // TODO: this is a reference outside of the devkit code for FirstLocalID -#include "data\context\GameContext.hh" +#include "util/Log.hh" -#include "data\models\LocalBadgesModel.hh" -#include "data\models\TriggerValidation.hh" +#include "data/models/LocalBadgesModel.hh" +#include "data/models/TriggerValidation.hh" -#include "services\ServiceLocator.hh" +#include "services/ServiceLocator.hh" -#include "util\Strings.hh" +#include "util/Strings.hh" -#include -#include +#include +#include namespace ra { namespace data { @@ -109,24 +110,16 @@ void AchievementModel::OnValueChanged(const StringModelProperty::ChangeArgs& arg { if (ra::util::String::StartsWith(args.tOldValue, L"local\\")) { - auto& pGameContext = ra::services::ServiceLocator::GetMutable(); - auto* pLocalBadges = dynamic_cast(pGameContext.Assets().FindAsset(ra::data::models::AssetType::LocalBadges, 0)); - if (pLocalBadges) - { - const bool bCommitted = (GetLocalValue(BadgeProperty) == args.tOldValue); - pLocalBadges->RemoveReference(args.tOldValue, bCommitted); - } + const bool bCommitted = (GetLocalValue(BadgeProperty) == args.tOldValue); + auto& pGameContext = ra::services::ServiceLocator::GetMutable(); + pGameContext.LocalBadges().RemoveReference(args.tOldValue, bCommitted); } if (ra::util::String::StartsWith(args.tNewValue, L"local\\")) { - auto& pGameContext = ra::services::ServiceLocator::GetMutable(); - auto* pLocalBadges = dynamic_cast(pGameContext.Assets().FindAsset(ra::data::models::AssetType::LocalBadges, 0)); - if (pLocalBadges) - { - const bool bCommitted = (GetLocalValue(BadgeProperty) == args.tNewValue); - pLocalBadges->AddReference(args.tNewValue, bCommitted); - } + const bool bCommitted = (GetLocalValue(BadgeProperty) == args.tNewValue); + auto& pGameContext = ra::services::ServiceLocator::GetMutable(); + pGameContext.LocalBadges().AddReference(args.tNewValue, bCommitted); } if (m_pAchievementInfo) @@ -143,10 +136,8 @@ void AchievementModel::CommitTransaction() const auto& pBadgeName = GetBadge(); if (*pPreviousBadgeName != pBadgeName) { - auto& pGameContext = ra::services::ServiceLocator::GetMutable(); - auto* pLocalBadges = dynamic_cast(pGameContext.Assets().FindAsset(ra::data::models::AssetType::LocalBadges, 0)); - if (pLocalBadges) - pLocalBadges->Commit(*pPreviousBadgeName, pBadgeName); + auto& pGameContext = ra::services::ServiceLocator::GetMutable(); + pGameContext.LocalBadges().Commit(*pPreviousBadgeName, pBadgeName); } } diff --git a/src/data/models/AchievementModel.hh b/src/devkit/data/models/AchievementModel.hh similarity index 98% rename from src/data/models/AchievementModel.hh rename to src/devkit/data/models/AchievementModel.hh index d24e1854..ac0cfd80 100644 --- a/src/data/models/AchievementModel.hh +++ b/src/devkit/data/models/AchievementModel.hh @@ -1,5 +1,5 @@ -#ifndef RA_DATA_ACHIEVEMENT_MODEL_H -#define RA_DATA_ACHIEVEMENT_MODEL_H +#ifndef RA_DATA_MODELS_ACHIEVEMENTMODEL_H +#define RA_DATA_MODELS_ACHIEVEMENTMODEL_H #pragma once #include "data/models/AssetModelBase.hh" @@ -237,4 +237,4 @@ private: } // namespace data } // namespace ra -#endif RA_DATA_ACHIEVEMENT_MODEL_H +#endif RA_DATA_MODELS_ACHIEVEMENTMODEL_H diff --git a/src/data/models/LeaderboardModel.cpp b/src/devkit/data/models/LeaderboardModel.cpp similarity index 98% rename from src/data/models/LeaderboardModel.cpp rename to src/devkit/data/models/LeaderboardModel.cpp index d5abd913..2229fd25 100644 --- a/src/data/models/LeaderboardModel.cpp +++ b/src/devkit/data/models/LeaderboardModel.cpp @@ -1,15 +1,15 @@ #include "LeaderboardModel.hh" -#include "context\IRcClient.hh" +#include "context/IRcClient.hh" -#include "data\models\TriggerValidation.hh" +#include "data/models/TriggerValidation.hh" -#include "services\ServiceLocator.hh" +#include "services/ServiceLocator.hh" -#include "util\Strings.hh" +#include "util/Strings.hh" -#include -#include +#include +#include namespace ra { namespace data { diff --git a/src/data/models/LeaderboardModel.hh b/src/devkit/data/models/LeaderboardModel.hh similarity index 98% rename from src/data/models/LeaderboardModel.hh rename to src/devkit/data/models/LeaderboardModel.hh index c57bf604..4773d53d 100644 --- a/src/data/models/LeaderboardModel.hh +++ b/src/devkit/data/models/LeaderboardModel.hh @@ -1,5 +1,5 @@ -#ifndef RA_DATA_LEADERBOARD_MODEL_H -#define RA_DATA_LEADERBOARD_MODEL_H +#ifndef RA_DATA_MODELS_LEADERBOARDMODEL_H +#define RA_DATA_MODELS_LEADERBOARDMODEL_H #pragma once #include "data/models/AssetModelBase.hh" @@ -260,4 +260,4 @@ private: } // namespace data } // namespace ra -#endif RA_DATA_LEADERBOARD_MODEL_H +#endif RA_DATA_MODELS_LEADERBOARDMODEL_H diff --git a/src/ui/win32/bindings/ImageBinding.hh b/src/ui/win32/bindings/ImageBinding.hh index f67367bc..58c9ea5a 100644 --- a/src/ui/win32/bindings/ImageBinding.hh +++ b/src/ui/win32/bindings/ImageBinding.hh @@ -19,8 +19,11 @@ public: ~ImageBinding() noexcept { - GSL_SUPPRESS_F6 auto& pImageRepository = ra::services::ServiceLocator::GetMutable(); - pImageRepository.RemoveNotifyTarget(*this); + if (ra::services::ServiceLocator::Exists()) + { + GSL_SUPPRESS_F6 auto& pImageRepository = ra::services::ServiceLocator::GetMutable(); + pImageRepository.RemoveNotifyTarget(*this); + } } ImageBinding(const ImageBinding&) noexcept = delete; diff --git a/tests/RA_Integration.Tests.vcxproj b/tests/RA_Integration.Tests.vcxproj index f261656a..0206547f 100644 --- a/tests/RA_Integration.Tests.vcxproj +++ b/tests/RA_Integration.Tests.vcxproj @@ -82,8 +82,6 @@ - - Create @@ -144,7 +142,6 @@ - @@ -155,8 +152,6 @@ - - diff --git a/tests/RA_Integration.Tests.vcxproj.filters b/tests/RA_Integration.Tests.vcxproj.filters index e3c0fb90..999a73fa 100644 --- a/tests/RA_Integration.Tests.vcxproj.filters +++ b/tests/RA_Integration.Tests.vcxproj.filters @@ -31,9 +31,6 @@ {da241f86-5f80-4b36-b3d8-f8a0ecc1a4ee} - - {a0f14c97-e5dd-4827-9864-ca54f0c9177e} - @@ -309,12 +306,6 @@ Tests\Data\Context - - Code - - - Tests\Data\Models - Tests\UI\ViewModels @@ -339,12 +330,6 @@ Code - - Code - - - Tests\Data\Models - Code @@ -512,9 +497,6 @@ Tests\UI\ViewModels - - Code - Code diff --git a/tests/devkit/RADevKit.Tests.vcxproj b/tests/devkit/RADevKit.Tests.vcxproj index 6f62eb63..27e21359 100644 --- a/tests/devkit/RADevKit.Tests.vcxproj +++ b/tests/devkit/RADevKit.Tests.vcxproj @@ -70,6 +70,8 @@ + + @@ -88,6 +90,7 @@ + diff --git a/tests/devkit/RADevKit.Tests.vcxproj.filters b/tests/devkit/RADevKit.Tests.vcxproj.filters index ff15a7f0..eccf4c02 100644 --- a/tests/devkit/RADevKit.Tests.vcxproj.filters +++ b/tests/devkit/RADevKit.Tests.vcxproj.filters @@ -70,6 +70,12 @@ data\models + + data\models + + + data\models + @@ -170,5 +176,8 @@ ui\mocks + + testutil + \ No newline at end of file diff --git a/tests/devkit/context/mocks/MockGameContext.hh b/tests/devkit/context/mocks/MockGameContext.hh index 6af100b5..855b8fb3 100644 --- a/tests/devkit/context/mocks/MockGameContext.hh +++ b/tests/devkit/context/mocks/MockGameContext.hh @@ -4,6 +4,7 @@ #include "context/IGameContext.hh" +#include "data/models/LocalBadgesModel.hh" #include "data/models/MemoryNotesModel.hh" #include "services/ServiceLocator.hh" @@ -26,6 +27,9 @@ public: ra::data::models::MemoryNotesModel& MemoryNotes() noexcept override { return m_oMemoryNotes; } const ra::data::models::MemoryNotesModel& MemoryNotes() const noexcept override { return m_oMemoryNotes; } + ra::data::models::LocalBadgesModel& LocalBadges() noexcept override { return m_oLocalBadges; } + const ra::data::models::LocalBadgesModel& LocalBadges() const noexcept override { return m_oLocalBadges; } + bool SetNote(ra::data::ByteAddress nAddress, const std::wstring& sNote) { if (m_oMemoryNotes.NoteCount() == 0) @@ -88,6 +92,7 @@ private: }; MockMemoryNotesModel m_oMemoryNotes; + ra::data::models::LocalBadgesModel m_oLocalBadges; ra::services::ServiceLocator::ServiceOverride m_Override; }; diff --git a/tests/devkit/context/mocks/MockRcClient.cpp b/tests/devkit/context/mocks/MockRcClient.cpp index 2b83d0cb..648ff9ee 100644 --- a/tests/devkit/context/mocks/MockRcClient.cpp +++ b/tests/devkit/context/mocks/MockRcClient.cpp @@ -186,6 +186,7 @@ void MockRcClient::MockGame(uint32_t nGameId, const char* title, uint32_t nConso pGame->public_.id = nGameId; pGame->public_.console_id = nConsoleId; pGame->public_.title = title; + pGame->public_.badge_name = "55443"; auto* pClient = GetClient(); rc_client_unload_game(pClient); @@ -194,6 +195,147 @@ void MockRcClient::MockGame(uint32_t nGameId, const char* title, uint32_t nConso pClient->state.frames_processed = pClient->state.frames_at_last_ping = 0; } +static rc_client_subset_info_t* GetSubset(rc_client_game_info_t* game, uint32_t subset_id, const char* name) +{ + rc_client_subset_info_t* subset = game->subsets; + gsl::not_null next = gsl::make_not_null(&game->subsets); + for (; subset; subset = subset->next) + { + if (subset->public_.id == subset_id) + return subset; + + next = gsl::make_not_null(&subset->next); + } + + subset = static_cast(rc_buffer_alloc(&game->buffer, sizeof(rc_client_subset_info_t))); + memset(subset, 0, sizeof(*subset)); + subset->public_.id = subset_id; + strcpy_s(subset->public_.badge_name, sizeof(subset->public_.badge_name), game->public_.badge_name); + subset->public_.title = name; + subset->active = 1; + + *next = subset; + + return subset; +} + +static rc_client_subset_info_t* GetCoreSubset(rc_client_game_info_t* game) +{ + Assert::IsNotNull(game, L"MockGame must be called first"); + return GetSubset(game, game->public_.id, game->public_.title); +} + +static rc_client_achievement_info_t* AddAchievement(rc_client_game_info_t* game, + rc_client_subset_info_t* subset, uint32_t nId, const char* sTitle) +{ + Expects(subset != nullptr); + if (subset->public_.num_achievements % 8 == 0) + { + const uint32_t new_count = subset->public_.num_achievements + 8; + rc_client_achievement_info_t* new_achievements = static_cast(rc_buffer_alloc( + &game->buffer, sizeof(rc_client_achievement_info_t) * new_count)); + + if (subset->public_.num_achievements > 0) + { + memcpy(new_achievements, subset->achievements, + sizeof(rc_client_achievement_info_t) * subset->public_.num_achievements); + } + + subset->achievements = new_achievements; + } + + rc_client_achievement_info_t* achievement = &subset->achievements[subset->public_.num_achievements++]; + memset(achievement, 0, sizeof(*achievement)); + achievement->public_.id = nId; + + if (sTitle) + { + achievement->public_.title = rc_buffer_strcpy(&game->buffer, sTitle); + } + else + { + const std::string sGeneratedTitle = ra::util::String::Printf("Achievement %u", nId); + achievement->public_.title = rc_buffer_strcpy(&game->buffer, sGeneratedTitle.c_str()); + } + + const std::string sGeneratedDescripton = ra::util::String::Printf("Description %u", nId); + achievement->public_.description = rc_buffer_strcpy(&game->buffer, sGeneratedDescripton.c_str()); + + achievement->public_.category = RC_CLIENT_ACHIEVEMENT_CATEGORY_CORE; + achievement->public_.state = RC_CLIENT_ACHIEVEMENT_STATE_ACTIVE; + achievement->public_.points = 5; + achievement->author = "Author"; + + return achievement; +} + +rc_client_achievement_info_t* MockRcClient::MockAchievement(uint32_t nId, const char* sTitle) +{ + rc_client_game_info_t* game = GetClient()->game; + rc_client_achievement_info_t* achievement = AddAchievement(game, GetCoreSubset(game), nId, sTitle); + + achievement->trigger = static_cast(rc_buffer_alloc(&game->buffer, sizeof(rc_trigger_t))); + memset(achievement->trigger, 0, sizeof(*achievement->trigger)); + achievement->trigger->state = RC_TRIGGER_STATE_ACTIVE; + + return achievement; +} + +static rc_client_leaderboard_info_t* AddLeaderboard(const rc_client_t* client, rc_client_game_info_t* game, + rc_client_subset_info_t* subset, uint32_t nId, const char* sTitle) +{ + Expects(subset != nullptr); + if (subset->public_.num_leaderboards % 8 == 0) + { + const uint32_t new_count = subset->public_.num_leaderboards + 8; + rc_client_leaderboard_info_t* new_leaderboards = static_cast(rc_buffer_alloc( + &game->buffer, sizeof(rc_client_leaderboard_info_t) * new_count)); + + if (subset->public_.num_leaderboards > 0) + { + memcpy(new_leaderboards, subset->leaderboards, + sizeof(rc_client_leaderboard_info_t) * subset->public_.num_leaderboards); + } + + subset->leaderboards = new_leaderboards; + } + + rc_client_leaderboard_info_t* leaderboard = &subset->leaderboards[subset->public_.num_leaderboards++]; + memset(leaderboard, 0, sizeof(*leaderboard)); + leaderboard->public_.id = nId; + + if (sTitle) + { + leaderboard->public_.title = rc_buffer_strcpy(&game->buffer, sTitle); + } + else + { + const std::string sGeneratedTitle = ra::util::String::Printf("Leaderboard %u", nId); + leaderboard->public_.title = rc_buffer_strcpy(&game->buffer, sGeneratedTitle.c_str()); + } + + const std::string sGeneratedDescripton = ra::util::String::Printf("Description %u", nId); + leaderboard->public_.description = rc_buffer_strcpy(&game->buffer, sGeneratedDescripton.c_str()); + + leaderboard->public_.state = static_cast(rc_client_get_hardcore_enabled(client) ? + RC_CLIENT_LEADERBOARD_STATE_ACTIVE : RC_CLIENT_LEADERBOARD_STATE_INACTIVE); + + return leaderboard; +} + +rc_client_leaderboard_info_t* MockRcClient::MockLeaderboard(uint32_t nId, const char* sTitle) +{ + rc_client_game_info_t* game = GetClient()->game; + rc_client_leaderboard_info_t* leaderboard = AddLeaderboard(GetClient(), game, GetCoreSubset(game), nId, sTitle); + + leaderboard->lboard = static_cast(rc_buffer_alloc(&game->buffer, sizeof(rc_lboard_t))); + memset(leaderboard->lboard, 0, sizeof(*leaderboard->lboard)); + leaderboard->lboard->state = static_cast( + rc_client_get_hardcore_enabled(GetClient()) ? RC_LBOARD_STATE_ACTIVE : RC_LBOARD_STATE_INACTIVE); + + return leaderboard; +} + } // namespace mocks } // namespace context } // namespace ra diff --git a/tests/devkit/context/mocks/MockRcClient.hh b/tests/devkit/context/mocks/MockRcClient.hh index 901343e0..01f28366 100644 --- a/tests/devkit/context/mocks/MockRcClient.hh +++ b/tests/devkit/context/mocks/MockRcClient.hh @@ -6,6 +6,9 @@ #include "services\ServiceLocator.hh" +typedef struct rc_client_achievement_info_t rc_client_achievement_info_t; +typedef struct rc_client_leaderboard_info_t rc_client_leaderboard_info_t; + namespace ra { namespace context { namespace mocks { @@ -31,6 +34,8 @@ public: void SetHardcoreEnabled(bool bValue) noexcept; void MockGame(uint32_t nGameId, const char* title, uint32_t nConsoleId = 1); + rc_client_achievement_info_t* MockAchievement(uint32_t nId, const char* sTitle = nullptr); + rc_client_leaderboard_info_t* MockLeaderboard(uint32_t nId, const char* sTitle = nullptr); private: typedef struct MockApiResponse diff --git a/tests/data/models/AchievementModel_Tests.cpp b/tests/devkit/data/models/AchievementModel_Tests.cpp similarity index 82% rename from tests/data/models/AchievementModel_Tests.cpp rename to tests/devkit/data/models/AchievementModel_Tests.cpp index 19d3779a..29eacdd9 100644 --- a/tests/data/models/AchievementModel_Tests.cpp +++ b/tests/devkit/data/models/AchievementModel_Tests.cpp @@ -1,20 +1,20 @@ -#include "CppUnitTest.h" +#include "data/models/AchievementModel.hh" -#include "data\models\AchievementModel.hh" -#include "data\models\LocalBadgesModel.hh" +#include "context/mocks/MockEmulatorMemoryContext.hh" +#include "context/mocks/MockGameContext.hh" +#include "context/mocks/MockRcClient.hh" +#include "context/mocks/MockUserContext.hh" -#include "services\impl\StringTextWriter.hh" +#include "data/models/LocalBadgesModel.hh" -#include "tests\RA_UnitTestHelpers.h" -#include "tests\data\DataAsserts.hh" +#include "services/impl/StringTextWriter.hh" +#include "services/mocks/MockClock.hh" -#include "tests\devkit\context\mocks\MockEmulatorMemoryContext.hh" -#include "tests\devkit\context\mocks\MockRcClient.hh" -#include "tests\devkit\context\mocks\MockUserContext.hh" -#include "tests\devkit\services\mocks\MockClock.hh" -#include "tests\devkit\testutil\AssetAsserts.hh" -#include "tests\mocks\MockAchievementRuntime.hh" -#include "tests\mocks\MockGameContext.hh" +#include "testutil/AchievementAsserts.hh" +#include "testutil/AssetAsserts.hh" +#include "testutil/CppUnitTest.hh" + +#include using namespace Microsoft::VisualStudio::CppUnitTestFramework; @@ -33,29 +33,15 @@ TEST_CLASS(AchievementModel_Tests) public: AchievementModelHarness() noexcept { - GSL_SUPPRESS_F6 mockRuntime.MockGame(); + GSL_SUPPRESS_F6 mockRcClient.MockGame(1, "Game Title"); } ra::context::mocks::MockEmulatorMemoryContext mockEmulatorMemoryContext; + ra::context::mocks::MockGameContext mockGameContext; ra::context::mocks::MockRcClient mockRcClient; ra::context::mocks::MockUserContext mockUserContext; - ra::data::context::mocks::MockGameContext mockGameContext; ra::services::impl::StringTextWriter textWriter; - ra::services::mocks::MockAchievementRuntime mockRuntime; ra::services::mocks::MockClock mockClock; - - void AddLocalBadgesModel() - { - auto pLocalBadges = std::make_unique(); - pLocalBadges->CreateServerCheckpoint(); - pLocalBadges->CreateLocalCheckpoint(); - mockGameContext.Assets().Append(std::move(pLocalBadges)); - } - - ra::data::models::LocalBadgesModel& GetLocalBadgesModel() - { - return *(dynamic_cast(mockGameContext.Assets().FindAsset(AssetType::LocalBadges, 0))); - } }; public: @@ -82,7 +68,6 @@ TEST_CLASS(AchievementModel_Tests) { AchievementModelHarness achievement; achievement.mockGameContext.SetGameId(22); - achievement.AddLocalBadgesModel(); achievement.CreateServerCheckpoint(); achievement.CreateLocalCheckpoint(); @@ -90,7 +75,7 @@ TEST_CLASS(AchievementModel_Tests) achievement.SetTrigger("0xH1234=1"); achievement.SetBadge(L"local\\22-ABC.png"); - const auto& pLocalBadges = achievement.GetLocalBadgesModel(); + const auto& pLocalBadges = achievement.mockGameContext.LocalBadges(); Assert::AreEqual(1, pLocalBadges.GetReferenceCount(L"local\\22-ABC.png", false)); Assert::AreEqual(0, pLocalBadges.GetReferenceCount(L"local\\22-ABC.png", true)); @@ -105,7 +90,6 @@ TEST_CLASS(AchievementModel_Tests) { AchievementModelHarness achievement; achievement.mockGameContext.SetGameId(22); - achievement.AddLocalBadgesModel(); achievement.SetBadge(L"12345.png"); achievement.CreateServerCheckpoint(); achievement.CreateLocalCheckpoint(); @@ -114,7 +98,7 @@ TEST_CLASS(AchievementModel_Tests) achievement.SetTrigger("0xH1234=1"); achievement.SetBadge(L"local\\22-ABC.png"); - const auto& pLocalBadges = achievement.GetLocalBadgesModel(); + const auto& pLocalBadges = achievement.mockGameContext.LocalBadges(); Assert::AreEqual(1, pLocalBadges.GetReferenceCount(L"local\\22-ABC.png", false)); Assert::AreEqual(0, pLocalBadges.GetReferenceCount(L"local\\22-ABC.png", true)); @@ -132,7 +116,6 @@ TEST_CLASS(AchievementModel_Tests) AchievementModelHarness achievement; achievement.mockGameContext.SetGameId(22); achievement.mockGameContext.SetNote(0x1234, L"Note"); - achievement.AddLocalBadgesModel(); achievement.SetBadge(L"12345.png"); achievement.CreateServerCheckpoint(); achievement.CreateLocalCheckpoint(); @@ -171,7 +154,6 @@ TEST_CLASS(AchievementModel_Tests) { AchievementModelHarness achievement; achievement.mockGameContext.SetGameId(22); - achievement.AddLocalBadgesModel(); achievement.SetBadge(L"12345.png"); achievement.CreateServerCheckpoint(); achievement.CreateLocalCheckpoint(); @@ -203,7 +185,6 @@ TEST_CLASS(AchievementModel_Tests) { AchievementModelHarness achievement; achievement.mockGameContext.SetGameId(22); - achievement.AddLocalBadgesModel(); achievement.SetBadge(L"12345.png"); achievement.CreateServerCheckpoint(); achievement.CreateLocalCheckpoint(); @@ -239,12 +220,12 @@ TEST_CLASS(AchievementModel_Tests) achievement.CreateServerCheckpoint(); achievement.CreateLocalCheckpoint(); - achievement.mockRuntime.MockGame(); - auto* achievement_info = achievement.mockRuntime.MockAchievementWithTrigger(achievement.GetID()); + auto* achievement_info = achievement.mockRcClient.MockAchievement(achievement.GetID()); + Expects(achievement_info != nullptr); achievement.SetLocalAchievementInfo(*achievement_info); g_bEventSeen = false; - achievement.mockRuntime.GetClient()->callbacks.event_handler = + achievement.mockRcClient.GetClient()->callbacks.event_handler = [](const rc_client_event_t* pEvent, rc_client_t*) { Assert::AreEqual({RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_HIDE}, pEvent->type); @@ -272,12 +253,12 @@ TEST_CLASS(AchievementModel_Tests) achievement.CreateServerCheckpoint(); achievement.CreateLocalCheckpoint(); - achievement.mockRuntime.MockGame(); - auto* achievement_info = achievement.mockRuntime.MockAchievementWithTrigger(achievement.GetID()); + auto* achievement_info = achievement.mockRcClient.MockAchievement(achievement.GetID()); + Expects(achievement_info != nullptr); achievement.SetLocalAchievementInfo(*achievement_info); g_bEventSeen = false; - achievement.mockRuntime.GetClient()->callbacks.event_handler = [](const rc_client_event_t* pEvent, + achievement.mockRcClient.GetClient()->callbacks.event_handler = [](const rc_client_event_t* pEvent, rc_client_t*) { Assert::AreEqual({RC_CLIENT_EVENT_ACHIEVEMENT_CHALLENGE_INDICATOR_HIDE}, pEvent->type); Assert::AreEqual({53}, pEvent->achievement->id); diff --git a/tests/data/models/LeaderboardModel_Tests.cpp b/tests/devkit/data/models/LeaderboardModel_Tests.cpp similarity index 90% rename from tests/data/models/LeaderboardModel_Tests.cpp rename to tests/devkit/data/models/LeaderboardModel_Tests.cpp index 7aecf4d0..1a34288c 100644 --- a/tests/data/models/LeaderboardModel_Tests.cpp +++ b/tests/devkit/data/models/LeaderboardModel_Tests.cpp @@ -1,18 +1,17 @@ -#include "CppUnitTest.h" +#include "data/models/LeaderboardModel.hh" -#include "data\models\LeaderboardModel.hh" +#include "context/mocks/MockEmulatorMemoryContext.hh" +#include "context/mocks/MockGameContext.hh" +#include "context/mocks/MockRcClient.hh" +#include "context/mocks/MockUserContext.hh" -#include "services\impl\StringTextWriter.hh" +#include "services/impl/StringTextWriter.hh" -#include "tests\RA_UnitTestHelpers.h" +#include "testutil/AssetAsserts.hh" +#include "testutil/CppUnitTest.hh" +#include "testutil/ValueAsserts.hh" -#include "tests\devkit\context\mocks\MockEmulatorMemoryContext.hh" -#include "tests\devkit\context\mocks\MockRcClient.hh" -#include "tests\devkit\context\mocks\MockUserContext.hh" -#include "tests\devkit\testutil\AssetAsserts.hh" -#include "tests\devkit\testutil\ValueAsserts.hh" -#include "tests\mocks\MockAchievementRuntime.hh" -#include "tests\mocks\MockGameContext.hh" +#include using namespace Microsoft::VisualStudio::CppUnitTestFramework; @@ -30,11 +29,10 @@ TEST_CLASS(LeaderboardModel_Tests) { public: ra::context::mocks::MockEmulatorMemoryContext mockEmulatorMemoryContext; + ra::context::mocks::MockGameContext mockGameContext; ra::context::mocks::MockRcClient mockRcClient; ra::context::mocks::MockUserContext mockUserContext; - ra::data::context::mocks::MockGameContext mockGameContext; ra::services::impl::StringTextWriter textWriter; - ra::services::mocks::MockAchievementRuntime mockRuntime; }; public: @@ -280,14 +278,15 @@ TEST_CLASS(LeaderboardModel_Tests) leaderboard.CreateServerCheckpoint(); leaderboard.CreateLocalCheckpoint(); - leaderboard.mockRuntime.MockGame(); - auto* leaderboard_info = leaderboard.mockRuntime.MockLeaderboardWithLboard(leaderboard.GetID()); + leaderboard.mockRcClient.MockGame(1, "Game"); + auto* leaderboard_info = leaderboard.mockRcClient.MockLeaderboard(leaderboard.GetID()); + Expects(leaderboard_info != nullptr); leaderboard.SetLocalLeaderboardInfo(*leaderboard_info); - rc_client_allocate_leaderboard_tracker(leaderboard.mockRuntime.GetClient()->game, leaderboard_info); + rc_client_allocate_leaderboard_tracker(leaderboard.mockRcClient.GetClient()->game, leaderboard_info); g_bEventSeen = false; - leaderboard.mockRuntime.GetClient()->callbacks.event_handler = + leaderboard.mockRcClient.GetClient()->callbacks.event_handler = [](const rc_client_event_t* pEvent, rc_client_t*) { Assert::AreEqual({RC_CLIENT_EVENT_LEADERBOARD_TRACKER_HIDE}, pEvent->type); Assert::AreEqual({1}, pEvent->leaderboard_tracker->id); @@ -316,16 +315,17 @@ TEST_CLASS(LeaderboardModel_Tests) leaderboard.CreateServerCheckpoint(); leaderboard.CreateLocalCheckpoint(); - leaderboard.mockRuntime.MockGame(); - auto* leaderboard_info = leaderboard.mockRuntime.MockLeaderboardWithLboard(leaderboard.GetID()); + leaderboard.mockRcClient.MockGame(1, "Game"); + auto* leaderboard_info = leaderboard.mockRcClient.MockLeaderboard(leaderboard.GetID()); + Expects(leaderboard_info != nullptr); leaderboard.SetLocalLeaderboardInfo(*leaderboard_info); - rc_client_allocate_leaderboard_tracker(leaderboard.mockRuntime.GetClient()->game, leaderboard_info); - auto* leaderboard_info2 = leaderboard.mockRuntime.MockLeaderboardWithLboard(99); - rc_client_allocate_leaderboard_tracker(leaderboard.mockRuntime.GetClient()->game, leaderboard_info2); + rc_client_allocate_leaderboard_tracker(leaderboard.mockRcClient.GetClient()->game, leaderboard_info); + auto* leaderboard_info2 = leaderboard.mockRcClient.MockLeaderboard(99); + rc_client_allocate_leaderboard_tracker(leaderboard.mockRcClient.GetClient()->game, leaderboard_info2); g_bEventSeen = false; - leaderboard.mockRuntime.GetClient()->callbacks.event_handler = + leaderboard.mockRcClient.GetClient()->callbacks.event_handler = [](const rc_client_event_t*, rc_client_t*) { g_bEventSeen = true; }; @@ -352,14 +352,15 @@ TEST_CLASS(LeaderboardModel_Tests) leaderboard.CreateServerCheckpoint(); leaderboard.CreateLocalCheckpoint(); - leaderboard.mockRuntime.MockGame(); - auto* leaderboard_info = leaderboard.mockRuntime.MockLeaderboardWithLboard(leaderboard.GetID()); + leaderboard.mockRcClient.MockGame(1, "Game"); + auto* leaderboard_info = leaderboard.mockRcClient.MockLeaderboard(leaderboard.GetID()); + Expects(leaderboard_info != nullptr); leaderboard.SetLocalLeaderboardInfo(*leaderboard_info); - rc_client_allocate_leaderboard_tracker(leaderboard.mockRuntime.GetClient()->game, leaderboard_info); + rc_client_allocate_leaderboard_tracker(leaderboard.mockRcClient.GetClient()->game, leaderboard_info); g_bEventSeen = false; - leaderboard.mockRuntime.GetClient()->callbacks.event_handler = + leaderboard.mockRcClient.GetClient()->callbacks.event_handler = [](const rc_client_event_t* pEvent, rc_client_t*) { Assert::AreEqual({RC_CLIENT_EVENT_LEADERBOARD_TRACKER_HIDE}, pEvent->type); Assert::AreEqual({1}, pEvent->leaderboard_tracker->id); @@ -391,15 +392,16 @@ TEST_CLASS(LeaderboardModel_Tests) leaderboard.CreateServerCheckpoint(); leaderboard.CreateLocalCheckpoint(); - leaderboard.mockRuntime.MockGame(); - auto* leaderboard_info = leaderboard.mockRuntime.MockLeaderboard(leaderboard.GetID()); + leaderboard.mockRcClient.MockGame(1, "Game"); + auto* leaderboard_info = leaderboard.mockRcClient.MockLeaderboard(leaderboard.GetID()); + Expects(leaderboard_info != nullptr); leaderboard.SetLocalLeaderboardInfo(*leaderboard_info); // forcefully start the leaderboard leaderboard.SetState(AssetState::Primed); const auto* pLboard = leaderboard_info->lboard; Assert::IsNotNull(pLboard); - rc_client_allocate_leaderboard_tracker(leaderboard.mockRuntime.GetClient()->game, leaderboard_info); + rc_client_allocate_leaderboard_tracker(leaderboard.mockRcClient.GetClient()->game, leaderboard_info); Assert::IsTrue(leaderboard.IsActive()); Assert::AreEqual({ RC_LBOARD_STATE_STARTED }, leaderboard_info->lboard->state); diff --git a/tests/devkit/testutil/AchievementAsserts.hh b/tests/devkit/testutil/AchievementAsserts.hh new file mode 100644 index 00000000..c45d6c36 --- /dev/null +++ b/tests/devkit/testutil/AchievementAsserts.hh @@ -0,0 +1,44 @@ +#ifndef RA_ACHIEVEMENT_ASSERTS_H +#define RA_ACHIEVEMENT_ASSERTS_H +#pragma once + +#include "CppUnitTest.hh" + +#include "data/models/AchievementModel.hh" + +#include "util/TypeCasts.hh" + +namespace Microsoft { +namespace VisualStudio { +namespace CppUnitTestFramework { + +// converters for asserting enum values + +#pragma warning(push) +#pragma warning(disable : 4505) // unreferenced inline functions, they are referenced. Must be a bug. + +template<> +std::wstring ToString(const ra::data::models::AchievementType& t) +{ + switch (t) + { + case ra::data::models::AchievementType::None: + return L"None"; + case ra::data::models::AchievementType::Missable: + return L"Missable"; + case ra::data::models::AchievementType::Progression: + return L"Progression"; + case ra::data::models::AchievementType::Win: + return L"Win"; + default: + return std::to_wstring(static_cast(t)); + } +} + +#pragma warning(pop) + +} // namespace CppUnitTestFramework +} // namespace VisualStudio +} // namespace Microsoft + +#endif /* !RA_ACHIEVEMENT_ASSERTS_H */