/**
 * @file   test_cmp_decmp.c
 * @author Dominik Loidolt (dominik.loidolt@univie.ac.at)
 * @date   2022
 *
 * @copyright GPLv2
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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.
 *
 * @brief random compression decompression tests
 * @details We generate random data and compress them with random parameters.
 *	After that we  decompress the compression entity and compare the
 *	decompressed data with the original data.
 */


#include <string.h>
#include <stdlib.h>
#include <stdio.h>

#include <unity.h>
#include "../test_common/test_common.h"

#include <cmp_icu.h>
#include <cmp_chunk.h>
#include <decmp.h>
#include <cmp_data_types.h>
#include <leon_inttypes.h>
#include <byteorder.h>
#include <cmp_error.h>

#if defined __has_include
#  if __has_include(<time.h>)
#    include <time.h>
#    include <unistd.h>
#    define HAS_TIME_H 1
#  endif
#endif

#define ROUND_UP_TO_MULTIPLE_OF_4(x) (((x) + 3U) & ~3U)


/**
 * @brief  Seeds the pseudo-random number generator
 */

void setUp(void)
{
	uint64_t seed;
	static int n;

#ifdef HAS_TIME_H
	seed = (uint64_t)(time(NULL) ^ getpid()  ^ (intptr_t)&setUp);
	seed = 0;
#else
	seed = 1;
#endif

	if (!n) {
		uint32_t high = seed >> 32;
		uint32_t low = seed & 0xFFFFFFFF;
		n = 1;
		cmp_rand_seed(seed);
		printf("seed: 0x%08"PRIx32"%08"PRIx32"\n", high, low);
	}
}


static size_t gen_ima_data(uint16_t *data, enum cmp_data_type data_type,
			   uint32_t samples, const struct cmp_max_used_bits *max_used_bits)
{
	uint32_t i;

	if (data) {
		uint32_t max_data_bits;

		switch (data_type) {
		case DATA_TYPE_IMAGETTE:
		case DATA_TYPE_IMAGETTE_ADAPTIVE:
			max_data_bits = max_used_bits->nc_imagette;
			break;
		case DATA_TYPE_SAT_IMAGETTE:
		case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE:
			max_data_bits = max_used_bits->saturated_imagette;
			break;
		case DATA_TYPE_F_CAM_IMAGETTE:
		case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE:
			max_data_bits = max_used_bits->fc_imagette;
			break;
		default:
			TEST_FAIL();
		}
		for (i = 0; i < samples; i++)
			data[i] = (uint16_t)cmp_rand_nbits(max_data_bits);
	}
	return sizeof(*data) * samples;
}


static size_t gen_nc_offset_data(struct offset *data, uint32_t samples,
				 const struct cmp_max_used_bits *max_used_bits)
{
	uint32_t i;

	if (data) {
		for (i = 0; i < samples; i++) {
			data[i].mean = cmp_rand_nbits(max_used_bits->nc_offset_mean);
			data[i].variance = cmp_rand_nbits(max_used_bits->nc_offset_variance);
		}
	}
	return sizeof(*data) * samples;
}


static size_t gen_fc_offset_data(struct offset *data, uint32_t samples,
				 const struct cmp_max_used_bits *max_used_bits)
{
	uint32_t i;

	if (data) {
		for (i = 0; i < samples; i++) {
			data[i].mean = cmp_rand_nbits(max_used_bits->fc_offset_mean);
			data[i].variance = cmp_rand_nbits(max_used_bits->fc_offset_variance);
		}
	}
	return sizeof(*data) * samples;
}


static size_t gen_nc_background_data(struct background *data, uint32_t samples,
				     const struct cmp_max_used_bits *max_used_bits)
{
	uint32_t i;

	if (data) {
		for (i = 0; i < samples; i++) {
			data[i].mean = cmp_rand_nbits(max_used_bits->nc_background_mean);
			data[i].variance = cmp_rand_nbits(max_used_bits->nc_background_variance);
			data[i].outlier_pixels = (__typeof__(data[i].outlier_pixels))cmp_rand_nbits(max_used_bits->nc_background_outlier_pixels);
		}
	}
	return sizeof(*data) * samples;
}


static size_t gen_fc_background_data(struct background *data, uint32_t samples,
				     const struct cmp_max_used_bits *max_used_bits)
{
	uint32_t i;

	if (data) {
		for (i = 0; i < samples; i++) {
			data[i].mean = cmp_rand_nbits(max_used_bits->fc_background_mean);
			data[i].variance = cmp_rand_nbits(max_used_bits->fc_background_variance);
			data[i].outlier_pixels = (__typeof__(data[i].outlier_pixels))cmp_rand_nbits(max_used_bits->fc_background_outlier_pixels);
		}
	}
	return sizeof(*data) * samples;
}


static size_t gen_smearing_data(struct smearing *data, uint32_t samples,
				const struct cmp_max_used_bits *max_used_bits)
{
	uint32_t i;

	if (data) {
		for (i = 0; i < samples; i++) {
			data[i].mean = cmp_rand_nbits(max_used_bits->smearing_mean);
			data[i].variance_mean = (__typeof__(data[i].variance_mean))cmp_rand_nbits(max_used_bits->smearing_variance_mean);
			data[i].outlier_pixels = (__typeof__(data[i].outlier_pixels))cmp_rand_nbits(max_used_bits->smearing_outlier_pixels);
		}
	}
	return sizeof(*data) * samples;
}


static size_t gen_s_fx_data(struct s_fx *data, uint32_t samples,
			    const struct cmp_max_used_bits *max_used_bits)
{
	uint32_t i;

	if (data) {
		for (i = 0; i < samples; i++) {
			data[i].exp_flags = (__typeof__(data[i].exp_flags))cmp_rand_nbits(max_used_bits->s_exp_flags);
			data[i].fx = cmp_rand_nbits(max_used_bits->s_fx);
		}
	}
	return sizeof(*data) * samples;
}


static size_t gen_s_fx_efx_data(struct s_fx_efx *data, uint32_t samples,
				const struct cmp_max_used_bits *max_used_bits)
{
	uint32_t i;

	if (data) {
		for (i = 0; i < samples; i++) {
			data[i].exp_flags = (__typeof__(data[i].exp_flags))cmp_rand_nbits(max_used_bits->s_exp_flags);
			data[i].fx = cmp_rand_nbits(max_used_bits->s_fx);
			data[i].efx = cmp_rand_nbits(max_used_bits->s_efx);
		}
	}
	return sizeof(*data) * samples;
}


static size_t gen_s_fx_ncob_data(struct s_fx_ncob *data, uint32_t samples,
				 const struct cmp_max_used_bits *max_used_bits)
{
	uint32_t i;

	if (data) {
		for (i = 0; i < samples; i++) {
			data[i].exp_flags = (__typeof__(data[i].exp_flags))cmp_rand_nbits(max_used_bits->s_exp_flags);
			data[i].fx = cmp_rand_nbits(max_used_bits->s_fx);
			data[i].ncob_x = cmp_rand_nbits(max_used_bits->s_ncob);
			data[i].ncob_y = cmp_rand_nbits(max_used_bits->s_ncob);
		}
	}
	return sizeof(*data) * samples;
}


static size_t gen_s_fx_efx_ncob_ecob_data(struct s_fx_efx_ncob_ecob *data, uint32_t samples,
					  const struct cmp_max_used_bits *max_used_bits)
{
	uint32_t i;

	if (data) {
		for (i = 0; i < samples; i++) {
			data[i].exp_flags = (__typeof__(data[i].exp_flags))cmp_rand_nbits(max_used_bits->s_exp_flags);
			data[i].fx = cmp_rand_nbits(max_used_bits->s_fx);
			data[i].ncob_x = cmp_rand_nbits(max_used_bits->s_ncob);
			data[i].ncob_y = cmp_rand_nbits(max_used_bits->s_ncob);
			data[i].efx = cmp_rand_nbits(max_used_bits->s_efx);
			data[i].ecob_x = cmp_rand_nbits(max_used_bits->s_ecob);
			data[i].ecob_y = cmp_rand_nbits(max_used_bits->s_ecob);
		}
	}
	return sizeof(*data) * samples;
}


static size_t gen_f_fx_data(struct f_fx *data, uint32_t samples,
			    const struct cmp_max_used_bits *max_used_bits)
{
	uint32_t i;

	if (data)
		for (i = 0; i < samples; i++)
			data[i].fx = cmp_rand_nbits(max_used_bits->f_fx);
	return sizeof(*data) * samples;
}


static size_t gen_f_fx_efx_data(struct f_fx_efx *data, uint32_t samples,
				const struct cmp_max_used_bits *max_used_bits)
{
	uint32_t i;

	if (data) {
		for (i = 0; i < samples; i++) {
			data[i].fx = cmp_rand_nbits(max_used_bits->f_fx);
			data[i].efx = cmp_rand_nbits(max_used_bits->f_efx);
		}
	}
	return sizeof(*data) * samples;
}


