def mutate(self) -> None:
        """Apply mutation at test suite level."""
        assert self._test_case_factory, "Can only mutate with test case factory."
        changed = False

        # Mutate existing test cases.
        for test in self._tests:
            if randomness.next_float() < 1.0 / self.size():
                test.mutate()
                if test.has_changed():
                    changed = True

        # Randomly add new test cases.
        alpha = config.INSTANCE.test_insertion_probability
        exponent = 1
        while (randomness.next_float() <= pow(alpha, exponent)
               and self.size() < config.INSTANCE.max_size):
            self.add_test(self._test_case_factory.get_test_case())
            exponent += 1
            changed = True

        # Remove any tests that have no more statements left.
        self._tests = [t for t in self._tests if t.size() > 0]

        if changed:
            self.set_changed(True)
    def mutate(self) -> None:
        """Each statement is mutated with probability 1/l."""
        changed = False

        if (config.INSTANCE.chop_max_length
                and self.size() >= config.INSTANCE.chromosome_length):
            last_mutatable_position = self._get_last_mutatable_statement()
            if last_mutatable_position is not None:
                self.chop(last_mutatable_position)
                changed = True

        if randomness.next_float() <= config.INSTANCE.test_delete_probability:
            if self._mutation_delete():
                changed = True

        if randomness.next_float() <= config.INSTANCE.test_change_probability:
            if self._mutation_change():
                changed = True

        if randomness.next_float() <= config.INSTANCE.test_insert_probability:
            if self._mutation_insert():
                changed = True

        if changed:
            self.set_changed(True)
    def mutate(self) -> None:
        """Apply mutation at test suite level."""
        assert (
            self._test_case_chromosome_factory is not None
        ), "Mutation is not possibly without test case chromosome factory"

        changed = False

        # Mutate existing test cases.
        for test in self._test_case_chromosomes:
            if randomness.next_float() < 1.0 / self.size():
                test.mutate()
                if test.has_changed():
                    changed = True

        # Randomly add new test cases.
        alpha = config.configuration.test_insertion_probability
        exponent = 1
        while (randomness.next_float() <= pow(alpha, exponent)
               and self.size() < config.configuration.max_size):
            self.add_test_case_chromosome(
                self._test_case_chromosome_factory.get_chromosome())
            exponent += 1
            changed = True

        # Remove any tests that have no more statements left.
        self._test_case_chromosomes = [
            t for t in self._test_case_chromosomes if t.size() > 0
        ]

        if changed:
            self.set_changed(True)
    def mutate(self) -> None:
        changed = False

        if (config.configuration.chop_max_length
                and self.size() >= config.configuration.chromosome_length):
            last_mutatable_position = self.get_last_mutatable_statement()
            if last_mutatable_position is not None:
                self._test_case.chop(last_mutatable_position)
                changed = True

        # In case mutation removes all calls on the SUT.
        backup = self.test_case.clone()

        if randomness.next_float(
        ) <= config.configuration.test_delete_probability:
            if self._mutation_delete():
                changed = True

        if randomness.next_float(
        ) <= config.configuration.test_change_probability:
            if self._mutation_change():
                changed = True

        if randomness.next_float(
        ) <= config.configuration.test_insert_probability:
            if self._mutation_insert():
                changed = True

        assert self._test_factory, "Required for mutation"
        if not self._test_factory.has_call_on_sut(self._test_case):
            self._test_case = backup
            self._mutation_insert()

        if changed:
            self.set_changed(True)
Exemple #5
0
 def _mutate_parameters(self, p_per_param: float) -> bool:
     """
     Mutates args and kwargs with the given probability.
     :param p_per_param: The probability for one parameter to be mutated.
     """
     changed = False
     for arg in range(len(self.args)):
         if randomness.next_float() < p_per_param:
             changed |= self._mutate_parameter(arg)
     for kwarg in self.kwargs.keys():
         if randomness.next_float() < p_per_param:
             changed |= self._mutate_parameter(kwarg)
     return changed
    def delta(self) -> None:
        assert self._value is not None
        working_on = list(self._value)
        p_perform_action = 1.0 / 3.0
        if randomness.next_float() < p_perform_action and len(working_on) > 0:
            working_on = self._random_deletion(working_on)

        if randomness.next_float() < p_perform_action and len(working_on) > 0:
            working_on = self._random_replacement(working_on)

        if randomness.next_float() < p_perform_action:
            working_on = self._random_insertion(working_on)

        self._value = "".join(working_on)
 def _random_replacement(working_on: List[str]) -> List[str]:
     p_per_char = 1.0 / len(working_on)
     return [
         randomness.next_char()
         if randomness.next_float() < p_per_char else char
         for char in working_on
     ]
