#!/usr/bin/env python3 """Pure unit test for the empty-My-Packs store resolver guard in autopatch.py. Covers the fail-closed guard decision (original -> PATCH, already-patched -> NOOP, unknown -> SKIP) and pins the guarded patch table to the exact RVA/bytes proven on the tested FIFA 17 build (JNZ 0x14869 -> JG 0x14869 at CardsDLL RVA 0x14858). Run: python3 test_autopatch_guard.py """ import os import sys sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) import autopatch # importable: runtime loop is guarded by `if __name__ == "__main__"` GUARD_VA = 0x180014858 ORIG = bytes.fromhex("750f") # JNZ 0x14869 PATCH = bytes.fromhex("7f0f") # JG 0x14869 def test_table_exact(): assert autopatch.STORE_PATCHES_GUARDED == {GUARD_VA: (ORIG, PATCH)}, \ autopatch.STORE_PATCHES_GUARDED # Byte-level pin so a bad hex literal cannot slip through. assert ORIG == b"\x75\x0f" and PATCH == b"\x7f\x0f" def test_decision(): assert autopatch.guarded_action(ORIG, ORIG, PATCH) == "patch" # apply assert autopatch.guarded_action(PATCH, ORIG, PATCH) == "noop" # already patched assert autopatch.guarded_action(b"\x00\x00", ORIG, PATCH) == "skip" # build mismatch assert autopatch.guarded_action(b"\x90", ORIG, PATCH) == "skip" # wrong length def test_guard_state_after(): # already patched (7f0f) -> VERIFIED (guarded_action "noop"); write args irrelevant. assert autopatch.guard_state_after(PATCH, ORIG, PATCH, True, PATCH) == autopatch.GUARD_VERIFIED # original (750f) + write ok + reread 7f0f -> VERIFIED (guarded_action "patch"). assert autopatch.guard_state_after(ORIG, ORIG, PATCH, True, PATCH) == autopatch.GUARD_VERIFIED # original + write FAILS -> WRITE_FAILED. assert autopatch.guard_state_after(ORIG, ORIG, PATCH, False, ORIG) == autopatch.GUARD_WRITE_FAILED # original + write ok but reread != 7f0f -> VERIFY_FAILED. assert autopatch.guard_state_after(ORIG, ORIG, PATCH, True, ORIG) == autopatch.GUARD_VERIFY_FAILED assert autopatch.guard_state_after(ORIG, ORIG, PATCH, True, b"") == autopatch.GUARD_VERIFY_FAILED # unknown bytes -> UNSUPPORTED_BUILD (guarded_action "skip"); write args irrelevant. assert autopatch.guard_state_after(b"\x00\x00", ORIG, PATCH, True, PATCH) == autopatch.GUARD_UNSUPPORTED_BUILD def test_capability_constants(): assert autopatch.EMPTY_MYPACKS_RESOLVER_VERSION == 1 assert autopatch.EMPTY_MYPACKS_RESOLVER_CAPABILITY == "fifa17.empty_mypacks_resolver" # State constant values are the exact tokens carried in the emitted status line. assert autopatch.GUARD_VERIFIED == "VERIFIED" assert autopatch.GUARD_UNSUPPORTED_BUILD == "UNSUPPORTED_BUILD" assert autopatch.GUARD_WRITE_FAILED == "WRITE_FAILED" assert autopatch.GUARD_VERIFY_FAILED == "VERIFY_FAILED" assert autopatch.GUARD_NOT_ATTEMPTED == "NOT_ATTEMPTED" if __name__ == "__main__": test_table_exact() test_decision() test_guard_state_after() test_capability_constants() print("OK: autopatch guard table + fail-closed decision + guard-state function + capability constants")