summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--coverage/data.py34
-rw-r--r--tests/test_data.py68
2 files changed, 94 insertions, 8 deletions
diff --git a/coverage/data.py b/coverage/data.py
index be9ceba6..f50bf1cf 100644
--- a/coverage/data.py
+++ b/coverage/data.py
@@ -173,6 +173,9 @@ class CoverageData(object):
`line_data` is { filename: { lineno: None, ... }, ...}
"""
+ if self.has_arcs():
+ raise CoverageException("Can't add lines to existing arc data")
+
for filename, linenos in iitems(line_data):
self._lines.setdefault(filename, {}).update(linenos)
@@ -182,6 +185,9 @@ class CoverageData(object):
`arc_data` is { filename: { (l1,l2): None, ... }, ...}
"""
+ if self.has_lines():
+ raise CoverageException("Can't add arcs to existing line data")
+
for filename, arcs in iitems(arc_data):
self._arcs.setdefault(filename, {}).update(arcs)
@@ -200,14 +206,36 @@ class CoverageData(object):
re-map paths to match the local machine's.
"""
+ if ((self.has_lines() and other_data.has_arcs()) or
+ (self.has_arcs() and other_data.has_lines())):
+ raise CoverageException("Can't combine line data with arc data")
+
aliases = aliases or PathAliases()
+
+ # _lines: merge dicts.
for filename, file_data in iitems(other_data._lines):
filename = aliases.map(filename)
self._lines.setdefault(filename, {}).update(file_data)
+
+ # _arcs: merge dicts.
for filename, file_data in iitems(other_data._arcs):
filename = aliases.map(filename)
self._arcs.setdefault(filename, {}).update(file_data)
- self._plugins.update(other_data._plugins)
+
+ # _plugins: only have a string, so they have to agree.
+ for filename, plugin_name in iitems(other_data._plugins):
+ filename = aliases.map(filename)
+ this_plugin = self._plugins.get(filename)
+ # TODO: plugin=None could mean no filename recorded, or it could
+ # mean, handled by Python. Need to distinguish those cases.
+ if this_plugin is None:
+ self._plugins[filename] = plugin_name
+ elif this_plugin != plugin_name:
+ raise CoverageException(
+ "Conflicting plugin name for '%s': %s vs %s" % (
+ filename, this_plugin, plugin_name,
+ )
+ )
def touch_file(self, filename):
"""Ensure that `filename` appears in the data, empty if needed."""
@@ -247,6 +275,10 @@ class CoverageData(object):
__bool__ = __nonzero__
+ def has_lines(self):
+ """Does this data have lines?"""
+ return bool(self._lines)
+
def has_arcs(self):
"""Does this data have arcs?"""
return bool(self._arcs)
diff --git a/tests/test_data.py b/tests/test_data.py
index 3cae55bd..1d913c3d 100644
--- a/tests/test_data.py
+++ b/tests/test_data.py
@@ -45,6 +45,7 @@ Y_PY_ARCS_3 = [(-1, 17), (17, 23), (23, -1)]
SUMMARY_3 = {'x.py': 3, 'y.py': 2}
MEASURED_FILES_3 = ['x.py', 'y.py']
X_PY_LINES_3 = [1, 2, 3]
+Y_PY_LINES_3 = [17, 23]
class DataTestHelpers(CoverageTest):
@@ -92,12 +93,32 @@ class CoverageDataTest(DataTestHelpers, CoverageTest):
self.assert_measured_files(covdata, MEASURED_FILES_3)
self.assertCountEqual(covdata.lines("x.py"), X_PY_LINES_3)
self.assertCountEqual(covdata.arcs("x.py"), X_PY_ARCS_3)
+ self.assertCountEqual(covdata.lines("y.py"), Y_PY_LINES_3)
+ self.assertCountEqual(covdata.arcs("y.py"), Y_PY_ARCS_3)
- def test_touch_file(self):
+ def test_cant_add_arcs_to_lines(self):
covdata = CoverageData()
covdata.add_lines(DATA_1)
- covdata.touch_file('x.py')
- self.assert_measured_files(covdata, MEASURED_FILES_1 + ['x.py'])
+ with self.assertRaises(CoverageException):
+ covdata.add_arcs(ARC_DATA_3)
+
+ def test_cant_add_lines_to_arcs(self):
+ covdata = CoverageData()
+ covdata.add_arcs(ARC_DATA_3)
+ with self.assertRaises(CoverageException):
+ covdata.add_lines(DATA_1)
+
+ def test_touch_file_with_lines(self):
+ covdata = CoverageData()
+ covdata.add_lines(DATA_1)
+ covdata.touch_file('zzz.py')
+ self.assert_measured_files(covdata, MEASURED_FILES_1 + ['zzz.py'])
+
+ def test_touch_file_with_arcs(self):
+ covdata = CoverageData()
+ covdata.add_arcs(ARC_DATA_3)
+ covdata.touch_file('zzz.py')
+ self.assert_measured_files(covdata, MEASURED_FILES_3 + ['zzz.py'])
def test_plugin_name(self):
covdata = CoverageData()
@@ -105,6 +126,30 @@ class CoverageDataTest(DataTestHelpers, CoverageTest):
self.assertEqual(covdata.plugin_name("p1.foo"), "p1.plugin")
self.assertIsNone(covdata.plugin_name("p3.not_here"))
+ def test_update(self):
+ covdata1 = CoverageData()
+ covdata1.add_lines(DATA_1)
+
+ covdata2 = CoverageData()
+ covdata2.add_lines(DATA_2)
+
+ covdata3 = CoverageData()
+ covdata3.update(covdata1)
+ covdata3.update(covdata2)
+
+ self.assert_line_counts(covdata3, SUMMARY_1_2)
+ self.assert_measured_files(covdata3, MEASURED_FILES_1_2)
+
+ def test_update_cant_mix_lines_and_arcs(self):
+ covdata1 = CoverageData()
+ covdata1.add_lines(DATA_1)
+
+ covdata2 = CoverageData()
+ covdata2.add_arcs(ARC_DATA_3)
+
+ with self.assertRaises(CoverageException):
+ covdata1.update(covdata2)
+
class CoverageDataTestInTempDir(DataTestHelpers, CoverageTest):
"""Tests of CoverageData that need a temp dir to make files."""
@@ -131,6 +176,8 @@ class CoverageDataTestInTempDir(DataTestHelpers, CoverageTest):
self.assert_measured_files(covdata2, MEASURED_FILES_3)
self.assertCountEqual(covdata2.lines("x.py"), X_PY_LINES_3)
self.assertCountEqual(covdata2.arcs("x.py"), X_PY_ARCS_3)
+ self.assertCountEqual(covdata2.lines("y.py"), Y_PY_LINES_3)
+ self.assertCountEqual(covdata2.arcs("y.py"), Y_PY_ARCS_3)
def test_read_errors(self):
covdata = CoverageData()
@@ -207,18 +254,26 @@ class CoverageDataFilesTest(DataTestHelpers, CoverageTest):
self.assertEqual(debug.get_output(), "")
def test_combining(self):
+ self.assert_doesnt_exist(".coverage.1")
+ self.assert_doesnt_exist(".coverage.2")
+
covdata1 = CoverageData()
covdata1.add_lines(DATA_1)
self.data_files.write(covdata1, suffix='1')
+ self.assert_exists(".coverage.1")
+ self.assert_doesnt_exist(".coverage.2")
covdata2 = CoverageData()
covdata2.add_lines(DATA_2)
self.data_files.write(covdata2, suffix='2')
+ self.assert_exists(".coverage.2")
covdata3 = CoverageData()
self.data_files.combine_parallel_data(covdata3)
self.assert_line_counts(covdata3, SUMMARY_1_2)
self.assert_measured_files(covdata3, MEASURED_FILES_1_2)
+ self.assert_doesnt_exist(".coverage.1")
+ self.assert_doesnt_exist(".coverage.2")
def test_erasing(self):
covdata1 = CoverageData()
@@ -303,10 +358,9 @@ class CoverageDataFilesTest(DataTestHelpers, CoverageTest):
covdata2.write_file('cov2/.coverage.2')
covdata3 = CoverageData()
- self.data_files.combine_parallel_data(covdata3, data_dirs=[
- 'cov1/',
- 'cov2/',
- ])
+ self.data_files.combine_parallel_data(covdata3, data_dirs=['cov1/', 'cov2/'])
self.assert_line_counts(covdata3, SUMMARY_1_2)
self.assert_measured_files(covdata3, MEASURED_FILES_1_2)
+ self.assert_doesnt_exist("cov1/.coverage.1")
+ self.assert_doesnt_exist("cov2/.coverage.2")