Exemple #8
0
    def insert_random_statement(self, test_case: tc.TestCase,
                                last_position: int) -> int:
        """Insert a random statement up to the given position.

        If the insertion was successful, the position at which the statement was inserted
        is returned, otherwise -1.

        Args:
            test_case: The test case to add the statement to
            last_position: The last position before that the statement is inserted

        Returns:
            The index the statement was inserted to, otherwise -1
        """
        old_size = test_case.size()
        rand = randomness.next_float()

        position = randomness.next_int(0, last_position + 1)
        if rand <= config.INSTANCE.insertion_uut:
            success = self.insert_random_call(test_case, position)
        else:
            success = self.insert_random_call_on_object(test_case, position)

        if test_case.size() - old_size > 1:
            position += test_case.size() - old_size - 1
        if success:
            return position
        return -1
    def _mutation_insert(self) -> bool:
        """With exponentially decreasing probability, insert statements at a
        random position.

        Returns:
            Whether or not the test case was changed
        """
        changed = False
        alpha = config.configuration.statement_insertion_probability
        exponent = 1
        while (randomness.next_float() <= pow(alpha, exponent)
               and self.size() < config.configuration.chromosome_length):
            assert self._test_factory, "Mutation requires a test factory."
            max_position = self.get_last_mutatable_statement()
            if max_position is None:
                # No mutatable statement found, so start at the first position.
                max_position = 0
            else:
                # Also include the position after the last mutatable statement.
                max_position += 1

            position = self._test_factory.insert_random_statement(
                self._test_case, max_position)
            exponent += 1
            if 0 <= position < self.size():
                changed = True
        return changed
Exemple #10
0
    def _get_variable_fallback(
        self,
        test_case: tc.TestCase,
        parameter_type: Optional[Type],
        position: int,
        recursion_depth: int,
        allow_none: bool,
    ) -> Optional[vr.VariableReference]:
        """Best effort approach to return some kind of matching variable."""
        objects = test_case.get_objects(parameter_type, position)

        # No objects to choose from, so either create random type variable or use None.
        if not objects:
            if config.INSTANCE.guess_unknown_types and randomness.next_float(
            ) <= 0.85:
                return self._create_random_type_variable(
                    test_case, position, recursion_depth, allow_none)
            if allow_none:
                return self._create_none(test_case, parameter_type, position,
                                         recursion_depth)
            raise ConstructionFailedException(
                f"No objects for type {parameter_type}")

        # Could not create, so re-use an existing variable.
        self._logger.debug("Choosing from %d existing objects: %s",
                           len(objects), objects)
        reference = randomness.choice(objects)
        self._logger.debug("Use existing object of type %s: %s",
                           parameter_type, reference)
        return reference
