/*
 * Copyright 2018, 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.client;

import com.google.protobuf.StringValue;
import com.google.protobuf.Timestamp;
import io.spine.core.Command;
import io.spine.core.TenantId;
import io.spine.test.commands.RequiredFieldCommand;
import io.spine.time.Timestamps2;
import io.spine.time.testing.TimeTests;
import io.spine.validate.ValidationException;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

@DisplayName("Command factory should")
class CommandFactoryTest extends ActorRequestFactoryTest {

    @Nested
    @DisplayName("create command")
    class CreateCommand {

        @Test
        @DisplayName("with current time")
        void withTimestamp() {
            // We are creating a range of +/- second between the call to make sure the timestamp
            // would fit into this range. The purpose of this test is to make sure it works with
            // this precision and to add coverage.
            Timestamp beforeCall = TimeTests.Past.secondsAgo(1);
            Command command = factory().command()
                                       .create(StringValue.getDefaultInstance());
            Timestamp afterCall = TimeTests.Future.secondsFromNow(1);

            assertTrue(Timestamps2.isBetween(
                    command.getContext()
                           .getActorContext()
                           .getTimestamp(), beforeCall, afterCall)
            );
        }

        @Test
        @DisplayName("with given entity version")
        void withEntityVersion() {
            Command command = factory().command()
                                       .create(StringValue.getDefaultInstance(), 2);

            assertEquals(2, command.getContext()
                                   .getTargetVersion());
        }

        @Test
        @DisplayName("with own tenant ID")
        void withOwnTenantId() {
            TenantId tenantId = TenantId
                    .newBuilder()
                    .setValue(getClass().getSimpleName())
                    .build();
            ActorRequestFactory mtFactory = builder()
                    .setTenantId(tenantId)
                    .setActor(actor())
                    .setZoneOffset(zoneOffset())
                    .build();
            Command command = mtFactory.command()
                                       .create(StringValue.getDefaultInstance());

            assertEquals(tenantId, command.getContext()
                                          .getActorContext()
                                          .getTenantId());
        }
    }

    @Nested
    @DisplayName("throw ValidationException when creating command")
    class NotAccept {

        @SuppressWarnings("unused")
        private final RequiredFieldCommand invalidCommand =
                RequiredFieldCommand.getDefaultInstance();

        @Test
        @DisplayName("from invalid Message")
        void invalidMessage() {
            RequiredFieldCommand invalidCommand = RequiredFieldCommand.getDefaultInstance();
            assertThrows(ValidationException.class, () -> factory().command()
                                                                   .create(invalidCommand));
        }

        @Test
        @DisplayName("from invalid Message with version")
        void invalidMessageWithVersion() {
            RequiredFieldCommand invalidCommand = RequiredFieldCommand.getDefaultInstance();
            assertThrows(ValidationException.class, () -> factory().command()
                                                                   .create(invalidCommand, 42));
        }
    }
}

@@ -1813,37 +1813,35 @@
 mand %7B%0A%0A        
-@Test
+/**
 %0A        @Displa
@@ -1837,72 +1837,97 @@
     
-@DisplayName(%22with current time%22)%0A        void withTimestamp() %7B
+ * Tests that a command is created with the current time.%0A         *%0A         * @implNote
 %0A   
@@ -1932,21 +1932,17 @@
         
-   //
+*
  We are 
@@ -2025,21 +2025,17 @@
         
-   //
+*
  would f
@@ -2060,111 +2060,236 @@
 . Th
-e purpose of this
+is way the test the
  test 
-is to make sure it works with%0A            // this precision and to add coverage.
+ensures the sub-second precision%0A         * of timestamps, which is enough for the purpose of this test.%0A         */%0A        @Test%0A        @DisplayName(%22with current time%22)%0A        void withTimestamp() %7B
 %0A   
@@ -2384,67 +2384,17 @@
 d = 
-factory().command()%0A                                       
+command()
 .cre
@@ -2862,67 +2862,17 @@
 d = 
-factory().command()%0A                                       
+command()
 .cre
@@ -3818,23 +3818,23 @@
       %7D%0A
+%0A
     %7D%0A
-%0A
     @Nes
@@ -3932,44 +3932,8 @@
  %7B%0A%0A
-        @SuppressWarnings(%22unused%22)%0A
     
@@ -3950,16 +3950,25 @@
 e final 
+%0A        
 Required
@@ -3996,32 +3996,16 @@
 ommand =
-%0A               
  Require
@@ -4148,234 +4148,63 @@
     
-RequiredFieldCommand invalidCommand = RequiredFieldCommand.getDefaultInstance();%0A            assertThrows(ValidationException.class, () -%3E factory().command()%0A                                                                   
+assertThrows(ValidationException.class, () -%3E command()
 .cre
@@ -4355,101 +4355,8 @@
 ) %7B%0A
-            RequiredFieldCommand invalidCommand = RequiredFieldCommand.getDefaultInstance();%0A
     
@@ -4413,27 +4413,46 @@
  -%3E 
-factory().command()
+command().create(invalidCommand, 42));
 %0A   
@@ -4460,106 +4460,92 @@
     
+%7D%0A%0A
     
-                                                       .create(invalidCommand, 42));%0A        %7D
+%7D%0A%0A    private CommandFactory command() %7B%0A        return factory().command();
 %0A   

Fix test code duplication and documentation