use nth_check::{parse, Nth};
fn ab(s: &str) -> (i32, i32) {
let n = parse(s).unwrap();
(n.a(), n.b())
}
#[test]
fn keywords() {
assert_eq!(ab("odd"), (2, 1));
assert_eq!(ab("even"), (2, 0));
assert_eq!(ab("ODD"), (2, 1)); assert_eq!(ab("Even"), (2, 0));
}
#[test]
fn plain_integers() {
assert_eq!(ab("0"), (0, 0));
assert_eq!(ab("3"), (0, 3));
assert_eq!(ab("+3"), (0, 3));
assert_eq!(ab("-2"), (0, -2));
}
#[test]
fn n_forms() {
assert_eq!(ab("n"), (1, 0));
assert_eq!(ab("+n"), (1, 0));
assert_eq!(ab("-n"), (-1, 0));
assert_eq!(ab("2n"), (2, 0));
assert_eq!(ab("+2n"), (2, 0));
assert_eq!(ab("-2n"), (-2, 0));
assert_eq!(ab("N"), (1, 0)); }
#[test]
fn an_plus_b_forms() {
assert_eq!(ab("2n+1"), (2, 1));
assert_eq!(ab("2n-1"), (2, -1));
assert_eq!(ab("n+3"), (1, 3));
assert_eq!(ab("n-1"), (1, -1));
assert_eq!(ab("-n+3"), (-1, 3));
assert_eq!(ab("-2n-3"), (-2, -3));
}
#[test]
fn whitespace_is_tolerated() {
assert_eq!(ab(" 2n + 1 "), (2, 1));
assert_eq!(ab("2n +1"), (2, 1));
assert_eq!(ab("2n+ 1"), (2, 1));
assert_eq!(ab(" odd "), (2, 1));
assert_eq!(ab("-n + 6"), (-1, 6));
}
#[test]
fn invalid_inputs_error() {
for bad in [
"", " ", "n+", "n-", "2x", "n2", "2 n", "++1", "a", "1.5", "n n", "+", "-", "2n+1x", "odde",
] {
assert!(parse(bad).is_err(), "{bad:?} should be invalid");
}
}
#[test]
fn matches_positions() {
let odd = parse("2n+1").unwrap(); assert!(odd.matches(1) && odd.matches(3) && odd.matches(5));
assert!(!odd.matches(2) && !odd.matches(4));
let even = parse("2n").unwrap(); assert!(even.matches(2) && even.matches(4));
assert!(!even.matches(1) && !even.matches(3));
let third = parse("3").unwrap(); assert!(third.matches(3));
assert!(!third.matches(2) && !third.matches(4));
let first_three = parse("-n+3").unwrap(); assert!(first_three.matches(1) && first_three.matches(2) && first_three.matches(3));
assert!(!first_three.matches(4));
let every_third = parse("3n").unwrap();
assert!(every_third.matches(3) && every_third.matches(6) && every_third.matches(9));
assert!(!every_third.matches(1) && !every_third.matches(4));
let all = parse("n").unwrap();
assert!(all.matches(1) && all.matches(2) && all.matches(1000));
}
#[test]
fn display_canonical() {
assert_eq!(Nth::new(2, 1).to_string(), "2n+1");
assert_eq!(Nth::new(2, -1).to_string(), "2n-1");
assert_eq!(Nth::new(1, 0).to_string(), "n");
assert_eq!(Nth::new(-1, 3).to_string(), "-n+3");
assert_eq!(Nth::new(0, 3).to_string(), "3");
assert_eq!(Nth::new(0, -2).to_string(), "-2");
assert_eq!(Nth::new(3, 0).to_string(), "3n");
for s in ["2n+1", "-n+3", "n", "3", "3n", "-2"] {
let n = parse(s).unwrap();
assert_eq!(parse(&n.to_string()).unwrap(), n, "round-trip {s}");
}
}
#[test]
fn from_str_works() {
let n: Nth = "2n+1".parse().unwrap();
assert_eq!((n.a(), n.b()), (2, 1));
}
#[test]
fn offset_reaches_i32_min() {
assert_eq!(ab("n-2147483648"), (1, i32::MIN));
assert_eq!(ab("2n-2147483648"), (2, i32::MIN));
assert_eq!(ab("-2147483648"), (0, i32::MIN));
assert!(parse("n-2147483649").is_err());
assert!(parse("2n+2147483648").is_err());
for a in [1, -1, 2, i32::MIN] {
let n = Nth::new(a, i32::MIN);
assert_eq!(parse(&n.to_string()).unwrap(), n, "round-trip a={a}, b=MIN");
}
}