diff --git a/tests/test_pin.py b/tests/test_pin.py index e51232f..5344a12 100644 --- a/tests/test_pin.py +++ b/tests/test_pin.py @@ -51,22 +51,11 @@ def test_pin_key_without_dot_raises(): generate_profile(seed=42, pin={"madeup": 1}) -def test_pin_top_level_fonts_accepted(): - p = generate_profile(seed=42, pin={"fonts": ["Arial", "Verdana", "Tahoma"]}) - assert "Arial" in p.fonts - assert "Verdana" in p.fonts - - def test_pin_top_level_dark_theme_accepted(): p = generate_profile(seed=42, pin={"dark_theme": True}) assert p.dark_theme is True -def test_pin_fonts_wrong_type_raises(): - with pytest.raises(TypeError, match="list/tuple"): - generate_profile(seed=42, pin={"fonts": "Arial,Verdana"}) - - def test_pin_overrides_seed_value(): """The same seed produces different output once a pin is applied.""" natural = generate_profile(seed=42) diff --git a/tests/test_profile.py b/tests/test_profile.py index bddf5b1..eee2856 100644 --- a/tests/test_profile.py +++ b/tests/test_profile.py @@ -21,12 +21,6 @@ from invisible_playwright._fpforge.profile import ( # _validate_pin_key # ───────────────────────────────────────────────────────────────────── -@pytest.mark.unit -def test_validate_pin_key_top_level_fonts(): - """VK1 — `fonts` is a known top-level key.""" - _validate_pin_key("fonts") - - @pytest.mark.unit def test_validate_pin_key_top_level_dark_theme(): """VK2 — `dark_theme` is a known top-level key.""" @@ -98,7 +92,6 @@ def _raw_baseline(): "screen_h": 1080, "webgl_vendor": "Google Inc. (Intel)", "webgl_renderer": "ANGLE (Intel)", - "font_whitelist": "arial,calibri", "dark_theme": 0, } @@ -110,34 +103,6 @@ def test_apply_pins_to_raw_screen_width(): assert out["screen_w"] == 2560 -@pytest.mark.unit -def test_apply_pins_to_raw_fonts_list(): - """AP2 — list pin joined into comma-separated whitelist.""" - out = _apply_pins_to_raw(_raw_baseline(), {"fonts": ["Arial", "Verdana"]}) - assert out["font_whitelist"] == "Arial,Verdana" - - -@pytest.mark.unit -def test_apply_pins_to_raw_fonts_tuple(): - """AP3 — tuple pin is also accepted.""" - out = _apply_pins_to_raw(_raw_baseline(), {"fonts": ("Arial",)}) - assert out["font_whitelist"] == "Arial" - - -@pytest.mark.unit -def test_apply_pins_to_raw_fonts_string_raises(): - """AP4 — bare string is not a list/tuple, must raise.""" - with pytest.raises(TypeError, match="list/tuple"): - _apply_pins_to_raw(_raw_baseline(), {"fonts": "Arial"}) - - -@pytest.mark.unit -def test_apply_pins_to_raw_fonts_int_raises(): - """AP5 — int is also rejected.""" - with pytest.raises(TypeError): - _apply_pins_to_raw(_raw_baseline(), {"fonts": 42}) - - @pytest.mark.unit def test_apply_pins_to_raw_multiple_pins(): """AP6 — multiple pins all land in raw.""" @@ -158,7 +123,7 @@ def test_apply_pins_to_raw_returns_copy_not_mutation(): @pytest.mark.unit def test_apply_pins_to_raw_unknown_key_silent(): - """AP8 — key not in `_PIN_TO_RAW` (and not 'fonts') is ignored. + """AP8 — key not in `_PIN_TO_RAW` is ignored. Validation happens upstream in `generate_profile`; the inner helper guards defensively but does not raise. @@ -260,15 +225,6 @@ def test_generate_profile_is_frozen(): p.seed = 99 # type: ignore[misc] -@pytest.mark.unit -def test_generate_profile_fonts_is_list_of_strings(): - """GP11 — fonts is a non-empty list of stripped strings.""" - p = generate_profile(seed=42) - assert isinstance(p.fonts, list) - assert len(p.fonts) > 0 - assert all(isinstance(f, str) and f.strip() == f for f in p.fonts) - - @pytest.mark.unit def test_generate_profile_to_prefs_dict_flat_and_matches_raw(): """GP12 — to_prefs_dict() returns a flat dict containing core sampler keys.""" @@ -319,13 +275,6 @@ def test_generate_profile_pin_dark_theme_false(): assert p.dark_theme is False -@pytest.mark.unit -def test_generate_profile_pin_fonts_list_visible_on_profile(): - """fonts pin: list → joined raw string → split back to list on Profile.""" - p = generate_profile(seed=42, pin={"fonts": ["Arial", "Verdana"]}) - assert p.fonts == ["Arial", "Verdana"] - - @pytest.mark.unit def test_generate_profile_pin_gpu_renderer_propagates(): p = generate_profile(seed=42, pin={"gpu.renderer": "FORCED_RENDERER"}) @@ -335,14 +284,13 @@ def test_generate_profile_pin_gpu_renderer_propagates(): @pytest.mark.unit def test_generate_profile_pin_to_raw_keymap_complete(): - """Every dotted pin key (besides 'fonts') has a `_PIN_TO_RAW` mapping. + """Every dotted pin key has a `_PIN_TO_RAW` mapping. Guards against silently-ignored pins if someone adds a key to `_PIN_GROUPS` but forgets the raw-key mapping. """ dotted = {f"{group}.{field}" for group, fields in _PIN_GROUPS.items() for field in fields} - # 'dark_theme' is top-level and present in _PIN_TO_RAW; 'fonts' is handled - # specially and intentionally absent. + # 'dark_theme' is top-level and present in _PIN_TO_RAW. missing = dotted - set(_PIN_TO_RAW.keys()) assert missing == set(), f"pin keys without raw mapping: {sorted(missing)}" diff --git a/tests/test_sampler.py b/tests/test_sampler.py index e9af219..fc715f5 100644 --- a/tests/test_sampler.py +++ b/tests/test_sampler.py @@ -1,11 +1,8 @@ """Unit tests for invisible_playwright._fpforge._sampler. Covers classify_gpu (decision-table over GPU strings), _screen_tier, -derive_font_prefs / derive_font_whitelist, and the public Forge / sample -entry points. +and the public Forge / sample entry points. """ -import random - import pytest from invisible_playwright._fpforge import _sampler @@ -14,8 +11,6 @@ from invisible_playwright._fpforge._sampler import ( _LOCKED, _screen_tier, classify_gpu, - derive_font_prefs, - derive_font_whitelist, sample, ) @@ -213,116 +208,6 @@ def test_screen_tier_4200x2000_is_ultrawide_via_width_branch(): assert _screen_tier({"screen": {"w": 4200, "h": 2000}}) == "ultrawide" -# ── derive_font_prefs / derive_font_whitelist ─────────────────────────── - -@pytest.mark.unit -def test_derive_font_prefs_returns_whitelist_key(): - """FP1 [HAPPY]: result is a single-key dict with the font family list. - - The per-family ``metrics`` string was removed on 2026-06-20: fonts now - render from the bundled real Windows files (genuine widths) and per-session - metric uniqueness comes from the HarfBuzz jitter, not fabricated factors.""" - out = derive_font_prefs("integrated_modern", random.Random(42)) - assert set(out.keys()) == {"whitelist"} - assert isinstance(out["whitelist"], str) - - -@pytest.mark.unit -def test_derive_font_prefs_core_fonts_always_present(): - """FP2 [ECP]: every core font name appears in whitelist regardless of class.""" - out = derive_font_prefs("integrated_old", random.Random(0)) - names = set(out["whitelist"].split(",")) - for entry in _sampler._FONT_CORE: - assert entry["name"] in names - - -@pytest.mark.unit -def test_derive_font_prefs_deterministic_per_seed(): - """FP3 [ECP]: same gpu_class + same rng seed → identical result.""" - a = derive_font_prefs("workstation", random.Random(7)) - b = derive_font_prefs("workstation", random.Random(7)) - assert a == b - - -@pytest.mark.unit -def test_derive_font_prefs_unknown_class_falls_back_to_integrated_modern(): - """FP4 [ECP]: gpu_class missing from CPT → uses integrated_modern row.""" - fallback = derive_font_prefs("nonexistent", random.Random(123)) - expected = derive_font_prefs("integrated_modern", random.Random(123)) - assert fallback == expected - - -@pytest.mark.unit -def test_derive_font_prefs_whitelist_alphabetically_sorted(): - """FP6 [ECP]: whitelist names are sorted (ordering invariant for stable dedup).""" - out = derive_font_prefs("high_end", random.Random(5)) - names = out["whitelist"].split(",") - assert names == sorted(names) - - -@pytest.mark.unit -def test_derive_font_whitelist_legacy_shim_matches_dict_form(): - """FW1 [HAPPY]: legacy shim returns same string as dict['whitelist'].""" - rng_a = random.Random(11) - rng_b = random.Random(11) - assert derive_font_whitelist("low_end", rng_a) == \ - derive_font_prefs("low_end", rng_b)["whitelist"] - - -# Standard fonts that ship with every Windows 10/11 install. They MUST be in the -# core (always-present) set, never in the optional/per-profile set: a real Windows -# machine never lacks them, so a session that drops one advertises a font set that -# doesn't match any real Windows profile (image-dedup font probes then report a -# short/degenerate name list → server-side OS-font-set checks fail). Calibri in -# particular sat in `optional` (a bug); these caused the detected set to come up -# short on some seeds. Regression guard for the 2026-06-18 optional→core move. -# NB: the exact Win11 family is "franklin gothic medium" (there is no bare -# "franklin gothic" family); the 2026-06-20 bundle reconciliation uses real names. -_STANDARD_WINDOWS_FONTS = [ - "calibri", "franklin gothic medium", "gadugi", "javanese text", "myanmar text", -] -_ALL_GPU_CLASSES = [ - "integrated_old", "integrated_modern", "mid_range", "high_end", - "low_end", "workstation", -] - - -@pytest.mark.unit -@pytest.mark.parametrize("gpu_class", _ALL_GPU_CLASSES) -def test_standard_windows_fonts_always_present_every_class_and_seed(gpu_class): - """FP7 [regression]: the standard-Windows fonts appear in the whitelist for - every gpu_class across many seeds (i.e. they are core, not profile-optional). - Guards against a standard font silently becoming optional.""" - for seed in range(40): - out = derive_font_prefs(gpu_class, random.Random(seed)) - wl = set(out["whitelist"].split(",")) - for font in _STANDARD_WINDOWS_FONTS: - assert font in wl, f"{font!r} missing from whitelist (class={gpu_class}, seed={seed})" - - -@pytest.mark.unit -def test_standard_windows_fonts_are_in_core_pool(): - """FP8 [regression]: the standard-Windows fonts live in the CORE pool (not - optional) — the structural source of the always-present guarantee above.""" - core_names = {e["name"] for e in _sampler._FONT_CORE} - optional_names = {e["name"] for e in _sampler._FONT_OPTIONAL} - for font in _STANDARD_WINDOWS_FONTS: - assert font in core_names, f"{font!r} must be in core pool" - assert font not in optional_names, f"{font!r} must NOT be in optional pool" - - -@pytest.mark.unit -@pytest.mark.parametrize("gpu_class", _ALL_GPU_CLASSES) -def test_derive_font_prefs_no_duplicate_families(gpu_class): - """FP9 [regression]: no family appears twice in the whitelist, even when a - profile's optional list also names a core font. Guards the dedup in - derive_font_prefs (a duplicate family would emit a malformed list).""" - for seed in range(30): - out = derive_font_prefs(gpu_class, random.Random(seed)) - wl = out["whitelist"].split(",") - assert len(wl) == len(set(wl)), f"duplicate in whitelist (class={gpu_class}, seed={seed})" - - # ── Forge / sample ────────────────────────────────────────────────────── # Keys the Forge.sample bundle must always contain. Builds on _LOCKED + @@ -338,7 +223,6 @@ _EXPECTED_KEYS = { "av1_enabled", "webm_encoder_enabled", "mediasource_webm", "mediasource_mp4", "webspeech_synth", "storage_quota_mb", "dark_theme", - "font_whitelist", } @@ -425,14 +309,6 @@ def test_forge_sample_avail_h_defaults_to_h_minus_40_when_missing(monkeypatch): assert out["screen_avail_h"] == 1080 - 40 -@pytest.mark.unit -def test_forge_sample_includes_font_keys(): - """FS9 [ECP]: font_whitelist present and non-empty (the joined family list).""" - out = sample(42) - assert out["font_whitelist"] - assert "," in out["font_whitelist"] # at least the core fonts joined - - @pytest.mark.unit def test_forge_seed_coercion_to_int(): """FS extra: Forge(seed) coerces seed to int (e.g. float 42.7 → 42)."""