rust/hedgewars-server/src/protocol/test.rs
changeset 15804 747278149393
parent 15803 b06b33cf0a89
child 15805 61da40b657fa
equal deleted inserted replaced
15803:b06b33cf0a89 15804:747278149393
     1 use proptest::{
       
     2     arbitrary::{any, any_with, Arbitrary, StrategyFor},
       
     3     strategy::{BoxedStrategy, Just, Map, Strategy},
       
     4     test_runner::{Reason, TestRunner},
       
     5 };
       
     6 
       
     7 use crate::core::types::{GameCfg, HedgehogInfo, ServerVar, ServerVar::*, TeamInfo, VoteType};
       
     8 
       
     9 use super::messages::{HwProtocolMessage, HwProtocolMessage::*};
       
    10 
       
    11 // Due to inability to define From between Options
       
    12 trait Into2<T>: Sized {
       
    13     fn into2(self) -> T;
       
    14 }
       
    15 impl<T> Into2<T> for T {
       
    16     fn into2(self) -> T {
       
    17         self
       
    18     }
       
    19 }
       
    20 impl Into2<Vec<String>> for Vec<Ascii> {
       
    21     fn into2(self) -> Vec<String> {
       
    22         self.into_iter().map(|x| x.0).collect()
       
    23     }
       
    24 }
       
    25 impl Into2<String> for Ascii {
       
    26     fn into2(self) -> String {
       
    27         self.0
       
    28     }
       
    29 }
       
    30 impl Into2<Option<String>> for Option<Ascii> {
       
    31     fn into2(self) -> Option<String> {
       
    32         self.map(|x| x.0)
       
    33     }
       
    34 }
       
    35 
       
    36 macro_rules! proto_msg_case {
       
    37     ($val: ident()) => {
       
    38         Just($val)
       
    39     };
       
    40     ($val: ident($arg: ty)) => {
       
    41         any::<$arg>().prop_map(|v| $val(v.into2()))
       
    42     };
       
    43     ($val: ident($arg1: ty, $arg2: ty)) => {
       
    44         any::<($arg1, $arg2)>().prop_map(|v| $val(v.0.into2(), v.1.into2()))
       
    45     };
       
    46     ($val: ident($arg1: ty, $arg2: ty, $arg3: ty)) => {
       
    47         any::<($arg1, $arg2, $arg3)>().prop_map(|v| $val(v.0.into2(), v.1.into2(), v.2.into2()))
       
    48     };
       
    49 }
       
    50 
       
    51 macro_rules! proto_msg_match {
       
    52     ($var: expr, def = $default: expr, $($num: expr => $constr: ident $res: tt),*) => (
       
    53         match $var {
       
    54             $($num => (proto_msg_case!($constr $res)).boxed()),*,
       
    55             _ => Just($default).boxed()
       
    56         }
       
    57     )
       
    58 }
       
    59 
       
    60 /// Wrapper type for generating non-empty strings
       
    61 #[derive(Debug)]
       
    62 struct Ascii(String);
       
    63 
       
    64 impl Arbitrary for Ascii {
       
    65     type Parameters = <String as Arbitrary>::Parameters;
       
    66 
       
    67     fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
       
    68         "[a-zA-Z0-9]+".prop_map(Ascii).boxed()
       
    69     }
       
    70 
       
    71     type Strategy = BoxedStrategy<Ascii>;
       
    72 }
       
    73 
       
    74 impl Arbitrary for GameCfg {
       
    75     type Parameters = ();
       
    76 
       
    77     fn arbitrary_with(_args: <Self as Arbitrary>::Parameters) -> <Self as Arbitrary>::Strategy {
       
    78         use crate::core::types::GameCfg::*;
       
    79         (0..10)
       
    80             .no_shrink()
       
    81             .prop_flat_map(|i| {
       
    82                 proto_msg_match!(i, def = FeatureSize(0),
       
    83             0 => FeatureSize(u32),
       
    84             1 => MapType(Ascii),
       
    85             2 => MapGenerator(u32),
       
    86             3 => MazeSize(u32),
       
    87             4 => Seed(Ascii),
       
    88             5 => Template(u32),
       
    89             6 => Ammo(Ascii, Option<Ascii>),
       
    90             7 => Scheme(Ascii, Vec<Ascii>),
       
    91             8 => Script(Ascii),
       
    92             9 => Theme(Ascii),
       
    93             10 => DrawnMap(Ascii))
       
    94             })
       
    95             .boxed()
       
    96     }
       
    97 
       
    98     type Strategy = BoxedStrategy<GameCfg>;
       
    99 }
       
   100 
       
   101 impl Arbitrary for TeamInfo {
       
   102     type Parameters = ();
       
   103 
       
   104     fn arbitrary_with(_args: <Self as Arbitrary>::Parameters) -> <Self as Arbitrary>::Strategy {
       
   105         (
       
   106             "[a-z]+",
       
   107             0u8..127u8,
       
   108             "[a-z]+",
       
   109             "[a-z]+",
       
   110             "[a-z]+",
       
   111             "[a-z]+",
       
   112             0u8..127u8,
       
   113         )
       
   114             .prop_map(|(name, color, grave, fort, voice_pack, flag, difficulty)| {
       
   115                 fn hog(n: u8) -> HedgehogInfo {
       
   116                     HedgehogInfo {
       
   117                         name: format!("hog{}", n),
       
   118                         hat: format!("hat{}", n),
       
   119                     }
       
   120                 }
       
   121                 let hedgehogs = [
       
   122                     hog(1),
       
   123                     hog(2),
       
   124                     hog(3),
       
   125                     hog(4),
       
   126                     hog(5),
       
   127                     hog(6),
       
   128                     hog(7),
       
   129                     hog(8),
       
   130                 ];
       
   131                 TeamInfo {
       
   132                     owner: String::new(),
       
   133                     name,
       
   134                     color,
       
   135                     grave,
       
   136                     fort,
       
   137                     voice_pack,
       
   138                     flag,
       
   139                     difficulty,
       
   140                     hedgehogs,
       
   141                     hedgehogs_number: 0,
       
   142                 }
       
   143             })
       
   144             .boxed()
       
   145     }
       
   146 
       
   147     type Strategy = BoxedStrategy<TeamInfo>;
       
   148 }
       
   149 
       
   150 impl Arbitrary for ServerVar {
       
   151     type Parameters = ();
       
   152 
       
   153     fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
       
   154         (0..=2)
       
   155             .no_shrink()
       
   156             .prop_flat_map(|i| {
       
   157                 proto_msg_match!(i, def = ServerVar::LatestProto(0),
       
   158                     0 => MOTDNew(Ascii),
       
   159                     1 => MOTDOld(Ascii),
       
   160                     2 => LatestProto(u16)
       
   161                 )
       
   162             })
       
   163             .boxed()
       
   164     }
       
   165 
       
   166     type Strategy = BoxedStrategy<ServerVar>;
       
   167 }
       
   168 
       
   169 impl Arbitrary for VoteType {
       
   170     type Parameters = ();
       
   171 
       
   172     fn arbitrary_with(args: Self::Parameters) -> Self::Strategy {
       
   173         use VoteType::*;
       
   174         (0..=4)
       
   175             .no_shrink()
       
   176             .prop_flat_map(|i| {
       
   177                 proto_msg_match!(i, def = VoteType::Pause,
       
   178                     0 => Kick(Ascii),
       
   179                     1 => Map(Option<Ascii>),
       
   180                     2 => Pause(),
       
   181                     3 => NewSeed(),
       
   182                     4 => HedgehogsPerTeam(u8)
       
   183                 )
       
   184             })
       
   185             .boxed()
       
   186     }
       
   187 
       
   188     type Strategy = BoxedStrategy<VoteType>;
       
   189 }
       
   190 
       
   191 pub fn gen_proto_msg() -> BoxedStrategy<HwProtocolMessage> where {
       
   192     let res = (0..=55).no_shrink().prop_flat_map(|i| {
       
   193         proto_msg_match!(i, def = Ping,
       
   194             0 => Ping(),
       
   195             1 => Pong(),
       
   196             2 => Quit(Option<Ascii>),
       
   197             4 => Global(Ascii),
       
   198             5 => Watch(u32),
       
   199             6 => ToggleServerRegisteredOnly(),
       
   200             7 => SuperPower(),
       
   201             8 => Info(Ascii),
       
   202             9 => Nick(Ascii),
       
   203             10 => Proto(u16),
       
   204             11 => Password(Ascii, Ascii),
       
   205             12 => Checker(u16, Ascii, Ascii),
       
   206             13 => List(),
       
   207             14 => Chat(Ascii),
       
   208             15 => CreateRoom(Ascii, Option<Ascii>),
       
   209             16 => JoinRoom(Ascii, Option<Ascii>),
       
   210             17 => Follow(Ascii),
       
   211             18 => Rnd(Vec<Ascii>),
       
   212             19 => Kick(Ascii),
       
   213             20 => Ban(Ascii, Ascii, u32),
       
   214             21 => BanIp(Ascii, Ascii, u32),
       
   215             22 => BanNick(Ascii, Ascii, u32),
       
   216             23 => BanList(),
       
   217             24 => Unban(Ascii),
       
   218             25 => SetServerVar(ServerVar),
       
   219             26 => GetServerVar(),
       
   220             27 => RestartServer(),
       
   221             28 => Stats(),
       
   222             29 => Part(Option<Ascii>),
       
   223             30 => Cfg(GameCfg),
       
   224             31 => AddTeam(Box<TeamInfo>),
       
   225             32 => RemoveTeam(Ascii),
       
   226             33 => SetHedgehogsNumber(Ascii, u8),
       
   227             34 => SetTeamColor(Ascii, u8),
       
   228             35 => ToggleReady(),
       
   229             36 => StartGame(),
       
   230             37 => EngineMessage(Ascii),
       
   231             38 => RoundFinished(),
       
   232             39 => ToggleRestrictJoin(),
       
   233             40 => ToggleRestrictTeams(),
       
   234             41 => ToggleRegisteredOnly(),
       
   235             42 => RoomName(Ascii),
       
   236             43 => Delegate(Ascii),
       
   237             44 => TeamChat(Ascii),
       
   238             45 => MaxTeams(u8),
       
   239             46 => Fix(),
       
   240             47 => Unfix(),
       
   241             48 => Greeting(Option<Ascii>),
       
   242             49 => CallVote(Option<VoteType>),
       
   243             50 => Vote(bool),
       
   244             51 => ForceVote(bool),
       
   245             52 => Save(Ascii, Ascii),
       
   246             53 => Delete(Ascii),
       
   247             54 => SaveRoom(Ascii),
       
   248             55 => LoadRoom(Ascii)
       
   249         )
       
   250     });
       
   251     res.boxed()
       
   252 }