# HG changeset patch # User alfadur # Date 1643642689 -10800 # Node ID ea459da15b30f89839d31559eb5c473f5b683e3a # Parent d5e6c8c92d8797bf9acbcba6ba9784a625fb9191 update protocol 📦 diff -r d5e6c8c92d87 -r ea459da15b30 rust/hedgewars-network-protocol/Cargo.toml --- a/rust/hedgewars-network-protocol/Cargo.toml Fri Jan 28 02:33:44 2022 +0300 +++ b/rust/hedgewars-network-protocol/Cargo.toml Mon Jan 31 18:24:49 2022 +0300 @@ -2,11 +2,12 @@ name = "hedgewars-network-protocol" version = "0.1.0" authors = ["Andrey Korotaev "] -edition = "2018" +edition = "2021" [dependencies] -nom = "6" +nom = "7.1" serde_derive = "1.0" serde = "1.0" +[dev-dependencies] proptest = "1.0" \ No newline at end of file diff -r d5e6c8c92d87 -r ea459da15b30 rust/hedgewars-network-protocol/src/lib.rs --- a/rust/hedgewars-network-protocol/src/lib.rs Fri Jan 28 02:33:44 2022 +0300 +++ b/rust/hedgewars-network-protocol/src/lib.rs Mon Jan 31 18:24:49 2022 +0300 @@ -1,3 +1,5 @@ pub mod messages; pub mod parser; +#[cfg(test)] +mod tests; pub mod types; diff -r d5e6c8c92d87 -r ea459da15b30 rust/hedgewars-network-protocol/src/messages.rs --- a/rust/hedgewars-network-protocol/src/messages.rs Fri Jan 28 02:33:44 2022 +0300 +++ b/rust/hedgewars-network-protocol/src/messages.rs Mon Jan 31 18:24:49 2022 +0300 @@ -260,7 +260,7 @@ macro_rules! msg { [$($part: expr),*] => { - format!(concat!($(const_braces!($part)),*, "\n"), $($part),*); + format!(concat!($(const_braces!($part)),*, "\n"), $($part),*) }; } diff -r d5e6c8c92d87 -r ea459da15b30 rust/hedgewars-network-protocol/src/parser.rs --- a/rust/hedgewars-network-protocol/src/parser.rs Fri Jan 28 02:33:44 2022 +0300 +++ b/rust/hedgewars-network-protocol/src/parser.rs Mon Jan 31 18:24:49 2022 +0300 @@ -23,8 +23,10 @@ str::{FromStr, Utf8Error}, }; -use crate::messages::{HwProtocolMessage, HwProtocolMessage::*, HwServerMessage}; -use crate::types::{GameCfg, HedgehogInfo, ServerVar, TeamInfo, VoteType}; +use crate::{ + messages::{HwProtocolMessage, HwProtocolMessage::*, HwServerMessage}, + types::{GameCfg, HedgehogInfo, ServerVar, TeamInfo, VoteType}, +}; #[derive(Debug, PartialEq)] pub struct HwProtocolError {} @@ -493,8 +495,8 @@ )), ), |values| CheckedOk(values.unwrap_or_default()), - ) -))(input) + ), + ))(input) } pub fn malformed_message(input: &[u8]) -> HwResult<()> { diff -r d5e6c8c92d87 -r ea459da15b30 rust/hedgewars-network-protocol/src/tests/mod.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/hedgewars-network-protocol/src/tests/mod.rs Mon Jan 31 18:24:49 2022 +0300 @@ -0,0 +1,2 @@ +mod parser; +mod test; diff -r d5e6c8c92d87 -r ea459da15b30 rust/hedgewars-network-protocol/src/tests/parser.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/hedgewars-network-protocol/src/tests/parser.rs Mon Jan 31 18:24:49 2022 +0300 @@ -0,0 +1,76 @@ +use crate::{ + parser::HwProtocolError, + parser::{message, server_message}, + types::GameCfg, +}; + +#[test] +fn parse_test() { + use crate::messages::HwProtocolMessage::*; + + assert_eq!(message(b"PING\n\n"), Ok((&b""[..], Ping))); + assert_eq!(message(b"START_GAME\n\n"), Ok((&b""[..], StartGame))); + assert_eq!( + message(b"NICK\nit's me\n\n"), + Ok((&b""[..], Nick("it's me".to_string()))) + ); + assert_eq!(message(b"PROTO\n51\n\n"), Ok((&b""[..], Proto(51)))); + assert_eq!( + message(b"QUIT\nbye-bye\n\n"), + Ok((&b""[..], Quit(Some("bye-bye".to_string())))) + ); + assert_eq!(message(b"QUIT\n\n"), Ok((&b""[..], Quit(None)))); + assert_eq!( + message(b"CMD\nwatch 49471\n\n"), + Ok((&b""[..], Watch(49471))) + ); + assert_eq!( + message(b"BAN\nme\nbad\n77\n\n"), + Ok((&b""[..], Ban("me".to_string(), "bad".to_string(), 77))) + ); + + assert_eq!(message(b"CMD\nPART\n\n"), Ok((&b""[..], Part(None)))); + assert_eq!( + message(b"CMD\nPART _msg_\n\n"), + Ok((&b""[..], Part(Some("_msg_".to_string())))) + ); + + assert_eq!(message(b"CMD\nRND\n\n"), Ok((&b""[..], Rnd(vec![])))); + assert_eq!( + message(b"CMD\nRND A B\n\n"), + Ok((&b""[..], Rnd(vec![String::from("A"), String::from("B")]))) + ); + + assert_eq!( + message(b"CFG\nSCHEME\na\nA\n\n"), + Ok(( + &b""[..], + Cfg(GameCfg::Scheme("a".to_string(), vec!["A".to_string()])) + )) + ); + + assert_eq!( + message(b"QUIT\n1\n2\n\n"), + Err(nom::Err::Error(HwProtocolError::new())) + ); +} + +#[test] +fn parse_server_messages_test() { + use crate::messages::HwServerMessage::*; + + assert_eq!(server_message(b"PING\n\n"), Ok((&b""[..], Ping))); + + assert_eq!( + server_message(b"JOINING\nnoone\n\n"), + Ok((&b""[..], Joining("noone".to_string()))) + ); + + assert_eq!( + server_message(b"CLIENT_FLAGS\naaa\nA\nB\n\n"), + Ok(( + &b""[..], + ClientFlags("aaa".to_string(), vec!["A".to_string(), "B".to_string()]) + )) + ) +} diff -r d5e6c8c92d87 -r ea459da15b30 rust/hedgewars-network-protocol/src/tests/test.rs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/rust/hedgewars-network-protocol/src/tests/test.rs Mon Jan 31 18:24:49 2022 +0300 @@ -0,0 +1,325 @@ +use crate::{ + messages::{HwProtocolMessage, HwServerMessage}, + parser::{message, server_message}, + types::ServerVar::*, + types::*, + types::{GameCfg, ServerVar, TeamInfo, VoteType}, +}; + +use proptest::{ + arbitrary::{any, Arbitrary}, + proptest, + strategy::{BoxedStrategy, Just, Strategy}, +}; + +// Due to inability to define From between Options +pub trait Into2: Sized { + fn into2(self) -> T; +} +impl Into2 for T { + fn into2(self) -> T { + self + } +} +impl Into2> for Vec { + fn into2(self) -> Vec { + self.into_iter().map(|x| x.0).collect() + } +} +impl Into2 for Ascii { + fn into2(self) -> String { + self.0 + } +} +impl Into2> for Option { + fn into2(self) -> Option { + self.map(|x| x.0) + } +} + +#[macro_export] +macro_rules! proto_msg_case { + ($val: ident()) => { + Just($val) + }; + ($val: ident($arg: ty)) => { + any::<$arg>().prop_map(|v| $val(v.into2())) + }; + ($val: ident($arg1: ty, $arg2: ty)) => { + any::<($arg1, $arg2)>().prop_map(|v| $val(v.0.into2(), v.1.into2())) + }; + ($val: ident($arg1: ty, $arg2: ty, $arg3: ty)) => { + any::<($arg1, $arg2, $arg3)>().prop_map(|v| $val(v.0.into2(), v.1.into2(), v.2.into2())) + }; +} + +macro_rules! proto_msg_match { +($var: expr, def = $default: expr, $($num: expr => $constr: ident $res: tt),*) => ( + match $var { + $($num => (proto_msg_case!($constr $res)).boxed()),*, + _ => Just($default).boxed() + } +) +} + +/// Wrapper type for generating non-empty strings +#[derive(Debug)] +pub struct Ascii(String); + +impl Arbitrary for Ascii { + type Parameters = ::Parameters; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + "[a-zA-Z0-9]+".prop_map(Ascii).boxed() + } + + type Strategy = BoxedStrategy; +} + +impl Arbitrary for GameCfg { + type Parameters = (); + + fn arbitrary_with(_args: ::Parameters) -> ::Strategy { + use crate::types::GameCfg::*; + (0..10) + .no_shrink() + .prop_flat_map(|i| { + proto_msg_match!(i, def = FeatureSize(0), + 0 => FeatureSize(u32), + 1 => MapType(Ascii), + 2 => MapGenerator(u32), + 3 => MazeSize(u32), + 4 => Seed(Ascii), + 5 => Template(u32), + 6 => Ammo(Ascii, Option), + 7 => Scheme(Ascii, Vec), + 8 => Script(Ascii), + 9 => Theme(Ascii), + 10 => DrawnMap(Ascii)) + }) + .boxed() + } + + type Strategy = BoxedStrategy; +} + +impl Arbitrary for TeamInfo { + type Parameters = (); + + fn arbitrary_with(_args: ::Parameters) -> ::Strategy { + ( + "[a-z]+", + 0u8..127u8, + "[a-z]+", + "[a-z]+", + "[a-z]+", + "[a-z]+", + 0u8..127u8, + ) + .prop_map(|(name, color, grave, fort, voice_pack, flag, difficulty)| { + fn hog(n: u8) -> HedgehogInfo { + HedgehogInfo { + name: format!("hog{}", n), + hat: format!("hat{}", n), + } + } + let hedgehogs = [ + hog(1), + hog(2), + hog(3), + hog(4), + hog(5), + hog(6), + hog(7), + hog(8), + ]; + TeamInfo { + owner: String::new(), + name, + color, + grave, + fort, + voice_pack, + flag, + difficulty, + hedgehogs, + hedgehogs_number: 0, + } + }) + .boxed() + } + + type Strategy = BoxedStrategy; +} + +impl Arbitrary for ServerVar { + type Parameters = (); + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + (0..=2) + .no_shrink() + .prop_flat_map(|i| { + proto_msg_match!(i, def = ServerVar::LatestProto(0), + 0 => MOTDNew(Ascii), + 1 => MOTDOld(Ascii), + 2 => LatestProto(u16) + ) + }) + .boxed() + } + + type Strategy = BoxedStrategy; +} + +impl Arbitrary for VoteType { + type Parameters = (); + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + use VoteType::*; + (0..=4) + .no_shrink() + .prop_flat_map(|i| { + proto_msg_match!(i, def = VoteType::Pause, + 0 => Kick(Ascii), + 1 => Map(Option), + 2 => Pause(), + 3 => NewSeed(), + 4 => HedgehogsPerTeam(u8) + ) + }) + .boxed() + } + + type Strategy = BoxedStrategy; +} + +pub fn gen_proto_msg() -> BoxedStrategy where { + use HwProtocolMessage::*; + + let res = (0..=58).no_shrink().prop_flat_map(|i| { + proto_msg_match!(i, def = Ping, + 0 => Ping(), + 1 => Pong(), + 2 => Quit(Option), + 4 => Global(Ascii), + 5 => Watch(u32), + 6 => ToggleServerRegisteredOnly(), + 7 => SuperPower(), + 8 => Info(Ascii), + 9 => Nick(Ascii), + 10 => Proto(u16), + 11 => Password(Ascii, Ascii), + 12 => Checker(u16, Ascii, Ascii), + 13 => List(), + 14 => Chat(Ascii), + 15 => CreateRoom(Ascii, Option), + 16 => JoinRoom(Ascii, Option), + 17 => Follow(Ascii), + 18 => Rnd(Vec), + 19 => Kick(Ascii), + 20 => Ban(Ascii, Ascii, u32), + 21 => BanIp(Ascii, Ascii, u32), + 22 => BanNick(Ascii, Ascii, u32), + 23 => BanList(), + 24 => Unban(Ascii), + 25 => SetServerVar(ServerVar), + 26 => GetServerVar(), + 27 => RestartServer(), + 28 => Stats(), + 29 => Part(Option), + 30 => Cfg(GameCfg), + 31 => AddTeam(Box), + 32 => RemoveTeam(Ascii), + 33 => SetHedgehogsNumber(Ascii, u8), + 34 => SetTeamColor(Ascii, u8), + 35 => ToggleReady(), + 36 => StartGame(), + 37 => EngineMessage(Ascii), + 38 => RoundFinished(), + 39 => ToggleRestrictJoin(), + 40 => ToggleRestrictTeams(), + 41 => ToggleRegisteredOnly(), + 42 => RoomName(Ascii), + 43 => Delegate(Ascii), + 44 => TeamChat(Ascii), + 45 => MaxTeams(u8), + 46 => Fix(), + 47 => Unfix(), + 48 => Greeting(Option), + 49 => CallVote(Option), + 50 => Vote(bool), + 51 => ForceVote(bool), + 52 => Save(Ascii, Ascii), + 53 => Delete(Ascii), + 54 => SaveRoom(Ascii), + 55 => LoadRoom(Ascii), + 56 => CheckerReady(), + 57 => CheckedOk(Vec), + 58 => CheckedFail(Ascii) + ) + }); + res.boxed() +} + +pub fn gen_server_msg() -> BoxedStrategy where { + use HwServerMessage::*; + + let res = (0..=38).no_shrink().prop_flat_map(|i| { + proto_msg_match!(i, def = Ping, + 0 => Connected(Ascii, u32), + 1 => Redirect(u16), + 2 => Ping(), + 3 => Pong(), + 4 => Bye(Ascii), + 5 => Nick(Ascii), + 6 => Proto(u16), + 7 => AskPassword(Ascii), + 8 => ServerAuth(Ascii), + 9 => LogonPassed(), + 10 => LobbyLeft(Ascii, Ascii), + 11 => LobbyJoined(Vec), + // 12 => ChatMsg { Ascii, Ascii }, + 13 => ClientFlags(Ascii, Vec), + 14 => Rooms(Vec), + 15 => RoomAdd(Vec), + 16=> RoomJoined(Vec), + 17 => RoomLeft(Ascii, Ascii), + 18 => RoomRemove(Ascii), + 19 => RoomUpdated(Ascii, Vec), + 20 => Joining(Ascii), + 21 => TeamAdd(Vec), + 22 => TeamRemove(Ascii), + 23 => TeamAccepted(Ascii), + 24 => TeamColor(Ascii, u8), + 25 => HedgehogsNumber(Ascii, u8), + 26 => ConfigEntry(Ascii, Vec), + 27 => Kicked(), + 28 => RunGame(), + 29 => ForwardEngineMessage(Vec), + 30 => RoundFinished(), + 31 => ReplayStart(), + 32 => Info(Vec), + 33 => ServerMessage(Ascii), + 34 => ServerVars(Vec), + 35 => Notice(Ascii), + 36 => Warning(Ascii), + 37 => Error(Ascii), + 38 => Replay(Vec) + ) + }); + res.boxed() +} + +proptest! { + #[test] + fn is_parser_composition_idempotent(ref msg in gen_proto_msg()) { + println!("!! Msg: {:?}, Bytes: {:?} !!", msg, msg.to_raw_protocol().as_bytes()); + assert_eq!(message(msg.to_raw_protocol().as_bytes()), Ok((&b""[..], msg.clone()))) + } + + #[test] + fn is_server_message_parser_composition_idempotent(ref msg in gen_server_msg()) { + println!("!! Msg: {:?}, Bytes: {:?} !!", msg, msg.to_raw_protocol().as_bytes()); + assert_eq!(server_message(msg.to_raw_protocol().as_bytes()), Ok((&b""[..], msg.clone()))) + } +} diff -r d5e6c8c92d87 -r ea459da15b30 rust/hedgewars-network-protocol/src/types.rs --- a/rust/hedgewars-network-protocol/src/types.rs Fri Jan 28 02:33:44 2022 +0300 +++ b/rust/hedgewars-network-protocol/src/types.rs Mon Jan 31 18:24:49 2022 +0300 @@ -163,196 +163,3 @@ pub is_pro: bool, pub is_forced: bool, } - -//#[cfg(test)] -#[macro_use] -pub mod testing { - use crate::types::ServerVar::*; - use crate::types::*; - use proptest::{ - arbitrary::{any, Arbitrary}, - strategy::{BoxedStrategy, Just, Strategy}, - }; - - // Due to inability to define From between Options - pub trait Into2: Sized { - fn into2(self) -> T; - } - impl Into2 for T { - fn into2(self) -> T { - self - } - } - impl Into2> for Vec { - fn into2(self) -> Vec { - self.into_iter().map(|x| x.0).collect() - } - } - impl Into2 for Ascii { - fn into2(self) -> String { - self.0 - } - } - impl Into2> for Option { - fn into2(self) -> Option { - self.map(|x| x.0) - } - } - - #[macro_export] - macro_rules! proto_msg_case { - ($val: ident()) => { - Just($val) - }; - ($val: ident($arg: ty)) => { - any::<$arg>().prop_map(|v| $val(v.into2())) - }; - ($val: ident($arg1: ty, $arg2: ty)) => { - any::<($arg1, $arg2)>().prop_map(|v| $val(v.0.into2(), v.1.into2())) - }; - ($val: ident($arg1: ty, $arg2: ty, $arg3: ty)) => { - any::<($arg1, $arg2, $arg3)>().prop_map(|v| $val(v.0.into2(), v.1.into2(), v.2.into2())) - }; - } - - #[macro_export] - macro_rules! proto_msg_match { - ($var: expr, def = $default: expr, $($num: expr => $constr: ident $res: tt),*) => ( - match $var { - $($num => (proto_msg_case!($constr $res)).boxed()),*, - _ => Just($default).boxed() - } - ) -} - - /// Wrapper type for generating non-empty strings - #[derive(Debug)] - pub struct Ascii(String); - - impl Arbitrary for Ascii { - type Parameters = ::Parameters; - - fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { - "[a-zA-Z0-9]+".prop_map(Ascii).boxed() - } - - type Strategy = BoxedStrategy; - } - - impl Arbitrary for GameCfg { - type Parameters = (); - - fn arbitrary_with(_args: ::Parameters) -> ::Strategy { - use crate::types::GameCfg::*; - (0..10) - .no_shrink() - .prop_flat_map(|i| { - proto_msg_match!(i, def = FeatureSize(0), - 0 => FeatureSize(u32), - 1 => MapType(Ascii), - 2 => MapGenerator(u32), - 3 => MazeSize(u32), - 4 => Seed(Ascii), - 5 => Template(u32), - 6 => Ammo(Ascii, Option), - 7 => Scheme(Ascii, Vec), - 8 => Script(Ascii), - 9 => Theme(Ascii), - 10 => DrawnMap(Ascii)) - }) - .boxed() - } - - type Strategy = BoxedStrategy; - } - - impl Arbitrary for TeamInfo { - type Parameters = (); - - fn arbitrary_with(_args: ::Parameters) -> ::Strategy { - ( - "[a-z]+", - 0u8..127u8, - "[a-z]+", - "[a-z]+", - "[a-z]+", - "[a-z]+", - 0u8..127u8, - ) - .prop_map(|(name, color, grave, fort, voice_pack, flag, difficulty)| { - fn hog(n: u8) -> HedgehogInfo { - HedgehogInfo { - name: format!("hog{}", n), - hat: format!("hat{}", n), - } - } - let hedgehogs = [ - hog(1), - hog(2), - hog(3), - hog(4), - hog(5), - hog(6), - hog(7), - hog(8), - ]; - TeamInfo { - owner: String::new(), - name, - color, - grave, - fort, - voice_pack, - flag, - difficulty, - hedgehogs, - hedgehogs_number: 0, - } - }) - .boxed() - } - - type Strategy = BoxedStrategy; - } - - impl Arbitrary for ServerVar { - type Parameters = (); - - fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { - (0..=2) - .no_shrink() - .prop_flat_map(|i| { - proto_msg_match!(i, def = ServerVar::LatestProto(0), - 0 => MOTDNew(Ascii), - 1 => MOTDOld(Ascii), - 2 => LatestProto(u16) - ) - }) - .boxed() - } - - type Strategy = BoxedStrategy; - } - - impl Arbitrary for VoteType { - type Parameters = (); - - fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { - use VoteType::*; - (0..=4) - .no_shrink() - .prop_flat_map(|i| { - proto_msg_match!(i, def = VoteType::Pause, - 0 => Kick(Ascii), - 1 => Map(Option), - 2 => Pause(), - 3 => NewSeed(), - 4 => HedgehogsPerTeam(u8) - ) - }) - .boxed() - } - - type Strategy = BoxedStrategy; - } -} diff -r d5e6c8c92d87 -r ea459da15b30 rust/hedgewars-network-protocol/tests/parser.rs --- a/rust/hedgewars-network-protocol/tests/parser.rs Fri Jan 28 02:33:44 2022 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,76 +0,0 @@ -use hedgewars_network_protocol::{ - parser::HwProtocolError, - parser::{message, server_message}, - types::GameCfg, -}; - -#[test] -fn parse_test() { - use hedgewars_network_protocol::messages::HwProtocolMessage::*; - - assert_eq!(message(b"PING\n\n"), Ok((&b""[..], Ping))); - assert_eq!(message(b"START_GAME\n\n"), Ok((&b""[..], StartGame))); - assert_eq!( - message(b"NICK\nit's me\n\n"), - Ok((&b""[..], Nick("it's me".to_string()))) - ); - assert_eq!(message(b"PROTO\n51\n\n"), Ok((&b""[..], Proto(51)))); - assert_eq!( - message(b"QUIT\nbye-bye\n\n"), - Ok((&b""[..], Quit(Some("bye-bye".to_string())))) - ); - assert_eq!(message(b"QUIT\n\n"), Ok((&b""[..], Quit(None)))); - assert_eq!( - message(b"CMD\nwatch 49471\n\n"), - Ok((&b""[..], Watch(49471))) - ); - assert_eq!( - message(b"BAN\nme\nbad\n77\n\n"), - Ok((&b""[..], Ban("me".to_string(), "bad".to_string(), 77))) - ); - - assert_eq!(message(b"CMD\nPART\n\n"), Ok((&b""[..], Part(None)))); - assert_eq!( - message(b"CMD\nPART _msg_\n\n"), - Ok((&b""[..], Part(Some("_msg_".to_string())))) - ); - - assert_eq!(message(b"CMD\nRND\n\n"), Ok((&b""[..], Rnd(vec![])))); - assert_eq!( - message(b"CMD\nRND A B\n\n"), - Ok((&b""[..], Rnd(vec![String::from("A"), String::from("B")]))) - ); - - assert_eq!( - message(b"CFG\nSCHEME\na\nA\n\n"), - Ok(( - &b""[..], - Cfg(GameCfg::Scheme("a".to_string(), vec!["A".to_string()])) - )) - ); - - assert_eq!( - message(b"QUIT\n1\n2\n\n"), - Err(nom::Err::Error(HwProtocolError::new())) - ); -} - -#[test] -fn parse_server_messages_test() { - use hedgewars_network_protocol::messages::HwServerMessage::*; - - assert_eq!(server_message(b"PING\n\n"), Ok((&b""[..], Ping))); - - assert_eq!( - server_message(b"JOINING\nnoone\n\n"), - Ok((&b""[..], Joining("noone".to_string()))) - ); - - assert_eq!( - server_message(b"CLIENT_FLAGS\naaa\nA\nB\n\n"), - Ok(( - &b""[..], - ClientFlags("aaa".to_string(), vec!["A".to_string(), "B".to_string()]) - )) - ) -} diff -r d5e6c8c92d87 -r ea459da15b30 rust/hedgewars-network-protocol/tests/test.rs --- a/rust/hedgewars-network-protocol/tests/test.rs Fri Jan 28 02:33:44 2022 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,143 +0,0 @@ -use proptest::{ - arbitrary::any, - proptest, - strategy::{BoxedStrategy, Just, Strategy}, -}; - -use hedgewars_network_protocol::messages::{HwProtocolMessage, HwServerMessage}; -use hedgewars_network_protocol::parser::{message, server_message}; -use hedgewars_network_protocol::types::{GameCfg, ServerVar, TeamInfo, VoteType}; - -use hedgewars_network_protocol::types::testing::*; -use hedgewars_network_protocol::{proto_msg_case, proto_msg_match}; - -pub fn gen_proto_msg() -> BoxedStrategy where { - use hedgewars_network_protocol::messages::HwProtocolMessage::*; - - let res = (0..=58).no_shrink().prop_flat_map(|i| { - proto_msg_match!(i, def = Ping, - 0 => Ping(), - 1 => Pong(), - 2 => Quit(Option), - 4 => Global(Ascii), - 5 => Watch(u32), - 6 => ToggleServerRegisteredOnly(), - 7 => SuperPower(), - 8 => Info(Ascii), - 9 => Nick(Ascii), - 10 => Proto(u16), - 11 => Password(Ascii, Ascii), - 12 => Checker(u16, Ascii, Ascii), - 13 => List(), - 14 => Chat(Ascii), - 15 => CreateRoom(Ascii, Option), - 16 => JoinRoom(Ascii, Option), - 17 => Follow(Ascii), - 18 => Rnd(Vec), - 19 => Kick(Ascii), - 20 => Ban(Ascii, Ascii, u32), - 21 => BanIp(Ascii, Ascii, u32), - 22 => BanNick(Ascii, Ascii, u32), - 23 => BanList(), - 24 => Unban(Ascii), - 25 => SetServerVar(ServerVar), - 26 => GetServerVar(), - 27 => RestartServer(), - 28 => Stats(), - 29 => Part(Option), - 30 => Cfg(GameCfg), - 31 => AddTeam(Box), - 32 => RemoveTeam(Ascii), - 33 => SetHedgehogsNumber(Ascii, u8), - 34 => SetTeamColor(Ascii, u8), - 35 => ToggleReady(), - 36 => StartGame(), - 37 => EngineMessage(Ascii), - 38 => RoundFinished(), - 39 => ToggleRestrictJoin(), - 40 => ToggleRestrictTeams(), - 41 => ToggleRegisteredOnly(), - 42 => RoomName(Ascii), - 43 => Delegate(Ascii), - 44 => TeamChat(Ascii), - 45 => MaxTeams(u8), - 46 => Fix(), - 47 => Unfix(), - 48 => Greeting(Option), - 49 => CallVote(Option), - 50 => Vote(bool), - 51 => ForceVote(bool), - 52 => Save(Ascii, Ascii), - 53 => Delete(Ascii), - 54 => SaveRoom(Ascii), - 55 => LoadRoom(Ascii), - 56 => CheckerReady(), - 57 => CheckedOk(Vec), - 58 => CheckedFail(Ascii) - ) - }); - res.boxed() -} - -pub fn gen_server_msg() -> BoxedStrategy where { - use hedgewars_network_protocol::messages::HwServerMessage::*; - - let res = (0..=38).no_shrink().prop_flat_map(|i| { - proto_msg_match!(i, def = Ping, - 0 => Connected(Ascii, u32), - 1 => Redirect(u16), - 2 => Ping(), - 3 => Pong(), - 4 => Bye(Ascii), - 5 => Nick(Ascii), - 6 => Proto(u16), - 7 => AskPassword(Ascii), - 8 => ServerAuth(Ascii), - 9 => LogonPassed(), - 10 => LobbyLeft(Ascii, Ascii), - 11 => LobbyJoined(Vec), - // 12 => ChatMsg { Ascii, Ascii }, - 13 => ClientFlags(Ascii, Vec), - 14 => Rooms(Vec), - 15 => RoomAdd(Vec), - 16=> RoomJoined(Vec), - 17 => RoomLeft(Ascii, Ascii), - 18 => RoomRemove(Ascii), - 19 => RoomUpdated(Ascii, Vec), - 20 => Joining(Ascii), - 21 => TeamAdd(Vec), - 22 => TeamRemove(Ascii), - 23 => TeamAccepted(Ascii), - 24 => TeamColor(Ascii, u8), - 25 => HedgehogsNumber(Ascii, u8), - 26 => ConfigEntry(Ascii, Vec), - 27 => Kicked(), - 28 => RunGame(), - 29 => ForwardEngineMessage(Vec), - 30 => RoundFinished(), - 31 => ReplayStart(), - 32 => Info(Vec), - 33 => ServerMessage(Ascii), - 34 => ServerVars(Vec), - 35 => Notice(Ascii), - 36 => Warning(Ascii), - 37 => Error(Ascii), - 38 => Replay(Vec) - ) - }); - res.boxed() -} - -proptest! { - #[test] - fn is_parser_composition_idempotent(ref msg in gen_proto_msg()) { - println!("!! Msg: {:?}, Bytes: {:?} !!", msg, msg.to_raw_protocol().as_bytes()); - assert_eq!(message(msg.to_raw_protocol().as_bytes()), Ok((&b""[..], msg.clone()))) - } - - #[test] - fn is_server_message_parser_composition_idempotent(ref msg in gen_server_msg()) { - println!("!! Msg: {:?}, Bytes: {:?} !!", msg, msg.to_raw_protocol().as_bytes()); - assert_eq!(server_message(msg.to_raw_protocol().as_bytes()), Ok((&b""[..], msg.clone()))) - } -}