static size_t gen_f_fx_ncob_data(struct f_fx_ncob *data, uint32_t samples,
				 const struct cmp_max_used_bits *max_used_bits)
{
	uint32_t i;

	if (data) {
		for (i = 0; i < samples; i++) {
			data[i].fx = cmp_rand_nbits(max_used_bits->f_fx);
			data[i].ncob_x = cmp_rand_nbits(max_used_bits->f_ncob);
			data[i].ncob_y = cmp_rand_nbits(max_used_bits->f_ncob);
		}
	}
	return sizeof(*data) * samples;
}


static size_t gen_f_fx_efx_ncob_ecob_data(struct f_fx_efx_ncob_ecob *data, uint32_t samples,
					  const struct cmp_max_used_bits *max_used_bits)
{
	uint32_t i;

	if (data) {
		for (i = 0; i < samples; i++) {
			data[i].fx = cmp_rand_nbits(max_used_bits->f_fx);
			data[i].ncob_x = cmp_rand_nbits(max_used_bits->f_ncob);
			data[i].ncob_y = cmp_rand_nbits(max_used_bits->f_ncob);
			data[i].efx = cmp_rand_nbits(max_used_bits->f_efx);
			data[i].ecob_x = cmp_rand_nbits(max_used_bits->f_ecob);
			data[i].ecob_y = cmp_rand_nbits(max_used_bits->f_ecob);
		}
	}
	return sizeof(*data) * samples;
}


static size_t gen_l_fx_data(struct l_fx *data, uint32_t samples,
			    const struct cmp_max_used_bits *max_used_bits)
{
	uint32_t i;

	if (data) {
		for (i = 0; i < samples; i++) {
			data[i].exp_flags = cmp_rand_nbits(max_used_bits->l_exp_flags);
			data[i].fx = cmp_rand_nbits(max_used_bits->l_fx);
			data[i].fx_variance = cmp_rand_nbits(max_used_bits->l_fx_variance);
		}
	}
	return sizeof(*data) * samples;
}


static size_t gen_l_fx_efx_data(struct l_fx_efx *data, uint32_t samples,
				const struct cmp_max_used_bits *max_used_bits)
{
	uint32_t i;

	if (data) {
		for (i = 0; i < samples; i++) {
			data[i].exp_flags = cmp_rand_nbits(max_used_bits->l_exp_flags);
			data[i].fx = cmp_rand_nbits(max_used_bits->l_fx);
			data[i].efx = cmp_rand_nbits(max_used_bits->l_efx);
			data[i].fx_variance = cmp_rand_nbits(max_used_bits->l_fx_variance);
		}
	}
	return sizeof(*data) * samples;
}


static size_t gen_l_fx_ncob_data(struct l_fx_ncob *data, uint32_t samples,
				 const struct cmp_max_used_bits *max_used_bits)
{
	if (data) {
		uint32_t i;

		for (i = 0; i < samples; i++) {
			data[i].exp_flags = cmp_rand_nbits(max_used_bits->l_exp_flags);
			data[i].fx = cmp_rand_nbits(max_used_bits->l_fx);
			data[i].ncob_x = cmp_rand_nbits(max_used_bits->l_ncob);
			data[i].ncob_y = cmp_rand_nbits(max_used_bits->l_ncob);
			data[i].fx_variance = cmp_rand_nbits(max_used_bits->l_fx_variance);
			data[i].cob_x_variance = cmp_rand_nbits(max_used_bits->l_cob_variance);
			data[i].cob_y_variance = cmp_rand_nbits(max_used_bits->l_cob_variance);
		}
	}
	return sizeof(*data) * samples;
}


static size_t gen_l_fx_efx_ncob_ecob_data(struct l_fx_efx_ncob_ecob *data, uint32_t samples,
					  const struct cmp_max_used_bits *max_used_bits)
{
	if (data) {
		uint32_t i;

		for (i = 0; i < samples; i++) {
			data[i].exp_flags = cmp_rand_nbits(max_used_bits->l_exp_flags);
			data[i].fx = cmp_rand_nbits(max_used_bits->l_fx);
			data[i].ncob_x = cmp_rand_nbits(max_used_bits->l_ncob);
			data[i].ncob_y = cmp_rand_nbits(max_used_bits->l_ncob);
			data[i].efx = cmp_rand_nbits(max_used_bits->l_efx);
			data[i].ecob_x = cmp_rand_nbits(max_used_bits->l_ecob);
			data[i].ecob_y = cmp_rand_nbits(max_used_bits->l_ecob);
			data[i].fx_variance = cmp_rand_nbits(max_used_bits->l_fx_variance);
			data[i].cob_x_variance = cmp_rand_nbits(max_used_bits->l_cob_variance);
			data[i].cob_y_variance = cmp_rand_nbits(max_used_bits->l_cob_variance);
		}
	}
	return sizeof(*data) * samples;
}


uint32_t generate_random_collection_hdr(struct collection_hdr *col, enum cmp_data_type data_type,
					uint32_t samples)
{
	static uint8_t sequence_num;
	size_t data_size = size_of_a_sample(data_type)*samples;

	TEST_ASSERT(data_size <= UINT16_MAX);

	if (col) {
#ifdef HAS_TIME_H
		TEST_ASSERT_FALSE(cmp_col_set_timestamp(col, cmp_ent_create_timestamp(NULL)));
#else
		TEST_ASSERT_FALSE(cmp_col_set_timestamp(col, 0x150D15AB1ED));
#endif
		TEST_ASSERT_FALSE(cmp_col_set_configuration_id(col, (uint16_t)cmp_rand32()));

		TEST_ASSERT_FALSE(cmp_col_set_pkt_type(col, COL_SCI_PKTS_TYPE));
		TEST_ASSERT_FALSE(cmp_col_set_subservice(col, convert_cmp_data_type_to_subservice(data_type)));
		TEST_ASSERT_FALSE(cmp_col_set_ccd_id(col, (uint8_t)cmp_rand_between(0, 3)));
		TEST_ASSERT_FALSE(cmp_col_set_sequence_num(col, sequence_num++));

		TEST_ASSERT_FALSE(cmp_col_set_data_length(col, (uint16_t)data_size));
	}
	return COLLECTION_HDR_SIZE;
}


/**
 * @brief generates a random collection (with header)
 *
 * @param col		pointer to where the random collection will be stored;
 *			if NULL, the function will only return the size of the
 *			random collection
 * @param data_type	specifies the compression data type of the test data
 * @param samples	the number of random test data samples to generate
 * @param max_used_bits	pointer to a structure that tracks the maximum number of
 *			bits used
 *
 * @return the size of the generated random collection in bytes
 */

size_t generate_random_collection(struct collection_hdr *col, enum cmp_data_type data_type,
				  uint32_t samples, const struct cmp_max_used_bits *max_used_bits)
{
	size_t size;
	void *science_data = NULL;

	if (col)
		science_data = col->entry;

	size = generate_random_collection_hdr(col, data_type, samples);
#if 0
	{	int i;

		for (i = 0; i < size_of_a_sample(data_type)*samples; i++) {
			if (col)
				col->entry[i] = i;
		}
		return size+i;
	}
#endif

	switch (data_type) {
	case DATA_TYPE_IMAGETTE:
	case DATA_TYPE_IMAGETTE_ADAPTIVE:
	case DATA_TYPE_SAT_IMAGETTE:
	case DATA_TYPE_SAT_IMAGETTE_ADAPTIVE:
	case DATA_TYPE_F_CAM_IMAGETTE:
	case DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE:
		size += gen_ima_data(science_data, data_type, samples, max_used_bits);
		break;
	case DATA_TYPE_OFFSET:
		size += gen_nc_offset_data(science_data, samples, max_used_bits);
		break;
	case DATA_TYPE_BACKGROUND:
		size += gen_nc_background_data(science_data, samples, max_used_bits);
		break;
	case DATA_TYPE_SMEARING:
		size += gen_smearing_data(science_data, samples, max_used_bits);
		break;
	case DATA_TYPE_S_FX:
		size += gen_s_fx_data(science_data, samples, max_used_bits);
		break;
	case DATA_TYPE_S_FX_EFX:
		size += gen_s_fx_efx_data(science_data, samples, max_used_bits);
		break;
	case DATA_TYPE_S_FX_NCOB:
		size += gen_s_fx_ncob_data(science_data, samples, max_used_bits);
		break;
	case DATA_TYPE_S_FX_EFX_NCOB_ECOB:
		size += gen_s_fx_efx_ncob_ecob_data(science_data, samples, max_used_bits);
		break;
	case DATA_TYPE_L_FX:
		size += gen_l_fx_data(science_data, samples, max_used_bits);
		break;
	case DATA_TYPE_L_FX_EFX:
		size += gen_l_fx_efx_data(science_data, samples, max_used_bits);
		break;
	case DATA_TYPE_L_FX_NCOB:
		size += gen_l_fx_ncob_data(science_data, samples, max_used_bits);
		break;
	case DATA_TYPE_L_FX_EFX_NCOB_ECOB:
		size += gen_l_fx_efx_ncob_ecob_data(science_data, samples, max_used_bits);
		break;
	case DATA_TYPE_F_FX:
		size += gen_f_fx_data(science_data, samples, max_used_bits);
		break;
	case DATA_TYPE_F_FX_EFX:
		size += gen_f_fx_efx_data(science_data, samples, max_used_bits);
		break;
	case DATA_TYPE_F_FX_NCOB:
		size += gen_f_fx_ncob_data(science_data, samples, max_used_bits);
		break;
	case DATA_TYPE_F_FX_EFX_NCOB_ECOB:
		size += gen_f_fx_efx_ncob_ecob_data(science_data, samples, max_used_bits);
		break;
	case DATA_TYPE_F_CAM_OFFSET:
		size += gen_fc_offset_data(science_data, samples, max_used_bits);
		break;
	case DATA_TYPE_F_CAM_BACKGROUND:
		size += gen_fc_background_data(science_data, samples, max_used_bits);
		break;
	default:
		TEST_FAIL();
	}

	if (col)
		TEST_ASSERT_EQUAL_UINT(size, cmp_col_get_size(col));

	return size;
}

