cz.jirutka.rsql.hibernate.RSQL2CriteriaConverterImplTest.java Source code

Java tutorial

Introduction

Here is the source code for cz.jirutka.rsql.hibernate.RSQL2CriteriaConverterImplTest.java

Source

/*
 * The MIT License
 *
 * Copyright 2013 Jakub Jirutka <jakub@jirutka.cz>.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */
package cz.jirutka.rsql.hibernate;

import cz.jirutka.rsql.hibernate.builder.AbstractCriterionBuilder;
import cz.jirutka.rsql.hibernate.builder.CriteriaBuilder;
import cz.jirutka.rsql.hibernate.exception.ArgumentFormatException;
import cz.jirutka.rsql.hibernate.exception.AssociationsLimitException;
import cz.jirutka.rsql.hibernate.exception.RSQLException;
import cz.jirutka.rsql.hibernate.exception.UnknownSelectorException;
import org.hibernate.impl.CriteriaImpl.Subcriteria;
import cz.jirutka.rsql.hibernate.RSQL2CriteriaConverterImpl.InnerBuilder;
import org.hibernate.Criteria;
import cz.jirutka.rsql.hibernate.entity.Course;
import cz.jirutka.rsql.parser.model.Comparison;
import cz.jirutka.rsql.parser.model.ComparisonExpression;
import cz.jirutka.rsql.parser.model.Expression;
import cz.jirutka.rsql.parser.model.Logical;
import cz.jirutka.rsql.parser.model.LogicalExpression;
import java.util.Iterator;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.hibernate.impl.CriteriaImpl;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;

/**
 *
 * @author Jakub Jirutka <jakub@jirutka.cz>
 */
public class RSQL2CriteriaConverterImplTest {

    private SessionFactory sessionFactory;
    private Mapper mapper;
    private RSQL2CriteriaConverterImpl instance;
    private InnerBuilder inner;

    @Before
    public void setUp() throws Exception {
        sessionFactory = SessionFactoryInitializer.getSessionFactory();
        mapper = new Mapper() {
            @Override
            public String translate(String selector, Class<?> entityClass) {
                return selector;
            }
        };
        instance = new MockRSQL2CriteriaConverterImpl(sessionFactory);
        instance.setMapper(mapper);
        instance.pushCriterionBuilder(new MockCriterionBuilder());
        inner = ((MockRSQL2CriteriaConverterImpl) instance).createInnerBuilder(Course.class);
    }

    ////////////////////////// Tests //////////////////////////

    /**
     * Test if single comparison expression is routed to Criterion Builder well.
     */
    @Test
    public void testInnerConvertDetached0() {
        instance.setMapper(mapper);
        instance.pushCriterionBuilder(new MockCriterionBuilder() {
            @Override
            public Criterion createCriterion(String property, Comparison operator, String argument,
                    Class<?> entityClass, String alias, CriteriaBuilder parent)
                    throws ArgumentFormatException, UnknownSelectorException {
                assertEquals("foo", property);
                assertEquals(operator, Comparison.EQUAL);
                assertEquals("bar", argument);
                assertEquals(Course.class, entityClass);
                assertEquals("this.", alias);
                assertNotNull(parent);

                throw new AssertionError("This should be thrown!");
            }

        });

        Expression expression = new ComparisonExpression("foo", Comparison.EQUAL, "bar");
        try {
            inner.convert(expression, DetachedCriteria.forClass(Course.class));
            fail("Method createCriterion() was not called!");
        } catch (AssertionError ex) {
            /*OK*/ }
    }

    /**
     * Test if composite expression is routed to Criterion Builder well.
     */
    @Test
    public void testInnerConvertDetached1() {
        instance.setMapper(mapper);
        instance.pushCriterionBuilder(new MockCriterionBuilder() {
            int call = 0;

            @Override
            public Criterion createCriterion(String property, Comparison operator, String argument,
                    Class<?> entityClass, String alias, CriteriaBuilder parent)
                    throws ArgumentFormatException, UnknownSelectorException {
                if (call == 0) {
                    assertEquals("sel0", property);
                    assertEquals(operator, Comparison.EQUAL);
                    assertEquals("foo", argument);
                } else if (call == 1) {
                    assertEquals("sel1", property);
                    assertEquals(operator, Comparison.NOT_EQUAL);
                    assertEquals("bar", argument);
                } else if (call == 2) {
                    assertEquals("sel2", property);
                    assertEquals(operator, Comparison.LESS_THAN);
                    assertEquals("baz", argument);

                    throw new AssertionError("This should be thrown!");
                }
                assertNotNull(parent);
                call++;
                return Restrictions.eq("null", "null");
            }
        });

        Expression expression = new LogicalExpression(
                new LogicalExpression(new ComparisonExpression("sel0", Comparison.EQUAL, "foo"), Logical.OR,
                        new ComparisonExpression("sel1", Comparison.NOT_EQUAL, "bar")),
                Logical.AND, new ComparisonExpression("sel2", Comparison.LESS_THAN, "baz"));

        try {
            inner.convert(expression, DetachedCriteria.forClass(Course.class));
            fail("Method createCriterion() was not called for third time!");
        } catch (AssertionError ex) {
            /*OK*/ }
    }