Exemple #11
0
    def _attempt_generation(
        self,
        test_case: tc.TestCase,
        parameter_type: Optional[Type],
        position: int,
        recursion_depth: int,
        allow_none: bool,
        exclude: Optional[vr.VariableReference] = None,
    ) -> Optional[vr.VariableReference]:
        # We only select a concrete type e.g. from a union, when we are forced to choose one.
        parameter_type = self._test_cluster.select_concrete_type(
            parameter_type)

        if not parameter_type:
            return None

        if allow_none and randomness.next_float(
        ) <= config.INSTANCE.none_probability:
            return self._create_none(test_case, parameter_type, position,
                                     recursion_depth)
        if is_primitive_type(parameter_type):
            return self._create_primitive(
                test_case,
                parameter_type,
                position,
                recursion_depth,
            )
        if type_generators := self._test_cluster.get_generators_for(
                parameter_type):
            return self._attempt_generation_for_type(test_case, position,
                                                     recursion_depth,
                                                     allow_none,
                                                     type_generators)
 def _random_insertion(self) -> bool:
     changed = False
     pos = 0
     if len(self._elements) > 0:
         pos = randomness.next_int(0, len(self._elements) + 1)
     # This is so ugly...
     key_type = (get_args(self.ret_val.variable_type)[0]
                 if get_args(self.ret_val.variable_type) else None)
     val_type = (get_args(self.ret_val.variable_type)[1]
                 if get_args(self.ret_val.variable_type) else None)
     possibles_keys = self.test_case.get_objects(key_type,
                                                 self.get_position())
     possibles_values = self.test_case.get_objects(val_type,
                                                   self.get_position())
     alpha = 0.5
     exponent = 1
     while randomness.next_float() <= pow(alpha, exponent):
         exponent += 1
         if len(possibles_keys) > 0 and len(possibles_values) > 0:
             self._elements.insert(
                 pos,
                 (
                     randomness.choice(possibles_keys),
                     randomness.choice(possibles_values),
                 ),
             )
             changed = True
     return changed
    def mutate(self) -> bool:
        changed = False
        if (randomness.next_float() <
                config.Configuration.test_delete_probability
                and len(self._elements) > 0):
            changed |= self._random_deletion()

        if (randomness.next_float() <
                config.Configuration.test_change_probability
                and len(self._elements) > 0):
            changed |= self._random_replacement()

        if randomness.next_float(
        ) < config.Configuration.test_insert_probability:
            changed |= self._random_insertion()
        return changed
 def randomize_value(self) -> None:
     if (config.INSTANCE.constant_seeding
             and StaticConstantSeeding().has_ints
             and randomness.next_float() <= 0.90):
         self._value = StaticConstantSeeding().random_int
     else:
         self._value = int(randomness.next_gaussian() *
                           config.INSTANCE.max_int)
 def _random_deletion(self) -> bool:
     p_per_element = 1.0 / len(self._elements)
     previous_length = len(self._elements)
     self._elements = [
         element for element in self._elements
         if randomness.next_float() >= p_per_element
     ]
     return previous_length != len(self._elements)
 def randomize_value(self) -> None:
     if (config.INSTANCE.constant_seeding
             and StaticConstantSeeding().has_strings
             and randomness.next_float() <= 0.90):
         self._value = StaticConstantSeeding().random_string
     else:
         length = randomness.next_int(0, config.INSTANCE.string_length + 1)
         self._value = randomness.next_string(length)
 def randomize_value(self) -> None:
     if (config.INSTANCE.constant_seeding
             and StaticConstantSeeding().has_floats
             and randomness.next_float() <= 0.90):
         self._value = StaticConstantSeeding().random_float
     else:
         val = randomness.next_gaussian() * config.INSTANCE.max_int
         precision = randomness.next_int(0, 7)
         self._value = round(val, precision)
 def delta(self) -> None:
     assert self._value is not None
     probability = randomness.next_float()
     if probability < 1.0 / 3.0:
         self._value += randomness.next_gaussian() * config.INSTANCE.max_delta
     elif probability < 2.0 / 3.0:
         self._value += randomness.next_gaussian()
     else:
         self._value = round(self._value, randomness.next_int(0, 7))
Exemple #19
0
 def get_test_case(self) -> tc.TestCase:
     if (
         config.configuration.initial_population_seeding
         and initpopseeding.initialpopulationseeding.has_tests
         and randomness.next_float()
         <= config.configuration.seeded_testcases_reuse_probability
     ):
         return initpopseeding.initialpopulationseeding.seeded_testcase
     return self._delegate.get_test_case()
Exemple #20
0
    def cross_over(self, parent1: T, parent2: T):
        if parent1.size() < 2 or parent2.size() < 2:
            return

        split_point = randomness.next_float()
        position1 = floor((parent1.size() - 1) * split_point) + 1
        position2 = floor((parent2.size() - 1) * split_point) + 1
        clone1 = parent1.clone()
        clone2 = parent2.clone()
        parent1.cross_over(clone2, position1, position2)
        parent2.cross_over(clone1, position2, position1)
Exemple #21
0
 def get_index(self, population: List[T]) -> int:
     """Provides an index in the population that is chosen by rank selection.
     Make sure that the population is sorted. The fittest chromosomes have to
     come first."""
     random_value = randomness.next_float()
     bias = config.INSTANCE.rank_bias
     return int(
         len(population) *
         ((bias - sqrt(bias**2 - (4.0 *
                                  (bias - 1.0) * random_value))) / 2.0 /
          (bias - 1.0)))
 def _random_replacement(self) -> bool:
     p_per_element = 1.0 / len(self._elements)
     changed = False
     for i, elem in enumerate(self._elements):
         if randomness.next_float() < p_per_element:
             # TODO(fk) what if the current type is not correct?
             replace = randomness.choice(
                 self.test_case.get_objects(elem.variable_type,
                                            self.get_position()) + [elem])
             self._elements[i] = replace
             changed |= replace != elem
     return changed
    def mutate(self) -> bool:
        if randomness.next_float(
        ) >= config.INSTANCE.change_parameter_probability:
            return False

        objects = self.test_case.get_objects(self.source.variable_type,
                                             self.get_position())
        objects.remove(self.source)
        if len(objects) > 0:
            self.source = randomness.choice(objects)
            return True
        return False
