Select Git revision
test_cmp_decmp.c
test_cmp_decmp.c 53.53 KiB
/**
* @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 <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>
#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) + 3) & ~3)
/**
* @brief Seeds the pseudo-random number generator
*/
void setUp(void)
{
uint64_t seed;
static int n;
#if HAS_TIME_H
seed = (uint64_t)(time(NULL) ^ getpid() ^ (intptr_t)&setUp);
#else
seed = 1;
#endif
if (!n) {
n = 1;
cmp_rand_seed(seed);
printf("seed: %"PRIu64"\n", seed);
}
}
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();
}
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));
}
#if 0
if (cfg->cmp_mode == CMP_MODE_STUFF) {
/* cfg->golomb_par = cmp_rand_between(16, MAX_STUFF_CMP_PAR); */
cfg->golomb_par = 16;
cfg->ap1_golomb_par = cmp_rand_between(0, MAX_STUFF_CMP_PAR);
cfg->ap2_golomb_par = cmp_rand_between(0, MAX_STUFF_CMP_PAR);
cfg->cmp_par_exp_flags = cmp_rand_between(0, MAX_STUFF_CMP_PAR);
cfg->cmp_par_fx = cmp_rand_between(0, MAX_STUFF_CMP_PAR);
cfg->cmp_par_ncob = cmp_rand_between(0, MAX_STUFF_CMP_PAR);
cfg->cmp_par_efx = cmp_rand_between(0, MAX_STUFF_CMP_PAR);
cfg->cmp_par_ecob = cmp_rand_between(0, MAX_STUFF_CMP_PAR);
cfg->cmp_par_fx_cob_variance = cmp_rand_between(0, MAX_STUFF_CMP_PAR);
cfg->cmp_par_mean = cmp_rand_between(0, MAX_STUFF_CMP_PAR);
cfg->cmp_par_variance = cmp_rand_between(0, MAX_STUFF_CMP_PAR);
cfg->cmp_par_pixels_error = cmp_rand_between(0, MAX_STUFF_CMP_PAR);
return;
}
#endif
}
/**
* @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 int32_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)
{
int32_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);
TEST_ASSERT(cmp_size != CMP_ERROR_HIGH_VALUE);
#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_size >= 0 && 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_chunk_round_trip(void)
{
enum cmp_data_type data_type;
enum cmp_mode cmp_mode;
enum { MAX_DATA_TO_COMPRESS_SIZE = CMP_ENTITY_MAX_ORIGINAL_SIZE};
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);
uint32_t cmp_data_capacity = CMP_ENTITY_MAX_SIZE-NON_IMAGETTE_HEADER_SIZE;
void *cmp_data = malloc(cmp_data_capacity);
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;
int32_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(cmp_size == -1);
else
TEST_ASSERT(cmp_size > 0);
}
}
free(data);
free(model);
free(updated_model);
free(cmp_data);
}
/**
* @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;
int 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, 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 */
int 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, 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);
int 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);
int 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);
}
}
/**
* @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;
int 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 */
int 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_size);
}
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)];
int 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_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;
int 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);
}