/*
 * 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.server.event.enrich;

import com.google.common.collect.ImmutableSet;
import com.google.protobuf.Message;
import io.spine.type.TypeName;

import static com.google.common.truth.Truth.assertThat;

/**
 * Asserts that the passed enrichment class enriches message classes.
 */
final class EnrichmentAssertion {

    private static final EnrichmentMap INSTANCE = EnrichmentMap.load();

    private final TypeName enrichmentType;

    private EnrichmentAssertion(Class<? extends Message> cls) {
        enrichmentType = TypeName.of(cls);
    }

    static EnrichmentAssertion _assert(Class<? extends Message> cls) {
        return new EnrichmentAssertion(cls);
    }

    /**
     * Asserts that the passed enrichment class is used for enriching passed message classes.
     */
    @SafeVarargs
    final void enriches(Class<? extends Message>... expectedClasses) {
        ImmutableSet<TypeName> sourceEvents = map().sourceTypes(enrichmentType);

        for (Class<? extends Message> eventClass : expectedClasses) {
            TypeName eventType = TypeName.of(eventClass);
            assertThat(sourceEvents).contains(eventType);
        }
    }

    /**
     * Asserts that passed enrichment class enriches <em>only</em> passed source message classes.
     */
    @SafeVarargs
    final void enrichesOnly(Class<? extends Message>... expectedClasses) {

        ImmutableSet<Class<Message>> actual = map().sourceClasses(enrichmentType);
        assertThat(actual)
                .hasSize(expectedClasses.length);
        enriches(expectedClasses);
    }

    private static EnrichmentMap map() {
        return INSTANCE;
    }
}

@@ -1092,16 +1092,64 @@
 bleSet;%0A
+import com.google.common.truth.IterableSubject;%0A
 import c
@@ -1208,16 +1208,118 @@
 eName;%0A%0A
+import java.util.stream.Stream;%0A%0Aimport static com.google.common.collect.ImmutableSet.toImmutableSet;%0A
 import s
@@ -1519,24 +1519,19 @@
 mentMap 
-INSTANCE
+MAP
  = Enric
@@ -2039,277 +2039,47 @@
     
-ImmutableSet%3CTypeName%3E sourceEvents = map().sourceTypes(enrichmentType);%0A%0A        for (Class%3C? extends Message%3E eventClass : expectedClasses) %7B%0A            TypeName eventType = TypeName.of(eventClass);%0A            assertThat(sourceEvents).contains(eventType);%0A        %7D
+assertEnriches(false, expectedClasses);
 %0A   
@@ -2288,25 +2288,24 @@
 sses) %7B%0A
-%0A
         
 Immutabl
@@ -2300,43 +2300,214 @@
     
-ImmutableSet%3CClass%3CMessage%3E%3E actual
+assertEnriches(true, expectedClasses);%0A    %7D%0A%0A    @SafeVarargs%0A    private final void assertEnriches(boolean strict, Class%3C? extends Message%3E... expectedClasses) %7B%0A        ImmutableSet%3CTypeName%3E sourceTypes
  = m
@@ -2517,21 +2517,19 @@
 ).source
-Class
+Typ
 es(enric
@@ -2552,26 +2552,46 @@
     
-assertThat(actual)
+ImmutableSet%3CTypeName%3E expectedTypes =
 %0A   
@@ -2607,16 +2607,17 @@
     
-.hasSize
+Stream.of
 (exp
@@ -2632,52 +2632,330 @@
 sses
-.length);%0A        enriches(expectedClasses);
+)%0A                      .map(TypeName::of)%0A                      .collect(toImmutableSet());%0A%0A        IterableSubject assertThat = assertThat(sourceTypes);%0A        if (strict) %7B%0A            assertThat.containsExactlyElementsIn(expectedTypes);%0A        %7D else %7B%0A            assertThat.containsAllIn(expectedTypes);%0A        %7D
 %0A   
@@ -3018,16 +3018,11 @@
 urn 
-INSTANCE
+MAP
 ;%0A  

Improve checking iterables