# AbstractEntityFinderTest.java

    /*
     * Copyright 2008 Alin Dreghiciu.
     * Copyright 2012 Stanislav Muhametsin.
     * Copyright 2012 Paul Merlin.
     *
     * Licensed  under the  Apache License,  Version 2.0  (the "License");
     * you may not use  this file  except in  compliance with the License.
     * You may obtain a copy of the License at
     *
     *   http://www.apache.org/licenses/LICENSE-2.0
     *
     * Unless required by applicable law or agreed to in writing, software
     * distributed  under the  License is distributed on an "AS IS" BASIS,
     * WITHOUT  WARRANTIES OR CONDITIONS  OF ANY KIND, either  express  or
     * implied.
     *
     * See the License for the specific language governing permissions and
     * limitations under the License.
     */
    package org.qi4j.test.indexing;

    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import org.junit.Before;
    import org.junit.Test;
    import org.qi4j.api.composite.Composite;
    import org.qi4j.api.entity.EntityReference;
    import org.qi4j.api.query.grammar.OrderBy;
    import org.qi4j.api.service.ServiceReference;
    import org.qi4j.functional.Specification;
    import org.qi4j.spi.query.EntityFinder;
    import org.qi4j.spi.query.EntityFinderException;
    import org.qi4j.spi.query.IndexExporter;
    import org.qi4j.test.indexing.model.Domain;
    import org.qi4j.test.indexing.model.Female;
    import org.qi4j.test.indexing.model.Male;
    import org.qi4j.test.indexing.model.Nameable;
    import org.qi4j.test.indexing.model.Person;

    import static org.junit.Assert.assertEquals;
    import static org.qi4j.api.query.QueryExpressions.and;
    import static org.qi4j.api.query.QueryExpressions.eq;
    import static org.qi4j.api.query.QueryExpressions.ge;
    import static org.qi4j.api.query.QueryExpressions.gt;
    import static org.qi4j.api.query.QueryExpressions.isNotNull;
    import static org.qi4j.api.query.QueryExpressions.isNull;
    import static org.qi4j.api.query.QueryExpressions.matches;
    import static org.qi4j.api.query.QueryExpressions.not;
    import static org.qi4j.api.query.QueryExpressions.or;
    import static org.qi4j.api.query.QueryExpressions.orderBy;
    import static org.qi4j.api.query.QueryExpressions.templateFor;
    import static org.qi4j.api.query.QueryExpressions.variable;
    import static org.qi4j.functional.Iterables.toList;
    import static org.qi4j.test.indexing.NameableAssert.assertNames;

    /**
     * Abstract satisfiedBy with tests for the EntityFinder interface.
     */
    public abstract class AbstractEntityFinderTest
        extends AbstractAnyQueryTest
    {

        private static final Specification<Composite> ALL = null;

        private static final OrderBy[] NO_SORTING = null;

        private static final Integer NO_FIRST_RESULT = null;

        private static final Integer NO_MAX_RESULTS = null;

        private static final Map<String, Object> NO_VARIABLES = Collections.<String, Object>emptyMap();

        private static final String JACK = "Jack Doe";

        private static final String JOE = "Joe Doe";

        private static final String ANN = "Ann Doe";

        private EntityFinder entityFinder;

        @Before
        @Override
        public void setUp()
            throws Exception
        {
            super.setUp();
            entityFinder = this.module.findService( EntityFinder.class ).get();
        }

        @Test
        public void showNetwork()
            throws IOException
        {
            final ServiceReference<IndexExporter> indexerService = this.module.findService( IndexExporter.class );
            final IndexExporter exporter = indexerService.get();
            exporter.exportReadableToStream( System.out );
            // todo asserts
        }

        @Test
        public void script01()
            throws EntityFinderException
        {
            // should return all persons (Joe, Ann, Jack Doe)
            Iterable<EntityReference> entities = entityFinder.findEntities(
                Person.class,
                ALL,
                NO_SORTING,
                NO_FIRST_RESULT, NO_MAX_RESULTS,
                NO_VARIABLES );
            assertNames( entities, JOE, JACK, ANN );
        }

        @Test
        public void script02()
            throws EntityFinderException
        {
            Nameable nameable = templateFor( Nameable.class );
            // should return Gaming domain
            Iterable<EntityReference> entities = entityFinder.findEntities(
                Domain.class,
                eq( nameable.name(), "Gaming" ),
                NO_SORTING,
                NO_FIRST_RESULT, NO_MAX_RESULTS,
                NO_VARIABLES );
            assertNames( entities, "Gaming" );
        }

        @Test
        public void script03()
            throws EntityFinderException
        {
            // should return all entities
            Iterable<EntityReference> entities = entityFinder.findEntities(
                Nameable.class,
                ALL,
                NO_SORTING,
                NO_FIRST_RESULT, NO_MAX_RESULTS,
                NO_VARIABLES );
            assertNames( entities, NameableAssert.allNames() );
        }

        @Test
        public void script04()
            throws EntityFinderException
        {
            Person person = templateFor( Person.class );
            // should return Joe and Ann Doe
            Iterable<EntityReference> entities = entityFinder.findEntities(
                Person.class,
                eq( person.placeOfBirth().get().name(), "Kuala Lumpur" ),
                NO_SORTING,
                NO_FIRST_RESULT, NO_MAX_RESULTS,
                NO_VARIABLES );
            assertNames( entities, JOE, ANN );
        }

        @Test
        public void script05()
            throws EntityFinderException
        {
            Person person = templateFor( Person.class );
            // should return Joe Doe
            Iterable<EntityReference> entities = entityFinder.findEntities(
                Person.class,
                eq( person.mother().get().placeOfBirth().get().name(), "Kuala Lumpur" ),
                NO_SORTING,
                NO_FIRST_RESULT, NO_MAX_RESULTS,
                NO_VARIABLES );
            assertNames( entities, JOE );
        }

        @Test
        public void script06()
            throws EntityFinderException
        {
            Person person = templateFor( Person.class );
            // should return Joe and Ann Doe
            Iterable<EntityReference> entities = entityFinder.findEntities(
                Person.class,
                ge( person.yearOfBirth(), 1973 ),
                NO_SORTING,
                NO_FIRST_RESULT, NO_MAX_RESULTS,
                NO_VARIABLES );
            assertNames( entities, JOE, ANN );
        }

        @Test
        @SuppressWarnings( "unchecked" )
        public void script07()
            throws EntityFinderException
        {
            Person person = templateFor( Person.class );
            // should return Jack Doe
            Iterable<EntityReference> entities = entityFinder.findEntities(
                Nameable.class,
                and( ge( person.yearOfBirth(), 1900 ), eq( person.placeOfBirth().get().name(), "Penang" ) ),
                NO_SORTING,
                NO_FIRST_RESULT, NO_MAX_RESULTS,
                NO_VARIABLES );
            assertNames( entities, JACK );
        }

        @Test
        @SuppressWarnings( "unchecked" )
        public void script08()
            throws EntityFinderException
        {
            Person person = templateFor( Person.class );
            // should return Jack and Ann Doe
            Iterable<EntityReference> entities = entityFinder.findEntities(
                Person.class,
                or( eq( person.yearOfBirth(), 1970 ), eq( person.yearOfBirth(), 1975 ) ),
                NO_SORTING,
                NO_FIRST_RESULT, NO_MAX_RESULTS,
                NO_VARIABLES );
            assertNames( entities, JACK, ANN );
        }

        @Test
        @SuppressWarnings( "unchecked" )
        public void script09()
            throws EntityFinderException
        {
            Person person = templateFor( Person.class );
            // should return Ann Doe
            Iterable<EntityReference> entities = entityFinder.findEntities(
                Female.class,
                or( eq( person.yearOfBirth(), 1970 ), eq( person.yearOfBirth(), 1975 ) ),
                NO_SORTING,
                NO_FIRST_RESULT, NO_MAX_RESULTS,
                NO_VARIABLES );
            assertNames( entities, ANN );
        }

        @Test
        public void script10()
            throws EntityFinderException
        {
            Person person = templateFor( Person.class );
            // should return Joe and Jack Doe
            Iterable<EntityReference> entities = entityFinder.findEntities(
                Person.class,
                not( eq( person.yearOfBirth(), 1975 ) ),
                NO_SORTING,
                NO_FIRST_RESULT, NO_MAX_RESULTS,
                NO_VARIABLES );
            assertNames( entities, JOE, JACK );
        }

        @Test
        public void script11()
            throws EntityFinderException
        {
            Person person = templateFor( Person.class );
            // should return Joe Doe
            Iterable<EntityReference> entities = entityFinder.findEntities(
                Person.class,
                isNotNull( person.email() ),
                NO_SORTING,
                NO_FIRST_RESULT, NO_MAX_RESULTS,
                NO_VARIABLES );
            assertNames( entities, JOE );
        }

        @Test
        public void script12()
            throws EntityFinderException
        {
            Person person = templateFor( Person.class );
            // should return Ann and Jack Doe
            Iterable<EntityReference> entities = entityFinder.findEntities(
                Person.class,
                isNull( person.email() ),
                NO_SORTING,
                NO_FIRST_RESULT, NO_MAX_RESULTS,
                NO_VARIABLES );
            assertNames( entities, ANN, JACK );
        }

        @Test
        public void script13()
            throws EntityFinderException
        {
            Male person = templateFor( Male.class );
            // should return Jack Doe
            Iterable<EntityReference> entities = entityFinder.findEntities(
                Person.class,
                isNotNull( person.wife() ),
                NO_SORTING,
                NO_FIRST_RESULT, NO_MAX_RESULTS,
                NO_VARIABLES );
            assertNames( entities, JACK );
        }

        @Test
        public void script14()
            throws EntityFinderException
        {
            Male person = templateFor( Male.class );
            // should return Joe Doe
            Iterable<EntityReference> entities = entityFinder.findEntities(
                Male.class,
                isNull( person.wife() ),
                NO_SORTING,
                NO_FIRST_RESULT, NO_MAX_RESULTS,
                NO_VARIABLES );
            assertNames( entities, JOE );
        }

        @Test
        public void script15()
            throws EntityFinderException
        {
            Male person = templateFor( Male.class );
            // should return Ann and Joe Doe
            Iterable<EntityReference> entities = entityFinder.findEntities(
                Person.class,
                isNull( person.wife() ),
                NO_SORTING,
                NO_FIRST_RESULT, NO_MAX_RESULTS,
                NO_VARIABLES );
            assertNames( entities, ANN, JOE );
        }

        @Test
        public void script16()
            throws EntityFinderException
        {
            // should return only 2 entities
            final List<EntityReference> references = toList( entityFinder.findEntities(
                Nameable.class,
                ALL,
                NO_SORTING,
                NO_FIRST_RESULT, 2,
                NO_VARIABLES ) );
            assertEquals( "2 identitities", 2, references.size() );
        }

        @Test
        public void script17()
            throws EntityFinderException
        {
            // should return only 2 entities starting with third one
            final List<EntityReference> references = toList( entityFinder.findEntities(
                Nameable.class,
                ALL,
                NO_SORTING,
                3, 2,
                NO_VARIABLES ) );
            assertEquals( "2 identitities", 2, references.size() );
        }

        @Test
        public void script18()
            throws EntityFinderException
        {
            // should return all Nameable entities sorted by name
            Nameable nameable = templateFor( Nameable.class );
            final String[] allNames = NameableAssert.allNames();
            Arrays.sort( allNames );

            Iterable<EntityReference> entities = entityFinder.findEntities(
                Nameable.class,
                ALL,
                new OrderBy[]
            {
                orderBy( nameable.name() )
                },
                NO_FIRST_RESULT, NO_MAX_RESULTS,
                NO_VARIABLES );
            assertNames( false, entities, allNames );
        }

        @Test
        public void script19()
            throws EntityFinderException
        {
            // should return all Nameable entities with a name > "B" sorted by name
            Nameable nameable = templateFor( Nameable.class );
            List<String> largerThanB = new ArrayList<>();
            for( String name : NameableAssert.allNames() )
            {
                if( name.compareTo( "B" ) > 0 )
                {
                    largerThanB.add( name );
                }
            }
            Collections.sort( largerThanB );
            Iterable<EntityReference> entities = entityFinder.findEntities(
                Nameable.class,
                gt( nameable.name(), "B" ),
                new OrderBy[]
            {
                orderBy( nameable.name() )
                },
                NO_FIRST_RESULT, NO_MAX_RESULTS,
                NO_VARIABLES );
            assertNames( false, entities, largerThanB.toArray( new String[ largerThanB.size() ] ) );
        }

        @Test
        public void script20()
            throws EntityFinderException
        {
            // should return all Persons born after 1973 (Ann and Joe Doe) sorted descending by name
            Person person = templateFor( Person.class );
            Iterable<EntityReference> entities = entityFinder.findEntities(
                Person.class,
                gt( person.yearOfBirth(), 1973 ),
                new OrderBy[]
            {
                orderBy( person.name(), OrderBy.Order.DESCENDING )
                },
                NO_FIRST_RESULT, NO_MAX_RESULTS,
                NO_VARIABLES );
            assertNames( false, entities, JOE, ANN );
        }

        @Test
        public void script21()
            throws EntityFinderException
        {
            // should return all Persons sorted name of the city they were born
            Person person = templateFor( Person.class );
            Iterable<EntityReference> entities = entityFinder.findEntities(
                Person.class,
                ALL,
                new OrderBy[]
            {
                orderBy( person.placeOfBirth().get().name() ), orderBy( person.name() )
                },
                NO_FIRST_RESULT, NO_MAX_RESULTS,
                NO_VARIABLES );
            assertNames( false, entities, ANN, JOE, JACK );
        }

        @Test
        public void script22()
            throws EntityFinderException
        {
            Nameable nameable = templateFor( Nameable.class );
            // should return Jack and Joe Doe
            Iterable<EntityReference> entities = entityFinder.findEntities(
                Nameable.class,
                matches( nameable.name(), "J.*Doe" ),
                NO_SORTING,
                NO_FIRST_RESULT, NO_MAX_RESULTS,
                NO_VARIABLES );
            assertNames( entities, JACK, JOE );
        }

        @Test
        public void script23()
            throws EntityFinderException
        {
            Nameable nameable = templateFor( Nameable.class );
            // Try using variables
            Map<String, Object> variables = new HashMap<>( 1 );
            variables.put( "domain", "Gaming" );
            Iterable<EntityReference> entities = entityFinder.findEntities(
                Domain.class,
                eq( nameable.name(), variable( "domain" ) ),
                NO_SORTING,
                NO_FIRST_RESULT, NO_MAX_RESULTS,
                variables );
            assertNames( entities, "Gaming" );
        }

    }