Skip to content
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

code-coverage: handle functions in __init__.py files #1005

Merged
merged 4 commits into from
Apr 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion src/fuzz_introspector/code_coverage.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,11 @@ def _python_ast_funcname_to_cov_file(self, function_name) -> Optional[str]:
# Resolve name if required. This is needed to normalise filenames.
logger.debug("Resolving name")
potential_paths = []
init_paths = []
current_path = ""
for module_name in function_name.split("."):
current_path += module_name
init_paths.append(current_path + "/__init__.py")
potential_paths.append(current_path + ".py")
current_path += "/"

Expand All @@ -193,6 +195,24 @@ def _python_ast_funcname_to_cov_file(self, function_name) -> Optional[str]:
if potential_key.endswith(potential_path):
logger.debug(f"Found key: {str(potential_key)}")
return potential_key
# We found no matches when filenames exclude __init__.py. Try to
# include these now.
init_matches = []
# Iterate based in init paths since we want to have the longest match
# at the end of __init__matches list.
logger.info("Scanning for init paths")
for potential_init_path in init_paths:
logger.info("Trying %s" % (potential_init_path))
for potential_key in self.file_map:
logger.debug(f"Scanning {str(potential_key)}")
if potential_key.endswith(potential_init_path):
logger.debug(f"Found __init__ match: {str(potential_key)}")
init_matches.append(potential_key)

# Return the last match, as this signals the path with most precise
# matching.
if len(init_matches) > 0:
return init_matches[-1]

# If this is reached then no match was found. Return None.
logger.debug("Could not find key")
Expand Down Expand Up @@ -639,7 +659,6 @@ def load_python_json_coverage(json_file: str,
'executed_lines']
cp.dual_file_map[cov_entry]['missing_lines'] = data['files'][entry][
'missing_lines']

return cp


Expand Down
12 changes: 12 additions & 0 deletions src/fuzz_introspector/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,11 +200,13 @@ def approximate_python_coverage_files(src1: str, src2: str) -> bool:

# Generate list of potential candidates
possible_candidates = []
possible_init_candidates = []
splits = src1.split(".")
curr_str = ""
for s2 in splits:
curr_str = curr_str + s2
possible_candidates.append(curr_str + ".py")
possible_init_candidates.append("/__init__.py")
curr_str = curr_str + "/"

# Start from backwards to find te longest possible candidate
Expand All @@ -218,6 +220,16 @@ def approximate_python_coverage_files(src1: str, src2: str) -> bool:
target = candidate
break

if target is None:
for init_candidate in reversed(possible_init_candidates):
if src2.endswith(init_candidate):
# ensure the entire filename is matched in the event of not slashes
if "/" not in init_candidate:
if not src2.split("/")[-1] == init_candidate:
continue
target = init_candidate
break

if target is not None:
logger.debug(f"Found target {target}")
return True
Expand Down