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

/**
    @defgroup kmclipm_test_functions Unit tests for the functions in kmclipm_vector

    Unit test for the functions in the module @ref kmclipm_vector

    @{
*/

/*------------------------------------------------------------------------------
 *              Includes
 *----------------------------------------------------------------------------*/
#define _ISOC99_SOURCE

#include <math.h>
#include <sys/stat.h>

#include "kmclipm_vector.h"
#include "kmclipm_math.h"

cpl_msg_severity my_level= CPL_MSG_WARNING;

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

void test_kmclipm_vector_new()
{
    cpl_test_null(kmclipm_vector_new(0));
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_new(5));
    cpl_test_eq(5, cpl_vector_get_size(kv->data));
    cpl_test_eq(5, cpl_vector_get_size(kv->mask));
    cpl_test_eq(0, cpl_vector_get_mean(kv->data));
    cpl_test_eq(1, cpl_vector_get_mean(kv->mask));

    kmclipm_vector_delete(kv);
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_create()
{
    cpl_test_null(kmclipm_vector_create(NULL));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_fill(v, 2);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));
    cpl_test_eq(5, cpl_vector_get_size(kv->data));
    cpl_test_eq(5, cpl_vector_get_size(kv->mask));
    cpl_test_eq(2, cpl_vector_get_mean(kv->data));
    cpl_test_eq(1, cpl_vector_get_mean(kv->mask));
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    cpl_test_nonnull(kv = kmclipm_vector_create(v));
    cpl_test_eq(5, cpl_vector_get_size(kv->data));
    cpl_test_eq(5, cpl_vector_get_size(kv->mask));
    cpl_test_eq(1, isnan(cpl_vector_get_mean(kv->data)));
    cpl_test_abs(4./5., cpl_vector_get_mean(kv->mask), 0.01);
    kmclipm_vector_delete(kv);
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    cpl_test_nonnull(kv = kmclipm_vector_create(v));
    cpl_test_eq(5, cpl_vector_get_size(kv->data));
    cpl_test_eq(5, cpl_vector_get_size(kv->mask));
    cpl_test_eq(1, isnan(cpl_vector_get_mean(kv->data)));
    cpl_test_abs(0., cpl_vector_get_mean(kv->mask), 0.01);
    kmclipm_vector_delete(kv);
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_create2()
{
    cpl_test_null(kmclipm_vector_create2(NULL, NULL));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *d = cpl_vector_new(5);
    cpl_vector_set(d, 0, 1);
    cpl_vector_set(d, 1, 2);
    cpl_vector_set(d, 2, 3);
    cpl_vector_set(d, 3, 4);
    cpl_vector_set(d, 4, 5);
    cpl_test_null(kmclipm_vector_create2(d, NULL));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *m = cpl_vector_new(2);
    cpl_test_null(kmclipm_vector_create2(d, m));
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cpl_vector_delete(m);

    m = cpl_vector_new(5);
    cpl_vector_set(m, 0, 0);
    cpl_vector_set(m, 1, 1);
    cpl_vector_set(m, 2, 5);
    cpl_vector_set(m, 3, -7);
    cpl_vector_set(m, 4, 1);

    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create2(d, m));
    cpl_test_eq(5, cpl_vector_get_size(kv->data));
    cpl_test_eq(5, cpl_vector_get_size(kv->mask));
    cpl_test_abs(3.333, kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_abs(3./5., cpl_vector_get_mean(kv->mask), 0.01);

    kmclipm_vector_delete(kv);
    cpl_test_error(CPL_ERROR_NONE);

    d = cpl_vector_new(5);
    cpl_vector_set(d, 0, 1);
    cpl_vector_set(d, 1, NAN);
    cpl_vector_set(d, 2, 3);
    cpl_vector_set(d, 3, 4);
    cpl_vector_set(d, 4, 5);
    m = cpl_vector_new(5);
    cpl_vector_set(m, 0, 0);
    cpl_vector_set(m, 1, 1);
    cpl_vector_set(m, 2, NAN);
    cpl_vector_set(m, 3, -7);
    cpl_vector_set(m, 4, 1);

    cpl_test_nonnull(kv = kmclipm_vector_create2(d, m));
    cpl_test_eq(5, cpl_vector_get_size(kv->data));
    cpl_test_eq(5, cpl_vector_get_size(kv->mask));
    cpl_test_eq(5, kmclipm_vector_get_mean(kv));
    cpl_test_abs(1./5., cpl_vector_get_mean(kv->mask), 0.01);
    cpl_test_abs(3, cpl_vector_get(kv->data,2), 0.01);
    cpl_test_eq(0, cpl_vector_get(kv->mask,2));
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_delete(kv);
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_delete()
{
    kmclipm_vector_delete(NULL);
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector *kv = kmclipm_vector_new(5);
    kmclipm_vector_delete(kv);
    cpl_test_error(CPL_ERROR_NONE);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));
    kmclipm_vector_delete(kv);
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_duplicate()
{
    cpl_test_null(kmclipm_vector_duplicate(NULL));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL, *kv2 = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_nonnull(kv2 = kmclipm_vector_duplicate(kv));
    cpl_test_abs(3, kmclipm_vector_get_mean(kv2), 0.01);
    cpl_test_abs(4./5., cpl_vector_get_mean(kv2->mask), 0.01);
    kmclipm_vector_delete(kv); kv = NULL;
    kmclipm_vector_delete(kv2); kv2 = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_nonnull(kv2 = kmclipm_vector_duplicate(kv));
    cpl_test_abs(0, kmclipm_vector_get_mean(kv2), 0.01);
    cpl_test_abs(0., cpl_vector_get_mean(kv2->mask), 0.01);
    kmclipm_vector_delete(kv); kv = NULL;
    kmclipm_vector_delete(kv2); kv2 = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_set()
{
    kmclipm_vector_set(NULL, -1, 0);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    kmclipm_vector_set(kv, -1, 0);
    cpl_test_error(CPL_ERROR_ACCESS_OUT_OF_RANGE);

    kmclipm_vector_set(kv, 0, 0);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(11./4., kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_abs(4./5., cpl_vector_get_mean(kv->mask), 0.01);

    kmclipm_vector_set(kv, 0, 1./0.);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(11./3., kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_abs(3./5., cpl_vector_get_mean(kv->mask), 0.01);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    kmclipm_vector_set(kv, 0, 1);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(1., kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_abs(1./5., cpl_vector_get_mean(kv->mask), 0.01);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_get()
{
    cpl_test_abs(0, kmclipm_vector_get(NULL, -1, NULL), 0.01);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_abs(0, kmclipm_vector_get(kv, -1, NULL), 0.01);
    cpl_test_error(CPL_ERROR_ACCESS_OUT_OF_RANGE);

    cpl_test_abs(1, kmclipm_vector_get(kv, 0, NULL), 0.01);
    cpl_test_error(CPL_ERROR_NONE);
    int rej = 0;
    cpl_test_abs(2, kmclipm_vector_get(kv, 1, &rej), 0.01);
    cpl_test_eq(0, rej);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_eq(1, isnan(kmclipm_vector_get(kv, 2, &rej)));
    cpl_test_eq(1, rej);
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_eq(1, isnan(kmclipm_vector_get(kv, 0, NULL)));
    cpl_test_error(CPL_ERROR_NONE);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_get_mask()
{
    cpl_test_null(kmclipm_vector_get_mask(NULL));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_vector *mask = NULL;
    cpl_test_nonnull(mask = kmclipm_vector_get_mask(kv));
    cpl_test_abs(4./5., cpl_vector_get_mean(mask), 0.01);
    cpl_test_error(CPL_ERROR_NONE);

    cpl_vector_delete(mask); mask = NULL;
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_nonnull(mask = kmclipm_vector_get_mask(kv));
    cpl_test_abs(0., cpl_vector_get_mean(mask), 0.01);
    cpl_test_error(CPL_ERROR_NONE);

    cpl_vector_delete(mask); mask = NULL;
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_get_bpm()
{
    cpl_test_null(kmclipm_vector_get_bpm(NULL));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_vector *mask = NULL;
    cpl_test_nonnull(mask = kmclipm_vector_get_bpm(kv));
    cpl_test_abs(4./5., cpl_vector_get_mean(mask), 0.01);
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_nonnull(mask = kmclipm_vector_get_bpm(kv));
    cpl_test_abs(0., cpl_vector_get_mean(mask), 0.01);
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_reject_from_mask() {
    kmclipm_vector_reject_from_mask(NULL, NULL, -1);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    kmclipm_vector_reject_from_mask(kv, NULL, -1);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *mask = cpl_vector_new(4);
    kmclipm_vector_reject_from_mask(kv, mask, -1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cpl_vector_delete(mask); mask = NULL;

    mask = cpl_vector_new(5);
    cpl_vector_set(mask, 0, 1);
    cpl_vector_set(mask, 1, 0);
    cpl_vector_set(mask, 2, 1);
    cpl_vector_set(mask, 3, 1);
    cpl_vector_set(mask, 4, 1);

    kmclipm_vector_reject_from_mask(kv, mask, -1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

    kmclipm_vector_reject_from_mask(kv, mask, TRUE);
    cpl_test_abs(10./3., kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_error(CPL_ERROR_NONE);

    cpl_vector_set(mask, 0, 1);
    cpl_vector_set(mask, 1, 1);
    cpl_vector_set(mask, 2, 0);
    cpl_vector_set(mask, 3, 0);
    cpl_vector_set(mask, 4, 1);

    kmclipm_vector_reject_from_mask(kv, mask, FALSE);
    cpl_test_abs(8./3., kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_error(CPL_ERROR_NONE);

    cpl_vector_delete(mask); mask = NULL;
    kmclipm_vector_delete(kv); kv = NULL;
}

void test_kmclipm_vector_count_rejected()
{
    cpl_test_eq(-1, kmclipm_vector_count_rejected(NULL));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));
    cpl_test_eq(1, kmclipm_vector_count_rejected(kv));
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));
    cpl_test_eq(5, kmclipm_vector_count_rejected(kv));
    cpl_test_error(CPL_ERROR_NONE);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_count_non_rejected()
{
    cpl_test_eq(-1, kmclipm_vector_count_non_rejected(NULL));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));
    cpl_test_eq(4, kmclipm_vector_count_non_rejected(kv));
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));
    cpl_test_eq(0, kmclipm_vector_count_non_rejected(kv));
    cpl_test_error(CPL_ERROR_NONE);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_adapt_rejected()
{
    kmclipm_vector_adapt_rejected(NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv1 = NULL, *kv2 = NULL;
    cpl_test_nonnull(kv1 = kmclipm_vector_create(v));

    kmclipm_vector_adapt_rejected(kv1, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v2 = cpl_vector_new(1);
    cpl_vector_set(v2, 0, 1);
    cpl_test_nonnull(kv2 = kmclipm_vector_create(v2));

    kmclipm_vector_adapt_rejected(kv1, kv2);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmclipm_vector_delete(kv2); kv2 = NULL;

    v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, NAN);
    cpl_vector_set(v, 2, 3);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    cpl_test_nonnull(kv2 = kmclipm_vector_create(v));

    cpl_test_abs(12, kmclipm_vector_get_sum(kv1), 0.01);
    cpl_test_abs(13, kmclipm_vector_get_sum(kv2), 0.01);
    kmclipm_vector_adapt_rejected(kv1, kv2);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(10, kmclipm_vector_get_sum(kv1), 0.01);
    cpl_test_abs(10, kmclipm_vector_get_sum(kv2), 0.01);

    kmclipm_vector_delete(kv1); kv1 = NULL;
    kmclipm_vector_delete(kv2); kv2 = NULL;
}

void test_kmclipm_vector_is_rejected()
{
    cpl_test_eq(-1, kmclipm_vector_is_rejected(NULL, -1));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_eq(-1, kmclipm_vector_is_rejected(kv, -1));
    cpl_test_error(CPL_ERROR_ACCESS_OUT_OF_RANGE);
    cpl_test_eq(-1, kmclipm_vector_is_rejected(kv, 5));
    cpl_test_error(CPL_ERROR_ACCESS_OUT_OF_RANGE);

    cpl_test_eq(0, kmclipm_vector_is_rejected(kv, 1));
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_eq(1, kmclipm_vector_is_rejected(kv, 2));
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));
    cpl_test_eq(1, kmclipm_vector_is_rejected(kv, 1));
    cpl_test_error(CPL_ERROR_NONE);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_reject()
{
    kmclipm_vector_reject(NULL, -1);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    kmclipm_vector_reject(kv, -1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmclipm_vector_reject(kv, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

    cpl_test_eq(2, cpl_vector_get(kv->data, 1));
    cpl_test_eq(1, cpl_vector_get(kv->mask, 1));
    kmclipm_vector_reject(kv, 1);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_eq(2, cpl_vector_get(kv->data, 1));
    cpl_test_eq(0, cpl_vector_get(kv->mask, 1));

    cpl_test_eq(5, cpl_vector_get_size(kv->data));
    cpl_test_eq(5, cpl_vector_get_size(kv->mask));
    cpl_test_eq(3, kmclipm_vector_get_mean(kv));
    cpl_test_abs(3./5., cpl_vector_get_mean(kv->mask), 0.01);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));
    kmclipm_vector_reject(kv, 1);
    cpl_test_error(CPL_ERROR_NONE);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_extract()
{
    kmclipm_vector *kv_out = NULL;
    cpl_test_null(kmclipm_vector_extract(NULL, 5, -1));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_null(kmclipm_vector_extract(kv, 5, -1));
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

    cpl_test_nonnull(kv_out = kmclipm_vector_extract(kv, 1, 3));
    cpl_test_eq(3, kmclipm_vector_get_mean(kv_out));
    cpl_test_eq(3, kmclipm_vector_get_size(kv_out));
    kmclipm_vector_delete(kv); kv = NULL;
    kmclipm_vector_delete(kv_out); kv_out = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_nonnull(kv_out = kmclipm_vector_extract(kv, 1, 3));
    cpl_test_eq(0, kmclipm_vector_get_mean(kv_out));
    cpl_test_eq(3, kmclipm_vector_get_size(kv_out));
    kmclipm_vector_delete(kv); kv = NULL;
    kmclipm_vector_delete(kv_out); kv_out = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_create_non_rejected()
{
    cpl_test_null(kmclipm_vector_create_non_rejected(NULL));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_vector *out = NULL;
    cpl_test_nonnull(out = kmclipm_vector_create_non_rejected(kv));
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_eq(4, cpl_vector_get_size(out));
    cpl_test_abs(3, cpl_vector_get_mean(out), 0.01);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_vector_delete(out);
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));
    cpl_test_null(out = kmclipm_vector_create_non_rejected(kv));
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_add()
{
    kmclipm_vector_add(NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv1 = NULL, *kv2 = NULL;
    cpl_test_nonnull(kv1 = kmclipm_vector_create(v));

    kmclipm_vector_add(kv1, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v2 = cpl_vector_new(1);
    cpl_vector_set(v2, 0, 1);
    cpl_test_nonnull(kv2 = kmclipm_vector_create(v2));

    kmclipm_vector_add(kv1, kv2);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmclipm_vector_delete(kv2); kv2 = NULL;

    v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, NAN);
    cpl_vector_set(v, 2, 3);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    cpl_test_nonnull(kv2 = kmclipm_vector_create(v));

    cpl_test_abs(12, kmclipm_vector_get_sum(kv1), 0.01);
    cpl_test_abs(13, kmclipm_vector_get_sum(kv2), 0.01);
    kmclipm_vector_add(kv1, kv2);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(20, kmclipm_vector_get_sum(kv1), 0.01);
    cpl_test_abs(13, kmclipm_vector_get_sum(kv2), 0.01);

    kmclipm_vector_delete(kv1); kv1 = NULL;
    kmclipm_vector_delete(kv2); kv2 = NULL;
}

void test_kmclipm_vector_subtract()
{
    kmclipm_vector_subtract(NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv1 = NULL, *kv2 = NULL;
    cpl_test_nonnull(kv1 = kmclipm_vector_create(v));

    kmclipm_vector_subtract(kv1, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v2 = cpl_vector_new(1);
    cpl_vector_set(v2, 0, 1);
    cpl_test_nonnull(kv2 = kmclipm_vector_create(v2));

    kmclipm_vector_subtract(kv1, kv2);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmclipm_vector_delete(kv2); kv2 = NULL;

    v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, NAN);
    cpl_vector_set(v, 2, 3);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    cpl_test_nonnull(kv2 = kmclipm_vector_create(v));

    cpl_test_abs(12, kmclipm_vector_get_sum(kv1), 0.01);
    cpl_test_abs(13, kmclipm_vector_get_sum(kv2), 0.01);
    kmclipm_vector_subtract(kv1, kv2);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(0, kmclipm_vector_get_sum(kv1), 0.01);
    cpl_test_abs(13, kmclipm_vector_get_sum(kv2), 0.01);

    kmclipm_vector_delete(kv1); kv1 = NULL;
    kmclipm_vector_delete(kv2); kv2 = NULL;
}

void test_kmclipm_vector_multiply()
{
    kmclipm_vector_multiply(NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv1 = NULL, *kv2 = NULL;
    cpl_test_nonnull(kv1 = kmclipm_vector_create(v));

    kmclipm_vector_multiply(kv1, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v2 = cpl_vector_new(1);
    cpl_vector_set(v2, 0, 1);
    cpl_test_nonnull(kv2 = kmclipm_vector_create(v2));

    kmclipm_vector_multiply(kv1, kv2);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmclipm_vector_delete(kv2); kv2 = NULL;

    v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, NAN);
    cpl_vector_set(v, 2, 3);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    cpl_test_nonnull(kv2 = kmclipm_vector_create(v));

    cpl_test_abs(12, kmclipm_vector_get_sum(kv1), 0.01);
    cpl_test_abs(13, kmclipm_vector_get_sum(kv2), 0.01);
    kmclipm_vector_multiply(kv1, kv2);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(42, kmclipm_vector_get_sum(kv1), 0.01);
    cpl_test_abs(13, kmclipm_vector_get_sum(kv2), 0.01);

    kmclipm_vector_delete(kv1); kv1 = NULL;
    kmclipm_vector_delete(kv2); kv2 = NULL;
}

void test_kmclipm_vector_divide()
{
    kmclipm_vector_divide(NULL, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv1 = NULL, *kv2 = NULL;
    cpl_test_nonnull(kv1 = kmclipm_vector_create(v));

    kmclipm_vector_divide(kv1, NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v2 = cpl_vector_new(1);
    cpl_vector_set(v2, 0, 1);
    cpl_test_nonnull(kv2 = kmclipm_vector_create(v2));

    kmclipm_vector_divide(kv1, kv2);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmclipm_vector_delete(kv2); kv2 = NULL;

    v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, NAN);
    cpl_vector_set(v, 2, 3);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    cpl_test_nonnull(kv2 = kmclipm_vector_create(v));

    cpl_test_abs(12, kmclipm_vector_get_sum(kv1), 0.01);
    cpl_test_abs(13, kmclipm_vector_get_sum(kv2), 0.01);
    kmclipm_vector_divide(kv1, kv2);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(3, kmclipm_vector_get_sum(kv1), 0.01);
    cpl_test_abs(13, kmclipm_vector_get_sum(kv2), 0.01);

    kmclipm_vector_delete(kv1); kv1 = NULL;
    kmclipm_vector_delete(kv2); kv2 = NULL;
}

void test_kmclipm_vector_add_scalar()
{
    kmclipm_vector_add_scalar(NULL, -1);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_abs(3, kmclipm_vector_get_mean(kv), 0.01);
    kmclipm_vector_add_scalar(kv, -1);
    cpl_test_abs(2, kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_error(CPL_ERROR_NONE);
    kmclipm_vector_add_scalar(kv, 2);
    cpl_test_abs(4, kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_error(CPL_ERROR_NONE);
    kmclipm_vector_add_scalar(kv, NAN);
    cpl_test_abs(0, kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));
    kmclipm_vector_add_scalar(kv, 2);
    cpl_test_abs(0, kmclipm_vector_get_mean(kv), 0.01);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_subtract_scalar()
{
    kmclipm_vector_subtract_scalar(NULL, -1);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_abs(3, kmclipm_vector_get_mean(kv), 0.01);
    kmclipm_vector_subtract_scalar(kv, -1);
    cpl_test_abs(4, kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_error(CPL_ERROR_NONE);
    kmclipm_vector_subtract_scalar(kv, 2);
    cpl_test_abs(2, kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_error(CPL_ERROR_NONE);
    kmclipm_vector_subtract_scalar(kv, NAN);
    cpl_test_abs(0, kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));
    kmclipm_vector_subtract_scalar(kv, 2);
    cpl_test_abs(0, kmclipm_vector_get_mean(kv), 0.01);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_multiply_scalar()
{
    kmclipm_vector_multiply_scalar(NULL, -1);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_abs(3, kmclipm_vector_get_mean(kv), 0.01);
    kmclipm_vector_multiply_scalar(kv, -1);
    cpl_test_abs(-3, kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_error(CPL_ERROR_NONE);
    kmclipm_vector_multiply_scalar(kv, 2);
    cpl_test_abs(-6, kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_error(CPL_ERROR_NONE);
    kmclipm_vector_multiply_scalar(kv, NAN);
    cpl_test_abs(0, kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));
    kmclipm_vector_multiply_scalar(kv, 2);
    cpl_test_abs(0, kmclipm_vector_get_mean(kv), 0.01);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_divide_scalar()
{
    kmclipm_vector_divide_scalar(NULL, -1);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_abs(3, kmclipm_vector_get_mean(kv), 0.01);
    kmclipm_vector_divide_scalar(kv, -1);
    cpl_test_abs(-3, kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_error(CPL_ERROR_NONE);
    kmclipm_vector_divide_scalar(kv, 2);
    cpl_test_abs(-1.5, kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_error(CPL_ERROR_NONE);
    kmclipm_vector_divide_scalar(kv, NAN);
    cpl_test_abs(0, kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));
    kmclipm_vector_divide_scalar(kv, 2);
    cpl_test_abs(0, kmclipm_vector_get_mean(kv), 0.01);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_abs()
{
    kmclipm_vector_abs(NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, -1);
    cpl_vector_set(v, 1, -2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, -4);
    cpl_vector_set(v, 4, -5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_abs(-3, kmclipm_vector_get_mean(kv), 0.01);
    kmclipm_vector_abs(kv);
    cpl_test_abs(3, kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));
    kmclipm_vector_abs(kv);
    cpl_test_abs(0, kmclipm_vector_get_mean(kv), 0.01);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_get_size()
{
    cpl_test_eq(-1, kmclipm_vector_get_size(NULL));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_eq(5, kmclipm_vector_get_size(kv));
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_eq(5, kmclipm_vector_get_size(kv));
    cpl_test_error(CPL_ERROR_NONE);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

}

void test_kmclipm_vector_get_mean()
{
    cpl_test_abs(0., kmclipm_vector_get_mean(NULL), 0.01);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_abs(3., kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_abs(0., kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_error(CPL_ERROR_NONE);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

}

void test_kmclipm_vector_get_median()
{
    cpl_test_abs(0., kmclipm_vector_get_median(NULL, KMCLIPM_ARITHMETIC), 0.01);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    /* even size */
    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 5);
    cpl_vector_set(v, 1, 4);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 2);
    cpl_vector_set(v, 4, 1);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_abs(3., kmclipm_vector_get_median(kv, KMCLIPM_ARITHMETIC), 0.01);
    cpl_test_abs(2., kmclipm_vector_get_median(kv, KMCLIPM_STATISTICAL), 0.01);
    cpl_test_error(CPL_ERROR_NONE);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    /* uneven size */
    v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 5);
    cpl_vector_set(v, 1, 4);
    cpl_vector_set(v, 2, 3);
    cpl_vector_set(v, 3, 2);
    cpl_vector_set(v, 4, 1);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_abs(3., kmclipm_vector_get_median(kv, KMCLIPM_ARITHMETIC), 0.01);
    cpl_test_abs(3., kmclipm_vector_get_median(kv, KMCLIPM_STATISTICAL), 0.01);
    cpl_test_error(CPL_ERROR_NONE);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_abs(0., kmclipm_vector_get_median(kv, KMCLIPM_ARITHMETIC), 0.01);
    cpl_test_error(CPL_ERROR_NONE);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_cut_percentian()
{
    cpl_test_null(kmclipm_vector_cut_percentian(NULL, -1.));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(10);
    cpl_vector_set(v, 0, 10);
    cpl_vector_set(v, 1, 8);
    cpl_vector_set(v, 2, 7);
    cpl_vector_set(v, 3, 6);
    cpl_vector_set(v, 4, 5);
    cpl_vector_set(v, 5, 4);
    cpl_vector_set(v, 6, 3);
    cpl_vector_set(v, 7, 2);
    cpl_vector_set(v, 8, 1);
    cpl_vector_set(v, 9, 9);
    kmclipm_vector *kv = NULL,
                   *kvout = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_null(kmclipm_vector_cut_percentian(kv, -1.0));
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

    cpl_test_null(kmclipm_vector_cut_percentian(kv, 1.0));
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

    cpl_test_nonnull(kvout = kmclipm_vector_cut_percentian(kv, 0.0));
    cpl_test_eq(10, kmclipm_vector_get_size(kvout));
    cpl_test_abs(5.5, kmclipm_vector_get_mean(kvout), 0.01);
    kmclipm_vector_delete(kvout); kvout = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    cpl_test_nonnull(kvout = kmclipm_vector_cut_percentian(kv, 0.1));
    cpl_test_eq(9, kmclipm_vector_get_size(kvout));
    cpl_test_abs(5.0, kmclipm_vector_get_mean(kvout), 0.01);
    kmclipm_vector_delete(kvout); kvout = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    cpl_test_nonnull(kvout = kmclipm_vector_cut_percentian(kv, 0.25));
    cpl_test_eq(7, kmclipm_vector_get_size(kvout));
    cpl_test_abs(4, kmclipm_vector_get_mean(kvout), 0.01);
    kmclipm_vector_delete(kvout); kvout = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    cpl_test_nonnull(kvout = kmclipm_vector_cut_percentian(kv, 0.5));
    cpl_test_eq(5, kmclipm_vector_get_size(kvout));
    cpl_test_abs(3.0, kmclipm_vector_get_mean(kvout), 0.01);
    kmclipm_vector_delete(kvout); kvout = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    cpl_test_nonnull(kvout = kmclipm_vector_cut_percentian(kv, 0.7));
    cpl_test_eq(3, kmclipm_vector_get_size(kvout));
    cpl_test_abs(2.0, kmclipm_vector_get_mean(kvout), 0.01);
    kmclipm_vector_delete(kvout); kvout = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_get_sum()
{
    cpl_test_eq(0, kmclipm_vector_get_sum(NULL));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_eq(12, kmclipm_vector_get_sum(kv));
    cpl_test_error(CPL_ERROR_NONE);
    kmclipm_vector_delete(kv); kv = NULL;

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_eq(0, kmclipm_vector_get_sum(kv));
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_get_stdev()
{
    cpl_test_abs(-1, kmclipm_vector_get_stdev(NULL), 0.01);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_abs(1.82574, kmclipm_vector_get_stdev(kv), 0.01);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));
    cpl_test_abs(0, kmclipm_vector_get_stdev(kv), 0.01);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_get_stdev_median()
{
    cpl_test_eq(-1, kmclipm_vector_get_stdev_median(NULL));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_abs(1.82574, kmclipm_vector_get_stdev_median(kv), 0.01);
    cpl_test_error(CPL_ERROR_NONE);
    kmclipm_vector_delete(kv); kv = NULL;

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_eq(-1, kmclipm_vector_get_stdev_median(kv));
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_get_max()
{
    cpl_test_abs(0, kmclipm_vector_get_max(NULL, NULL), 0.01);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_abs(5, kmclipm_vector_get_max(kv, NULL), 0.01);
    cpl_test_error(CPL_ERROR_NONE);

    int pos;
    cpl_test_abs(5, kmclipm_vector_get_max(kv, &pos), 0.01);
    cpl_test_eq(4, pos);
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 6);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 0.5);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_abs(6, kmclipm_vector_get_max(kv, &pos), 0.01);
    cpl_test_eq(0, pos);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));
    cpl_test_abs(0, kmclipm_vector_get_max(kv, &pos), 0.01);
    cpl_test_eq(-1, pos);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_get_min()
{
    cpl_test_abs(0, kmclipm_vector_get_min(NULL, NULL), 0.01);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_abs(1, kmclipm_vector_get_min(kv, NULL), 0.01);
    cpl_test_error(CPL_ERROR_NONE);

    int pos;
    cpl_test_abs(1, kmclipm_vector_get_min(kv, &pos), 0.01);
    cpl_test_eq(0, pos);
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 0.5);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_abs(0.5, kmclipm_vector_get_min(kv, &pos), 0.01);
    cpl_test_eq(4, pos);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));
    cpl_test_abs(0, kmclipm_vector_get_min(kv, &pos), 0.01);
    cpl_test_eq(-1, pos);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_power()
{
    kmclipm_vector_power(NULL, -1);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_abs(3., kmclipm_vector_get_mean(kv), 0.01);
    kmclipm_vector_power(kv, -1);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(0.4875, kmclipm_vector_get_mean(kv), 0.01);

    kmclipm_vector_power(kv, 2);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(0.338125, kmclipm_vector_get_mean(kv), 0.01);

    kmclipm_vector_power(kv, 0);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(1, kmclipm_vector_get_mean(kv), 0.01);

    kmclipm_vector_power(kv, NAN);
    cpl_test_error(CPL_ERROR_NONE);
    cpl_test_abs(1, kmclipm_vector_get_mean(kv), 0.01);

    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    kmclipm_vector_power(kv, 2);
    cpl_test_abs(0., kmclipm_vector_get_mean(kv), 0.01);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(5);
    cpl_vector_fill(v, 0.);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    kmclipm_vector_power(kv, 2);
    cpl_test_abs(0., kmclipm_vector_get_mean(kv), 0.01);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_fill()
{
    kmclipm_vector_fill(NULL, -1);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_abs(3., kmclipm_vector_get_mean(kv), 0.01);
    kmclipm_vector_fill(kv, -1);
    cpl_test_abs(-1, kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_fill(kv, NAN);
    cpl_test_abs(0, kmclipm_vector_get_mean(kv), 0.01);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_flip()
{
    kmclipm_vector_flip(NULL);
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    kmclipm_vector_flip(kv);
    cpl_test_abs(cpl_vector_get(kv->data, 0), 5, 0.01);
    cpl_test_abs(cpl_vector_get(kv->data, 1), 4, 0.01);
    cpl_test_abs(cpl_vector_get(kv->mask, 2), 0, 0.01);
    cpl_test_abs(cpl_vector_get(kv->mask, 1), 1, 0.01);
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_delete(kv);
}

void test_kmclipm_vector_histogram()
{
    kmclipm_vector  *out    = NULL;

    cpl_test_null(out = kmclipm_vector_histogram(NULL, -1.0));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_null(out = kmclipm_vector_histogram(kv, -1.0));
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);

    cpl_test_nonnull(out = kmclipm_vector_histogram(kv, 4));
    cpl_test_eq(4, cpl_vector_get_size(out->data));
    cpl_test_eq(2, cpl_vector_get(out->data, 0));
    cpl_test_eq(0, cpl_vector_get(out->data, 1));
    cpl_test_eq(1, cpl_vector_get(out->data, 2));
    cpl_test_eq(1, cpl_vector_get(out->data, 3));
    cpl_test_eq(1, cpl_vector_get_mean(out->mask));
    kmclipm_vector_delete(out); out = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    cpl_test_nonnull(out = kmclipm_vector_histogram(kv, 2));
    cpl_test_eq(2, cpl_vector_get_size(out->data));
    cpl_test_eq(3, cpl_vector_get(out->data, 0));
    cpl_test_eq(1, cpl_vector_get(out->data, 1));
    cpl_test_eq(1, cpl_vector_get_mean(out->mask));
    kmclipm_vector_delete(out); out = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_delete(kv);

    v = cpl_vector_new(8);
    cpl_vector_set(v, 0, 1.5);
    cpl_vector_set(v, 1, 0.5);
    cpl_vector_set(v, 2, 0.0);
    cpl_vector_set(v, 3, 1.0);
    cpl_vector_set(v, 4, 2.0);
    cpl_vector_set(v, 5, -1.0);
    cpl_vector_set(v, 6, 3.0);
    cpl_vector_set(v, 7, -2.1);
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    cpl_test_nonnull(out = kmclipm_vector_histogram(kv, 4));
    cpl_test_eq(4, cpl_vector_get_size(out->data));
    cpl_test_eq(2, cpl_vector_get(out->data, 0));
    cpl_test_eq(3, cpl_vector_get(out->data, 1));
    cpl_test_eq(2, cpl_vector_get(out->data, 2));
    cpl_test_eq(1, cpl_vector_get(out->data, 3));
    kmclipm_vector_delete(out); out = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_delete(kv);
}

void test_kmclipm_vector_load()
{
    char *my_path;

    cpl_msg_set_level(CPL_MSG_OFF);
    cpl_test_null(kmclipm_vector_load(NULL, -1));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    cpl_vector *v = cpl_vector_new(5);
    cpl_vector_set(v, 0, 1);
    cpl_vector_set(v, 1, 2);
    cpl_vector_set(v, 2, NAN);
    cpl_vector_set(v, 3, 4);
    cpl_vector_set(v, 4, 5);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));
    my_path = cpl_sprintf("%s/test_data/ttt.fits", ".");
    kmclipm_vector_save(kv, my_path, CPL_BPP_IEEE_DOUBLE, NULL, CPL_IO_CREATE, NAN);
    cpl_free(my_path);
    kmclipm_vector_delete(kv); kv = NULL;

    v = cpl_vector_new(5);
    cpl_vector_fill(v, NAN);
    cpl_test_nonnull(kv = kmclipm_vector_create(v));
    my_path = cpl_sprintf("%s/test_data/ttt2.fits", ".");
    kmclipm_vector_save(kv, my_path, CPL_BPP_IEEE_DOUBLE, NULL, CPL_IO_CREATE, NAN);
    cpl_free(my_path);
    kmclipm_vector_delete(kv); kv = NULL;

    my_path = cpl_sprintf("%s/test_data/ttt.fits", ".");
    cpl_test_null(kmclipm_vector_load(my_path, -1));
    cpl_free(my_path);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cpl_msg_set_level(my_level);

    /* --- valid tests --- */
    my_path = cpl_sprintf("%s/test_data/ttt.fits", ".");
    cpl_test_nonnull(kv = kmclipm_vector_load(my_path, 0));
    cpl_free(my_path);
    cpl_test_eq(5, cpl_vector_get_size(kv->data));
    cpl_test_eq(5, cpl_vector_get_size(kv->mask));
    cpl_test_abs(3, kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_abs(4./5., cpl_vector_get_mean(kv->mask), 0.01);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    my_path = cpl_sprintf("%s/test_data/ttt2.fits", ".");
    cpl_test_nonnull(kv = kmclipm_vector_load(my_path, 0));
    cpl_free(my_path);
    cpl_test_eq(5, cpl_vector_get_size(kv->data));
    cpl_test_eq(5, cpl_vector_get_size(kv->mask));
    cpl_test_abs(0, kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_abs(0, cpl_vector_get_mean(kv->mask), 0.01);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_save()
{
    char *my_path;

    cpl_msg_set_level(CPL_MSG_OFF);
    cpl_test_null(kmclipm_vector_load(NULL, -1));
    cpl_test_error(CPL_ERROR_NULL_INPUT);

    my_path = cpl_sprintf("%s/test_data/ttt.fits", ".");
    cpl_test_null(kmclipm_vector_load(my_path, -1));
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cpl_msg_set_level(my_level);

    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_load(my_path, 0));

    kmclipm_vector_save(kv, my_path, CPL_BPP_IEEE_DOUBLE, NULL, CPL_IO_CREATE, NAN);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_load(my_path, 0));
    cpl_test_eq(5, cpl_vector_get_size(kv->data));
    cpl_test_eq(5, cpl_vector_get_size(kv->mask));
    cpl_test_abs(3, kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_abs(4./5., cpl_vector_get_mean(kv->mask), 0.01);
    cpl_test_error(CPL_ERROR_NONE);

    kmclipm_vector_save(kv, my_path, CPL_BPP_IEEE_DOUBLE, NULL, CPL_IO_CREATE, 0.);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_load(my_path, 0));
    cpl_test_eq(5, cpl_vector_get_size(kv->data));
    cpl_test_eq(5, cpl_vector_get_size(kv->mask));
    cpl_test_abs(12./5., kmclipm_vector_get_mean(kv), 0.01);
    cpl_test_abs(1, cpl_vector_get_mean(kv->mask), 0.01);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_free(my_path);
    cpl_test_error(CPL_ERROR_NONE);
}

void test_kmclipm_vector_dump()
{
    kmclipm_vector_dump(NULL);
    cpl_test_error(CPL_ERROR_NONE);

    cpl_vector *v = cpl_vector_new(1);
    cpl_vector_set(v, 0, 1);
    kmclipm_vector *kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    kmclipm_vector_dump(kv);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_NONE);

    v = cpl_vector_new(1);
    cpl_vector_fill(v, NAN);
    kv = NULL;
    cpl_test_nonnull(kv = kmclipm_vector_create(v));

    kmclipm_vector_dump(kv);
    kmclipm_vector_delete(kv); kv = NULL;
    cpl_test_error(CPL_ERROR_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_vector_new();
    test_kmclipm_vector_create();
    test_kmclipm_vector_create2();
    test_kmclipm_vector_delete();
    test_kmclipm_vector_duplicate();
    test_kmclipm_vector_set();
    test_kmclipm_vector_get();
    test_kmclipm_vector_get_mask();
    test_kmclipm_vector_get_bpm();
    test_kmclipm_vector_reject_from_mask();

    test_kmclipm_vector_count_rejected();
    test_kmclipm_vector_count_non_rejected();
    test_kmclipm_vector_is_rejected();
    test_kmclipm_vector_reject();
    test_kmclipm_vector_extract();
    test_kmclipm_vector_create_non_rejected();
    test_kmclipm_vector_adapt_rejected();

    test_kmclipm_vector_add();
    test_kmclipm_vector_subtract();
    test_kmclipm_vector_multiply();
    test_kmclipm_vector_divide();
    test_kmclipm_vector_add_scalar();
    test_kmclipm_vector_subtract_scalar();
    test_kmclipm_vector_multiply_scalar();
    test_kmclipm_vector_divide_scalar();
    test_kmclipm_vector_abs();

    test_kmclipm_vector_get_size();
    test_kmclipm_vector_get_mean();
    test_kmclipm_vector_get_median();
    test_kmclipm_vector_cut_percentian();
    test_kmclipm_vector_get_sum();
    test_kmclipm_vector_get_stdev();
    test_kmclipm_vector_get_stdev_median();
    test_kmclipm_vector_get_max();
    test_kmclipm_vector_get_min();
    test_kmclipm_vector_power();
    test_kmclipm_vector_fill();
    test_kmclipm_vector_flip();
    test_kmclipm_vector_histogram();

    test_kmclipm_vector_load();
    test_kmclipm_vector_save();
    test_kmclipm_vector_dump();

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

/** @} */
