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

import com.google.common.collect.Multimap;
import com.google.protobuf.Descriptors.FieldDescriptor;
import org.junit.Test;
import org.spine3.server.event.Given;
import org.spine3.test.event.ProjectCreated;
import org.spine3.test.event.enrichment.EnrichmentBoundWithMultipleFieldsWithDifferentNames;
import org.spine3.test.event.enrichment.GranterEventsEnrichment;
import org.spine3.test.event.enrichment.ProjectCreatedEnrichmentAnotherPackage;
import org.spine3.test.event.enrichment.ProjectCreatedEnrichmentAnotherPackageFqn;
import org.spine3.test.event.user.UserDeletedEvent;

import java.util.Collection;
import java.util.Iterator;
import java.util.Map;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.spine3.test.Verify.assertSize;

/**
 * @author Dmytro Dashenkov
 */
public class ReferenceValidatorShould {

    private final EventEnricher eventEnricher = Given.Enrichment.newEventEnricher();

    @Test
    public void initialize_with_valid_enricher() {
        final ReferenceValidator validator = new ReferenceValidator(eventEnricher,
                                                                    ProjectCreated.class,
                                                                    ProjectCreatedEnrichmentAnotherPackage.class);
        assertNotNull(validator);
    }

    @Test
    public void store_null_map_of_enrichment_fields_before_validation() {
        final ReferenceValidator validator = new ReferenceValidator(eventEnricher,
                                                                    ProjectCreated.class,
                                                                    ProjectCreatedEnrichmentAnotherPackageFqn.class);
        final Multimap<?, ?> fieldMap = validator.fieldMap();
        assertNull(fieldMap);
    }

    @Test
    public void store_valid_map_of_enrichment_fields_after_validation() {
        final ReferenceValidator validator = new ReferenceValidator(eventEnricher,
                                                                    UserDeletedEvent.class,
                                                                    EnrichmentBoundWithMultipleFieldsWithDifferentNames.class);
        validator.validate();
        final Multimap<FieldDescriptor, FieldDescriptor> fieldMap = validator.fieldMap();
        assertNotNull(fieldMap);
        assertFalse(fieldMap.isEmpty());
        assertSize(1, fieldMap);

        final Iterator<? extends Map.Entry<?, ? extends Collection<?>>> fieldsIterator = fieldMap.asMap()
                                                                                                 .entrySet()
                                                                                                 .iterator();
        assertTrue(fieldsIterator.hasNext());
        final Map.Entry<?, ? extends Collection<?>> entry = fieldsIterator.next();

        @SuppressWarnings("unchecked")
        final Map.Entry<FieldDescriptor, Collection<FieldDescriptor>> fieldEntry
                = (Map.Entry<FieldDescriptor, Collection<FieldDescriptor>>) entry;

        final FieldDescriptor eventField = fieldEntry.getKey();
        final String eventFieldName = eventField.getName();
        assertEquals("deleted_uid", eventFieldName);

        final Collection<FieldDescriptor> enrichmentFields = fieldEntry.getValue();
        assertFalse(enrichmentFields.isEmpty());
        assertSize(1, enrichmentFields);

        final Iterator<FieldDescriptor> enrichmentFieldIterator = enrichmentFields.iterator();
        assertTrue(enrichmentFieldIterator.hasNext());

        final FieldDescriptor enrichmentField = enrichmentFieldIterator.next();
        final String enrichmentFieldName = enrichmentField.getName();
        assertEquals("user_google_uid", enrichmentFieldName);
    }

    @Test(expected = IllegalStateException.class)
    public void fail_validation_if_enrichment_is_not_declared() {
        final ReferenceValidator validator = new ReferenceValidator(eventEnricher,
                                                                    UserDeletedEvent.class,
                                                                    GranterEventsEnrichment.class);
        validator.validate();
    }


}

@@ -1051,16 +1051,56 @@
 nrich;%0A%0A
+import com.google.common.base.Optional;%0A
 import c
@@ -1970,16 +1970,144 @@
 rtTrue;%0A
+import static org.mockito.ArgumentMatchers.any;%0Aimport static org.mockito.Mockito.mock;%0Aimport static org.mockito.Mockito.when;%0A
 import s
@@ -5600,11 +5600,649 @@
 %0A    %7D%0A%0A
+    @Test(expected = IllegalStateException.class)%0A    public void fail_if_no_mapping_function_is_defined() %7B%0A        final EventEnricher mockEnricher = mock(EventEnricher.class);%0A        when(mockEnricher.functionFor(any(Class.class), any(Class.class)))%0A                .thenReturn(Optional.%3CEnrichmentFunction%3C?, ?%3E%3Eabsent());%0A        final ReferenceValidator validator = new ReferenceValidator(mockEnricher,%0A                                                                    UserDeletedEvent.class,%0A                                                                    GranterEventsEnrichment.class);%0A        validator.validate();%0A    %7D%0A
 %0A%7D%0A

Add yet one more test for the ReferenceValidator.