struct chunk_def {
	enum cmp_data_type data_type;
	uint32_t samples;
};


/**
 * @brief generates a random chunk of collections
 *
 * @param chunk		pointer to  where the random chunk will be stored; if
 *			NULL, the function will only return the size of the
 *			random chunk
 * @param col_array	specifies which collections are contained in the chunk
 * @param array_elements	number of elements in the col_array
 * @param max_used_bits	pointer to a structure that tracks the maximum number of
 *			bits used
 *
 * @return the size of the generated random chunk in bytes
 */

static uint32_t generate_random_chunk(void *chunk, struct chunk_def col_array[], size_t array_elements,
				    const struct cmp_max_used_bits *max_used_bits)
{
	size_t i;
	uint32_t chunk_size = 0;
	struct collection_hdr *col = NULL;

	for (i = 0; i < array_elements; i++) {
		if (chunk)
			col = (struct collection_hdr *)((uint8_t *)chunk + chunk_size);

		chunk_size += generate_random_collection(col, col_array[i].data_type,
							 col_array[i].samples, max_used_bits);
	}
	return chunk_size;
}


/**
 * @brief generate random compression configuration
 *
 * @param cfg	pointer to a compression configuration
 */

void generate_random_cmp_cfg(struct cmp_cfg *cfg)
{
	if (cmp_imagette_data_type_is_used(cfg->data_type)) {
		cfg->cmp_par_imagette = cmp_rand_between(MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR);
		cfg->ap1_golomb_par = cmp_rand_between(MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR);
		cfg->ap2_golomb_par = cmp_rand_between(MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR);
		cfg->spill_imagette = cmp_rand_between(MIN_IMA_SPILL, cmp_ima_max_spill(cfg->golomb_par));
		cfg->ap1_spill = cmp_rand_between(MIN_IMA_SPILL, cmp_ima_max_spill(cfg->ap1_golomb_par));
		cfg->ap2_spill = cmp_rand_between(MIN_IMA_SPILL, cmp_ima_max_spill(cfg->ap2_golomb_par));
	} else {
		cfg->cmp_par_1 = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		cfg->cmp_par_2 = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		cfg->cmp_par_3 = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		cfg->cmp_par_4 = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		cfg->cmp_par_5 = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		cfg->cmp_par_6 = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		cfg->spill_par_1 = cmp_rand_between(MIN_NON_IMA_SPILL, cmp_icu_max_spill(cfg->cmp_par_exp_flags));
		cfg->spill_par_2 = cmp_rand_between(MIN_NON_IMA_SPILL, cmp_icu_max_spill(cfg->cmp_par_fx));
		cfg->spill_par_3 = cmp_rand_between(MIN_NON_IMA_SPILL, cmp_icu_max_spill(cfg->cmp_par_ncob));
		cfg->spill_par_4 = cmp_rand_between(MIN_NON_IMA_SPILL, cmp_icu_max_spill(cfg->cmp_par_efx));
		cfg->spill_par_5 = cmp_rand_between(MIN_NON_IMA_SPILL, cmp_icu_max_spill(cfg->cmp_par_ecob));
		cfg->spill_par_6 = cmp_rand_between(MIN_NON_IMA_SPILL, cmp_icu_max_spill(cfg->cmp_par_fx_cob_variance));
	}
}


/**
 * @brief generate random chunk compression parameters
 *
 * @param par	pointer where to store the chunk compression
 */

void generate_random_cmp_par(struct cmp_par *par)
{
	if (par) {
		par->cmp_mode = cmp_rand_between(0, MAX_RDCU_CMP_MODE);
		par->model_value = cmp_rand_between(0, MAX_MODEL_VALUE);
		par->lossy_par = cmp_rand_between(0, MAX_ICU_ROUND);

		par->nc_imagette = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);

		par->s_exp_flags = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		par->s_fx = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		par->s_ncob = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		par->s_efx = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		par->s_ecob = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);

		par->l_exp_flags = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		par->l_fx = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		par->l_ncob = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		par->l_efx = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		par->l_ecob = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		par->l_fx_cob_variance = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);

		par->saturated_imagette = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);

		par->nc_offset_mean = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		par->nc_offset_variance = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		par->nc_background_mean = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		par->nc_background_variance = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		par->nc_background_outlier_pixels = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);

		par->smearing_mean = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		par->smearing_variance_mean = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		par->smearing_outlier_pixels = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);

		par->fc_imagette = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		par->fc_offset_mean = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		par->fc_offset_variance = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		par->fc_background_mean = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		par->fc_background_variance = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
		par->fc_background_outlier_pixels = cmp_rand_between(MIN_NON_IMA_GOLOMB_PAR, MAX_NON_IMA_GOLOMB_PAR);
	}
}


/**
 * @brief compress the given configuration and decompress it afterwards; finally
 *	compare the results
 *
 * @param cfg	pointer to a compression configuration
 */

void compression_decompression(struct cmp_cfg *cfg)
{
	int cmp_size_bits, s, error;
	uint32_t data_size, cmp_data_size, cmp_ent_size;
	struct cmp_entity *ent;
	void *decompressed_data;
	static void *model_of_data;
	void *updated_model = NULL;

	if (!cfg) {
		free(model_of_data);
		return;
	}

	TEST_ASSERT_NOT_NULL(cfg);

	TEST_ASSERT_NULL(cfg->icu_output_buf);

	data_size = cmp_cal_size_of_data(cfg->samples, cfg->data_type);

	/* create a compression entity */
	cmp_data_size = cmp_cal_size_of_data(cfg->buffer_length, cfg->data_type);
	/* cmp_data_size &= ~0x3U; /1* the size of the compressed data should be a multiple of 4 *1/ */
	TEST_ASSERT_NOT_EQUAL_INT(0, cmp_data_size);

	cmp_ent_size = cmp_ent_create(NULL, cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW, cmp_data_size);
	TEST_ASSERT_NOT_EQUAL_UINT(0, cmp_ent_size);
	ent = malloc(cmp_ent_size); TEST_ASSERT_TRUE(ent);
	cmp_ent_size = cmp_ent_create(ent, cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW, cmp_data_size);
	TEST_ASSERT_NOT_EQUAL_UINT(0, cmp_ent_size);

	/* we put the compressed data direct into the compression entity */
	cfg->icu_output_buf = cmp_ent_get_data_buf(ent);
	TEST_ASSERT_NOT_NULL(cfg->icu_output_buf);

	/* now compress the data */
	cmp_size_bits = icu_compress_data(cfg);

	TEST_ASSERT(cmp_size_bits > 0);

	/* put the compression parameters in the entity header */
	{
		/* mock values */
		uint32_t version_id = ~0U;
		uint64_t start_time = 32;
		uint64_t end_time = 42;
		uint16_t model_id = 0xCAFE;
		uint8_t model_counter = 0;
		uint32_t ent_size;

		ent_size = cmp_ent_build(ent, version_id, start_time, end_time,
					 model_id, model_counter, cfg, cmp_size_bits);
		TEST_ASSERT_NOT_EQUAL_UINT(0, ent_size);
		error = cmp_ent_set_size(ent, ent_size);
		TEST_ASSERT_FALSE(error);
	}

	/* allocate the buffers for decompression */
	TEST_ASSERT_NOT_EQUAL_INT(0, data_size);
	s = decompress_cmp_entiy(ent, model_of_data, NULL, NULL);
	decompressed_data = malloc((size_t)s); TEST_ASSERT_NOT_NULL(decompressed_data);

	if (model_mode_is_used(cfg->cmp_mode)) {
		updated_model = malloc(data_size);
		TEST_ASSERT_NOT_NULL(updated_model);
	}

	/* now we try to decompress the data */
	s = decompress_cmp_entiy(ent, model_of_data, updated_model, decompressed_data);
	TEST_ASSERT_EQUAL_INT(data_size, s);
	TEST_ASSERT_FALSE(memcmp(decompressed_data, cfg->input_buf, data_size));

	if (model_mode_is_used(cfg->cmp_mode)) {
		TEST_ASSERT_NOT_NULL(updated_model);
		TEST_ASSERT_NOT_NULL(model_of_data);
		TEST_ASSERT_FALSE(memcmp(updated_model, cfg->icu_new_model_buf, data_size));
		memcpy(model_of_data, updated_model, data_size);
	} else { /* non-model mode */
		/* reset model */
		free(model_of_data);
		model_of_data = malloc(data_size);
		memcpy(model_of_data, decompressed_data, data_size);
	}

	cfg->icu_output_buf = NULL;
	free(ent);
	free(decompressed_data);
	free(updated_model);
}


