use super::*;
#[test]
fn solves_digit_addition() {
assert_eq!(solve_expression("What is 3 + 5?"), Some(8));
}
#[test]
fn solves_digit_subtraction() {
assert_eq!(solve_expression("12 - 4 = ?"), Some(8));
}
#[test]
fn solves_digit_multiplication() {
assert_eq!(solve_expression("7 * 2 = ?"), Some(14));
assert_eq!(solve_expression("7 × 2 = ?"), Some(14));
assert_eq!(solve_expression("7 x 2 = ?"), Some(14));
}
#[test]
fn solves_digit_division() {
assert_eq!(solve_expression("20 / 4 = ?"), Some(5));
assert_eq!(solve_expression("20 ÷ 4 = ?"), Some(5));
}
#[test]
fn solves_word_numbers() {
assert_eq!(solve_expression("What is two plus four?"), Some(6));
assert_eq!(solve_expression("six minus three"), Some(3));
assert_eq!(solve_expression("five times three"), Some(15));
}
#[test]
fn solves_word_operators() {
assert_eq!(solve_expression("4 plus 5"), Some(9));
assert_eq!(solve_expression("10 minus 3"), Some(7));
assert_eq!(solve_expression("3 times 4"), Some(12));
assert_eq!(solve_expression("12 divided by 3"), Some(4));
assert_eq!(solve_expression("5 multiplied by 6"), Some(30));
}
#[test]
fn ignores_surrounding_text() {
assert_eq!(
solve_expression("Solve this anti-spam check: 8 + 7 = ? then submit"),
Some(15)
);
}
#[test]
fn handles_no_match() {
assert!(solve_expression("How are you today?").is_none());
assert!(solve_expression("").is_none());
assert!(solve_expression("just one number 5").is_none());
}
#[test]
fn handles_div_by_zero() {
assert!(solve_expression("5 / 0").is_none());
}
#[test]
fn handles_negative_results() {
assert_eq!(solve_expression("3 - 10"), Some(-7));
}
#[test]
fn solves_unicode_minus_sign() {
assert_eq!(solve_expression("8 \u{2212} 3 = ?"), Some(5));
assert_eq!(solve_expression("8 \u{2013} 3"), Some(5));
assert_eq!(solve_expression("8 \u{2014} 3"), Some(5));
}
#[test]
fn first_match_wins_when_multiple_expressions() {
assert_eq!(
solve_expression("Question 1: 2 + 2 = ? Question 2: 3 + 3 = ?"),
Some(4)
);
}
#[test]
fn solves_zero_through_twenty_word_numbers() {
for (i, word) in [
"zero",
"one",
"two",
"three",
"four",
"five",
"six",
"seven",
"eight",
"nine",
"ten",
"eleven",
"twelve",
"thirteen",
"fourteen",
"fifteen",
"sixteen",
"seventeen",
"eighteen",
"nineteen",
"twenty",
]
.iter()
.enumerate()
{
assert_eq!(parse_number(word), Some(i as i64), "word: {word}");
}
}
#[test]
fn name_and_method_stable() {
let s = MathCaptchaSolver::new();
assert_eq!(s.name(), "MathCaptchaSolver");
assert_eq!(s.method(), SolveMethod::BehavioralBypass);
}
#[test]
fn supports_relevant_kinds_only() {
let s = MathCaptchaSolver::new();
assert!(s.supports(&DetectedCaptcha::Custom("wp_math_captcha".into())));
assert!(s.supports(&DetectedCaptcha::Custom("math_captcha".into())));
assert!(s.supports(&DetectedCaptcha::PowCaptcha));
assert!(s.supports(&DetectedCaptcha::ImageCaptcha));
assert!(s.supports(&DetectedCaptcha::CanvasCaptcha));
assert!(!s.supports(&DetectedCaptcha::Custom("datadome".into())));
assert!(!s.supports(&DetectedCaptcha::Custom("perimeterx_human".into())));
assert!(!s.supports(&DetectedCaptcha::Custom("akamai_bot_manager".into())));
assert!(!s.supports(&DetectedCaptcha::Turnstile));
assert!(!s.supports(&DetectedCaptcha::None));
}
const QUESTION_SELECTORS: &[&str] = &[
"[id*='math-captcha'] label",
"[class*='math-captcha'] label",
"[id*='math_captcha'] label",
"[class*='math_captcha'] label",
".captcha-question",
".captcha-prompt",
"label[for*='captcha']",
"label[for*='math']",
"[data-captcha-question]",
".g-recaptcha-question",
];
const ANSWER_SELECTORS: &[&str] = &[
"input[name*='math-captcha']",
"input[name*='math_captcha']",
"input[name='captcha']",
"input[name='captcha_answer']",
"input[id*='captcha-answer']",
"input[name*='quiz']",
"input[type='text'][placeholder*='answer']",
"input[type='number'][name*='captcha']",
];
#[test]
fn probe_js_includes_documented_selectors() {
for sel in QUESTION_SELECTORS {
assert!(
PROBE_JS.contains(sel),
"probe must contain question sel: {sel}"
);
}
for sel in ANSWER_SELECTORS {
assert!(
PROBE_JS.contains(sel),
"probe must contain input sel: {sel}"
);
}
}