chore: initialize git repo, add matplotlib dep, extend config

- Add .gitignore for Python/data/models
- Add matplotlib>=3.8.0 for eval plots
- Add PretrainConfig, FinetuneConfig, BalabitAdapterConfig, EvalConfig dataclasses
This commit is contained in:
2026-05-10 12:24:07 +08:00
commit 4d414fd180
44 changed files with 9681 additions and 0 deletions

View File

@@ -0,0 +1,65 @@
"""Tests for scroll collection state and target generation."""
from __future__ import annotations
import pytest
from ai_mouse.scroll.collector import ScrollCollector
class TestNextTarget:
def test_target_mode_distance_range(self):
sc = ScrollCollector(mode="target", count=10, page_height=10000, viewport_height=900)
for _ in range(20):
result = sc.next_target(current_scrollY=2000)
dist = abs(result["target_scrollY"] - 2000)
assert 500 <= dist <= 3000
assert result["direction"] in ("up", "down")
def test_fast_mode_distance_range(self):
sc = ScrollCollector(mode="fast", count=10, page_height=10000, viewport_height=900)
for _ in range(20):
result = sc.next_target(current_scrollY=5000)
dist = abs(result["target_scrollY"] - 5000)
assert 3000 <= dist <= 8000
def test_precise_mode_distance_range(self):
sc = ScrollCollector(mode="precise", count=10, page_height=10000, viewport_height=900)
for _ in range(20):
result = sc.next_target(current_scrollY=3000)
dist = abs(result["target_scrollY"] - 3000)
assert 200 <= dist <= 800
def test_target_within_page_bounds(self):
sc = ScrollCollector(mode="target", count=10, page_height=10000, viewport_height=900)
result = sc.next_target(current_scrollY=1000)
assert 0 <= result["target_scrollY"] <= 10000
result = sc.next_target(current_scrollY=9000)
assert 0 <= result["target_scrollY"] <= 10000
def test_success_zone_by_mode(self):
sc = ScrollCollector(mode="target", count=10, page_height=10000)
assert sc.success_radius == 80
sc2 = ScrollCollector(mode="fast", count=10, page_height=10000)
assert sc2.success_radius == 120
sc3 = ScrollCollector(mode="precise", count=10, page_height=10000)
assert sc3.success_radius == 40
def test_target_always_reachable(self):
"""Target must always be reachable: user can scroll to bring it into success zone."""
sc = ScrollCollector(mode="target", count=10, page_height=10000, viewport_height=900)
viewport_center = 450 # 900 / 2
max_scroll_top = 10000 - 900 # 9100
for current in [0, 100, 500, 2000, 5000, 8000, 9000]:
for _ in range(10):
result = sc.next_target(current_scrollY=current)
target = result["target_scrollY"]
# The scrollTop needed to bring target into viewport center
needed_scroll = target - viewport_center + 25
# Must be achievable (0 <= needed_scroll <= max_scroll_top)
# With success_radius=80, there's a window, not exact match needed
reachable_min = viewport_center - sc.success_radius
reachable_max = max_scroll_top + viewport_center + sc.success_radius
assert reachable_min <= target <= reachable_max, (
f"Target {target} not reachable from scrollY={current}"
)