LexLeo 0.0.0-dev+f8e5087-dirty
Technical documentation
Loading...
Searching...
No Matches
integration_test_stream_factory_fs_stream.c
Go to the documentation of this file.
1/* SPDX-License-Identifier: GPL-3.0-or-later
2 * Copyright (C) 2026 Sylvain Labopin
3 */
4
39
43
45
46#include "osal/mem/osal_mem.h"
47
51
52#include "lexleo_cmocka.h"
53
195
205typedef enum {
206 OUT_CHECK_NONE,
207 OUT_EXPECT_NULL,
208 OUT_EXPECT_NON_NULL,
209 OUT_EXPECT_UNCHANGED
210} out_expect_t;
211
227typedef struct {
228 const char *name;
229
230 // arrange
232 osal_file_status_t open_fail_status; // e.g. OSAL_FILE_NOENT
233
234 // assert
235 stream_status_t expected_ret;
236 out_expect_t out_expect;
237} test_stream_fact_create_fs_case_t;
238
253typedef struct {
255 stream_factory_t *factory;
256
257 stream_t *out;
258
259 fs_stream_cfg_t fs_stream_cfg;
260 fs_stream_env_t fs_stream_env;
261
262 stream_factory_cfg_t stream_factory_cfg;
263 stream_env_t stream_env;
264
265 fs_stream_args_t args;
266
267 // fake file backing
268 uint8_t backing[64];
269
270 const test_stream_fact_create_fs_case_t *tc;
271} test_stream_fact_create_fs_fixture_t;
272
273//-----------------------------------------------------------------------------
274// FIXTURES
275//-----------------------------------------------------------------------------
276
293static int setup_stream_fact_create_fs(void **state)
294{
295 const test_stream_fact_create_fs_case_t *tc =
296 (const test_stream_fact_create_fs_case_t *)(*state);
297
298 test_stream_fact_create_fs_fixture_t *fx =
299 (test_stream_fact_create_fs_fixture_t *)malloc(sizeof(*fx));
300 if (!fx) return -1;
301
302 osal_memset(fx, 0, sizeof(*fx));
303 fx->tc = tc;
304
305 fake_file_reset();
306
307 osal_memset(fx->backing, 0, sizeof(fx->backing));
308 fake_file_set_backing(fx->backing, sizeof(fx->backing), 0);
309 fake_file_set_pos(0);
310 fake_file_fail_disable();
311
312 if (tc->scenario == STREAM_FACT_CREATE_FS_SCENARIO_OPEN_FAIL) {
313 fake_file_fail_enable(FAKE_FILE_OP_OPEN, 1, tc->open_fail_status);
314 }
315
316 // DI
317 fx->fs_stream_env.file_env.mem = osal_mem_default_ops();
318 fx->fs_stream_env.file_ops = osal_file_test_fake_ops();
319 fx->fs_stream_env.port_env.mem = osal_mem_default_ops();
320 fx->stream_env.mem = osal_mem_default_ops();
321
322 fx->fs_stream_cfg.reserved = 0;
323 fx->stream_factory_cfg.fact_cap = 8;
324
326
327 st =
329 &fx->factory,
330 &fx->stream_factory_cfg,
331 &fx->stream_env );
332 assert_int_equal(st, STREAM_STATUS_OK);
333
334 st =
336 &fx->desc,
337 "fs",
338 &fx->fs_stream_cfg,
339 &fx->fs_stream_env,
340 fx->stream_env.mem );
341 assert_int_equal(st, STREAM_STATUS_OK);
342
343 st =
345 fx->factory,
346 &fx->desc );
347 assert_int_equal(st, STREAM_STATUS_OK);
348
349 fx->args.path = "crazy_injection.txt";
351 fx->args.autoclose = true;
352
353 *state = fx;
354 return 0;
355}
356
365static int teardown_stream_fact_create_fs(void **state)
366{
367 test_stream_fact_create_fs_fixture_t *fx =
368 (test_stream_fact_create_fs_fixture_t *)(*state);
369
370 if (fx->out) {
371 stream_destroy(&fx->out);
372 fx->out = NULL;
373 }
374
375 stream_destroy_factory(&fx->factory);
376
377 free(fx);
378 return 0;
379}
380
381//-----------------------------------------------------------------------------
382// TEST
383//-----------------------------------------------------------------------------
384
397static void test_stream_fact_create_fs(void **state)
398{
399 test_stream_fact_create_fs_fixture_t *fx =
400 (test_stream_fact_create_fs_fixture_t *)(*state);
401 const test_stream_fact_create_fs_case_t *tc = fx->tc;
402
403 // ARRANGE
406
407 const stream_factory_t *factory_arg = fx->factory;
408 const fs_stream_args_t *args_arg = &fx->args;
409 stream_key_t key_arg = fx->desc.key;
410 stream_t **out_arg = &fx->out;
411
412 // invalid args
413 if (tc->scenario == STREAM_FACT_CREATE_FS_SCENARIO_OUT_NULL) out_arg = NULL;
414 if (tc->scenario == STREAM_FACT_CREATE_FS_SCENARIO_ARGS_NULL) args_arg = NULL;
415 if (tc->scenario == STREAM_FACT_CREATE_FS_SCENARIO_PATH_NULL) fx->args.path = NULL;
416 if (tc->scenario == STREAM_FACT_CREATE_FS_SCENARIO_PATH_EMPTY) fx->args.path = "";
417 if (tc->scenario == STREAM_FACT_CREATE_FS_SCENARIO_FLAGS_ZERO) fx->args.flags = (uint32_t)0;
418 if (tc->scenario == STREAM_FACT_CREATE_FS_SCENARIO_FACTORY_NULL) factory_arg = NULL;
419 if (tc->scenario == STREAM_FACT_CREATE_FS_SCENARIO_KEY_NULL) key_arg = NULL;
420 if (tc->scenario == STREAM_FACT_CREATE_FS_SCENARIO_KEY_EMPTY) key_arg = "";
421 if (tc->scenario == STREAM_FACT_CREATE_FS_SCENARIO_KEY_UNKNOWN) key_arg = "unknown_key";
422
423 // ensure OUT_EXPECT_UNCHANGED is meaningful
424 if (tc->out_expect == OUT_EXPECT_UNCHANGED && out_arg != NULL) {
425 fx->out = (stream_t *)(uintptr_t)0xDEADC0DEu; // sentinel
426 }
427
428 stream_t *out_arg_snapshot = fx->out;
429
430 // ACT
431 ret = stream_factory_create_stream(factory_arg, key_arg, args_arg, out_arg);
432
433 // ASSERT
434 assert_int_equal(ret, tc->expected_ret);
435
436 switch (tc->out_expect) {
437 case OUT_CHECK_NONE: break;
438 case OUT_EXPECT_NULL: assert_null(fx->out); break;
439 case OUT_EXPECT_NON_NULL: assert_non_null(fx->out); break;
440 case OUT_EXPECT_UNCHANGED:
441 assert_ptr_equal(out_arg_snapshot, fx->out);
442 fx->out = NULL; // prevent teardown from destroying sentinel
443 break;
444 default: fail();
445 }
446
447 if (tc->scenario == STREAM_FACT_CREATE_FS_SCENARIO_OK) {
448 assert_non_null(fx->out);
449 const char msg[] = "hello";
450 size_t w = stream_write(fx->out, msg, sizeof(msg) - 1, &st);
451 assert_int_equal((int)w, (int)(sizeof(msg) - 1));
452 assert_int_equal(st, STREAM_STATUS_OK);
453 assert_int_equal(fake_file_backing_len(), sizeof(msg) - 1);
454 assert_memory_equal(fx->backing, msg, sizeof(msg) - 1);
455 assert_int_equal(stream_flush(fx->out), STREAM_STATUS_OK);
456 }
457}
458
459//-----------------------------------------------------------------------------
460// CASES
461//-----------------------------------------------------------------------------
462
463static const test_stream_fact_create_fs_case_t CASE_STREAM_FACT_CREATE_FS_OK = {
464 .name = "fs_stream_fact_create_stream_ok",
466
467 .expected_ret = STREAM_STATUS_OK,
468 .out_expect = OUT_EXPECT_NON_NULL
469};
470
471static const test_stream_fact_create_fs_case_t CASE_STREAM_FACT_CREATE_FS_ARGS_NULL = {
472 .name = "fs_stream_fact_create_stream_args_null",
474
475 .expected_ret = STREAM_STATUS_INVALID,
476 .out_expect = OUT_EXPECT_UNCHANGED
477};
478
479static const test_stream_fact_create_fs_case_t CASE_STREAM_FACT_CREATE_FS_OUT_NULL = {
480 .name = "fs_stream_fact_create_stream_out_null",
482
483 .expected_ret = STREAM_STATUS_INVALID,
484 .out_expect = OUT_CHECK_NONE
485};
486
487static const test_stream_fact_create_fs_case_t CASE_STREAM_FACT_CREATE_FS_PATH_NULL = {
488 .name = "fs_stream_fact_create_stream_path_null",
490
491 .expected_ret = STREAM_STATUS_INVALID,
492 .out_expect = OUT_EXPECT_UNCHANGED
493};
494
495static const test_stream_fact_create_fs_case_t CASE_STREAM_FACT_CREATE_FS_PATH_EMPTY = {
496 .name = "fs_stream_fact_create_stream_path_empty",
498
499 .expected_ret = STREAM_STATUS_INVALID,
500 .out_expect = OUT_EXPECT_UNCHANGED
501};
502
503static const test_stream_fact_create_fs_case_t CASE_STREAM_FACT_CREATE_FS_FLAGS_ZERO = {
504 .name = "fs_stream_fact_create_stream_flags_zero",
506
507 .expected_ret = STREAM_STATUS_INVALID,
508 .out_expect = OUT_EXPECT_UNCHANGED
509};
510
511static const test_stream_fact_create_fs_case_t CASE_STREAM_FACT_CREATE_FS_OPEN_FAIL = {
512 .name = "fs_stream_fact_create_stream_open_fail",
514
515 .expected_ret = STREAM_STATUS_IO_ERROR,
516 .out_expect = OUT_EXPECT_UNCHANGED
517};
518
519static const test_stream_fact_create_fs_case_t CASE_STREAM_FACT_CREATE_FS_FACTORY_NULL = {
520 .name = "fs_stream_fact_create_stream_factory_null",
522
523 .expected_ret = STREAM_STATUS_INVALID,
524 .out_expect = OUT_EXPECT_UNCHANGED
525};
526
527static const test_stream_fact_create_fs_case_t CASE_STREAM_FACT_CREATE_FS_KEY_NULL = {
528 .name = "fs_stream_fact_create_stream_key_null",
530
531 .expected_ret = STREAM_STATUS_INVALID,
532 .out_expect = OUT_EXPECT_UNCHANGED
533};
534
535static const test_stream_fact_create_fs_case_t CASE_STREAM_FACT_CREATE_FS_KEY_EMPTY = {
536 .name = "fs_stream_fact_create_stream_key_empty",
538
539 .expected_ret = STREAM_STATUS_INVALID,
540 .out_expect = OUT_EXPECT_UNCHANGED
541};
542
543static const test_stream_fact_create_fs_case_t CASE_STREAM_FACT_CREATE_FS_KEY_UNKNOWN = {
544 .name = "fs_stream_fact_create_stream_key_unknown",
546
547 .expected_ret = STREAM_STATUS_NOT_FOUND,
548 .out_expect = OUT_EXPECT_UNCHANGED
549};
550
551//-----------------------------------------------------------------------------
552// CASES REGISTRY
553//-----------------------------------------------------------------------------
554
555#define STREAM_FACT_CREATE_FS_CASES(X) \
556X(CASE_STREAM_FACT_CREATE_FS_OK) \
557X(CASE_STREAM_FACT_CREATE_FS_ARGS_NULL) \
558X(CASE_STREAM_FACT_CREATE_FS_OUT_NULL) \
559X(CASE_STREAM_FACT_CREATE_FS_PATH_NULL) \
560X(CASE_STREAM_FACT_CREATE_FS_PATH_EMPTY) \
561X(CASE_STREAM_FACT_CREATE_FS_FLAGS_ZERO) \
562X(CASE_STREAM_FACT_CREATE_FS_OPEN_FAIL) \
563X(CASE_STREAM_FACT_CREATE_FS_FACTORY_NULL) \
564X(CASE_STREAM_FACT_CREATE_FS_KEY_NULL) \
565X(CASE_STREAM_FACT_CREATE_FS_KEY_EMPTY) \
566X(CASE_STREAM_FACT_CREATE_FS_KEY_UNKNOWN)
567
568#define STREAM_MAKE_FACT_CREATE_FS_TEST(case_sym) \
569LEXLEO_MAKE_TEST(stream_fact_create_fs, case_sym)
570
571static const struct CMUnitTest fact_create_fs_tests[] = {
572 STREAM_FACT_CREATE_FS_CASES(STREAM_MAKE_FACT_CREATE_FS_TEST)
573};
574
575#undef STREAM_FACT_CREATE_FS_CASES
576#undef STREAM_MAKE_FACT_CREATE_FS_TEST
577
578//-----------------------------------------------------------------------------
579// MAIN
580//-----------------------------------------------------------------------------
581
582int main(void) {
583 int failed = 0;
584 failed += cmocka_run_group_tests(fact_create_fs_tests, NULL, NULL);
585 return failed;
586}
587
Composition Root API for wiring the fs_stream adapter into the stream factory.
stream_status_t fs_stream_create_desc(stream_adapter_desc_t *out, stream_key_t key, const fs_stream_cfg_t *cfg, const fs_stream_env_t *env, const osal_mem_ops_t *mem)
Build an adapter descriptor for registering fs_stream in a factory.
Definition fs_stream.c:256
stream_fact_create_fs_scenario_t
Scenarios for stream_factory_create_stream() / fs_stream integration.
@ OSAL_FILE_WRITE
@ OSAL_FILE_TRUNC
@ OSAL_FILE_CREATE
@ OSAL_FILE_READ
osal_file_status_t
int main()
Definition main.c:5
const osal_file_ops_t * osal_file_test_fake_ops(void)
void * osal_memset(void *s, int c, size_t n)
Definition osal_mem.c:30
const osal_mem_ops_t * osal_mem_default_ops(void)
Borrower-facing runtime operations for the stream port.
stream_status_t stream_flush(stream_t *s)
Flush a stream.
Definition stream.c:62
size_t stream_write(stream_t *s, const void *buf, size_t n, stream_status_t *st)
Write bytes to a stream.
Definition stream.c:38
Composition Root factory API for the stream port.
stream_status_t stream_create_factory(stream_factory_t **out, const stream_factory_cfg_t *cfg, const stream_env_t *env)
Create a stream factory.
stream_status_t stream_factory_add_adapter(stream_factory_t *fact, const stream_adapter_desc_t *desc)
Register an adapter descriptor into a stream factory.
stream_status_t stream_factory_create_stream(const stream_factory_t *f, stream_key_t key, const void *args, stream_t **out)
Create a stream from a registered adapter key.
void stream_destroy_factory(stream_factory_t **fact)
Destroy a stream factory.
const char * stream_key_t
Public identifier type for a registered stream adapter.
Lifecycle services for stream_t handles.
void stream_destroy(stream_t **s)
Destroy a stream handle.
Definition stream.c:98
stream_status_t
Public status codes used by the stream port.
@ STREAM_STATUS_INVALID
@ STREAM_STATUS_IO_ERROR
@ STREAM_STATUS_OK
@ STREAM_STATUS_NOT_FOUND
Arguments provided when creating a file-backed stream.
const char * path
UTF-8 path of the target file.
Configuration type for the fs_stream adapter.
Injected dependencies for the fs_stream adapter.
Public descriptor used to register a concrete stream adapter.
Runtime environment for the stream port.
Definition stream_env.h:35
Configuration for stream_factory_t.
Private handle structure for a stream_factory_t.
Private handle structure for a stream_t.