|
|
@ -23,6 +23,10 @@ class AbstractMutator( |
|
|
|
VALID_MUTANTS_COUNT = 0 |
|
|
|
VALID_MUTANTS_COUNT = 0 |
|
|
|
VALID_RR_MUTANTS_COUNT = 0 |
|
|
|
VALID_RR_MUTANTS_COUNT = 0 |
|
|
|
VALID_CR_MUTANTS_COUNT = 0 |
|
|
|
VALID_CR_MUTANTS_COUNT = 0 |
|
|
|
|
|
|
|
# total revert/comment/tweak mutants that were generated and compiled |
|
|
|
|
|
|
|
total_mutant_counts = [0, 0, 0] |
|
|
|
|
|
|
|
# total valid revert/comment/tweak mutants |
|
|
|
|
|
|
|
valid_mutant_counts = [0, 0, 0] |
|
|
|
|
|
|
|
|
|
|
|
def __init__( # pylint: disable=too-many-arguments |
|
|
|
def __init__( # pylint: disable=too-many-arguments |
|
|
|
self, |
|
|
|
self, |
|
|
@ -73,12 +77,12 @@ class AbstractMutator( |
|
|
|
"""TODO Documentation""" |
|
|
|
"""TODO Documentation""" |
|
|
|
return {} |
|
|
|
return {} |
|
|
|
|
|
|
|
|
|
|
|
def mutate(self) -> Tuple[int, int, int, int, List[int]]: |
|
|
|
def mutate(self) -> Tuple[List[int], List[int], List[int]]: |
|
|
|
# call _mutate function from different mutators |
|
|
|
# call _mutate function from different mutators |
|
|
|
(all_patches) = self._mutate() |
|
|
|
(all_patches) = self._mutate() |
|
|
|
if "patches" not in all_patches: |
|
|
|
if "patches" not in all_patches: |
|
|
|
logger.debug("No patches found by %s", self.NAME) |
|
|
|
logger.debug("No patches found by %s", self.NAME) |
|
|
|
return (0, 0, self.dont_mutate_line) |
|
|
|
return ([0,0,0], [0,0,0], self.dont_mutate_line) |
|
|
|
|
|
|
|
|
|
|
|
for file in all_patches["patches"]: |
|
|
|
for file in all_patches["patches"]: |
|
|
|
original_txt = self.slither.source_code[file].encode("utf8") |
|
|
|
original_txt = self.slither.source_code[file].encode("utf8") |
|
|
@ -87,7 +91,8 @@ class AbstractMutator( |
|
|
|
logger.info(yellow(f"Mutating {file} with {self.NAME} \n")) |
|
|
|
logger.info(yellow(f"Mutating {file} with {self.NAME} \n")) |
|
|
|
for patch in patches: |
|
|
|
for patch in patches: |
|
|
|
# test the patch |
|
|
|
# test the patch |
|
|
|
flag = test_patch( |
|
|
|
|
|
|
|
|
|
|
|
patchIsValid = test_patch( |
|
|
|
file, |
|
|
|
file, |
|
|
|
patch, |
|
|
|
patch, |
|
|
|
self.test_command, |
|
|
|
self.test_command, |
|
|
@ -97,36 +102,41 @@ class AbstractMutator( |
|
|
|
self.solc_remappings, |
|
|
|
self.solc_remappings, |
|
|
|
self.verbose, |
|
|
|
self.verbose, |
|
|
|
) |
|
|
|
) |
|
|
|
# if RR or CR and valid mutant, add line no. |
|
|
|
|
|
|
|
if self.NAME in ("RR", "CR") and flag: |
|
|
|
# count the valid mutants, flag RR/CR mutants to skip further mutations |
|
|
|
|
|
|
|
if patchIsValid == 0: |
|
|
|
if self.NAME == 'RR': |
|
|
|
if self.NAME == 'RR': |
|
|
|
self.VALID_RR_MUTANTS_COUNT += 1 |
|
|
|
self.valid_mutant_counts[0] += 1 |
|
|
|
if self.NAME == 'CR': |
|
|
|
self.dont_mutate_line.append(patch['line_number']) |
|
|
|
self.VALID_CR_MUTANTS_COUNT += 1 |
|
|
|
elif self.NAME == 'CR': |
|
|
|
logger.info(yellow("Severe mutant is valid, skipping further mutations")) |
|
|
|
self.valid_mutant_counts[1] += 1 |
|
|
|
self.dont_mutate_line.append(patch["line_number"]) |
|
|
|
self.dont_mutate_line.append(patch['line_number']) |
|
|
|
|
|
|
|
else: |
|
|
|
# count the valid and invalid mutants |
|
|
|
self.valid_mutant_counts[2] += 1 |
|
|
|
if not flag: |
|
|
|
|
|
|
|
self.INVALID_MUTANTS_COUNT += 1 |
|
|
|
patched_txt,_ = apply_patch(original_txt, patch, 0) |
|
|
|
continue |
|
|
|
diff = create_diff(self.compilation_unit, original_txt, patched_txt, file) |
|
|
|
logger.info(yellow("Severe mutant is invalid, continuing further mutations")) |
|
|
|
if not diff: |
|
|
|
self.VALID_MUTANTS_COUNT += 1 |
|
|
|
logger.info(f"Impossible to generate patch; empty {patches}") |
|
|
|
patched_txt, _ = apply_patch(original_txt, patch, 0) |
|
|
|
|
|
|
|
diff = create_diff(self.compilation_unit, original_txt, patched_txt, file) |
|
|
|
# add valid mutant patches to a output file |
|
|
|
if not diff: |
|
|
|
with open( |
|
|
|
logger.info(f"Impossible to generate patch; empty {patches}") |
|
|
|
self.output_folder + "/patches_file.txt", "a", encoding="utf8" |
|
|
|
|
|
|
|
) as patches_file: |
|
|
|
# add valid mutant patches to a output file |
|
|
|
patches_file.write(diff + "\n") |
|
|
|
with open( |
|
|
|
|
|
|
|
self.output_folder + "/patches_file.txt", "a", encoding="utf8" |
|
|
|
# count the total number of mutants that we were able to compile |
|
|
|
) as patches_file: |
|
|
|
if patchIsValid != 2: |
|
|
|
patches_file.write(diff + "\n") |
|
|
|
if self.NAME == 'RR': |
|
|
|
|
|
|
|
self.total_mutant_counts[0] += 1 |
|
|
|
|
|
|
|
elif self.NAME == 'CR': |
|
|
|
|
|
|
|
self.total_mutant_counts[1] += 1 |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
self.total_mutant_counts[2] += 1 |
|
|
|
# logger.info(yellow(f"{self.VALID_MUTANTS_COUNT} valid mutants, {self.INVALID_MUTANTS_COUNT} invalid mutants")) |
|
|
|
# logger.info(yellow(f"{self.VALID_MUTANTS_COUNT} valid mutants, {self.INVALID_MUTANTS_COUNT} invalid mutants")) |
|
|
|
|
|
|
|
|
|
|
|
return ( |
|
|
|
return ( |
|
|
|
self.INVALID_MUTANTS_COUNT, |
|
|
|
self.total_mutant_counts, |
|
|
|
self.VALID_MUTANTS_COUNT, |
|
|
|
self.valid_mutant_counts, |
|
|
|
self.VALID_RR_MUTANTS_COUNT, |
|
|
|
|
|
|
|
self.VALID_CR_MUTANTS_COUNT, |
|
|
|
|
|
|
|
self.dont_mutate_line |
|
|
|
self.dont_mutate_line |
|
|
|
) |
|
|
|
) |
|
|
|