From 7ee4798b5700e7696c9e51df6c06a8bfb9e8e322 Mon Sep 17 00:00:00 2001
From: Dominik Loidolt <dominik.loidolt@univie.ac.at>
Date: Mon, 26 Sep 2022 11:59:12 +0200
Subject: [PATCH] Add compression decompression test

---
 test/cmp_icu/meson.build      |  18 +-
 test/cmp_icu/test_cmp_decmp.c | 614 ++++++++++++++++++++++++++++++++++
 test/meson.build              |   1 +
 3 files changed, 631 insertions(+), 2 deletions(-)
 create mode 100644 test/cmp_icu/test_cmp_decmp.c

diff --git a/test/cmp_icu/meson.build b/test/cmp_icu/meson.build
index 405d376..7c9b356 100644
--- a/test/cmp_icu/meson.build
+++ b/test/cmp_icu/meson.build
@@ -12,10 +12,24 @@ test_cmp_icu = executable('test_cmp_icu',
 test('cmp_icu Unit Tests', test_cmp_icu)
 
 
+test_case = files('test_cmp_decmp.c')
+test_runner = test_runner_generator.process(test_case)
+
+test_cmp_decmp = executable('test_cmp_decmp',
+   test_case, test_runner,
+   include_directories : incdir,
+   link_with : cmp_lib,
+   dependencies : unity_dep,
+   build_by_default : false
+)
+
+test('Compression Decompression Unit Tests', test_cmp_decmp)
+
+
 test_case = files('test_decmp.c')
 test_runner = test_runner_generator.process(test_case)
 
-test_cmp_decomp = executable('test_cmp_decomp',
+test_decmp = executable('test_decmp',
    test_case, test_runner,
    include_directories : incdir,
    link_with : cmp_lib,
@@ -23,4 +37,4 @@ test_cmp_decomp = executable('test_cmp_decomp',
    build_by_default : false
 )
 
-test('Compression Decompression Unit Tests', test_cmp_decomp)
+test('Decompression Unit Tests', test_decmp)
diff --git a/test/cmp_icu/test_cmp_decmp.c b/test/cmp_icu/test_cmp_decmp.c
new file mode 100644
index 0000000..e961ffc
--- /dev/null
+++ b/test/cmp_icu/test_cmp_decmp.c
@@ -0,0 +1,614 @@
+/**
+ * @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 test
+ * @detail We generate random 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.
+ */
+
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <unity.h>
+
+#include <cmp_icu.h>
+#include <decmp.h>
+#include <cmp_data_types.h>
+
+#if defined __has_include
+#  if __has_include(<time.h>)
+#    include <time.h>
+#    include <unistd.h>
+#    define HAS_TIME_H 1
+#  endif
+#endif
+
+#define IMAX_BITS(m) ((m)/((m)%255+1) / 255%255*8 + 7-86/((m)%255+12))
+#define RAND_MAX_WIDTH IMAX_BITS(RAND_MAX)
+
+#define set_n_bits(n)  (~(~0UL << (n)))
+
+
+/**
+ * @brief  Seeds the pseudo-random number generator used by rand()
+ */
+
+void setUp(void)
+{
+	unsigned int seed;
+	static int n;
+
+#if HAS_TIME_H
+	seed = time(NULL) * getpid();
+#else
+	seed = 1;
+#endif
+
+	if (!n) {
+		n = 1;
+		srand(seed);
+		printf("seed: %u\n", seed);
+	}
+}
+
+
+/**
+ * @brief generate a uint32_t random number
+ *
+ * @return a "random" uint32_t value
+ * @see https://stackoverflow.com/a/33021408
+ */
+
+uint32_t rand32(void)
+{
+	int i;
+	uint32_t r = 0;
+
+	for (i = 0; i < 32; i += RAND_MAX_WIDTH) {
+		r <<= RAND_MAX_WIDTH;
+		r ^= (unsigned int) rand();
+	}
+	return r;
+}
+
+
+/**
+ * @brief generate a random number in a range
+ *
+ * @param min minimum value (inclusive)
+ * @param max maximum value (inclusive)
+ *
+ * @returns "random" numbers in the range [min, max]
+ *
+ * @see https://c-faq.com/lib/randrange.html
+ */
+
+uint32_t random_between(unsigned int min, unsigned int max)
+{
+	TEST_ASSERT(min < max);
+	if (max-min < RAND_MAX)
+		return min + rand() / (RAND_MAX / (max - min + 1ULL) + 1);
+	else
+		return min + rand32() / (UINT32_MAX / (max - min + 1ULL) + 1);
+}
+
+
+static void gen_ima_data(uint16_t *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i] = random_between(0, set_n_bits(max_used_bits.nc_imagette));
+	}
+}
+
+
+static void gen_offset_data(struct nc_offset *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].mean = random_between(0, set_n_bits(max_used_bits.nc_offset_mean));
+		data[i].variance = random_between(0, set_n_bits(max_used_bits.nc_offset_variance));
+	}
+}
+
+
+static void gen_background_data(struct nc_background *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].mean = random_between(0, set_n_bits(max_used_bits.nc_background_mean));
+		data[i].variance = random_between(0, set_n_bits(max_used_bits.nc_background_variance));
+		data[i].outlier_pixels = random_between(0, set_n_bits(max_used_bits.nc_background_outlier_pixels));
+	}
+}
+
+
+static void gen_smearing_data(struct smearing *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].mean = random_between(0, set_n_bits(max_used_bits.smearing_mean));
+		data[i].variance_mean = random_between(0, set_n_bits(max_used_bits.smearing_variance_mean));
+		data[i].outlier_pixels = random_between(0, set_n_bits(max_used_bits.smearing_outlier_pixels));
+	}
+}
+
+
+static void gen_s_fx_data(struct s_fx *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.s_exp_flags));
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.s_fx));
+	}
+}
+
+
+static void gen_s_fx_efx_data(struct s_fx_efx *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.s_exp_flags));
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.s_fx));
+		data[i].efx = random_between(0, set_n_bits(max_used_bits.s_efx));
+	}
+}
+
+
+static void gen_s_fx_ncob_data(struct s_fx_ncob *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.s_exp_flags));
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.s_fx));
+		data[i].ncob_x = random_between(0, set_n_bits(max_used_bits.s_ncob));
+		data[i].ncob_y = random_between(0, set_n_bits(max_used_bits.s_ncob));
+	}
+}
+
+
+static void gen_s_fx_efx_ncob_ecob_data(struct s_fx_efx_ncob_ecob *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.s_exp_flags));
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.s_fx));
+		data[i].ncob_x = random_between(0, set_n_bits(max_used_bits.s_ncob));
+		data[i].ncob_y = random_between(0, set_n_bits(max_used_bits.s_ncob));
+		data[i].efx = random_between(0, set_n_bits(max_used_bits.s_efx));
+		data[i].ecob_x = random_between(0, set_n_bits(max_used_bits.s_ecob));
+		data[i].ecob_y = random_between(0, set_n_bits(max_used_bits.s_ecob));
+	}
+}
+
+
+static void gen_f_fx_data(struct f_fx *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.f_fx));
+	}
+}
+
+
+static void gen_f_fx_efx_data(struct f_fx_efx *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.f_fx));
+		data[i].efx = random_between(0, set_n_bits(max_used_bits.f_efx));
+	}
+}
+
+
+static void gen_f_fx_ncob_data(struct f_fx_ncob *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.f_fx));
+		data[i].ncob_x = random_between(0, set_n_bits(max_used_bits.f_ncob));
+		data[i].ncob_y = random_between(0, set_n_bits(max_used_bits.f_ncob));
+	}
+}
+
+
+static void gen_f_fx_efx_ncob_ecob_data(struct f_fx_efx_ncob_ecob *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.f_fx));
+		data[i].ncob_x = random_between(0, set_n_bits(max_used_bits.f_ncob));
+		data[i].ncob_y = random_between(0, set_n_bits(max_used_bits.f_ncob));
+		data[i].efx = random_between(0, set_n_bits(max_used_bits.f_efx));
+		data[i].ecob_x = random_between(0, set_n_bits(max_used_bits.f_ecob));
+		data[i].ecob_y = random_between(0, set_n_bits(max_used_bits.f_ecob));
+	}
+}
+
+
+static void gen_l_fx_data(struct l_fx *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.l_exp_flags));
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.l_fx));
+		data[i].fx_variance = random_between(0, set_n_bits(max_used_bits.l_fx_variance));
+	}
+}
+
+
+static void gen_l_fx_efx_data(struct l_fx_efx *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.l_exp_flags));
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.l_fx));
+		data[i].efx = random_between(0, set_n_bits(max_used_bits.l_efx));
+		data[i].fx_variance = random_between(0, set_n_bits(max_used_bits.l_fx_variance));
+	}
+}
+
+
+static void gen_l_fx_ncob_data(struct l_fx_ncob *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.l_exp_flags));
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.l_fx));
+		data[i].ncob_x = random_between(0, set_n_bits(max_used_bits.l_ncob));
+		data[i].ncob_y = random_between(0, set_n_bits(max_used_bits.l_ncob));
+		data[i].fx_variance = random_between(0, set_n_bits(max_used_bits.l_fx_variance));
+		data[i].cob_x_variance = random_between(0, set_n_bits(max_used_bits.l_cob_variance));
+		data[i].cob_y_variance = random_between(0, set_n_bits(max_used_bits.l_cob_variance));
+	}
+}
+
+
+static void gen_l_fx_efx_ncob_ecob_data(struct l_fx_efx_ncob_ecob *data, uint32_t samples)
+{
+	uint32_t i;
+	struct cmp_max_used_bits max_used_bits = cmp_get_max_used_bits();
+
+	for (i = 0; i < samples; i++) {
+		data[i].exp_flags = random_between(0, set_n_bits(max_used_bits.l_exp_flags));
+		data[i].fx = random_between(0, set_n_bits(max_used_bits.l_fx));
+		data[i].ncob_x = random_between(0, set_n_bits(max_used_bits.l_ncob));
+		data[i].ncob_y = random_between(0, set_n_bits(max_used_bits.l_ncob));
+		data[i].efx = random_between(0, set_n_bits(max_used_bits.l_efx));
+		data[i].ecob_x = random_between(0, set_n_bits(max_used_bits.l_ecob));
+		data[i].ecob_y = random_between(0, set_n_bits(max_used_bits.l_ecob));
+		data[i].fx_variance = random_between(0, set_n_bits(max_used_bits.l_fx_variance));
+		data[i].cob_x_variance = random_between(0, set_n_bits(max_used_bits.l_cob_variance));
+		data[i].cob_y_variance = random_between(0, set_n_bits(max_used_bits.l_cob_variance));
+	}
+}
+
+
+/**
+ * @brief generate random test data
+ *
+ * @param samples	number of random test samples
+ * @param data_type	compression data type of the test data
+ *
+ * @returns a pointer to the generated random test data
+ */
+
+void *generate_random_test_data(uint32_t samples, enum cmp_data_type data_type)
+{
+	size_t data_size = cmp_cal_size_of_data(samples, data_type);
+	void *data = malloc(data_size);
+	void *data_cpy = data;
+	uint8_t *p = data;
+
+	TEST_ASSERT_NOT_EQUAL_INT(data_size, 0);
+	TEST_ASSERT(data_size < (CMP_ENTITY_MAX_SIZE - NON_IMAGETTE_HEADER_SIZE));
+	TEST_ASSERT_NOT_NULL(data);
+
+	if (!rdcu_supported_data_type_is_used(data_type)) {
+		int i;
+		TEST_ASSERT(data_size > MULTI_ENTRY_HDR_SIZE);
+		for (i = 0; i < MULTI_ENTRY_HDR_SIZE; ++i) {
+			*p++ = random_between(0, UINT8_MAX);
+		}
+		data = p;
+	}
+
+	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:
+		gen_ima_data(data, samples);
+		break;
+	case DATA_TYPE_OFFSET:
+		gen_offset_data(data, samples);
+		break;
+	case DATA_TYPE_BACKGROUND:
+		gen_background_data(data, samples);
+		break;
+	case DATA_TYPE_SMEARING:
+		gen_smearing_data(data, samples);
+		break;
+	case DATA_TYPE_S_FX:
+		gen_s_fx_data(data, samples);
+		break;
+	case DATA_TYPE_S_FX_EFX:
+		gen_s_fx_efx_data(data, samples);
+		break;
+	case DATA_TYPE_S_FX_NCOB:
+		gen_s_fx_ncob_data(data, samples);
+		break;
+	case DATA_TYPE_S_FX_EFX_NCOB_ECOB:
+		gen_s_fx_efx_ncob_ecob_data(data, samples);
+		break;
+	case DATA_TYPE_L_FX:
+		gen_l_fx_data(data, samples);
+		break;
+	case DATA_TYPE_L_FX_EFX:
+		gen_l_fx_efx_data(data, samples);
+		break;
+	case DATA_TYPE_L_FX_NCOB:
+		gen_l_fx_ncob_data(data, samples);
+		break;
+	case DATA_TYPE_L_FX_EFX_NCOB_ECOB:
+		gen_l_fx_efx_ncob_ecob_data(data, samples);
+		break;
+	case DATA_TYPE_F_FX:
+		gen_f_fx_data(data, samples);
+		break;
+	case DATA_TYPE_F_FX_EFX:
+		gen_f_fx_efx_data(data, samples);
+		break;
+	case DATA_TYPE_F_FX_NCOB:
+		gen_f_fx_ncob_data(data, samples);
+		break;
+	case DATA_TYPE_F_FX_EFX_NCOB_ECOB:
+		gen_f_fx_efx_ncob_ecob_data(data, samples);
+		break;
+	case DATA_TYPE_F_CAM_OFFSET: /* TODO: implement this */
+	case DATA_TYPE_F_CAM_BACKGROUND: /* TODO: implement this */
+	default:
+		TEST_FAIL();
+	}
+
+	return data_cpy;
+}
+
+
+/**
+ * @brief generate random compression configuration
+ *
+ * @param cfg	pointer to a compression configuration
+ *
+ */
+
+void generate_random_cmp_par(struct cmp_cfg *cfg)
+{
+	cfg->golomb_par = random_between(MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR);
+	cfg->ap1_golomb_par = random_between(MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR);
+	cfg->ap2_golomb_par = random_between(MIN_IMA_GOLOMB_PAR, MAX_IMA_GOLOMB_PAR);
+
+	cfg->cmp_par_exp_flags = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+	cfg->cmp_par_fx = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+	cfg->cmp_par_ncob = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+	cfg->cmp_par_efx = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+	cfg->cmp_par_ecob = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+	cfg->cmp_par_fx_cob_variance = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+	cfg->cmp_par_mean = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+	cfg->cmp_par_variance = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+	cfg->cmp_par_pixels_error = random_between(MIN_ICU_GOLOMB_PAR, MAX_ICU_GOLOMB_PAR);
+
+
+	cfg->spill = random_between(MIN_IMA_SPILL, cmp_ima_max_spill(cfg->golomb_par));
+	cfg->ap1_spill = random_between(MIN_IMA_SPILL, cmp_ima_max_spill(cfg->ap1_golomb_par));
+	cfg->ap2_spill = random_between(MIN_IMA_SPILL, cmp_ima_max_spill(cfg->ap2_golomb_par));
+
+	cfg->spill_exp_flags = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_exp_flags));
+	cfg->spill_fx = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_fx));
+	cfg->spill_ncob = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_ncob));
+	cfg->spill_efx = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_efx));
+	cfg->spill_ecob = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_ecob));
+	cfg->spill_fx_cob_variance = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_fx_cob_variance));
+	cfg->spill_mean = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_mean));
+	cfg->spill_variance = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_variance));
+	cfg->spill_pixels_error = random_between(MIN_ICU_SPILL, cmp_icu_max_spill(cfg->cmp_par_pixels_error));
+#if 0
+	if (cfg->cmp_mode == CMP_MODE_STUFF) {
+		/* cfg->golomb_par = random_between(16, MAX_STUFF_CMP_PAR); */
+		cfg->golomb_par = 16;
+		cfg->ap1_golomb_par = random_between(0, MAX_STUFF_CMP_PAR);
+		cfg->ap2_golomb_par = random_between(0, MAX_STUFF_CMP_PAR);
+		cfg->cmp_par_exp_flags = random_between(0, MAX_STUFF_CMP_PAR);
+		cfg->cmp_par_fx = random_between(0, MAX_STUFF_CMP_PAR);
+		cfg->cmp_par_ncob = random_between(0, MAX_STUFF_CMP_PAR);
+		cfg->cmp_par_efx = random_between(0, MAX_STUFF_CMP_PAR);
+		cfg->cmp_par_ecob = random_between(0, MAX_STUFF_CMP_PAR);
+		cfg->cmp_par_fx_cob_variance = random_between(0, MAX_STUFF_CMP_PAR);
+		cfg->cmp_par_mean = random_between(0, MAX_STUFF_CMP_PAR);
+		cfg->cmp_par_variance = random_between(0, MAX_STUFF_CMP_PAR);
+		cfg->cmp_par_pixels_error = random_between(0, MAX_STUFF_CMP_PAR);
+		return;
+	}
+#endif
+}
+
+
+/**
+ * @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;
+	int data_size, cmp_data_size;
+	struct cmp_entity *ent;
+	void *decompressed_data;
+	static void *model_of_data;
+	void *updated_model = NULL;
+
+	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 &= ~0x3; /* the size of the compressed data should be a multiple of 4 */
+	TEST_ASSERT_NOT_EQUAL_INT(0, cmp_data_size);
+
+	s = cmp_ent_create(NULL, cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW, cmp_data_size);
+	TEST_ASSERT_NOT_EQUAL_INT(0, s);
+	ent = malloc(s); TEST_ASSERT_TRUE(ent);
+	s = cmp_ent_create(ent, cfg->data_type, cfg->cmp_mode == CMP_MODE_RAW, cmp_data_size);
+	TEST_ASSERT_NOT_EQUAL_INT(0, s);
+
+	/* we put the coompressed 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 */
+	error = cmp_ent_write_cmp_pars(ent, cfg, cmp_size_bits);
+	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(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);
+}
+
+
+#define CMP_BUFFER_FAKTOR 3 /* compression data buffer size / data to compress buffer size */
+
+/**
+ * @brief random compression decompression test
+ * @detail We generate random 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_compression_decompression(void)
+{
+	enum cmp_data_type data_type;
+	enum cmp_mode cmp_mode;
+	struct cmp_cfg cfg;
+	int cmp_buffer_size;
+
+	/* TODO: extend test for DATA_TYPE_F_CAM_BACKGROUND, DATA_TYPE_F_CAM_OFFSET  */
+	for (data_type = 1; data_type <= DATA_TYPE_F_CAM_IMAGETTE_ADAPTIVE; data_type++) {
+		/* printf("%s\n", data_type2string(data_type)); */
+		/* generate random data*/
+		uint32_t samples = random_between(1, 430179/CMP_BUFFER_FAKTOR);
+		uint32_t model_value = random_between(0, MAX_MODEL_VALUE);
+		void *data_to_compress1 = generate_random_test_data(samples, data_type);
+		void *data_to_compress2 = generate_random_test_data(samples, data_type);
+		void *updated_model = calloc(1, cmp_cal_size_of_data(samples, data_type));
+		/* for (cmp_mode = CMP_MODE_RAW; cmp_mode <= CMP_MODE_STUFF; cmp_mode++) { */
+		for (cmp_mode = CMP_MODE_RAW; cmp_mode < CMP_MODE_STUFF; 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_par(&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_INT(cmp_buffer_size, cmp_cal_size_of_data(CMP_BUFFER_FAKTOR*samples, data_type));
+
+			compression_decompression(&cfg);
+		}
+		free(data_to_compress1);
+		free(data_to_compress2);
+		free(updated_model);
+	}
+}
diff --git a/test/meson.build b/test/meson.build
index 145cdb8..11ddac0 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -38,3 +38,4 @@ unity_dep = dependency('unity', fallback : ['unity', 'unity_dep'])
 
 subdir('cmp_icu')
 subdir('cmp_data_types')
+subdir('cmp_entity')
-- 
GitLab