mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 18:25:35 -04:00
fe22c12f7b
PR #134 fixed test_netplay_snap_ring.c's harness. This addresses why it broke: its only build instructions were a gcc command line in a header comment, and a comment cannot fail. 16 of the 41 C/C++ tests in runtime/tests/ were in that state, plus 3 python guards. Four had already rotted against the runtime API. Worse, two tests that WERE registered did not link on origin/master -- sio_dualshock_rumble_test (psx_read_word / psx_get_cycle_count / i_mask / g_debug_last_store_pc) and spu_fidelity_test (crc32_update) -- so `ctest` in a runtime tree did not build at all. Registering them fixes the instance. check_test_registration.cmake fixes the class: it reads both CMakeLists.txt files as text and fails configure on any test file that is neither registered nor listed with a reason. Reading them as text (rather than adding a top-level CMakeLists.txt) keeps the BIOS-free recompiler tree configurable, which is the only tree a newcomer can configure; both projects call the guard, so each catches orphans in the other. CONFIGURE_DEPENDS matters: without it, ADDING a test would not re-run configure. Also incorporates TechnicallyComputers' review of #134. -Werror turns a pre-existing Linux warning into a hard failure: clock_gettime/CLOCK_MONOTONIC need _POSIX_C_SOURCE under a strict -std=cNN. Both halves are needed -- the define in netplay_snap_ring.c fixes a direct compile of that TU, but not the harness, which includes <stdio.h> first and so has already latched glibc's <features.h>. Verified on Ubuntu 24.04 / GCC 13.3. Test-file changes: * repaired 4 rotted tests (stubs / a changed parameter list), no logic edits * build recipes replaced with `ctest -R <name>`, so exactly one description of how a test builds exists and the build executes it * known-failing tests registered DISABLED, not de-registered -- de-registering is the mechanism that hid these in the first place; DISABLED keeps them in `ctest -N` and countable without turning the run red * sio_card_protocol_test runs in a build-tree scratch dir; it writes test_dir/card1.mcd, and that is a TRACKED fixture * removed three committed test binaries and widened the .gitignore rule that missed them (it only covered *.exe, and these were Linux builds) Disabled, each with a bead: sio_card_protocol_test (147/309), sio_dualshock_rumble_test (27), spu_fidelity_test (4 ADSR), aot_overlay_discovery (cwd), and the 3 pre-existing perf guards. Verified: * adding an unregistered test file fails the build with an actionable message; removing it passes * runtime ctest 32/32 pass, 3 disabled * recompiler ctest: same 5 failures as a pristine origin/master baseline * Tomba, Tomba 2 and MMX6 build against this framework and were each driven 240s of attract + randomised pad fuzz (~195 injections, 47+ combos): 59.6 fps sustained, zero stalls, all three reached real gameplay Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
147 lines
5.3 KiB
C
147 lines
5.3 KiB
C
/*
|
|
* test_netplay_input_hist.c — pad map, invent hold-last, promote.
|
|
*
|
|
* Build/run: ctest -R netplay_input_hist_test
|
|
* (needs the lib/recomp-net submodule; registration is conditional.)
|
|
*/
|
|
#define PSX_HAS_RECOMP_NET 1
|
|
#include "netplay_input_hist.h"
|
|
#include "recomp_net/input_contract.h"
|
|
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
/* Standalone: provide normalize used by pad↔frame (mirrors psx_netplay). */
|
|
void psx_netplay_normalize_pad(PsxNetPad *pad)
|
|
{
|
|
const int dead = 24;
|
|
if (!pad) return;
|
|
if (pad->lx > (uint8_t)(0x80 - dead) && pad->lx < (uint8_t)(0x80 + dead))
|
|
pad->lx = 0x80;
|
|
if (pad->ly > (uint8_t)(0x80 - dead) && pad->ly < (uint8_t)(0x80 + dead))
|
|
pad->ly = 0x80;
|
|
if (pad->rx > (uint8_t)(0x80 - dead) && pad->rx < (uint8_t)(0x80 + dead))
|
|
pad->rx = 0x80;
|
|
if (pad->ry > (uint8_t)(0x80 - dead) && pad->ry < (uint8_t)(0x80 + dead))
|
|
pad->ry = 0x80;
|
|
}
|
|
|
|
static int failures;
|
|
#define CHECK(cond, msg) do { \
|
|
if (!(cond)) { printf("FAIL: %s\n", msg); failures++; } \
|
|
else { printf("ok: %s\n", msg); } \
|
|
} while (0)
|
|
|
|
static uint8_t hc_yes(void *ctx) { (void)ctx; return 1; }
|
|
static uint8_t hc_no(void *ctx) { (void)ctx; return 0; }
|
|
|
|
int main(void)
|
|
{
|
|
NetplayInputHist h;
|
|
RNetRbFrame f, got;
|
|
PsxNetPad pad, pad2;
|
|
RNetInputContractFrame pub, wire;
|
|
RNetInputContractParams params;
|
|
RNetInputContractHostGates gates;
|
|
RNetInputContractDecision d;
|
|
|
|
netplay_ih_reset(&h, 2);
|
|
CHECK(h.slot_count == 2, "slot_count");
|
|
|
|
memset(&pad, 0, sizeof(pad));
|
|
pad.buttons = 0xFDFFu; /* cross pressed (active-low) */
|
|
pad.lx = 0x80 + 40;
|
|
pad.ly = 0x80;
|
|
pad.rx = pad.ry = 0x80;
|
|
pad.analog = 1;
|
|
pad.connected = 1;
|
|
|
|
netplay_ih_pad_to_frame(&pad, 10, 0, &f);
|
|
CHECK(f.tick == 10u, "frame tick");
|
|
CHECK(f.buttons == 0xFDFFu, "buttons");
|
|
CHECK(f.stick_x == 40, "stick_x");
|
|
CHECK(f.stick_y == 0, "stick_y");
|
|
CHECK(f.analog == 1u, "analog flag from pad");
|
|
CHECK(!f.is_predicted && f.is_valid, "local auth flags");
|
|
|
|
netplay_ih_frame_to_pad(&f, &pad2);
|
|
CHECK(pad2.buttons == 0xFDFFu, "roundtrip buttons");
|
|
CHECK(pad2.lx == (uint8_t)(0x80 + 40), "roundtrip lx");
|
|
CHECK(pad2.analog == 1u, "roundtrip analog");
|
|
|
|
/* Digital MotK path must not become DualShock through hist. */
|
|
{
|
|
RNetRbFrame dig;
|
|
pad.analog = 0;
|
|
pad.lx = pad.ly = 0x80;
|
|
netplay_ih_pad_to_frame(&pad, 9, 0, &dig);
|
|
CHECK(dig.analog == 0u, "digital frame");
|
|
netplay_ih_frame_to_pad(&dig, &pad2);
|
|
CHECK(pad2.analog == 0u, "digital roundtrip");
|
|
}
|
|
|
|
CHECK(netplay_ih_put(&h, 0, &f), "put local");
|
|
CHECK(netplay_ih_get(&h, 0, 10, &got), "get local");
|
|
CHECK(got.stick_x == 40, "get stick");
|
|
CHECK(got.analog == 1u, "get analog");
|
|
|
|
/* Invent remote at 11 with no history → neutral digital. */
|
|
CHECK(netplay_ih_invent_hold_last(&h, 1, 11, &got), "invent neutral");
|
|
CHECK(got.is_predicted && got.buttons == 0xFFFFu, "invent predicted neutral");
|
|
CHECK(got.stick_x == 0 && got.stick_y == 0, "invent sticks zero");
|
|
CHECK(got.analog == 0u, "invent neutral digital");
|
|
CHECK(h.invent_count == 1u, "invent count");
|
|
|
|
/* Store auth remote at 11 then invent 12 → hold-last (incl. analog). */
|
|
f = got;
|
|
f.tick = 11;
|
|
f.buttons = 0xFBFFu;
|
|
f.stick_x = -20;
|
|
f.analog = 1u;
|
|
f.is_predicted = 0;
|
|
CHECK(netplay_ih_put(&h, 1, &f), "put auth remote");
|
|
CHECK(netplay_ih_invent_hold_last(&h, 1, 12, &got), "invent hold-last");
|
|
CHECK(got.buttons == 0xFBFFu && got.stick_x == -20, "held buttons/stick");
|
|
CHECK(got.analog == 1u, "held analog");
|
|
CHECK(got.is_predicted, "hold-last predicted");
|
|
|
|
/* Idle invent ignores prior hold (MotK menu path). */
|
|
CHECK(netplay_ih_invent_idle(&h, 1, 13, &got), "invent idle");
|
|
CHECK(got.is_predicted && got.buttons == 0xFFFFu, "idle buttons");
|
|
CHECK(got.stick_x == 0 && got.stick_y == 0 && got.analog == 0u, "idle sticks");
|
|
CHECK(h.invent_count == 3u, "invent count after idle");
|
|
|
|
/* Promote replaces predicted (tick 13 idle row). */
|
|
f = got;
|
|
f.stick_x = -18;
|
|
f.is_predicted = 0;
|
|
CHECK(netplay_ih_promote(&h, 1, &f), "promote");
|
|
CHECK(netplay_ih_get(&h, 1, 13, &got), "get promoted");
|
|
CHECK(!got.is_predicted && got.stick_x == -18, "promoted flags/stick");
|
|
CHECK(h.promote_count == 1u, "promote count");
|
|
|
|
/* Contract: predicted same-intent + hash_confirm → PromoteHashConfirm. */
|
|
rnet_input_contract_params_init_defaults(¶ms);
|
|
netplay_ih_frame_to_contract(&got, &pub);
|
|
pub.is_predicted = 1;
|
|
pub.stick_x = -20;
|
|
wire = pub;
|
|
wire.is_predicted = 0;
|
|
wire.stick_x = -18;
|
|
memset(&gates, 0, sizeof(gates));
|
|
gates.hash_confirm_promote = hc_no;
|
|
d = rnet_input_contract_stick_replace_decide(&pub, &wire, 1, ¶ms, &gates);
|
|
CHECK(rnet_input_contract_decision_is_rewind(d), "no hash_confirm → rewind");
|
|
gates.hash_confirm_promote = hc_yes;
|
|
d = rnet_input_contract_stick_replace_decide(&pub, &wire, 1, ¶ms, &gates);
|
|
CHECK(d == nRNetInputContractPromoteHashConfirm, "hash_confirm → promote");
|
|
CHECK(!rnet_input_contract_decision_is_rewind(d), "promote not rewind");
|
|
|
|
if (failures) {
|
|
printf("%d failure(s)\n", failures);
|
|
return 1;
|
|
}
|
|
printf("ALL PASS\n");
|
|
return 0;
|
|
}
|