/*
 * Copyright 2017, TeamDev Ltd. 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 org.spine3.examples.todolist.c.aggregate.definition;

import com.google.common.base.Throwables;
import com.google.protobuf.Message;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.spine3.examples.todolist.TaskDefinition;
import org.spine3.examples.todolist.c.commands.CompleteTask;
import org.spine3.examples.todolist.c.commands.CreateBasicTask;
import org.spine3.examples.todolist.c.commands.CreateDraft;
import org.spine3.examples.todolist.c.commands.DeleteTask;
import org.spine3.examples.todolist.c.events.TaskCompleted;
import org.spine3.examples.todolist.c.failures.CannotCompleteTask;

import java.util.List;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
import static org.spine3.examples.todolist.TaskStatus.COMPLETED;
import static org.spine3.examples.todolist.testdata.TestTaskCommandFactory.DESCRIPTION;
import static org.spine3.examples.todolist.testdata.TestTaskCommandFactory.completeTaskInstance;
import static org.spine3.examples.todolist.testdata.TestTaskCommandFactory.createDraftInstance;
import static org.spine3.examples.todolist.testdata.TestTaskCommandFactory.createTaskInstance;
import static org.spine3.examples.todolist.testdata.TestTaskCommandFactory.deleteTaskInstance;

/**
 * @author Illia Shepilov
 */
@DisplayName("CompleteTask command should be interpreted by TaskDefinitionPart and")
public class CompleteTaskTest extends TaskDefinitionCommandTest<CompleteTask> {

    @Override
    @BeforeEach
    protected void setUp() {
        super.setUp();
    }

    @Test
    @DisplayName("produce TaskCompleted event")
    void produceEvent() {
        dispatchCreateTaskCmd();

        final List<? extends Message> messageList = dispatchCompleteTaskCmd();

        assertEquals(1, messageList.size());
        assertEquals(TaskCompleted.class, messageList.get(0)
                                                     .getClass());
        final TaskCompleted taskCompleted = (TaskCompleted) messageList.get(0);

        assertEquals(taskId, taskCompleted.getTaskId());
    }

    @Test
    @DisplayName("complete the task")
    void completeTheTask() {
        dispatchCreateTaskCmd();

        dispatchCompleteTaskCmd();
        final TaskDefinition state = aggregate.getState();

        assertEquals(taskId, state.getId());
        assertEquals(COMPLETED, state.getTaskStatus());
    }

    @Test
    @DisplayName("throw CannotCompleteTask failure upon an attempt to complete the deleted task")
    void cannotCompleteDeletedTask() {
        dispatchCreateTaskCmd();

        final DeleteTask deleteTaskCmd = deleteTaskInstance(taskId);
        aggregate.dispatchForTest(deleteTaskCmd, commandContext);

        try {
            dispatchCompleteTaskCmd();
        } catch (Throwable e) {
            @SuppressWarnings("ThrowableResultOfMethodCallIgnored") // Need it for checking.
            final Throwable cause = Throwables.getRootCause(e);
            assertTrue(cause instanceof CannotCompleteTask);
        }
    }

    @Test
    @DisplayName("throw CannotCompleteTask failure upon an attempt to complete the task in draft state")
    void cannotCompleteDraft() {
        final CreateDraft createDraftCmd = createDraftInstance(taskId);
        aggregate.dispatchForTest(createDraftCmd, commandContext);

        try {
            dispatchCompleteTaskCmd();
            fail("CannotCompleteTask was not thrown.");
        } catch (Throwable e) {
            @SuppressWarnings("ThrowableResultOfMethodCallIgnored") // Need it for checking.
            final Throwable cause = Throwables.getRootCause(e);
            assertTrue(cause instanceof CannotCompleteTask);
        }
    }

    private void dispatchCreateTaskCmd() {
        final CreateBasicTask createTaskCmd = createTaskInstance(taskId, DESCRIPTION);
        aggregate.dispatchForTest(createTaskCmd, commandContext);
    }

    private List<? extends Message> dispatchCompleteTaskCmd() {
        final CompleteTask completeTaskCmd = completeTaskInstance(taskId);
        return aggregate.dispatchForTest(completeTaskCmd, commandContext);
    }
}

@@ -1738,49 +1738,89 @@
 org.
-junit.jupiter.api.Assertions.assertEquals
+hamcrest.MatcherAssert.assertThat;%0Aimport static org.hamcrest.Matchers.instanceOf
 ;%0Aim
@@ -1870,20 +1870,22 @@
 s.assert
-True
+Equals
 ;%0Aimport
@@ -1925,20 +1925,28 @@
 ertions.
-fail
+assertThrows
 ;%0Aimport
@@ -3924,116 +3924,41 @@
     
-try %7B%0A            dispatchCompleteTaskCmd();%0A        %7D catch (Throwable e) %7B%0A            @SuppressWarning
+final Throwable t = assertThrow
 s(
-%22
 Thro
@@ -3966,153 +3966,94 @@
 able
-ResultOfMethodCallIgnored%22) // Need it for checking.%0A            final Throwable cause = Throwables.getRootCause(e);%0A            assertTrue(cause
+.class, this::dispatchCompleteTaskCmd);%0A        assertThat(Throwables.getRootCause(t),
  ins
@@ -4049,35 +4049,35 @@
 use(t), instance
-of 
+Of(
 CannotCompleteTa
@@ -4074,36 +4074,33 @@
 CompleteTask
-);%0A        %7D
+.class));
 %0A    %7D%0A%0A    
@@ -4153,32 +4153,49 @@
 sk failure upon 
+%22 +%0A            %22
 an attempt to co
@@ -4412,172 +4412,41 @@
     
-try %7B%0A            dispatchCompleteTaskCmd();%0A            fail(%22CannotCompleteTask was not thrown.%22);%0A        %7D catch (Throwable e) %7B%0A            @SuppressWarning
+final Throwable t = assertThrow
 s(
-%22
 Thro
@@ -4454,153 +4454,94 @@
 able
-ResultOfMethodCallIgnored%22) // Need it for checking.%0A            final Throwable cause = Throwables.getRootCause(e);%0A            assertTrue(cause
+.class, this::dispatchCompleteTaskCmd);%0A        assertThat(Throwables.getRootCause(t),
  ins
@@ -4549,11 +4549,11 @@
 ance
-of 
+Of(
 Cann
@@ -4570,20 +4570,17 @@
 Task
-);%0A        %7D
+.class));
 %0A   

Rewrite exception instance checking using `assertThrows`