From 93e80dae5f8bd3c3dce28a5a8692f61c6cfcd21f Mon Sep 17 00:00:00 2001 From: Vincent Swarte Date: Sun, 11 Aug 2024 06:27:49 +0200 Subject: [PATCH] Add some deserialization tests --- Cargo.lock | 1 + crates/message/Cargo.toml | 3 + crates/message/src/bloodmessage.rs | 52 ++++++++++++++++ crates/message/src/bloodstain.rs | 56 +++++++++++++++++- crates/message/src/player.rs | 22 +++++++ crates/message/src/sign.rs | 46 ++++++++++++++ .../test/data/RequestCreateBloodMessage.bin | Bin 0 -> 555 bytes .../test/data/RequestCreateBloodstain.bin | Bin 1443 -> 1324 bytes .../test/data/RequestGetBloodMessageList.bin | Bin 121 -> 112 bytes .../message/test/data/RequestGetSignList.bin | Bin 0 -> 69 bytes .../message/test/data/RequestUpdateSign.bin | Bin 0 -> 12 bytes .../message/test/data/RequestUseItemLog.bin | Bin 0 -> 32 bytes .../test/data/ResponseCreateBloodstain.bin | Bin 8 -> 0 bytes .../test/data/ResponseCreateSession.bin | Bin 137 -> 0 bytes .../test/data/ResponseGetBloodMessageList.bin | Bin 36080 -> 0 bytes 15 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 crates/message/test/data/RequestCreateBloodMessage.bin mode change 100755 => 100644 crates/message/test/data/RequestCreateBloodstain.bin create mode 100644 crates/message/test/data/RequestGetSignList.bin create mode 100644 crates/message/test/data/RequestUpdateSign.bin create mode 100644 crates/message/test/data/RequestUseItemLog.bin delete mode 100755 crates/message/test/data/ResponseCreateBloodstain.bin delete mode 100755 crates/message/test/data/ResponseCreateSession.bin delete mode 100644 crates/message/test/data/ResponseGetBloodMessageList.bin diff --git a/Cargo.lock b/Cargo.lock index 41c4e66..d3d7bd4 100755 --- a/Cargo.lock +++ b/Cargo.lock @@ -2896,6 +2896,7 @@ name = "waygate-message" version = "0.1.0" dependencies = [ "serde", + "waygate-wire", ] [[package]] diff --git a/crates/message/Cargo.toml b/crates/message/Cargo.toml index 50decaa..f9ec561 100644 --- a/crates/message/Cargo.toml +++ b/crates/message/Cargo.toml @@ -5,3 +5,6 @@ edition = "2021" [dependencies.serde] workspace = true + +[dependencies.waygate-wire] +workspace = true diff --git a/crates/message/src/bloodmessage.rs b/crates/message/src/bloodmessage.rs index 5a435eb..963570f 100755 --- a/crates/message/src/bloodmessage.rs +++ b/crates/message/src/bloodmessage.rs @@ -57,3 +57,55 @@ pub struct ResponseReentryBloodMessageParams { pub struct RequestRemoveBloodMessageParams { pub identifier: ObjectIdentifier, } + +#[cfg(test)] +mod test { + use waygate_wire::deserialize; + use crate::RequestGetBloodMessageListParams; + use crate::RequestCreateBloodMessageParams; + + #[test] + fn deserialize_create_bloodmessage() { + let deserialized: RequestCreateBloodMessageParams = deserialize( + include_bytes!("../test/data/RequestCreateBloodMessage.bin"), + ).unwrap(); + + assert_eq!(deserialized.area.play_region, 1400001); + assert_eq!(deserialized.area.area, 1400001); + assert_eq!(deserialized.character_id, 21); + assert_eq!(deserialized.data.len(), 520); + assert_eq!(deserialized.group_passwords.len(), 1); + assert_eq!(deserialized.group_passwords[0], "schlong"); + assert_eq!(deserialized.unk, 0); + } + + #[test] + fn deserialize_get_bloodmessage_list() { + let deserialized: RequestGetBloodMessageListParams = deserialize( + include_bytes!("../test/data/RequestGetBloodMessageList.bin"), + ).unwrap(); + + assert_eq!(deserialized.search_areas.len(), 8); + assert_eq!(deserialized.search_areas[0].play_region, 6043340); + assert_eq!(deserialized.search_areas[0].area, 6102002); + assert_eq!(deserialized.search_areas[1].play_region, 6042340); + assert_eq!(deserialized.search_areas[1].area, 6102002); + assert_eq!(deserialized.search_areas[2].play_region, 6043350); + assert_eq!(deserialized.search_areas[2].area, 6102002); + assert_eq!(deserialized.search_areas[3].play_region, 6042350); + assert_eq!(deserialized.search_areas[3].area, 6102002); + assert_eq!(deserialized.search_areas[4].play_region, 6043340); + assert_eq!(deserialized.search_areas[4].area, 6102000); + assert_eq!(deserialized.search_areas[5].play_region, 6042340); + assert_eq!(deserialized.search_areas[5].area, 600000); + assert_eq!(deserialized.search_areas[6].play_region, 6041340); + assert_eq!(deserialized.search_areas[6].area, 6102002); + assert_eq!(deserialized.search_areas[7].play_region, 6041340); + assert_eq!(deserialized.search_areas[7].area, 600000); + assert_eq!(deserialized.group_passwords.len(), 4); + assert_eq!(deserialized.group_passwords[0], "group1"); + assert_eq!(deserialized.group_passwords[1], "group2"); + assert_eq!(deserialized.group_passwords[2], "group3"); + assert_eq!(deserialized.group_passwords[3], "group4"); + } +} diff --git a/crates/message/src/bloodstain.rs b/crates/message/src/bloodstain.rs index 4520d8e..16f49c0 100755 --- a/crates/message/src/bloodstain.rs +++ b/crates/message/src/bloodstain.rs @@ -1,4 +1,4 @@ -use serde::{Serialize, Deserialize}; +use serde::{Deserialize, Serialize}; use super::*; @@ -44,3 +44,57 @@ pub struct ResponseGetDeadingGhostParams { pub identifier: ObjectIdentifier, pub replay_data: Vec, } + +#[cfg(test)] +mod test { + use waygate_wire::deserialize; + use crate::{RequestCreateBloodstainParams, RequestGetBloodstainListParams}; + + #[test] + fn deserialize_create_bloodstain() { + let deserialized: RequestCreateBloodstainParams = deserialize( + include_bytes!("../test/data/RequestCreateBloodstain.bin"), + ).unwrap(); + + assert_eq!(deserialized.area.play_region, 1400001); + assert_eq!(deserialized.area.area, 1400001); + assert_eq!(deserialized.advertisement_data.len(), 128); + assert_eq!(deserialized.replay_data.len(), 1165); + assert_eq!(deserialized.group_passwords.len(), 1); + assert_eq!(deserialized.group_passwords[0], "schlong"); + } + + #[test] + fn deserialize_get_bloodstain_list() { + let deserialized: RequestGetBloodstainListParams = deserialize( + include_bytes!("../test/data/RequestGetBloodstainList.bin"), + ).unwrap(); + + assert_eq!(deserialized.search_areas.len(), 10); + assert_eq!(deserialized.search_areas[0].play_region, 3000001); + assert_eq!(deserialized.search_areas[0].area, 3000001); + assert_eq!(deserialized.search_areas[1].play_region, 6043330); + assert_eq!(deserialized.search_areas[1].area, 6102002); + assert_eq!(deserialized.search_areas[2].play_region, 6042330); + assert_eq!(deserialized.search_areas[2].area, 6102002); + assert_eq!(deserialized.search_areas[3].play_region, 3000000); + assert_eq!(deserialized.search_areas[3].area, 3000000); + assert_eq!(deserialized.search_areas[4].play_region, 6043330); + assert_eq!(deserialized.search_areas[4].area, 6102000); + assert_eq!(deserialized.search_areas[5].play_region, 6043340); + assert_eq!(deserialized.search_areas[5].area, 6102002); + assert_eq!(deserialized.search_areas[6].play_region, 6043340); + assert_eq!(deserialized.search_areas[6].area, 6102000); + assert_eq!(deserialized.search_areas[7].play_region, 6043320); + assert_eq!(deserialized.search_areas[7].area, 6102002); + assert_eq!(deserialized.search_areas[8].play_region, 6042340); + assert_eq!(deserialized.search_areas[8].area, 6102002); + assert_eq!(deserialized.search_areas[9].play_region, 6042320); + assert_eq!(deserialized.search_areas[9].area, 6102002); + assert_eq!(deserialized.group_passwords.len(), 4); + assert_eq!(deserialized.group_passwords[0], "group1"); + assert_eq!(deserialized.group_passwords[1], "group2"); + assert_eq!(deserialized.group_passwords[2], "group3"); + assert_eq!(deserialized.group_passwords[3], "group4"); + } +} diff --git a/crates/message/src/player.rs b/crates/message/src/player.rs index 2da14f3..5dfa4df 100755 --- a/crates/message/src/player.rs +++ b/crates/message/src/player.rs @@ -232,3 +232,25 @@ pub struct RequestJoinMultiplayParams { pub unk5: u32, pub unk6: u32, } + +#[cfg(test)] +mod test { + use waygate_wire::deserialize; + use crate::{ObjectIdentifier, RequestUpdateSignParams, RequestUseItemLogParams}; + + #[test] + fn deserialize_use_item_log() { + let deserialized: RequestUseItemLogParams = deserialize( + include_bytes!("../test/data/RequestUseItemLog.bin"), + ).unwrap(); + + assert_eq!(deserialized.used_items.len(), 1); + assert_eq!(deserialized.used_items[0].item_id, 101); + assert_eq!(deserialized.used_items[0].times_used, 1); + assert_eq!(deserialized.used_items[0].unk3, 1); + assert_eq!(deserialized.location.map, 60423600); + assert_eq!(deserialized.location.x, -45.939575); + assert_eq!(deserialized.location.y, 92.36392); + assert_eq!(deserialized.location.z, 79.65545); + } +} diff --git a/crates/message/src/sign.rs b/crates/message/src/sign.rs index 806fc1f..b98c139 100755 --- a/crates/message/src/sign.rs +++ b/crates/message/src/sign.rs @@ -112,3 +112,49 @@ pub struct RequestCreateMatchAreaSignParams { pub struct ResponseCreateMatchAreaSignParams { pub identifier: ObjectIdentifier, } + +#[cfg(test)] +mod test { + use waygate_wire::deserialize; + use crate::{ObjectIdentifier, RequestGetSignListParams, RequestUpdateSignParams}; + + #[test] + fn deserialize_update_sign() { + let deserialized: RequestUpdateSignParams = deserialize( + include_bytes!("../test/data/RequestUpdateSign.bin"), + ).unwrap(); + + assert_eq!( + deserialized.identifier, + ObjectIdentifier { object_id: -1198167463, secondary_id: 328094526 } + ); + assert_eq!(deserialized.unk0, 0); + } + + #[test] + fn deserialize_get_sign_list() { + let deserialized: RequestGetSignListParams = deserialize( + include_bytes!("../test/data/RequestGetSignList.bin"), + ).unwrap(); + + // TODO: add example with known signs + assert_eq!(deserialized.known_signs.len(), 0); + assert_eq!(deserialized.search_areas.len(), 2); + assert_eq!(deserialized.search_areas[0].play_region, 1100000); + assert_eq!(deserialized.search_areas[0].area, 1100000); + assert_eq!(deserialized.search_areas[1].play_region, 1100001); + assert_eq!(deserialized.search_areas[1].area, 1100001); + assert_eq!(deserialized.matching_parameters.game_version, 11001000); + assert_eq!(deserialized.matching_parameters.unk1, 5); + assert_eq!(deserialized.matching_parameters.region_flags, 256); + assert_eq!(deserialized.matching_parameters.unk2, 0); + assert_eq!(deserialized.matching_parameters.soul_level, 99); + assert_eq!(deserialized.matching_parameters.unk3, 0); + assert_eq!(deserialized.matching_parameters.unk4, 0); + assert_eq!(deserialized.matching_parameters.clear_count, 0); + assert_eq!(deserialized.matching_parameters.password, ""); + assert_eq!(deserialized.matching_parameters.unk5, 0); + assert_eq!(deserialized.matching_parameters.max_reinforce, 22); + assert_eq!(deserialized.matching_parameters.unk6, 5); + } +} diff --git a/crates/message/test/data/RequestCreateBloodMessage.bin b/crates/message/test/data/RequestCreateBloodMessage.bin new file mode 100644 index 0000000000000000000000000000000000000000..19aa5630caecfc968d482873c04b752c52e0d68a GIT binary patch literal 555 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 O0{v75Kb7H6W%LibahSLO diff --git a/crates/message/test/data/RequestGetBloodMessageList.bin b/crates/message/test/data/RequestGetBloodMessageList.bin index 2957f84867263376796fa9793b059e69349491fa..6c65c710254bfdf15d8a1c9cd707ac6c23c08209 100644 GIT binary patch delta 5 Mcmb;{n8;ZG00vh9^Z)<= delta 14 TcmXS@iEVn!(5@OLJ&!XfiRA-i@sP4}Pg1OQUE2wVUF literal 0 HcmV?d00001 diff --git a/crates/message/test/data/ResponseCreateBloodstain.bin b/crates/message/test/data/ResponseCreateBloodstain.bin deleted file mode 100755 index 1b1cb4d44c57c2d7a5122870fa6ac3e62ff7e94e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8 KcmZQzfB*mh2mk>9 diff --git a/crates/message/test/data/ResponseCreateSession.bin b/crates/message/test/data/ResponseCreateSession.bin deleted file mode 100755 index 893e3ac6f29331c989ab4924100e4446c7a7bd1b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 137 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