captchaforge 0.2.6

Automatic CAPTCHA detection and multi-strategy solving for chromiumoxide-driven headless browsers (Cloudflare Turnstile, reCAPTCHA v2/v3, hCaptcha, image grids, audio, sliders).
Documentation
//! Property-based tests for behavior simulation math.

use proptest::prelude::*;
use proptest::test_runner::TestRunner;

#[test]
fn bezier_curve_finite_for_valid_points() {
    let mut runner = TestRunner::default();
    runner
        .run(
            &(
                -1000.0f64..1000.0,
                -1000.0f64..1000.0,
                -1000.0f64..1000.0,
                -1000.0f64..1000.0,
            ),
            |(x0, y0, x1, y1)| {
                let p1x = x0 + (x1 - x0) / 3.0;
                let _p1y = y0;
                let p2x = x1 - (x1 - x0) / 3.0;
                let _p2y = y1;

                for i in 0..=100 {
                    let t = i as f64 / 100.0;
                    let x = (1.0f64 - t).powi(3) * x0
                        + 3.0 * (1.0f64 - t).powi(2) * t * p1x
                        + 3.0 * (1.0f64 - t) * t.powi(2) * p2x
                        + t.powi(3) * x1;
                    let y = (1.0f64 - t).powi(3) * y0
                        + 3.0 * (1.0f64 - t).powi(2) * t * _p1y
                        + 3.0 * (1.0f64 - t) * t.powi(2) * _p2y
                        + t.powi(3) * y1;

                    prop_assert!(x.is_finite(), "NaN/Inf x at t={}", t);
                    prop_assert!(y.is_finite(), "NaN/Inf y at t={}", t);
                }
                Ok(())
            },
        )
        .unwrap();
}

#[test]
fn bezier_endpoints_exact() {
    let mut runner = TestRunner::default();
    runner
        .run(
            &(
                -1000.0f64..1000.0,
                -1000.0f64..1000.0,
                -1000.0f64..1000.0,
                -1000.0f64..1000.0,
            ),
            |(x0, y0, x1, y1)| {
                let x_at_0 = (1.0f64).powi(3) * x0;
                let y_at_0 = (1.0f64).powi(3) * y0;
                prop_assert!((x_at_0 - x0).abs() < 1e-10);
                prop_assert!((y_at_0 - y0).abs() < 1e-10);

                let x_at_1 = (1.0f64).powi(3) * x1;
                let y_at_1 = (1.0f64).powi(3) * y1;
                prop_assert!((x_at_1 - x1).abs() < 1e-10);
                prop_assert!((y_at_1 - y1).abs() < 1e-10);
                Ok(())
            },
        )
        .unwrap();
}

#[test]
fn bezier_midpoint_in_bbox() {
    let mut runner = TestRunner::default();
    runner
        .run(
            &(
                -500.0f64..500.0,
                -500.0f64..500.0,
                -500.0f64..500.0,
                -500.0f64..500.0,
            ),
            |(x0, y0, x1, y1)| {
                let p1x = x0 + (x1 - x0) / 3.0;
                let p1y = y0;
                let p2x = x1 - (x1 - x0) / 3.0;
                let p2y = y1;

                let t = 0.5;
                let x = (1.0f64 - t).powi(3) * x0
                    + 3.0 * (1.0f64 - t).powi(2) * t * p1x
                    + 3.0 * (1.0f64 - t) * t.powi(2) * p2x
                    + t.powi(3) * x1;
                let y = (1.0f64 - t).powi(3) * y0
                    + 3.0 * (1.0f64 - t).powi(2) * t * p1y
                    + 3.0 * (1.0f64 - t) * t.powi(2) * p2y
                    + t.powi(3) * y1;

                let min_x = x0.min(x1);
                let max_x = x0.max(x1);
                let min_y = y0.min(y1);
                let max_y = y0.max(y1);

                prop_assert!(x >= min_x - (max_x - min_x).abs());
                prop_assert!(x <= max_x + (max_x - min_x).abs());
                prop_assert!(y >= min_y - (max_y - min_y).abs());
                prop_assert!(y <= max_y + (max_y - min_y).abs());
                Ok(())
            },
        )
        .unwrap();
}