Files
AnyPS5/core/libs/tests/GuestCamera2.cpp
T
zaryabzip d13569637b test(libSceCamera): check the Camera2 calls for checked, exempt and unchecked app categories
AnyPS5's app info record always reports category 0xffffffff, so the
initialization check, the 0x20F00 exemption and the Initialize throw were
never reached. SetCamera2AppCategoryForTest_nid_no_patch overrides the
category the Camera2 calls read, and the test runs categories 0, 0x20F00
and 0x1000000.
2026-11-02 01:57:29 +05:00

117 lines
6.0 KiB
C++

#include "prx/libSceCamera/libSceCamera.hpp"
#include "prx/libSceCamera/include/Camera.hpp"
#include "prx/libc/include/general/VabiMacros.hpp"
#include <chrono>
#include <cstdint>
#include <cstdio>
#include <cstdlib>
#include <filesystem>
#include <fstream>
#include <stdexcept>
#include <string>
namespace {
constexpr int ErrorParam = static_cast<int>(0x8A760000);
constexpr int ErrorNotInit = static_cast<int>(0x8A760002);
constexpr int ErrorCameraOpen = static_cast<int>(0x8A760015);
using NoArgumentFn = int (APS5_VABI*)();
using HandleFn = int (APS5_VABI*)(std::int32_t);
using OpenFn = int (APS5_VABI*)(std::int32_t, std::int32_t, std::int32_t, void*);
void Require(bool condition, const char* message) {
if (condition) return;
std::fprintf(stderr, "Camera2: %s\n", message);
std::abort();
}
template <typename Function, typename Export>
Function As(Export function) {
return reinterpret_cast<Function>(function);
}
bool InitializeThrows(NoArgumentFn initialize) {
try {
initialize();
} catch (const std::runtime_error&) {
return true;
}
return false;
}
}
int main() {
const auto original = std::filesystem::current_path();
const auto directory = original / ("camera2-test-" + std::to_string(std::chrono::steady_clock::now().time_since_epoch().count()));
Require(std::filesystem::create_directory(directory), "the test directory could not be created");
std::filesystem::current_path(directory);
std::filesystem::create_directories("app0/sce_sys");
{
std::ofstream param("app0/sce_sys/param.json", std::ios::binary);
param << R"({"titleId":"PPSA00000","localizedParameters":{"en-US":{"titleName":"Example"}}})";
Require(static_cast<bool>(param), "param.json could not be written");
}
const auto initialize = As<NoArgumentFn>(&sceCamera2Initialize);
const auto finalize = As<NoArgumentFn>(&sceCamera2Finalize);
const auto open = As<OpenFn>(&sceCamera2Open);
const auto isAttached = As<HandleFn>(&sceCamera2IsAttached);
const HandleFn handleCalls[] = {
As<HandleFn>(&sceCamera2Close), As<HandleFn>(&sceCamera2GetAttribute), As<HandleFn>(&sceCamera2SetAttribute),
As<HandleFn>(&sceCamera2GetAutoExposureGain), As<HandleFn>(&sceCamera2SetAutoExposureGain), As<HandleFn>(&sceCamera2GetAutoWhiteBalance),
As<HandleFn>(&sceCamera2SetAutoWhiteBalance), As<HandleFn>(&sceCamera2GetConfig), As<HandleFn>(&sceCamera2SetConfig),
As<HandleFn>(&sceCamera2GetContrast), As<HandleFn>(&sceCamera2SetContrast), As<HandleFn>(&sceCamera2GetExposureGain),
As<HandleFn>(&sceCamera2SetExposureGain), As<HandleFn>(&sceCamera2GetGamma), As<HandleFn>(&sceCamera2SetGamma),
As<HandleFn>(&sceCamera2GetHue), As<HandleFn>(&sceCamera2SetHue), As<HandleFn>(&sceCamera2GetSaturation),
As<HandleFn>(&sceCamera2SetSaturation), As<HandleFn>(&sceCamera2GetSharpness), As<HandleFn>(&sceCamera2SetSharpness),
As<HandleFn>(&sceCamera2GetWhiteBalance), As<HandleFn>(&sceCamera2SetWhiteBalance), As<HandleFn>(&sceCamera2GetFieldOfView),
As<HandleFn>(&sceCamera2GetFrameData), As<HandleFn>(&sceCamera2IsValidFrameData), As<HandleFn>(&sceCamera2SetVideoSync),
As<HandleFn>(&sceCamera2Start), As<HandleFn>(&sceCamera2Stop),
};
for (const std::int32_t handle : {0, 1, 2, -1}) {
for (const auto call : handleCalls) Require(call(handle) == ErrorParam, "a handle that sceCamera2Open never returned was accepted");
}
Require(open(0xFE, 0, 0, nullptr) == ErrorParam, "sceCamera2Open took a user other than the system user");
Require(open(0xFF, 1, 0, nullptr) == ErrorParam && open(0xFF, 0, 1, nullptr) == ErrorParam, "sceCamera2Open took a nonzero type or index");
Require(isAttached(0) == ErrorParam && isAttached(2) == ErrorParam, "sceCamera2IsAttached took a device other than 1");
Require(initialize() == 0 && initialize() == 0, "sceCamera2Initialize failed");
for (const auto call : handleCalls) Require(call(1) == ErrorParam, "an initialized Camera2 accepted a handle it never opened");
Require(finalize() == 0, "sceCamera2Finalize failed with no camera open");
const int camera = sceCameraOpen(0xFF, 0, 0, nullptr);
Require(camera > 0, "sceCameraOpen failed");
Require(finalize() == ErrorCameraOpen, "sceCamera2Finalize ran while a camera was open");
Require(sceCameraClose(camera) == 0, "sceCameraClose failed");
Require(finalize() == 0, "sceCamera2Finalize failed after the camera closed");
const std::uint32_t checked = 0;
SetCamera2AppCategoryForTest_nid_no_patch(&checked);
for (const auto call : handleCalls) Require(call(1) == ErrorNotInit, "a category below 0x1000000 skipped the initialization check");
Require(finalize() == ErrorNotInit && open(0xFF, 0, 0, nullptr) == ErrorNotInit, "a checked category finalized or opened before sceCamera2Initialize");
Require(InitializeThrows(initialize), "sceCamera2Initialize answered for a checked category it doesn't model");
const std::uint32_t exempt = 0x20F00;
SetCamera2AppCategoryForTest_nid_no_patch(&exempt);
for (const auto call : handleCalls) Require(call(1) == ErrorParam, "category 0x20F00 was checked for initialization");
Require(initialize() == 0, "sceCamera2Initialize failed for category 0x20F00");
SetCamera2AppCategoryForTest_nid_no_patch(&checked);
for (const auto call : handleCalls) Require(call(1) == ErrorParam, "a checked category stayed uninitialized after sceCamera2Initialize");
Require(finalize() == 0, "sceCamera2Finalize failed for an initialized checked category");
const std::uint32_t unchecked = 0x1000000;
SetCamera2AppCategoryForTest_nid_no_patch(&unchecked);
for (const auto call : handleCalls) Require(call(1) == ErrorParam, "category 0x1000000 was checked for initialization");
Require(initialize() == 0 && finalize() == 0, "sceCamera2Initialize or Finalize failed for category 0x1000000");
SetCamera2AppCategoryForTest_nid_no_patch(nullptr);
std::filesystem::current_path(original);
std::filesystem::remove_all(directory);
std::puts("Camera2 tests passed");
return 0;
}