    @Test
    public void testPaginate() throws Exception {

        Object[][] objectDefinitions = new Object[][]{
                {"A", 22},
                {"B", 23},
                {"Z", 10},
                {"D", 12},
                {"E", 13},
                {"C", 42},
                {"Z", 11},
                {"E", 12},
                {"X", 35},
                {"X", 35}
        };

        List<Object> objectList = new ArrayList<>();
        for (Object[] objectDefinition : objectDefinitions) {
            objectList.add(new Object() {
                @Override
                public String toString() {
                    return (String) objectDefinition[0];
                }

                @Override
                public int hashCode() {
                    return (int) objectDefinition[1];
                }
            });
        }

        class TestCase {
            private final String filter;
            private final String sort;
            private final int page;
            private final int perPage;
            private final int total;
            private final Integer[] expectedOrder;

            private TestCase(String filter, String sort, int page, int perPage, int total, Integer[] expectedOrder) {
                this.filter = filter;
                this.sort = sort;
                this.page = page;
                this.perPage = perPage;
                this.total = total;
                this.expectedOrder = expectedOrder;
            }

            public String toString() {
                return "TestCase(" + filter + ", " + sort + ", " + page + ", " + perPage + ", " + total + ")";
            }
        }

        List<TestCase> testCaseList = new ArrayList<>();
        testCaseList.add(new TestCase("", "", 1, 2, 10, new Integer[]{0, 1}));
        testCaseList.add(new TestCase("", "", 2, 2, 10, new Integer[]{2, 3}));
        testCaseList.add(new TestCase("", "", 5, 2, 10, new Integer[]{8, 9}));
        testCaseList.add(new TestCase("", "", 0, -1, 10, new Integer[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}));
        testCaseList.add(new TestCase("", "", 5, 5, 10, new Integer[]{}));
        testCaseList.add(new TestCase("X", "", 1, 2, 2, new Integer[]{8, 9}));
        testCaseList.add(new TestCase("1,string=E", "", 1, 2, 2, new Integer[]{4, 7}));
        testCaseList.add(new TestCase("E,hash=3", "", 1, 2, 1, new Integer[]{4}));
        testCaseList.add(new TestCase("", "string", 1, 5, 10, new Integer[]{0, 1, 5, 3, 4}));
        testCaseList.add(new TestCase("", "-hash", 1, 5, 10, new Integer[]{5, 8, 9, 1, 0}));
        testCaseList.add(new TestCase("E", "hash", 1, 5, 2, new Integer[]{7, 4}));
        testCaseList.add(new TestCase("E", "hash", 1, 1, 2, new Integer[]{7}));
        testCaseList.add(new TestCase("E", "hash", 2, 1, 2, new Integer[]{4}));
        testCaseList.add(new TestCase("1", "string,-hash", 2, 3, 5, new Integer[]{6, 2}));

        PaginationHelper<Object> paginationHelper = new PaginationHelper<>(
                new PaginationFilterTest.TestObjectFilter(),
                new PaginationComparatorTest.TestObjectComparator());

        for (TestCase testCase : testCaseList) {
            List<Object> copyList = new ArrayList<>(objectList.size());
            copyList.addAll(objectList);

            Map<String, Object> result = paginationHelper.paginate("objects", copyList,
                    testCase.filter, "+0000", testCase.sort, testCase.page,
                    testCase.perPage);

            @SuppressWarnings("unchecked")
            Integer[] actualOrder = ((List<Object>) result.get("objects")).stream()
                    .map(objectList::indexOf)
                    .collect(Collectors.toList())
                    .toArray(new Integer[]{});

            Assert.assertArrayEquals("TestCase failed (order): " + testCase,
                    testCase.expectedOrder,
                    actualOrder);

            Assert.assertEquals("TestCase failed (number): " + testCase,
                    testCase.total,
                    result.get("totalEntries"));
        }
    }