    /**
     * Finally test whole DetachedCriteria creation.
     */
    @Test
    public void testInnerConvertDetached2() {
        instance.pushCriterionBuilder(new MockCriterionBuilder());

        DetachedCriteria expResult = DetachedCriteria.forClass(Course.class, RSQL2CriteriaConverter.ROOT_ALIAS)
                .add(Restrictions.and(Restrictions.eq("foo", "flynn"),
                        Restrictions.or(Restrictions.eq("bar", 42), Restrictions.eq("baz", 42.2))));

        Expression expression = new LogicalExpression(new ComparisonExpression("foo", Comparison.EQUAL, "flynn"),
                Logical.AND, new LogicalExpression(new ComparisonExpression("bar", Comparison.EQUAL, "42"),
                        Logical.OR, new ComparisonExpression("baz", Comparison.EQUAL, "42.2")));

        DetachedCriteria result = DetachedCriteria.forClass(Course.class);
        inner.convert(expression, result);

        assertEquals(expResult.toString(), result.toString());
    }

    @Test
    public void testCreateCriteria2arg() {
        DetachedCriteria expResult;
        expResult = DetachedCriteria.forClass(Course.class, RSQL2CriteriaConverter.ROOT_ALIAS)
                .add(Restrictions.eq("foo", "bar"));

        DetachedCriteria result = instance.createCriteria("foo==bar", Course.class);
        assertEquals("Expression: foo==bar", expResult.toString(), result.toString());

        try {
            instance.createCriteria("invalid input ", Course.class);
            fail("Should raise RSQLException");
        } catch (RSQLException ex) {
            /* OK */ }
    }

    @Test
    public void testPushCriterionBuilder() {
        MockRSQL2CriteriaConverterImpl converter = new MockRSQL2CriteriaConverterImpl(sessionFactory);
        converter.setMapper(mapper);

        converter.pushCriterionBuilder(new MockCriterionBuilder() {
            @Override
            public Criterion createCriterion(String property, Comparison operator, String argument,
                    Class<?> entityClass, String alias, CriteriaBuilder parent)
                    throws ArgumentFormatException, UnknownSelectorException {
                fail("Should be at the bottom of builders stack");
                return null;
            }
        });

        converter.pushCriterionBuilder(new MockCriterionBuilder() {
            @Override
            public Criterion createCriterion(String property, Comparison operator, String argument,
                    Class<?> entityClass, String alias, CriteriaBuilder parent)
                    throws ArgumentFormatException, UnknownSelectorException {
                // ok
                return Restrictions.ne("foo", "notbar");
            }
        });

        converter.pushCriterionBuilder(new MockCriterionBuilder() {
            @Override
            public boolean accept(String selector, Class<?> entityClass, CriteriaBuilder parent) {
                return false;
            }

            @Override
            public Criterion createCriterion(String property, Comparison operator, String argument,
                    Class<?> entityClass, String alias, CriteriaBuilder parent)
                    throws ArgumentFormatException, UnknownSelectorException {
                fail("Should not be accepted");
                return null;
            }
        });

        Expression expression = new ComparisonExpression("foo", Comparison.EQUAL, "bar");

        DetachedCriteria expResult = DetachedCriteria.forClass(Course.class).add(Restrictions.ne("foo", "notbar"));

        DetachedCriteria result = DetachedCriteria.forClass(Course.class);
        converter.createInnerBuilder(Course.class).convert(expression, result);

        assertEquals(expResult.toString(), result.toString());
    }

