package com.mmnaseri.cs.clrs.common;

import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.util.Arrays;
import java.util.Comparator;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.collection.IsArrayContainingInOrder.arrayContaining;
import static org.hamcrest.collection.IsArrayWithSize.arrayWithSize;
import static org.hamcrest.collection.IsArrayWithSize.emptyArray;

/**
 * @author Mohammad Milad Naseri (m.m.naseri@gmail.com)
 * @since 1.0 (7/9/15, 8:53 PM)
 */
public abstract class BaseSortTest {
    
    protected abstract Sorter<Integer> getAscendingSorter();

    protected static final Comparator<Integer> NATURAL_COMPARATOR = new Comparator<Integer>() {
        @Override
        public int compare(Integer first, Integer second) {
            return first.compareTo(second);
        }
    };

    @Test
    public void testSortingEmptyArray() throws Exception {
        final Integer[] items = {};
        getAscendingSorter().sort(items);
        assertThat(items, emptyArray());
    }

    @Test
    public void testSimpleAscendingSortWithNegativeItems() throws Exception {
        final Integer[] items = {-7, -9, -8, 7, 9, 8, 0};
        final int length = items.length;
        getAscendingSorter().sort(items);
        assertThat(items, arrayWithSize(length));
        assertThat(items, arrayContaining(-9, -8, -7, 0, 7, 8, 9));
    }

    @Test
    public void testAscendingSortWithInfinity() throws Exception {
        final Integer[] items = {1, 2, 3, Integer.MIN_VALUE, 0, Integer.MAX_VALUE, 4, 5, 6};
        final int length = items.length;
        getAscendingSorter().sort(items);
        assertThat(items, arrayWithSize(length));
        assertThat(items, arrayContaining(Integer.MIN_VALUE, 0, 1, 2, 3, 4, 5, 6, Integer.MAX_VALUE));
    }

    @DataProvider
    public Object[][] normalDataProvider() {
        return new Object[][]{
                new Object[]{new Integer[]{10}}, //testSortingSingleItemList
                new Object[]{new Integer[]{1, 9, 3, 7, 3, 0}}, //testSimpleAscendingSort
                new Object[]{new Integer[]{8, 8, 8, 7, 7, 7, 6, 6, 6}}, //testWithDuplicates
                new Object[]{new Integer[]{1, 2, 3, 4, 5, 6}}, //testSortingAlreadySortedArray
                new Object[]{new Integer[]{6, 5, 4, 3, 2, 1}}, //testSortingReversedArray
        };
    }

    @Test(dataProvider = "normalDataProvider")
    public void testSortIntegrity(Integer[] items) throws Exception {
        final Integer[] target = new Integer[items.length];
        final Integer[] expected = new Integer[items.length];
        System.arraycopy(items, 0, target, 0, target.length);
        System.arraycopy(items, 0, expected, 0, expected.length);
        Arrays.sort(expected);
        getAscendingSorter().sort(target);
        assertThat(target, arrayWithSize(expected.length));
        assertThat(target, arrayContaining(expected));
    }

}

@@ -165,16 +165,41 @@
 parator;
+%0Aimport java.util.Random;
 %0A%0Aimport
@@ -459,16 +459,55 @@
 tyArray;
+%0Aimport static org.hamcrest.core.Is.is;
 %0A%0A/**%0A *
@@ -3017,10 +3017,607 @@
 %0A    %7D%0A%0A
+    @Test%0A    public void testSortingLargeCollection() %7B%0A        final Sorter%3CInteger%3E sorter = getAscendingSorter();%0A        final int length = 1000;%0A        final Integer%5B%5D original = new Integer%5Blength%5D;%0A        final Integer%5B%5D expected = new Integer%5Blength%5D;%0A        final Random random = new Random();%0A        for (int i = 0; i %3C original.length; i++) %7B%0A            original%5Bi%5D = random.nextInt(10);%0A        %7D%0A        System.arraycopy(original, 0, expected, 0, original.length);%0A        Arrays.sort(expected);%0A        sorter.sort(original);%0A        assertThat(original, is(expected));%0A    %7D%0A%0A
 %7D%0A

test (clrs.common): add base test case for large collections