/**
 * @brief random RDCU like compression decompression test
 *
 * We generate random imagette data and compress them with random parameters.
 * After that we put the data in a compression entity. We decompress the
 * compression entity and compare the decompressed data with the original data.
 *
 * @test icu_compress_data
 * @test decompress_cmp_entiy
 */

void test_random_round_trip_like_rdcu_compression(void)
{
	enum cmp_data_type data_type;
	enum cmp_mode cmp_mode;
	struct cmp_cfg cfg;
	uint32_t cmp_buffer_size;
	enum {
		MAX_DATA_TO_COMPRESS_SIZE = 0x1000B,
		CMP_BUFFER_FAKTOR = 3 /* compression data buffer size / data to compress buffer size */
	};
	void *data_to_compress1 = malloc(MAX_DATA_TO_COMPRESS_SIZE);
	void *data_to_compress2 = malloc(MAX_DATA_TO_COMPRESS_SIZE);
	void *updated_model = calloc(1, MAX_DATA_TO_COMPRESS_SIZE);

	for (data_type = 1; data_type <= DATA_TYPE_F_CAM_BACKGROUND; data_type++) {
		/* printf("%s\n", data_type2string(data_type)); */
		/* generate random data*/
		size_t size;
		uint32_t samples = cmp_rand_between(1, UINT16_MAX/size_of_a_sample(data_type));
		uint32_t model_value = cmp_rand_between(0, MAX_MODEL_VALUE);

		if (!rdcu_supported_data_type_is_used(data_type))
			continue;

		size = gen_ima_data(NULL, data_type, samples, &MAX_USED_BITS_V1);
		TEST_ASSERT(size <= MAX_DATA_TO_COMPRESS_SIZE);
		size = gen_ima_data(data_to_compress1, data_type, samples, &MAX_USED_BITS_V1);
		TEST_ASSERT(size <= MAX_DATA_TO_COMPRESS_SIZE);
		size = gen_ima_data(data_to_compress2, data_type, samples, &MAX_USED_BITS_V1);
		TEST_ASSERT(size <= MAX_DATA_TO_COMPRESS_SIZE);
		/* for (cmp_mode = CMP_MODE_RAW; cmp_mode <= CMP_MODE_STUFF; cmp_mode++) { */
		for (cmp_mode = CMP_MODE_RAW; cmp_mode <= CMP_MODE_DIFF_MULTI; cmp_mode++) {
			/* printf("cmp_mode: %i\n", cmp_mode); */
			cfg = cmp_cfg_icu_create(data_type, cmp_mode, model_value,
						 CMP_LOSSLESS);
			TEST_ASSERT_NOT_EQUAL_INT(cfg.data_type, DATA_TYPE_UNKNOWN);

			generate_random_cmp_cfg(&cfg);

			if (!model_mode_is_used(cmp_mode))
				cmp_buffer_size = cmp_cfg_icu_buffers(&cfg, data_to_compress1,
								      samples, NULL, NULL, NULL, samples*CMP_BUFFER_FAKTOR);
			else
				cmp_buffer_size = cmp_cfg_icu_buffers(&cfg, data_to_compress2,
								      samples, data_to_compress1, updated_model, NULL, samples*CMP_BUFFER_FAKTOR);

			TEST_ASSERT_EQUAL_UINT(cmp_buffer_size, cmp_cal_size_of_data(CMP_BUFFER_FAKTOR*samples, data_type));

			compression_decompression(&cfg);
		}
	}
	compression_decompression(NULL);
	free(data_to_compress1);
	free(data_to_compress2);
	free(updated_model);
}


/**
 * @test icu_compress_data
 */

void test_random_compression_decompress_rdcu_data(void)
{
	struct cmp_cfg cfg;
	struct cmp_info info = {0};
	uint32_t cmp_buffer_size;
	int s, i, cmp_size_bits;
	void *compressed_data;
	uint16_t *decompressed_data;
	enum {N_SAMPLES = 5};
	uint16_t data[N_SAMPLES] = {0, UINT16_MAX, INT16_MAX, 42, 23};
	enum {
		CMP_BUFFER_FAKTOR = 2 /* compression data buffer size / data to compress buffer size */
	};

	cfg = cmp_cfg_icu_create(DATA_TYPE_IMAGETTE, CMP_MODE_RAW, 8, CMP_LOSSLESS);
	TEST_ASSERT_NOT_EQUAL_INT(cfg.data_type, DATA_TYPE_UNKNOWN);

	cmp_buffer_size = cmp_cfg_icu_buffers(&cfg, data, N_SAMPLES, NULL, NULL,
					      NULL, N_SAMPLES*CMP_BUFFER_FAKTOR);
	compressed_data = malloc(cmp_buffer_size);
	cmp_buffer_size = cmp_cfg_icu_buffers(&cfg, data, N_SAMPLES, NULL, NULL,
					      compressed_data, N_SAMPLES*CMP_BUFFER_FAKTOR);
	TEST_ASSERT_EQUAL_INT(cmp_buffer_size, cmp_cal_size_of_data(CMP_BUFFER_FAKTOR*N_SAMPLES, DATA_TYPE_IMAGETTE));

	cmp_size_bits = icu_compress_data(&cfg);
	TEST_ASSERT(cmp_size_bits > 0);
	info.cmp_size = (uint32_t)cmp_size_bits;
	info.cmp_mode_used = (uint8_t)cfg.cmp_mode;
	info.model_value_used = (uint8_t)cfg.model_value;
	info.round_used = (uint8_t)cfg.round;
	info.spill_used = cfg.spill;
	info.golomb_par_used = cfg.golomb_par;
	info.samples_used = cfg.samples;
	info.rdcu_new_model_adr_used = cfg.rdcu_new_model_adr;
	info.rdcu_cmp_adr_used = cfg.rdcu_buffer_adr;

	s = decompress_rdcu_data(compressed_data, &info, NULL, NULL, NULL);
	TEST_ASSERT_EQUAL(sizeof(data), s);
	decompressed_data = malloc((size_t)s);
	s = decompress_rdcu_data(compressed_data, &info, NULL, NULL, decompressed_data);
	TEST_ASSERT_EQUAL(sizeof(data), s);

	for (i = 0; i < N_SAMPLES; i++)
		TEST_ASSERT_EQUAL_HEX16(data[i], decompressed_data[i]);

	free(compressed_data);
	free(decompressed_data);
}


static uint32_t chunk_round_trip(void *data, uint32_t data_size,
				 void *model, void *up_model,
				 uint32_t *cmp_data, uint32_t cmp_data_capacity,
				 struct cmp_par *cmp_par, int use_decmp_buf, int use_decmp_up_model)
{
	uint32_t cmp_size;
	void *model_cpy = NULL;

	/* if in-place model update is used (up_model == model), the model
	 * needed for decompression is destroyed; therefore we make a copy
	 */
	if (model) {
		if (up_model == model) {
			model_cpy = TEST_malloc(data_size);
			memcpy(model_cpy, model, data_size);
		} else {
			model_cpy = model;
		}
	}

	cmp_size = compress_chunk(data, data_size, model, up_model,
				  cmp_data, cmp_data_capacity, cmp_par);

#if 0
	{ /* Compress a second time and check for determinism */
		int32_t cSize2;
		void *compressed2 = NULL;
		void *up_model2 = NULL;

		if (compressed)
			compressed2 = FUZZ_malloc(compressedCapacity);

		if (up_model)
			up_model2 = FUZZ_malloc(srcSize);
		cSize2 = compress_chunk((void *)src, srcSize, (void *)model, up_model2,
					   compressed2, compressedCapacity, cmp_par);
		FUZZ_ASSERT(cSize == cSize2);
		FUZZ_ASSERT_MSG(!FUZZ_memcmp(compressed, compressed2, cSize), "Not deterministic!");
		FUZZ_ASSERT_MSG(!FUZZ_memcmp(up_model, compressed2, cSize), "NO deterministic!");
		free(compressed2);
		free(up_model2);
	}
#endif
	if (!cmp_is_error(cmp_size) && cmp_data) {
		void *decmp_data = NULL;
		void *up_model_decmp = NULL;
		int decmp_size;

		decmp_size = decompress_cmp_entiy((struct cmp_entity *)cmp_data, model_cpy, NULL, NULL);
		TEST_ASSERT(decmp_size >= 0);
		TEST_ASSERT_EQUAL((uint32_t)decmp_size, data_size);

		if (use_decmp_buf)
			decmp_data = TEST_malloc(data_size);
		if (use_decmp_up_model)
			up_model_decmp = TEST_malloc(data_size);

		decmp_size = decompress_cmp_entiy((struct cmp_entity *)cmp_data, model_cpy,
						  up_model_decmp, decmp_data);
		TEST_ASSERT(decmp_size >= 0);
		TEST_ASSERT((uint32_t)decmp_size == data_size);

		if (use_decmp_buf) {
			TEST_ASSERT_EQUAL_HEX8_ARRAY(data, decmp_data, data_size);
			TEST_ASSERT(!memcmp(data, decmp_data, data_size));

			/*
			 * the model is only updated when the decompressed_data
			 * buffer is set
			 */
			if (up_model && up_model_decmp)
				TEST_ASSERT(!memcmp(up_model, up_model_decmp, data_size));
		}

		free(decmp_data);
		free(up_model_decmp);
	}

