| """ |
| Test script for the enhanced HVAC calculator. |
| |
| This script tests all the enhancements made to the HVAC calculator: |
| 1. Window shading calculation fix |
| 2. Scenario comparison functionality |
| 3. Attribution and purpose information |
| """ |
|
|
| import sys |
| import os |
| import unittest |
| from pathlib import Path |
| import json |
|
|
| |
| sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) |
|
|
| |
| from utils.scenario_manager import ScenarioManager |
|
|
| class MockReferenceData: |
| """Mock implementation of ReferenceData for testing.""" |
| |
| def __init__(self): |
| """Initialize mock reference data.""" |
| self.locations = { |
| 'london': { |
| 'name': 'London', |
| 'summer_design_temp': 32.0, |
| 'winter_design_temp': -1.0, |
| 'solar_intensity': { |
| 'north': 100, |
| 'south': 500, |
| 'east': 300, |
| 'west': 300 |
| } |
| } |
| } |
| |
| self.glass_types = { |
| 'single': { |
| 'name': 'Single Glazing', |
| 'u_value': 5.8, |
| 'shgf': { |
| 'north': 200, |
| 'south': 500, |
| 'east': 350, |
| 'west': 350 |
| } |
| } |
| } |
| |
| self.shading_factors = { |
| 'none': { |
| 'name': 'No shading', |
| 'factor': 0.0, |
| 'description': 'No shading devices' |
| }, |
| 'internal_blinds': { |
| 'name': 'Internal venetian blinds', |
| 'factor': 0.4, |
| 'description': 'Internal venetian blinds' |
| }, |
| 'external_awning': { |
| 'name': 'External awning', |
| 'factor': 0.7, |
| 'description': 'External awning or overhang' |
| } |
| } |
| |
| def get_location(self, location_id): |
| """Get location data.""" |
| return self.locations.get(location_id) |
| |
| def get_glass_type(self, glass_type): |
| """Get glass type data.""" |
| return self.glass_types.get(glass_type) |
| |
| def get_shading_factor(self, shading_id): |
| """Get shading factor data.""" |
| return self.shading_factors.get(shading_id) |
|
|
| class TestShadingFix(unittest.TestCase): |
| """Test the window shading calculation fix.""" |
| |
| def test_shading_calculation(self): |
| """Test the shading calculation logic directly.""" |
| |
| shading_data = {'factor': 0.0} |
| shade_factor = 1.0 - shading_data['factor'] |
| self.assertEqual(shade_factor, 1.0) |
| |
| |
| shading_data = {'factor': 0.4} |
| shade_factor = 1.0 - shading_data['factor'] |
| self.assertAlmostEqual(shade_factor, 0.6) |
| |
| |
| shading_data = {'factor': 0.7} |
| shade_factor = 1.0 - shading_data['factor'] |
| self.assertAlmostEqual(shade_factor, 0.3) |
|
|
| class TestScenarioManager(unittest.TestCase): |
| """Test the scenario comparison functionality.""" |
| |
| def setUp(self): |
| """Set up the test case.""" |
| |
| self.test_dir = Path("test_scenarios") |
| self.test_dir.mkdir(exist_ok=True) |
| |
| |
| self.scenario_manager = ScenarioManager(base_path=str(self.test_dir)) |
| |
| |
| self.sample_form_data = { |
| "building_info": { |
| "location": "london", |
| "indoor_temp": 24.0, |
| "building_volume": 500.0, |
| "air_changes": 1.0 |
| }, |
| "components": [ |
| { |
| "type": "wall", |
| "area": 50.0, |
| "u_value": 0.5, |
| "orientation": "south" |
| } |
| ], |
| "windows": [ |
| { |
| "orientation": "south", |
| "area": 10.0, |
| "u_value": 2.8, |
| "glass_type": "single", |
| "shading": "none" |
| } |
| ] |
| } |
| |
| self.sample_results = { |
| "total_load_w": 5000.0, |
| "total_load_kw": 5.0, |
| "recommended_size_kw": 5.75, |
| "breakdown_percentage": { |
| "transmission": 40.0, |
| "solar": 30.0, |
| "ventilation": 20.0, |
| "internal": 10.0 |
| } |
| } |
| |
| def tearDown(self): |
| """Clean up after the test.""" |
| |
| import shutil |
| shutil.rmtree(self.test_dir, ignore_errors=True) |
| |
| def test_save_scenario(self): |
| """Test saving a scenario.""" |
| |
| path = self.scenario_manager.save_scenario( |
| name="Test Scenario", |
| description="Test description", |
| calculator_type="cooling", |
| form_data=self.sample_form_data, |
| results=self.sample_results |
| ) |
| |
| |
| self.assertTrue(os.path.exists(path)) |
| |
| def test_load_scenario(self): |
| """Test loading a scenario.""" |
| |
| path = self.scenario_manager.save_scenario( |
| name="Test Scenario", |
| description="Test description", |
| calculator_type="cooling", |
| form_data=self.sample_form_data, |
| results=self.sample_results |
| ) |
| |
| |
| scenario = self.scenario_manager.load_scenario(path) |
| |
| |
| self.assertIsNotNone(scenario) |
| self.assertEqual(scenario["name"], "Test Scenario") |
| self.assertEqual(scenario["description"], "Test description") |
| self.assertEqual(scenario["calculator_type"], "cooling") |
| self.assertEqual(scenario["form_data"], self.sample_form_data) |
| self.assertEqual(scenario["results"], self.sample_results) |
| |
| def test_compare_scenarios(self): |
| """Test comparing scenarios.""" |
| |
| path1 = self.scenario_manager.save_scenario( |
| name="Scenario 1", |
| description="Base scenario", |
| calculator_type="cooling", |
| form_data=self.sample_form_data, |
| results=self.sample_results |
| ) |
| |
| |
| modified_results = self.sample_results.copy() |
| modified_results["total_load_kw"] = 6.0 |
| modified_results["recommended_size_kw"] = 6.9 |
| modified_results["breakdown_percentage"] = { |
| "transmission": 45.0, |
| "solar": 25.0, |
| "ventilation": 20.0, |
| "internal": 10.0 |
| } |
| |
| path2 = self.scenario_manager.save_scenario( |
| name="Scenario 2", |
| description="Modified scenario", |
| calculator_type="cooling", |
| form_data=self.sample_form_data, |
| results=modified_results |
| ) |
| |
| |
| comparison = self.scenario_manager.compare_scenarios([path1, path2]) |
| |
| |
| self.assertIsNotNone(comparison) |
| self.assertNotIn("error", comparison) |
| self.assertEqual(comparison["calculator_type"], "cooling") |
| self.assertEqual(len(comparison["scenarios"]), 2) |
| self.assertEqual(comparison["scenarios"][0], "Scenario 1") |
| self.assertEqual(comparison["scenarios"][1], "Scenario 2") |
| self.assertEqual(len(comparison["total_loads"]), 2) |
| self.assertEqual(comparison["total_loads"][0]["total_load_kw"], 5.0) |
| self.assertEqual(comparison["total_loads"][1]["total_load_kw"], 6.0) |
| self.assertIn("differences", comparison) |
| self.assertIn("Scenario 2", comparison["differences"]) |
| self.assertEqual(comparison["differences"]["Scenario 2"]["absolute_diff_kw"], 1.0) |
|
|
| def run_tests(): |
| """Run all tests.""" |
| |
| suite = unittest.TestSuite() |
| |
| |
| suite.addTest(unittest.makeSuite(TestShadingFix)) |
| suite.addTest(unittest.makeSuite(TestScenarioManager)) |
| |
| |
| runner = unittest.TextTestRunner(verbosity=2) |
| result = runner.run(suite) |
| |
| return result.wasSuccessful() |
|
|
| if __name__ == "__main__": |
| success = run_tests() |
| sys.exit(0 if success else 1) |
|
|