    @Test
    public void testCreateAssociationAlias() {
        final String aliasPrefix = RSQL2CriteriaConverter.ALIAS_PREFIX;

        instance.setAssociationsLimit(3);

        instance.pushCriterionBuilder(new MockCriterionBuilder() {
            @Override
            public Criterion createCriterion(String property, Comparison operator, String argument,
                    Class<?> entityClass, String alias, CriteriaBuilder parent)
                    throws ArgumentFormatException, UnknownSelectorException {
                assertEquals(aliasPrefix + "1", parent.createAssociationAlias("foo", Criteria.INNER_JOIN));
                assertEquals(aliasPrefix + "2", parent.createAssociationAlias("bar", Criteria.LEFT_JOIN));
                assertEquals(aliasPrefix + "1", parent.createAssociationAlias("foo", Criteria.LEFT_JOIN));
                assertEquals(aliasPrefix + "3", parent.createAssociationAlias("baz", Criteria.FULL_JOIN));

                try {
                    parent.createAssociationAlias("qux");
                    fail("Should raise JoinsLimitException");
                } catch (AssociationsLimitException ex) {
                    /*OK*/ }

                throw new AssertionError("This should be thrown!");
            }
        });

        Criteria criteria = sessionFactory.openSession().createCriteria(Course.class);
        Expression expression = new ComparisonExpression("foo", Comparison.EQUAL, "bar");

        try {
            inner.convert(expression, criteria);
            fail("Method createCriterion() was not called!");
        } catch (AssertionError ex) {
            /*OK*/ }

        int i = 0;
        Iterator<Subcriteria> it = ((CriteriaImpl) criteria).iterateSubcriteria();
        while (it.hasNext()) {
            Subcriteria sub = it.next();
            switch (i) {
            case 0: {
                assertEquals("foo", sub.getPath());
                assertEquals("alias1", sub.getAlias());
                assertEquals(Criteria.INNER_JOIN, sub.getJoinType());
                break;
            }
            case 1: {
                assertEquals("bar", sub.getPath());
                assertEquals("alias2", sub.getAlias());
                assertEquals(Criteria.LEFT_JOIN, sub.getJoinType());
                break;
            }
            case 2: {
                assertEquals("baz", sub.getPath());
                assertEquals("alias3", sub.getAlias());
                assertEquals(Criteria.FULL_JOIN, sub.getJoinType());
                break;
            }
            default:
                fail("Should not be here!");
            }
            i++;
        }
        assertEquals("Should iterate over three subcriterias", 3, i);

    }

    @Test
    public void testLoadAssociationAliases() {
        Expression expression = new ComparisonExpression("foo", Comparison.EQUAL, "bar");

        instance.pushCriterionBuilder(new MockCriterionBuilder() {
            @Override
            public Criterion createCriterion(String property, Comparison operator, String argument,
                    Class<?> entityClass, String alias, CriteriaBuilder parent)
                    throws ArgumentFormatException, UnknownSelectorException {
                assertEquals("givenAlias1", parent.createAssociationAlias("foo"));
                assertEquals("givenAlias3", parent.createAssociationAlias("baz"));
                assertEquals("givenAlias2", parent.createAssociationAlias("bar"));

                throw new AssertionError("This should be thrown!");
            }
        });

        Criteria criteria1 = sessionFactory.openSession().createCriteria(Course.class)
                .createAlias("foo", "givenAlias1").createAlias("bar", "givenAlias2")
                .createAlias("baz", "givenAlias3");
        try {
            inner.convert(expression, criteria1);
            fail("Method createCriterion() was not called!");
        } catch (AssertionError ex) {
            /*OK*/ }

        Criteria criteria2 = sessionFactory.openSession().createCriteria(Course.class)
                .createCriteria("foo", "givenAlias1").createCriteria("bar", "givenAlias2")
                .createCriteria("baz", "givenAlias3");
        try {
            inner.convert(expression, criteria2);
            fail("Method createCriterion() was not called!");
        } catch (AssertionError ex) {
            /*OK*/ }
    }

    ////////////////////////// Mocks //////////////////////////

    private static class MockRSQL2CriteriaConverterImpl extends RSQL2CriteriaConverterImpl {

        public MockRSQL2CriteriaConverterImpl(SessionFactory sessionFactory) {
            super(sessionFactory);
        }

        public InnerBuilder createInnerBuilder(Class<?> entityClass) {
            return new InnerBuilder(entityClass);
        }

    }

    private static class MockCriterionBuilder extends AbstractCriterionBuilder {

        @Override
        public boolean accept(String property, Class<?> entityClass, CriteriaBuilder parent) {
            return true;
        }

        @Override
        public Criterion createCriterion(String property, Comparison operator, String argument,
                Class<?> entityClass, String alias, CriteriaBuilder parent)
                throws ArgumentFormatException, UnknownSelectorException {
            return Restrictions.eq(property, argument);
        }
    }

}