import pytest import torch # --- Fast tests (no model loading required) --- def test_app_imports_without_model_load(): """Importing app should not trigger model download.""" import app assert hasattr(app, "translate") assert hasattr(app, "_load_tokenizer") assert hasattr(app, "_load_model") # --- Slow tests (require GPU + model download) --- gpu_available = torch.backends.mps.is_available() or torch.cuda.is_available() @pytest.fixture(scope="module") def loaded_app(): import app # Force model/tokenizer loading app._load_tokenizer() app._load_model() return app @pytest.mark.slow @pytest.mark.skipif(not gpu_available, reason="Requires MPS or CUDA") def test_name_to_code_matches_language_names(loaded_app): name_to_code, language_names = loaded_app._build_language_mappings() assert set(name_to_code.keys()) == set(language_names) @pytest.mark.slow @pytest.mark.skipif(not gpu_available, reason="Requires MPS or CUDA") def test_language_names_sorted(loaded_app): _, language_names = loaded_app._build_language_mappings() assert language_names == sorted(language_names) @pytest.mark.slow @pytest.mark.skipif(not gpu_available, reason="Requires MPS or CUDA") def test_all_codes_are_bcp47_tokens(loaded_app): name_to_code, _ = loaded_app._build_language_mappings() for name, code in name_to_code.items(): assert code.startswith("<2") and code.endswith(">"), f"Invalid code {code} for {name}" @pytest.mark.slow @pytest.mark.skipif(not gpu_available, reason="Requires MPS or CUDA") def test_translate_unsupported_language(loaded_app): with pytest.raises(ValueError, match="Unsupported language"): loaded_app.translate("hello", "FakeLanguage") @pytest.mark.slow @pytest.mark.skipif(not gpu_available, reason="Requires MPS or CUDA") def test_translate_returns_string(loaded_app): result = loaded_app.translate("Hello", "French") assert isinstance(result, str) assert len(result) > 0