<commit_before>/*
 * Copyright 2019, TeamDev. All rights reserved.
 *
 * Redistribution and use in source and/or binary forms, with or without
 * modification, must retain the above copyright notice and the following
 * disclaimer.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package io.spine.server.model;

import com.google.common.collect.ImmutableSet;
import com.google.protobuf.Message;
import io.spine.base.CommandMessage;
import io.spine.base.EventMessage;
import io.spine.core.CommandClass;
import io.spine.core.EventClass;
import io.spine.server.model.given.HandlerReturnTypeTestEnv.MessageProducer;
import io.spine.test.model.ModCreateProject;
import io.spine.test.model.ModProjectCreated;
import io.spine.test.model.ModProjectOwnerAssigned;
import io.spine.test.model.ModProjectStarted;
import io.spine.test.model.ModStartProject;
import io.spine.test.model.Rejections.ModCannotAssignOwnerToProject;
import io.spine.test.model.Rejections.ModProjectAlreadyExists;
import io.spine.type.MessageClass;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Set;

import static com.google.common.truth.Truth.assertThat;
import static io.spine.util.Exceptions.newIllegalArgumentException;
import static java.util.stream.Collectors.toSet;
import static org.junit.jupiter.api.Assertions.fail;

@DisplayName("HandlerReturnType should")
class HandlerReturnTypeTest {

    @Nested
    @DisplayName("extract produced message type")
    class ExtractProducedMessage {

        @Test
        @DisplayName("from command return type")
        void fromCommand() {
            checkProduces("emitCommand", ImmutableSet.of(ModCreateProject.class));
        }

        @Test
        @DisplayName("from event return type")
        void fromEvent() {
            checkProduces("emitEvent", ImmutableSet.of(ModProjectCreated.class));
        }

        @Test
        @DisplayName("from `Optional` return type")
        void fromOptional() {
            checkProduces("emitOptionalEvent", ImmutableSet.of(ModProjectStarted.class));
        }

        @Test
        @DisplayName("from `Iterable` return type")
        void fromIterable() {
            checkProduces("emitListOfCommands", ImmutableSet.of(ModStartProject.class));
        }
    }

    @Nested
    @DisplayName("extract multiple produced types")
    class ExtractMultipleProducedTypes {

        @Test
        @DisplayName("from `Either` return type")
        void fromEither() {
            checkProduces("emitEither",
                          ImmutableSet.of(ModProjectCreated.class,
                                          ModProjectAlreadyExists.class));
        }

        @Test
        @DisplayName("from `Tuple` return type")
        void fromTuple() {
            checkProduces("emitPair",
                          ImmutableSet.of(ModProjectCreated.class,
                                          ModProjectOwnerAssigned.class,
                                          ModCannotAssignOwnerToProject.class));
        }

        @Test
        @DisplayName("from type that mixes concrete type params and too broad type params")
        void fromMixedReturnType() {
            checkProduces("emitEitherWithTooBroad",
                          ImmutableSet.of(ModProjectOwnerAssigned.class,
                                          ModCannotAssignOwnerToProject.class));
        }
    }

    @Nested
    @DisplayName("return empty produced messages list")
    class ReturnEmptyList {

        @Test
        @DisplayName("for `void` return type")
        void forVoid() {
            checkProducesNothing("returnVoid");
        }

        @Test
        @DisplayName("for `Nothing` return type")
        void forNothing() {
            checkProducesNothing("returnNothing");
        }

        @Test
        @DisplayName("for `Empty` return type")
        void forEmpty() {
            checkProducesNothing("returnEmpty");
        }

        @Test
        @DisplayName("for method returning too broad message type")
        void forTooBroadType() {
            checkProducesNothing("returnTooBroadEvent");
        }

        @Test
        @DisplayName("for method parameterized with too broad message type")
        void forTooBroadTypeParam() {
            checkProducesNothing("returnTooBroadIterable");
        }
<commit_msg>Improve wording of `HandlerReturnTypeTest`<commit_after>/*
 * Copyright 2019, TeamDev. All rights reserved.
 *
 * Redistribution and use in source and/or binary forms, with or without
 * modification, must retain the above copyright notice and the following
 * disclaimer.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package io.spine.server.model;

import com.google.common.collect.ImmutableSet;
import com.google.protobuf.Message;
import io.spine.base.CommandMessage;
import io.spine.base.EventMessage;
import io.spine.core.CommandClass;
import io.spine.core.EventClass;
import io.spine.server.model.given.HandlerReturnTypeTestEnv.MessageProducer;
import io.spine.test.model.ModCreateProject;
import io.spine.test.model.ModProjectCreated;
import io.spine.test.model.ModProjectOwnerAssigned;
import io.spine.test.model.ModProjectStarted;
import io.spine.test.model.ModStartProject;
import io.spine.test.model.Rejections.ModCannotAssignOwnerToProject;
import io.spine.test.model.Rejections.ModProjectAlreadyExists;
import io.spine.type.MessageClass;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Set;

import static com.google.common.truth.Truth.assertThat;
import static io.spine.util.Exceptions.newIllegalArgumentException;
import static java.util.stream.Collectors.toSet;
import static org.junit.jupiter.api.Assertions.fail;

@DisplayName("HandlerReturnType should")
class HandlerReturnTypeTest {

    @Nested
    @DisplayName("collect a single produced message type")
    class CollectProducedMessageType {

        @Test
        @DisplayName("from command return type")
        void fromCommand() {
            checkProduces("emitCommand", ImmutableSet.of(ModCreateProject.class));
        }

        @Test
        @DisplayName("from event return type")
        void fromEvent() {
            checkProduces("emitEvent", ImmutableSet.of(ModProjectCreated.class));
        }

        @Test
        @DisplayName("from `Optional` return type")
        void fromOptional() {
            checkProduces("emitOptionalEvent", ImmutableSet.of(ModProjectStarted.class));
        }

        @Test
        @DisplayName("from `Iterable` return type")
        void fromIterable() {
            checkProduces("emitListOfCommands", ImmutableSet.of(ModStartProject.class));
        }
    }

    @Nested
    @DisplayName("collect multiple produced types")
    class CollectMultipleProducedTypes {

        @Test
        @DisplayName("from `Either` return type")
        void fromEither() {
            checkProduces("emitEither",
                          ImmutableSet.of(ModProjectCreated.class,
                                          ModProjectAlreadyExists.class));
        }

        @Test
        @DisplayName("from `Tuple` return type")
        void fromTuple() {
            checkProduces("emitPair",
                          ImmutableSet.of(ModProjectCreated.class,
                                          ModProjectOwnerAssigned.class,
                                          ModCannotAssignOwnerToProject.class));
        }

        @Test
        @DisplayName("from type that mixes concrete type params and too broad type params")
        void fromMixedReturnType() {
            checkProduces("emitEitherWithTooBroad",
                          ImmutableSet.of(ModProjectOwnerAssigned.class,
                                          ModCannotAssignOwnerToProject.class));
        }
    }

    @Nested
    @DisplayName("collect empty produced messages list")
    class CollectEmptyList {

        @Test
        @DisplayName("for `void` return type")
        void forVoid() {
            checkProducesNothing("returnVoid");
        }

        @Test
        @DisplayName("for `Nothing` return type")
        void forNothing() {
            checkProducesNothing("returnNothing");
        }

        @Test
        @DisplayName("for `Empty` return type")
        void forEmpty() {
            checkProducesNothing("returnEmpty");
        }

        @Test
        @DisplayName("for method returning too broad message type")
        void forTooBroadType() {
            checkProducesNothing("returnTooBroadEvent");
        }

        @Test
        @DisplayName("for method parameterized with too broad message type")
        void forTooBroadTypeParam() {
            checkProducesNothing("returnTooBroadIterable");
        }

{'fraction_non_alphanumeric': 0.08615384615384615, 'fraction_numerical': 0.0007692307692307692, 'mean_word_length': 2.768478260869565, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3836104', 'n_tokens_mistral': 2785, 'n_tokens_neox': 2656, 'n_words': 703}