def test_second_order_mutation(self): mutator = HighOrderMutator(operators=[ operators.ArithmeticOperatorReplacement, operators.AssignmentOperatorReplacement ], ) target_ast = utils.create_ast('x += y + z') for number, (mutations, mutant) in enumerate(mutator.mutate(target_ast)): self.assertEqual(number, 0) self.assertEqual('x -= y - z', codegen.to_source(mutant)) self.assertEqual(len(mutations), 2) self.assertEqual(codegen.to_source(target_ast), 'x += y + z')
def test_second_order_mutation_with_multiple_visitors(self): mutator = HighOrderMutator(operators=[operators.ConstantReplacement], ) target_ast = utils.create_ast('x = "test"') number = None for number, (mutations, mutant) in enumerate(mutator.mutate(target_ast)): if number == 0: self.assertEqual("x = 'mutpy'", codegen.to_source(mutant)) self.assertEqual(len(mutations), 1) elif number == 1: self.assertEqual("x = ''", codegen.to_source(mutant)) self.assertEqual(len(mutations), 1) self.assertEqual(number, 1) self.assertEqual(codegen.to_source(target_ast), "x = 'test'")
def test_second_order_mutation_with_same_node_as_target(self): mutator = HighOrderMutator(operators=[ operators.ArithmeticOperatorDeletion, operators.ArithmeticOperatorReplacement ], ) target_ast = utils.create_ast('- a') number = None for number, (mutations, mutant) in enumerate(mutator.mutate(target_ast)): if number == 0: self.assertEqual('a', codegen.to_source(mutant)) self.assertEqual(len(mutations), 1) elif number == 1: self.assertEqual('+a', codegen.to_source(mutant)) self.assertEqual(len(mutations), 1) self.assertEqual(number, 1) self.assertEqual(codegen.to_source(target_ast), '-a')
def test_first_order_mutation(self): mutator = FirstOrderMutator(operators=[ operators.ArithmeticOperatorReplacement, operators.AssignmentOperatorReplacement ], ) target_ast = utils.create_ast('x += y + z') for number, (mutations, mutant) in enumerate(mutator.mutate(target_ast)): self.assertIn(number, [0, 1]) self.assertEqual(len(mutations), 1) if number == 0: self.assertEqual('x += y - z', codegen.to_source(mutant)) elif number == 1: self.assertEqual('x -= y + z', codegen.to_source(mutant)) self.assertEqual(codegen.to_source(target_ast), 'x += y + z')
def end_mutation(self, *args, **kwargs): super().end_mutation(*args, **kwargs) template = self.env.get_template('detail.html') context = { 'mutant_code': codegen.to_source(self.current_mutation['mutant']), } context.update(self.current_mutation) report = template.render(context) file_path = os.path.join( self.dir_name, 'mutants', '{}.html'.format(self.current_mutation['number'])) with open(file_path, 'w') as report_file: report_file.write(report)
def assert_mutation(self, original, mutants, lines=None, operator=None, with_coverage=False, with_exec=False): original_ast = utils.create_ast(original) if with_coverage: coverage_injector = coverage.CoverageInjector() coverage_injector.inject(original_ast) else: coverage_injector = None if not operator: operator = self.__class__.op if isinstance(mutants, str): mutants = [mutants] mutants = list(map(codegen.remove_extra_lines, mutants)) module = None if with_exec: module = utils.create_module(original_ast) for mutation, mutatnt in operator.mutate( original_ast, coverage_injector=coverage_injector, module=module): mutant_code = codegen.remove_extra_lines( codegen.to_source(mutatnt)) msg = '\n\nMutant:\n\n' + mutant_code + '\n\nNot found in:' for other_mutant in mutants: msg += '\n\n----------\n\n' + other_mutant self.assertIn(mutant_code, mutants, msg) mutants.remove(mutant_code) self.assert_location(mutatnt) if lines is not None: if not hasattr(mutation.node, 'lineno'): self.assert_mutation_lineo(mutation.node.parent.lineno, lines) else: self.assert_mutation_lineo(mutation.node.lineno, lines) self.assertListEqual(mutants, [], 'did not generate all mutants')
def print_code(self, mutant, original): mutant_src = codegen.to_source(mutant) mutant_src = codegen.add_line_numbers(mutant_src) original_src = codegen.to_source(original) original_src = codegen.add_line_numbers(original_src) self._print_diff(mutant_src, original_src)