""" Tests de Sprint 0 — Validación del esqueleto del proyecto. """ import json from pathlib import Path import pytest def test_version_importable(): """La versión del paquete debe ser importable.""" from arshipdesign import __version__ assert __version__ == "0.1.0" def test_units_conversions(): """Conversiones de unidades deben ser correctas.""" from arshipdesign.core.units import ( m_to_ft, ft_to_m, kn_to_ms, ms_to_kn, kg_to_ton_metric, w_to_kw, c_to_f, ) # Longitud assert abs(m_to_ft(1.0) - 3.280839895) < 1e-6 assert abs(ft_to_m(3.280839895) - 1.0) < 1e-6 # Velocidad assert abs(kn_to_ms(1.0) - 0.514444) < 1e-4 assert abs(ms_to_kn(0.514444) - 1.0) < 1e-3 # Masa assert abs(kg_to_ton_metric(1000.0) - 1.0) < 1e-9 # Potencia assert abs(w_to_kw(1000.0) - 1.0) < 1e-9 # Temperatura assert abs(c_to_f(0.0) - 32.0) < 1e-6 assert abs(c_to_f(100.0) - 212.0) < 1e-6 def test_units_roundtrip(): """Las conversiones deben ser reversibles (roundtrip).""" from arshipdesign.core.units import m_to_ft, ft_to_m, kn_to_ms, ms_to_kn for val in [1.0, 5.5, 100.0, 0.01]: assert abs(ft_to_m(m_to_ft(val)) - val) < 1e-9 assert abs(ms_to_kn(kn_to_ms(val)) - val) < 1e-9 def test_project_new(): """Crear un proyecto nuevo debe generar metadatos correctos.""" from arshipdesign.core.project import Project p = Project.new("Test Boat", author="Test Author") assert p.name == "Test Boat" assert p.metadata.author == "Test Author" assert p.is_modified is True assert p.path is None def test_project_save_load(tmp_path): """Guardar y cargar un proyecto debe preservar los datos.""" from arshipdesign.core.project import Project project = Project.new("Mi Velero de Prueba", author="Álvaro") save_path = tmp_path / "test_project.arsd" project.save(save_path) assert save_path.exists() assert not project.is_modified # Recargar loaded = Project.load(save_path) assert loaded.name == "Mi Velero de Prueba" assert loaded.metadata.author == "Álvaro" assert loaded.metadata.format_version == "1.0" assert not loaded.is_modified def test_project_save_creates_valid_zip(tmp_path): """El archivo .arsd debe ser un ZIP válido con manifest.json.""" import zipfile from arshipdesign.core.project import Project p = Project.new("Zip Test") path = tmp_path / "ziptest.arsd" p.save(path) assert zipfile.is_zipfile(path) with zipfile.ZipFile(path) as zf: assert "manifest.json" in zf.namelist() assert "ship.json" in zf.namelist() def test_project_load_nonexistent(): """Cargar un archivo inexistente debe lanzar FileNotFoundError.""" from arshipdesign.core.project import Project with pytest.raises(FileNotFoundError): Project.load(Path("/ruta/que/no/existe.arsd")) def test_project_load_wrong_extension(tmp_path): """Cargar un archivo con extensión incorrecta debe lanzar ValueError.""" from arshipdesign.core.project import Project fake = tmp_path / "archivo.txt" fake.write_text("hola") with pytest.raises(ValueError): Project.load(fake) def test_i18n_files_valid(): """Los archivos de i18n deben ser JSON válido con claves básicas.""" base = Path(__file__).parent.parent / "arshipdesign" / "ui" / "i18n" for lang in ("es", "en"): f = base / f"{lang}.json" assert f.exists(), f"Falta el archivo i18n/{lang}.json" data = json.loads(f.read_text(encoding="utf-8")) assert "app_title" in data assert "menu_file" in data assert "hydro_draft" in data def test_liquids_json_valid(): """El archivo de líquidos debe tener las propiedades requeridas.""" liq_path = Path(__file__).parent.parent / "data" / "liquids.json" assert liq_path.exists() liquids = json.loads(liq_path.read_text(encoding="utf-8")) required_codes = {"FW", "SW", "MGO", "HFO"} for code in required_codes: assert code in liquids, f"Líquido {code} faltante" assert "density_kg_m3" in liquids[code] assert liquids[code]["density_kg_m3"] > 0 def test_stability_criteria_json_valid(): """El archivo de criterios de estabilidad debe tener IMO IS Code 2008.""" crit_path = Path(__file__).parent.parent / "data" / "stability_criteria.json" assert crit_path.exists() criteria = json.loads(crit_path.read_text(encoding="utf-8")) assert "IMO_IS_Code_2008" in criteria imo = criteria["IMO_IS_Code_2008"]["criteria"] assert "area_0_30" in imo assert imo["area_0_30"]["min"] == 0.055 def test_directory_structure(): """Los módulos principales deben existir como paquetes Python.""" root = Path(__file__).parent.parent / "arshipdesign" required_packages = [ "core", "geometry", "hydrostatics", "stability", "scantling", "resistance", "propulsion", "fabrication", "fabrication/molds", "sailing", "seakeeping", "systems", "ui", "ui/widgets", "ui/dialogs", "utils", "reports", "parametric", "tanks", "engines", "io", ] for pkg in required_packages: init_file = root / pkg / "__init__.py" assert init_file.exists(), f"Falta {pkg}/__init__.py"