	if (up_model == model)
		free(model_cpy);

	return cmp_size;
}


/**
 * @brief random compression decompression round trip test
 *
 * We generate random data and compress them with random parameters.
 * We decompress the compression entity and compare the decompressed data with
 * the original data.
 *
 * @test compress_chunk
 * @test decompress_cmp_entiy
 */

void test_random_collection_round_trip(void)
{
	enum cmp_data_type data_type;
	enum cmp_mode cmp_mode;
	enum { MAX_DATA_TO_COMPRESS_SIZE = UINT16_MAX};
	uint32_t cmp_data_capacity = COMPRESS_CHUNK_BOUND(MAX_DATA_TO_COMPRESS_SIZE, 1);
#ifdef __sparc__
	void *data          = (void *)0x63000000;
	void *model         = (void *)0x64000000;
	void *updated_model = (void *)0x65000000;
	void *cmp_data      = (void *)0x66000000;
#else /* assume PC */
	void *data = malloc(CMP_ENTITY_MAX_ORIGINAL_SIZE);
	void *model = malloc(MAX_DATA_TO_COMPRESS_SIZE);
	void *updated_model = calloc(1, MAX_DATA_TO_COMPRESS_SIZE);
	void *cmp_data = malloc(cmp_data_capacity);
#endif

	TEST_ASSERT_NOT_NULL(data);
	TEST_ASSERT_NOT_NULL(model);
	TEST_ASSERT_NOT_NULL(updated_model);
	TEST_ASSERT_NOT_NULL(cmp_data);

	for (data_type = 1; data_type <= DATA_TYPE_F_CAM_BACKGROUND; data_type++) {
		/* printf("%s\n", data_type2string(data_type)); */
		/* generate random data*/
		size_t size;
		uint32_t samples = cmp_rand_between(1, UINT16_MAX/size_of_a_sample(data_type));

		size = generate_random_collection(NULL, data_type, samples, &MAX_USED_BITS_SAFE);
		TEST_ASSERT(size <= MAX_DATA_TO_COMPRESS_SIZE);
		size = generate_random_collection(data, data_type, samples, &MAX_USED_BITS_SAFE);
		TEST_ASSERT(size <= MAX_DATA_TO_COMPRESS_SIZE);
		size = generate_random_collection(model, data_type, samples, &MAX_USED_BITS_SAFE);
		TEST_ASSERT(size <= MAX_DATA_TO_COMPRESS_SIZE);

		for (cmp_mode = CMP_MODE_RAW; cmp_mode <= CMP_MODE_DIFF_MULTI; cmp_mode++) {
			struct cmp_par par;
			uint32_t cmp_size;

			generate_random_cmp_par(&par);
			par.cmp_mode = cmp_mode;
			par.lossy_par = CMP_LOSSLESS;

			cmp_size = chunk_round_trip(data, (uint32_t)size, model, updated_model,
						   cmp_data, cmp_data_capacity,
						   &par, 1, model_mode_is_used(par.cmp_mode));
			/* No chunk is defined for fast cadence subservices */
			if (data_type == DATA_TYPE_F_FX || data_type == DATA_TYPE_F_FX_EFX ||
			    data_type == DATA_TYPE_F_FX_NCOB || data_type == DATA_TYPE_F_FX_EFX_NCOB_ECOB)
				TEST_ASSERT_EQUAL_INT(CMP_ERROR_COL_SUBSERVICE_UNSUPPORTED, cmp_get_error_code(cmp_size));
			else
				TEST_ASSERT_FALSE(cmp_is_error(cmp_size));
		}
	}
#ifndef __sparc__
	free(data);
	free(model);
	free(updated_model);
	free(cmp_data);
#endif
}


/**
 * @test compress_chunk
 * @test decompress_cmp_entiy
 */

void test_cmp_collection_raw(void)
{
	struct collection_hdr *col = NULL;
	uint32_t samples = 2;
	uint32_t dst_capacity = 0;
	struct s_fx *data;
	uint32_t *dst = NULL;
	struct cmp_par par = {0};
	const uint32_t col_size = COLLECTION_HDR_SIZE+2*sizeof(struct s_fx);
	const size_t exp_cmp_size_byte = GENERIC_HEADER_SIZE + col_size;
	uint32_t cmp_size_byte;

	par.cmp_mode = CMP_MODE_RAW;

	col = malloc(col_size); TEST_ASSERT_NOT_NULL(col);
	generate_random_collection_hdr(col, DATA_TYPE_S_FX, samples);
	data = (struct s_fx *)col->entry;
	data[0].exp_flags = 0;
	data[0].fx = 0;
	data[1].exp_flags = 0xF0;
	data[1].fx = 0xABCDE0FF;

	cmp_size_byte = compress_chunk(col, col_size, NULL, NULL, dst, dst_capacity, &par);
	TEST_ASSERT_EQUAL_INT(exp_cmp_size_byte, cmp_size_byte);
	dst_capacity = (uint32_t)cmp_size_byte;
	dst = malloc(dst_capacity);
	TEST_ASSERT_NOT_NULL(dst);
	cmp_size_byte = compress_chunk(col, col_size, NULL, NULL, dst, dst_capacity, &par);
	TEST_ASSERT_EQUAL_INT(exp_cmp_size_byte, cmp_size_byte);

	{
		uint8_t *p = (uint8_t *)dst+GENERIC_HEADER_SIZE;
		struct collection_hdr *raw_cmp_col = (struct collection_hdr *)p;
		struct s_fx *raw_cmp_data = (void *)raw_cmp_col->entry;

		/* TEST_ASSERT_EQUAL_UINT(cpu_to_be16(2*sizeof(struct s_fx)), ((uint16_t *)p)[0]); */
		TEST_ASSERT(memcmp(col, raw_cmp_col, COLLECTION_HDR_SIZE) == 0);
		TEST_ASSERT_EQUAL_HEX(data[0].exp_flags, raw_cmp_data[0].exp_flags);
		TEST_ASSERT_EQUAL_HEX(data[0].fx, be32_to_cpu(raw_cmp_data[0].fx));
		TEST_ASSERT_EQUAL_HEX(data[1].exp_flags, raw_cmp_data[1].exp_flags);
		TEST_ASSERT_EQUAL_HEX(data[1].fx, be32_to_cpu(raw_cmp_data[1].fx));
	}
	{ /* decompress the data */
		int decmp_size;
		uint8_t *decompressed_data;

		decmp_size = decompress_cmp_entiy((struct cmp_entity *)dst, NULL, NULL, NULL);
		TEST_ASSERT_EQUAL_INT(col_size, decmp_size);
		decompressed_data = malloc((size_t)decmp_size); TEST_ASSERT_TRUE(decompressed_data);
		decmp_size = decompress_cmp_entiy((struct cmp_entity *)dst, NULL, NULL, decompressed_data);
		TEST_ASSERT_EQUAL_INT(col_size, decmp_size);
		TEST_ASSERT_EQUAL_HEX8_ARRAY(col, decompressed_data, decmp_size);
		free(decompressed_data);
	}

	/* error case: buffer for the compressed data is to small */
	dst_capacity -= 1;
	TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF_,
			      cmp_get_error_code(compress_chunk(col, col_size, NULL, NULL, dst, dst_capacity, &par)));

	free(col);
	free(dst);
}


/**
 * @test compress_chunk
 * @test decompress_cmp_entiy
 */

