Skip to content

Commit eccf218

Browse files
Ensure that test suite coverage is deterministically ordered (#343)
* tidying code * ensure deterministic test suite coverage * remove redundant __contains__
1 parent 8e71bb9 commit eccf218

File tree

1 file changed

+20
-38
lines changed

1 file changed

+20
-38
lines changed

bugzoo/core/coverage.py

Lines changed: 20 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
__all__ = ['CoverageInstructions', 'TestCoverage', 'TestSuiteCoverage']
22

3-
from typing import Dict, List, Set, Iterator, Any, Iterable, FrozenSet, Type, \
4-
Optional
3+
from typing import (Dict, List, Set, Iterator, Any, Iterable, FrozenSet, Type,
4+
Optional, Mapping)
5+
from collections import OrderedDict
56
import logging
67

78
import yaml
@@ -26,15 +27,11 @@ def _convert_files_to_instrument(files: Iterable[str]) -> FrozenSet[str]:
2627
return frozenset(files)
2728

2829

29-
class CoverageInstructions(object):
30-
"""
31-
Provides instructions for computing coverage.
32-
"""
30+
class CoverageInstructions:
31+
"""Instructions for computing coverage."""
3332
@classmethod
3433
def registered_under_name(cls) -> str:
35-
"""
36-
Returns the name that was used to register this class.
37-
"""
34+
"""Returns the name that was used to register this class."""
3835
return _INSTRUCTIONS_TO_NAME[cls]
3936

4037
@staticmethod
@@ -49,7 +46,7 @@ def language_default(language: Language
4946
@staticmethod
5047
def find(name: str) -> Type['CoverageInstructions']:
5148
"""
52-
Retrives the coverage instructions class registered under a given name.
49+
Retrieves the coverage instructions class registered for a given name.
5350
"""
5451
return _NAME_TO_INSTRUCTIONS[name]
5552

@@ -106,7 +103,7 @@ def to_dict(self) -> Dict[str, Any]:
106103
raise NotImplementedError
107104

108105

109-
class TestCoverage(object):
106+
class TestCoverage:
110107
"""
111108
Provides complete line coverage information for all files and across all
112109
tests within a given project.
@@ -157,23 +154,17 @@ def __contains__(self, fileline: FileLine) -> bool:
157154

158155
@property
159156
def test(self) -> str:
160-
"""
161-
The name of the test case used to generate this coverage.
162-
"""
157+
"""Name of the test case used to generate this coverage."""
163158
return self.__test
164159

165160
@property
166161
def outcome(self) -> TestOutcome:
167-
"""
168-
The outcome of the test associated with this coverage.
169-
"""
162+
"""Outcome of the test associated with this coverage."""
170163
return self.__outcome
171164

172165
@property
173166
def lines(self) -> FileLineSet:
174-
"""
175-
The set of file-lines that were covered.
176-
"""
167+
"""Set of file-lines that were covered."""
177168
return self.__coverage
178169

179170
coverage = lines
@@ -193,7 +184,7 @@ def to_dict(self) -> dict:
193184
'coverage': self.__coverage.to_dict()}
194185

195186

196-
class TestSuiteCoverage(object):
187+
class TestSuiteCoverage(Mapping[str, TestCoverage]):
197188
"""
198189
Holds coverage information for all tests belonging to a particular program
199190
version.
@@ -212,17 +203,18 @@ def from_file(fn: str) -> 'TestSuiteCoverage':
212203
d = yaml.safe_load(f)
213204
return TestSuiteCoverage.from_dict(d)
214205

215-
def __init__(self, test_coverage: Dict[str, TestCoverage]) -> None:
216-
self.__test_coverage = test_coverage
206+
def __init__(self, test_coverage: Mapping[str, TestCoverage]) -> None:
207+
self.__test_coverage = \
208+
OrderedDict() # type: OrderedDict[str, TestCoverage]
209+
for test_name in sorted(test_coverage):
210+
self.__test_coverage[test_name] = test_coverage[test_name]
217211

218212
def __repr__(self) -> str:
219213
output = [repr(self[name_test]) for name_test in self]
220214
return '\n'.join(output)
221215

222216
def covering_tests(self, line: FileLine) -> Set[str]:
223-
"""
224-
Returns the names of all test cases that cover a given line.
225-
"""
217+
"""Returns the names of all test cases that cover a given line."""
226218
return set(test for (test, cov) in self.__test_coverage.items() \
227219
if line in cov)
228220

@@ -234,8 +226,7 @@ def __iter__(self) -> Iterator[str]:
234226
return self.__test_coverage.keys().__iter__()
235227

236228
def __getitem__(self, name: str) -> TestCoverage:
237-
"""
238-
Retrieves coverage information for a given test case.
229+
"""Retrieves coverage information for a given test case.
239230
240231
Parameters:
241232
name: the name of the test case.
@@ -246,13 +237,6 @@ def __getitem__(self, name: str) -> TestCoverage:
246237
"""
247238
return self.__test_coverage[name]
248239

249-
def __contains__(self, name: str) -> bool:
250-
"""
251-
Determines whether this report contains coverage information for a given
252-
test case.
253-
"""
254-
return name in self.__test_coverage
255-
256240
def to_dict(self) -> dict:
257241
return {test: cov.to_dict() \
258242
for (test, cov) in self.__test_coverage.items()}
@@ -298,9 +282,7 @@ def __len__(self) -> int:
298282

299283
@property
300284
def lines(self) -> FileLineSet:
301-
"""
302-
Returns the set of all file lines that were covered.
303-
"""
285+
"""Returns the set of all file lines that were covered."""
304286
assert len(self) > 0
305287
output = FileLineSet()
306288
for coverage in self.__test_coverage.values():

0 commit comments

Comments
 (0)