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