Files
benilla-octo/crates/benilla-protocol/tests/quest_share.rs
T
SamandClaude Opus 5.5 bfb5c008b8 comments: protocol, the auth to reputation integration tests
1,039 comment lines become 472 across 19 files; the code is unchanged.
The movement test's claim that write() never serializes a transport
tail is gone: it does.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-23 20:12:46 +07:00

100 lines
3.7 KiB
Rust

//! The party quest-share wire: the Share Quest push, the escort confirm, and the verdict relay.
//! `MSG_QUEST_PUSH_RESULT`'s guid is the sharer going up and the member concerned coming down.
mod common;
use benilla_protocol::events::{decode, SessionEvent};
use benilla_protocol::messages::{self, opcode, quest_flags, QuestShareMsg};
use benilla_protocol::ServerPacket;
use common::hx;
/// The three CMSG bodies (vmangos `Server/Packets/Quest.cpp:63-77`).
#[test]
fn cmsg_bodies_golden() {
// CMSG_PUSHQUESTTOPARTY / CMSG_QUEST_CONFIRM_ACCEPT: one u32 quest id and no member guid; the
// server addresses the group itself.
assert_eq!(
messages::push_quest_to_party(0x1234),
hx("34120000"),
"CMSG_PUSHQUESTTOPARTY body"
);
assert_eq!(
messages::quest_confirm_accept(0x1234),
hx("34120000"),
"CMSG_QUEST_CONFIRM_ACCEPT body"
);
// MSG_QUEST_PUSH_RESULT going up: the u64 guid of the sharer we answer, then the u8 verdict
// (`Quest.cpp:73-77`).
assert_eq!(
messages::quest_push_result(0x1234_5678_9abc_def0, QuestShareMsg::DECLINE_QUEST),
hx("f0debc9a7856341203"),
"MSG_QUEST_PUSH_RESULT (client) body"
);
}
/// `MSG_QUEST_PUSH_RESULT` coming down (`Quest.cpp:81-85`): the same two fields, the guid now the
/// party member the verdict concerns.
#[test]
fn push_result_decodes_member_and_verdict() {
let body = hx("f0debc9a7856341200");
let p = messages::parse_server(opcode::MSG_QUEST_PUSH_RESULT, &body).unwrap();
match &p {
ServerPacket::QuestPushResult(r) => {
assert_eq!(r.member, 0x1234_5678_9abc_def0);
assert_eq!(r.msg, QuestShareMsg::SHARING_QUEST);
}
other => panic!("expected QuestPushResult, got {}", other.name()),
}
match decode(p).as_slice() {
[SessionEvent::QuestPushResult { member, msg }] => {
assert_eq!(*member, 0x1234_5678_9abc_def0);
assert_eq!(*msg, QuestShareMsg::SHARING_QUEST);
}
other => panic!("push result decoded to {} events", other.len()),
}
}
/// An unmapped verdict byte reaches the app as data rather than failing the parse.
#[test]
fn every_verdict_byte_round_trips() {
for raw in [0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xFF] {
let mut body = 1u64.to_le_bytes().to_vec();
body.push(raw);
match messages::parse_server(opcode::MSG_QUEST_PUSH_RESULT, &body).unwrap() {
ServerPacket::QuestPushResult(r) => {
assert_eq!(r.msg, QuestShareMsg(raw), "verdict {raw}");
assert_eq!(r.member, 1);
}
other => panic!("verdict {raw} parsed as {}", other.name()),
}
}
}
/// `SMSG_QUEST_CONFIRM_ACCEPT` (`Quest.cpp:131-136`): `u32` questId, cstring title, `u64`
/// senderGuid; the title sits between the two numbers.
#[test]
fn confirm_accept_decodes_id_title_sender() {
let mut body = 1234u32.to_le_bytes().to_vec();
body.extend_from_slice(b"Escort Duty\0");
body.extend_from_slice(&0x0000_0000_0000_002Au64.to_le_bytes());
let p = messages::parse_server(opcode::SMSG_QUEST_CONFIRM_ACCEPT, &body).unwrap();
match decode(p).as_slice() {
[SessionEvent::QuestConfirmAccept(c)] => {
assert_eq!(c.quest_id, 1234);
assert_eq!(c.title, "Escort Duty");
assert_eq!(c.sender, 0x2A);
}
other => panic!("confirm accept decoded to {} events", other.len()),
}
}
/// The two quest flags the share flow reads (vmangos `QuestDef.h:145-160`), the client's only
/// sign that a quest is shareable or an escort.
#[test]
fn share_quest_flags_are_the_documented_bits() {
assert_eq!(quest_flags::PARTY_ACCEPT, 0x2);
assert_eq!(quest_flags::SHARABLE, 0x8);
}