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
;
148 struct region_file regf
;
150 rdev_chain_mem_rw(&bad_dev
, NULL
, 0);
152 /* Expect fail when passing invalid region_device. */
153 assert_int_equal(-1, region_file_init(®f
, &bad_dev
));
156 static void test_region_file_data(void **state
)
158 /* region_device with empty data buffer */
159 struct region_device
*mrdev
= *state
;
160 /* region_device with prepared data buffer */
161 struct region_device rdev
;
162 rdev_chain_mem_rw(&rdev
, region_file_data_buffer1
, REGION_FILE_BUFFER_SIZE
);
164 struct region_file regf
;
165 struct region_device read_rdev
;
168 /* Check if region_file_data() fails to return region_device for empty region_file */
169 ret
= region_file_init(®f
, mrdev
);
170 assert_int_equal(0, ret
);
171 ret
= region_file_data(®f
, &read_rdev
);
172 assert_int_equal(-1, ret
);
174 /* Check if region_file_data() correctly returns region_device for hardcoded
175 region_file data with update of 256 bytes */
176 ret
= region_file_init(®f
, &rdev
);
177 assert_int_equal(0, ret
);
178 ret
= region_file_data(®f
, &read_rdev
);
179 assert_int_equal(0, ret
);
180 assert_int_equal(region_device_sz(&read_rdev
),
181 ALIGN_UP(region_file_data_buffer1_update_sz
, 16));
184 static void test_region_file_update_data(void **state
)
186 struct region_device
*rdev
= *state
;
187 struct region_file regf
;
188 struct region_device read_rdev
;
189 const size_t dummy_data_size
= 256;
190 uint8_t dummy_data
[dummy_data_size
];
191 uint8_t output_buffer
[dummy_data_size
];
194 for (int i
= 0; i
< dummy_data_size
; ++i
)
195 dummy_data
[i
] = 'A' + i
% ('Z' - 'A');
197 ret
= region_file_init(®f
, rdev
);
198 assert_int_equal(0, ret
);
200 /* Write half of buffer, read it and check, if it is the same.
201 region_file_update_data() should be able to deal with empty region_file. */
202 ret
= region_file_update_data(®f
, dummy_data
, dummy_data_size
/ 2);
203 assert_int_equal(0, ret
);
204 region_file_data(®f
, &read_rdev
);
205 assert_int_equal(ALIGN_UP(dummy_data_size
/ 2, 16), region_device_sz(&read_rdev
));
206 rdev_readat(&read_rdev
, output_buffer
, 0, dummy_data_size
/ 2);
207 assert_memory_equal(dummy_data
, output_buffer
, dummy_data_size
/ 2);
209 /* Update data to a bigger size */
210 ret
= region_file_update_data(®f
, dummy_data
, dummy_data_size
);
211 assert_int_equal(0, ret
);
212 region_file_data(®f
, &read_rdev
);
213 assert_int_equal(ALIGN_UP(dummy_data_size
, 16), region_device_sz(&read_rdev
));
214 rdev_readat(&read_rdev
, output_buffer
, 0, dummy_data_size
);
215 assert_memory_equal(dummy_data
, output_buffer
, dummy_data_size
);
217 /* Update data to smaller size and check if it was properly stored */
218 ret
= region_file_update_data(®f
, dummy_data
, dummy_data_size
/ 2 + 3);
219 assert_int_equal(0, ret
);
220 region_file_data(®f
, &read_rdev
);
221 assert_int_equal(ALIGN_UP(dummy_data_size
/ 2 + 3, 16), region_device_sz(&read_rdev
));
222 rdev_readat(&read_rdev
, output_buffer
, 0, dummy_data_size
/ 2 + 3);
223 assert_memory_equal(dummy_data
, output_buffer
, dummy_data_size
/ 2 + 3);
226 static void test_region_file_update_data_arr(void **state
)
228 struct region_device
*rdev
= *state
;
229 struct region_file regf
;
230 struct region_device read_rdev
;
231 const size_t dummy_data_size
= 256;
232 uint8_t dummy_data
[dummy_data_size
];
233 uint8_t output_buffer
[dummy_data_size
* 4];
234 struct update_region_file_entry update_entries
[3];
235 const size_t data1_size
= dummy_data_size
;
236 const size_t data2_size
= dummy_data_size
/ 2;
237 const size_t data3_size
= dummy_data_size
/ 4 + 3;
238 const size_t data1_offset
= 0;
239 const size_t data2_offset
= dummy_data_size
/ 4 + 2;
240 const size_t data3_offset
= dummy_data_size
/ 8 + 5;
243 for (int i
= 0; i
< dummy_data_size
; ++i
)
244 dummy_data
[i
] = 'A' + i
% ('Z' - 'A');
246 update_entries
[0] = (struct update_region_file_entry
){
247 .size
= data1_size
, .data
= &dummy_data
[data1_offset
]};
248 update_entries
[1] = (struct update_region_file_entry
){
249 .size
= data2_size
, .data
= &dummy_data
[data2_offset
]};
250 update_entries
[2] = (struct update_region_file_entry
){
251 .size
= data3_size
, .data
= &dummy_data
[data3_offset
]};
253 ret
= region_file_init(®f
, rdev
);
254 assert_int_equal(0, ret
);
256 /* Write two update blocks as first data state. region_file_update_data_arr() should
257 be able to deal with empty region_file. */
258 ret
= region_file_update_data_arr(®f
, update_entries
, 2);
259 assert_int_equal(0, ret
);
260 region_file_data(®f
, &read_rdev
);
261 assert_int_equal(ALIGN_UP(data1_size
+ data2_size
, 16), region_device_sz(&read_rdev
));
262 ret
= rdev_readat(&read_rdev
, output_buffer
, 0, data1_size
+ data2_size
);
263 assert_int_equal(data1_size
+ data2_size
, ret
);
264 assert_memory_equal(&dummy_data
[data1_offset
], output_buffer
, data1_size
);
265 assert_memory_equal(&dummy_data
[data1_offset
+ data2_offset
],
266 &output_buffer
[data1_size
], data2_size
);
268 /* Check if new block of data is added correctly */
269 ret
= region_file_update_data_arr(®f
, update_entries
, 3);
270 assert_int_equal(0, ret
);
271 region_file_data(®f
, &read_rdev
);
272 assert_int_equal(ALIGN_UP(data1_size
+ data2_size
+ data3_size
, 16),
273 region_device_sz(&read_rdev
));
274 ret
= rdev_readat(&read_rdev
, output_buffer
, 0, data1_size
+ data2_size
+ data3_size
);
275 assert_int_equal(data1_size
+ data2_size
+ data3_size
, ret
);
276 assert_memory_equal(&dummy_data
[data1_offset
], output_buffer
, data1_size
);
277 assert_memory_equal(&dummy_data
[data2_offset
], &output_buffer
[data1_size
], data2_size
);
278 assert_memory_equal(&dummy_data
[data3_offset
], &output_buffer
[data1_size
+ data2_size
],
281 /* Check if data is correctly shrunk down to smaller size and different content */
282 ret
= region_file_update_data_arr(®f
, &update_entries
[1], 2);
283 assert_int_equal(0, ret
);
284 region_file_data(®f
, &read_rdev
);
285 assert_int_equal(ALIGN_UP(data2_size
+ data3_size
, 16), region_device_sz(&read_rdev
));
286 ret
= rdev_readat(&read_rdev
, output_buffer
, 0, data2_size
+ data3_size
);
287 assert_int_equal(data2_size
+ data3_size
, ret
);
288 assert_memory_equal(&dummy_data
[data2_offset
], &output_buffer
[0], data2_size
);
289 assert_memory_equal(&dummy_data
[data3_offset
], &output_buffer
[data2_size
], data3_size
);
294 const struct CMUnitTest tests
[] = {
295 cmocka_unit_test_setup_teardown(test_region_file_init_empty
,
296 setup_teardown_region_file_test
,
297 setup_teardown_region_file_test
),
298 cmocka_unit_test_setup_teardown(test_region_file_init_invalid_metadata
,
299 setup_teardown_region_file_test
,
300 setup_teardown_region_file_test
),
301 cmocka_unit_test_setup_teardown(test_region_file_init_valid_no_data
,
302 setup_teardown_region_file_test
,
303 setup_teardown_region_file_test
),
304 cmocka_unit_test_setup_teardown(test_region_file_init_invalid_data_offset
,
305 setup_teardown_region_file_test
,
306 setup_teardown_region_file_test
),
307 cmocka_unit_test_setup_teardown(test_region_file_init_correct_data_offset
,
308 setup_teardown_region_file_test
,
309 setup_teardown_region_file_test
),
310 cmocka_unit_test_setup_teardown(test_region_file_init_real_data
,
311 setup_teardown_region_file_test
,
312 setup_teardown_region_file_test
),
313 cmocka_unit_test_setup_teardown(test_region_file_init_invalid_region_device
,
314 setup_teardown_region_file_test
,
315 setup_teardown_region_file_test
),
316 cmocka_unit_test_setup_teardown(test_region_file_data
,
317 setup_teardown_region_file_test
,
318 setup_teardown_region_file_test
),
319 cmocka_unit_test_setup_teardown(test_region_file_update_data
,
320 setup_teardown_region_file_test
,
321 setup_teardown_region_file_test
),
322 cmocka_unit_test_setup_teardown(test_region_file_update_data_arr
,
323 setup_teardown_region_file_test
,
324 setup_teardown_region_file_test
),
327 return cb_run_group_tests(tests
, setup_region_file_test_group
,
328 teardown_region_file_test_group
);