1 /* SPDX-License-Identifier: GPL-2.0-only */
3 #include "../lib/region_file.c"
5 #include <tests/test.h>
8 #include <commonlib/region.h>
9 #include <tests/lib/region_file_data.h>
11 static void clear_region_file(struct region_device
*rdev
)
13 memset(rdev_mmap_full(rdev
), 0xff, REGION_FILE_BUFFER_SIZE
);
16 static int setup_region_file_test_group(void **state
)
18 void *mem_buffer
= malloc(REGION_FILE_BUFFER_SIZE
);
19 struct region_device
*dev
= malloc(sizeof(struct region_device
));
21 if (mem_buffer
== NULL
|| dev
== NULL
) {
27 rdev_chain_mem_rw(dev
, mem_buffer
, REGION_FILE_BUFFER_SIZE
);
30 clear_region_file(dev
);
35 static int teardown_region_file_test_group(void **state
)
37 struct region_device
*dev
= *state
;
38 void *mem_buffer
= rdev_mmap_full(dev
);
46 /* This function clears buffer associated with used region_device, so tests will be in clear
47 state at the beginning and leave no trace after successful execution. The cost of memsetting
48 everything twice is known, but acceptable as it grants safety and makes tests independent. */
49 static int setup_teardown_region_file_test(void **state
)
51 struct region_device
*dev
= *state
;
53 clear_region_file(dev
);
58 static void test_region_file_init_empty(void **state
)
60 struct region_device
*rdev
= *state
;
61 struct region_file regf
;
63 /* Test general approach using valid mem_region_device with buffer filled with 0xff.
64 Parameters cannot be NULL. */
65 assert_int_equal(0, region_file_init(®f
, rdev
));
66 assert_int_equal(RF_EMPTY
, regf
.slot
);
69 static void test_region_file_init_invalid_metadata(void **state
)
71 struct region_device
*rdev
= *state
;
72 uint16_t *mem_buffer16
= (uint16_t *)rdev_mmap_full(rdev
);
73 struct region_file regf
;
75 /* Set number of metadata blocks to 0 */
77 assert_int_equal(0, region_file_init(®f
, rdev
));
78 assert_int_equal(RF_NEED_TO_EMPTY
, regf
.slot
);
81 static void test_region_file_init_valid_no_data(void **state
)
83 struct region_device
*rdev
= *state
;
84 uint16_t *mem_buffer16
= (uint16_t *)rdev_mmap_full(rdev
);
85 struct region_file regf
;
87 /* Manually allocate 4 metadata blocks and no data. */
89 assert_int_equal(0, region_file_init(®f
, rdev
));
90 assert_int_equal(0, regf
.slot
);
93 static void test_region_file_init_invalid_data_offset(void **state
)
95 struct region_device
*rdev
= *state
;
96 uint16_t *mem_buffer16
= (uint16_t *)rdev_mmap_full(rdev
);
97 struct region_file regf
;
99 /* Manually allocate 4 metadata blocks and no data. */
102 assert_int_equal(0, region_file_init(®f
, rdev
));
103 assert_int_equal(RF_NEED_TO_EMPTY
, regf
.slot
);
105 /* Set data size to be larger than region */
107 mem_buffer16
[1] = 4 + 4096;
108 assert_int_equal(0, region_file_init(®f
, rdev
));
109 assert_int_equal(RF_NEED_TO_EMPTY
, regf
.slot
);
112 static void test_region_file_init_correct_data_offset(void **state
)
114 struct region_device
*rdev
= *state
;
115 uint16_t *mem_buffer16
= (uint16_t *)rdev_mmap_full(rdev
);
116 struct region_file regf
;
118 /* Set data size to 8 blocks which is correct value. */
120 mem_buffer16
[1] = 4 + 8;
121 assert_int_equal(0, region_file_init(®f
, rdev
));
122 assert_int_equal(1, regf
.slot
);
125 static void test_region_file_init_real_data(void **state
)
127 struct region_device rdev
;
128 struct region_file regf
;
130 rdev_chain_mem_rw(&rdev
, region_file_data_buffer1
, REGION_FILE_BUFFER_SIZE
);
132 /* Check on real example with one update */
133 assert_int_equal(0, region_file_init(®f
, &rdev
));
134 /* There is one update available */
135 assert_int_equal(1, regf
.slot
);
138 /* Check on real example with multiple updates */
139 rdev_chain_mem_rw(&rdev
, region_file_data_buffer2
, REGION_FILE_BUFFER_SIZE
);
140 assert_int_equal(0, region_file_init(®f
, &rdev
));
141 /* There are three update available */
142 assert_int_equal(3, regf
.slot
);
145 static void test_region_file_init_invalid_region_device(void **state
)
147 struct region_device bad_dev
;
149 assert_int_equal(rdev_chain_mem_rw(&bad_dev
, NULL
, 0), -1);
152 static void test_region_file_data(void **state
)
154 /* region_device with empty data buffer */
155 struct region_device
*mrdev
= *state
;
156 /* region_device with prepared data buffer */
157 struct region_device rdev
;
158 rdev_chain_mem_rw(&rdev
, region_file_data_buffer1
, REGION_FILE_BUFFER_SIZE
);
160 struct region_file regf
;
161 struct region_device read_rdev
;
164 /* Check if region_file_data() fails to return region_device for empty region_file */
165 ret
= region_file_init(®f
, mrdev
);
166 assert_int_equal(0, ret
);
167 ret
= region_file_data(®f
, &read_rdev
);
168 assert_int_equal(-1, ret
);
170 /* Check if region_file_data() correctly returns region_device for hardcoded
171 region_file data with update of 256 bytes */
172 ret
= region_file_init(®f
, &rdev
);
173 assert_int_equal(0, ret
);
174 ret
= region_file_data(®f
, &read_rdev
);
175 assert_int_equal(0, ret
);
176 assert_int_equal(region_device_sz(&read_rdev
),
177 ALIGN_UP(region_file_data_buffer1_update_sz
, 16));
180 static void test_region_file_update_data(void **state
)
182 struct region_device
*rdev
= *state
;
183 struct region_file regf
;
184 struct region_device read_rdev
;
185 const size_t dummy_data_size
= 256;
186 uint8_t dummy_data
[dummy_data_size
];
187 uint8_t output_buffer
[dummy_data_size
];
190 for (int i
= 0; i
< dummy_data_size
; ++i
)
191 dummy_data
[i
] = 'A' + i
% ('Z' - 'A');
193 ret
= region_file_init(®f
, rdev
);
194 assert_int_equal(0, ret
);
196 /* Write half of buffer, read it and check, if it is the same.
197 region_file_update_data() should be able to deal with empty region_file. */
198 ret
= region_file_update_data(®f
, dummy_data
, dummy_data_size
/ 2);
199 assert_int_equal(0, ret
);
200 region_file_data(®f
, &read_rdev
);
201 assert_int_equal(ALIGN_UP(dummy_data_size
/ 2, 16), region_device_sz(&read_rdev
));
202 rdev_readat(&read_rdev
, output_buffer
, 0, dummy_data_size
/ 2);
203 assert_memory_equal(dummy_data
, output_buffer
, dummy_data_size
/ 2);
205 /* Update data to a bigger size */
206 ret
= region_file_update_data(®f
, dummy_data
, dummy_data_size
);
207 assert_int_equal(0, ret
);
208 region_file_data(®f
, &read_rdev
);
209 assert_int_equal(ALIGN_UP(dummy_data_size
, 16), region_device_sz(&read_rdev
));
210 rdev_readat(&read_rdev
, output_buffer
, 0, dummy_data_size
);
211 assert_memory_equal(dummy_data
, output_buffer
, dummy_data_size
);
213 /* Update data to smaller size and check if it was properly stored */
214 ret
= region_file_update_data(®f
, dummy_data
, dummy_data_size
/ 2 + 3);
215 assert_int_equal(0, ret
);
216 region_file_data(®f
, &read_rdev
);
217 assert_int_equal(ALIGN_UP(dummy_data_size
/ 2 + 3, 16), region_device_sz(&read_rdev
));
218 rdev_readat(&read_rdev
, output_buffer
, 0, dummy_data_size
/ 2 + 3);
219 assert_memory_equal(dummy_data
, output_buffer
, dummy_data_size
/ 2 + 3);
222 static void test_region_file_update_data_arr(void **state
)
224 struct region_device
*rdev
= *state
;
225 struct region_file regf
;
226 struct region_device read_rdev
;
227 const size_t dummy_data_size
= 256;
228 uint8_t dummy_data
[dummy_data_size
];
229 uint8_t output_buffer
[dummy_data_size
* 4];
230 struct update_region_file_entry update_entries
[3];
231 const size_t data1_size
= dummy_data_size
;
232 const size_t data2_size
= dummy_data_size
/ 2;
233 const size_t data3_size
= dummy_data_size
/ 4 + 3;
234 const size_t data1_offset
= 0;
235 const size_t data2_offset
= dummy_data_size
/ 4 + 2;
236 const size_t data3_offset
= dummy_data_size
/ 8 + 5;
239 for (int i
= 0; i
< dummy_data_size
; ++i
)
240 dummy_data
[i
] = 'A' + i
% ('Z' - 'A');
242 update_entries
[0] = (struct update_region_file_entry
){
243 .size
= data1_size
, .data
= &dummy_data
[data1_offset
]};
244 update_entries
[1] = (struct update_region_file_entry
){
245 .size
= data2_size
, .data
= &dummy_data
[data2_offset
]};
246 update_entries
[2] = (struct update_region_file_entry
){
247 .size
= data3_size
, .data
= &dummy_data
[data3_offset
]};
249 ret
= region_file_init(®f
, rdev
);
250 assert_int_equal(0, ret
);
252 /* Write two update blocks as first data state. region_file_update_data_arr() should
253 be able to deal with empty region_file. */
254 ret
= region_file_update_data_arr(®f
, update_entries
, 2);
255 assert_int_equal(0, ret
);
256 region_file_data(®f
, &read_rdev
);
257 assert_int_equal(ALIGN_UP(data1_size
+ data2_size
, 16), region_device_sz(&read_rdev
));
258 ret
= rdev_readat(&read_rdev
, output_buffer
, 0, data1_size
+ data2_size
);
259 assert_int_equal(data1_size
+ data2_size
, ret
);
260 assert_memory_equal(&dummy_data
[data1_offset
], output_buffer
, data1_size
);
261 assert_memory_equal(&dummy_data
[data1_offset
+ data2_offset
],
262 &output_buffer
[data1_size
], data2_size
);
264 /* Check if new block of data is added correctly */
265 ret
= region_file_update_data_arr(®f
, update_entries
, 3);
266 assert_int_equal(0, ret
);
267 region_file_data(®f
, &read_rdev
);
268 assert_int_equal(ALIGN_UP(data1_size
+ data2_size
+ data3_size
, 16),
269 region_device_sz(&read_rdev
));
270 ret
= rdev_readat(&read_rdev
, output_buffer
, 0, data1_size
+ data2_size
+ data3_size
);
271 assert_int_equal(data1_size
+ data2_size
+ data3_size
, ret
);
272 assert_memory_equal(&dummy_data
[data1_offset
], output_buffer
, data1_size
);
273 assert_memory_equal(&dummy_data
[data2_offset
], &output_buffer
[data1_size
], data2_size
);
274 assert_memory_equal(&dummy_data
[data3_offset
], &output_buffer
[data1_size
+ data2_size
],
277 /* Check if data is correctly shrunk down to smaller size and different content */
278 ret
= region_file_update_data_arr(®f
, &update_entries
[1], 2);
279 assert_int_equal(0, ret
);
280 region_file_data(®f
, &read_rdev
);
281 assert_int_equal(ALIGN_UP(data2_size
+ data3_size
, 16), region_device_sz(&read_rdev
));
282 ret
= rdev_readat(&read_rdev
, output_buffer
, 0, data2_size
+ data3_size
);
283 assert_int_equal(data2_size
+ data3_size
, ret
);
284 assert_memory_equal(&dummy_data
[data2_offset
], &output_buffer
[0], data2_size
);
285 assert_memory_equal(&dummy_data
[data3_offset
], &output_buffer
[data2_size
], data3_size
);
290 const struct CMUnitTest tests
[] = {
291 cmocka_unit_test_setup_teardown(test_region_file_init_empty
,
292 setup_teardown_region_file_test
,
293 setup_teardown_region_file_test
),
294 cmocka_unit_test_setup_teardown(test_region_file_init_invalid_metadata
,
295 setup_teardown_region_file_test
,
296 setup_teardown_region_file_test
),
297 cmocka_unit_test_setup_teardown(test_region_file_init_valid_no_data
,
298 setup_teardown_region_file_test
,
299 setup_teardown_region_file_test
),
300 cmocka_unit_test_setup_teardown(test_region_file_init_invalid_data_offset
,
301 setup_teardown_region_file_test
,
302 setup_teardown_region_file_test
),
303 cmocka_unit_test_setup_teardown(test_region_file_init_correct_data_offset
,
304 setup_teardown_region_file_test
,
305 setup_teardown_region_file_test
),
306 cmocka_unit_test_setup_teardown(test_region_file_init_real_data
,
307 setup_teardown_region_file_test
,
308 setup_teardown_region_file_test
),
309 cmocka_unit_test_setup_teardown(test_region_file_init_invalid_region_device
,
310 setup_teardown_region_file_test
,
311 setup_teardown_region_file_test
),
312 cmocka_unit_test_setup_teardown(test_region_file_data
,
313 setup_teardown_region_file_test
,
314 setup_teardown_region_file_test
),
315 cmocka_unit_test_setup_teardown(test_region_file_update_data
,
316 setup_teardown_region_file_test
,
317 setup_teardown_region_file_test
),
318 cmocka_unit_test_setup_teardown(test_region_file_update_data_arr
,
319 setup_teardown_region_file_test
,
320 setup_teardown_region_file_test
),
323 return cb_run_group_tests(tests
, setup_region_file_test_group
,
324 teardown_region_file_test_group
);