Coverage for test/unit/elements/mapping/test_filter.py: 93%
102 statements
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-16 08:28 +0000
« prev ^ index » next coverage.py v7.8.0, created at 2025-05-16 08:28 +0000
1"""Testing StoreyFilter functionality on IFC elements"""
2import unittest
3from pathlib import Path
4from unittest.mock import MagicMock, patch
6from bim2sim.elements.mapping import ifc2python
7from bim2sim.elements.mapping.filter import StoreyFilter, TypeFilter
8from bim2sim.elements.base_elements import Material
9from bim2sim.elements import bps_elements as bps_elements
10from bim2sim.elements.mapping.ifc2python import (getSpatialChildren,
11 getHierarchicalChildren)
12from bim2sim.tasks.common import CreateElementsOnIfcTypes
14# Path to test file
15IFC_PATH = (Path(__file__).parent.parent.parent.parent /
16 'resources/arch/ifc/AC20-FZK-Haus.ifc')
19class TestStoreyFilter(unittest.TestCase):
21 @classmethod
22 def setUpClass(cls):
23 """Loads the IFC file for all test cases"""
24 cls.ifc = ifc2python.load_ifc(IFC_PATH)
26 def setUp(self):
27 """Called before each test case"""
28 # Create mock objects for entity_type_dict and unknown
29 self.entity_type_dict = {}
30 self.unknown = []
31 default_ifc_types = {'IfcBuildingElementProxy', 'IfcUnitaryEquipment'}
32 relevant_elements = {*bps_elements.items, Material}
33 relevant_ifc_types = CreateElementsOnIfcTypes.get_ifc_types(
34 relevant_elements)
35 relevant_ifc_types.update(default_ifc_types)
37 # Get real storeys from the IFC file
38 self.all_storeys = self.ifc.by_type('IfcBuildingStorey')
40 # Create a new StoreyFilter object for each test
41 # We assume that the first storey should be kept
42 self.keep_guid = self.all_storeys[0].GlobalId
43 self.filter = StoreyFilter([self.keep_guid])
45 # Fill dictionaries with all storeys
46 type_filter = TypeFilter(relevant_ifc_types)
47 self.entity_type_dict, self.unknown = type_filter.run(
48 self.ifc)
50 def test_filter_initialization(self):
51 """Test if the filter is initialized correctly"""
52 self.assertEqual(self.filter.storey_guids, [self.keep_guid])
54 def test_run_basic_functionality(self):
55 """Test the basic filter functionality"""
56 # Create a copy of the original dictionary keys and unknown list
57 original_keys = set(self.entity_type_dict.keys())
58 original_unknown = set(self.unknown)
60 # Count original storeys in both dictionaries
61 original_storeys_in_dict = sum(
62 1 for k in original_keys if k in self.all_storeys)
63 original_storeys_in_unknown = sum(
64 1 for k in original_unknown if k in self.all_storeys)
66 # Execute the filter with a fresh copy of the dictionaries
67 working_dict = self.entity_type_dict.copy()
68 working_unknown = self.unknown.copy()
70 result_dict, result_unknown = self.filter.run(
71 self.ifc, working_dict, working_unknown)
73 # Check if only the storey to be kept remains in the result
74 storey_keys = [k for k in result_dict.keys() if k in self.all_storeys]
75 self.assertEqual(len(storey_keys), 1)
76 self.assertEqual(storey_keys[0].GlobalId, self.keep_guid)
78 # Check if the storey to be kept also remains in unknown (if it was
79 # there)
80 unknown_storeys = [s for s in result_unknown if s in self.all_storeys]
81 if any(s.GlobalId == self.keep_guid for s in self.unknown):
82 self.assertEqual(len(unknown_storeys), 1)
83 self.assertEqual(unknown_storeys[0].GlobalId, self.keep_guid)
84 else:
85 self.assertEqual(len(unknown_storeys), 0)
87 # Verify that some filtering actually occurred
88 self.assertLess(len(result_dict), len(original_keys))
90 def test_empty_guid_list(self):
91 """Test with empty GUID list - no storeys should be removed"""
92 empty_filter = StoreyFilter([])
94 # Create a copy of the original dictionary keys and unknown list
95 original_keys = set(self.entity_type_dict.keys())
96 original_unknown = set(self.unknown)
98 # Execute the filter with a fresh copy of the dictionaries
99 working_dict = self.entity_type_dict.copy()
100 working_unknown = self.unknown.copy()
102 result_dict, result_unknown = empty_filter.run(
103 self.ifc, working_dict, working_unknown)
105 # Check if the counts match the original
106 self.assertEqual(len(result_dict), len(original_keys))
107 self.assertEqual(len(result_unknown), len(original_unknown))
109 # Verify that all keys from the original dictionaries are present in
110 # the results
111 for key in original_keys:
112 self.assertIn(key, result_dict)
114 for item in original_unknown:
115 self.assertIn(item, result_unknown)
117 def test_keep_all_storeys(self):
118 """Test where all storeys should be kept"""
119 all_guids = [storey.GlobalId for storey in self.all_storeys]
120 keep_all_filter = StoreyFilter(all_guids)
122 # Create a copy of the original dictionary keys and unknown list
123 original_keys = set(self.entity_type_dict.keys())
124 original_unknown = set(self.unknown)
126 # Execute the filter with a fresh copy of the dictionaries
127 working_dict = self.entity_type_dict.copy()
128 working_unknown = self.unknown.copy()
130 result_dict, result_unknown = keep_all_filter.run(
131 self.ifc, working_dict, working_unknown)
133 # Check if the counts match the original
134 self.assertEqual(len(result_dict), len(original_keys))
135 self.assertEqual(len(result_unknown), len(original_unknown))
137 # Verify that all keys from the original dictionaries are present in
138 # the results
139 for key in original_keys:
140 self.assertIn(key, result_dict)
142 for item in original_unknown:
143 self.assertIn(item, result_unknown)
145 def test_nonexistent_guid(self):
146 """Test with a GUID that doesn't exist - no storeys should be
147 removed"""
148 non_existent_filter = StoreyFilter(["non_existent_guid"])
150 # Create a copy of the original dictionary keys and unknown list
151 original_keys = set(self.entity_type_dict.keys())
152 original_unknown = set(self.unknown)
154 # Execute the filter with a fresh copy of the dictionaries
155 working_dict = self.entity_type_dict.copy()
156 working_unknown = self.unknown.copy()
158 result_dict, result_unknown = non_existent_filter.run(
159 self.ifc, working_dict, working_unknown)
161 # Check if the counts match the original
162 self.assertEqual(len(result_dict), len(original_keys))
163 self.assertEqual(len(result_unknown), len(original_unknown))
165 # Verify that all keys from the original dictionaries are present in
166 # the results
167 for key in original_keys:
168 self.assertIn(key, result_dict)
170 for item in original_unknown:
171 self.assertIn(item, result_unknown)
173 def test_error_handling(self):
174 """Test error handling"""
175 # Create a copy of the original dictionary keys and unknown list
176 original_keys = set(self.entity_type_dict.keys())
177 original_unknown = set(self.unknown)
179 # Count storeys to be kept
180 kept_storey = next(
181 s for s in self.all_storeys if s.GlobalId == self.keep_guid)
182 has_kept_storey_in_dict = kept_storey in original_keys
183 has_kept_storey_in_unknown = kept_storey in original_unknown
185 # Execute the filter with a fresh copy of the dictionaries
186 working_dict = self.entity_type_dict.copy()
187 working_unknown = self.unknown.copy()
189 # Create a mock for getSpatialChildren that throws an exception
190 with (patch(
191 'bim2sim.elements.mapping.ifc2python.getSpatialChildren') as
192 mock_get_spatial):
193 mock_get_spatial.side_effect = Exception("Test error")
195 # The filter should catch the error and still function
196 result_dict, result_unknown = self.filter.run(
197 self.ifc, working_dict, working_unknown)
199 # The storey to be kept should still be present
200 if has_kept_storey_in_dict:
201 self.assertIn(kept_storey, result_dict)
202 if has_kept_storey_in_unknown:
203 self.assertIn(kept_storey, result_unknown)
206if __name__ == '__main__':
207 unittest.main()