/*
 * Copyright 2020, 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.commandbus;

import com.google.common.truth.Correspondence;
import com.google.protobuf.Any;
import io.spine.base.Time;
import io.spine.core.Command;
import io.spine.core.CommandContext;
import io.spine.core.CommandId;
import io.spine.protobuf.AnyPacker;
import io.spine.server.type.CommandEnvelope;
import io.spine.test.command.CmdEmpty;
import io.spine.test.commandbus.command.CmdBusCreateProject;
import io.spine.testing.client.TestActorRequestFactory;
import io.spine.validate.ConstraintViolation;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import java.util.List;

import static com.google.common.truth.Truth.assertThat;
import static io.spine.server.commandbus.CommandValidator.inspect;
import static io.spine.server.commandbus.Given.CommandMessage.createProjectMessage;
import static io.spine.testing.core.given.GivenCommandContext.withRandomActor;

@DisplayName("CommandValidator violation check should")
class CommandValidatorViolationCheckTest {

    @Test
    @DisplayName("validate command and return empty violations list if command is valid")
    void returnNothingForValidCmd() {
        Command cmd = Given.ACommand.createProject();

        List<ConstraintViolation> violations = inspectCommand(cmd);

        assertThat(violations)
                .isEmpty();
    }

    @Test
    @DisplayName("not allow commands without IDs")
    void notAllowDefaultId() {
        Command cmd = Given.ACommand.createProject();
        Command unidentifiableCommand = cmd
                .toBuilder()
                .setId(CommandId.getDefaultInstance())
                .build();
        List<ConstraintViolation> violations = inspectCommand(unidentifiableCommand);

        assertThat(violations)
                .hasSize(1);
    }

    @Test
    @DisplayName("return violations if command has invalid Message")
    void notAllowInvalidMessage() {
        Any invalidMessagePacked = AnyPacker.pack(CmdBusCreateProject.getDefaultInstance());
        Command commandWithEmptyMessage = Command
                .newBuilder()
                .setId(CommandId.generate())
                .setMessage(invalidMessagePacked)
                .setContext(withRandomActor())
                .build();

        List<ConstraintViolation> violations = inspectCommand(commandWithEmptyMessage);

        assertThat(violations)
                .hasSize(2);
    }

    @Test
    @DisplayName("return violations if command has invalid context")
    void notAllowInvalidContext() {
        TestActorRequestFactory factory = new TestActorRequestFactory(getClass());
        Command command = factory.createCommand(createProjectMessage(), Time.currentTime());
        Command commandWithoutContext = command
                .toBuilder()
                .setContext(CommandContext.getDefaultInstance())
                .build();

        List<ConstraintViolation> violations = inspectCommand(commandWithoutContext);

        assertThat(violations)
                .hasSize(1);
    }

    @Test
    @DisplayName("allow empty command messages")
    void emptyMessage() {
        TestActorRequestFactory factory = new TestActorRequestFactory(getClass());
        Command emptyCommand = factory.createCommand(CmdEmpty.getDefaultInstance());
        List<ConstraintViolation> violations = inspectCommand(emptyCommand);

        Correspondence<@NonNull ConstraintViolation, @NonNull String> messageFormatContains =
                Correspondence.from(
                        (actual, expected) -> actual.getMsgFormat().contains(expected),
                        "has message format"
                );
        assertThat(violations)
                .comparingElementsUsing(messageFormatContains)
                .doesNotContain("command target ID");
    }

    private static List<ConstraintViolation> inspectCommand(Command command) {
        return inspect(CommandEnvelope.of(command));
    }
}

@@ -1090,16 +1090,64 @@
 ndence;%0A
+import com.google.common.truth.IterableSubject;%0A
 import c
@@ -1170,16 +1170,16 @@
 uf.Any;%0A
-
 import i
@@ -2127,16 +2127,301 @@
 Test %7B%0A%0A
+    private static final Correspondence%3C@NonNull ConstraintViolation, @NonNull String%3E%0A            messageFormatContains = Correspondence.from(%0A                    (actual, expected) -%3E actual.getMsgFormat().contains(expected),%0A                    %22has message format%22%0A            );%0A%0A
     @Tes
@@ -3748,38 +3748,99 @@
         
-assertThat(violations)
+IterableSubject assertViolations = assertThat(violations);%0A        assertViolations
 %0A       
@@ -4414,17 +4414,16 @@
 ntext);%0A
-%0A
         
@@ -4726,32 +4726,32 @@
 ultInstance());%0A
+
         List%3CCon
@@ -4814,292 +4814,8 @@
 nd);
-%0A%0A        Correspondence%3C@NonNull ConstraintViolation, @NonNull String%3E messageFormatContains =%0A                Correspondence.from(%0A                        (actual, expected) -%3E actual.getMsgFormat().contains(expected),%0A                        %22has message format%22%0A                );
 %0A   

Clean up a test