/*
 * Copyright 2020, 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.store;

import com.google.common.collect.ImmutableList;
import com.google.protobuf.util.Timestamps;
import io.spine.core.Event;
import io.spine.core.EventId;
import io.spine.query.QueryPredicate;
import io.spine.query.RecordQuery;
import io.spine.query.Subject;
import io.spine.query.SubjectParameter;
import io.spine.server.event.EventFilter;
import io.spine.server.event.EventStreamQuery;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

import static com.google.common.truth.Truth.assertThat;
import static io.spine.query.LogicalOperator.AND;
import static io.spine.query.LogicalOperator.OR;
import static io.spine.server.event.store.Queries.convert;

@DisplayName("`Queries` should")
class QueriesTest {

    @Test
    @DisplayName("convert empty query to an empty `RecordQuery`")
    void convertEmptyToFilters() {
        EventStreamQuery query = EventStreamQuery.newBuilder()
                                                 .build();
        RecordQuery<EventId, Event> result = convert(query);
        Subject<EventId, Event> subject = result.subject();
        assertThat(subject.id().values()).isEmpty();
        assertThat(subject.predicates()).isEmpty();
    }

    @Test
    @DisplayName("convert time query to the corresponding `RecordQuery`")
    void convertTimeToFilters() {
        EventStreamQuery query = EventStreamQuery
                .newBuilder()
                .setAfter(Timestamps.MIN_VALUE)
                .setBefore(Timestamps.MAX_VALUE)
                .build();
        RecordQuery<EventId, Event> result = convert(query);
        Subject<EventId, Event> subject = result.subject();
        assertThat(subject.predicates()).hasSize(1);

        QueryPredicate<Event> predicate = subject.predicates()
                                                 .get(0);
        assertThat(predicate.operator()).isEqualTo(AND);
        assertThat(predicate.parameters()).hasSize(2);
    }

    @Test
    @DisplayName("convert type query to the corresponding `RecordQuery`")
    void convertTypeToFilters() {
        String expected = " com.example.EventType ";
        EventFilter validFilter = filterForType(expected);
        EventFilter invalidFilter = filterForType("   ");
        EventStreamQuery query = EventStreamQuery
                .newBuilder()
                .addFilter(validFilter)
                .addFilter(invalidFilter)
                .build();
        RecordQuery<EventId, Event> result = convert(query);
        Subject<EventId, Event> subject = result.subject();
        assertThat(subject.predicates()).hasSize(1);
        QueryPredicate<Event> predicate = subject.predicates()
                                                 .get(0);
        assertThat(predicate.operator()).isEqualTo(OR);

        ImmutableList<SubjectParameter<Event, ?, ?>> parameters = predicate.parameters();
        assertThat(parameters).hasSize(1);

        SubjectParameter<Event, ?, ?> parameter = parameters.get(0);
        Object value = parameter.value();
        assertThat(value).isEqualTo(expected.trim());
    }

    private static EventFilter filterForType(String typeName) {
        return EventFilter.newBuilder()
                          .setEventType(typeName)
                          .build();
    }
}

@@ -1092,16 +1092,68 @@
 leList;%0A
+import com.google.common.testing.NullPointerTester;%0A
 import c
@@ -1557,16 +1557,94 @@
 .Test;%0A%0A
+import static com.google.common.testing.NullPointerTester.Visibility.PACKAGE;%0A
 import s
@@ -1853,61 +1853,597 @@
 rt;%0A
-%0A@DisplayName(%22%60Queries%60 should%22)%0Aclass QueriesTest %7B
+import static io.spine.testing.DisplayNames.HAVE_PARAMETERLESS_CTOR;%0Aimport static io.spine.testing.DisplayNames.NOT_ACCEPT_NULLS;%0Aimport static io.spine.testing.Tests.assertHasPrivateParameterlessCtor;%0A%0A@DisplayName(%22%60Queries%60 should%22)%0Aclass QueriesTest %7B%0A%0A    @Test%0A    @DisplayName(HAVE_PARAMETERLESS_CTOR)%0A    void haveUtilityConstructor() %7B%0A        assertHasPrivateParameterlessCtor(Queries.class);%0A    %7D%0A%0A    @Test%0A    @DisplayName(NOT_ACCEPT_NULLS)%0A    void passNullToleranceCheck() %7B%0A        new NullPointerTester()%0A                .testStaticMethods(Queries.class, PACKAGE);%0A    %7D
 %0A%0A  
@@ -2476,16 +2476,19 @@
 convert 
+an 
 empty qu
@@ -2828,16 +2828,43 @@
 ect.id()
+%0A                          
 .values(
@@ -2973,19 +2973,35 @@
 onvert t
-ime
+he time-constrained
  query t
@@ -3724,16 +3724,26 @@
 convert 
+the event-
 type que

Test `Queries` for `null` intolerance of the params and ensure it has a private parameterless ctor. Rephrase some of the display names.