"""Smoke tests del Studio Sprint 1.""" from __future__ import annotations import pytest pytest.importorskip("PySide6") def test_app_constructs(qtbot): from vmssailor.studio.app import StudioApp # qtbot ya construyó un QCoreApplication. Verificamos que apply_theme no rompe. # No instanciamos StudioApp porque qtbot ya tiene QApplication activo. _ = StudioApp # import OK assert True def test_main_window_builds(qtbot): from vmssailor.studio.main_window import MainWindow w = MainWindow() qtbot.addWidget(w) assert w.windowTitle().startswith("VMS-Sailor") assert w.current_project() is None def test_main_window_set_project(qtbot, sample_project): from vmssailor.studio.main_window import MainWindow w = MainWindow() qtbot.addWidget(w) w.set_project(sample_project, path=None) assert w.current_project() is sample_project # Stats label refleja proyecto assert "1 sistemas" in w._stats_label.text() def test_wizard_builds_with_8_pages(qtbot): from vmssailor.studio.wizard.wizard import VesselWizard wiz = VesselWizard() qtbot.addWidget(wiz) assert len(wiz.pageIds()) == 8 def test_wizard_step_01_default_subtypes(qtbot): from vmssailor.studio.wizard.step_01_vessel_type import Step01VesselType step = Step01VesselType() qtbot.addWidget(step) # default type = yacht_motor → subtypes incluyen planing/semi/displacement items = [step._subtype_combo.itemData(i) for i in range(step._subtype_combo.count())] assert "planing" in items assert "displacement" in items def test_wizard_step_04_systems_select_defaults(qtbot): from vmssailor.studio.wizard.step_04_systems import Step04Systems step = Step04Systems() qtbot.addWidget(step) # Simular VesselType de yacht_motor step.setField = lambda *a, **k: None # noop # Forzamos pre-selection llamando directamente # (no podemos invocar field() sin un QWizard padre) enabled = step.get_enabled_systems() # Inicialmente todos desmarcados (hasta initializePage) assert isinstance(enabled, list) def test_vessel_canvas_empty_state(qtbot): from vmssailor.studio.widgets.vessel_canvas import VesselCanvas c = VesselCanvas() qtbot.addWidget(c) # Empty scene tiene un placeholder text + grid lines assert c._scene.items() # algo se renderizó def test_vessel_canvas_renders_project(qtbot, sample_project): from vmssailor.studio.widgets.vessel_canvas import VesselCanvas c = VesselCanvas() qtbot.addWidget(c) c.set_project(sample_project) # Hay items en la escena (silueta + grid + bulkheads + equipos) assert len(c._scene.items()) > 10 def test_system_sidebar_with_project(qtbot, sample_project): from vmssailor.studio.widgets.system_sidebar import SystemSidebar sb = SystemSidebar() qtbot.addWidget(sb) sb.set_project(sample_project) # Debe haber al menos 1 sistema habilitado en la lista assert sb._enabled_list.count() >= 1 def test_ship_to_scene_mapping(): """Coordenadas naval → escena: y_cl > 0 (estribor) cae en y de pantalla negativo.""" from vmssailor.core.coords import ShipCoord from vmssailor.studio.widgets.vessel_canvas import ship_to_scene starboard = ShipCoord(x_pp=10.0, y_cl=2.0, z_bl=1.0) scene_pt = ship_to_scene(starboard, px_per_m=10) assert scene_pt.x() == 100 # 10 m * 10 px/m assert scene_pt.y() == -20 # estribor → y de pantalla negativo (arriba) def test_studio_main_module_importable(): """`python studio_main.py` debe ser importable sin lanzar la UI.""" import importlib import sys from pathlib import Path root = Path(__file__).resolve().parents[2] sys.path.insert(0, str(root)) try: spec = importlib.util.spec_from_file_location("_studio_main", root / "studio_main.py") mod = importlib.util.module_from_spec(spec) spec.loader.exec_module(mod) assert callable(mod.main) finally: if str(root) in sys.path: sys.path.remove(str(root))