Exemple #24
0
    def mutate(self) -> bool:
        if randomness.next_float(
        ) >= config.INSTANCE.change_parameter_probability:
            return False

        changed = False
        mutable_param_count = self._mutable_argument_count()
        if mutable_param_count > 0:
            p_per_param = 1.0 / mutable_param_count
            changed |= self._mutate_special_parameters(p_per_param)
            changed |= self._mutate_parameters(p_per_param)
        return changed
 def _random_insertion(working_on: List[str]) -> List[str]:
     pos = 0
     if len(working_on) > 0:
         pos = randomness.next_int(0, len(working_on) + 1)
     alpha = 0.5
     exponent = 1
     while (randomness.next_float() <= pow(alpha, exponent)
            and len(working_on) < config.INSTANCE.string_length):
         exponent += 1
         working_on = working_on[:pos] + [randomness.next_char()
                                          ] + working_on[pos:]
     return working_on
Exemple #26
0
    def _mutate_special_parameters(self, p_per_param: float) -> bool:
        # We mutate the callee here, as the special parameter.
        if randomness.next_float() < p_per_param:
            callee = self.callee
            objects = self.test_case.get_objects(callee.variable_type,
                                                 self.get_position())
            objects.remove(callee)

            if len(objects) > 0:
                self.callee = randomness.choice(objects)
                return True
        return False
 def _random_insertion(working_on: List[int]) -> List[int]:
     pos = 0
     if len(working_on) > 0:
         pos = randomness.next_int(0, len(working_on) + 1)
     alpha = 0.5
     exponent = 1
     while (
         randomness.next_float() <= pow(alpha, exponent)
         and len(working_on) < config.configuration.bytes_length
     ):
         exponent += 1
         working_on = working_on[:pos] + [randomness.next_byte()] + working_on[pos:]
     return working_on
    def _mutation_delete(self) -> bool:
        last_mutatable_statement = self._get_last_mutatable_statement()
        if last_mutatable_statement is None:
            return False

        changed = False
        p_per_statement = 1.0 / (last_mutatable_statement + 1)
        for idx in reversed(range(last_mutatable_statement + 1)):
            if idx >= self.size():
                continue
            if randomness.next_float() <= p_per_statement:
                changed |= self._delete_statement(idx)
        return changed
 def randomize_value(self) -> None:
     use_seed = (
         randomness.next_float()
         <= config.configuration.seeded_primitives_reuse_probability
     )
     if (
         config.configuration.dynamic_constant_seeding
         and dynamic_constant_seeding.has_ints
         and use_seed
         and config.configuration.constant_seeding
         and randomness.next_float()
         <= config.configuration.seeded_dynamic_values_reuse_probability
     ):
         self._value = dynamic_constant_seeding.random_int
     elif (
         config.configuration.constant_seeding
         and static_constant_seeding.has_ints
         and use_seed
     ):
         self._value = static_constant_seeding.random_int
     else:
         self._value = int(randomness.next_gaussian() * config.configuration.max_int)
Exemple #30
0
    def evolve(self) -> None:
        """Evolve the current population and replace it with a new one."""
        new_generation = []
        new_generation.extend(self.elitism())
        while not self.is_next_population_full(new_generation):
            parent1 = self._selection_function.select(self._population, 1)[0]
            parent2 = self._selection_function.select(self._population, 1)[0]

            offspring1 = parent1.clone()
            offspring2 = parent2.clone()

            try:
                if randomness.next_float() <= config.INSTANCE.crossover_rate:
                    self._crossover_function.cross_over(offspring1, offspring2)

                offspring1.mutate()
                offspring2.mutate()
            except ConstructionFailedException as ex:
                self._logger.info("Crossover/Mutation failed: %s", ex)
                continue

            fitness_parents = min(parent1.get_fitness(), parent2.get_fitness())
            fitness_offspring = min(offspring1.get_fitness(), offspring2.get_fitness())
            length_parents = (
                parent1.total_length_of_test_cases + parent2.total_length_of_test_cases
            )
            length_offspring = (
                offspring1.total_length_of_test_cases
                + offspring2.total_length_of_test_cases
            )
            best_individual = self._get_best_individual()

            if (fitness_offspring < fitness_parents) or (
                fitness_offspring == fitness_parents
                and length_offspring <= length_parents
            ):
                for offspring in [offspring1, offspring2]:
                    if (
                        offspring.total_length_of_test_cases
                        <= 2 * best_individual.total_length_of_test_cases
                    ):
                        new_generation.append(offspring)
                    else:
                        new_generation.append(randomness.choice([parent1, parent2]))
            else:
                new_generation.append(parent1)
                new_generation.append(parent2)

        self._population = new_generation
        self._sort_population()
        StatisticsTracker().current_individual(self._get_best_individual())