/*
 * Copyright 2011 Steven Gribble
 *
 *  This file is part of the UW CSE 333 course project sequence
 *  (333proj).
 *
 *  333proj is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  333proj is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with 333proj.  If not, see <http://www.gnu.org/licenses/>.
 */

// Lecture 10 exercise 1

#include <stdio.h>
#include <stdint.h>

#include "sort.h"
#include "CUnit/Basic.h"

// This declares comparator function we pass in to
// our sort routines.
int IntComparator(void *el1, void *el2);

// Our test suite initializer and cleanup functions.
int SSInit(void);
int SSCleanup(void);

// Bubblesort unit tests.
void SSBubbleSortSimple(void);
void SSBubbleSortDegenerate(void);

// Quicksort unit tests.
void SSQuickSortSimple(void);
void SSQuickSortDegenerate(void);

int main(int argc, char **argv) {
  CU_pSuite pSuite = NULL;

  // Initialize the unit test registry.
  if (CU_initialize_registry() != CUE_SUCCESS) {
    return CU_get_error();
  }

  // Add our test suite to the registry.
  pSuite = CU_add_suite("sort suite", &SSInit, &SSCleanup);
  if (pSuite == NULL) {
    CU_cleanup_registry();
    return CU_get_error();
  }

  // Add the unit tests to the suite.
  if ((CU_ADD_TEST(pSuite, SSBubbleSortSimple) == NULL) ||
      (CU_ADD_TEST(pSuite, SSBubbleSortDegenerate) == NULL) ||
      (CU_ADD_TEST(pSuite, SSQuickSortSimple) == NULL) ||
      (CU_ADD_TEST(pSuite, SSQuickSortDegenerate) == NULL)) {
    CU_cleanup_registry();
    return CU_get_error();
  }

  // Run all of the unit tests, using the CUnit "basic" interface.
  CU_basic_set_mode(CU_BRM_VERBOSE);
  CU_basic_run_tests();
  CU_cleanup_registry();
  return CU_get_error();
}

int IntComparator(void *el1, void *el2) {
  int *i1 = (int *) el1;
  int *i2 = (int *) el2;

  if (*i1 > *i2)
    return 1;
  if (*i1 == *i2)
    return 0;
  return -1;
}

int SSInit(void) {
  // return 0 on success, non-zero otherwise
  return 0;
}
int SSCleanup(void) {
  // return 0 on success, non-zero otherwise
  return 0;
}

// Test various in-order and out-of-order sorting cases.  Also test
// the case where many elements are equal.
void SSBubbleSortSimple(void) {
  int i;
  int v[10] = {6, 5, 5, 5, 5, 5, 5, 5, 5, 5};
  int w[10] = {5, 4, 3, 2, 1, 1, 2, 3, 4, 5};
  int x[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  int y[10] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
  int z[10] = {1, 2, 3, 4, 5, 5, 4, 3, 2, 1};

  BubbleSort(v, 10, sizeof(int), &IntComparator);
  BubbleSort(w, 10, sizeof(int), &IntComparator);
  BubbleSort(x, 10, sizeof(int), &IntComparator);
  BubbleSort(y, 10, sizeof(int), &IntComparator);
  BubbleSort(z, 10, sizeof(int), &IntComparator);

  for (i = 0; i < 10; i++) {
    CU_ASSERT_EQUAL(v[i], i == 9 ? 6 : 5);
    CU_ASSERT_EQUAL(w[i], (i/2)+1);
    CU_ASSERT_EQUAL(x[i], i+1);
    CU_ASSERT_EQUAL(y[i], i+1);
    CU_ASSERT_EQUAL(z[i], (i/2)+1);
  }
}

// Test some degenerate edge cases.
void SSBubbleSortDegenerate(void) {
  int v[1] = {1};
  int w[2] = {2, 1};
  int x[2] = {1, 2};
  int *y = NULL;

  BubbleSort(v, 1, sizeof(int), &IntComparator);
  BubbleSort(w, 2, sizeof(int), &IntComparator);
  BubbleSort(x, 2, sizeof(int), &IntComparator);
  BubbleSort(y, 0, sizeof(int), &IntComparator);

  CU_ASSERT_EQUAL(v[0], 1);
  CU_ASSERT_EQUAL(w[0], 1);
  CU_ASSERT_EQUAL(w[1], 2);
  CU_ASSERT_EQUAL(x[0], 1);
  CU_ASSERT_EQUAL(x[1], 2);
}


// Test various in-order and out-of-order sorting cases.  Also test
// the case where many elements are equal.
void SSQuickSortSimple(void) {
  int i;
  int v[10] = {6, 5, 5, 5, 5, 5, 5, 5, 5, 5};
  int w[10] = {5, 4, 3, 2, 1, 1, 2, 3, 4, 5};
  int x[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  int y[10] = {10, 9, 8, 7, 6, 5, 4, 3, 2, 1};
  int z[10] = {1, 2, 3, 4, 5, 5, 4, 3, 2, 1};

  QuickSort(v, 10, sizeof(int), &IntComparator);
  QuickSort(w, 10, sizeof(int), &IntComparator);
  QuickSort(x, 10, sizeof(int), &IntComparator);
  QuickSort(y, 10, sizeof(int), &IntComparator);
  QuickSort(z, 10, sizeof(int), &IntComparator);

  for (i = 0; i < 10; i++) {
    CU_ASSERT_EQUAL(v[i], i == 9 ? 6 : 5);
    CU_ASSERT_EQUAL(w[i], (i/2)+1);
    CU_ASSERT_EQUAL(x[i], i+1);
    CU_ASSERT_EQUAL(y[i], i+1);
    CU_ASSERT_EQUAL(z[i], (i/2)+1);
  }
}

// Test some degenerate edge cases.
void SSQuickSortDegenerate(void) {
  int v[1] = {1};
  int w[2] = {2, 1};
  int x[2] = {1, 2};
  int *y = NULL;

  QuickSort(v, 1, sizeof(int), &IntComparator);
  QuickSort(w, 2, sizeof(int), &IntComparator);
  QuickSort(x, 2, sizeof(int), &IntComparator);
  QuickSort(y, 0, sizeof(int), &IntComparator);

  CU_ASSERT_EQUAL(v[0], 1);
  CU_ASSERT_EQUAL(w[0], 1);
  CU_ASSERT_EQUAL(w[1], 2);
  CU_ASSERT_EQUAL(x[0], 1);
  CU_ASSERT_EQUAL(x[1], 2);
}