// test_reconstruction.cpp - behavioral tests for the reconstructed libg native code. // // Compiled for the HOST (x86_64) and run directly. Because the reconstruction is arch-independent // C++, this exercises the exact logic that ships in the arm64/v7a .so - so it validates the // *function-matching* claim behaviourally, not just that the code compiles. Covers the String class // (SSO + heap) and the dual-mode FileHandle (stdio backend; the AAsset backend needs a device). #include "engine_structs.h" #include "file_handle.h" #include #include #include using namespace titan; // Host stubs for the NDK AAsset C API. These tests exercise the stdio (FILE*) backend only, so the // asset branch is never taken; the stubs merely satisfy the linker (on device these live in // libandroid.so). Signatures must match the forward declarations in file_handle.h. extern "C" { int AAsset_read(AAsset*, void*, size_t) { return -1; } long AAsset_seek(AAsset*, long, int) { return -1; } long AAsset_getLength(AAsset*) { return 0; } void AAsset_close(AAsset*) {} AAsset* AAssetManager_open(AAssetManager*, const char*, int) { return nullptr; } } // Reconstructed String methods (defined in titan_string.cpp / sub_1fe_cluster.cpp). namespace titan { struct_unknown_1* sub_1fe43c(struct_unknown_1*); int sub_1f7160(const struct_unknown_1*); const char* fcn_001f712c(const struct_unknown_1*); bool fcn_00200064(const struct_unknown_1*, const void*, int, int); bool fcn_0020010c(const struct_unknown_1*, const char*); bool fcn_002000d8(const struct_unknown_1*, const struct_unknown_1*); struct_unknown_1* fcn_001fea7c(struct_unknown_1*, const char*); struct_unknown_1* fcn_001feb70(struct_unknown_1*, const char*); struct_unknown_1* fcn_001fe9b8(struct_unknown_1*); struct_unknown_1* fcn_001feb9c(struct_unknown_1*, const struct_unknown_1*); const char* fcn_001f7044(struct_unknown_1*); } static int g_fail = 0, g_pass = 0; #define CHECK(cond, msg) do { if (cond) { ++g_pass; } else { ++g_fail; \ std::printf(" FAIL: %s\n", msg); } } while (0) static void test_string_sso() { std::printf("[String] short string (SSO path)\n"); struct_unknown_1 s; fcn_001feb70(&s, "hello"); // String("hello") CHECK(titan_string_length(&s) == 5, "length==5"); CHECK(sub_1f7160(&s) == 1, "isSSO (len<8)"); CHECK(std::strcmp(fcn_001f712c(&s), "hello") == 0, "data()==\"hello\""); CHECK(std::strcmp(fcn_001f7044(&s), "hello") == 0, "c_str()==\"hello\""); CHECK(fcn_0020010c(&s, "he") == true, "startsWith(\"he\")"); CHECK(fcn_0020010c(&s, "xy") == false, "!startsWith(\"xy\")"); CHECK(fcn_00200064(&s, "ll", 2, 2) == true, "matchAt(2,\"ll\")"); fcn_001fe9b8(&s); // ~String (no heap to free) } static void test_string_heap() { std::printf("[String] long string (heap path)\n"); struct_unknown_1 s; const char* L = "this_is_a_long_string_over_8_chars"; fcn_001feb70(&s, L); CHECK(titan_string_length(&s) == (int)std::strlen(L), "length matches"); CHECK(sub_1f7160(&s) == 0, "!isSSO (len>=8 -> heap)"); CHECK(std::strcmp(fcn_001f712c(&s), L) == 0, "heap data() matches"); CHECK(fcn_0020010c(&s, "this_is") == true, "startsWith prefix"); struct_unknown_1 c; // copy-ctor sub_1fe43c(&c); fcn_001feb9c(&c, &s); CHECK(std::strcmp(fcn_001f712c(&c), L) == 0, "copy has same content"); CHECK(fcn_002000d8(&s, &c) == true, "startsWith(String copy)"); fcn_001fe9b8(&c); fcn_001fe9b8(&s); // frees heap (no crash / leak-clean) std::printf(" (heap alloc/free exercised)\n"); } static void test_filehandle_stdio() { std::printf("[FileHandle] stdio backend (read/seek/getLength/getc/close)\n"); char tmpl[] = "/tmp/titan_fh_XXXXXX"; int fd = mkstemp(tmpl); CHECK(fd >= 0, "temp file created"); const char* payload = "Hello\nWorld"; // 11 bytes FILE* w = fdopen(fd, "wb"); std::fwrite(payload, 1, 11, w); std::fclose(w); FileHandle fh; fcn_0022af94(&fh, tmpl, "rb"); // open (falls to fopen: real file) CHECK(fcn_002293dc(&fh) == true, "isOpen after open"); CHECK(fh.fp != nullptr && fh.asset == nullptr, "stdio backend selected"); CHECK(fcn_00229410(&fh) == 11, "getLength==11"); char buf[6] = {0}; int n = fcn_00229484(&fh, buf, 1, 5); // read 5 bytes CHECK(n == 5 && std::memcmp(buf, "Hello", 5) == 0, "read 5 == \"Hello\""); fcn_0022b2f4(&fh, 6, SEEK_SET); // seek past the '\n' CHECK(fcn_0022b18c(&fh) == 'W', "getc after seek == 'W'"); fcn_002294e0(&fh); // closeImpl CHECK(fh.fp == nullptr, "fp nulled after close"); std::remove(tmpl); } static void test_filehandle_missing() { std::printf("[FileHandle] missing file (no backend, isOpen false)\n"); FileHandle fh; fcn_0022af94(&fh, "/no/such/titan/path.dat", "rb"); // fopen fails; no asset mgr -> nothing CHECK(fcn_002293dc(&fh) == false, "isOpen false for missing file"); fcn_0022b204(&fh); // close+reset is safe on empty } int main() { std::printf("== reconstructed libg behavioral tests ==\n"); test_string_sso(); test_string_heap(); test_filehandle_stdio(); test_filehandle_missing(); std::printf("\n== %d passed, %d failed ==\n", g_pass, g_fail); return g_fail == 0 ? 0 : 1; }