feat(humanize): add coordinate/duration/swipe-path jitter module

This commit is contained in:
2026-07-15 18:51:15 +08:00
parent a58ded055e
commit 7d79f677fe
2 changed files with 236 additions and 0 deletions
+87
View File
@@ -0,0 +1,87 @@
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