/*
 * 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.server.projection.e2e;

import io.spine.base.EventMessage;
import io.spine.core.Event;
import io.spine.server.projection.given.EntitySubscriberProjection;
import io.spine.server.projection.given.ProjectionRepositoryTestEnv.GivenEventMessage;
import io.spine.server.projection.given.TestProjection;
import io.spine.test.projection.ProjectId;
import io.spine.test.projection.ProjectTaskNames;
import io.spine.test.projection.event.PrjProjectCreated;
import io.spine.test.projection.event.PrjTaskAdded;
import io.spine.testing.server.TestEventFactory;
import io.spine.testing.server.blackbox.BlackBoxBoundedContext;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static com.google.common.collect.ImmutableSet.of;
import static io.spine.testing.server.TestEventFactory.newInstance;
import static io.spine.testing.server.blackbox.VerifyState.exactly;

@DisplayName("Projection should")
class ProjectionEndToEndTest {

    @Test
    @DisplayName("receive entity state updates from other entities")
    void receiveUpdates() {
        PrjProjectCreated created = GivenEventMessage.projectCreated();
        PrjTaskAdded firstTaskAdded = GivenEventMessage.taskAdded();
        PrjTaskAdded secondTaskAdded = GivenEventMessage.taskAdded();
        ProjectId id = created.getProjectId();
        BlackBoxBoundedContext
                .newInstance()
                .with(new EntitySubscriberProjection.Repository(),
                      new TestProjection.Repository())
                .receivesEvents(event(id, created),
                                event(id, firstTaskAdded),
                                event(id, secondTaskAdded))
                .assertThat(exactly(ProjectTaskNames.class,
                                    of(ProjectTaskNames
                                               .newBuilder()
                                               .setProjectId(id)
                                               .setProjectName(created.getName())
                                               .addTaskName(firstTaskAdded.getTask().getTitle())
                                               .addTaskName(secondTaskAdded.getTask().getTitle())
                                               .build())));
    }

    private static Event event(ProjectId producer, EventMessage eventMessage) {
        TestEventFactory eventFactory = newInstance(producer, ProjectionEndToEndTest.class);
        Event result = eventFactory.createEvent(eventMessage);
        return result;
    }
}

@@ -2753,16 +2753,20 @@
 s.class,
+ of(
 %0A       
@@ -2786,23 +2786,8 @@
     
-            of(
 Proj
@@ -2799,31 +2799,16 @@
 skNames%0A
-               
         
@@ -2873,39 +2873,24 @@
             
-               
 .setProjectI
@@ -2895,31 +2895,16 @@
 tId(id)%0A
-               
         
@@ -2982,32 +2982,86 @@
                 
+    .addTaskName(firstTaskAdded.getTask().getTitle())%0A
                 
@@ -3055,32 +3055,45 @@
                 
+             
 .addTaskName(fir
@@ -3081,37 +3081,38 @@
    .addTaskName(
-first
+second
 TaskAdded.getTas
@@ -3151,32 +3151,41 @@
                 
+.build()%0A
                .
@@ -3187,82 +3187,970 @@
     
-.addTaskName(secondTaskAdded.getTask().getTitle())%0A                       
+ )));%0A    %7D%0A%0A    @Test%0A    @DisplayName(%22receive entity state updates of entities of other context%22)%0A    @SuppressWarnings(%22ResultOfMethodCallIgnored%22)%0A        // Black box context is used in a non-fluent fashion.%0A    void receiveExternal() %7B%0A        PrjProjectCreated created = GivenEventMessage.projectCreated();%0A        ProjectId id = created.getProjectId();%0A        BlackBoxBoundedContext sender = BlackBoxBoundedContext%0A                .newInstance()%0A                .with(new TestProjection.Repository());%0A        BlackBoxBoundedContext receiver = BlackBoxBoundedContext%0A                .newInstance()%0A                .with(new EntitySubscriberProjection.Repository());%0A        sender.receivesEvent(event(id, created));%0A        receiver.assertThat(exactly(ProjectTaskNames.class, of(%0A                ProjectTaskNames%0A                        .newBuilder()%0A                        .setProjectId(id)%0A                        .setProjectName(created.getName())%0A
     
@@ -4177,16 +4177,25 @@
 .build()
+%0A        
 )));%0A   

Add one more test.