test_sbuf_load.c (10270B)
1 /* Copyright (C) 2022, 2023 |Méso|Star> (contact@meso-star.com) 2 * 3 * This program is free software: you can redistribute it and/or modify 4 * it under the terms of the GNU General Public License as published by 5 * the Free Software Foundation, either version 3 of the License, or 6 * (at your option) any later version. 7 * 8 * This program is distributed in the hope that it will be useful, 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 * GNU General Public License for more details. 12 * 13 * You should have received a copy of the GNU General Public License 14 * along with this program. If not, see <http://www.gnu.org/licenses/>. */ 15 16 #include "sbuf.h" 17 #include <rsys/math.h> 18 #include <rsys/mem_allocator.h> 19 #include <string.h> 20 21 struct type_desc { 22 void (*set)(void* data, const size_t i); 23 int (*eq)(const void* a, const void* b); 24 25 uint64_t size; 26 uint64_t alignment; 27 }; 28 29 struct header { 30 uint64_t pagesize; 31 uint64_t size; 32 uint64_t szitem; 33 uint64_t alitem; 34 }; 35 36 /******************************************************************************* 37 * i16_f32 type 38 ******************************************************************************/ 39 struct i16_f32 { 40 int16_t i16; 41 float f32; 42 }; 43 44 static void 45 i16_f32_set(void* data, const size_t i) 46 { 47 struct i16_f32* t = data; 48 CHK(t); 49 t->i16 = (int16_t)i; 50 t->f32 = (float)i/100.f; 51 } 52 53 static int 54 i16_f32_eq(const void* a, const void* b) 55 { 56 const struct i16_f32* t0 = a; 57 const struct i16_f32* t1 = b; 58 CHK(t0 && t1); 59 return t0->i16 == t1->i16 && t0->f32 == t1->f32; 60 } 61 62 /******************************************************************************* 63 * char[7] 64 ******************************************************************************/ 65 typedef char (char7_T) [7]; 66 67 static void 68 char7_set(void* data, const size_t i) 69 { 70 char* str = data; 71 CHK(i < 1000); 72 sprintf(str, "%3dabc", (int)i); 73 } 74 75 static int 76 char7_eq(const void* a, const void* b) 77 { 78 const char* s0 = a; 79 const char* s1 = b; 80 CHK(s0 && s1); 81 return strcmp(s0, s1) == 0; 82 } 83 84 /******************************************************************************* 85 * ui32_f32 type 86 ******************************************************************************/ 87 struct ui32_f32 { 88 uint32_t ui32; 89 float f32; 90 }; 91 92 static void 93 ui32_f32_set(void* data, const size_t i) 94 { 95 struct ui32_f32* t = data; 96 CHK(t); 97 t->ui32 = (uint32_t)i; 98 t->f32 = (float)i/100.f; 99 } 100 101 static int 102 ui32_f32_eq(const void* a, const void* b) 103 { 104 const struct ui32_f32* t0 = a; 105 const struct ui32_f32* t1 = b; 106 CHK(t0 && t1); 107 return t0->ui32 == t1->ui32 && t0->f32 == t1->f32; 108 } 109 110 /******************************************************************************* 111 * float 112 ******************************************************************************/ 113 static void 114 f32_set(void* data, const size_t i) 115 { 116 float* f = data; 117 CHK(f); 118 *f = (float)i; 119 } 120 121 static int 122 f32_eq(const void* a, const void* b) 123 { 124 const float* f0 = a; 125 const float* f1 = b; 126 CHK(f0 && f1); 127 return *f0 == *f1; 128 } 129 130 /******************************************************************************* 131 * Helper functions 132 ******************************************************************************/ 133 static void 134 check_sbuf_desc 135 (const struct sbuf_desc* desc, 136 const uint64_t size, 137 const struct type_desc* type) 138 { 139 char ALIGN(512) mem[512] = {0}; 140 size_t i; 141 CHK(desc && type); 142 CHK(type->size <= sizeof(mem)); 143 CHK(type->alignment <= ALIGNOF(mem)); 144 145 CHK(desc->buffer != NULL); 146 CHK(desc->size == size); 147 CHK(desc->szitem == type->size); 148 CHK(desc->alitem == type->alignment); 149 CHK(desc->pitch == ALIGN_SIZE(type->size, type->alignment)); 150 151 FOR_EACH(i, 0, size) { 152 const void* item = sbuf_desc_at(desc, i); 153 CHK(IS_ALIGNED(item, desc->alitem)); 154 type->set(mem, i); 155 CHK(type->eq(mem, item)); 156 } 157 } 158 159 static void 160 write_buffer 161 (FILE* fp, 162 const struct header* header, 163 const struct type_desc* type) 164 { 165 char ALIGN(512) mem[512] = {0}; 166 size_t i; 167 const char byte = 0; 168 169 CHK(type); 170 CHK(type->size <= sizeof(mem)); 171 172 /* Write file header */ 173 CHK(fwrite(&header->pagesize, sizeof(header->pagesize), 1, fp) == 1); 174 CHK(fwrite(&header->size, sizeof(header->size), 1, fp) == 1); 175 CHK(fwrite(&header->szitem, sizeof(header->szitem), 1, fp) == 1); 176 CHK(fwrite(&header->alitem, sizeof(header->alitem), 1, fp) == 1); 177 178 /* Padding */ 179 CHK(fseek(fp, 180 (long)ALIGN_SIZE((size_t)ftell(fp), header->pagesize), SEEK_SET) == 0); 181 182 /* Write the buffer data */ 183 FOR_EACH(i, 0, header->size) { 184 type->set(mem, i); 185 CHK(fwrite(mem, type->size, 1, fp) == 1); 186 CHK(fseek(fp, 187 (long)ALIGN_SIZE((size_t)ftell(fp), type->alignment), SEEK_SET) == 0); 188 } 189 190 /* Padding. Write one char to position the EOF indicator */ 191 CHK(fseek(fp, 192 (long)ALIGN_SIZE((size_t)ftell(fp), header->pagesize)-1, SEEK_SET) == 0); 193 CHK(fwrite(&byte, sizeof(byte), 1, fp) == 1); 194 CHK(fflush(fp) == 0); 195 } 196 197 static void 198 test_misc(struct sbuf* buf) 199 { 200 struct sbuf_desc desc = SBUF_DESC_NULL; 201 struct header header; 202 struct type_desc type; 203 FILE* fp = NULL; 204 CHK(buf); 205 206 type.set = f32_set; 207 type.eq = f32_eq; 208 type.size = sizeof(float); 209 type.alignment = ALIGNOF(float); 210 211 header.pagesize = 16384; 212 header.size = 123; 213 header.szitem = type.size; 214 header.alitem = type.alignment; 215 216 CHK(fp = tmpfile()); 217 write_buffer(fp, &header, &type); 218 rewind(fp); 219 220 CHK(sbuf_load_stream(NULL, fp, NULL) == RES_BAD_ARG); 221 CHK(sbuf_load_stream(buf, NULL, NULL) == RES_BAD_ARG); 222 CHK(sbuf_load_stream(buf, fp, NULL) == RES_OK); 223 224 rewind(fp); 225 CHK(sbuf_load_stream(buf, fp, "<stream>") == RES_OK); 226 227 CHK(sbuf_get_desc(NULL, &desc) == RES_BAD_ARG); 228 CHK(sbuf_get_desc(buf, NULL) == RES_BAD_ARG); 229 CHK(sbuf_get_desc(buf, &desc) == RES_OK); 230 check_sbuf_desc(&desc, header.size, &type); 231 232 CHK(fclose(fp) == 0); 233 } 234 235 static void 236 test_buffer 237 (struct sbuf* buf, 238 const struct header* header, 239 const struct type_desc* type, 240 const res_T res) 241 { 242 FILE* fp = NULL; 243 CHK(buf && type); 244 245 CHK(fp = tmpfile()); 246 write_buffer(fp, header, type); 247 rewind(fp); 248 249 CHK(sbuf_load_stream(buf, fp, NULL) == res); 250 251 if(res == RES_OK) { 252 struct sbuf_desc desc = SBUF_DESC_NULL; 253 CHK(sbuf_get_desc(buf, &desc) == RES_OK); 254 check_sbuf_desc(&desc, header->size, type); 255 } 256 257 CHK(fclose(fp) == 0); 258 } 259 260 static void 261 test_load(struct sbuf* buf) 262 { 263 struct header header; 264 struct type_desc type; 265 266 type.set = i16_f32_set; 267 type.eq = i16_f32_eq; 268 type.size = sizeof(struct i16_f32); 269 type.alignment = ALIGNOF(struct i16_f32); 270 271 header.pagesize = 16384; 272 header.size = 287; 273 header.szitem = type.size; 274 header.alitem = type.alignment; 275 276 test_buffer(buf, &header, &type, RES_OK); 277 278 type.alignment = header.alitem = 32; 279 test_buffer(buf, &header, &type, RES_OK); 280 281 type.set = char7_set; 282 type.eq = char7_eq; 283 type.size = header.szitem = sizeof(char7_T); 284 type.alignment = header.alitem = ALIGNOF(char7_T); 285 test_buffer(buf, &header, &type, RES_OK); 286 287 type.set = ui32_f32_set; 288 type.eq = ui32_f32_eq; 289 type.size = header.szitem = sizeof(struct ui32_f32); 290 type.alignment = header.alitem = ALIGNOF(struct ui32_f32); 291 test_buffer(buf, &header, &type, RES_OK); 292 293 type.set = f32_set; 294 type.eq = f32_eq; 295 type.size = header.szitem = sizeof(float); 296 type.alignment = header.alitem = ALIGNOF(float); 297 test_buffer(buf, &header, &type, RES_OK); 298 } 299 300 static void 301 test_load_fail(struct sbuf* buf) 302 { 303 struct type_desc type; 304 struct header header; 305 uint64_t size = 0; 306 FILE* fp = NULL; 307 308 type.set = f32_set; 309 type.eq = f32_eq; 310 type.size = sizeof(float); 311 type.alignment = 32; 312 313 header.pagesize = 4096; 314 header.size = 100; 315 header.szitem = type.size; 316 header.alitem = type.alignment; 317 318 /* Check the a priori validity of the current parameters */ 319 test_buffer(buf, &header, &type, RES_OK); 320 321 /* Invalid page size */ 322 header.pagesize = 2048; 323 test_buffer(buf, &header, &type, RES_BAD_ARG); 324 header.pagesize = 4098; 325 test_buffer(buf, &header, &type, RES_BAD_ARG); 326 327 /* Invalid size */ 328 header.pagesize = 4096; 329 header.size = 0; 330 test_buffer(buf, &header, &type, RES_BAD_ARG); 331 332 /* Invalid item size */ 333 header.size = 100; 334 header.szitem = 0; 335 test_buffer(buf, &header, &type, RES_BAD_ARG); 336 337 /* Invalid type alignment */ 338 header.szitem = type.size; 339 header.alitem = 0; 340 test_buffer(buf, &header, &type, RES_BAD_ARG); 341 header.alitem = 33; 342 test_buffer(buf, &header, &type, RES_BAD_ARG); 343 header.alitem = 8192; 344 test_buffer(buf, &header, &type, RES_BAD_ARG); 345 346 /* Invalid file size */ 347 header.alitem = type.alignment; 348 CHK(fp = tmpfile()); 349 write_buffer(fp, &header, &type); 350 CHK(fseek(fp, 8, SEEK_SET) == 0); /* Overwrite the size */ 351 size = 5000; 352 CHK(fwrite(&size, sizeof(size), 1, fp) == 1); 353 rewind(fp); 354 CHK(sbuf_load_stream(buf, fp, NULL) == RES_IO_ERR); 355 CHK(fclose(fp) == 0); 356 } 357 358 static void 359 test_load_files(struct sbuf* buf, int argc, char** argv) 360 { 361 int i; 362 CHK(buf); 363 FOR_EACH(i, 1, argc) { 364 struct sbuf_desc desc = SBUF_DESC_NULL; 365 size_t iitem; 366 367 printf("Loading %s\n", argv[i]); 368 CHK(sbuf_load(buf, argv[i]) == RES_OK); 369 CHK(sbuf_get_desc(buf, &desc) == RES_OK); 370 CHK(desc.buffer); 371 CHK(desc.size); 372 CHK(desc.szitem); 373 CHK(desc.alitem); 374 CHK(desc.pitch); 375 CHK(IS_POW2(desc.alitem)); 376 377 FOR_EACH(iitem, 0, desc.size) { 378 const void* data = NULL; 379 data = sbuf_desc_at(&desc, iitem); 380 CHK(data != 0); 381 CHK(IS_ALIGNED(data, desc.alitem)); 382 if(iitem) { 383 const void* prev = (char*)data - desc.pitch; 384 CHK(prev == sbuf_desc_at(&desc, iitem-1)); 385 } 386 } 387 } 388 } 389 390 /******************************************************************************* 391 * Main function 392 ******************************************************************************/ 393 int 394 main(int argc, char** argv) 395 { 396 struct sbuf_create_args args = SBUF_CREATE_ARGS_DEFAULT; 397 struct sbuf* buf = NULL; 398 (void)argc, (void)argv; 399 400 args.verbose = 1; 401 CHK(sbuf_create(&args, &buf) == RES_OK); 402 403 if(argc > 1) { 404 test_load_files(buf, argc, argv); 405 } else { 406 test_misc(buf); 407 test_load(buf); 408 test_load_fail(buf); 409 } 410 411 CHK(sbuf_ref_put(buf) == RES_OK); 412 CHK(mem_allocated_size() == 0); 413 return 0; 414 }