/src/cmp_tool/test/test_common/chunk_round_trip.c
Line | Count | Source (jump to first uncovered line) |
1 | | /** |
2 | | * @file chunk_round_trip.c |
3 | | * @date 2024 |
4 | | * |
5 | | * @copyright GPLv2 |
6 | | * This program is free software; you can redistribute it and/or modify it |
7 | | * under the terms and conditions of the GNU General Public License, |
8 | | * version 2, as published by the Free Software Foundation. |
9 | | * |
10 | | * This program is distributed in the hope it will be useful, but WITHOUT |
11 | | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
12 | | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for |
13 | | * more details. |
14 | | * |
15 | | * @brief chunk compression/decompression test |
16 | | * |
17 | | */ |
18 | | |
19 | | #include <string.h> |
20 | | #include <stdlib.h> |
21 | | |
22 | | #include "../test_common/test_common.h" |
23 | | #include "../../lib/cmp_chunk.h" |
24 | | #include "../../lib/decmp.h" |
25 | | #include "chunk_round_trip.h" |
26 | | |
27 | | #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION |
28 | | # include "../fuzz/fuzz_helpers.h" |
29 | 11.1k | # define TEST_ASSERT(cond) FUZZ_ASSERT(cond) |
30 | | #else |
31 | | # include <unity.h> |
32 | | #endif |
33 | | |
34 | | |
35 | | |
36 | | /** |
37 | | * @brief allocates memory safely for tests |
38 | | * |
39 | | * @param size the size of memory to allocate |
40 | | * |
41 | | * @returns a pointer to the allocated memory, or NULL if allocation fails |
42 | | */ |
43 | | |
44 | | static void *TEST_malloc(size_t size) |
45 | 2.02k | { |
46 | 2.02k | if (size > 0) { |
47 | 2.02k | void *mem = malloc(size); |
48 | | |
49 | 2.02k | TEST_ASSERT(mem); |
50 | 2.02k | return mem; |
51 | 2.02k | } |
52 | 0 | return NULL; |
53 | 2.02k | } |
54 | | |
55 | | |
56 | | /** |
57 | | * @brief performs chunk compression and checks if a decompression is possible |
58 | | * |
59 | | * @param chunk pointer to the chunk to be compressed |
60 | | * @param chunk_size byte size of the chunk |
61 | | * @param chunk_model pointer to a model of a chunk; has the same size |
62 | | * as the chunk (can be NULL if no model compression |
63 | | * mode is used) |
64 | | * @param updated_chunk_model pointer to store the updated model for the next |
65 | | * model mode compression; has the same size as the |
66 | | * chunk (can be the same as the model_of_data |
67 | | * buffer for in-place update or NULL if updated |
68 | | * model is not needed) |
69 | | * @param dst destination pointer to the compressed data |
70 | | * buffer; has to be 4-byte aligned; can be NULL to |
71 | | * only get the compressed data size |
72 | | * @param dst_capacity capacity of the dst buffer; it's recommended to |
73 | | * provide a dst_capacity >= |
74 | | * compress_chunk_cmp_size_bound(chunk, chunk_size) |
75 | | * as it eliminates one potential failure scenario: |
76 | | * not enough space in the dst buffer to write the |
77 | | * compressed data; size is internally rounded down |
78 | | * to a multiple of 4 |
79 | | * @param use_decmp_buf if non-zero, a buffer is allocated for the |
80 | | * decompressed data |
81 | | * @param use_decmp_up_model if non-zero, a buffer for the updated model is |
82 | | * allocated during the decompression |
83 | | * @param cmp_par pointer to a compression parameters struct |
84 | | * |
85 | | * @returns the return value of the compress_chunk() function |
86 | | */ |
87 | | |
88 | | uint32_t chunk_round_trip(const void *chunk, uint32_t chunk_size, |
89 | | const void *chunk_model, void *updated_chunk_model, |
90 | | uint32_t *dst, uint32_t dst_capacity, |
91 | | const struct cmp_par *cmp_par, |
92 | | int use_decmp_buf, int use_decmp_up_model) |
93 | 2.70k | { |
94 | 2.70k | uint32_t cmp_size; |
95 | 2.70k | void *model_cpy_p = NULL; |
96 | 2.70k | const void *model_cpy = NULL; |
97 | | |
98 | | /* if in-place model update is used (up_model == model), the model |
99 | | * needed for decompression is destroyed; therefore we make a copy |
100 | | */ |
101 | 2.70k | if (chunk_model) { |
102 | 1.37k | if (updated_chunk_model == chunk_model) { |
103 | 0 | model_cpy_p = TEST_malloc(chunk_size); |
104 | 0 | memcpy(model_cpy_p, chunk_model, chunk_size); |
105 | 0 | model_cpy = model_cpy_p; |
106 | 1.37k | } else { |
107 | 1.37k | model_cpy = chunk_model; |
108 | 1.37k | } |
109 | 1.37k | } |
110 | | |
111 | 2.70k | cmp_size = compress_chunk(chunk, chunk_size, chunk_model, updated_chunk_model, |
112 | 2.70k | dst, dst_capacity, cmp_par); |
113 | | |
114 | 2.70k | if (!cmp_is_error(cmp_size)) { /* second run with dst = NULL */ |
115 | 1.65k | uint32_t cmp_size2; |
116 | | |
117 | | /* reset model if in-place update was used */ |
118 | 1.65k | if (chunk_model && updated_chunk_model == chunk_model) |
119 | 0 | memcpy(updated_chunk_model, model_cpy, chunk_size); |
120 | | |
121 | 1.65k | cmp_size2 = compress_chunk(chunk, chunk_size, chunk_model, updated_chunk_model, |
122 | 1.65k | NULL, dst_capacity, cmp_par); |
123 | 1.65k | if (cmp_get_error_code(cmp_size) != CMP_ERROR_SMALL_BUFFER) |
124 | 1.65k | TEST_ASSERT(cmp_size == cmp_size2); |
125 | 1.65k | } |
126 | | |
127 | | |
128 | | /* decompress the data if the compression was successful */ |
129 | 2.70k | if (!cmp_is_error(cmp_size) && dst) { |
130 | 1.31k | void *decmp_data = NULL; |
131 | 1.31k | void *up_model_decmp = NULL; |
132 | 1.31k | int decmp_size; |
133 | | |
134 | 1.31k | decmp_size = decompress_cmp_entiy((struct cmp_entity *)dst, model_cpy, NULL, NULL); |
135 | 1.31k | TEST_ASSERT(decmp_size >= 0); |
136 | 1.31k | TEST_ASSERT((uint32_t)decmp_size == chunk_size); |
137 | | |
138 | 1.31k | if (use_decmp_buf) |
139 | 1.11k | decmp_data = TEST_malloc(chunk_size); |
140 | 1.31k | if (use_decmp_up_model) { |
141 | 905 | up_model_decmp = TEST_malloc(chunk_size); |
142 | 905 | if (!model_mode_is_used(cmp_par->cmp_mode)) |
143 | 307 | memset(up_model_decmp, 0, chunk_size); /* up_model is not used */ |
144 | 905 | } |
145 | | |
146 | 1.31k | decmp_size = decompress_cmp_entiy((struct cmp_entity *)dst, model_cpy, |
147 | 1.31k | up_model_decmp, decmp_data); |
148 | 1.31k | TEST_ASSERT(decmp_size >= 0); |
149 | 1.31k | TEST_ASSERT((uint32_t)decmp_size == chunk_size); |
150 | | |
151 | 1.31k | if (use_decmp_buf) { |
152 | 1.11k | TEST_ASSERT(!memcmp(chunk, decmp_data, chunk_size)); |
153 | | |
154 | | /* |
155 | | * the model is only updated when the decompressed_data |
156 | | * buffer is set |
157 | | */ |
158 | 1.11k | if (use_decmp_up_model && updated_chunk_model) |
159 | 1.11k | TEST_ASSERT(!memcmp(updated_chunk_model, up_model_decmp, chunk_size)); |
160 | 1.11k | } |
161 | | |
162 | 0 | free(decmp_data); |
163 | 1.31k | free(up_model_decmp); |
164 | 1.31k | } |
165 | | |
166 | 2.70k | if (updated_chunk_model == chunk_model) |
167 | 614 | free(model_cpy_p); |
168 | | |
169 | 2.70k | return cmp_size; |
170 | 2.70k | } |