|
1 use proptest::{ |
|
2 test_runner::{TestRunner, Reason}, |
|
3 arbitrary::{any, any_with, Arbitrary, StrategyFor}, |
|
4 strategy::{Strategy, BoxedStrategy, Just, Map} |
|
5 }; |
|
6 |
|
7 use crate::server::coretypes::{GameCfg, TeamInfo, HedgehogInfo}; |
|
8 |
|
9 use super::messages::{ |
|
10 HWProtocolMessage, HWProtocolMessage::* |
|
11 }; |
|
12 |
|
13 // Due to inability to define From between Options |
|
14 trait Into2<T>: Sized { fn into2(self) -> T; } |
|
15 impl <T> Into2<T> for T { fn into2(self) -> T { self } } |
|
16 impl Into2<Vec<String>> for Vec<Ascii> { |
|
17 fn into2(self) -> Vec<String> { |
|
18 self.into_iter().map(|x| x.0).collect() |
|
19 } |
|
20 } |
|
21 impl Into2<String> for Ascii { fn into2(self) -> String { self.0 } } |
|
22 impl Into2<Option<String>> for Option<Ascii>{ |
|
23 fn into2(self) -> Option<String> { self.map(|x| {x.0}) } |
|
24 } |
|
25 |
|
26 macro_rules! proto_msg_case { |
|
27 ($val: ident()) => |
|
28 (Just($val)); |
|
29 ($val: ident($arg: ty)) => |
|
30 (any::<$arg>().prop_map(|v| {$val(v.into2())})); |
|
31 ($val: ident($arg1: ty, $arg2: ty)) => |
|
32 (any::<($arg1, $arg2)>().prop_map(|v| {$val(v.0.into2(), v.1.into2())})); |
|
33 ($val: ident($arg1: ty, $arg2: ty, $arg3: ty)) => |
|
34 (any::<($arg1, $arg2, $arg3)>().prop_map(|v| {$val(v.0.into2(), v.1.into2(), v.2.into2())})); |
|
35 } |
|
36 |
|
37 macro_rules! proto_msg_match { |
|
38 ($var: expr, def = $default: expr, $($num: expr => $constr: ident $res: tt),*) => ( |
|
39 match $var { |
|
40 $($num => (proto_msg_case!($constr $res)).boxed()),*, |
|
41 _ => Just($default).boxed() |
|
42 } |
|
43 ) |
|
44 } |
|
45 |
|
46 /// Wrapper type for generating non-empty strings |
|
47 #[derive(Debug)] |
|
48 struct Ascii(String); |
|
49 |
|
50 impl Arbitrary for Ascii { |
|
51 type Parameters = <String as Arbitrary>::Parameters; |
|
52 |
|
53 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { |
|
54 "[a-zA-Z0-9]+".prop_map(Ascii).boxed() |
|
55 } |
|
56 |
|
57 type Strategy = BoxedStrategy<Ascii>; |
|
58 } |
|
59 |
|
60 impl Arbitrary for GameCfg { |
|
61 type Parameters = (); |
|
62 |
|
63 fn arbitrary_with(_args: <Self as Arbitrary>::Parameters) -> <Self as Arbitrary>::Strategy { |
|
64 use crate::server::coretypes::GameCfg::*; |
|
65 (0..10).no_shrink().prop_flat_map(|i| { |
|
66 proto_msg_match!(i, def = FeatureSize(0), |
|
67 0 => FeatureSize(u32), |
|
68 1 => MapType(Ascii), |
|
69 2 => MapGenerator(u32), |
|
70 3 => MazeSize(u32), |
|
71 4 => Seed(Ascii), |
|
72 5 => Template(u32), |
|
73 6 => Ammo(Ascii, Option<Ascii>), |
|
74 7 => Scheme(Ascii, Vec<Ascii>), |
|
75 8 => Script(Ascii), |
|
76 9 => Theme(Ascii), |
|
77 10 => DrawnMap(Ascii)) |
|
78 }).boxed() |
|
79 } |
|
80 |
|
81 type Strategy = BoxedStrategy<GameCfg>; |
|
82 } |
|
83 |
|
84 impl Arbitrary for TeamInfo { |
|
85 type Parameters = (); |
|
86 |
|
87 fn arbitrary_with(_args: <Self as Arbitrary>::Parameters) -> <Self as Arbitrary>::Strategy { |
|
88 ("[a-z]+", 0u8..127u8, "[a-z]+", "[a-z]+", "[a-z]+", "[a-z]+", 0u8..127u8) |
|
89 .prop_map(|(name, color, grave, fort, voice_pack, flag, difficulty)| { |
|
90 fn hog(n: u8) -> HedgehogInfo { |
|
91 HedgehogInfo { name: format!("hog{}", n), hat: format!("hat{}", n)} |
|
92 } |
|
93 let hedgehogs = [hog(1), hog(2), hog(3), hog(4), hog(5), hog(6), hog(7), hog(8)]; |
|
94 TeamInfo { |
|
95 name, color, grave, fort, |
|
96 voice_pack, flag,difficulty, |
|
97 hedgehogs, hedgehogs_number: 0 |
|
98 } |
|
99 }).boxed() |
|
100 } |
|
101 |
|
102 type Strategy = BoxedStrategy<TeamInfo>; |
|
103 } |
|
104 |
|
105 pub fn gen_proto_msg() -> BoxedStrategy<HWProtocolMessage> where { |
|
106 let res = (0..58).no_shrink().prop_flat_map(|i| { |
|
107 proto_msg_match!(i, def = Malformed, |
|
108 0 => Ping(), |
|
109 1 => Pong(), |
|
110 2 => Quit(Option<Ascii>), |
|
111 //3 => Cmd |
|
112 4 => Global(Ascii), |
|
113 5 => Watch(Ascii), |
|
114 6 => ToggleServerRegisteredOnly(), |
|
115 7 => SuperPower(), |
|
116 8 => Info(Ascii), |
|
117 9 => Nick(Ascii), |
|
118 10 => Proto(u16), |
|
119 11 => Password(Ascii, Ascii), |
|
120 12 => Checker(u16, Ascii, Ascii), |
|
121 13 => List(), |
|
122 14 => Chat(Ascii), |
|
123 15 => CreateRoom(Ascii, Option<Ascii>), |
|
124 16 => JoinRoom(Ascii, Option<Ascii>), |
|
125 17 => Follow(Ascii), |
|
126 18 => Rnd(Vec<Ascii>), |
|
127 19 => Kick(Ascii), |
|
128 20 => Ban(Ascii, Ascii, u32), |
|
129 21 => BanIP(Ascii, Ascii, u32), |
|
130 22 => BanNick(Ascii, Ascii, u32), |
|
131 23 => BanList(), |
|
132 24 => Unban(Ascii), |
|
133 //25 => SetServerVar(ServerVar), |
|
134 26 => GetServerVar(), |
|
135 27 => RestartServer(), |
|
136 28 => Stats(), |
|
137 29 => Part(Option<Ascii>), |
|
138 30 => Cfg(GameCfg), |
|
139 31 => AddTeam(Box<TeamInfo>), |
|
140 32 => RemoveTeam(Ascii), |
|
141 33 => SetHedgehogsNumber(Ascii, u8), |
|
142 34 => SetTeamColor(Ascii, u8), |
|
143 35 => ToggleReady(), |
|
144 36 => StartGame(), |
|
145 37 => EngineMessage(Ascii), |
|
146 38 => RoundFinished(), |
|
147 39 => ToggleRestrictJoin(), |
|
148 40 => ToggleRestrictTeams(), |
|
149 41 => ToggleRegisteredOnly(), |
|
150 42 => RoomName(Ascii), |
|
151 43 => Delegate(Ascii), |
|
152 44 => TeamChat(Ascii), |
|
153 45 => MaxTeams(u8), |
|
154 46 => Fix(), |
|
155 47 => Unfix(), |
|
156 48 => Greeting(Ascii), |
|
157 //49 => CallVote(Option<(String, Option<String>)>), |
|
158 50 => Vote(bool), |
|
159 51 => ForceVote(bool), |
|
160 52 => Save(Ascii, Ascii), |
|
161 53 => Delete(Ascii), |
|
162 54 => SaveRoom(Ascii), |
|
163 55 => LoadRoom(Ascii), |
|
164 56 => Malformed(), |
|
165 57 => Empty() |
|
166 )}); |
|
167 res.boxed() |
|
168 } |