OLD | NEW |
(Empty) | |
| 1 # Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 |
| 2 # For details: https://bitbucket.org/ned/coveragepy/src/default/NOTICE.txt |
| 3 |
| 4 """Tests for coverage.data""" |
| 5 |
| 6 import glob |
| 7 import json |
| 8 import os |
| 9 import os.path |
| 10 import re |
| 11 |
| 12 import mock |
| 13 |
| 14 from coverage.backward import StringIO |
| 15 from coverage.data import CoverageData, CoverageDataFiles, debug_main, canonical
ize_json_data |
| 16 from coverage.files import PathAliases, canonical_filename |
| 17 from coverage.misc import CoverageException |
| 18 |
| 19 from tests.coveragetest import CoverageTest, DebugControlString |
| 20 |
| 21 |
| 22 LINES_1 = { |
| 23 'a.py': {1: None, 2: None}, |
| 24 'b.py': {3: None}, |
| 25 } |
| 26 SUMMARY_1 = {'a.py': 2, 'b.py': 1} |
| 27 MEASURED_FILES_1 = ['a.py', 'b.py'] |
| 28 A_PY_LINES_1 = [1, 2] |
| 29 B_PY_LINES_1 = [3] |
| 30 |
| 31 LINES_2 = { |
| 32 'a.py': {1: None, 5: None}, |
| 33 'c.py': {17: None}, |
| 34 } |
| 35 SUMMARY_1_2 = {'a.py': 3, 'b.py': 1, 'c.py': 1} |
| 36 MEASURED_FILES_1_2 = ['a.py', 'b.py', 'c.py'] |
| 37 |
| 38 ARCS_3 = { |
| 39 'x.py': { |
| 40 (-1, 1): None, |
| 41 (1, 2): None, |
| 42 (2, 3): None, |
| 43 (3, -1): None, |
| 44 }, |
| 45 'y.py': { |
| 46 (-1, 17): None, |
| 47 (17, 23): None, |
| 48 (23, -1): None, |
| 49 }, |
| 50 } |
| 51 X_PY_ARCS_3 = [(-1, 1), (1, 2), (2, 3), (3, -1)] |
| 52 Y_PY_ARCS_3 = [(-1, 17), (17, 23), (23, -1)] |
| 53 SUMMARY_3 = {'x.py': 3, 'y.py': 2} |
| 54 MEASURED_FILES_3 = ['x.py', 'y.py'] |
| 55 X_PY_LINES_3 = [1, 2, 3] |
| 56 Y_PY_LINES_3 = [17, 23] |
| 57 |
| 58 ARCS_4 = { |
| 59 'x.py': { |
| 60 (-1, 2): None, |
| 61 (2, 5): None, |
| 62 (5, -1): None, |
| 63 }, |
| 64 'z.py': { |
| 65 (-1, 1000): None, |
| 66 (1000, -1): None, |
| 67 }, |
| 68 } |
| 69 SUMMARY_3_4 = {'x.py': 5, 'y.py': 2, 'z.py': 1} |
| 70 MEASURED_FILES_3_4 = ['x.py', 'y.py', 'z.py'] |
| 71 |
| 72 |
| 73 class DataTestHelpers(CoverageTest): |
| 74 """Test helpers for data tests.""" |
| 75 |
| 76 def assert_line_counts(self, covdata, line_counts, fullpath=False): |
| 77 """Check that the line_counts of `covdata` is `line_counts`.""" |
| 78 self.assertEqual(covdata.line_counts(fullpath), line_counts) |
| 79 |
| 80 def assert_measured_files(self, covdata, measured): |
| 81 """Check that `covdata`'s measured files are `measured`.""" |
| 82 self.assertCountEqual(covdata.measured_files(), measured) |
| 83 |
| 84 def assert_lines1_data(self, covdata): |
| 85 """Check that `covdata` has the data from LINES1.""" |
| 86 self.assert_line_counts(covdata, SUMMARY_1) |
| 87 self.assert_measured_files(covdata, MEASURED_FILES_1) |
| 88 self.assertCountEqual(covdata.lines("a.py"), A_PY_LINES_1) |
| 89 self.assertEqual(covdata.run_infos(), []) |
| 90 self.assertFalse(covdata.has_arcs()) |
| 91 |
| 92 def assert_arcs3_data(self, covdata): |
| 93 """Check that `covdata` has the data from ARCS3.""" |
| 94 self.assert_line_counts(covdata, SUMMARY_3) |
| 95 self.assert_measured_files(covdata, MEASURED_FILES_3) |
| 96 self.assertCountEqual(covdata.lines("x.py"), X_PY_LINES_3) |
| 97 self.assertCountEqual(covdata.arcs("x.py"), X_PY_ARCS_3) |
| 98 self.assertCountEqual(covdata.lines("y.py"), Y_PY_LINES_3) |
| 99 self.assertCountEqual(covdata.arcs("y.py"), Y_PY_ARCS_3) |
| 100 self.assertTrue(covdata.has_arcs()) |
| 101 self.assertEqual(covdata.run_infos(), []) |
| 102 |
| 103 |
| 104 class CoverageDataTest(DataTestHelpers, CoverageTest): |
| 105 """Test cases for CoverageData.""" |
| 106 |
| 107 run_in_temp_dir = False |
| 108 |
| 109 def test_empty_data_is_false(self): |
| 110 covdata = CoverageData() |
| 111 self.assertFalse(covdata) |
| 112 |
| 113 def test_line_data_is_true(self): |
| 114 covdata = CoverageData() |
| 115 covdata.add_lines(LINES_1) |
| 116 self.assertTrue(covdata) |
| 117 |
| 118 def test_arc_data_is_true(self): |
| 119 covdata = CoverageData() |
| 120 covdata.add_arcs(ARCS_3) |
| 121 self.assertTrue(covdata) |
| 122 |
| 123 def test_empty_line_data_is_false(self): |
| 124 covdata = CoverageData() |
| 125 covdata.add_lines({}) |
| 126 self.assertFalse(covdata) |
| 127 |
| 128 def test_empty_arc_data_is_false(self): |
| 129 covdata = CoverageData() |
| 130 covdata.add_arcs({}) |
| 131 self.assertFalse(covdata) |
| 132 |
| 133 def test_adding_lines(self): |
| 134 covdata = CoverageData() |
| 135 covdata.add_lines(LINES_1) |
| 136 self.assert_lines1_data(covdata) |
| 137 |
| 138 def test_adding_arcs(self): |
| 139 covdata = CoverageData() |
| 140 covdata.add_arcs(ARCS_3) |
| 141 self.assert_arcs3_data(covdata) |
| 142 |
| 143 def test_ok_to_add_lines_twice(self): |
| 144 covdata = CoverageData() |
| 145 covdata.add_lines(LINES_1) |
| 146 covdata.add_lines(LINES_2) |
| 147 self.assert_line_counts(covdata, SUMMARY_1_2) |
| 148 self.assert_measured_files(covdata, MEASURED_FILES_1_2) |
| 149 |
| 150 def test_ok_to_add_arcs_twice(self): |
| 151 covdata = CoverageData() |
| 152 covdata.add_arcs(ARCS_3) |
| 153 covdata.add_arcs(ARCS_4) |
| 154 self.assert_line_counts(covdata, SUMMARY_3_4) |
| 155 self.assert_measured_files(covdata, MEASURED_FILES_3_4) |
| 156 |
| 157 def test_cant_add_arcs_with_lines(self): |
| 158 covdata = CoverageData() |
| 159 covdata.add_lines(LINES_1) |
| 160 with self.assertRaisesRegex(CoverageException, "Can't add arcs to existi
ng line data"): |
| 161 covdata.add_arcs(ARCS_3) |
| 162 |
| 163 def test_cant_add_lines_with_arcs(self): |
| 164 covdata = CoverageData() |
| 165 covdata.add_arcs(ARCS_3) |
| 166 with self.assertRaisesRegex(CoverageException, "Can't add lines to exist
ing arc data"): |
| 167 covdata.add_lines(LINES_1) |
| 168 |
| 169 def test_touch_file_with_lines(self): |
| 170 covdata = CoverageData() |
| 171 covdata.add_lines(LINES_1) |
| 172 covdata.touch_file('zzz.py') |
| 173 self.assert_measured_files(covdata, MEASURED_FILES_1 + ['zzz.py']) |
| 174 |
| 175 def test_touch_file_with_arcs(self): |
| 176 covdata = CoverageData() |
| 177 covdata.add_arcs(ARCS_3) |
| 178 covdata.touch_file('zzz.py') |
| 179 self.assert_measured_files(covdata, MEASURED_FILES_3 + ['zzz.py']) |
| 180 |
| 181 def test_no_lines_vs_unmeasured_file(self): |
| 182 covdata = CoverageData() |
| 183 covdata.add_lines(LINES_1) |
| 184 covdata.touch_file('zzz.py') |
| 185 self.assertEqual(covdata.lines('zzz.py'), []) |
| 186 self.assertIsNone(covdata.lines('no_such_file.py')) |
| 187 |
| 188 def test_run_info(self): |
| 189 covdata = CoverageData() |
| 190 self.assertEqual(covdata.run_infos(), []) |
| 191 covdata.add_run_info(hello="there") |
| 192 self.assertEqual(covdata.run_infos(), [{"hello": "there"}]) |
| 193 covdata.add_run_info(count=17) |
| 194 self.assertEqual(covdata.run_infos(), [{"hello": "there", "count": 17}]) |
| 195 |
| 196 def test_no_arcs_vs_unmeasured_file(self): |
| 197 covdata = CoverageData() |
| 198 covdata.add_arcs(ARCS_3) |
| 199 covdata.touch_file('zzz.py') |
| 200 self.assertEqual(covdata.lines('zzz.py'), []) |
| 201 self.assertIsNone(covdata.lines('no_such_file.py')) |
| 202 self.assertEqual(covdata.arcs('zzz.py'), []) |
| 203 self.assertIsNone(covdata.arcs('no_such_file.py')) |
| 204 |
| 205 def test_file_tracer_name(self): |
| 206 covdata = CoverageData() |
| 207 covdata.add_lines({ |
| 208 "p1.foo": dict.fromkeys([1, 2, 3]), |
| 209 "p2.html": dict.fromkeys([10, 11, 12]), |
| 210 "main.py": dict.fromkeys([20]), |
| 211 }) |
| 212 covdata.add_file_tracers({"p1.foo": "p1.plugin", "p2.html": "p2.plugin"}
) |
| 213 self.assertEqual(covdata.file_tracer("p1.foo"), "p1.plugin") |
| 214 self.assertEqual(covdata.file_tracer("main.py"), "") |
| 215 self.assertIsNone(covdata.file_tracer("p3.not_here")) |
| 216 |
| 217 def test_cant_file_tracer_unmeasured_files(self): |
| 218 covdata = CoverageData() |
| 219 msg = "Can't add file tracer data for unmeasured file 'p1.foo'" |
| 220 with self.assertRaisesRegex(CoverageException, msg): |
| 221 covdata.add_file_tracers({"p1.foo": "p1.plugin"}) |
| 222 |
| 223 covdata.add_lines({"p2.html": dict.fromkeys([10, 11, 12])}) |
| 224 with self.assertRaisesRegex(CoverageException, msg): |
| 225 covdata.add_file_tracers({"p1.foo": "p1.plugin"}) |
| 226 |
| 227 def test_cant_change_file_tracer_name(self): |
| 228 covdata = CoverageData() |
| 229 covdata.add_lines({"p1.foo": dict.fromkeys([1, 2, 3])}) |
| 230 covdata.add_file_tracers({"p1.foo": "p1.plugin"}) |
| 231 |
| 232 msg = "Conflicting file tracer name for 'p1.foo': 'p1.plugin' vs 'p1.plu
gin.foo'" |
| 233 with self.assertRaisesRegex(CoverageException, msg): |
| 234 covdata.add_file_tracers({"p1.foo": "p1.plugin.foo"}) |
| 235 |
| 236 def test_update_lines(self): |
| 237 covdata1 = CoverageData() |
| 238 covdata1.add_lines(LINES_1) |
| 239 |
| 240 covdata2 = CoverageData() |
| 241 covdata2.add_lines(LINES_2) |
| 242 |
| 243 covdata3 = CoverageData() |
| 244 covdata3.update(covdata1) |
| 245 covdata3.update(covdata2) |
| 246 |
| 247 self.assert_line_counts(covdata3, SUMMARY_1_2) |
| 248 self.assert_measured_files(covdata3, MEASURED_FILES_1_2) |
| 249 self.assertEqual(covdata3.run_infos(), []) |
| 250 |
| 251 def test_update_arcs(self): |
| 252 covdata1 = CoverageData() |
| 253 covdata1.add_arcs(ARCS_3) |
| 254 |
| 255 covdata2 = CoverageData() |
| 256 covdata2.add_arcs(ARCS_4) |
| 257 |
| 258 covdata3 = CoverageData() |
| 259 covdata3.update(covdata1) |
| 260 covdata3.update(covdata2) |
| 261 |
| 262 self.assert_line_counts(covdata3, SUMMARY_3_4) |
| 263 self.assert_measured_files(covdata3, MEASURED_FILES_3_4) |
| 264 self.assertEqual(covdata3.run_infos(), []) |
| 265 |
| 266 def test_update_run_info(self): |
| 267 covdata1 = CoverageData() |
| 268 covdata1.add_arcs(ARCS_3) |
| 269 covdata1.add_run_info(hello="there", count=17) |
| 270 |
| 271 covdata2 = CoverageData() |
| 272 covdata2.add_arcs(ARCS_4) |
| 273 covdata2.add_run_info(hello="goodbye", count=23) |
| 274 |
| 275 covdata3 = CoverageData() |
| 276 covdata3.update(covdata1) |
| 277 covdata3.update(covdata2) |
| 278 |
| 279 self.assertEqual(covdata3.run_infos(), [ |
| 280 {'hello': 'there', 'count': 17}, |
| 281 {'hello': 'goodbye', 'count': 23}, |
| 282 ]) |
| 283 |
| 284 def test_update_cant_mix_lines_and_arcs(self): |
| 285 covdata1 = CoverageData() |
| 286 covdata1.add_lines(LINES_1) |
| 287 |
| 288 covdata2 = CoverageData() |
| 289 covdata2.add_arcs(ARCS_3) |
| 290 |
| 291 with self.assertRaisesRegex(CoverageException, "Can't combine arc data w
ith line data"): |
| 292 covdata1.update(covdata2) |
| 293 |
| 294 with self.assertRaisesRegex(CoverageException, "Can't combine line data
with arc data"): |
| 295 covdata2.update(covdata1) |
| 296 |
| 297 def test_update_file_tracers(self): |
| 298 covdata1 = CoverageData() |
| 299 covdata1.add_lines({ |
| 300 "p1.html": dict.fromkeys([1, 2, 3, 4]), |
| 301 "p2.html": dict.fromkeys([5, 6, 7]), |
| 302 "main.py": dict.fromkeys([10, 11, 12]), |
| 303 }) |
| 304 covdata1.add_file_tracers({ |
| 305 "p1.html": "html.plugin", |
| 306 "p2.html": "html.plugin2", |
| 307 }) |
| 308 |
| 309 covdata2 = CoverageData() |
| 310 covdata2.add_lines({ |
| 311 "p1.html": dict.fromkeys([3, 4, 5, 6]), |
| 312 "p2.html": dict.fromkeys([7, 8, 9]), |
| 313 "p3.foo": dict.fromkeys([1000, 1001]), |
| 314 "main.py": dict.fromkeys([10, 11, 12]), |
| 315 }) |
| 316 covdata2.add_file_tracers({ |
| 317 "p1.html": "html.plugin", |
| 318 "p2.html": "html.plugin2", |
| 319 "p3.foo": "foo_plugin", |
| 320 }) |
| 321 |
| 322 covdata3 = CoverageData() |
| 323 covdata3.update(covdata1) |
| 324 covdata3.update(covdata2) |
| 325 self.assertEqual(covdata3.file_tracer("p1.html"), "html.plugin") |
| 326 self.assertEqual(covdata3.file_tracer("p2.html"), "html.plugin2") |
| 327 self.assertEqual(covdata3.file_tracer("p3.foo"), "foo_plugin") |
| 328 self.assertEqual(covdata3.file_tracer("main.py"), "") |
| 329 |
| 330 def test_update_conflicting_file_tracers(self): |
| 331 covdata1 = CoverageData() |
| 332 covdata1.add_lines({"p1.html": dict.fromkeys([1, 2, 3])}) |
| 333 covdata1.add_file_tracers({"p1.html": "html.plugin"}) |
| 334 |
| 335 covdata2 = CoverageData() |
| 336 covdata2.add_lines({"p1.html": dict.fromkeys([1, 2, 3])}) |
| 337 covdata2.add_file_tracers({"p1.html": "html.other_plugin"}) |
| 338 |
| 339 msg = "Conflicting file tracer name for 'p1.html': 'html.plugin' vs 'htm
l.other_plugin'" |
| 340 with self.assertRaisesRegex(CoverageException, msg): |
| 341 covdata1.update(covdata2) |
| 342 |
| 343 msg = "Conflicting file tracer name for 'p1.html': 'html.other_plugin' v
s 'html.plugin'" |
| 344 with self.assertRaisesRegex(CoverageException, msg): |
| 345 covdata2.update(covdata1) |
| 346 |
| 347 def test_update_file_tracer_vs_no_file_tracer(self): |
| 348 covdata1 = CoverageData() |
| 349 covdata1.add_lines({"p1.html": dict.fromkeys([1, 2, 3])}) |
| 350 covdata1.add_file_tracers({"p1.html": "html.plugin"}) |
| 351 |
| 352 covdata2 = CoverageData() |
| 353 covdata2.add_lines({"p1.html": dict.fromkeys([1, 2, 3])}) |
| 354 |
| 355 msg = "Conflicting file tracer name for 'p1.html': 'html.plugin' vs ''" |
| 356 with self.assertRaisesRegex(CoverageException, msg): |
| 357 covdata1.update(covdata2) |
| 358 |
| 359 msg = "Conflicting file tracer name for 'p1.html': '' vs 'html.plugin'" |
| 360 with self.assertRaisesRegex(CoverageException, msg): |
| 361 covdata2.update(covdata1) |
| 362 |
| 363 def test_add_to_hash_with_lines(self): |
| 364 covdata = CoverageData() |
| 365 covdata.add_lines(LINES_1) |
| 366 hasher = mock.Mock() |
| 367 covdata.add_to_hash("a.py", hasher) |
| 368 self.assertEqual(hasher.method_calls, [ |
| 369 mock.call.update([1, 2]), # lines |
| 370 mock.call.update(""), # file_tracer name |
| 371 ]) |
| 372 |
| 373 def test_add_to_hash_with_arcs(self): |
| 374 covdata = CoverageData() |
| 375 covdata.add_arcs(ARCS_3) |
| 376 covdata.add_file_tracers({"y.py": "hologram_plugin"}) |
| 377 hasher = mock.Mock() |
| 378 covdata.add_to_hash("y.py", hasher) |
| 379 self.assertEqual(hasher.method_calls, [ |
| 380 mock.call.update([(-1, 17), (17, 23), (23, -1)]), # arcs |
| 381 mock.call.update("hologram_plugin"), # file_tracer na
me |
| 382 ]) |
| 383 |
| 384 def test_add_to_lines_hash_with_missing_file(self): |
| 385 # https://bitbucket.org/ned/coveragepy/issues/403 |
| 386 covdata = CoverageData() |
| 387 covdata.add_lines(LINES_1) |
| 388 hasher = mock.Mock() |
| 389 covdata.add_to_hash("missing.py", hasher) |
| 390 self.assertEqual(hasher.method_calls, [ |
| 391 mock.call.update([]), |
| 392 mock.call.update(None), |
| 393 ]) |
| 394 |
| 395 def test_add_to_arcs_hash_with_missing_file(self): |
| 396 # https://bitbucket.org/ned/coveragepy/issues/403 |
| 397 covdata = CoverageData() |
| 398 covdata.add_arcs(ARCS_3) |
| 399 covdata.add_file_tracers({"y.py": "hologram_plugin"}) |
| 400 hasher = mock.Mock() |
| 401 covdata.add_to_hash("missing.py", hasher) |
| 402 self.assertEqual(hasher.method_calls, [ |
| 403 mock.call.update([]), |
| 404 mock.call.update(None), |
| 405 ]) |
| 406 |
| 407 def test_empty_lines_are_still_lines(self): |
| 408 covdata = CoverageData() |
| 409 covdata.add_lines({}) |
| 410 covdata.touch_file("abc.py") |
| 411 self.assertFalse(covdata.has_arcs()) |
| 412 |
| 413 def test_empty_arcs_are_still_arcs(self): |
| 414 covdata = CoverageData() |
| 415 covdata.add_arcs({}) |
| 416 covdata.touch_file("abc.py") |
| 417 self.assertTrue(covdata.has_arcs()) |
| 418 |
| 419 def test_read_and_write_are_opposites(self): |
| 420 covdata1 = CoverageData() |
| 421 covdata1.add_arcs(ARCS_3) |
| 422 stringio = StringIO() |
| 423 covdata1.write_fileobj(stringio) |
| 424 |
| 425 stringio.seek(0) |
| 426 covdata2 = CoverageData() |
| 427 covdata2.read_fileobj(stringio) |
| 428 self.assert_arcs3_data(covdata2) |
| 429 |
| 430 |
| 431 class CoverageDataTestInTempDir(DataTestHelpers, CoverageTest): |
| 432 """Tests of CoverageData that need a temporary directory to make files.""" |
| 433 |
| 434 def test_read_write_lines(self): |
| 435 covdata1 = CoverageData() |
| 436 covdata1.add_lines(LINES_1) |
| 437 covdata1.write_file("lines.dat") |
| 438 |
| 439 covdata2 = CoverageData() |
| 440 covdata2.read_file("lines.dat") |
| 441 self.assert_lines1_data(covdata2) |
| 442 |
| 443 def test_read_write_arcs(self): |
| 444 covdata1 = CoverageData() |
| 445 covdata1.add_arcs(ARCS_3) |
| 446 covdata1.write_file("arcs.dat") |
| 447 |
| 448 covdata2 = CoverageData() |
| 449 covdata2.read_file("arcs.dat") |
| 450 self.assert_arcs3_data(covdata2) |
| 451 |
| 452 def test_read_errors(self): |
| 453 covdata = CoverageData() |
| 454 |
| 455 msg = r"Couldn't read data from '{0}': \S+" |
| 456 self.make_file("xyzzy.dat", "xyzzy") |
| 457 with self.assertRaisesRegex(CoverageException, msg.format("xyzzy.dat")): |
| 458 covdata.read_file("xyzzy.dat") |
| 459 |
| 460 self.make_file("empty.dat", "") |
| 461 with self.assertRaisesRegex(CoverageException, msg.format("empty.dat")): |
| 462 covdata.read_file("empty.dat") |
| 463 |
| 464 with self.assertRaisesRegex(CoverageException, msg.format("nonexistent.d
at")): |
| 465 covdata.read_file("nonexistent.dat") |
| 466 |
| 467 self.make_file("misleading.dat", CoverageData._GO_AWAY + " this isn't JS
ON") |
| 468 with self.assertRaisesRegex(CoverageException, msg.format("misleading.da
t")): |
| 469 covdata.read_file("misleading.dat") |
| 470 |
| 471 # After all that, no data should be in our CoverageData. |
| 472 self.assertFalse(covdata) |
| 473 |
| 474 def test_debug_main(self): |
| 475 covdata1 = CoverageData() |
| 476 covdata1.add_lines(LINES_1) |
| 477 covdata1.write_file(".coverage") |
| 478 debug_main([]) |
| 479 |
| 480 covdata2 = CoverageData() |
| 481 covdata2.add_arcs(ARCS_3) |
| 482 covdata2.add_file_tracers({"y.py": "magic_plugin"}) |
| 483 covdata2.add_run_info(version="v3.14", chunks=["z", "a"]) |
| 484 covdata2.write_file("arcs.dat") |
| 485 |
| 486 covdata3 = CoverageData() |
| 487 covdata3.write_file("empty.dat") |
| 488 debug_main(["arcs.dat", "empty.dat"]) |
| 489 |
| 490 expected = { |
| 491 ".coverage": { |
| 492 "lines": { |
| 493 "a.py": [1, 2], |
| 494 "b.py": [3], |
| 495 }, |
| 496 }, |
| 497 "arcs.dat": { |
| 498 "arcs": { |
| 499 "x.py": [[-1, 1], [1, 2], [2, 3], [3, -1]], |
| 500 "y.py": [[-1, 17], [17, 23], [23, -1]], |
| 501 }, |
| 502 "file_tracers": {"y.py": "magic_plugin"}, |
| 503 "runs": [ |
| 504 { |
| 505 "chunks": ["z", "a"], |
| 506 "version": "v3.14", |
| 507 }, |
| 508 ], |
| 509 }, |
| 510 "empty.dat": {}, |
| 511 } |
| 512 pieces = re.split(r"(?m)-+ ([\w.]+) -+$", self.stdout()) |
| 513 for name, json_out in zip(pieces[1::2], pieces[2::2]): |
| 514 json_got = json.loads(json_out) |
| 515 canonicalize_json_data(json_got) |
| 516 self.assertEqual(expected[name], json_got) |
| 517 |
| 518 |
| 519 class CoverageDataFilesTest(DataTestHelpers, CoverageTest): |
| 520 """Tests of CoverageDataFiles.""" |
| 521 |
| 522 no_files_in_temp_dir = True |
| 523 |
| 524 def setUp(self): |
| 525 super(CoverageDataFilesTest, self).setUp() |
| 526 self.data_files = CoverageDataFiles() |
| 527 |
| 528 def test_reading_missing(self): |
| 529 self.assert_doesnt_exist(".coverage") |
| 530 covdata = CoverageData() |
| 531 self.data_files.read(covdata) |
| 532 self.assert_line_counts(covdata, {}) |
| 533 |
| 534 def test_writing_and_reading(self): |
| 535 covdata1 = CoverageData() |
| 536 covdata1.add_lines(LINES_1) |
| 537 self.data_files.write(covdata1) |
| 538 |
| 539 covdata2 = CoverageData() |
| 540 self.data_files.read(covdata2) |
| 541 self.assert_line_counts(covdata2, SUMMARY_1) |
| 542 |
| 543 def test_debug_output_with_debug_option(self): |
| 544 # With debug option dataio, we get debug output about reading and |
| 545 # writing files. |
| 546 debug = DebugControlString(options=["dataio"]) |
| 547 covdata1 = CoverageData(debug=debug) |
| 548 covdata1.add_lines(LINES_1) |
| 549 self.data_files.write(covdata1) |
| 550 |
| 551 covdata2 = CoverageData(debug=debug) |
| 552 self.data_files.read(covdata2) |
| 553 self.assert_line_counts(covdata2, SUMMARY_1) |
| 554 |
| 555 self.assertRegex( |
| 556 debug.get_output(), |
| 557 r"^Writing data to '.*\.coverage'\n" |
| 558 r"Reading data from '.*\.coverage'\n$" |
| 559 ) |
| 560 |
| 561 def test_debug_output_without_debug_option(self): |
| 562 # With a debug object, but not the dataio option, we don't get debug |
| 563 # output. |
| 564 debug = DebugControlString(options=[]) |
| 565 covdata1 = CoverageData(debug=debug) |
| 566 covdata1.add_lines(LINES_1) |
| 567 self.data_files.write(covdata1) |
| 568 |
| 569 covdata2 = CoverageData(debug=debug) |
| 570 self.data_files.read(covdata2) |
| 571 self.assert_line_counts(covdata2, SUMMARY_1) |
| 572 |
| 573 self.assertEqual(debug.get_output(), "") |
| 574 |
| 575 def test_explicit_suffix(self): |
| 576 self.assert_doesnt_exist(".coverage.SUFFIX") |
| 577 covdata = CoverageData() |
| 578 covdata.add_lines(LINES_1) |
| 579 self.data_files.write(covdata, suffix='SUFFIX') |
| 580 self.assert_exists(".coverage.SUFFIX") |
| 581 self.assert_doesnt_exist(".coverage") |
| 582 |
| 583 def test_true_suffix(self): |
| 584 self.assertEqual(glob.glob(".coverage.*"), []) |
| 585 |
| 586 # suffix=True will make a randomly named data file. |
| 587 covdata1 = CoverageData() |
| 588 covdata1.add_lines(LINES_1) |
| 589 self.data_files.write(covdata1, suffix=True) |
| 590 self.assert_doesnt_exist(".coverage") |
| 591 data_files1 = glob.glob(".coverage.*") |
| 592 self.assertEqual(len(data_files1), 1) |
| 593 |
| 594 # Another suffix=True will choose a different name. |
| 595 covdata2 = CoverageData() |
| 596 covdata2.add_lines(LINES_1) |
| 597 self.data_files.write(covdata2, suffix=True) |
| 598 self.assert_doesnt_exist(".coverage") |
| 599 data_files2 = glob.glob(".coverage.*") |
| 600 self.assertEqual(len(data_files2), 2) |
| 601 |
| 602 # In addition to being different, the suffixes have the pid in them. |
| 603 self.assertTrue(all(str(os.getpid()) in fn for fn in data_files2)) |
| 604 |
| 605 def test_combining(self): |
| 606 self.assert_doesnt_exist(".coverage.1") |
| 607 self.assert_doesnt_exist(".coverage.2") |
| 608 |
| 609 covdata1 = CoverageData() |
| 610 covdata1.add_lines(LINES_1) |
| 611 self.data_files.write(covdata1, suffix='1') |
| 612 self.assert_exists(".coverage.1") |
| 613 self.assert_doesnt_exist(".coverage.2") |
| 614 |
| 615 covdata2 = CoverageData() |
| 616 covdata2.add_lines(LINES_2) |
| 617 self.data_files.write(covdata2, suffix='2') |
| 618 self.assert_exists(".coverage.2") |
| 619 |
| 620 covdata3 = CoverageData() |
| 621 self.data_files.combine_parallel_data(covdata3) |
| 622 self.assert_line_counts(covdata3, SUMMARY_1_2) |
| 623 self.assert_measured_files(covdata3, MEASURED_FILES_1_2) |
| 624 self.assert_doesnt_exist(".coverage.1") |
| 625 self.assert_doesnt_exist(".coverage.2") |
| 626 |
| 627 def test_erasing(self): |
| 628 covdata1 = CoverageData() |
| 629 covdata1.add_lines(LINES_1) |
| 630 self.data_files.write(covdata1) |
| 631 |
| 632 covdata1.erase() |
| 633 self.assert_line_counts(covdata1, {}) |
| 634 |
| 635 self.data_files.erase() |
| 636 covdata2 = CoverageData() |
| 637 self.data_files.read(covdata2) |
| 638 self.assert_line_counts(covdata2, {}) |
| 639 |
| 640 def test_erasing_parallel(self): |
| 641 self.make_file("datafile.1") |
| 642 self.make_file("datafile.2") |
| 643 self.make_file(".coverage") |
| 644 data_files = CoverageDataFiles("datafile") |
| 645 data_files.erase(parallel=True) |
| 646 self.assert_doesnt_exist("datafile.1") |
| 647 self.assert_doesnt_exist("datafile.2") |
| 648 self.assert_exists(".coverage") |
| 649 |
| 650 def read_json_data_file(self, fname): |
| 651 """Read a JSON data file for testing the JSON directly.""" |
| 652 with open(fname, 'r') as fdata: |
| 653 go_away = fdata.read(len(CoverageData._GO_AWAY)) |
| 654 self.assertEqual(go_away, CoverageData._GO_AWAY) |
| 655 return json.load(fdata) |
| 656 |
| 657 def test_file_format(self): |
| 658 # Write with CoverageData, then read the JSON explicitly. |
| 659 covdata = CoverageData() |
| 660 covdata.add_lines(LINES_1) |
| 661 self.data_files.write(covdata) |
| 662 |
| 663 data = self.read_json_data_file(".coverage") |
| 664 |
| 665 lines = data['lines'] |
| 666 self.assertCountEqual(lines.keys(), MEASURED_FILES_1) |
| 667 self.assertCountEqual(lines['a.py'], A_PY_LINES_1) |
| 668 self.assertCountEqual(lines['b.py'], B_PY_LINES_1) |
| 669 # If not measuring branches, there's no arcs entry. |
| 670 self.assertNotIn('arcs', data) |
| 671 # If no file tracers were involved, there's no file_tracers entry. |
| 672 self.assertNotIn('file_tracers', data) |
| 673 |
| 674 def test_file_format_with_arcs(self): |
| 675 # Write with CoverageData, then read the JSON explicitly. |
| 676 covdata = CoverageData() |
| 677 covdata.add_arcs(ARCS_3) |
| 678 self.data_files.write(covdata) |
| 679 |
| 680 data = self.read_json_data_file(".coverage") |
| 681 |
| 682 self.assertNotIn('lines', data) |
| 683 arcs = data['arcs'] |
| 684 self.assertCountEqual(arcs.keys(), MEASURED_FILES_3) |
| 685 self.assertCountEqual(arcs['x.py'], map(list, X_PY_ARCS_3)) |
| 686 self.assertCountEqual(arcs['y.py'], map(list, Y_PY_ARCS_3)) |
| 687 # If no file tracers were involved, there's no file_tracers entry. |
| 688 self.assertNotIn('file_tracers', data) |
| 689 |
| 690 def test_writing_to_other_file(self): |
| 691 data_files = CoverageDataFiles(".otherfile") |
| 692 covdata = CoverageData() |
| 693 covdata.add_lines(LINES_1) |
| 694 data_files.write(covdata) |
| 695 self.assert_doesnt_exist(".coverage") |
| 696 self.assert_exists(".otherfile") |
| 697 |
| 698 data_files.write(covdata, suffix="extra") |
| 699 self.assert_exists(".otherfile.extra") |
| 700 self.assert_doesnt_exist(".coverage") |
| 701 |
| 702 def test_combining_with_aliases(self): |
| 703 covdata1 = CoverageData() |
| 704 covdata1.add_lines({ |
| 705 '/home/ned/proj/src/a.py': {1: None, 2: None}, |
| 706 '/home/ned/proj/src/sub/b.py': {3: None}, |
| 707 '/home/ned/proj/src/template.html': {10: None}, |
| 708 }) |
| 709 covdata1.add_file_tracers({ |
| 710 '/home/ned/proj/src/template.html': 'html.plugin', |
| 711 }) |
| 712 self.data_files.write(covdata1, suffix='1') |
| 713 |
| 714 covdata2 = CoverageData() |
| 715 covdata2.add_lines({ |
| 716 r'c:\ned\test\a.py': {4: None, 5: None}, |
| 717 r'c:\ned\test\sub\b.py': {3: None, 6: None}, |
| 718 }) |
| 719 self.data_files.write(covdata2, suffix='2') |
| 720 |
| 721 covdata3 = CoverageData() |
| 722 aliases = PathAliases() |
| 723 aliases.add("/home/ned/proj/src/", "./") |
| 724 aliases.add(r"c:\ned\test", "./") |
| 725 self.data_files.combine_parallel_data(covdata3, aliases=aliases) |
| 726 |
| 727 apy = canonical_filename('./a.py') |
| 728 sub_bpy = canonical_filename('./sub/b.py') |
| 729 template_html = canonical_filename('./template.html') |
| 730 |
| 731 self.assert_line_counts(covdata3, {apy: 4, sub_bpy: 2, template_html: 1}
, fullpath=True) |
| 732 self.assert_measured_files(covdata3, [apy, sub_bpy, template_html]) |
| 733 self.assertEqual(covdata3.file_tracer(template_html), 'html.plugin') |
| 734 |
| 735 def test_combining_from_different_directories(self): |
| 736 covdata1 = CoverageData() |
| 737 covdata1.add_lines(LINES_1) |
| 738 os.makedirs('cov1') |
| 739 covdata1.write_file('cov1/.coverage.1') |
| 740 |
| 741 covdata2 = CoverageData() |
| 742 covdata2.add_lines(LINES_2) |
| 743 os.makedirs('cov2') |
| 744 covdata2.write_file('cov2/.coverage.2') |
| 745 |
| 746 # This data won't be included. |
| 747 covdata_xxx = CoverageData() |
| 748 covdata_xxx.add_arcs(ARCS_3) |
| 749 covdata_xxx.write_file('.coverage.xxx') |
| 750 |
| 751 covdata3 = CoverageData() |
| 752 self.data_files.combine_parallel_data(covdata3, data_paths=['cov1', 'cov
2']) |
| 753 |
| 754 self.assert_line_counts(covdata3, SUMMARY_1_2) |
| 755 self.assert_measured_files(covdata3, MEASURED_FILES_1_2) |
| 756 self.assert_doesnt_exist("cov1/.coverage.1") |
| 757 self.assert_doesnt_exist("cov2/.coverage.2") |
| 758 self.assert_exists(".coverage.xxx") |
| 759 |
| 760 def test_combining_from_files(self): |
| 761 covdata1 = CoverageData() |
| 762 covdata1.add_lines(LINES_1) |
| 763 os.makedirs('cov1') |
| 764 covdata1.write_file('cov1/.coverage.1') |
| 765 |
| 766 covdata2 = CoverageData() |
| 767 covdata2.add_lines(LINES_2) |
| 768 os.makedirs('cov2') |
| 769 covdata2.write_file('cov2/.coverage.2') |
| 770 |
| 771 # This data won't be included. |
| 772 covdata_xxx = CoverageData() |
| 773 covdata_xxx.add_arcs(ARCS_3) |
| 774 covdata_xxx.write_file('.coverage.xxx') |
| 775 covdata_xxx.write_file('cov2/.coverage.xxx') |
| 776 |
| 777 covdata3 = CoverageData() |
| 778 self.data_files.combine_parallel_data(covdata3, data_paths=['cov1', 'cov
2/.coverage.2']) |
| 779 |
| 780 self.assert_line_counts(covdata3, SUMMARY_1_2) |
| 781 self.assert_measured_files(covdata3, MEASURED_FILES_1_2) |
| 782 self.assert_doesnt_exist("cov1/.coverage.1") |
| 783 self.assert_doesnt_exist("cov2/.coverage.2") |
| 784 self.assert_exists(".coverage.xxx") |
| 785 self.assert_exists("cov2/.coverage.xxx") |
| 786 |
| 787 def test_combining_from_nonexistent_directories(self): |
| 788 covdata = CoverageData() |
| 789 msg = "Couldn't combine from non-existent path 'xyzzy'" |
| 790 with self.assertRaisesRegex(CoverageException, msg): |
| 791 self.data_files.combine_parallel_data(covdata, data_paths=['xyzzy']) |
OLD | NEW |