void test_cmp_collection_diff(void)
{
	struct collection_hdr *col = NULL;
	uint32_t *dst = NULL;
	uint32_t dst_capacity = 0;
	struct cmp_par par = {0};
	const uint16_t cmp_size_byte_exp = 2;
	struct s_fx *data;
	const uint32_t samples = 2;
	const uint32_t col_size = COLLECTION_HDR_SIZE+samples*sizeof(*data);


	 /* generate test data */
	col = malloc(col_size); TEST_ASSERT_NOT_NULL(col);
	generate_random_collection_hdr(col, DATA_TYPE_S_FX, samples);
	data = (struct s_fx *)col->entry;
	data[0].exp_flags = 0;
	data[0].fx = 0;
	data[1].exp_flags = 1;
	data[1].fx = 1;


	{ /* compress data */
		uint32_t cmp_size_byte;
		const int exp_cmp_size_byte = NON_IMAGETTE_HEADER_SIZE + CMP_COLLECTION_FILD_SIZE
			+ COLLECTION_HDR_SIZE + cmp_size_byte_exp;

		par.cmp_mode = CMP_MODE_DIFF_ZERO;
		par.s_exp_flags = 1;
		par.s_fx = 1;

		cmp_size_byte = compress_chunk(col, col_size, NULL, NULL, dst, dst_capacity, &par);
		TEST_ASSERT_EQUAL_INT(exp_cmp_size_byte, cmp_size_byte);
		dst_capacity = (uint32_t)ROUND_UP_TO_MULTIPLE_OF_4(cmp_size_byte);
		dst = malloc(dst_capacity); TEST_ASSERT_NOT_NULL(dst);
		cmp_size_byte = compress_chunk(col, col_size, NULL, NULL, dst, dst_capacity, &par);
		TEST_ASSERT_EQUAL_INT(exp_cmp_size_byte, cmp_size_byte);
	}

	{ /* check the compressed data */
		uint8_t *p = (uint8_t *)dst;
		uint16_t cmp_collection_size_exp = cpu_to_be16(cmp_size_byte_exp);

		/* TODO: check the entity header */
		p += NON_IMAGETTE_HEADER_SIZE;

		TEST_ASSERT_EQUAL_HEX8_ARRAY(&cmp_collection_size_exp, p, CMP_COLLECTION_FILD_SIZE);
		p += CMP_COLLECTION_FILD_SIZE;

		TEST_ASSERT(memcmp(col, p, COLLECTION_HDR_SIZE) == 0);
		p += COLLECTION_HDR_SIZE;

		TEST_ASSERT_EQUAL_HEX8(0xAE, *p++);
		TEST_ASSERT_EQUAL_HEX8(0xE0, *p++);

		TEST_ASSERT_EQUAL_size_t(dst_capacity, p - (uint8_t *)dst);
	}
	{ /* decompress the data */
		int decmp_size;
		uint8_t *decompressed_data;

		decmp_size = decompress_cmp_entiy((struct cmp_entity *)dst, NULL, NULL, NULL);
		TEST_ASSERT_EQUAL_INT(col_size, decmp_size);
		decompressed_data = malloc((size_t)decmp_size); TEST_ASSERT_TRUE(decompressed_data);
		decmp_size = decompress_cmp_entiy((struct cmp_entity *)dst, NULL, NULL, decompressed_data);
		TEST_ASSERT_EQUAL_INT(col_size, decmp_size);
		TEST_ASSERT_EQUAL_HEX8_ARRAY(col, decompressed_data, decmp_size);
		free(decompressed_data);
	}

	/* error cases dst buffer to small */
	dst_capacity -= 1;
	TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF_, cmp_get_error_code(compress_chunk(col, col_size, NULL, NULL, dst, dst_capacity, &par)));

	free(col);
	free(dst);
}


/**
 * @test compress_chunk
 * @test decompress_cmp_entiy
 */

void test_cmp_collection_worst_case(void)
{
	struct collection_hdr *col = NULL;
	uint32_t *dst = NULL;
	uint32_t dst_capacity = 0;
	struct cmp_par par = {0};
	const uint16_t cmp_size_byte_exp = 2*sizeof(struct s_fx);
	uint32_t cmp_size_byte;
	struct s_fx *data;
	uint32_t samples = 2;
	const uint32_t col_size = COLLECTION_HDR_SIZE+samples*sizeof(*data);

	/* generate test data */
	col = malloc(col_size); TEST_ASSERT_NOT_NULL(col);
	generate_random_collection_hdr(col, DATA_TYPE_S_FX, samples);
	data = (struct s_fx *)col->entry;
	data[0].exp_flags = 0x4;
	data[0].fx = 0x0000000E;
	data[1].exp_flags = 0x4;
	data[1].fx = 0x00000016;


	{ /* compress data */
		const int exp_cmp_size_byte = NON_IMAGETTE_HEADER_SIZE + CMP_COLLECTION_FILD_SIZE
			+ COLLECTION_HDR_SIZE + cmp_size_byte_exp;

		par.cmp_mode = CMP_MODE_DIFF_ZERO;
		par.s_exp_flags = 1;
		par.s_fx = 1;

		cmp_size_byte = compress_chunk(col, col_size, NULL, NULL, dst, dst_capacity, &par);
		TEST_ASSERT_EQUAL_INT(exp_cmp_size_byte, cmp_size_byte);
		dst_capacity = (uint32_t)cmp_size_byte;
		dst = malloc(dst_capacity); TEST_ASSERT_NOT_NULL(dst);
		memset(dst, 0xFF, dst_capacity);
		cmp_size_byte = compress_chunk(col, col_size, NULL, NULL, dst, dst_capacity, &par);
		TEST_ASSERT_EQUAL_INT(exp_cmp_size_byte, cmp_size_byte);
	}

	{ /* check the compressed data */
		uint8_t *p = (uint8_t *)dst;
		uint16_t cmp_collection_size_exp = cpu_to_be16(cmp_size_byte_exp);

		/* TODO: check the entity header */
		p += NON_IMAGETTE_HEADER_SIZE;

		TEST_ASSERT_EQUAL_HEX8_ARRAY(&cmp_collection_size_exp, p, CMP_COLLECTION_FILD_SIZE);
		p += CMP_COLLECTION_FILD_SIZE;

		TEST_ASSERT(memcmp(col, p, COLLECTION_HDR_SIZE) == 0);
		p += COLLECTION_HDR_SIZE;

		TEST_ASSERT_EQUAL_HEX8(0x04, *p++);
		TEST_ASSERT_EQUAL_HEX8(0x00, *p++);
		TEST_ASSERT_EQUAL_HEX8(0x00, *p++);
		TEST_ASSERT_EQUAL_HEX8(0x00, *p++);
		TEST_ASSERT_EQUAL_HEX8(0x0E, *p++);
		TEST_ASSERT_EQUAL_HEX8(0x04, *p++);
		TEST_ASSERT_EQUAL_HEX8(0x00, *p++);
		TEST_ASSERT_EQUAL_HEX8(0x00, *p++);
		TEST_ASSERT_EQUAL_HEX8(0x00, *p++);
		TEST_ASSERT_EQUAL_HEX8(0x16, *p++);

		TEST_ASSERT_EQUAL_size_t(cmp_size_byte, p - (uint8_t *)dst);
	}
	{ /* decompress the data */
		int decmp_size;
		uint8_t *decompressed_data;

		decmp_size = decompress_cmp_entiy((struct cmp_entity *)dst, NULL, NULL, NULL);
		TEST_ASSERT_EQUAL_INT(col_size, decmp_size);
		decompressed_data = malloc((size_t)decmp_size); TEST_ASSERT_TRUE(decompressed_data);
		decmp_size = decompress_cmp_entiy((struct cmp_entity *)dst, NULL, NULL, decompressed_data);
		TEST_ASSERT_EQUAL_INT(col_size, decmp_size);
		TEST_ASSERT_EQUAL_HEX8_ARRAY(col, decompressed_data, decmp_size);
		free(decompressed_data);
	}
	free(dst);
	free(col);
}


/**
 * @test compress_chunk
 * @test decompress_cmp_entiy
 */

void test_cmp_collection_imagette_worst_case(void)
{
	struct collection_hdr *col = NULL;
	uint32_t *dst = NULL;
	struct cmp_par par = {0};
	uint16_t const cmp_size_byte_exp = 10*sizeof(uint16_t);
	uint32_t cmp_size_byte;
	uint32_t const col_size = COLLECTION_HDR_SIZE + cmp_size_byte_exp;

	{ /* generate test data */
		uint16_t *data;

		col = malloc(col_size); TEST_ASSERT_NOT_NULL(col);
		generate_random_collection_hdr(col, DATA_TYPE_IMAGETTE, 10);

		data = (void *)col->entry;
		data[0] = 0x0102;
		data[1] = 0x0304;
		data[2] = 0x0506;
		data[3] = 0x0708;
		data[4] = 0x090A;
		data[5] = 0x0B0C;
		data[6] = 0x0D0E;
		data[7] = 0x0F10;
		data[8] = 0x1112;
		data[9] = 0x1314;
	}

	{ /* compress data */
		uint32_t dst_capacity = 0;
		const int exp_cmp_size_byte = NON_IMAGETTE_HEADER_SIZE + CMP_COLLECTION_FILD_SIZE
			+ COLLECTION_HDR_SIZE + cmp_size_byte_exp;

		par.cmp_mode = CMP_MODE_DIFF_MULTI;
		par.nc_imagette = 62;

		cmp_size_byte = compress_chunk(col, col_size, NULL, NULL, dst, dst_capacity, &par);
		TEST_ASSERT_EQUAL_INT(exp_cmp_size_byte, cmp_size_byte);
		dst_capacity = (uint32_t)cmp_size_byte;
		dst = malloc(dst_capacity); TEST_ASSERT_NOT_NULL(dst);
		memset(dst, 0xFF, dst_capacity);
		cmp_size_byte = compress_chunk(col, col_size, NULL, NULL, dst, dst_capacity, &par);
		TEST_ASSERT_EQUAL_INT(exp_cmp_size_byte, cmp_size_byte);
	}

	{ /* check the compressed data */
		uint32_t i;
		uint8_t *p = (uint8_t *)dst;
		uint16_t cmp_collection_size_exp = cpu_to_be16(cmp_size_byte_exp);

		/* TODO: check the entity header */
		p += NON_IMAGETTE_HEADER_SIZE;

		TEST_ASSERT_EQUAL_HEX8_ARRAY(&cmp_collection_size_exp, p, CMP_COLLECTION_FILD_SIZE);
		p += CMP_COLLECTION_FILD_SIZE;

		TEST_ASSERT(memcmp(col, p, COLLECTION_HDR_SIZE) == 0);
		p += COLLECTION_HDR_SIZE;

		for (i = 1; i <= col_size-COLLECTION_HDR_SIZE; ++i)
			TEST_ASSERT_EQUAL_HEX8(i, *p++);

		TEST_ASSERT_EQUAL_size_t(cmp_size_byte, p - (uint8_t *)dst);
	}
	{ /* decompress the data */
		int decmp_size;
		uint8_t *decompressed_data;

		decmp_size = decompress_cmp_entiy((struct cmp_entity *)dst, NULL, NULL, NULL);
		TEST_ASSERT_EQUAL_INT(col_size, decmp_size);
		decompressed_data = malloc((size_t)decmp_size); TEST_ASSERT_TRUE(decompressed_data);
		decmp_size = decompress_cmp_entiy((struct cmp_entity *)dst, NULL, NULL, decompressed_data);
		TEST_ASSERT_EQUAL_INT(col_size, decmp_size);
		TEST_ASSERT_EQUAL_HEX8_ARRAY(col, decompressed_data, decmp_size);
		free(decompressed_data);
	}
	free(dst);
	free(col);
}


