161 |
161 |
162 pub struct Vote { |
162 pub struct Vote { |
163 pub is_pro: bool, |
163 pub is_pro: bool, |
164 pub is_forced: bool, |
164 pub is_forced: bool, |
165 } |
165 } |
166 |
|
167 //#[cfg(test)] |
|
168 #[macro_use] |
|
169 pub mod testing { |
|
170 use crate::types::ServerVar::*; |
|
171 use crate::types::*; |
|
172 use proptest::{ |
|
173 arbitrary::{any, Arbitrary}, |
|
174 strategy::{BoxedStrategy, Just, Strategy}, |
|
175 }; |
|
176 |
|
177 // Due to inability to define From between Options |
|
178 pub trait Into2<T>: Sized { |
|
179 fn into2(self) -> T; |
|
180 } |
|
181 impl<T> Into2<T> for T { |
|
182 fn into2(self) -> T { |
|
183 self |
|
184 } |
|
185 } |
|
186 impl Into2<Vec<String>> for Vec<Ascii> { |
|
187 fn into2(self) -> Vec<String> { |
|
188 self.into_iter().map(|x| x.0).collect() |
|
189 } |
|
190 } |
|
191 impl Into2<String> for Ascii { |
|
192 fn into2(self) -> String { |
|
193 self.0 |
|
194 } |
|
195 } |
|
196 impl Into2<Option<String>> for Option<Ascii> { |
|
197 fn into2(self) -> Option<String> { |
|
198 self.map(|x| x.0) |
|
199 } |
|
200 } |
|
201 |
|
202 #[macro_export] |
|
203 macro_rules! proto_msg_case { |
|
204 ($val: ident()) => { |
|
205 Just($val) |
|
206 }; |
|
207 ($val: ident($arg: ty)) => { |
|
208 any::<$arg>().prop_map(|v| $val(v.into2())) |
|
209 }; |
|
210 ($val: ident($arg1: ty, $arg2: ty)) => { |
|
211 any::<($arg1, $arg2)>().prop_map(|v| $val(v.0.into2(), v.1.into2())) |
|
212 }; |
|
213 ($val: ident($arg1: ty, $arg2: ty, $arg3: ty)) => { |
|
214 any::<($arg1, $arg2, $arg3)>().prop_map(|v| $val(v.0.into2(), v.1.into2(), v.2.into2())) |
|
215 }; |
|
216 } |
|
217 |
|
218 #[macro_export] |
|
219 macro_rules! proto_msg_match { |
|
220 ($var: expr, def = $default: expr, $($num: expr => $constr: ident $res: tt),*) => ( |
|
221 match $var { |
|
222 $($num => (proto_msg_case!($constr $res)).boxed()),*, |
|
223 _ => Just($default).boxed() |
|
224 } |
|
225 ) |
|
226 } |
|
227 |
|
228 /// Wrapper type for generating non-empty strings |
|
229 #[derive(Debug)] |
|
230 pub struct Ascii(String); |
|
231 |
|
232 impl Arbitrary for Ascii { |
|
233 type Parameters = <String as Arbitrary>::Parameters; |
|
234 |
|
235 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { |
|
236 "[a-zA-Z0-9]+".prop_map(Ascii).boxed() |
|
237 } |
|
238 |
|
239 type Strategy = BoxedStrategy<Ascii>; |
|
240 } |
|
241 |
|
242 impl Arbitrary for GameCfg { |
|
243 type Parameters = (); |
|
244 |
|
245 fn arbitrary_with(_args: <Self as Arbitrary>::Parameters) -> <Self as Arbitrary>::Strategy { |
|
246 use crate::types::GameCfg::*; |
|
247 (0..10) |
|
248 .no_shrink() |
|
249 .prop_flat_map(|i| { |
|
250 proto_msg_match!(i, def = FeatureSize(0), |
|
251 0 => FeatureSize(u32), |
|
252 1 => MapType(Ascii), |
|
253 2 => MapGenerator(u32), |
|
254 3 => MazeSize(u32), |
|
255 4 => Seed(Ascii), |
|
256 5 => Template(u32), |
|
257 6 => Ammo(Ascii, Option<Ascii>), |
|
258 7 => Scheme(Ascii, Vec<Ascii>), |
|
259 8 => Script(Ascii), |
|
260 9 => Theme(Ascii), |
|
261 10 => DrawnMap(Ascii)) |
|
262 }) |
|
263 .boxed() |
|
264 } |
|
265 |
|
266 type Strategy = BoxedStrategy<GameCfg>; |
|
267 } |
|
268 |
|
269 impl Arbitrary for TeamInfo { |
|
270 type Parameters = (); |
|
271 |
|
272 fn arbitrary_with(_args: <Self as Arbitrary>::Parameters) -> <Self as Arbitrary>::Strategy { |
|
273 ( |
|
274 "[a-z]+", |
|
275 0u8..127u8, |
|
276 "[a-z]+", |
|
277 "[a-z]+", |
|
278 "[a-z]+", |
|
279 "[a-z]+", |
|
280 0u8..127u8, |
|
281 ) |
|
282 .prop_map(|(name, color, grave, fort, voice_pack, flag, difficulty)| { |
|
283 fn hog(n: u8) -> HedgehogInfo { |
|
284 HedgehogInfo { |
|
285 name: format!("hog{}", n), |
|
286 hat: format!("hat{}", n), |
|
287 } |
|
288 } |
|
289 let hedgehogs = [ |
|
290 hog(1), |
|
291 hog(2), |
|
292 hog(3), |
|
293 hog(4), |
|
294 hog(5), |
|
295 hog(6), |
|
296 hog(7), |
|
297 hog(8), |
|
298 ]; |
|
299 TeamInfo { |
|
300 owner: String::new(), |
|
301 name, |
|
302 color, |
|
303 grave, |
|
304 fort, |
|
305 voice_pack, |
|
306 flag, |
|
307 difficulty, |
|
308 hedgehogs, |
|
309 hedgehogs_number: 0, |
|
310 } |
|
311 }) |
|
312 .boxed() |
|
313 } |
|
314 |
|
315 type Strategy = BoxedStrategy<TeamInfo>; |
|
316 } |
|
317 |
|
318 impl Arbitrary for ServerVar { |
|
319 type Parameters = (); |
|
320 |
|
321 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { |
|
322 (0..=2) |
|
323 .no_shrink() |
|
324 .prop_flat_map(|i| { |
|
325 proto_msg_match!(i, def = ServerVar::LatestProto(0), |
|
326 0 => MOTDNew(Ascii), |
|
327 1 => MOTDOld(Ascii), |
|
328 2 => LatestProto(u16) |
|
329 ) |
|
330 }) |
|
331 .boxed() |
|
332 } |
|
333 |
|
334 type Strategy = BoxedStrategy<ServerVar>; |
|
335 } |
|
336 |
|
337 impl Arbitrary for VoteType { |
|
338 type Parameters = (); |
|
339 |
|
340 fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { |
|
341 use VoteType::*; |
|
342 (0..=4) |
|
343 .no_shrink() |
|
344 .prop_flat_map(|i| { |
|
345 proto_msg_match!(i, def = VoteType::Pause, |
|
346 0 => Kick(Ascii), |
|
347 1 => Map(Option<Ascii>), |
|
348 2 => Pause(), |
|
349 3 => NewSeed(), |
|
350 4 => HedgehogsPerTeam(u8) |
|
351 ) |
|
352 }) |
|
353 .boxed() |
|
354 } |
|
355 |
|
356 type Strategy = BoxedStrategy<VoteType>; |
|
357 } |
|
358 } |
|