Test Protocol V2 player state validation

This commit is contained in:
Nomads_Reach
2026-08-15 23:38:18 -04:00
parent f24bd062eb
commit e7fde0192d
+80
View File
@@ -0,0 +1,80 @@
from __future__ import annotations
from player_state import normalize_player_state_packet
from server_core import _normalize_action_events
def valid_packet() -> dict:
return {
"type": "playerState",
"playerId": 9999,
"characterName": "Sole Survivor",
"equippedItems": [
{"slot": "rightHand", "formId": "ff"},
{"slot": "body", "formId": ""},
],
"appearance": {
"version": 4,
"raceFormId": "13746",
"height": 1.0,
"morphWeight": {"thin": 0.2, "muscular": 0.3, "large": 0.5},
"bodyTintColor": {"r": 1, "g": 2, "b": 3, "a": 255},
"hairColorFormId": "",
"facialHairColorFormId": "",
"complexionFormId": "",
"isFemale": False,
"headParts": ["1a2b"],
"morphs": [{"id": "10", "value": 0.5}],
"morphRegions": [0.25],
"facialBoneMorphs": [
{
"id": "20",
"position": [0.0, 1.0, 2.0],
"rotation": [3.0, 4.0, 5.0],
"scale": [1.0, 1.0, 1.0],
}
],
"tints": [{"id": 1, "type": 2, "value": 3, "color": "ff00ff00", "swatch": 4}],
},
"actionEvents": [{"sequence": 7, "type": 3, "eventName": "fireSingle"}],
}
def test_player_state_normalizes_only_reliable_fields():
clean = normalize_player_state_packet(valid_packet(), _normalize_action_events)
assert clean is not None
assert clean["type"] == "playerState"
assert "playerId" not in clean
assert clean["equippedItems"][0]["formId"] == "000000FF"
assert clean["appearance"]["raceFormId"] == "00013746"
assert clean["appearance"]["headParts"] == ["00001A2B"]
assert clean["appearance"]["tints"][0]["color"] == "FF00FF00"
assert clean["actionEvents"][0]["sequence"] == 7
def test_empty_player_state_is_rejected():
assert normalize_player_state_packet({"type": "playerState"}, _normalize_action_events) is None
def test_invalid_equipment_is_rejected():
packet = valid_packet()
packet["equippedItems"][0]["formId"] = "not-a-form"
assert normalize_player_state_packet(packet, _normalize_action_events) is None
def test_invalid_appearance_numbers_are_rejected():
packet = valid_packet()
packet["appearance"]["height"] = float("nan")
assert normalize_player_state_packet(packet, _normalize_action_events) is None
def test_invalid_action_event_is_rejected_instead_of_silently_dropped():
packet = valid_packet()
packet["actionEvents"] = [{"sequence": 7, "type": 3, "eventName": "notAllowed"}]
assert normalize_player_state_packet(packet, _normalize_action_events) is None
def test_character_name_is_bounded():
packet = valid_packet()
packet["characterName"] = "x" * 129
assert normalize_player_state_packet(packet, _normalize_action_events) is None