|
12 | 12 | import unittest |
13 | 13 |
|
14 | 14 | from codechecker_report_converter.util import trim_path_prefixes |
| 15 | +from codechecker_report_converter.report import ( |
| 16 | + BugPathEvent, |
| 17 | + File, |
| 18 | + MacroExpansion, |
| 19 | + Report, |
| 20 | +) |
15 | 21 |
|
16 | 22 |
|
17 | 23 | class TrimPathPrefixTestCase(unittest.TestCase): |
@@ -70,3 +76,270 @@ def test_prefix_blob(self): |
70 | 76 | self.assertEqual('my_proj/x.cpp', |
71 | 77 | trim_path_prefixes('/home/jsmith/my_proj/x.cpp', |
72 | 78 | ['/home/jsmith/'])) |
| 79 | + |
| 80 | + def test_remove_only_root_prefix(self): |
| 81 | + """Test removing only the root '/' prefix from paths.""" |
| 82 | + |
| 83 | + test_paths = ["/a/b/c", "/foo.txt", "/dir/subdir/file.cpp", "/"] |
| 84 | + |
| 85 | + expected_paths = ["a/b/c", "foo.txt", "dir/subdir/file.cpp", ""] |
| 86 | + |
| 87 | + for test_path, expected in zip(test_paths, expected_paths): |
| 88 | + self.assertEqual( |
| 89 | + expected, |
| 90 | + trim_path_prefixes(test_path, ["/"]), |
| 91 | + f"Failed to remove root prefix from {test_path}", |
| 92 | + ) |
| 93 | + |
| 94 | + def test_trim_path_in_message(self): |
| 95 | + """ |
| 96 | + Test trimming path prefixes in report messages and bug path events. |
| 97 | + """ |
| 98 | + |
| 99 | + test_file = File("/path/to/workspace/src/example.cpp") |
| 100 | + |
| 101 | + test_cases = [ |
| 102 | + # Simple message with one path |
| 103 | + { |
| 104 | + "name": "simple_message", |
| 105 | + "message": ("Error in file " |
| 106 | + "/path/to/workspace/src/example.cpp:10:20"), |
| 107 | + "bug_path_events": [ |
| 108 | + BugPathEvent( |
| 109 | + "Found issue at " |
| 110 | + "/path/to/workspace/include/header.h:5:10", |
| 111 | + File("/path/to/workspace/include/header.h"), |
| 112 | + 5, |
| 113 | + 10, |
| 114 | + ) |
| 115 | + ], |
| 116 | + "expected_message": "Error in file src/example.cpp:10:20", |
| 117 | + "expected_bug_path_messages": [ |
| 118 | + "Found issue at include/header.h:5:10" |
| 119 | + ], |
| 120 | + }, |
| 121 | + # Complex message with multiple paths |
| 122 | + { |
| 123 | + "name": "complex_message", |
| 124 | + "message": ( |
| 125 | + "Multiple errors: " |
| 126 | + "/path/to/workspace/src/example.cpp:10:20 and " |
| 127 | + "/path/to/workspace/include/header.h:5:10" |
| 128 | + ), |
| 129 | + "bug_path_events": [], |
| 130 | + "expected_message": ( |
| 131 | + "Multiple errors: src/example.cpp:10:20 and " |
| 132 | + "include/header.h:5:10" |
| 133 | + ), |
| 134 | + "expected_bug_path_messages": [], |
| 135 | + }, |
| 136 | + ] |
| 137 | + |
| 138 | + for case in test_cases: |
| 139 | + report = Report( |
| 140 | + file=test_file, |
| 141 | + line=10, |
| 142 | + column=20, |
| 143 | + message=case["message"], |
| 144 | + checker_name="test-checker", |
| 145 | + severity="HIGH", |
| 146 | + ) |
| 147 | + |
| 148 | + for event in case["bug_path_events"]: |
| 149 | + report.bug_path_events.append(event) |
| 150 | + |
| 151 | + report.trim_path_prefixes(["/path/to/workspace"]) |
| 152 | + |
| 153 | + self.assertEqual( |
| 154 | + case["expected_message"], |
| 155 | + report.message, |
| 156 | + f"Failed to trim message in {case['name']} case", |
| 157 | + ) |
| 158 | + |
| 159 | + for i, expected_msg in enumerate( |
| 160 | + case["expected_bug_path_messages"] |
| 161 | + ): |
| 162 | + # Note: Bug path events are 1-indexed in the report |
| 163 | + self.assertEqual( |
| 164 | + expected_msg, |
| 165 | + report.bug_path_events[i + 1].message, |
| 166 | + "Failed to trim bug path event message " |
| 167 | + "in {case['name']} case", |
| 168 | + ) |
| 169 | + |
| 170 | + def test_trim_path_in_complex_message(self): |
| 171 | + |
| 172 | + test_file = File("/path/to/workspace/src/example.cpp") |
| 173 | + |
| 174 | + message = ( |
| 175 | + "Multiple errors: " |
| 176 | + "/path/to/workspace/src/example.cpp:10:20 and " |
| 177 | + "/path/to/workspace/include/header.h:5:10" |
| 178 | + ) |
| 179 | + |
| 180 | + report = Report( |
| 181 | + file=test_file, |
| 182 | + line=10, |
| 183 | + column=20, |
| 184 | + message=message, |
| 185 | + checker_name="test-checker", |
| 186 | + severity="HIGH", |
| 187 | + ) |
| 188 | + |
| 189 | + report.trim_path_prefixes(["/path/to/workspace"]) |
| 190 | + |
| 191 | + expected = ( |
| 192 | + "Multiple errors: src/example.cpp:10:20 and " |
| 193 | + "include/header.h:5:10" |
| 194 | + ) |
| 195 | + self.assertEqual(expected, report.message) |
| 196 | + |
| 197 | + def test_trim_path_in_macro_expansions(self): |
| 198 | + """ |
| 199 | + Test trimming path prefixes in macro expansions with various scenarios. |
| 200 | + """ |
| 201 | + |
| 202 | + test_file = File("/path/to/workspace/src/example.cpp") |
| 203 | + |
| 204 | + test_cases = [ |
| 205 | + # Single macro with simple path |
| 206 | + { |
| 207 | + "name": "single_macro", |
| 208 | + "files": [File("/path/to/workspace/include/macro.h")], |
| 209 | + "messages": [ |
| 210 | + "Macro expanded from " |
| 211 | + "/path/to/workspace/include/macro.h:5:10" |
| 212 | + ], |
| 213 | + "names": ["TEST_MACRO"], |
| 214 | + "lines": [5], |
| 215 | + "columns": [10], |
| 216 | + "expected_messages": [ |
| 217 | + "Macro expanded from include/macro.h:5:10" |
| 218 | + ], |
| 219 | + "expected_paths": ["include/macro.h"], |
| 220 | + }, |
| 221 | + # Multiple macros |
| 222 | + { |
| 223 | + "name": "multiple_macros", |
| 224 | + "files": [ |
| 225 | + File("/path/to/workspace/include/macro1.h"), |
| 226 | + File("/path/to/workspace/include/macro2.h"), |
| 227 | + ], |
| 228 | + "messages": [ |
| 229 | + "First macro from " |
| 230 | + "/path/to/workspace/include/macro1.h:5:10", |
| 231 | + "Second macro from " |
| 232 | + "/path/to/workspace/include/macro2.h:15:20", |
| 233 | + ], |
| 234 | + "names": ["MACRO1", "MACRO2"], |
| 235 | + "lines": [5, 15], |
| 236 | + "columns": [10, 20], |
| 237 | + "expected_messages": [ |
| 238 | + "First macro from include/macro1.h:5:10", |
| 239 | + "Second macro from include/macro2.h:15:20", |
| 240 | + ], |
| 241 | + "expected_paths": ["include/macro1.h", "include/macro2.h"], |
| 242 | + }, |
| 243 | + # Macro with multiple path references |
| 244 | + { |
| 245 | + "name": "multiple_paths", |
| 246 | + "files": [File("/path/to/workspace/include/macro.h")], |
| 247 | + "messages": [ |
| 248 | + "Macro expanded from " |
| 249 | + "/path/to/workspace/include/macro.h:5:10 " |
| 250 | + "includes /path/to/workspace/include/header.h:3:4" |
| 251 | + ], |
| 252 | + "names": ["TEST_MACRO"], |
| 253 | + "lines": [5], |
| 254 | + "columns": [10], |
| 255 | + "expected_messages": [ |
| 256 | + "Macro expanded from include/macro.h:5:10 " |
| 257 | + "includes include/header.h:3:4" |
| 258 | + ], |
| 259 | + "expected_paths": ["include/macro.h"], |
| 260 | + }, |
| 261 | + ] |
| 262 | + |
| 263 | + for case in test_cases: |
| 264 | + macros = [] |
| 265 | + for i in range(len(case["files"])): |
| 266 | + macros.append( |
| 267 | + MacroExpansion( |
| 268 | + message=case["messages"][i], |
| 269 | + name=case["names"][i], |
| 270 | + file=case["files"][i], |
| 271 | + line=case["lines"][i], |
| 272 | + column=case["columns"][i], |
| 273 | + ) |
| 274 | + ) |
| 275 | + |
| 276 | + report = Report( |
| 277 | + file=test_file, |
| 278 | + line=10, |
| 279 | + column=20, |
| 280 | + message=f"Error in macro expansion - {case['name']}", |
| 281 | + checker_name="test-checker", |
| 282 | + severity="HIGH", |
| 283 | + macro_expansions=macros, |
| 284 | + ) |
| 285 | + |
| 286 | + report.trim_path_prefixes(["/path/to/workspace"]) |
| 287 | + |
| 288 | + for i, (expected_msg, expected_path) in enumerate( |
| 289 | + zip(case["expected_messages"], case["expected_paths"]) |
| 290 | + ): |
| 291 | + self.assertEqual( |
| 292 | + expected_msg, |
| 293 | + report.macro_expansions[i].message, |
| 294 | + f"Failed to trim message in {case['name']} case", |
| 295 | + ) |
| 296 | + self.assertEqual( |
| 297 | + expected_path, |
| 298 | + report.macro_expansions[i].file.path, |
| 299 | + f"Failed to trim file path in {case['name']} case", |
| 300 | + ) |
| 301 | + |
| 302 | + def test_macro_expansion_edge_cases(self): |
| 303 | + """Test trimming path prefixes in macro expansions with edge cases.""" |
| 304 | + |
| 305 | + test_file = File("/path/to/workspace/src/example.cpp") |
| 306 | + |
| 307 | + edge_cases = [ |
| 308 | + (File(""), "Empty file path"), |
| 309 | + (File("/"), "Root path only"), |
| 310 | + (File("/path/to/workspace/"), "Directory path ending with slash"), |
| 311 | + (File("relative/path.h"), "Relative path"), |
| 312 | + ] |
| 313 | + |
| 314 | + for file, desc in edge_cases: |
| 315 | + macro = MacroExpansion( |
| 316 | + message=f"Macro with {desc}: {file.path}", |
| 317 | + name="TEST_MACRO", |
| 318 | + file=file, |
| 319 | + line=1, |
| 320 | + column=1, |
| 321 | + ) |
| 322 | + |
| 323 | + report = Report( |
| 324 | + file=test_file, |
| 325 | + line=10, |
| 326 | + column=20, |
| 327 | + message=f"Error in macro expansion - {desc}", |
| 328 | + checker_name="test-checker", |
| 329 | + severity="HIGH", |
| 330 | + macro_expansions=[macro], |
| 331 | + ) |
| 332 | + |
| 333 | + report.trim_path_prefixes(["/path/to/workspace"]) |
| 334 | + |
| 335 | + if desc in ["Empty file path", "Root path only"]: |
| 336 | + self.assertEqual( |
| 337 | + file.path, report.macro_expansions[0].file.path |
| 338 | + ) |
| 339 | + elif desc == "Directory path ending with slash": |
| 340 | + self.assertEqual("", report.macro_expansions[0].file.path) |
| 341 | + else: |
| 342 | + # Relative path unchanged |
| 343 | + self.assertEqual( |
| 344 | + file.path, report.macro_expansions[0].file.path |
| 345 | + ) |
0 commit comments