-
Notifications
You must be signed in to change notification settings - Fork 59
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Java-Integration]: Coverage report #612
Merged
Merged
Changes from all commits
Commits
Show all changes
16 commits
Select commit
Hold shift + click to select a range
58b7f12
Create dummy handler for jvm coverage report
arthurscchan af5dd39
Add jvm resolve coverage link logic
arthurscchan 4a85e72
Connect calltree to jacoco coverage report link
arthurscchan 5898a5f
Fix formatting
arthurscchan 11d91ac
Retrieving coverage from jacoco.xml
arthurscchan b2bda59
Fix extraction of jvm xml handling
arthurscchan 3b14aac
Add additional extraction logic for jvm coverage report
arthurscchan 388763b
Fix bug for int/string type conversion
arthurscchan b8fadd1
Fix divdided by zero bug
arthurscchan 58ad832
Fix type conversion bug and formatting
arthurscchan 9a28282
Fix bugs and code formatting
arthurscchan 8c8b02c
Fix formatting
arthurscchan a06cfc2
Add comments and combine redundant code
arthurscchan c7ede46
Merge branch 'main' of github.com:arthurscchan/fuzz-introspector into…
arthurscchan 6e241db
Fix bug
arthurscchan 70a1bf4
Fix formatting
arthurscchan File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
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 |
---|---|---|
|
@@ -168,6 +168,7 @@ def get_hit_details(self, funcname: str) -> List[Tuple[int, int]]: | |
|
||
if fuzz_key is None or fuzz_key not in self.covmap: | ||
return [] | ||
|
||
return self.covmap[fuzz_key] | ||
|
||
def _python_ast_funcname_to_cov_file( | ||
|
@@ -204,49 +205,22 @@ def _python_ast_funcname_to_cov_file( | |
|
||
return target_key | ||
|
||
def correlate_python_functions_with_coverage( | ||
def _retrieve_func_line( | ||
self, | ||
function_list, | ||
) -> None: | ||
|
||
logger.info("Correlating") | ||
# For each function identified in the ast identify the file | ||
# where it resides in with respect to the filepaths from the | ||
# coverage collection. Store this including the linumber | ||
# of the function definition. | ||
file_and_function_mappings: Dict[str, List[Tuple[str, int]]] = dict() | ||
for func_key in function_list: | ||
func = function_list[func_key] | ||
function_name = func.function_name | ||
function_line = func.function_linenumber | ||
|
||
logger.debug(f"Correlated init: {function_name} ---- {function_line}") | ||
cov_file = self._python_ast_funcname_to_cov_file(function_name) | ||
if cov_file is None: | ||
continue | ||
|
||
# Return False if file is not in file_map | ||
if cov_file not in self.file_map: | ||
logger.debug("Target key is not in file_map") | ||
continue | ||
|
||
if cov_file not in file_and_function_mappings: | ||
file_and_function_mappings[cov_file] = [] | ||
|
||
file_and_function_mappings[cov_file].append( | ||
(function_name, function_line) | ||
) | ||
|
||
file_and_function_mappings, | ||
) -> Dict[str, List[Tuple[str, int, int]]]: | ||
# Sort function and lines numbers for each coverage file. | ||
# Store in function_internals. | ||
logger.debug("Function intervals") | ||
logger.debug("Geting function start and end line") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: typo |
||
function_internals: Dict[str, List[Tuple[str, int, int]]] = dict() | ||
for cov_file, function_specs in file_and_function_mappings.items(): | ||
# Sort by line number | ||
sorted_func_specs = list(sorted(function_specs, key=lambda x: x[1])) | ||
|
||
function_internals[cov_file] = [] | ||
for i in range(len(sorted_func_specs)): | ||
fname, fstart = sorted_func_specs[i] | ||
|
||
# Get next function lineno to identify boundary | ||
if i < len(sorted_func_specs) - 1: | ||
fnext_name, fnext_start = sorted_func_specs[i + 1] | ||
|
@@ -257,13 +231,19 @@ def correlate_python_functions_with_coverage( | |
# Last function identified by end lineno being -1 | ||
function_internals[cov_file].append((fname, fstart, -1)) | ||
|
||
# Map the source codes of each line with coverage information. | ||
# Store the result in covmap to be compatible with other languages. | ||
return function_internals | ||
|
||
def _map_func_covmap( | ||
self, | ||
function_internals, | ||
) -> None: | ||
for filename in function_internals: | ||
logger.debug(f"Filename: {filename}") | ||
for fname, fstart, fend in function_internals[filename]: | ||
logger.debug(f"--- {fname} ::: {fstart} ::: {fend}") | ||
|
||
if fname not in self.covmap: | ||
# Fail safe | ||
self.covmap[fname] = [] | ||
|
||
# If we have the file in dual_file_map identify the | ||
|
@@ -273,13 +253,87 @@ def correlate_python_functions_with_coverage( | |
|
||
# Create the covmap | ||
for exec_line in self.dual_file_map[filename]['executed_lines']: | ||
if exec_line > fstart and (exec_line < fend or fend == -1): | ||
if (exec_line > fstart) and (exec_line < fend or fend == -1): | ||
logger.debug(f"E: {exec_line}") | ||
self.covmap[fname].append((exec_line, 1000)) | ||
for non_exec_line in self.dual_file_map[filename]['missing_lines']: | ||
if non_exec_line > fstart and (non_exec_line < fend or fend == -1): | ||
if (non_exec_line > fstart) and (non_exec_line < fend or fend == -1): | ||
logger.debug(f"N: {non_exec_line}") | ||
self.covmap[fname].append((non_exec_line, 0)) | ||
|
||
def correlate_python_functions_with_coverage( | ||
self, | ||
function_list, | ||
) -> None: | ||
|
||
logger.info("Correlating") | ||
# For each function identified in the ast identify the file | ||
# where it resides in with respect to the filepaths from the | ||
# coverage collection. Store this including the linumber | ||
# of the function definition. | ||
file_and_function_mappings: Dict[str, List[Tuple[str, int]]] = dict() | ||
for func_key in function_list: | ||
func = function_list[func_key] | ||
function_name = func.function_name | ||
function_line = func.function_linenumber | ||
|
||
logger.debug(f"Correlated init: {function_name} ---- {function_line}") | ||
cov_file = self._python_ast_funcname_to_cov_file(function_name) | ||
if cov_file is None: | ||
continue | ||
|
||
# Return False if file is not in file_map | ||
if cov_file not in self.file_map: | ||
logger.debug("Target key is not in file_map") | ||
continue | ||
|
||
if cov_file not in file_and_function_mappings: | ||
file_and_function_mappings[cov_file] = [] | ||
|
||
file_and_function_mappings[cov_file].append( | ||
(function_name, function_line) | ||
) | ||
|
||
# Sort and retrieve line range of all functions | ||
function_internals = self._retrieve_func_line(file_and_function_mappings) | ||
|
||
# Map the source codes of each line with coverage information. | ||
# Store the result in covmap to be compatible with other languages. | ||
self._map_func_covmap(function_internals) | ||
|
||
return | ||
|
||
def correlate_jvm_method_with_coverage( | ||
arthurscchan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
self, | ||
function_list, | ||
) -> None: | ||
logger.debug("Correlating JVM") | ||
|
||
file_and_function_mappings: Dict[str, List[Tuple[str, int]]] = dict() | ||
for (func_key, func) in function_list.items(): | ||
function_name = func.function_name | ||
function_line = func.function_linenumber | ||
class_name = func.function_source_file | ||
logger.debug(f"Correlated init: {class_name} ---- {function_name} ---- {function_line}") | ||
|
||
if class_name not in self.file_map: | ||
logger.debug("Fail to find matching class") | ||
continue | ||
|
||
if class_name not in file_and_function_mappings: | ||
file_and_function_mappings[class_name] = [] | ||
|
||
file_and_function_mappings[class_name].append( | ||
(function_name, function_line) | ||
) | ||
|
||
# Sort and retrieve line range of all functions | ||
function_internals = self._retrieve_func_line(file_and_function_mappings) | ||
|
||
# Map the source codes of each line with coverage information. | ||
# Store the result in covmap to be compatible with other languages. | ||
self._map_func_covmap(function_internals) | ||
|
||
return | ||
|
||
def get_hit_summary( | ||
|
@@ -503,6 +557,62 @@ def load_python_json_coverage( | |
return cp | ||
|
||
|
||
def load_jvm_coverage( | ||
target_dir: str, | ||
target_name: Optional[str] = None | ||
) -> CoverageProfile: | ||
arthurscchan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"""Find and load jacoco.xml, a jvm xml coverage report file | ||
|
||
The xml file is generated from Jacoco plugin. The specific dtd of the xml can | ||
be found in the following link: | ||
- https://www.jacoco.org/jacoco/trunk/coverage/report.dtd | ||
|
||
Return a CoverageProfile | ||
""" | ||
import xml.etree.ElementTree as ET | ||
cp = CoverageProfile() | ||
cp.set_type("file") | ||
|
||
coverage_reports = utils.get_all_files_in_tree_with_regex(target_dir, "jacoco.xml") | ||
logger.info(f"FOUND XML COVERAGE FILES: {str(coverage_reports)}") | ||
|
||
if len(coverage_reports) > 0: | ||
xml_file = coverage_reports[0] | ||
else: | ||
logger.info("Found no coverage files") | ||
return cp | ||
|
||
cp.coverage_files.append(xml_file) | ||
xml_tree = ET.parse(xml_file) | ||
root = xml_tree.getroot() | ||
|
||
for package in root.findall('package'): | ||
for cl in package.findall('sourcefile'): | ||
cov_entry = cl.attrib['name'] | ||
if package.attrib['name']: | ||
cov_entry = "%s/%s" % (package.attrib['name'], cov_entry) | ||
cov_entry = cov_entry.replace("/", ".") | ||
cov_entry = cov_entry.replace(".java", "") | ||
executed_lines = [] | ||
missing_lines = [] | ||
d_executed_lines = [] | ||
d_missing_lines = [] | ||
for line in cl.findall('line'): | ||
if line.attrib['ci'] > "0": | ||
executed_lines.append((int(line.attrib['nr']), 1000)) | ||
d_executed_lines.append(int(line.attrib['nr'])) | ||
else: | ||
missing_lines.append((int(line.attrib['nr']), 0)) | ||
d_missing_lines.append(int(line.attrib['nr'])) | ||
|
||
cp.file_map[cov_entry] = executed_lines | ||
cp.dual_file_map[cov_entry] = dict() | ||
cp.dual_file_map[cov_entry]['executed_lines'] = d_executed_lines | ||
cp.dual_file_map[cov_entry]['missing_lines'] = d_missing_lines | ||
|
||
return cp | ||
|
||
|
||
if __name__ == "__main__": | ||
logging.basicConfig() | ||
logger.info("Starting coverage loader") | ||
|
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
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This one we should watch out for as I'm not sure the condition will always be true. I'm thinking with regards to Python here.