diff --git a/core/libs/prx/libSceAgcDriver/tests/UnsupportedDiagnostics.cpp b/core/libs/prx/libSceAgcDriver/tests/UnsupportedDiagnostics.cpp index 00df156cf9..b32dd5dfe8 100644 --- a/core/libs/prx/libSceAgcDriver/tests/UnsupportedDiagnostics.cpp +++ b/core/libs/prx/libSceAgcDriver/tests/UnsupportedDiagnostics.cpp @@ -1,9 +1,19 @@ #include "prx/libSceAgcDriver/include/AgcDriver.hpp" #include "SceTypes.hpp" +#include #include #include +static bool ThrowsNotImplemented(int (APS5_VABI* function)(void), const char* name) { + try { + function(); + } catch (const std::runtime_error& error) { + return std::string(error.what()) == std::string(name) + " not implemented"; + } + return false; +} + int main() { if (sceAgcDriverGetCoredumpAddress() != nullptr) return 1; if (sceAgcDriverSetTargetRingForDiag() != static_cast(0x8A6D0001)) return 2; @@ -13,5 +23,51 @@ int main() { } catch (const std::runtime_error& error) { if (std::string(error.what()) != "sceAgcDriverSetFlip not implemented") return 4; } + struct Export { + int (APS5_VABI* function)(void); + const char* name; + }; + const Export exports[] = { + {sceAgcDriverAcquireRazorACQ, "sceAgcDriverAcquireRazorACQ"}, + {sceAgcDriverCreateQueue, "sceAgcDriverCreateQueue"}, + {sceAgcDriverCwsrResumeAcq, "sceAgcDriverCwsrResumeAcq"}, + {sceAgcDriverCwsrSuspendAcq, "sceAgcDriverCwsrSuspendAcq"}, + {sceAgcDriverDebugHardwareStatus, "sceAgcDriverDebugHardwareStatus"}, + {sceAgcDriverDestroyQueue, "sceAgcDriverDestroyQueue"}, + {sceAgcDriverGetPaDebugInterfaceVersion, "sceAgcDriverGetPaDebugInterfaceVersion"}, + {sceAgcDriverGetRegShadowInfo, "sceAgcDriverGetRegShadowInfo"}, + {sceAgcDriverGetRegShadowInfoAgr, "sceAgcDriverGetRegShadowInfoAgr"}, + {sceAgcDriverGetReservedDmemForAgc, "sceAgcDriverGetReservedDmemForAgc"}, + {sceAgcDriverGetWorkloadStreamInfo, "sceAgcDriverGetWorkloadStreamInfo"}, + {sceAgcDriverIDHSSubmit, "sceAgcDriverIDHSSubmit"}, + {sceAgcDriverModuleRegistration, "sceAgcDriverModuleRegistration"}, + {sceAgcDriverNotifyDefaultStates, "sceAgcDriverNotifyDefaultStates"}, + {sceAgcDriverPassInfoDownward, "sceAgcDriverPassInfoDownward"}, + {sceAgcDriverPatchClearState, "sceAgcDriverPatchClearState"}, + {sceAgcDriverSetHsOffchipParamDirect, "sceAgcDriverSetHsOffchipParamDirect"}, + {sceAgcDriverSetWorkloadComplete, "sceAgcDriverSetWorkloadComplete"}, + {sceAgcDriverSetWorkloadsActive, "sceAgcDriverSetWorkloadsActive"}, + {sceAgcDriverSetupAsyncGraphics, "sceAgcDriverSetupAsyncGraphics"}, + {sceAgcDriverSetupRegisterShadow, "sceAgcDriverSetupRegisterShadow"}, + {sceAgcDriverSubmitMultiCommandBuffersDirect, "sceAgcDriverSubmitMultiCommandBuffersDirect"}, + {sceAgcDriverSubmitToHDRScopesACQ, "sceAgcDriverSubmitToHDRScopesACQ"}, + {sceAgcDriverSubmitToRazorACQ, "sceAgcDriverSubmitToRazorACQ"}, + {sceAgcDriverSuspendPointSubmit, "sceAgcDriverSuspendPointSubmit"}, + {sceAgcDriverSuspendPointSubmitDirect, "sceAgcDriverSuspendPointSubmitDirect"}, + {sceAgcDriverSysEnableSubmitDone45Exception, "sceAgcDriverSysEnableSubmitDone45Exception"}, + {sceAgcDriverSysGetClientNumber, "sceAgcDriverSysGetClientNumber"}, + {sceAgcDriverSysIsGameClosed, "sceAgcDriverSysIsGameClosed"}, + {sceAgcDriverTmpInitIdhs, "sceAgcDriverTmpInitIdhs"}, + {sceAgcDriverUserDataWritePacket, "sceAgcDriverUserDataWritePacket"}, + {sceAgcDriverUserDataWritePopMarker, "sceAgcDriverUserDataWritePopMarker"}, + {sceAgcDriverUserDataWritePushMarker, "sceAgcDriverUserDataWritePushMarker"}, + {sceAgcDriverUserDataWriteSetMarker, "sceAgcDriverUserDataWriteSetMarker"}, + }; + for (const auto& entry : exports) { + if (!ThrowsNotImplemented(entry.function, entry.name)) { + std::fprintf(stderr, "%s did not throw its not-implemented error\n", entry.name); + return 5; + } + } return 0; } diff --git a/core/libs/prx/libSceAudiodec.native/CMakeLists.txt b/core/libs/prx/libSceAudiodec.native/CMakeLists.txt index 9820917503..aabb9c7777 100644 --- a/core/libs/prx/libSceAudiodec.native/CMakeLists.txt +++ b/core/libs/prx/libSceAudiodec.native/CMakeLists.txt @@ -1,3 +1,14 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/../libSceAudiodec/AudiodecLibrary.cmake) add_sce_audiodec_library(libSceAudiodec.native) target_sources(libSceAudiodec.native PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp) +if(BUILD_TESTING) + add_test_executable(guest_audiodec_native_tests ${LIBS_INCLUDE_DIR}/tests/GuestAudiodecNative.cpp) + target_include_directories(guest_audiodec_native_tests PRIVATE ${LIBS_INCLUDE_DIR}) + target_link_libraries(guest_audiodec_native_tests PRIVATE libSceAudiodec.native libc) + configure_windows_unwind(guest_audiodec_native_tests) + add_test(NAME guest_audiodec_native COMMAND guest_audiodec_native_tests) + if(WIN32) + set_tests_properties(guest_audiodec_native PROPERTIES ENVIRONMENT_MODIFICATION + "PATH=path_list_prepend:$") + endif() +endif() diff --git a/core/libs/prx/libSceAvPlayer.native/CMakeLists.txt b/core/libs/prx/libSceAvPlayer.native/CMakeLists.txt index b9a16defb7..f3ead66927 100644 --- a/core/libs/prx/libSceAvPlayer.native/CMakeLists.txt +++ b/core/libs/prx/libSceAvPlayer.native/CMakeLists.txt @@ -2,3 +2,14 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/../libSceAvPlayer/AvPlayerLibrary.cmake) add_sce_avplayer_library(libSceAvPlayer.native) target_sources(libSceAvPlayer.native PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp) set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/Export.cpp PROPERTIES COMPILE_OPTIONS -fvisibility=default) +if(BUILD_TESTING) + add_test_executable(guest_avplayer_native_tests ${LIBS_INCLUDE_DIR}/tests/GuestAvPlayerNative.cpp) + target_include_directories(guest_avplayer_native_tests PRIVATE ${LIBS_INCLUDE_DIR}) + target_link_libraries(guest_avplayer_native_tests PRIVATE libSceAvPlayer.native libc) + configure_windows_unwind(guest_avplayer_native_tests) + add_test(NAME guest_avplayer_native COMMAND guest_avplayer_native_tests) + if(WIN32) + set_tests_properties(guest_avplayer_native PROPERTIES ENVIRONMENT_MODIFICATION + "PATH=path_list_prepend:$") + endif() +endif() diff --git a/core/libs/prx/libSceNgs2.native/CMakeLists.txt b/core/libs/prx/libSceNgs2.native/CMakeLists.txt index 2ebaae1246..5998c1c073 100644 --- a/core/libs/prx/libSceNgs2.native/CMakeLists.txt +++ b/core/libs/prx/libSceNgs2.native/CMakeLists.txt @@ -16,4 +16,5 @@ if(BUILD_TESTING) "PATH=path_list_prepend:$") endif() endforeach() + target_link_libraries(ngs2_handleerrors_tests PRIVATE libSceNgs2) endif() diff --git a/core/libs/prx/libSceNgs2.native/tests/Ngs2HandleErrors.cpp b/core/libs/prx/libSceNgs2.native/tests/Ngs2HandleErrors.cpp index 27f5dbc9f6..0e981d88cf 100644 --- a/core/libs/prx/libSceNgs2.native/tests/Ngs2HandleErrors.cpp +++ b/core/libs/prx/libSceNgs2.native/tests/Ngs2HandleErrors.cpp @@ -1,5 +1,6 @@ #include "Ngs2Test.hpp" #include "prx/libSceNgs2.native/include/Api.hpp" +#include "prx/libSceNgs2/include/Api.hpp" #include #include @@ -24,6 +25,64 @@ static void CheckUnimplemented() { throw std::runtime_error("sceNgs2RackQueryInfo must report that it is not implemented"); } +static bool ThrowsNotImplemented(int (APS5_VABI* function)(void), const char* name) { + try { + function(); + } catch (const std::runtime_error& error) { + return std::string(error.what()) == std::string(name) + " not implemented"; + } + return false; +} + +template +static bool CallThrowsNotImplemented(Call call, const char* name) { + try { + call(); + } catch (const std::runtime_error& error) { + return std::string(error.what()) == std::string(name) + " not implemented"; + } + return false; +} + +static void CheckPendingExports() { + struct Export { + int (APS5_VABI* function)(void); + const char* name; + }; + const Export exports[] = { + {sceNgs2JobSchedulerResetOption, "sceNgs2JobSchedulerResetOption"}, + {sceNgs2ModuleArrayEnumItems, "sceNgs2ModuleArrayEnumItems"}, + {sceNgs2ModuleEnumConfigs, "sceNgs2ModuleEnumConfigs"}, + {sceNgs2ModuleQueueEnumItems, "sceNgs2ModuleQueueEnumItems"}, + {sceNgs2RackRunCommands, "sceNgs2RackRunCommands"}, + {sceNgs2StreamCreate, "sceNgs2StreamCreate"}, + {sceNgs2StreamCreateWithAllocator, "sceNgs2StreamCreateWithAllocator"}, + {sceNgs2StreamDestroy, "sceNgs2StreamDestroy"}, + {sceNgs2StreamQueryBufferSize, "sceNgs2StreamQueryBufferSize"}, + {sceNgs2StreamQueryInfo, "sceNgs2StreamQueryInfo"}, + {sceNgs2StreamResetOption, "sceNgs2StreamResetOption"}, + {sceNgs2StreamRunCommands, "sceNgs2StreamRunCommands"}, + {sceNgs2SystemQueryInfo, "sceNgs2SystemQueryInfo"}, + {sceNgs2SystemRunCommands, "sceNgs2SystemRunCommands"}, + }; + for (const auto& entry : exports) { + if (!ThrowsNotImplemented(entry.function, entry.name)) throw std::runtime_error(std::string(entry.name) + " did not throw its not-implemented error"); + } +} + +static void CheckCorePendingExports() { + std::uintptr_t handles[1] = {}; + const auto require = [](bool thrown, const char* name) { + if (!thrown) throw std::runtime_error(std::string(name) + " did not throw its not-implemented error"); + }; + require(ThrowsNotImplemented(sceNgs2FftInit, "sceNgs2FftInit"), "sceNgs2FftInit"); + require(ThrowsNotImplemented(sceNgs2FftProcess, "sceNgs2FftProcess"), "sceNgs2FftProcess"); + require(ThrowsNotImplemented(sceNgs2FftQuerySize, "sceNgs2FftQuerySize"), "sceNgs2FftQuerySize"); + require(CallThrowsNotImplemented([] { sceNgs2ParseWaveformUser(0, 0, nullptr); }, "sceNgs2ParseWaveformUser"), "sceNgs2ParseWaveformUser"); + require(CallThrowsNotImplemented([&] { sceNgs2SystemEnumHandles(handles, 1); }, "sceNgs2SystemEnumHandles"), "sceNgs2SystemEnumHandles"); + require(CallThrowsNotImplemented([&] { sceNgs2SystemEnumRackHandles(0, handles, 1); }, "sceNgs2SystemEnumRackHandles"), "sceNgs2SystemEnumRackHandles"); +} + static void CheckResetOption() { Status(sceNgs2SystemResetOption(nullptr), static_cast(0x804A8010u), "null system option did not return the invalid out address error"); constexpr std::uint64_t size = 0x90; @@ -328,6 +387,8 @@ int main() { CheckSetGrainSamples(); CheckSetSampleRate(); CheckUnimplemented(); + CheckPendingExports(); + CheckCorePendingExports(); std::cout << "NGS2 PS5 handle errors and validation precedence checked\n"; return 0; } catch (const std::exception& error) { diff --git a/core/libs/tests/GuestAudiodecNative.cpp b/core/libs/tests/GuestAudiodecNative.cpp new file mode 100644 index 0000000000..b2dd106ec5 --- /dev/null +++ b/core/libs/tests/GuestAudiodecNative.cpp @@ -0,0 +1,46 @@ +#include "prx/libSceAudiodec.native/include/Api.hpp" +#include "SceTypes.hpp" +#include "prx/libc/include/general/VabiMacros.hpp" +#include +#include +#include + +static bool ThrowsNotImplemented(int (APS5_VABI* function)(void), const char* name) { + try { + function(); + } catch (const std::runtime_error& error) { + return std::string(error.what()) == std::string(name) + " not implemented"; + } + return false; +} + +int main() { + struct Export { + int (APS5_VABI* function)(void); + const char* name; + }; + const Export exports[] = { + {sceAudiodecClearContextEx, "sceAudiodecClearContextEx"}, + {sceAudiodecCreateDecoderEx, "sceAudiodecCreateDecoderEx"}, + {sceAudiodecDecode2, "sceAudiodecDecode2"}, + {sceAudiodecDecode2Ex, "sceAudiodecDecode2Ex"}, + {sceAudiodecDecode2WithPriority, "sceAudiodecDecode2WithPriority"}, + {sceAudiodecDecode2WithPriorityEx, "sceAudiodecDecode2WithPriorityEx"}, + {sceAudiodecDecodeEx, "sceAudiodecDecodeEx"}, + {sceAudiodecDecodeWithPriority, "sceAudiodecDecodeWithPriority"}, + {sceAudiodecDecodeWithPriorityEx, "sceAudiodecDecodeWithPriorityEx"}, + {sceAudiodecDeleteDecoderEx, "sceAudiodecDeleteDecoderEx"}, + {sceAudiodecGetContext, "sceAudiodecGetContext"}, + {sceAudiodecInitialize, "sceAudiodecInitialize"}, + {sceAudiodecRegisterCodec, "sceAudiodecRegisterCodec"}, + {sceAudiodecTerminate, "sceAudiodecTerminate"}, + }; + for (const auto& entry : exports) { + if (!ThrowsNotImplemented(entry.function, entry.name)) { + std::fprintf(stderr, "%s did not throw its not-implemented error\n", entry.name); + return 1; + } + } + std::puts("libSceAudiodec.native pending exports throw"); + return 0; +} diff --git a/core/libs/tests/GuestAvPlayerNative.cpp b/core/libs/tests/GuestAvPlayerNative.cpp new file mode 100644 index 0000000000..8043869d1e --- /dev/null +++ b/core/libs/tests/GuestAvPlayerNative.cpp @@ -0,0 +1,34 @@ +#include "prx/libSceAvPlayer.native/include/Api.hpp" +#include "SceTypes.hpp" +#include "prx/libc/include/general/VabiMacros.hpp" +#include +#include +#include + +static bool ThrowsNotImplemented(int (APS5_VABI* function)(void), const char* name) { + try { + function(); + } catch (const std::runtime_error& error) { + return std::string(error.what()) == std::string(name) + " not implemented"; + } + return false; +} + +int main() { + struct Export { + int (APS5_VABI* function)(void); + const char* name; + }; + const Export exports[] = { + {sceAvPlayerPrintf, "sceAvPlayerPrintf"}, + {sceAvPlayerVprintf, "sceAvPlayerVprintf"}, + }; + for (const auto& entry : exports) { + if (!ThrowsNotImplemented(entry.function, entry.name)) { + std::fprintf(stderr, "%s did not throw its not-implemented error\n", entry.name); + return 1; + } + } + std::puts("libSceAvPlayer.native pending exports throw"); + return 0; +} diff --git a/core/libs/tests/GuestNpTrophy2.cpp b/core/libs/tests/GuestNpTrophy2.cpp index 2587f00f58..2d1a350d5f 100644 --- a/core/libs/tests/GuestNpTrophy2.cpp +++ b/core/libs/tests/GuestNpTrophy2.cpp @@ -11,6 +11,47 @@ static void Require(bool value) { if (!value) std::abort(); } static void APS5_VABI OnUnlock(int, int, void*) {} +static bool ThrowsNotImplemented(int (APS5_VABI* function)(void), const char* name) { + try { + function(); + } catch (const std::runtime_error& error) { + return std::string(error.what()) == std::string(name) + " not implemented"; + } + return false; +} + +static void ResolvePendingExports() { + struct Export { + int (APS5_VABI* function)(void); + const char* name; + }; + const Export exports[] = { + {sceNpTrophy2SystemAbortHandle, "sceNpTrophy2SystemAbortHandle"}, + {sceNpTrophy2SystemBuildGroupIconUri, "sceNpTrophy2SystemBuildGroupIconUri"}, + {sceNpTrophy2SystemBuildRewardIconUri, "sceNpTrophy2SystemBuildRewardIconUri"}, + {sceNpTrophy2SystemBuildTrophyIconUri, "sceNpTrophy2SystemBuildTrophyIconUri"}, + {sceNpTrophy2SystemCheckCallback, "sceNpTrophy2SystemCheckCallback"}, + {sceNpTrophy2SystemCheckNetSyncTitles, "sceNpTrophy2SystemCheckNetSyncTitles"}, + {sceNpTrophy2SystemCreateHandle, "sceNpTrophy2SystemCreateHandle"}, + {sceNpTrophy2SystemDebugLockTrophy, "sceNpTrophy2SystemDebugLockTrophy"}, + {sceNpTrophy2SystemDebugUnlockTrophy, "sceNpTrophy2SystemDebugUnlockTrophy"}, + {sceNpTrophy2SystemDestroyContext, "sceNpTrophy2SystemDestroyContext"}, + {sceNpTrophy2SystemGetTrophyDetails, "sceNpTrophy2SystemGetTrophyDetails"}, + {sceNpTrophy2SystemGetTrophyGroupConf, "sceNpTrophy2SystemGetTrophyGroupConf"}, + {sceNpTrophy2SystemGetTrophySetArray, "sceNpTrophy2SystemGetTrophySetArray"}, + {sceNpTrophy2SystemGetTrophyTitleConf, "sceNpTrophy2SystemGetTrophyTitleConf"}, + {sceNpTrophy2SystemGetTrophyTitleDetails, "sceNpTrophy2SystemGetTrophyTitleDetails"}, + {sceNpTrophy2SystemGetTrpIconByUri, "sceNpTrophy2SystemGetTrpIconByUri"}, + {sceNpTrophy2SystemIsServerAvailable, "sceNpTrophy2SystemIsServerAvailable"}, + {sceNpTrophy2SystemRegisterTitleSyncedCallback, "sceNpTrophy2SystemRegisterTitleSyncedCallback"}, + {sceNpTrophy2SystemRegisterTitleUpdateCallback, "sceNpTrophy2SystemRegisterTitleUpdateCallback"}, + {sceNpTrophy2SystemRemoveAll, "sceNpTrophy2SystemRemoveAll"}, + {sceNpTrophy2SystemRemoveTitleData, "sceNpTrophy2SystemRemoveTitleData"}, + {sceNpTrophy2SystemRemoveUserData, "sceNpTrophy2SystemRemoveUserData"}, + }; + for (const auto& entry : exports) Require(ThrowsNotImplemented(entry.function, entry.name)); +} + template static bool ThrowsInvalidArgument(Call call) { try { call(); @@ -36,6 +77,7 @@ int main() { } catch (const std::runtime_error& error) { Require(std::string(error.what()) == "sceNpTrophy2SystemCreateContext not implemented"); } + ResolvePendingExports(); NpTrophy2GameDetails details{}; NpTrophy2GameData data{}; diff --git a/core/libs/tests/GuestNpTrophyData.cpp b/core/libs/tests/GuestNpTrophyData.cpp index 2c1a678be5..a776ac4081 100644 --- a/core/libs/tests/GuestNpTrophyData.cpp +++ b/core/libs/tests/GuestNpTrophyData.cpp @@ -233,6 +233,35 @@ static void ReportUnimplemented() { Require(false, "sceNpUniversalDataSystemIntInitialize must report that it is not implemented"); } +static bool ThrowsNotImplemented(int (APS5_VABI* function)(void), const char* name) { + try { + function(); + } catch (const std::runtime_error& error) { + return std::string(error.what()) == std::string(name) + " not implemented"; + } + return false; +} + +static void ResolveInternalExports() { + struct Export { + int (APS5_VABI* function)(void); + const char* name; + }; + const Export exports[] = { + {sceNpUniversalDataSystemIntAbortHandle, "sceNpUniversalDataSystemIntAbortHandle"}, + {sceNpUniversalDataSystemIntCheckNetSyncTitles, "sceNpUniversalDataSystemIntCheckNetSyncTitles"}, + {sceNpUniversalDataSystemIntCreateContext, "sceNpUniversalDataSystemIntCreateContext"}, + {sceNpUniversalDataSystemIntCreateHandle, "sceNpUniversalDataSystemIntCreateHandle"}, + {sceNpUniversalDataSystemIntDeleteAllData, "sceNpUniversalDataSystemIntDeleteAllData"}, + {sceNpUniversalDataSystemIntDeleteUserDataWithServerData, "sceNpUniversalDataSystemIntDeleteUserDataWithServerData"}, + {sceNpUniversalDataSystemIntDestroyContext, "sceNpUniversalDataSystemIntDestroyContext"}, + {sceNpUniversalDataSystemIntDestroyHandle, "sceNpUniversalDataSystemIntDestroyHandle"}, + {sceNpUniversalDataSystemIntNetSyncTitles, "sceNpUniversalDataSystemIntNetSyncTitles"}, + {sceNpUniversalDataSystemIntTerminate, "sceNpUniversalDataSystemIntTerminate"}, + }; + for (const auto& entry : exports) Require(ThrowsNotImplemented(entry.function, entry.name), entry.name); +} + int main() { const auto previous = std::filesystem::current_path(); const auto root = std::filesystem::temp_directory_path() / ("anyps5-trophy-data-" + std::to_string(std::random_device{}())); @@ -247,6 +276,7 @@ int main() { PostUnlocks(context); ReportPlaceholders(); ReportUnimplemented(); + ResolveInternalExports(); std::filesystem::current_path(previous); std::filesystem::remove_all(root);