""" Unit tests for COST-231 Hata and COST-231 Walfisch-Ikegami models. """ import sys import os sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', '..')) from app.propagation.base import PropagationInput from app.propagation.cost231_hata import Cost231HataModel from app.propagation.cost231_wi import Cost231WIModel def make_input(**kwargs) -> PropagationInput: defaults = { "frequency_mhz": 1800, "distance_m": 5000, "tx_height_m": 30, "rx_height_m": 1.5, "environment": "urban", } defaults.update(kwargs) return PropagationInput(**defaults) class TestCost231Hata: def test_typical_range(self): model = Cost231HataModel() out = model.calculate(make_input()) assert 130 < out.path_loss_db < 170 def test_model_name(self): model = Cost231HataModel() assert model.name == "COST-231-Hata" def test_frequency_range(self): model = Cost231HataModel() assert model.is_valid_for(make_input(frequency_mhz=1500)) assert model.is_valid_for(make_input(frequency_mhz=2000)) assert not model.is_valid_for(make_input(frequency_mhz=900)) def test_distance_increases_loss(self): model = Cost231HataModel() loss_2 = model.calculate(make_input(distance_m=2000)).path_loss_db loss_10 = model.calculate(make_input(distance_m=10000)).path_loss_db assert loss_10 > loss_2 def test_urban_vs_suburban(self): model = Cost231HataModel() urban = model.calculate(make_input(environment="urban")).path_loss_db suburban = model.calculate(make_input(environment="suburban")).path_loss_db assert suburban < urban class TestCost231WI: def test_typical_range(self): model = Cost231WIModel() out = model.calculate(make_input(distance_m=500)) assert 80 < out.path_loss_db < 160 def test_model_name(self): model = Cost231WIModel() assert model.name == "COST-231-WI" def test_distance_increases_loss(self): model = Cost231WIModel() loss_200 = model.calculate(make_input(distance_m=200)).path_loss_db loss_1000 = model.calculate(make_input(distance_m=1000)).path_loss_db assert loss_1000 > loss_200 def test_frequency_range(self): model = Cost231WIModel() assert model.is_valid_for(make_input(frequency_mhz=800)) assert model.is_valid_for(make_input(frequency_mhz=2000)) assert not model.is_valid_for(make_input(frequency_mhz=400)) if __name__ == "__main__": for cls_name, cls in [("COST231Hata", TestCost231Hata), ("COST231WI", TestCost231WI)]: instance = cls() for method_name in [m for m in dir(instance) if m.startswith("test_")]: try: getattr(instance, method_name)() print(f" PASS {cls_name}.{method_name}") except AssertionError as e: print(f" FAIL {cls_name}.{method_name}: {e}") except Exception as e: print(f" ERROR {cls_name}.{method_name}: {e}") print("\nAll tests completed.")