class TestCrossover(TestOperatorCommon):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.sut = CrossoverOperator()

    def test_crossover_should_behave_like_evolution_operator(self):
        self.operator_executes_with_some_chance_scenario(
            self.configuration.operators.inversion.chance, [self.rule_1, self.rule_2])
        self.operator_raises_exception_on_invalid_arity_scenario(1, 3)

    def test_crossover_mixes_two_given_rules_into_two_new_ones(self):
        # Given:
        self.randomizer_mock.perform_with_chance.return_value = True

        # When/Then:
        rule_1_new, rule_2_new = self.sut.apply(self.service_mock, self.rule_population_mock,
                                                self.rule_1, self.rule_2)
        assert_that(rule_1_new, is_(equal_to(Rule(Symbol('D'), Symbol('E'), Symbol('C')))))
        assert_that(rule_2_new, is_(equal_to(Rule(Symbol('A'), Symbol('B'), Symbol('F')))))

        self.randomizer_mock.perform_with_chance.assert_has_calls([
            call(self.configuration.operators.crossover.chance),
            call(0.5)
        ])

    def test_crossover_mixes_two_given_rules_into_two_new_ones_another_combination(self):
        # Given:
        self.randomizer_mock.perform_with_chance.side_effect = [True, False]

        # When/Then:
        rule_1_new, rule_2_new = self.sut.apply(self.service_mock, self.rule_population_mock,
                                                self.rule_1, self.rule_2)
        assert_that(rule_1_new, is_(equal_to(Rule(Symbol('D'), Symbol('B'), Symbol('F')))))
        assert_that(rule_2_new, is_(equal_to(Rule(Symbol('A'), Symbol('E'), Symbol('C')))))

        self.randomizer_mock.perform_with_chance.assert_has_calls([
            call(self.configuration.operators.crossover.chance),
            call(0.5)
        ])
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        self.sut = CrossoverOperator()