from __future__ import annotations import math import random from tools.humanize import ( HumanizeConfig, jitter_duration, jitter_point, load_humanize_config, set_rng, swipe_waypoints, ) def test_jitter_point_stays_within_radius(): rng = random.Random(42) for _ in range(500): x, y = jitter_point(100, 200, radius=5.0, rng=rng) assert math.hypot(x - 100, y - 200) <= 5.0 def test_jitter_point_centered_on_input(): rng = random.Random(0) xs = [jitter_point(0, 0, radius=4.0, rng=rng)[0] for _ in range(4000)] assert abs(sum(xs) / len(xs)) < 0.3 def test_jitter_duration_within_spread(): rng = random.Random(3) for _ in range(200): v = jitter_duration(1000, spread=0.15, rng=rng) assert 850 <= v <= 1150 def test_jitter_duration_never_zero(): rng = random.Random(9) for _ in range(100): assert jitter_duration(1, spread=0.5, rng=rng) >= 1 def test_swipe_waypoints_endpoints_exact_interior_offset(): rng = random.Random(7) pts = swipe_waypoints((0, 0), (100, 0), curvature=0.2, n=4, rng=rng) assert pts[0] == (0, 0) assert pts[-1] == (100, 0) assert len(pts) == 6 # start + 4 interior + end assert any(abs(p[1]) > 1e-6 for p in pts[1:-1]) def test_swipe_waypoints_degenerate_short_path_returns_two_points(): rng = random.Random(1) pts = swipe_waypoints((5, 5), (5, 5), curvature=0.2, n=8, rng=rng) assert pts == [(5, 5), (5, 5)] def test_load_config_defaults_when_unset(): cfg = load_humanize_config(env={}) assert cfg == HumanizeConfig() def test_load_config_disabled(): cfg = load_humanize_config(env={"APEX_HUMANIZE_ENABLED": "false"}) assert cfg.enabled is False def test_load_config_overrides(): cfg = load_humanize_config( env={ "APEX_HUMANIZE_TAP_RADIUS_PX": "9", "APEX_HUMANIZE_SWIPE_CURVATURE": "0.3", "APEX_HUMANIZE_SWIPE_WAYPOINTS": "12", "APEX_HUMANIZE_DURATION_SPREAD": "0.2", } ) assert cfg.tap_radius_px == 9.0 assert cfg.swipe_curvature == 0.3 assert cfg.swipe_waypoints == 12 assert cfg.duration_spread == 0.2 def test_set_rng_makes_output_reproducible(): set_rng(random.Random(99)) a = jitter_point(0, 0, radius=5.0, rng=random.Random(99)) set_rng(None) # reset to default rng assert isinstance(a, tuple) and len(a) == 2