mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-11-04 13:07:32 +00:00
115 lines
7.8 KiB
C++
115 lines
7.8 KiB
C++
#include "prx/libSceJson2/include/Api.hpp"
|
|
#include "prx/libc/include/general/VabiMacros.hpp"
|
|
#include "JsonTestAllocator.hpp"
|
|
#include <cstddef>
|
|
#include <cstdint>
|
|
#include <cstdio>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
|
|
using namespace SceJson2;
|
|
|
|
struct Parameter { void* allocator; void* context; std::size_t bufferSize; std::int32_t mode; std::uint32_t reserved[3]; };
|
|
using Handler = const Value& (APS5_VABI*)(ValueType, const Value*, void*);
|
|
using MismatchHandler = const Value& (APS5_VABI*)(ValueType, const Value*, const Value*, void*);
|
|
static void Require(bool valid, const char* message) {
|
|
if (!valid) { std::fprintf(stderr, "%s\n", message); std::abort(); }
|
|
}
|
|
struct Context { int calls = 0; int requested = -1; const Value* parent = nullptr; const Value* replacement; const Value* reenter = nullptr; };
|
|
static const Value* mismatchSource = nullptr;
|
|
static const Value& APS5_VABI Mismatch(ValueType requested, const Value* self, const Value* parent, void* context) {
|
|
mismatchSource = self;
|
|
auto& trace = *static_cast<Context*>(context);
|
|
++trace.calls;
|
|
trace.requested = requested;
|
|
trace.parent = parent;
|
|
if (trace.reenter)
|
|
Require(*_ZNK3sce4Json5Value10getIntegerEv(trace.reenter) == 0, "Reentrant mismatch recovery must return its typed default");
|
|
return *trace.replacement;
|
|
}
|
|
static const Value& APS5_VABI Recover(ValueType requested, const Value* parent, void* context) {
|
|
auto& trace = *static_cast<Context*>(context);
|
|
++trace.calls;
|
|
trace.requested = requested;
|
|
trace.parent = parent;
|
|
if (trace.reenter)
|
|
Require(*_ZNK3sce4Json5Value10getIntegerEv(trace.reenter) == 0, "Reentrant null access must return its typed default");
|
|
return *trace.replacement;
|
|
}
|
|
int main() {
|
|
std::uint8_t initializer = 0, inactive = 0;
|
|
_ZN3sce4Json11InitializerC1Ev(&initializer);
|
|
Value replacement{}, localReplacement{};
|
|
_ZN3sce4Json5ValueC1El(&replacement, 99);
|
|
_ZN3sce4Json5ValueC1El(&localReplacement, 77);
|
|
Context global{0, -1, nullptr, &replacement, nullptr};
|
|
Context local{0, -1, nullptr, &localReplacement, nullptr};
|
|
Require(static_cast<unsigned>(_ZN3sce4Json11Initializer27setGlobalNullAccessCallbackEPFRKNS0_5ValueENS0_9ValueTypeEPS3_PvES7_(&initializer, Recover, &global)) == 0x80848110,
|
|
"Global callback registration must require an active initializer");
|
|
JsonTest::Allocator allocator;
|
|
Parameter parameter{&allocator, nullptr, 0, 2, {}};
|
|
Require(_ZN3sce4Json11Initializer10initializeEPKNS0_14InitParameter2E(&initializer, reinterpret_cast<const InitParameter2*>(¶meter)) == 0, "Initialize null recovery");
|
|
Require(static_cast<unsigned>(_ZN3sce4Json11Initializer27setGlobalNullAccessCallbackEPFRKNS0_5ValueENS0_9ValueTypeEPS3_PvES7_(&inactive, Recover, &global)) == 0x80848110,
|
|
"An inactive object cannot register a module-global callback");
|
|
Require(static_cast<unsigned>(_ZN3sce4Json11Initializer27setGlobalNullAccessCallbackEPFRKNS0_5ValueENS0_9ValueTypeEPS3_PvES7_(&initializer, nullptr, nullptr)) == 0x80848120,
|
|
"Global registration must reject a null callback");
|
|
Require(_ZN3sce4Json11Initializer27setGlobalNullAccessCallbackEPFRKNS0_5ValueENS0_9ValueTypeEPS3_PvES7_(&initializer, Recover, &global) == 0, "Register global null recovery");
|
|
Require(static_cast<unsigned>(_ZN3sce4Json11Initializer27setGlobalNullAccessCallbackEPFRKNS0_5ValueENS0_9ValueTypeEPS3_PvES7_(&initializer, Recover, &local)) == 0x80848112,
|
|
"Duplicate global registration must preserve its original callback and context");
|
|
Value root{};
|
|
_ZN3sce4Json5ValueC1Ev(&root);
|
|
const char text[] = "{\"n\":null,\"s\":\"text\"}";
|
|
Require(_ZN3sce4Json6Parser5parseERNS0_5ValueEPKcm(&root, text, sizeof(text) - 1) == 0, "Parse null recovery tree");
|
|
const auto* null = _ZNK3sce4Json5ValueixEPKc(&root, "n");
|
|
const auto* string = _ZNK3sce4Json5ValueixEPKc(&root, "s");
|
|
const auto* missing = _ZNK3sce4Json5ValueixEPKc(&root, "missing");
|
|
Require(missing->type == 0 && global.calls == 0, "Missing lookup must not invoke a typed null-access callback");
|
|
Require(*_ZNK3sce4Json5Value10getIntegerEv(null) == 99 && global.calls == 1 && global.requested == 2 && global.parent == &root,
|
|
"A typed null getter must call global recovery with its immediate parent");
|
|
Require(*_ZNK3sce4Json5Value10getIntegerEv(string) == 0 && global.calls == 1,
|
|
"A non-null type mismatch must not use null-access recovery");
|
|
Require(*_ZNK3sce4Json5Value10getIntegerEv(missing) == 99 && global.calls == 2 && global.parent == &root,
|
|
"The parser-owned fallback must retain its root parent");
|
|
Require(_ZN3sce4Json5Value21setNullAccessCallBackEPFRKS1_NS0_9ValueTypeEPS2_PvES6_(&root, Recover, &local) == 0,
|
|
"The value callback setter must take this, callback and context");
|
|
Require(*_ZNK3sce4Json5Value10getIntegerEv(null) == 77 && local.calls == 1 && local.parent == &root && global.calls == 2,
|
|
"Root-local null recovery must take precedence over global recovery");
|
|
local.reenter = null;
|
|
Require(!*_ZNK3sce4Json5Value10getBooleanEv(null) && local.calls == 2 && local.requested == 1,
|
|
"A mismatched callback result and reentrant getter must not recursively dispatch");
|
|
local.reenter = nullptr;
|
|
Require(_ZN3sce4Json5Value21setNullAccessCallBackEPFRKS1_NS0_9ValueTypeEPS2_PvES6_(&root, nullptr, nullptr) == 0,
|
|
"A value-local callback may be unregistered");
|
|
Require(*_ZNK3sce4Json5Value10getIntegerEv(null) == 99 && global.calls == 3 && local.calls == 2,
|
|
"Unregistration must restore global recovery");
|
|
Require(static_cast<unsigned>(_ZN3sce4Json5Value21setNullAccessCallBackEPFRKS1_NS0_9ValueTypeEPS2_PvES6_(const_cast<Value*>(null), Recover, &local)) == 0x80848104,
|
|
"Owned children must reject local null callback registration");
|
|
Context mismatch{0, -1, nullptr, &localReplacement, string};
|
|
Require(_ZN3sce4Json5Value22setTypeMismatchHandlerEPFRKS1_NS0_9ValueTypeEPS2_S5_PvES6_(&root, Mismatch, &mismatch) == 0,
|
|
"Register ancestor mismatch recovery");
|
|
Require(*_ZNK3sce4Json5Value10getIntegerEv(string) == 77 && mismatch.calls == 1 && mismatchSource == string &&
|
|
mismatch.parent == &root && mismatch.requested == 2,
|
|
"Mismatch recovery must pass the requested type, source and immediate parent");
|
|
Require(!*_ZNK3sce4Json5Value10getBooleanEv(string) && mismatch.calls == 2 && mismatch.requested == 1,
|
|
"A wrong-type recovery result must return the requested default without recursively dispatching");
|
|
Require(!_ZNK3sce4Json5ValuecvbEv(string) && mismatch.calls == 3,
|
|
"Boolean conversion must consult mismatch recovery before ordinary truth conversion");
|
|
Require(!_ZNK3sce4Json5ValuecvbEv(&root) && mismatch.calls == 4 && mismatchSource == &root && !mismatch.parent,
|
|
"A root boolean conversion must pass a null parent to mismatch recovery");
|
|
Require(*_ZNK3sce4Json5Value10getIntegerEv(null) == 77 && global.calls == 3 && mismatch.calls == 5,
|
|
"Root mismatch recovery must take precedence over module-global null recovery");
|
|
Require(_ZN3sce4Json5Value21setNullAccessCallBackEPFRKS1_NS0_9ValueTypeEPS2_PvES6_(&root, Recover, &local) == 0,
|
|
"Restore root-local null recovery");
|
|
Require(*_ZNK3sce4Json5Value10getIntegerEv(null) == 77 && local.calls == 3 && mismatch.calls == 5,
|
|
"Root-local null recovery must take precedence over mismatch recovery");
|
|
_ZN3sce4Json5ValueD1Ev(&root);
|
|
_ZN3sce4Json5ValueD1Ev(&replacement);
|
|
_ZN3sce4Json5ValueD1Ev(&localReplacement);
|
|
Require(_ZN3sce4Json11Initializer9terminateEv(&initializer) == 0, "Terminate null recovery");
|
|
Value after{};
|
|
_ZN3sce4Json5ValueC1Ev(&after);
|
|
Require(*_ZNK3sce4Json5Value10getIntegerEv(&after) == 0 && global.calls == 3, "Termination must clear global recovery");
|
|
_ZN3sce4Json5ValueD1Ev(&after);
|
|
return 0;
|
|
}
|