LexLeo 0.0.0-dev+f8e5087-dirty
Technical documentation
Loading...
Searching...
No Matches
integration_test_stream_factory.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
36
37#include "osal/mem/osal_mem.h"
38
42
43#include "lexleo_cmocka.h"
44
47//-----------------------------------------------------------------------------
48// LOCAL TEST DOUBLES
49//-----------------------------------------------------------------------------
50
51#define TEST_STREAM_SENTINEL_1 ((stream_t *)0x1111)
52#define TEST_STREAM_SENTINEL_2 ((stream_t *)0x2222)
53
62static stream_status_t test_stream_ctor_1(
63 const void *ud,
64 const void *args,
65 stream_t **out)
66{
67 (void)ud;
68 (void)args;
69
70 if (!out) return STREAM_STATUS_INVALID;
71
72 *out = TEST_STREAM_SENTINEL_1;
73 return STREAM_STATUS_OK;
74}
75
84static stream_status_t test_stream_ctor_2(
85 const void *ud,
86 const void *args,
87 stream_t **out)
88{
89 (void)ud;
90 (void)args;
91
92 if (!out) return STREAM_STATUS_INVALID;
93
94 *out = TEST_STREAM_SENTINEL_2;
95 return STREAM_STATUS_OK;
96}
97
114static stream_adapter_desc_t make_test_desc(
115 stream_key_t key,
116 stream_ctor_fn_t ctor)
117{
118 stream_adapter_desc_t d = {0};
119
120 d.key = key;
121 d.ctor = ctor;
122 d.ud = NULL;
123 d.ud_dtor = NULL;
124
125 return d;
126}
127
246
256typedef enum {
257 OUT_CHECK_NONE,
258 OUT_EXPECT_NULL,
259 OUT_EXPECT_NON_NULL,
260 OUT_EXPECT_UNCHANGED
261} out_expect_t;
262
272typedef struct {
273 const char *name;
274
275 // arrange
277
278 // assert
279 stream_status_t expected_ret;
280 out_expect_t out_expect;
281} test_stream_fact_lifecycle_case_t;
282
292typedef struct {
293 // runtime resource
294 stream_factory_t *out;
295
296 // injection
297 stream_factory_cfg_t stream_factory_cfg;
298 stream_env_t stream_env;
299
300 // reference to test case
301 const test_stream_fact_lifecycle_case_t *tc;
302} test_stream_fact_lifecycle_fixture_t;
303
304//-----------------------------------------------------------------------------
305// FIXTURES
306//-----------------------------------------------------------------------------
307
312static int setup_stream_fact_lifecycle(void **state)
313{
314 const test_stream_fact_lifecycle_case_t *tc =
315 (const test_stream_fact_lifecycle_case_t *)(*state);
316
317 test_stream_fact_lifecycle_fixture_t *fx =
318 (test_stream_fact_lifecycle_fixture_t *)malloc(sizeof(*fx));
319 if (!fx) return -1;
320
321 osal_memset(fx, 0, sizeof(*fx));
322 fx->tc = tc;
323
324 fx->stream_factory_cfg.fact_cap = 8;
325
326 // DI
327 fx->stream_env.mem = osal_mem_default_ops();
328
329 *state = fx;
330 return 0;
331}
332
336static int teardown_stream_fact_lifecycle(void **state)
337{
338 test_stream_fact_lifecycle_fixture_t *fx =
339 (test_stream_fact_lifecycle_fixture_t *)(*state);
340
341 if (fx->out) {
342 stream_destroy_factory(&fx->out);
343 fx->out = NULL;
344 }
345
346 free(fx);
347 return 0;
348}
349
350//-----------------------------------------------------------------------------
351// TEST
352//-----------------------------------------------------------------------------
353
358static void test_stream_fact_lifecycle(void **state)
359{
360 test_stream_fact_lifecycle_fixture_t *fx =
361 (test_stream_fact_lifecycle_fixture_t *)(*state);
362 const test_stream_fact_lifecycle_case_t *tc = fx->tc;
363
364 // ARRANGE
366
367 stream_factory_t **out_arg = &fx->out;
368 const stream_factory_cfg_t *cfg_arg = &fx->stream_factory_cfg;
369 stream_env_t env = fx->stream_env;
370 const stream_env_t *env_arg = &env;
371 osal_mem_ops_t mem_ops;
372 bool use_mem_ops_copy = false;
373
374 // invalid args
375 if (tc->scenario == STREAM_FACT_LIFECYCLE_SCENARIO_OUT_NULL) out_arg = NULL;
376 if (tc->scenario == STREAM_FACT_LIFECYCLE_SCENARIO_CFG_NULL) cfg_arg = NULL;
377 if (tc->scenario == STREAM_FACT_LIFECYCLE_SCENARIO_ENV_NULL) env_arg = NULL;
378 if (tc->scenario == STREAM_FACT_LIFECYCLE_SCENARIO_ENV_MEM_NULL) env.mem = NULL;
380 mem_ops = *fx->stream_env.mem;
381 use_mem_ops_copy = true;
382 mem_ops.calloc = NULL;
383 }
385 mem_ops = *fx->stream_env.mem;
386 use_mem_ops_copy = true;
387 mem_ops.free = NULL;
388 }
389
390 if (use_mem_ops_copy) {
391 env.mem = &mem_ops;
392 }
393
394 // ensure OUT_EXPECT_UNCHANGED is meaningful
395 if (tc->out_expect == OUT_EXPECT_UNCHANGED && out_arg != NULL) {
396 fx->out = (stream_factory_t *)(uintptr_t)0xDEADC0DEu; // sentinel
397 }
398
399 stream_factory_t *out_arg_snapshot = fx->out;
400
401 // ACT
402 ret = stream_create_factory(out_arg, cfg_arg, env_arg);
404 assert_int_equal(ret, STREAM_STATUS_OK);
405 assert_non_null(fx->out);
406
407 stream_destroy_factory(&fx->out);
408 assert_null(fx->out);
409
410 stream_destroy_factory(&fx->out);
411 assert_null(fx->out);
412 }
413
414 // ASSERT
415 assert_int_equal(ret, tc->expected_ret);
416
417 switch (tc->out_expect) {
418 case OUT_CHECK_NONE: break;
419 case OUT_EXPECT_NULL: assert_null(fx->out); break;
420 case OUT_EXPECT_NON_NULL: assert_non_null(fx->out); break;
421 case OUT_EXPECT_UNCHANGED:
422 assert_ptr_equal(out_arg_snapshot, fx->out);
423 fx->out = NULL; // prevent teardown from destroying sentinel
424 break;
425 default: fail();
426 }
427}
428
429//-----------------------------------------------------------------------------
430// CASES
431//-----------------------------------------------------------------------------
432
433static const test_stream_fact_lifecycle_case_t CASE_STREAM_FACT_LIFECYCLE_OK = {
434 .name = "stream_fact_lifecycle_ok",
436
437 .expected_ret = STREAM_STATUS_OK,
438 .out_expect = OUT_EXPECT_NON_NULL
439};
440
441static const test_stream_fact_lifecycle_case_t CASE_STREAM_FACT_LIFECYCLE_OUT_NULL = {
442 .name = "stream_fact_lifecycle_out_null",
444
445 .expected_ret = STREAM_STATUS_INVALID,
446 .out_expect = OUT_CHECK_NONE
447};
448
449static const test_stream_fact_lifecycle_case_t CASE_STREAM_FACT_LIFECYCLE_CFG_NULL = {
450 .name = "stream_fact_lifecycle_cfg_null",
452
453 .expected_ret = STREAM_STATUS_INVALID,
454 .out_expect = OUT_EXPECT_UNCHANGED
455};
456
457static const test_stream_fact_lifecycle_case_t CASE_STREAM_FACT_LIFECYCLE_ENV_NULL = {
458 .name = "stream_fact_lifecycle_env_null",
460
461 .expected_ret = STREAM_STATUS_INVALID,
462 .out_expect = OUT_EXPECT_UNCHANGED
463};
464
465static const test_stream_fact_lifecycle_case_t CASE_STREAM_FACT_LIFECYCLE_ENV_MEM_NULL = {
466 .name = "stream_fact_lifecycle_env_mem_null",
468
469 .expected_ret = STREAM_STATUS_INVALID,
470 .out_expect = OUT_EXPECT_UNCHANGED
471};
472
473static const test_stream_fact_lifecycle_case_t CASE_STREAM_FACT_LIFECYCLE_ENV_MEM_CALLOC_NULL = {
474 .name = "stream_fact_lifecycle_env_mem_calloc_null",
476
477 .expected_ret = STREAM_STATUS_INVALID,
478 .out_expect = OUT_EXPECT_UNCHANGED
479};
480
481static const test_stream_fact_lifecycle_case_t CASE_STREAM_FACT_LIFECYCLE_ENV_MEM_FREE_NULL = {
482 .name = "stream_fact_lifecycle_env_mem_free_null",
484
485 .expected_ret = STREAM_STATUS_INVALID,
486 .out_expect = OUT_EXPECT_UNCHANGED
487};
488
489static const test_stream_fact_lifecycle_case_t CASE_STREAM_FACT_LIFECYCLE_DESTROY_IDEMPOTENT = {
490 .name = "stream_fact_lifecycle_destroy_idempotent",
492
493 .expected_ret = STREAM_STATUS_OK,
494 .out_expect = OUT_EXPECT_NULL
495};
496
497//-----------------------------------------------------------------------------
498// CASES REGISTRY
499//-----------------------------------------------------------------------------
500
501#define STREAM_FACT_LIFECYCLE_CASES(X) \
502X(CASE_STREAM_FACT_LIFECYCLE_OK) \
503X(CASE_STREAM_FACT_LIFECYCLE_OUT_NULL) \
504X(CASE_STREAM_FACT_LIFECYCLE_CFG_NULL) \
505X(CASE_STREAM_FACT_LIFECYCLE_ENV_NULL) \
506X(CASE_STREAM_FACT_LIFECYCLE_ENV_MEM_NULL) \
507X(CASE_STREAM_FACT_LIFECYCLE_ENV_MEM_CALLOC_NULL) \
508X(CASE_STREAM_FACT_LIFECYCLE_ENV_MEM_FREE_NULL) \
509X(CASE_STREAM_FACT_LIFECYCLE_DESTROY_IDEMPOTENT)
510
511#define STREAM_MAKE_FACT_LIFECYCLE_TEST(case_sym) \
512LEXLEO_MAKE_TEST(stream_fact_lifecycle, case_sym)
513
514static const struct CMUnitTest fact_lifecycle_tests[] = {
515 STREAM_FACT_LIFECYCLE_CASES(STREAM_MAKE_FACT_LIFECYCLE_TEST)
516};
517
518#undef STREAM_FACT_LIFECYCLE_CASES
519#undef STREAM_MAKE_FACT_LIFECYCLE_TEST
520
629
642typedef struct {
643 const char *name;
644
645 // arrange
647
648 // assert
649 stream_status_t expected_ret;
650 bool check_resolution;
651 stream_status_t expected_create_ret;
652 stream_t *expected_created_stream;
653} test_stream_fact_add_adapter_case_t;
654
667typedef struct {
668 // runtime resources
669 stream_factory_t *factory;
670 stream_t *created_stream;
671
672 // configuration
673 stream_factory_cfg_t stream_factory_cfg;
674
675 // injection
676 stream_env_t stream_env;
677
678 // descriptors under test
680 stream_adapter_desc_t other_desc;
681
682 // dummy args used by test ctors
683 int dummy_args;
684
685 // reference to test case
686 const test_stream_fact_add_adapter_case_t *tc;
687} test_stream_fact_add_adapter_fixture_t;
688
689//-----------------------------------------------------------------------------
690// FIXTURES
691//-----------------------------------------------------------------------------
692
697static int setup_stream_fact_add_adapter(void **state)
698{
699 const test_stream_fact_add_adapter_case_t *tc =
700 (const test_stream_fact_add_adapter_case_t *)(*state);
701
702 test_stream_fact_add_adapter_fixture_t *fx =
703 (test_stream_fact_add_adapter_fixture_t *)malloc(sizeof(*fx));
704 if (!fx) return -1;
705
706 osal_memset(fx, 0, sizeof(*fx));
707 fx->tc = tc;
708
709 // DI
710 fx->stream_env.mem = osal_mem_default_ops();
711
712 fx->stream_factory_cfg.fact_cap = (tc->scenario == STREAM_FACT_ADD_ADAPTER_SCENARIO_CAP_REACHED) ? 1 : 8;
713
714 assert_int_equal(
715 stream_create_factory(&fx->factory, &fx->stream_factory_cfg, &fx->stream_env),
717
718 // valid test descriptors used by scenarios
719 fx->desc = make_test_desc("key_1", test_stream_ctor_1);
720 fx->other_desc = make_test_desc("key_2", test_stream_ctor_2);
721
722 *state = fx;
723 return 0;
724}
725
729static int teardown_stream_fact_add_adapter(void **state)
730{
731 test_stream_fact_add_adapter_fixture_t *fx =
732 (test_stream_fact_add_adapter_fixture_t *)(*state);
733
734 if (fx->factory) {
735 stream_destroy_factory(&fx->factory);
736 fx->factory = NULL;
737 }
738
739 free(fx);
740 return 0;
741}
742
743//-----------------------------------------------------------------------------
744// TEST
745//-----------------------------------------------------------------------------
746
750static void test_stream_fact_add_adapter(void **state)
751{
752 test_stream_fact_add_adapter_fixture_t *fx =
753 (test_stream_fact_add_adapter_fixture_t *)(*state);
754 const test_stream_fact_add_adapter_case_t *tc = fx->tc;
755
756 // ARRANGE
758
759 stream_factory_t *fact_arg = fx->factory;
760 const stream_adapter_desc_t *desc_arg = &fx->desc;
761 stream_key_t resolution_key = fx->desc.key;
762
764 assert_int_equal(
765 stream_factory_add_adapter(fact_arg, &fx->desc),
767 fx->other_desc.key = fx->desc.key;
768 desc_arg = &fx->other_desc;
769 resolution_key = fx->desc.key;
770 }
771
772 // invalid args
773 if (tc->scenario == STREAM_FACT_ADD_ADAPTER_SCENARIO_FACT_NULL) fact_arg = NULL;
774 if (tc->scenario == STREAM_FACT_ADD_ADAPTER_SCENARIO_DESC_NULL) desc_arg = NULL;
775 if (tc->scenario == STREAM_FACT_ADD_ADAPTER_SCENARIO_KEY_NULL) fx->desc.key = NULL;
776 if (tc->scenario == STREAM_FACT_ADD_ADAPTER_SCENARIO_KEY_EMPTY) fx->desc.key = "";
777 if (tc->scenario == STREAM_FACT_ADD_ADAPTER_SCENARIO_CTOR_NULL) fx->desc.ctor = NULL;
778
779 // make factory full
781 assert_int_equal(
782 stream_factory_add_adapter(fact_arg, &fx->desc),
784 desc_arg = &fx->other_desc;
785 resolution_key = fx->other_desc.key;
786 }
787
788 // ACT
789 ret = stream_factory_add_adapter(fact_arg, desc_arg);
790
791 // ASSERT
792 assert_int_equal(ret, tc->expected_ret);
793 if (tc->check_resolution) {
794 assert_null(fx->created_stream);
795 assert_int_equal(
797 fact_arg,
798 resolution_key,
799 (void*)&fx->dummy_args,
800 &fx->created_stream ),
801 tc->expected_create_ret );
802 assert_ptr_equal(
803 fx->created_stream,
804 tc->expected_created_stream );
805 }
806}
807
808//-----------------------------------------------------------------------------
809// CASES
810//-----------------------------------------------------------------------------
811
812static const test_stream_fact_add_adapter_case_t CASE_STREAM_FACT_ADD_ADAPTER_FACT_NULL = {
813 .name = "stream_fact_add_adapter_fact_null",
815
816 .expected_ret = STREAM_STATUS_INVALID,
817 .check_resolution = false,
818};
819
820static const test_stream_fact_add_adapter_case_t CASE_STREAM_FACT_ADD_ADAPTER_DESC_NULL = {
821 .name = "stream_fact_add_adapter_desc_null",
823
824 .expected_ret = STREAM_STATUS_INVALID,
825 .check_resolution = false,
826};
827
828static const test_stream_fact_add_adapter_case_t CASE_STREAM_FACT_ADD_ADAPTER_KEY_NULL = {
829 .name = "stream_fact_add_adapter_key_null",
831
832 .expected_ret = STREAM_STATUS_INVALID,
833 .check_resolution = false,
834};
835
836static const test_stream_fact_add_adapter_case_t CASE_STREAM_FACT_ADD_ADAPTER_KEY_EMPTY = {
837 .name = "stream_fact_add_adapter_key_empty",
839
840 .expected_ret = STREAM_STATUS_INVALID,
841 .check_resolution = false,
842};
843
844static const test_stream_fact_add_adapter_case_t CASE_STREAM_FACT_ADD_ADAPTER_CTOR_NULL = {
845 .name = "stream_fact_add_adapter_ctor_null",
847
848 .expected_ret = STREAM_STATUS_INVALID,
849 .check_resolution = false,
850};
851
852static const test_stream_fact_add_adapter_case_t CASE_STREAM_FACT_ADD_ADAPTER_DUPLICATE_KEY = {
853 .name = "stream_fact_add_adapter_duplicate_key",
855
856 .expected_ret = STREAM_STATUS_ALREADY_EXISTS,
857 .check_resolution = true,
858 .expected_create_ret = STREAM_STATUS_OK,
859 .expected_created_stream = TEST_STREAM_SENTINEL_1,
860};
861
862static const test_stream_fact_add_adapter_case_t CASE_STREAM_FACT_ADD_ADAPTER_CAP_REACHED = {
863 .name = "stream_fact_add_adapter_cap_reached",
865
866 .expected_ret = STREAM_STATUS_FULL,
867 .check_resolution = true,
868 .expected_create_ret = STREAM_STATUS_NOT_FOUND,
869 .expected_created_stream = NULL,
870};
871
872static const test_stream_fact_add_adapter_case_t CASE_STREAM_FACT_ADD_ADAPTER_OK = {
873 .name = "stream_fact_add_adapter_ok",
875
876 .expected_ret = STREAM_STATUS_OK,
877 .check_resolution = true,
878 .expected_create_ret = STREAM_STATUS_OK,
879 .expected_created_stream = TEST_STREAM_SENTINEL_1,
880};
881
882//-----------------------------------------------------------------------------
883// CASES REGISTRY
884//-----------------------------------------------------------------------------
885
886#define STREAM_FACT_ADD_ADAPTER_CASES(X) \
887X(CASE_STREAM_FACT_ADD_ADAPTER_FACT_NULL) \
888X(CASE_STREAM_FACT_ADD_ADAPTER_DESC_NULL) \
889X(CASE_STREAM_FACT_ADD_ADAPTER_KEY_NULL) \
890X(CASE_STREAM_FACT_ADD_ADAPTER_KEY_EMPTY) \
891X(CASE_STREAM_FACT_ADD_ADAPTER_CTOR_NULL) \
892X(CASE_STREAM_FACT_ADD_ADAPTER_DUPLICATE_KEY) \
893X(CASE_STREAM_FACT_ADD_ADAPTER_CAP_REACHED) \
894X(CASE_STREAM_FACT_ADD_ADAPTER_OK)
895
896#define STREAM_MAKE_STREAM_FACT_ADD_ADAPTER_TEST(case_sym) \
897LEXLEO_MAKE_TEST(stream_fact_add_adapter, case_sym)
898
899static const struct CMUnitTest stream_fact_add_adapter_tests[] = {
900 STREAM_FACT_ADD_ADAPTER_CASES(STREAM_MAKE_STREAM_FACT_ADD_ADAPTER_TEST)
901};
902
903#undef STREAM_FACT_ADD_ADAPTER_CASES
904#undef STREAM_MAKE_STREAM_FACT_ADD_ADAPTER_TEST
905
906//-----------------------------------------------------------------------------
907// MAIN
908//-----------------------------------------------------------------------------
909
910int main(void) {
911 int failed = 0;
912 failed += cmocka_run_group_tests(fact_lifecycle_tests, NULL, NULL);
913 failed += cmocka_run_group_tests(stream_fact_add_adapter_tests, NULL, NULL);
914 return failed;
915}
916
stream_fact_lifecycle_scenario_t
Scenarios for stream_create_factory() / stream_destroy_factory().
@ STREAM_FACT_LIFECYCLE_SCENARIO_ENV_MEM_NULL
@ STREAM_FACT_LIFECYCLE_SCENARIO_ENV_MEM_CALLOC_NULL
@ STREAM_FACT_LIFECYCLE_SCENARIO_DESTROY_IDEMPOTENT
@ STREAM_FACT_LIFECYCLE_SCENARIO_ENV_NULL
@ STREAM_FACT_LIFECYCLE_SCENARIO_OUT_NULL
@ STREAM_FACT_LIFECYCLE_SCENARIO_ENV_MEM_FREE_NULL
@ STREAM_FACT_LIFECYCLE_SCENARIO_CFG_NULL
stream_fact_add_adapter_scenario_t
Scenarios for stream_factory_add_adapter().
@ STREAM_FACT_ADD_ADAPTER_SCENARIO_KEY_EMPTY
@ STREAM_FACT_ADD_ADAPTER_SCENARIO_KEY_NULL
@ STREAM_FACT_ADD_ADAPTER_SCENARIO_DUPLICATE_KEY
@ STREAM_FACT_ADD_ADAPTER_SCENARIO_CTOR_NULL
@ STREAM_FACT_ADD_ADAPTER_SCENARIO_DESC_NULL
@ STREAM_FACT_ADD_ADAPTER_SCENARIO_FACT_NULL
@ STREAM_FACT_ADD_ADAPTER_SCENARIO_CAP_REACHED
@ STREAM_FACT_ADD_ADAPTER_SCENARIO_OK
int main()
Definition main.c:5
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)
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.
stream_status_t(* stream_ctor_fn_t)(const void *ud, const void *args, stream_t **out)
Adapter constructor contract used by stream factory services.
const char * stream_key_t
Public identifier type for a registered stream adapter.
stream_status_t
Public status codes used by the stream port.
@ STREAM_STATUS_INVALID
@ STREAM_STATUS_OK
@ STREAM_STATUS_FULL
@ STREAM_STATUS_NOT_FOUND
@ STREAM_STATUS_ALREADY_EXISTS
void *(* calloc)(size_t nmemb, size_t size)
void(* free)(void *ptr)
Public descriptor used to register a concrete stream adapter.
stream_key_t key
Public key used to identify the adapter.
const void * ud
Optional opaque user data bound to the constructor.
ud_dtor_fn_t ud_dtor
Optional destructor for ud.
stream_ctor_fn_t ctor
Adapter constructor used to create a stream_t.
Runtime environment for the stream port.
Definition stream_env.h:35
const osal_mem_ops_t * mem
Memory operations used by the stream port.
Definition stream_env.h:43
Configuration for stream_factory_t.
Private handle structure for a stream_factory_t.
Private handle structure for a stream_t.