-
Notifications
You must be signed in to change notification settings - Fork 35
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
convince coverage.py to cover vyper contracts by inspecting the frame. thread filename through the Contract data structure so we can report on it.
- Loading branch information
1 parent
e65c6f9
commit 30f85b4
Showing
5 changed files
with
123 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,3 +10,5 @@ dist/ | |
.pytest_cache | ||
venv/ | ||
.env | ||
|
||
.coverage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
"""The titanoboa coverage plugin.""" | ||
|
||
import coverage.plugin | ||
from vyper.ir import compile_ir | ||
|
||
import boa.interpret | ||
from boa.environment import Env, TracingCodeStream | ||
|
||
|
||
def coverage_init(registry, options): | ||
registry.add_file_tracer(TitanoboaPlugin(options)) | ||
|
||
|
||
class TitanoboaPlugin(coverage.plugin.CoveragePlugin): | ||
def __init__(self, options): | ||
pass | ||
|
||
def file_tracer(self, filename): | ||
if filename.endswith("boa/environment.py"): | ||
return TitanoboaTracer() | ||
|
||
def file_reporter(self, filename): | ||
if filename.endswith(".vy"): | ||
return TitanoboaReporter(filename) | ||
|
||
|
||
class TitanoboaTracer(coverage.plugin.FileTracer): | ||
def __init__(self, env=None): | ||
self.env = env or Env.get_singleton() | ||
|
||
def _contract_for_frame(self, frame): | ||
if frame.f_code.co_qualname != TracingCodeStream.__iter__.__qualname__: | ||
return None | ||
return frame.f_locals["self"]._contract | ||
|
||
def dynamic_source_filename(self, filename, frame): | ||
contract = self._contract_for_frame(frame) | ||
if contract is None: | ||
return None | ||
|
||
return contract.filename | ||
|
||
def has_dynamic_source_filename(self): | ||
return True | ||
|
||
# coverage.py requires us to inspect the python call frame to | ||
# see what line number to produce. since every loop of the py-evm | ||
# event loop uses CodeStream.__iter__, we intercept all calls to | ||
# __iter__, and then back out the contract and lineno information | ||
# from there. | ||
def line_number_range(self, frame): | ||
contract = self._contract_for_frame(frame) | ||
if contract is None: | ||
return super().line_number_range(frame) | ||
|
||
pc = frame.f_locals["self"].program_counter | ||
pc_map = contract.source_map["pc_pos_map"] | ||
|
||
if (src_loc := pc_map.get(pc)) is None: | ||
return (-1, -1) | ||
|
||
(start_lineno, _, end_lineno, _) = src_loc | ||
return start_lineno, end_lineno | ||
|
||
|
||
class TitanoboaReporter(coverage.plugin.FileReporter): | ||
def __init__(self, filename, env=None): | ||
super().__init__(filename) | ||
|
||
def lines(self): | ||
ret = set() | ||
c = boa.interpret.compiler_data(self.source(), self.filename) | ||
|
||
# source_map should really be in CompilerData | ||
_, source_map = compile_ir.assembly_to_evm(c.assembly_runtime) | ||
|
||
for _, v in source_map["pc_pos_map"].items(): | ||
if v is None: | ||
continue | ||
(start_lineno, _, end_lineno, _) = v | ||
for i in range(start_lineno, end_lineno + 1): | ||
ret.add(i) | ||
|
||
return ret |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters