use d20::roll_dice;
use d20::roll_range;
#[test]
fn preserve_simple_total_in_range() {
let r = roll_dice("3d6 + 4").unwrap();
assert!(r.total >= 7 && r.total <= 22, "got {}", r.total);
}
#[test]
fn preserve_deterministic_one_sided_dice() {
assert_eq!(roll_dice("3d1 + 2d1 + 1").unwrap().total, 6);
assert_eq!(roll_dice("1d1-3").unwrap().total, -2);
assert_eq!(roll_dice("-3d1 + 2d1 + 1").unwrap().total, 0);
}
#[test]
fn preserve_values_structure() {
let r = roll_dice("2d6 + 6 + 4d10").unwrap();
assert_eq!(r.terms.len(), 3);
assert_eq!(r.terms[0].rolls().len(), 2); assert_eq!(r.terms[1].rolls().len(), 0); assert_eq!(r.terms[2].rolls().len(), 4); }
#[test]
fn preserve_display_formatting() {
let roll = roll_dice("3d1 + 5").unwrap();
assert_eq!(format!("{}", roll), "3d1[1, 1, 1]+5 (Total: 8)");
let bigger = roll_dice("3d1 - 2d1 - 4").unwrap();
assert_eq!(
format!("{}", bigger),
"3d1[1, 1, 1]-2d1[1, 1]-4 (Total: -3)"
);
}
#[test]
fn preserve_range_roll_bounds() {
let v = roll_range(1, 100).unwrap();
assert!((1..=100).contains(&v), "got {}", v);
assert_eq!(roll_range(3, 3).unwrap(), 3);
}
#[test]
fn preserve_range_rejects_inverted() {
assert!(roll_range(12, 1).is_err());
}
#[test]
fn preserve_iterator_take_yields_n_rolls() {
let v: Vec<_> = roll_dice("3d6").unwrap().rolls().take(6).collect();
assert_eq!(v.len(), 6);
for roll in &v {
assert!(roll.total >= 3 && roll.total <= 18, "got {}", roll.total);
}
}
#[test]
fn preserve_non_numeric_garbage_errors() {
assert!(roll_dice("two plus two equals CHICKEN!").is_err());
}
#[test]
fn c1_large_multiplier_now_supported() {
let r = roll_dice("128d6").unwrap();
assert_eq!(r.terms[0].rolls().len(), 128);
assert!(r.total >= 128 && r.total <= 768, "got {}", r.total);
}
#[test]
fn c2_large_modifier_now_supported() {
let r = roll_dice("+500").unwrap();
assert_eq!(r.total, 500);
}
#[test]
fn c3_sides_over_255_now_supported() {
let r = roll_dice("1d256").unwrap();
assert!(r.total >= 1 && r.total <= 256, "got {}", r.total);
}
#[test]
fn c4_sides_128_to_255_now_supported() {
let r = roll_dice("1d200").unwrap();
assert!(r.total >= 1 && r.total <= 200, "got {}", r.total);
}
#[test]
fn c5_zero_sided_die_now_errors() {
assert!(roll_dice("1d0").is_err());
}
#[test]
fn c6_min_multiplier_now_supported() {
let r = roll_dice("-128d6").unwrap();
assert_eq!(r.terms[0].rolls().len(), 128);
assert!(r.total >= -768 && r.total <= -128, "got {}", r.total);
}
#[test]
fn c7_roll_range_max_no_longer_overflows() {
let v = roll_range(0, i32::MAX).unwrap();
assert!(v >= 0, "got {}", v);
}
#[test]
fn c8_whitespace_no_longer_merges_tokens() {
let err = roll_dice("2d6 5").unwrap_err();
assert!(
matches!(err, d20::D20Error::MissingOperator(_)),
"got {err:?}"
);
let r = roll_dice("2d6 + 5").unwrap();
assert_eq!(r.terms.len(), 2);
assert_eq!(r.drex, "2d6 + 5");
}
#[test]
fn c9_garbage_with_digit_now_errors() {
assert!(roll_dice("I have 5 apples").is_err());
}
#[test]
fn c10_digit_nonsense_now_errors() {
assert!(roll_dice("2 plus 2 equals CHICKEN!").is_err());
}
#[test]
fn c11_d6_shorthand_now_rolls_one_die() {
let r = roll_dice("d6").unwrap();
assert_eq!(r.terms.len(), 1);
assert_eq!(r.terms[0].rolls().len(), 1, "one die rolled");
assert!(r.total >= 1 && r.total <= 6, "got {}", r.total);
}
#[test]
fn c13_ambiguous_double_sign_now_errors() {
assert!(roll_dice("+-3").is_err());
}
#[test]
fn c12_drex_preserves_original_expression() {
let r = roll_dice("2d6 + 6 + 4d10").unwrap();
assert_eq!(r.drex, "2d6 + 6 + 4d10");
}
use d20::D20Error;
use d20::{MAX_DICE, MAX_SIDES};
#[test]
fn caps_reject_too_many_sides() {
let err = roll_dice(&format!("1d{}", MAX_SIDES as u64 + 1)).unwrap_err();
assert!(matches!(err, D20Error::SidesTooLarge { .. }), "got {err:?}");
}
#[test]
fn caps_reject_too_many_dice() {
let err = roll_dice(&format!("{}d6", MAX_DICE as u64 + 1)).unwrap_err();
assert!(
matches!(err, D20Error::DiceCountTooLarge { .. }),
"got {err:?}"
);
}
#[test]
fn caps_reject_unparseable_huge_number() {
let err = roll_dice("1d999999999999999999999999").unwrap_err();
assert!(matches!(err, D20Error::InvalidTerm(_)), "got {err:?}");
}
#[test]
fn caps_zero_sided_die_is_specific_error() {
assert_eq!(roll_dice("1d0").unwrap_err(), D20Error::ZeroSidedDie);
}
#[test]
fn caps_no_input_panics_across_extreme_values() {
let inputs = [
"0d6",
"1d1",
"1000000d1000000",
"-1000000d20",
"+1000000",
"-1000000",
"1d1000001",
"1000001d6",
"999999999999d6",
"1d0",
"",
];
for inp in inputs {
let _ = roll_dice(inp); }
}