/**
 * @test compress_chunk
 * @test decompress_cmp_entiy
 */

void test_cmp_decmp_chunk_raw(void)
{
	struct cmp_par par = {0};
	struct chunk_def chunk_def[2] = {{DATA_TYPE_S_FX, 2}, {DATA_TYPE_S_FX_EFX_NCOB_ECOB, 3}};
	uint32_t chunk_size;
	size_t chunk_size_exp = 2*sizeof(struct s_fx) + 3*sizeof(struct s_fx_efx_ncob_ecob) + 2*COLLECTION_HDR_SIZE;
	void *chunk = NULL;
	uint32_t *dst = NULL;
	uint32_t dst_capacity = 0;

	/* generate test data */
	chunk_size = generate_random_chunk(chunk, chunk_def, ARRAY_SIZE(chunk_def), &MAX_USED_BITS_SAFE);
	TEST_ASSERT_EQUAL_size_t(chunk_size_exp, chunk_size);
	chunk = calloc(1, chunk_size);
	TEST_ASSERT_NOT_NULL(chunk);
	chunk_size = generate_random_chunk(chunk, chunk_def, ARRAY_SIZE(chunk_def), &MAX_USED_BITS_SAFE);
	TEST_ASSERT_EQUAL_size_t(chunk_size_exp, chunk_size);

	/* "compress" data */
	{
		size_t cmp_size_exp = GENERIC_HEADER_SIZE + chunk_size_exp;
		uint32_t cmp_size;

		par.cmp_mode = CMP_MODE_RAW;

		cmp_size = compress_chunk(chunk, chunk_size, NULL, NULL, dst, dst_capacity, &par);
		TEST_ASSERT_EQUAL_INT(cmp_size_exp, cmp_size);
		dst_capacity = (uint32_t)cmp_size;
		dst = malloc(dst_capacity); TEST_ASSERT_NOT_NULL(dst);
		cmp_size = compress_chunk(chunk, chunk_size, NULL, NULL, dst, dst_capacity, &par);
		TEST_ASSERT_EQUAL_INT(cmp_size_exp, dst_capacity);
	}

	/* check results */
	{
		uint8_t *p = (uint8_t *)dst;
		struct collection_hdr *col = (struct collection_hdr *)chunk;
		struct s_fx *cmp_data_raw_1;
		struct s_fx *data = (void *)col->entry;
		int i;

		/* TODO: Check entity header */
		TEST_ASSERT_EQUAL_HEX(chunk_size, cmp_ent_get_original_size((struct cmp_entity *)dst));
		TEST_ASSERT_EQUAL_HEX(chunk_size+GENERIC_HEADER_SIZE, cmp_ent_get_size((struct cmp_entity *)dst));

		p += GENERIC_HEADER_SIZE;

		TEST_ASSERT(memcmp(col, p, COLLECTION_HDR_SIZE) == 0);
		p += COLLECTION_HDR_SIZE;

		cmp_data_raw_1 = (struct s_fx *)p;
		TEST_ASSERT_EQUAL_HEX(data[0].exp_flags, cmp_data_raw_1[0].exp_flags);
		TEST_ASSERT_EQUAL_HEX(data[0].fx, be32_to_cpu(cmp_data_raw_1[0].fx));
		TEST_ASSERT_EQUAL_HEX(data[1].exp_flags, cmp_data_raw_1[1].exp_flags);
		TEST_ASSERT_EQUAL_HEX(data[1].fx, be32_to_cpu(cmp_data_raw_1[1].fx));
		p += 2*sizeof(struct s_fx);

		/* check 2nd collection */
		col = (struct collection_hdr *) ((char *)col + cmp_col_get_size(col));
		TEST_ASSERT(memcmp(col, p, COLLECTION_HDR_SIZE) == 0);
		p += COLLECTION_HDR_SIZE;

		for (i = 0; i < 3; i++) {
			struct s_fx_efx_ncob_ecob *raw_cmp_data2 = (struct s_fx_efx_ncob_ecob *)p;
			struct s_fx_efx_ncob_ecob *data2 = (struct s_fx_efx_ncob_ecob *)col->entry;

			TEST_ASSERT_EQUAL_HEX(data2[i].exp_flags, raw_cmp_data2[i].exp_flags);
			TEST_ASSERT_EQUAL_HEX(data2[i].fx, be32_to_cpu(raw_cmp_data2[i].fx));
			TEST_ASSERT_EQUAL_HEX(data2[i].efx, be32_to_cpu(raw_cmp_data2[i].efx));
			TEST_ASSERT_EQUAL_HEX(data2[i].ncob_x, be32_to_cpu(raw_cmp_data2[i].ncob_x));
			TEST_ASSERT_EQUAL_HEX(data2[i].ncob_y, be32_to_cpu(raw_cmp_data2[i].ncob_y));
			TEST_ASSERT_EQUAL_HEX(data2[i].ecob_x, be32_to_cpu(raw_cmp_data2[i].ecob_x));
			TEST_ASSERT_EQUAL_HEX(data2[i].ecob_y, be32_to_cpu(raw_cmp_data2[i].ecob_y));
		}
	}
	{
		void *decompressed_data = NULL;
		int decmp_size = decompress_cmp_entiy((void *)dst, NULL, NULL, decompressed_data);
		TEST_ASSERT_EQUAL_size_t(chunk_size, decmp_size);

		decompressed_data = malloc((size_t)decmp_size); TEST_ASSERT_NOT_NULL(decompressed_data);
		decmp_size = decompress_cmp_entiy((void *)dst, NULL, NULL, decompressed_data);

		TEST_ASSERT_EQUAL_INT(chunk_size, decmp_size);
		TEST_ASSERT_EQUAL_HEX8_ARRAY(chunk, decompressed_data, chunk_size);
		free(decompressed_data);
	}
	{ /* error case: buffer to small for compressed data */
		uint32_t cmp_size;

		dst_capacity -= 1;
		cmp_size = compress_chunk(chunk, chunk_size, NULL, NULL, dst, dst_capacity, &par);
		TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF_, cmp_get_error_code(cmp_size));
	}

	free(dst);
	free(chunk);
}


