
/*********************************************************************
 * E.S.O. - VLT project
 *
 * "@(#) $Id: kmclipm_test_math.c,v 1.9 2013-10-08 11:12:02 aagudo Exp $"
 *
 * Tests for functions in src/kmclipm_priv_functions.c/.h
 *
 * who       when        what
 * --------  ----------  ----------------------------------------------
 * aagudo     2008-06-12  created
 */

/**
    @defgroup kmclipm_test_math Unit tests for the math functions in kmclipm_math

    Unit test for the functions in the module @ref kmclipm_math

    @{
*/

/*------------------------------------------------------------------------------
 *              Includes
 *----------------------------------------------------------------------------*/
#include <float.h>
#include <math.h>
#include <sys/stat.h>

#include "kmclipm_math.h"
#include "kmclipm_priv_error.h"
#include "kmclipm_constants.h"
#include "kmclipm_priv_constants.h"

cpl_msg_severity my_level= CPL_MSG_WARNING;

/*------------------------------------------------------------------------------
 *              Implementation
 *----------------------------------------------------------------------------*/

void test_kmclipm_median_min()
{
    cpl_image   *img        = NULL;
    double      ret_val     = 0.0,
                *dbl        = NULL,
                tol         = 0.01;
    float       *img_data   = NULL;
    int         i           = 0;

    /* ----- test with correct values ----- */
    /* empty 3x3 image */
    img = cpl_image_new(MEDIAN_WINDOW_SIZE, MEDIAN_WINDOW_SIZE,
                        CPL_TYPE_FLOAT);
    img_data = cpl_image_get_data_float(img);
    for (i = 0; i < MEDIAN_WINDOW_SIZE * MEDIAN_WINDOW_SIZE; i++) {
        /* initialise to zero */
        img_data[i] = 0.0;
    }
    cpl_test_abs(0.0, kmclipm_median_min(img, NULL, NULL), tol);

    /* non-empty 3x3 image */
    for (i = 0; i < MEDIAN_WINDOW_SIZE * MEDIAN_WINDOW_SIZE; i++) {
        /* initialise to some value */
        img_data[i] = i * 0.1;
    }
    cpl_test_abs(0.4, kmclipm_median_min(img, NULL, NULL), 1e-6);
    cpl_image_delete(img);

    /* non-empty 14x14 image */
    img = cpl_image_new(KMOS_SLITLET_X, KMOS_SLITLET_Y,
                        CPL_TYPE_FLOAT);
    img_data = cpl_image_get_data_float(img);
    for (i = 0; i < KMOS_SLITLET_X * KMOS_SLITLET_Y; i++) {
        /* initialise to zero */
        img_data[i] = i * 123.98348;
    }
    cpl_test_abs(1859.75, kmclipm_median_min(img, NULL, NULL), tol);

    cpl_image_delete(img);

    /* ----- test with wrong values ----- */
    /* NULL pointer */
    ret_val = kmclipm_median_min(NULL, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    /* casted pointer to double */
    dbl = cpl_malloc(sizeof(double));
    *dbl = 5.5;
    ret_val = kmclipm_median_min((cpl_image*)dbl, NULL, NULL);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cpl_free(dbl);

    /* empty 1x1 image */
    img = cpl_image_new(1, 1, CPL_TYPE_FLOAT);
    cpl_image_set(img, 1, 1, 0.0);

    ret_val = kmclipm_median_min(img, NULL, NULL);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cpl_image_delete(img);

    cpl_test_error(CPL_ERROR_NONE);

    tol = ret_val; /* against warnings [-Wunused-but-set-variable] */
}


void test_kmclipm_median_max()
{
    cpl_image   *img        = NULL;
    double      ret_val     = 0.0,
                *dbl        = NULL,
                tol         = 0.01;
    float       *img_data   = NULL;
    int         i           = 0;

    /* ----- test with correct values ----- */
    /* empty 3x3 image */
    img = cpl_image_new(MEDIAN_WINDOW_SIZE, MEDIAN_WINDOW_SIZE, CPL_TYPE_FLOAT);
    img_data = cpl_image_get_data_float(img);
    for (i = 0; i < MEDIAN_WINDOW_SIZE * MEDIAN_WINDOW_SIZE; i++) {
        /* initialise to zero */
        img_data[i] = 0.0;
    }
    cpl_test_abs(0.0, kmclipm_median_max(img, NULL, NULL), tol);

    /* non-empty 3x3 image */
    for (i = 0; i < MEDIAN_WINDOW_SIZE * MEDIAN_WINDOW_SIZE; i++) {
        /* initialise to some value */
        img_data[i] = i * 0.1;
    }
    cpl_test_abs(0.4, kmclipm_median_max(img, NULL, NULL), 1e-6);
    cpl_image_delete(img);

    /* non-empty 14x14 image */
    img = cpl_image_new(KMOS_SLITLET_X, KMOS_SLITLET_Y, CPL_TYPE_FLOAT);
    img_data = cpl_image_get_data_float(img);
    for (i = 0; i < KMOS_SLITLET_X * KMOS_SLITLET_Y; i++) {
        /* initialise to zero */
        img_data[i] = i * 123.98348;
    }
    cpl_test_abs(22317, kmclipm_median_max(img, NULL, NULL), tol*3);
    cpl_image_delete(img);

    /* ----- test with wrong values ----- */
    /* NULL pointer */
    ret_val = kmclipm_median_max(NULL, NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    /* casted pointer to double */
    dbl = cpl_malloc(sizeof(double));
    *dbl = 5.5;
    ret_val = kmclipm_median_max((cpl_image*)dbl, NULL, NULL);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cpl_free(dbl);

    /* empty 1x1 image */
    img = cpl_image_new(1, 1, CPL_TYPE_FLOAT);
    cpl_image_set(img, 1, 1, 0.0);
    ret_val = kmclipm_median_max(img, NULL, NULL);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cpl_image_delete(img);

    cpl_test_error(CPL_ERROR_NONE);

    tol = ret_val; /* against warnings [-Wunused-but-set-variable] */
}

void test_kmclipm_is_nan_or_inf()
{
    cpl_test_eq(FALSE, kmclipm_is_nan_or_inf(5.0));
    cpl_test_eq(TRUE, kmclipm_is_nan_or_inf(0.0/0.0));
    cpl_test_eq(TRUE, kmclipm_is_nan_or_inf(1.0/0.0));
    cpl_test_eq(TRUE, kmclipm_is_nan_or_inf(-1.0/0.0));

    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_is_inf()
{
    cpl_test_eq(0, kmclipm_is_inf(5.0));
    cpl_test_eq(0, kmclipm_is_inf(0.0/0.0));
    cpl_test_eq(1, kmclipm_is_inf(1.0/0.0));
    cpl_test_eq(-1, kmclipm_is_inf(-1.0/0.0));

    cpl_test_error(CPL_ERROR_NONE);
}

/**
    @brief  Executes the unit tests for all functions in the module @ref kmclipm_math

    @return Error code, 0 for NONE.
 */
int main()
{
    /* For DEVELOPERS:
     * to omit all CPL_MSG_INFO output, apply following statement in the shell
     * before executing "make check":
     *      setenv CPL_MSG_LEVEL warning
     *  (or export CPL_MSG_LEVEL=warning)
     */

    cpl_test_init("<usd-help@eso.org>", my_level);

    char *my_path = cpl_sprintf("%s/test_data", ".");
    mkdir(my_path, 0777);
    cpl_free(my_path);

    cpl_msg_set_level_from_env();
    my_level = cpl_msg_get_level();

    test_kmclipm_median_min();
    test_kmclipm_median_max();
    test_kmclipm_is_nan_or_inf();
    test_kmclipm_is_inf();

    cpl_msg_info("","All tests done.");
    cpl_msg_set_level(CPL_MSG_WARNING);
    return cpl_test_end(0);
}

/** @} */
