1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
use crate::Attack; use crate::ParseError; use regex::Regex; use std::str::FromStr; lazy_static! { static ref ATTACK_RE: Regex = Regex::new(r"^([^?]+) *\? *([^?]+)$").unwrap(); } impl FromStr for Attack { type Err = ParseError; fn from_str(s: &str) -> Result<Self, Self::Err> { if let Some(cap) = ATTACK_RE.captures(s) { let check = cap[1].parse()?; let damage = cap[2].parse()?; Ok(Attack { check, damage }) } else { Err(ParseError::new(s)) } } } #[cfg(test)] mod tests { use super::*; use crate::{Check, Damage, RollExpression}; #[test] fn inferred_r() { assert_eq!( "+3?2d8-1".parse::<Attack>().unwrap(), Attack { check: Check::new("r+3").unwrap(), damage: Damage::new("2d8-1").unwrap() } ) } #[test] fn advantage() { assert_eq!( "a-1?2d8+1".parse::<Attack>().unwrap(), Attack { check: Check::new("a-1").unwrap(), damage: Damage::new("2d8+1").unwrap() } ) } #[test] fn neutral() { assert_eq!( "r+8?3d10+2".parse::<Attack>().unwrap(), Attack { check: Check::new("r+8").unwrap(), damage: Damage::new("3d10+2").unwrap() } ) } #[test] fn complex() { assert_eq!( "d+1d4+3-1?1d4+4d6+2-1d4".parse::<Attack>().unwrap(), Attack { check: Check::new("d+1d4+3-1").unwrap(), damage: Damage::new("1d4+4d6+2-1d4").unwrap() } ) } #[test] fn invalid() { assert!("r+3".parse::<Attack>().is_err()); assert!("2d8".parse::<Attack>().is_err()); assert!("".parse::<Attack>().is_err()); assert!("2d8?3d6".parse::<Attack>().is_err()); assert!("r+3?r-2".parse::<Attack>().is_err()); assert!("?".parse::<Attack>().is_err()); assert!("not?2d10".parse::<Attack>().is_err()); assert!("d+3?3d6+4?3d8".parse::<Attack>().is_err()); assert!("d+3??3d8".parse::<Attack>().is_err()); assert!("d+3??majordamage".parse::<Attack>().is_err()); } }