void test_cmp_decmp_chunk_worst_case(void)
{
	struct chunk_def chunk_def[2] = {{DATA_TYPE_S_FX, 2}, {DATA_TYPE_S_FX_EFX_NCOB_ECOB, 3}};
	enum {CHUNK_SIZE_EXP = 2*sizeof(struct s_fx) + 3*sizeof(struct s_fx_efx_ncob_ecob) + 2*COLLECTION_HDR_SIZE};
	uint32_t chunk_size = CHUNK_SIZE_EXP;
	void *chunk = NULL;
	uint32_t dst[COMPRESS_CHUNK_BOUND(CHUNK_SIZE_EXP, ARRAY_SIZE(chunk_def))/sizeof(uint32_t)];
	uint32_t cmp_size_byte = 0;
	struct cmp_par par = {0};

	{ /* generate test data */
		uint16_t s;
		uint8_t *p, i;

		chunk = malloc(chunk_size); TEST_ASSERT_NOT_NULL(chunk);
		generate_random_collection_hdr(chunk, DATA_TYPE_S_FX, 2);
		p = chunk;
		p += COLLECTION_HDR_SIZE;
		for (i = 0; i < cmp_col_get_data_length(chunk); i++)
			*p++ = i;
		generate_random_collection_hdr((struct collection_hdr *)p, DATA_TYPE_S_FX_EFX_NCOB_ECOB, 3);
		s = cmp_col_get_data_length((struct collection_hdr *)p);
		p += COLLECTION_HDR_SIZE;
		for (i = 0; i < s; i++)
			*p++ = i;
	}


	{ /* "compress" data */
		size_t cmp_size_byte_exp = NON_IMAGETTE_HEADER_SIZE + 2*CMP_COLLECTION_FILD_SIZE + CHUNK_SIZE_EXP;

		par.cmp_mode = CMP_MODE_DIFF_ZERO;
		par.s_exp_flags = 1;
		par.s_fx = 1;
		par.s_efx = 1;
		par.s_ncob = 1;
		par.s_ecob = 1;


		TEST_ASSERT_NOT_NULL(dst);
		cmp_size_byte = compress_chunk(chunk, chunk_size, NULL, NULL, dst, sizeof(dst), &par);
		TEST_ASSERT_EQUAL_INT(cmp_size_byte_exp, cmp_size_byte);
	}

	{ /* check results */
		uint8_t *p = (uint8_t *)dst;
		uint16_t cmp_collection_size_exp = cpu_to_be16(2*sizeof(struct s_fx));
		struct collection_hdr *col = (struct collection_hdr *)chunk;
		struct s_fx *cmp_data_raw_1;
		struct s_fx *data = (void *)col->entry;
		int i;

		/* TODO: Check entity header */
		p += NON_IMAGETTE_HEADER_SIZE;

		TEST_ASSERT_EQUAL_HEX8_ARRAY(&cmp_collection_size_exp, p, CMP_COLLECTION_FILD_SIZE);
		p += CMP_COLLECTION_FILD_SIZE;

		TEST_ASSERT(memcmp(col, p, COLLECTION_HDR_SIZE) == 0);
		p += COLLECTION_HDR_SIZE;

		cmp_data_raw_1 = (struct s_fx *)p;
		TEST_ASSERT_EQUAL_HEX(data[0].exp_flags, cmp_data_raw_1[0].exp_flags);
		TEST_ASSERT_EQUAL_HEX(data[0].fx, be32_to_cpu(cmp_data_raw_1[0].fx));
		TEST_ASSERT_EQUAL_HEX(data[1].exp_flags, cmp_data_raw_1[1].exp_flags);
		TEST_ASSERT_EQUAL_HEX(data[1].fx, be32_to_cpu(cmp_data_raw_1[1].fx));
		p += 2*sizeof(struct s_fx);

		/* check 2nd collection */
		cmp_collection_size_exp = cpu_to_be16(3*sizeof(struct s_fx_efx_ncob_ecob));
		TEST_ASSERT(memcmp(p, &cmp_collection_size_exp, CMP_COLLECTION_FILD_SIZE) == 0);
		p += CMP_COLLECTION_FILD_SIZE;

		col = (struct collection_hdr *) ((char *)col + cmp_col_get_size(col));
		TEST_ASSERT(memcmp(col, p, COLLECTION_HDR_SIZE) == 0);
		p += COLLECTION_HDR_SIZE;

		for (i = 0; i < 3; i++) {
			struct s_fx_efx_ncob_ecob *raw_cmp_data2 = (struct s_fx_efx_ncob_ecob *)p;
			struct s_fx_efx_ncob_ecob *data2 = (struct s_fx_efx_ncob_ecob *)col->entry;

			TEST_ASSERT_EQUAL_HEX(data2[i].exp_flags, raw_cmp_data2[i].exp_flags);
			TEST_ASSERT_EQUAL_HEX(data2[i].fx, be32_to_cpu(raw_cmp_data2[i].fx));
			TEST_ASSERT_EQUAL_HEX(data2[i].efx, be32_to_cpu(raw_cmp_data2[i].efx));
			TEST_ASSERT_EQUAL_HEX(data2[i].ncob_x, be32_to_cpu(raw_cmp_data2[i].ncob_x));
			TEST_ASSERT_EQUAL_HEX(data2[i].ncob_y, be32_to_cpu(raw_cmp_data2[i].ncob_y));
			TEST_ASSERT_EQUAL_HEX(data2[i].ecob_x, be32_to_cpu(raw_cmp_data2[i].ecob_x));
			TEST_ASSERT_EQUAL_HEX(data2[i].ecob_y, be32_to_cpu(raw_cmp_data2[i].ecob_y));
		}
	}
	{
		void *decompressed_data = NULL;
		int decmp_size = decompress_cmp_entiy((void *)dst, NULL, NULL, decompressed_data);

		TEST_ASSERT_EQUAL_size_t(chunk_size, decmp_size);
		decompressed_data = malloc((size_t)decmp_size); TEST_ASSERT_NOT_NULL(decompressed_data);
		decmp_size = decompress_cmp_entiy((void *)dst, NULL, NULL, decompressed_data);

		TEST_ASSERT_EQUAL_INT(chunk_size, decmp_size);
		TEST_ASSERT_EQUAL_HEX8_ARRAY(chunk, decompressed_data, chunk_size);
		free(decompressed_data);
	}

	/* error case: buffer to small for compressed data */
	cmp_size_byte = compress_chunk(chunk, chunk_size, NULL, NULL, dst, chunk_size, &par);
	TEST_ASSERT_EQUAL_INT(CMP_ERROR_SMALL_BUF_, cmp_get_error_code(cmp_size_byte));

	free(chunk);
}


void test_cmp_decmp_diff(void)
{
	struct chunk_def chunk_def[2] = {{DATA_TYPE_S_FX, 2}, {DATA_TYPE_S_FX_EFX_NCOB_ECOB, 3}};
	uint32_t chunk_size;
	void *chunk = NULL;
	uint32_t *dst = NULL;

	{ /* generate test data */
		struct s_fx *col_data1;
		struct s_fx_efx_ncob_ecob *col_data2;
		struct collection_hdr *col;
		size_t chunk_size_exp = 2*sizeof(struct s_fx) + 3*sizeof(struct s_fx_efx_ncob_ecob) + 2*COLLECTION_HDR_SIZE;

		chunk_size = generate_random_chunk(chunk, chunk_def, ARRAY_SIZE(chunk_def), &MAX_USED_BITS_SAFE);
		TEST_ASSERT_EQUAL_size_t(chunk_size_exp, chunk_size);
		chunk = calloc(1, chunk_size);
		TEST_ASSERT_NOT_NULL(chunk);
		chunk_size = generate_random_chunk(chunk, chunk_def, ARRAY_SIZE(chunk_def), &MAX_USED_BITS_SAFE);
		TEST_ASSERT_EQUAL_size_t(chunk_size_exp, chunk_size);

		col = (struct collection_hdr *)chunk;
		col_data1 = (struct s_fx *)(col->entry);
		col_data1[0].exp_flags = 0;
		col_data1[0].fx = 0;
		col_data1[1].exp_flags = 1;
		col_data1[1].fx = 1;

		col = (struct collection_hdr *)((char *)col + cmp_col_get_size(col));
		col_data2 = (struct s_fx_efx_ncob_ecob *)(col->entry);
		col_data2[0].exp_flags = 0;
		col_data2[0].fx = 1;
		col_data2[0].efx = 2;
		col_data2[0].ncob_x = 0;
		col_data2[0].ncob_y = 1;
		col_data2[0].ecob_x = 3;
		col_data2[0].ecob_y = 7;
		col_data2[1].exp_flags = 1;
		col_data2[1].fx = 1;
		col_data2[1].efx = 1;
		col_data2[1].ncob_x = 1;
		col_data2[1].ncob_y = 2;
		col_data2[1].ecob_x = 1;
		col_data2[1].ecob_y = 1;
		col_data2[2].exp_flags = 2;
		col_data2[2].fx = 2;
		col_data2[2].efx = 2;
		col_data2[2].ncob_x = 2;
		col_data2[2].ncob_y = 45;
		col_data2[2].ecob_x = 2;
		col_data2[2].ecob_y = 2;
	}

	{ /* compress data */
		struct cmp_par par = {0};
		uint32_t dst_capacity = 0;
		uint32_t cmp_size;

		par.cmp_mode = CMP_MODE_DIFF_ZERO;
		par.s_exp_flags = 1;
		par.s_fx = 2;
		par.s_efx = 3;
		par.s_ncob = 4;
		par.s_ecob = 5;


		cmp_size = compress_chunk(chunk, chunk_size, NULL, NULL, dst, dst_capacity, &par);
		TEST_ASSERT_GREATER_THAN_INT(0, cmp_size);
		dst_capacity = (uint32_t)ROUND_UP_TO_MULTIPLE_OF_4(cmp_size);
		dst = malloc(dst_capacity);
		TEST_ASSERT_NOT_NULL(dst);
		cmp_size = compress_chunk(chunk, chunk_size, NULL, NULL, dst, dst_capacity, &par);
		TEST_ASSERT_GREATER_THAN_INT(0, cmp_size);
	}
	{
		void *decompressed_data = NULL;
		int decmp_size = decompress_cmp_entiy((void *)dst, NULL, NULL,
						      decompressed_data);
		TEST_ASSERT_EQUAL_size_t(chunk_size, decmp_size);
		decompressed_data = malloc((size_t)decmp_size); TEST_ASSERT_NOT_NULL(decompressed_data);
		decmp_size = decompress_cmp_entiy((void *)dst, NULL, NULL,
						  decompressed_data);

		TEST_ASSERT_EQUAL_INT(chunk_size, decmp_size);
		TEST_ASSERT_EQUAL_HEX8_ARRAY(chunk, decompressed_data, chunk_size);
		free(decompressed_data);
	}
	free(dst);
	free(chunk);
}