/*
 * This file is part of the KMOS Library
 * Copyright (C) 2007-2008 European Southern Observatory
 *
 * This program 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 2 of the License, or
 * (at your option) any later version.
 *
 * This program 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 this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 */

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include "kmclipm_vector.h"

#include "kmo_priv_copy.h"
#include "kmo_utils.h"

/**
    @defgroup kmo_priv_copy_test   kmo_priv_copy unit tests

    @{
*/

void kmo_test_verbose_off();
void kmo_test_verbose_on();
void kmo_test_fill_vector(cpl_vector *vec, float seed, float offset);
void kmo_test_fill_image(cpl_image *img, float seed, float offset);
void kmo_test_fill_cube(cpl_imagelist *cube, float seed, float offset);
void kmo_test_alloc_cube(cpl_imagelist *cube, int x, int y, int z);

/**
 * @brief   Test for kmo_copy_scalar_F1I()
 */
void test_kmo_copy_scalar_F1I()
{
    int size2D = 100;
    float tol = 0.01;
    cpl_vector *v           = cpl_vector_new(size2D);
    kmclipm_vector *vec_in  = NULL;
    kmo_test_fill_vector(v, 0.0, 1.0);
    vec_in = kmclipm_vector_create(v);

    kmo_test_verbose_off();
    kmo_copy_scalar_F1I(NULL, 10);
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    kmo_copy_scalar_F1I(vec_in, 0);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_copy_scalar_F1I(vec_in, size2D + 1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_test_verbose_on();

    cpl_test_abs(kmo_copy_scalar_F1I(vec_in, 10), 9.0, tol);

    kmclipm_vector_delete(vec_in);
    cpl_test_error(CPL_ERROR_NONE);
}

/**
 * @brief   Test for kmo_copy_scalar_F2I()
 */
void test_kmo_copy_scalar_F2I()
{
    int size2D = 100;
    float tol = 0.01;
    cpl_image  *img_in      = cpl_image_new(size2D, size2D, CPL_TYPE_FLOAT);
    kmo_test_fill_image(img_in, 0.0, 1.0);

    kmo_test_verbose_off();
    kmo_copy_scalar_F2I(NULL, 10, 10);
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    kmo_copy_scalar_F2I(img_in, 0, 10);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_copy_scalar_F2I(img_in, size2D + 1, 10);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_copy_scalar_F2I(img_in, 10, 0);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_copy_scalar_F2I(img_in, 10, size2D + 1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_test_verbose_on();

    cpl_test_abs(kmo_copy_scalar_F2I(img_in, 10, 10), 909.0, tol);

    cpl_image_delete(img_in);
    cpl_test_error(CPL_ERROR_NONE);
}

/**
 * @brief   Test for kmo_copy_scalar_F3I()
 */
void test_kmo_copy_scalar_F3I()
{
    int size2D = 100, size3D = 10;
    float tol = 0.01;
    cpl_imagelist *cube_in  = cpl_imagelist_new();
    kmo_test_alloc_cube(cube_in, size2D, size2D, size3D);
    kmo_test_fill_cube(cube_in, 0.0, 1.0);

    kmo_test_verbose_off();
    kmo_copy_scalar_F3I(NULL, 10, 10, 10);
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    kmo_copy_scalar_F3I(cube_in, 0, 10, 10);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_copy_scalar_F3I(cube_in, size2D + 1, 10, 10);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_copy_scalar_F3I(cube_in, 10, 0, 10);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_copy_scalar_F3I(cube_in, 10, size2D + 1, 10);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_copy_scalar_F3I(cube_in, 10, 10, 0);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_copy_scalar_F3I(cube_in, 10, 10, size3D + 1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_test_verbose_on();

    cpl_test_abs(kmo_copy_scalar_F3I(cube_in, 10, 10, 10), 918.0, tol);

    cpl_imagelist_delete(cube_in);
    cpl_test_error(CPL_ERROR_NONE);
}

/**
 * @brief   Test for kmo_copy_vector_F1I()
 */
void test_kmo_copy_vector_F1I()
{
    int            size2D = 100;
    float          tol = 0.01;
    cpl_vector     *v           = cpl_vector_new(size2D);
    kmclipm_vector *vec_in      = NULL,
                   *vec_out     = NULL;
    kmo_test_fill_vector(v, 0.0, 1.0);
    vec_in = kmclipm_vector_create(v);

    kmo_test_verbose_off();
    vec_out = kmo_copy_vector_F1I(NULL, 11, 60);
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    vec_out = kmo_copy_vector_F1I(vec_in, 0, 60);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F1I(vec_in, size2D + 1, 60);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F1I(vec_in, 2, 1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_test_verbose_on();

    cpl_test_nonnull(vec_out = kmo_copy_vector_F1I(vec_in, 11, 60));
    cpl_test_eq(cpl_vector_get_size(vec_out->data), 50);
    cpl_test_abs(cpl_vector_get(vec_out->data, 10), 20.0, tol);

    kmclipm_vector_delete(vec_in);
    kmclipm_vector_delete(vec_out);
    cpl_test_error(CPL_ERROR_NONE);
}

/**
 * @brief   Test for kmo_copy_vector_F2I_x()
 */
void test_kmo_copy_vector_F2I_x()
{
    int size2D = 100;
    float tol = 0.01;
    cpl_vector     *v           = cpl_vector_new(size2D);
    kmclipm_vector *vec_in      = NULL,
                   *vec_out     = NULL;
    cpl_image      *img_in      = cpl_image_new(size2D, size2D, CPL_TYPE_FLOAT);
    kmo_test_fill_vector(v, 0.0, 1.0);
    vec_in = kmclipm_vector_create(v);
    kmo_test_fill_image(img_in, 0.0, 1.0);

    kmo_test_verbose_off();
    vec_out = kmo_copy_vector_F2I_x(NULL, 1, 60, 10);
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    vec_out = kmo_copy_vector_F2I_x(img_in, 0, 60, 10);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F2I_x(img_in, size2D + 1, 60, 10);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F2I_x(img_in, 10, 0, 10);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F2I_x(img_in, 10, size2D + 1, 10);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F2I_x(img_in, 2, 1, 10);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F2I_x(img_in, 1, 2, 0);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F2I_x(img_in, 1, 2, size2D + 1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_test_verbose_on();

    cpl_test_nonnull(vec_out = kmo_copy_vector_F2I_x(img_in, 1, 60, 10));
    cpl_test_eq(cpl_vector_get_size(vec_out->data), 60);
    cpl_test_abs(cpl_vector_get(vec_out->data, 30), 930.0, tol);

    kmclipm_vector_delete(vec_in);
    kmclipm_vector_delete(vec_out);
    cpl_image_delete(img_in);
    cpl_test_error(CPL_ERROR_NONE);
}

/**
 * @brief   Test for kmo_copy_vector_F2I_y()
 */
void test_kmo_copy_vector_F2I_y()
{
    int size2D = 100;
    float tol = 0.01;
    cpl_vector     *v           = cpl_vector_new(size2D);
    kmclipm_vector *vec_in      = NULL,
                   *vec_out     = NULL;
    cpl_image      *img_in      = cpl_image_new(size2D, size2D, CPL_TYPE_FLOAT);

    kmo_test_fill_vector(v, 0.0, 1.0);
    vec_in = kmclipm_vector_create(v);
    kmo_test_fill_image(img_in, 0.0, 1.0);

    kmo_test_verbose_off();
    vec_out = kmo_copy_vector_F2I_y(NULL, 1, 60, 100);
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    vec_out = kmo_copy_vector_F2I_y(img_in, 0, 10, 60);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F2I_y(img_in, size2D + 1, 10, 60);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F2I_y(img_in, 1, 0, 10);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F2I_y(img_in, 1, size2D + 1, 10);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F2I_y(img_in, 1, 10, 0);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F2I_y(img_in, 1, 10, size2D + 1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F2I_y(img_in, 1, 2, 1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_test_verbose_on();

    cpl_test_nonnull(vec_out = kmo_copy_vector_F2I_y(img_in, 1, 81, 100));
    cpl_test_eq(cpl_vector_get_size(vec_out->data), 20);
    cpl_test_abs(cpl_vector_get(vec_out->data, 10), 9000.0, tol);

    kmclipm_vector_delete(vec_in);
    kmclipm_vector_delete(vec_out);
    cpl_image_delete(img_in);
    cpl_test_error(CPL_ERROR_NONE);
}

/**
 * @brief   Test for kmo_copy_vector_F3I_x()
 */
void test_kmo_copy_vector_F3I_x()
{
    int size2D = 100, size3D = 10;
    float tol = 0.01;
    kmclipm_vector *vec_out     = NULL;
    cpl_imagelist *cube_in  = cpl_imagelist_new();
    kmo_test_alloc_cube(cube_in, size2D, size2D, size3D);
    kmo_test_fill_cube(cube_in, 0.0, 1.0);

    kmo_test_verbose_off();
    vec_out = kmo_copy_vector_F3I_x(NULL, 1, 10, 81, 10);
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    vec_out = kmo_copy_vector_F3I_x(cube_in, 0, 10, 81, size3D);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_x(cube_in, size2D + 1, 10, 81, size3D);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_x(cube_in, 10, 0, 81, size3D);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_x(cube_in, 10, size2D + 1, 81, size3D);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_x(cube_in, 1, 10, 0, size3D);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_x(cube_in, 1, 10, size2D + 1, size3D);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_x(cube_in, 1, 10, 81, size3D + 1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_x(cube_in, 2, 1, 81, size3D);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_test_verbose_on();

    cpl_test_nonnull(vec_out = kmo_copy_vector_F3I_x(cube_in, 1, 10, 81, 10));
    cpl_test_eq(cpl_vector_get_size(vec_out->data), 10);
    cpl_test_abs(cpl_vector_get(vec_out->data, 9), 8018.0, tol);

    kmclipm_vector_delete(vec_out);
    cpl_imagelist_delete(cube_in);
    cpl_test_error(CPL_ERROR_NONE);
}

/**
 * @brief   Test for kmo_copy_vector_F3I_y()
 */
void test_kmo_copy_vector_F3I_y()
{
    int size2D = 100, size3D = 10;
    float tol = 0.01;
    kmclipm_vector *vec_out     = NULL;
    cpl_imagelist *cube_in  = cpl_imagelist_new();
    kmo_test_alloc_cube(cube_in, size2D, size2D, size3D);
    kmo_test_fill_cube(cube_in, 0.0, 1.0);

    kmo_test_verbose_off();
    vec_out = kmo_copy_vector_F3I_y(NULL, 100, 10, 81, 1);
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    vec_out = kmo_copy_vector_F3I_y(cube_in, 0, 10, 81, size3D);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_y(cube_in, size2D + 1, 10, 81, size3D);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_y(cube_in, 10, 0, 81, size3D);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_y(cube_in, 10, size2D + 1, 81, size3D);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_y(cube_in, 1, 10, 0, size3D);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_y(cube_in, 1, 10, size2D + 1, size3D);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_y(cube_in, 1, 10, 81, size3D + 1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_y(cube_in, 1, 2, 1, size3D);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_test_verbose_on();

    cpl_test_nonnull(vec_out = kmo_copy_vector_F3I_y(cube_in, 100, 10, 81, 1));
    cpl_test_eq(cpl_vector_get_size(vec_out->data), 72);
    cpl_test_abs(cpl_vector_get(vec_out->data, 9), 1899.0, tol);

    kmclipm_vector_delete(vec_out);
    cpl_imagelist_delete(cube_in);
    cpl_test_error(CPL_ERROR_NONE);
}

/**
 * @brief   Test for kmo_copy_vector_F3I_z()
 */
void test_kmo_copy_vector_F3I_z()
{
    int size2D = 100, size3D = 10;
    float tol = 0.01;
    kmclipm_vector *vec_out     = NULL;
    cpl_imagelist *cube_in  = cpl_imagelist_new();
    kmo_test_alloc_cube(cube_in, size2D, size2D, size3D);
    kmo_test_fill_cube(cube_in, 0.0, 1.0);

    kmo_test_verbose_off();
    vec_out = kmo_copy_vector_F3I_z(NULL, 1, 1, 8, 9);
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    vec_out = kmo_copy_vector_F3I_z(cube_in, 0, 10, 1, 2);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_z(cube_in, size2D + 1, 10, 1, 2);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_z(cube_in, 10, 0, 1, 2);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_z(cube_in, 10, size2D + 1, 1, 2);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_z(cube_in, 10, size2D + 1, 0, 2);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_z(cube_in, 10, size2D + 1, size3D + 1, 2);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_z(cube_in, 10, size2D + 1, 1, 0);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_z(cube_in, 10, size2D + 1, 2, size3D + 1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    vec_out = kmo_copy_vector_F3I_z(cube_in, 10, size2D + 1, 2, 1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_test_verbose_on();

    cpl_test_nonnull(vec_out = kmo_copy_vector_F3I_z(cube_in, 1, 1, 8, 9));
    cpl_test_eq(cpl_vector_get_size(vec_out->data), 2);
    cpl_test_abs(cpl_vector_get(vec_out->data, 1), 8.0, tol);

    kmclipm_vector_delete(vec_out);
    cpl_imagelist_delete(cube_in);
    cpl_test_error(CPL_ERROR_NONE);
}

/**
 * @brief   Test for kmo_copy_image_F2I()
 */
void test_kmo_copy_image_F2I()
{
    int size2D = 100, rej = 0;
    float tol = 0.01;
    cpl_image  *img_in      = cpl_image_new(size2D, size2D, CPL_TYPE_FLOAT),
               *img_out     = NULL;
    kmo_test_fill_image(img_in, 0.0, 1.0);

    kmo_test_verbose_off();
    img_out = kmo_copy_image_F2I(NULL, 1, 1, 11, 20);
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    img_out = kmo_copy_image_F2I(img_in, 0, 1, 11, 20);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F2I(img_in, size2D + 1, 1, 11, 20);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F2I(img_in, 1, 0, 11, 20);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F2I(img_in, 1, size2D + 1, 11, 20);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F2I(img_in, 1, 2, 0, 20);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F2I(img_in, 1, 2, size2D + 1, 20);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F2I(img_in, 1, 2, 1, 0);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F2I(img_in, 1, 2, 1, size2D + 1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F2I(img_in, 2, 1, 1, 2);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F2I(img_in, 1, 2, 2, 1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_test_verbose_on();

    cpl_test_nonnull(img_out = kmo_copy_image_F2I(img_in, 1, 1, 11, 20));
    cpl_test_eq(cpl_image_get_size_x(img_out), 1);
    cpl_test_eq(cpl_image_get_size_y(img_out), 10);
    cpl_test_abs(cpl_image_get(img_out, 1, 3, &rej), 1200.0, tol);

    cpl_image_delete(img_in);
    cpl_image_delete(img_out);
    cpl_test_error(CPL_ERROR_NONE);
}

/**
 * @brief   Test for kmo_copy_image_F3I_x()
 */
void test_kmo_copy_image_F3I_x()
{
    int size2D = 100, size3D = 10, rej = 0;
    float tol = 0.01;
    cpl_image  *img_out     = NULL;
    cpl_imagelist *cube_in  = cpl_imagelist_new();

    kmo_test_alloc_cube(cube_in, size2D, size2D, size3D);
    kmo_test_fill_cube(cube_in, 0.0, 1.0);

    kmo_test_verbose_off();
    img_out = kmo_copy_image_F3I_x(NULL, 2, 2, 7, 3, 5);
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    img_out = kmo_copy_image_F3I_x(cube_in, 0, 2, 7, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_x(cube_in, size2D + 1, 2, 7, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_x(cube_in, 1, 0, 7, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_x(cube_in, 1, size2D + 1, 7, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_x(cube_in, 1, 2, 0, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_x(cube_in, 1, 2, size2D + 1, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_x(cube_in, 1, 2, 7, 0, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_x(cube_in, 1, 2, 7, size2D + 1, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_x(cube_in, 1, 2, 7, 2, 0);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_x(cube_in, 1, 2, 7, 2, size2D + 1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_x(cube_in, 1, 7, 2, 2, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_x(cube_in, 1, 2, 7, 5, 2);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_test_verbose_on();

    cpl_test_nonnull(img_out = kmo_copy_image_F3I_x(cube_in, 2, 2, 7, 3, 5));
    cpl_test_eq(cpl_image_get_size_x(img_out), 3);
    cpl_test_eq(cpl_image_get_size_y(img_out), 6);
    cpl_test_abs(cpl_image_get(img_out, 2, 5, &rej), 504.0, tol);

    cpl_image_delete(img_out);
    cpl_imagelist_delete(cube_in);
    cpl_test_error(CPL_ERROR_NONE);
}

/**
 * @brief   Test for kmo_copy_image_F3I_y()
 */
void test_kmo_copy_image_F3I_y()
{
    int size2D = 100, size3D = 10, rej = 0;
    float tol = 0.01;
    cpl_image  *img_out     = NULL;
    cpl_imagelist *cube_in  = cpl_imagelist_new();

    kmo_test_alloc_cube(cube_in, size2D, size2D, size3D);
    kmo_test_fill_cube(cube_in, 0.0, 1.0);

    kmo_test_verbose_off();
    img_out = kmo_copy_image_F3I_y(NULL, 2, 5, 2, 2, 7);
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    img_out = kmo_copy_image_F3I_y(cube_in, 0, 2, 7, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_y(cube_in, size2D + 1, 2, 7, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_y(cube_in, 1, 0, 2, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_y(cube_in, 1, size2D + 1, 2, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_y(cube_in, 1, 2, 0, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_y(cube_in, 1, 2, size2D + 1, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_y(cube_in, 1, 2, 7, 0, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_y(cube_in, 1, 2, 7, size2D + 1, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_y(cube_in, 1, 2, 7, 3, 0);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_y(cube_in, 1, 2, 7, 3, size2D + 1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_y(cube_in, 1, 2, 7, 5, 3);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_y(cube_in, 2, 1, 7, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_test_verbose_on();

    cpl_test_nonnull(img_out = kmo_copy_image_F3I_y(cube_in, 2, 5, 2, 2, 7));
    cpl_test_eq(cpl_image_get_size_x(img_out), 6);
    cpl_test_eq(cpl_image_get_size_y(img_out), 4);
    cpl_test_abs(cpl_image_get(img_out, 3, 4, &rej), 107.0, tol);

    cpl_image_delete(img_out);
    cpl_imagelist_delete(cube_in);
    cpl_test_error(CPL_ERROR_NONE);
}

/**
 * @brief   Test for kmo_copy_image_F3I_z()
 */
void test_kmo_copy_image_F3I_z()
{
    int size2D = 100, size3D = 10, rej = 0;
    float tol = 0.01;
    cpl_image  *img_out     = NULL;
    cpl_imagelist *cube_in  = cpl_imagelist_new();

    kmo_test_alloc_cube(cube_in, size2D, size2D, size3D);
    kmo_test_fill_cube(cube_in, 0.0, 1.0);

    kmo_test_verbose_off();
    img_out = kmo_copy_image_F3I_z(NULL, 1, 50, 11, 30, 7);
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    img_out = kmo_copy_image_F3I_z(cube_in, 0, 2, 2, 5, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_z(cube_in, size2D + 1, 2, 2, 5, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_z(cube_in, 1, 0, 2, 5, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_z(cube_in, 1, size2D + 1, 2, 5, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_z(cube_in, 1, 2, 0, 5, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_z(cube_in, 1, 2, size2D + 1, 5, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_z(cube_in, 1, 2, 2, 0, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_z(cube_in, 1, 2, 2, size2D + 1, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_z(cube_in, 1, 2, 2, 5, 0);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_z(cube_in, 1, 2, 2, 5, size2D + 1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_z(cube_in, 2, 1, 2, 5, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    img_out = kmo_copy_image_F3I_z(cube_in, 1, 2, 5, 2, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_test_verbose_on();

    cpl_test_nonnull(img_out = kmo_copy_image_F3I_z(cube_in, 1, 50, 11, 30, 7));
    cpl_test_eq(cpl_image_get_size_x(img_out), 50);
    cpl_test_eq(cpl_image_get_size_y(img_out), 20);
    cpl_test_abs(cpl_image_get(img_out, 3, 4, &rej), 1308.0, tol);

    cpl_image_delete(img_out);
    cpl_imagelist_delete(cube_in);
    cpl_test_error(CPL_ERROR_NONE);
}

/**
 * @brief   Test for kmo_copy_cube_F3I()
 */
void test_kmo_copy_cube_F3I()
{
    int size2D = 100, size3D = 10, rej = 0;
    float tol = 0.01;
    cpl_image  *img_out     = NULL;
    cpl_imagelist *cube_in  = cpl_imagelist_new(),
                  *cube_out = NULL;
    kmo_test_alloc_cube(cube_in, size2D, size2D, size3D);
    kmo_test_fill_cube(cube_in, 0.0, 1.0);

    kmo_test_verbose_off();
    cube_out = kmo_copy_cube_F3I(NULL, 1, 50, 11, 30, 3, 7);
    cpl_test_error(CPL_ERROR_NULL_INPUT);
    cube_out = kmo_copy_cube_F3I(cube_in, 0, 2, 2, 5, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cube_out = kmo_copy_cube_F3I(cube_in, size2D + 1, 2, 2, 5, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cube_out = kmo_copy_cube_F3I(cube_in, 1, 0, 2, 5, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cube_out = kmo_copy_cube_F3I(cube_in, 1, size2D + 1, 2, 5, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cube_out = kmo_copy_cube_F3I(cube_in, 1, 2, 0, 5, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cube_out = kmo_copy_cube_F3I(cube_in, 1, 2, size2D + 1, 5, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cube_out = kmo_copy_cube_F3I(cube_in, 1, 2, 2, 0, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cube_out = kmo_copy_cube_F3I(cube_in, 1, 2, 2, size2D + 1, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cube_out = kmo_copy_cube_F3I(cube_in, 1, 2, 2, 5, 0, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cube_out = kmo_copy_cube_F3I(cube_in, 1, 2, 2, 5, size2D + 1, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cube_out = kmo_copy_cube_F3I(cube_in, 1, 2, 2, 5, 3, 0);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cube_out = kmo_copy_cube_F3I(cube_in, 1, 2, 2, 5, 3, size2D + 1);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cube_out = kmo_copy_cube_F3I(cube_in, 2, 1, 2, 5, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cube_out = kmo_copy_cube_F3I(cube_in, 1, 2, 5, 2, 3, 5);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    cube_out = kmo_copy_cube_F3I(cube_in, 1, 2, 2, 5, 5, 3);
    cpl_test_error(CPL_ERROR_ILLEGAL_INPUT);
    kmo_test_verbose_on();

    cpl_test_nonnull(cube_out = kmo_copy_cube_F3I(cube_in, 1, 50, 11, 30, 3, 7));
    cpl_test_eq(cpl_imagelist_get_size(cube_out), 5);
    cpl_test_nonnull(img_out = cpl_imagelist_get(cube_out, 2));
    cpl_test_eq(cpl_image_get_size_x(img_out), 50);
    cpl_test_eq(cpl_image_get_size_y(img_out), 20);
    cpl_test_abs(cpl_image_get(img_out, 3, 4, &rej), 1306.0, tol);

    cpl_imagelist_delete(cube_in);
    cpl_imagelist_delete(cube_out);
    cpl_test_error(CPL_ERROR_NONE);
}

/**
    @brief   Test of helper functions for kmo_copy
*/
int main()
{
    cpl_test_init("<usd-help@eso.org>", CPL_MSG_WARNING);

    test_kmo_copy_scalar_F1I();
    test_kmo_copy_scalar_F2I();
    test_kmo_copy_scalar_F3I();
    test_kmo_copy_vector_F1I();
    test_kmo_copy_vector_F2I_x();
    test_kmo_copy_vector_F2I_y();
    test_kmo_copy_vector_F3I_x();
    test_kmo_copy_vector_F3I_y();
    test_kmo_copy_vector_F3I_z();
    test_kmo_copy_image_F2I();
    test_kmo_copy_image_F3I_x();
    test_kmo_copy_image_F3I_y();
    test_kmo_copy_image_F3I_z();
    test_kmo_copy_cube_F3I();

    return cpl_test_end(0);
}

/** @} */
