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

1"""Testing StoreyFilter functionality on IFC elements""" 

2import unittest 

3from pathlib import Path 

4from unittest.mock import MagicMock, patch 

5 

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 

13 

14# Path to test file 

15IFC_PATH = (Path(__file__).parent.parent.parent.parent / 

16 'resources/arch/ifc/AC20-FZK-Haus.ifc') 

17 

18 

19class TestStoreyFilter(unittest.TestCase): 

20 

21 @classmethod 

22 def setUpClass(cls): 

23 """Loads the IFC file for all test cases""" 

24 cls.ifc = ifc2python.load_ifc(IFC_PATH) 

25 

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) 

36 

37 # Get real storeys from the IFC file 

38 self.all_storeys = self.ifc.by_type('IfcBuildingStorey') 

39 

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]) 

44 

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) 

49 

50 def test_filter_initialization(self): 

51 """Test if the filter is initialized correctly""" 

52 self.assertEqual(self.filter.storey_guids, [self.keep_guid]) 

53 

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) 

59 

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) 

65 

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() 

69 

70 result_dict, result_unknown = self.filter.run( 

71 self.ifc, working_dict, working_unknown) 

72 

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) 

77 

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) 

86 

87 # Verify that some filtering actually occurred 

88 self.assertLess(len(result_dict), len(original_keys)) 

89 

90 def test_empty_guid_list(self): 

91 """Test with empty GUID list - no storeys should be removed""" 

92 empty_filter = StoreyFilter([]) 

93 

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) 

97 

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() 

101 

102 result_dict, result_unknown = empty_filter.run( 

103 self.ifc, working_dict, working_unknown) 

104 

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)) 

108 

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) 

113 

114 for item in original_unknown: 

115 self.assertIn(item, result_unknown) 

116 

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) 

121 

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) 

125 

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() 

129 

130 result_dict, result_unknown = keep_all_filter.run( 

131 self.ifc, working_dict, working_unknown) 

132 

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)) 

136 

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) 

141 

142 for item in original_unknown: 

143 self.assertIn(item, result_unknown) 

144 

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"]) 

149 

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) 

153 

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() 

157 

158 result_dict, result_unknown = non_existent_filter.run( 

159 self.ifc, working_dict, working_unknown) 

160 

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)) 

164 

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) 

169 

170 for item in original_unknown: 

171 self.assertIn(item, result_unknown) 

172 

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) 

178 

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 

184 

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() 

188 

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") 

194 

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) 

198 

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) 

204 

205 

206if __name__ == '__main__': 

207 unittest.main()