/*
 * 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.validate;

import io.spine.test.validate.AggregateState;
import io.spine.test.validate.ProjectionState;
import io.spine.test.validate.command.EntityIdByteStringFieldValue;
import io.spine.test.validate.command.EntityIdDoubleFieldValue;
import io.spine.test.validate.command.EntityIdIntFieldValue;
import io.spine.test.validate.command.EntityIdLongFieldValue;
import io.spine.test.validate.command.EntityIdMsgFieldValue;
import io.spine.test.validate.command.EntityIdRepeatedFieldValue;
import io.spine.test.validate.command.EntityIdStringFieldValue;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static io.spine.base.Identifier.newUuid;
import static io.spine.validate.MessageValidatorTest.MESSAGE_VALIDATOR_SHOULD;
import static io.spine.validate.given.MessageValidatorTestEnv.VALUE;
import static io.spine.validate.given.MessageValidatorTestEnv.newByteString;
import static io.spine.validate.given.MessageValidatorTestEnv.newStringValue;

@DisplayName(MESSAGE_VALIDATOR_SHOULD + "validate an entity ID")
class EntityIdTest extends MessageValidatorTest {
    
    @Nested
    @DisplayName("in a command file and")
    class InCommandFile {

        @Test
        @DisplayName("find out that Message is valid")
        void findOutThatMessageEntityIdInCommandIsValid() {
            EntityIdMsgFieldValue msg = EntityIdMsgFieldValue.newBuilder()
                                                             .setValue(newStringValue())
                                                             .build();
            assertValid(msg);
        }

        @Test
        @DisplayName("find out that Message is NOT valid")
        void findOutThatMessageEntityIdInCommandIsNotValid() {
            EntityIdMsgFieldValue msg = EntityIdMsgFieldValue.getDefaultInstance();
            assertNotValid(msg);
        }

        @Test
        @DisplayName("find out that String is valid")
        void findOutThatStringEntityIdInCommandIsValid() {
            EntityIdStringFieldValue msg = EntityIdStringFieldValue.newBuilder()
                                                                   .setValue(newUuid())
                                                                   .build();
            assertValid(msg);
        }

        @Test
        @DisplayName("find out that String is NOT valid")
        void findOutThatStringEntityIdInCommandIsNotValid() {
            EntityIdStringFieldValue msg = EntityIdStringFieldValue.getDefaultInstance();
            assertNotValid(msg);
        }

        @Test
        @DisplayName("find out that Integer is valid")
        void findOutThatIntegerEntityIdInCommandIsValid() {
            EntityIdIntFieldValue msg = EntityIdIntFieldValue.newBuilder()
                                                             .setValue(5)
                                                             .build();
            assertValid(msg);
        }

        @Test
        @DisplayName("find out that Long is valid")
        void findOutThatLongEntityIdInCommandIsValid() {
            EntityIdLongFieldValue msg = EntityIdLongFieldValue.newBuilder()
                                                               .setValue(5)
                                                               .build();
            assertValid(msg);
        }

        @Test
        @DisplayName("find out that repeated is NOT valid")
        void findOutThatRepeatedEntityIdInCommandIsNotValid() {
            EntityIdRepeatedFieldValue msg = EntityIdRepeatedFieldValue.newBuilder()
                                                                       .addValue(newUuid())
                                                                       .build();
            assertNotValid(msg);
        }

        @Test
        @DisplayName("provide one valid violation if is not valid")
        void provideOneValidViolationIfEntityIdInCommandIsNotValid() {
            EntityIdMsgFieldValue msg = EntityIdMsgFieldValue.getDefaultInstance();
            assertSingleViolation(msg, VALUE);
        }
    }

    @Nested
    @DisplayName("in state and")
    class InState {

        @Test
        @DisplayName("consider it required by default")
        void requiredByDefault() {
            AggregateState stateWithDefaultId = AggregateState.getDefaultInstance();
            assertNotValid(stateWithDefaultId);
        }

        @Test
        @DisplayName("match only the first field named `id` or ending with `_id`")
        void onlyFirstField() {
            AggregateState onlyEntityIdSet = AggregateState.newBuilder()
                                                           .setEntityId(newUuid())
                                                           .build();
            assertValid(onlyEntityIdSet);
        }

        @Test
        @DisplayName("not consider it (required) if the option is set explicitly set to false")
        void notRequiredIfOptionIsFalse() {
            ProjectionState stateWithDefaultId = ProjectionState.getDefaultInstance();
            assertValid(stateWithDefaultId);
        }
    }

    @Nested
    @DisplayName("and reject")
    class Reject {

        @Test
        @DisplayName("ByteString")
        void findOutThatEntityIdInCommandCannotBeByteString() {
            EntityIdByteStringFieldValue msg = EntityIdByteStringFieldValue
                    .newBuilder()
                    .setValue(newByteString())
                    .build();
            assertNotValid(msg);
        }

        @Test
        @DisplayName("Float")
        void findOutThatEntityIdInCommandCannotBeFloatNumber() {
            EntityIdDoubleFieldValue msg = EntityIdDoubleFieldValue
                    .newBuilder()
                    .setValue(1.1)
                    .build();
            assertNotValid(msg);
        }
    }
}

@@ -1177,332 +1177,11 @@
 tyId
-ByteStringFieldValue;%0Aimport io.spine.test.validate.command.EntityIdDoubleFieldValue;%0Aimport io.spine.test.validate.command.EntityIdIntFieldValue;%0Aimport io.spine.test.validate.command.EntityIdLongFieldValue;%0Aimport io.spine.test.validate.command.EntityIdMsgFieldValue;%0Aimport io.spine.test.validate.command.EntityIdRepeated
+Msg
 Fiel
@@ -1567,85 +1567,8 @@
 UE;%0A
-import static io.spine.validate.given.MessageValidatorTestEnv.newByteString;%0A
 impo
@@ -1885,33 +1885,45 @@
 (%22find out that 
-M
+non-default m
 essage is valid%22
@@ -2310,17 +2310,25 @@
 ut that 
-M
+default m
 essage i
@@ -2574,33 +2574,43 @@
 (%22find out that 
-S
+non-empty s
 tring is valid%22)
@@ -3006,17 +3006,23 @@
 ut that 
-S
+empty s
 tring is
@@ -3234,1228 +3234,8 @@
  %7D%0A%0A
-        @Test%0A        @DisplayName(%22find out that Integer is valid%22)%0A        void findOutThatIntegerEntityIdInCommandIsValid() %7B%0A            EntityIdIntFieldValue msg = EntityIdIntFieldValue.newBuilder()%0A                                                             .setValue(5)%0A                                                             .build();%0A            assertValid(msg);%0A        %7D%0A%0A        @Test%0A        @DisplayName(%22find out that Long is valid%22)%0A        void findOutThatLongEntityIdInCommandIsValid() %7B%0A            EntityIdLongFieldValue msg = EntityIdLongFieldValue.newBuilder()%0A                                                               .setValue(5)%0A                                                               .build();%0A            assertValid(msg);%0A        %7D%0A%0A        @Test%0A        @DisplayName(%22find out that repeated is NOT valid%22)%0A        void findOutThatRepeatedEntityIdInCommandIsNotValid() %7B%0A            EntityIdRepeatedFieldValue msg = EntityIdRepeatedFieldValue.newBuilder()%0A                                                                       .addValue(newUuid())%0A                                                                       .build();%0A            assertNotValid(msg);%0A        %7D%0A%0A
     
@@ -4486,32 +4486,32 @@
 aultInstance();%0A
+
             asse
@@ -4558,740 +4558,7 @@
    %7D
-%0A%0A    @Nested%0A    @DisplayName(%22and reject%22)%0A    class Reject %7B%0A%0A        @Test%0A        @DisplayName(%22ByteString%22)%0A        void findOutThatEntityIdInCommandCannotBeByteString() %7B%0A            EntityIdByteStringFieldValue msg = EntityIdByteStringFieldValue%0A                    .newBuilder()%0A                    .setValue(newByteString())%0A                    .build();%0A            assertNotValid(msg);%0A        %7D%0A%0A        @Test%0A        @DisplayName(%22Float%22)%0A        void findOutThatEntityIdInCommandCannotBeFloatNumber() %7B%0A            EntityIdDoubleFieldValue msg = EntityIdDoubleFieldValue%0A                    .newBuilder()%0A                    .setValue(1.1)%0A                    .build();%0A            assertNotValid(msg);%0A        %7D%0A    %7D
 %0A%7D%0A

Delete some tests