Files
bancho.py/tests/unit/packets_test.py
2025-04-04 21:32:15 +09:00

670 lines
19 KiB
Python

from __future__ import annotations
import pytest
import app.packets
@pytest.mark.parametrize(
("test_input", "expected"),
[
(0, b"\x05\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00"),
(2_147_483_647, b"\x05\x00\x00\x04\x00\x00\x00\xff\xff\xff\x7f"),
],
)
def test_write_user_id(test_input, expected):
assert app.packets.login_reply(test_input) == expected
@pytest.mark.parametrize(
("test_input", "expected"),
[
(
{
"sender": "cmyui",
"msg": "woah woah crazy!!",
"recipient": "jacobian",
"sender_id": 32,
},
b"\x07\x00\x00(\x00\x00\x00\x0b\x05cmyui\x0b\x11woah woah crazy!!\x0b\x08jacobian \x00\x00\x00",
),
(
{
"sender": "",
"msg": "",
"recipient": "",
"sender_id": 0,
},
b"\x07\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
),
],
)
def test_write_send_message(test_input, expected):
assert app.packets.send_message(**test_input) == expected
def test_write_pong():
assert app.packets.pong() == b"\x08\x00\x00\x00\x00\x00\x00"
@pytest.mark.parametrize(
("test_input", "expected"),
[
(
{"old": "cmyui", "new": "abcgamer321"},
b"\t\x00\x00\x16\x00\x00\x00\x0b\x14cmyui>>>>abcgamer321",
),
(
{"old": "", "new": ""},
b"\t\x00\x00\x06\x00\x00\x00\x0b\x04>>>>",
),
],
)
def test_write_change_username(test_input, expected):
assert app.packets.change_username(**test_input) == expected
@pytest.mark.parametrize(
("test_input", "expected"),
[
(
{
"user_id": 1001,
"action": 2, # playing
"info_text": "gaming", # TODO: get a realistic one
"map_md5": "60b725f10c9c85c70d97880dfe8191b3",
"mods": 64,
"mode": 0,
"map_id": 1723723,
"ranked_score": 1_238_917_112,
"accuracy": 92.32,
"plays": 3821,
"total_score": 3_812_428_392,
"global_rank": 42,
"pp": 8291,
},
b"\x0b\x00\x00V\x00\x00\x00\xe9\x03\x00\x00\x02\x0b\x06gaming\x0b 60b725f10c9c85c70d97880dfe8191b3@\x00\x00\x00\x00KM\x1a\x00\xf8_\xd8I\x00\x00\x00\x00\xd6Vl?\xed\x0e\x00\x00h\n=\xe3\x00\x00\x00\x00*\x00\x00\x00c ",
),
(
{
"user_id": 0,
"action": 0,
"info_text": "",
"map_md5": "", # TODO: can this even be empty
"mods": 0,
"mode": 0,
"map_id": 0,
"ranked_score": 0,
"accuracy": 0.0,
"plays": 0,
"total_score": 0,
"global_rank": 0,
"pp": 0,
},
b"\x0b\x00\x00.\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
),
],
)
def test_write_user_stats(test_input, expected):
assert app.packets._user_stats(**test_input) == expected
@pytest.mark.parametrize(
("test_input", "expected"),
[
(0, b"\x0c\x00\x00\x05\x00\x00\x00\x00\x00\x00\x00\x00"),
(2_147_483_647, b"\x0c\x00\x00\x05\x00\x00\x00\xff\xff\xff\x7f\x00"),
],
)
def test_write_logout(test_input, expected):
assert app.packets.logout(test_input) == expected
@pytest.mark.parametrize(
("test_input", "expected"),
[
(0, b"\x0d\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00"),
(2_147_483_647, b"\x0d\x00\x00\x04\x00\x00\x00\xff\xff\xff\x7f"),
],
)
def test_write_spectator_joined(test_input, expected):
assert app.packets.spectator_joined(test_input) == expected
...
@pytest.mark.parametrize(
("test_input", "expected"),
[
(0, b"\x0e\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00"),
(2_147_483_647, b"\x0e\x00\x00\x04\x00\x00\x00\xff\xff\xff\x7f"),
],
)
def test_write_spectator_left(test_input, expected):
assert app.packets.spectator_left(test_input) == expected
@pytest.mark.xfail(reason="need to implement proper writing")
@pytest.mark.parametrize(("test_input", "expected"), [({}, b"")])
def test_write_spectate_frames(test_input, expected):
assert app.packets.spectate_frames(test_input) == expected
def test_write_version_update():
assert app.packets.version_update() == b"\x13\x00\x00\x00\x00\x00\x00"
@pytest.mark.parametrize(
("test_input", "expected"),
[
(0, b"\x16\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00"),
(2_147_483_647, b"\x16\x00\x00\x04\x00\x00\x00\xff\xff\xff\x7f"),
],
)
def test_write_spectator_cant_spectate(test_input, expected):
assert app.packets.spectator_cant_spectate(test_input) == expected
def test_write_get_attention():
assert app.packets.get_attention() == b"\x17\x00\x00\x00\x00\x00\x00"
@pytest.mark.parametrize(
("test_input", "expected"),
[
("waowww", b"\x18\x00\x00\x08\x00\x00\x00\x0b\x06waowww"),
("", b"\x18\x00\x00\x01\x00\x00\x00\x00"),
],
)
def test_write_notification(test_input, expected):
assert app.packets.notification(test_input) == expected
@pytest.mark.xfail(reason="need to remove bancho.py match object")
@pytest.mark.parametrize(
("test_input", "expected"),
[
({"m": None, "send_pw": False}, b""),
({"m": None, "send_pw": True}, b""),
],
)
def test_write_update_match(test_input, expected):
assert app.packets.update_match(test_input) == expected
@pytest.mark.xfail(reason="need to remove bancho.py match object")
@pytest.mark.parametrize(
("test_input", "expected"),
[
({}, b""),
({}, b""),
],
)
def test_write_new_match(test_input, expected):
assert app.packets.new_match(test_input) == expected
@pytest.mark.parametrize(
("test_input", "expected"),
[
(0, b"\x1c\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00"),
(2_147_483_647, b"\x1c\x00\x00\x04\x00\x00\x00\xff\xff\xff\x7f"),
],
)
def test_write_dispose_match(test_input, expected):
assert app.packets.dispose_match(test_input) == expected
def test_write_toggle_block_non_friend_pm():
assert app.packets.toggle_block_non_friend_dm() == b'"\x00\x00\x00\x00\x00\x00'
@pytest.mark.xfail(reason="need to remove bancho.py match object")
@pytest.mark.parametrize(
("test_input", "expected"),
[
({}, b""),
({}, b""),
],
)
def test_write_match_join_success(test_input, expected):
assert app.packets.match_join_success(test_input) == expected
def test_write_match_join_fail():
assert app.packets.match_join_fail() == b"%\x00\x00\x00\x00\x00\x00"
@pytest.mark.parametrize(
("test_input", "expected"),
[
(0, b"*\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00"),
(2_147_483_647, b"*\x00\x00\x04\x00\x00\x00\xff\xff\xff\x7f"),
],
)
def test_write_fellow_spectator_joined(test_input, expected):
assert app.packets.fellow_spectator_joined(test_input) == expected
@pytest.mark.parametrize(
("test_input", "expected"),
[
(0, b"+\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00"),
(2_147_483_647, b"+\x00\x00\x04\x00\x00\x00\xff\xff\xff\x7f"),
],
)
def test_write_fellow_spectator_left(test_input, expected):
assert app.packets.fellow_spectator_left(test_input) == expected
@pytest.mark.xfail(reason="need to remove bancho.py match object")
@pytest.mark.parametrize(
("test_input", "expected"),
[
({}, b""),
({}, b""),
],
)
def test_write_match_start(test_input, expected):
assert app.packets.match_start(test_input) == expected
@pytest.mark.parametrize(
("test_input", "expected"),
[
(
app.packets.ScoreFrame(
time=38242, # TODO: check if realistic
id=28, # TODO: check if realistic
num300=320,
num100=48,
num50=2,
num_geki=32,
num_katu=8,
num_miss=3,
total_score=492_392,
current_combo=39,
max_combo=122,
perfect=False,
current_hp=245, # TODO: check if realistic
tag_byte=0,
score_v2=False,
# NOTE: this stuff isn't written
# combo_portion=0.0,
# bonus_portion=0.0,
),
b"0\x00\x00\x1d\x00\x00\x00b\x95\x00\x00\x1c@\x010\x00\x02\x00 \x00\x08\x00\x03\x00h\x83\x07\x00z\x00'\x00\x00\xf5\x00\x00",
),
(
app.packets.ScoreFrame(
time=0,
id=0,
num300=0,
num100=0,
num50=0,
num_geki=0,
num_katu=0,
num_miss=0,
total_score=0,
current_combo=0,
max_combo=0,
perfect=False,
current_hp=0,
tag_byte=0,
score_v2=False,
combo_portion=0.0,
bonus_portion=0.0,
),
b"0\x00\x00\x1d\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
),
],
)
def test_write_match_score_update(test_input, expected):
assert app.packets.match_score_update(test_input) == expected
def test_write_match_transfer_host():
assert app.packets.match_transfer_host() == b"2\x00\x00\x00\x00\x00\x00"
def test_write_match_all_players_loaded():
assert app.packets.match_all_players_loaded() == b"5\x00\x00\x00\x00\x00\x00"
@pytest.mark.parametrize(
("test_input", "expected"),
[
(0, b"9\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00"),
(2_147_483_647, b"9\x00\x00\x04\x00\x00\x00\xff\xff\xff\x7f"),
],
)
def test_write_match_player_failed(test_input, expected):
assert app.packets.match_player_failed(test_input) == expected
def test_write_match_complete():
assert app.packets.match_complete() == b":\x00\x00\x00\x00\x00\x00"
def test_write_match_skip():
assert app.packets.match_skip() == b"=\x00\x00\x00\x00\x00\x00"
@pytest.mark.parametrize(
("test_input", "expected"),
[
("#osu", b"@\x00\x00\x06\x00\x00\x00\x0b\x04#osu"),
("", b"@\x00\x00\x01\x00\x00\x00\x00"),
],
)
def test_write_channel_join(test_input, expected):
assert app.packets.channel_join(test_input) == expected
@pytest.mark.parametrize(
("test_input", "expected"),
[
(
("#osu", "le topique", 123),
b"A\x00\x00\x14\x00\x00\x00\x0b\x04#osu\x0b\nle topique{\x00",
),
(("", "", 0), b"A\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00"),
],
)
def test_write_channel_info(test_input, expected):
assert app.packets.channel_info(*test_input) == expected
@pytest.mark.parametrize(
("test_input", "expected"),
[
("#osu", b"B\x00\x00\x06\x00\x00\x00\x0b\x04#osu"),
("", b"B\x00\x00\x01\x00\x00\x00\x00"),
],
)
def test_write_channel_kick(test_input, expected):
assert app.packets.channel_kick(test_input) == expected
@pytest.mark.parametrize(
("test_input", "expected"),
[
(
("#osu", "le topique", 123),
b"C\x00\x00\x14\x00\x00\x00\x0b\x04#osu\x0b\nle topique{\x00",
),
(("", "", 0), b"C\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00"),
],
)
def test_write_channel_auto_join(test_input, expected):
assert app.packets.channel_auto_join(*test_input) == expected
# TODO: test_write_beatmap_info_reply? it's disabled in
# app.packets but perhaps for completion i can keep it in
@pytest.mark.parametrize(
("test_input", "expected"),
[
(0, b"G\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00"),
(2_147_483_647, b"G\x00\x00\x04\x00\x00\x00\xff\xff\xff\x7f"),
],
)
def test_write_bancho_privileges(test_input, expected):
assert app.packets.bancho_privileges(test_input) == expected
@pytest.mark.parametrize(
("test_input", "expected"),
[
(
[1, 4, 1001],
b"H\x00\x00\x0e\x00\x00\x00\x03\x00\x01\x00\x00\x00\x04\x00\x00\x00\xe9\x03\x00\x00",
),
(
[],
b"H\x00\x00\x02\x00\x00\x00\x00\x00",
),
],
)
def test_write_friends_list(test_input, expected):
assert app.packets.friends_list(test_input) == expected
@pytest.mark.parametrize(
("test_input", "expected"),
[
(0, b"K\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00"),
(2_147_483_647, b"K\x00\x00\x04\x00\x00\x00\xff\xff\xff\x7f"),
],
)
def test_write_protocol_version(test_input, expected):
assert app.packets.protocol_version(test_input) == expected
@pytest.mark.parametrize(
("test_input", "expected"),
[
(
("https://icon-url.ca/a.png", "https://onclick-url.ca/a.png"),
b"L\x00\x008\x00\x00\x00\x0b6https://icon-url.ca/a.png|https://onclick-url.ca/a.png",
),
(
("", ""),
b"L\x00\x00\x03\x00\x00\x00\x0b\x01|",
),
],
)
def test_write_main_menu_icon(test_input, expected):
assert app.packets.main_menu_icon(*test_input) == expected
def test_write_monitor():
assert app.packets.monitor() == b"P\x00\x00\x00\x00\x00\x00"
@pytest.mark.parametrize(
("test_input", "expected"),
[
(0, b"Q\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00"),
(2_147_483_647, b"Q\x00\x00\x04\x00\x00\x00\xff\xff\xff\x7f"),
],
)
def test_write_match_player_skipped(test_input, expected):
assert app.packets.match_player_skipped(test_input) == expected
@pytest.mark.parametrize(
("test_input", "expected"),
[
(
{
"user_id": 1001,
"name": "cmyui",
"utc_offset": -5,
"country_code": 38,
"bancho_privileges": 31, # owner|dev|supporter|mod|player
"mode": 0,
"longitude": 43.768,
"latitude": -79.522,
"global_rank": 42,
},
b"S\x00\x00\x1a\x00\x00\x00\xe9\x03\x00\x00\x0b\x05cmyui\x13&\x1fo\x12/BD\x0b\x9f\xc2*\x00\x00\x00",
),
(
{
"user_id": 0,
"name": "",
"utc_offset": 0,
"country_code": 0,
"bancho_privileges": 0,
"mode": 0,
"longitude": 0.0,
"latitude": 0.0,
"global_rank": 0,
},
b"S\x00\x00\x14\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
),
],
)
def test_write_user_presence(test_input, expected):
assert app.packets._user_presence(**test_input) == expected
@pytest.mark.parametrize(
("test_input", "expected"),
[
(0, b"V\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00"),
(2_147_483_647, b"V\x00\x00\x04\x00\x00\x00\xff\xff\xff\x7f"),
],
)
def test_write_restart_server(test_input, expected):
assert app.packets.restart_server(test_input) == expected
@pytest.mark.xfail(reason="need to remove bancho.py match object")
@pytest.mark.parametrize(
("test_input", "expected"),
[
({"p": None, "t_name": "cover"}, b""),
({"p": None, "t_name": "cover"}, b""),
],
)
def test_write_match_invite(test_input, expected):
assert app.packets.match_invite(**test_input) == expected
def test_channel_info_end():
assert app.packets.channel_info_end() == b"Y\x00\x00\x00\x00\x00\x00"
@pytest.mark.parametrize(
("test_input", "expected"),
[
("newpassword", b"[\x00\x00\x0d\x00\x00\x00\x0b\x0bnewpassword"),
("", b"[\x00\x00\x01\x00\x00\x00\x00"),
],
)
def test_write_match_change_password(test_input, expected):
assert app.packets.match_change_password(test_input) == expected
@pytest.mark.parametrize(
("test_input", "expected"),
[
(0, b"\\\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00"),
(2_147_483_647, b"\\\x00\x00\x04\x00\x00\x00\xff\xff\xff\x7f"),
],
)
def test_write_silence_end(test_input, expected):
assert app.packets.silence_end(test_input) == expected
@pytest.mark.parametrize(
("test_input", "expected"),
[
(0, b"^\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00"),
(2_147_483_647, b"^\x00\x00\x04\x00\x00\x00\xff\xff\xff\x7f"),
],
)
def test_write_user_silenced(test_input, expected):
assert app.packets.user_silenced(test_input) == expected
@pytest.mark.parametrize(
("test_input", "expected"),
[
(0, b"_\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00"),
(2_147_483_647, b"_\x00\x00\x04\x00\x00\x00\xff\xff\xff\x7f"),
],
)
def test_write_user_presence_single(test_input, expected):
assert app.packets.user_presence_single(test_input) == expected
@pytest.mark.parametrize(
("test_input", "expected"),
[
(
[1, 4, 1001],
b"`\x00\x00\x0e\x00\x00\x00\x03\x00\x01\x00\x00\x00\x04\x00\x00\x00\xe9\x03\x00\x00",
),
(
[],
b"`\x00\x00\x02\x00\x00\x00\x00\x00",
),
],
)
def test_write_user_presence_bundle(test_input, expected):
assert app.packets.user_presence_bundle(test_input) == expected
@pytest.mark.parametrize(
("test_input", "expected"),
[
("cover", b"d\x00\x00\r\x00\x00\x00\x00\x00\x0b\x05cover\x00\x00\x00\x00"),
("", b"d\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
],
)
def test_write_user_dm_blocked(test_input, expected):
assert app.packets.user_dm_blocked(test_input) == expected
@pytest.mark.parametrize(
("test_input", "expected"),
[
("cover", b"e\x00\x00\r\x00\x00\x00\x00\x00\x0b\x05cover\x00\x00\x00\x00"),
("", b"e\x00\x00\x07\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"),
],
)
def test_write_target_silenced(test_input, expected):
assert app.packets.target_silenced(test_input) == expected
def test_write_version_update_forced():
assert app.packets.version_update_forced() == b"f\x00\x00\x00\x00\x00\x00"
@pytest.mark.parametrize(
("test_input", "expected"),
[
(0, b"g\x00\x00\x04\x00\x00\x00\x00\x00\x00\x00"),
(2_147_483_647, b"g\x00\x00\x04\x00\x00\x00\xff\xff\xff\x7f"),
],
)
def test_write_switch_server(test_input, expected):
assert app.packets.switch_server(test_input) == expected
def test_write_account_restricted():
assert app.packets.account_restricted() == b"h\x00\x00\x00\x00\x00\x00"
@pytest.mark.parametrize(
("test_input", "expected"),
[
("yoyoo rip rtx", b"i\x00\x00\x0f\x00\x00\x00\x0b\ryoyoo rip rtx"),
("", b"i\x00\x00\x01\x00\x00\x00\x00"),
],
)
def test_write_rtx(test_input, expected):
assert app.packets.rtx(test_input) == expected
def test_write_match_abort():
assert app.packets.match_abort() == b"j\x00\x00\x00\x00\x00\x00"
@pytest.mark.parametrize(
("test_input", "expected"),
[
(
"61.91.139.24",
b"k\x00\x00\x0e\x00\x00\x00\x0b\x0c61.91.139.24",
),
("", b"k\x00\x00\x01\x00\x00\x00\x00"),
],
)
def test_write_switch_tournament_server(test_input, expected):
assert app.packets.switch_tournament_server(test_input) == expected