Files
AnyPS5/core/libs/tests/GuestNpProfileDialog.cpp
T
MarcZX10 5e4d168601 test(libSceNpProfileDialog): cover the PSN notice on Open and OpenA
Check that silent mode and an unset variable show nothing, that show mode
shows the PSN notice once for Open and once for OpenA, that a refused null
parameter and an Open that throws show nothing, and that no notice is
shown when no presenter is registered. The guest test links libSceIme.
2026-10-30 18:49:35 +00:00

222 lines
10 KiB
C++

#include "prx/libSceNpProfileDialog/include/Api.hpp"
#include "prx/libSceIme/include/ModalDialog.hpp"
#include "prx/libSceIme/include/PsnDialogNotice.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include <cstddef>
#include <cstdint>
#include <cstdlib>
#include <cstring>
#include <stdexcept>
#include <string>
namespace {
void Require(bool value) { if (!value) std::abort(); }
constexpr int kStatusNone = 0;
constexpr int kStatusInitialized = 1;
constexpr int kStatusFinished = 3;
constexpr int kErrNotInitialized = static_cast<int>(0x80B80003u);
constexpr int kErrAlreadyInitialized = static_cast<int>(0x80B80004u);
constexpr int kErrNotFinished = static_cast<int>(0x80B80005u);
constexpr int kErrArgNull = static_cast<int>(0x80B8000Du);
constexpr std::int32_t kResultUserCanceled = 1;
constexpr std::size_t kParamSize = 128;
constexpr std::size_t kParamASize = 120;
constexpr std::size_t kParamUserData = 88;
constexpr std::size_t kParamAUserData = 80;
constexpr std::size_t kResultSize = 48;
constexpr std::uint8_t kSentinel = 0x5a;
template <typename TValue>
void Store(std::uint8_t* bytes, std::size_t offset, TValue value) {
std::memcpy(bytes + offset, &value, sizeof(value));
}
template <typename TValue>
TValue Load(const std::uint8_t* bytes, std::size_t offset) {
TValue value;
std::memcpy(&value, bytes + offset, sizeof(value));
return value;
}
void MakeParam(std::uint8_t* bytes, std::size_t capacity, std::uint64_t size, std::uint32_t mode, std::size_t userDataOffset, void* userData) {
std::memset(bytes, 0, capacity);
Store<std::uint64_t>(bytes, 0, 48);
Store<std::uint64_t>(bytes, 48, size);
Store<std::uint32_t>(bytes, 56, mode);
Store<std::int32_t>(bytes, 60, 1);
Store<void*>(bytes, userDataOffset, userData);
}
template <typename TCall>
void RequireThrows(TCall call) {
bool threw = false;
try {
call();
} catch (const std::runtime_error& error) {
threw = std::string(error.what()).find("not implemented") == std::string::npos;
}
Require(threw);
}
void RequireCanceled(const std::uint8_t* result, void* userData) {
Require(Load<std::int32_t>(result, 0) == 0);
Require(Load<std::int32_t>(result, 4) == kResultUserCanceled);
Require(Load<void*>(result, 8) == userData);
for (std::size_t i = 16; i < kResultSize; ++i) Require(result[i] == 0);
for (std::size_t i = kResultSize; i < kResultSize + 16; ++i) Require(result[i] == kSentinel);
}
bool PsnNoticeShown() {
ModalDialogView view;
if (!ModalDialogReadView_nid_postfix(view)) return false;
return view.message == PsnDialogNoticeRequest(PsnDialogNoticeKind::PsnFeature).message;
}
void RequireNotices(std::uint8_t* param, std::uint8_t* paramA) {
ModalDialogSetPresenter_nid_postfix(true);
Require(sceNpProfileDialogInitialize() == 0);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Silent);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpProfileDialogOpen(reinterpret_cast<const SceNpProfileDialogParam*>(param)) == 0);
Require(!PsnNoticeShown() && !ModalDialogCapturesInput_nid_postfix());
Require(sceNpProfileDialogGetStatus() == kStatusFinished);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Show);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpProfileDialogOpen(reinterpret_cast<const SceNpProfileDialogParam*>(param)) == 0);
Require(PsnNoticeShown());
Require(sceNpProfileDialogGetStatus() == kStatusFinished);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Show);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpProfileDialogOpenA(reinterpret_cast<const SceNpProfileDialogParamA*>(paramA)) == 0);
Require(PsnNoticeShown());
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Show);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpProfileDialogOpen(nullptr) == kErrArgNull);
Require(!PsnNoticeShown());
Store<std::uint32_t>(param, 56, 9);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Show);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
RequireThrows([&] { sceNpProfileDialogOpen(reinterpret_cast<const SceNpProfileDialogParam*>(param)); });
Require(!PsnNoticeShown());
Store<std::uint32_t>(param, 56, 1);
ModalDialogSetPresenter_nid_postfix(false);
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Show);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpProfileDialogOpen(reinterpret_cast<const SceNpProfileDialogParam*>(param)) == 0);
Require(!PsnNoticeShown() && !ModalDialogCapturesInput_nid_postfix());
PsnDialogNoticeSetMode_nid_postfix(PsnDialogNoticeMode::Silent);
ModalDialogReset_nid_postfix(ModalDialogAnyOwner);
Require(sceNpProfileDialogTerminate() == 0);
}
}
int main() {
alignas(8) std::uint8_t param[kParamSize + 16];
alignas(8) std::uint8_t paramA[kParamASize + 16];
alignas(8) std::uint8_t result[kResultSize + 16];
int first = 0;
int second = 0;
std::memset(result, kSentinel, sizeof(result));
MakeParam(param, sizeof(param), kParamSize, 1, kParamUserData, &first);
MakeParam(paramA, sizeof(paramA), kParamASize, 1, kParamAUserData, &second);
Require(sceNpProfileDialogTerminate() == kErrNotInitialized);
Require(sceNpProfileDialogClose() == kErrNotInitialized);
Require(sceNpProfileDialogGetResult(reinterpret_cast<SceNpProfileDialogResult*>(result)) == kErrNotInitialized);
Require(sceNpProfileDialogGetResult(nullptr) == kErrNotInitialized);
Require(sceNpProfileDialogGetStatus() == kStatusNone);
Require(sceNpProfileDialogUpdateStatus() == kStatusNone);
RequireThrows([&] { sceNpProfileDialogOpen(reinterpret_cast<const SceNpProfileDialogParam*>(param)); });
RequireThrows([&] { sceNpProfileDialogOpenA(reinterpret_cast<const SceNpProfileDialogParamA*>(paramA)); });
Require(sceNpProfileDialogGetStatus() == kStatusNone);
Require(result[0] == kSentinel);
Require(sceNpProfileDialogInitialize() == 0);
Require(sceNpProfileDialogInitialize() == kErrAlreadyInitialized);
Require(sceNpProfileDialogGetStatus() == kStatusInitialized);
Require(sceNpProfileDialogUpdateStatus() == kStatusInitialized);
Require(sceNpProfileDialogGetResult(reinterpret_cast<SceNpProfileDialogResult*>(result)) == kErrNotFinished);
Require(result[0] == kSentinel);
RequireThrows([] { sceNpProfileDialogGetResult(nullptr); });
RequireThrows([] { sceNpProfileDialogClose(); });
Require(sceNpProfileDialogGetStatus() == kStatusInitialized);
Require(sceNpProfileDialogOpen(nullptr) == kErrArgNull);
Require(sceNpProfileDialogOpenA(nullptr) == kErrArgNull);
Require(sceNpProfileDialogGetStatus() == kStatusInitialized);
alignas(8) std::uint8_t wrong[kParamSize + 16];
MakeParam(wrong, sizeof(wrong), kParamASize, 1, kParamUserData, &first);
RequireThrows([&] { sceNpProfileDialogOpen(reinterpret_cast<const SceNpProfileDialogParam*>(wrong)); });
MakeParam(wrong, sizeof(wrong), kParamSize, 1, kParamAUserData, &second);
RequireThrows([&] { sceNpProfileDialogOpenA(reinterpret_cast<const SceNpProfileDialogParamA*>(wrong)); });
MakeParam(wrong, sizeof(wrong), kParamSize, 0, kParamUserData, &first);
RequireThrows([&] { sceNpProfileDialogOpen(reinterpret_cast<const SceNpProfileDialogParam*>(wrong)); });
MakeParam(wrong, sizeof(wrong), kParamASize, 5, kParamAUserData, &second);
RequireThrows([&] { sceNpProfileDialogOpenA(reinterpret_cast<const SceNpProfileDialogParamA*>(wrong)); });
Require(sceNpProfileDialogGetStatus() == kStatusInitialized);
Require(sceNpProfileDialogGetResult(reinterpret_cast<SceNpProfileDialogResult*>(result)) == kErrNotFinished);
std::uint8_t paramCopy[sizeof(param)];
std::memcpy(paramCopy, param, sizeof(param));
Require(sceNpProfileDialogOpen(reinterpret_cast<const SceNpProfileDialogParam*>(param)) == 0);
Require(std::memcmp(param, paramCopy, sizeof(param)) == 0);
Require(sceNpProfileDialogGetStatus() == kStatusFinished);
Require(sceNpProfileDialogUpdateStatus() == kStatusFinished);
Require(sceNpProfileDialogGetResult(nullptr) == kErrArgNull);
Require(sceNpProfileDialogGetResult(reinterpret_cast<SceNpProfileDialogResult*>(result)) == 0);
RequireCanceled(result, &first);
RequireThrows([] { sceNpProfileDialogClose(); });
Require(sceNpProfileDialogGetStatus() == kStatusFinished);
for (std::uint32_t mode = 1; mode <= 4; ++mode) {
Store<std::uint32_t>(paramA, 56, mode);
std::uint8_t paramACopy[sizeof(paramA)];
std::memcpy(paramACopy, paramA, sizeof(paramA));
std::memset(result, kSentinel, sizeof(result));
Require(sceNpProfileDialogOpenA(reinterpret_cast<const SceNpProfileDialogParamA*>(paramA)) == 0);
Require(std::memcmp(paramA, paramACopy, sizeof(paramA)) == 0);
Require(sceNpProfileDialogUpdateStatus() == kStatusFinished);
Require(sceNpProfileDialogGetResult(reinterpret_cast<SceNpProfileDialogResult*>(result)) == 0);
RequireCanceled(result, &second);
}
Require(sceNpProfileDialogTerminate() == 0);
Require(sceNpProfileDialogTerminate() == kErrNotInitialized);
Require(sceNpProfileDialogClose() == kErrNotInitialized);
Require(sceNpProfileDialogGetResult(reinterpret_cast<SceNpProfileDialogResult*>(result)) == kErrNotInitialized);
Require(sceNpProfileDialogGetResult(nullptr) == kErrNotInitialized);
Require(sceNpProfileDialogGetStatus() == kStatusNone);
Require(sceNpProfileDialogUpdateStatus() == kStatusNone);
Require(sceNpProfileDialogInitialize() == 0);
std::memset(result, kSentinel, sizeof(result));
Require(sceNpProfileDialogGetResult(reinterpret_cast<SceNpProfileDialogResult*>(result)) == kErrNotFinished);
Require(result[0] == kSentinel);
Store<std::uint32_t>(param, 56, 4);
Require(sceNpProfileDialogOpen(reinterpret_cast<const SceNpProfileDialogParam*>(param)) == 0);
Require(sceNpProfileDialogGetResult(reinterpret_cast<SceNpProfileDialogResult*>(result)) == 0);
RequireCanceled(result, &first);
Require(sceNpProfileDialogTerminate() == 0);
Require(sceNpProfileDialogTerminate() == kErrNotInitialized);
Require(sceNpProfileDialogClose() == kErrNotInitialized);
Require(sceNpProfileDialogGetResult(reinterpret_cast<SceNpProfileDialogResult*>(result)) == kErrNotInitialized);
Require(sceNpProfileDialogGetResult(nullptr) == kErrNotInitialized);
Require(sceNpProfileDialogGetStatus() == kStatusNone);
Require(sceNpProfileDialogUpdateStatus() == kStatusNone);
RequireNotices(param, paramA);
return 0;
}