from __future__ import annotations import asyncio from textual.widgets import Button, Input, Select, Switch from yolo_tui.app import YoloTrainApp from yolo_tui.config import AugmentationConfig, DatasetSplitConfig def test_app_mounts_with_expected_defaults() -> None: async def exercise() -> None: app = YoloTrainApp() async with app.run_test(size=(140, 45)): assert app.query_one("#task", Select).value == "detect" assert app.query_one("#model", Input).value == "yolo11n.pt" assert app.query_one("#dataset", Input).value == "coco8.yaml" assert app.query_one("#augmentation-enabled", Switch).value is True assert app.query_one("#mosaic", Input).value == "1.0" assert app.query_one("#auto-augment", Select).value == "randaugment" assert app.query_one("#mlflow-enabled", Switch).value is True assert app.query_one("#start-button", Button).disabled is False assert app.query_one("#stop-button", Button).disabled is True asyncio.run(exercise()) def test_augmentation_fields_follow_switch() -> None: async def exercise() -> None: app = YoloTrainApp() async with app.run_test(size=(140, 45)) as pilot: switch = app.query_one("#augmentation-enabled", Switch) switch.value = False await pilot.pause() assert app.query_one("#mosaic", Input).disabled is True assert app.query_one("#auto-augment", Select).disabled is True asyncio.run(exercise()) def test_mlflow_fields_follow_switch() -> None: async def exercise() -> None: app = YoloTrainApp() async with app.run_test(size=(140, 45)) as pilot: switch = app.query_one("#mlflow-enabled", Switch) switch.value = False await pilot.pause() assert app.query_one("#tracking-uri", Input).disabled is True assert app.query_one("#experiment-name", Input).disabled is True asyncio.run(exercise()) def test_read_config_ignores_disabled_augmentation() -> None: async def exercise() -> None: app = YoloTrainApp() async with app.run_test(size=(140, 45)) as pilot: app.query_one("#augmentation-enabled", Switch).value = False app.query_one("#hsv-h", Input).value = "not a number" await pilot.pause() config = app._read_config() assert config.augmentation.enabled is False # When disabled, config.augmentation uses defaults, doesn't parse from UI input assert config.augmentation.hsv_h == AugmentationConfig(enabled=False).hsv_h asyncio.run(exercise()) def test_split_fields_follow_switch() -> None: async def exercise() -> None: app = YoloTrainApp() async with app.run_test(size=(140, 45)) as pilot: assert app.query_one("#split-ratio", Input).disabled is True assert app.query_one("#split-classes", Input).disabled is True app.query_one("#split-enabled", Switch).value = True await pilot.pause() assert app.query_one("#split-ratio", Input).disabled is False assert app.query_one("#split-classes", Input).disabled is False asyncio.run(exercise()) def test_read_config_ignores_disabled_split() -> None: async def exercise() -> None: app = YoloTrainApp() async with app.run_test(size=(140, 45)) as pilot: app.query_one("#split-enabled", Switch).value = False app.query_one("#split-ratio", Input).value = "not a float" await pilot.pause() config = app._read_config() assert config.split.enabled is False assert config.split.train_ratio == DatasetSplitConfig(enabled=False).train_ratio asyncio.run(exercise()) def test_classify_disables_detection_style_split() -> None: async def exercise() -> None: app = YoloTrainApp() async with app.run_test(size=(140, 45)) as pilot: app.query_one("#split-enabled", Switch).value = True await pilot.pause() app.query_one("#task", Select).value = "classify" await pilot.pause() assert app.query_one("#split-enabled", Switch).value is False assert app.query_one("#split-enabled", Switch).disabled is True assert app.query_one("#split-ratio", Input).disabled is True assert app.query_one("#split-classes", Input).disabled is True asyncio.run(exercise())