LexLeo 0.0.0-dev+f8e5087-dirty
Technical documentation
Loading...
Searching...
No Matches
unit_test_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
35
38
40
41#include "osal/mem/osal_mem.h"
43
47
48#include "lexleo_cmocka.h"
49
66static void test_fs_stream_default_cfg(void **state)
67{
68 (void)state;
69
71
72 assert_int_equal(ret.reserved, 0);
73}
74
100static void test_fs_stream_default_env(void **state) {
101 (void)state;
102
103 const osal_file_env_t dummy_file_env = {0};
104 const osal_file_env_t *dummy_file_env_p = &dummy_file_env;
105
106 const osal_file_ops_t *dummy_file_ops_p = (const osal_file_ops_t *)(uintptr_t)0x1234u;
107
108 const stream_env_t dummy_port_env = {0};
109 const stream_env_t *dummy_port_env_p = &dummy_port_env;
110
111 fs_stream_env_t ret =
112 fs_stream_default_env(dummy_file_env_p, dummy_file_ops_p, dummy_port_env_p);
113
114 assert_memory_equal(&ret.file_env, dummy_file_env_p, sizeof(ret.file_env));
115 assert_ptr_equal(ret.file_ops, dummy_file_ops_p);
116 assert_memory_equal(&ret.port_env, dummy_port_env_p, sizeof(ret.port_env));
117}
118
250
269typedef enum {
270 OUT_CHECK_NONE,
271 OUT_EXPECT_NULL,
272 OUT_EXPECT_NON_NULL,
273 OUT_EXPECT_UNCHANGED
274} out_expect_t;
275
285typedef struct {
286 const char *name;
287
288 // arrange
290 size_t fail_call_idx; // 0 = no OOM, otherwise 1-based (scenario == FS_CREATE_STREAM_SCENARIO_OOM)
291 osal_file_status_t open_fail_status; // e.g. OSAL_FILE_NOENT
292
293 // assert
294 stream_status_t expected_ret;
295 out_expect_t out_expect;
296} test_fs_stream_create_stream_case_t;
297
308typedef struct {
309 // runtime resources
310 stream_t *out;
311
312 // injection
313 fs_stream_env_t env;
314
315 fs_stream_args_t args;
316 fs_stream_cfg_t cfg;
317
318 // fake file backing
319 uint8_t backing[64];
320
321 const test_fs_stream_create_stream_case_t *tc;
322} test_fs_stream_create_stream_fixture_t;
323
324//-----------------------------------------------------------------------------
325// FIXTURES
326//-----------------------------------------------------------------------------
327
331static int setup_fs_stream_create_stream(void **state)
332{
333 const test_fs_stream_create_stream_case_t *tc =
334 (const test_fs_stream_create_stream_case_t *)(*state);
335
336 test_fs_stream_create_stream_fixture_t *fx =
337 (test_fs_stream_create_stream_fixture_t *)malloc(sizeof(*fx));
338 if (!fx) return -1;
339
340 osal_memset(fx, 0, sizeof(*fx));
341 fx->tc = tc;
342
343 fake_file_reset();
344 fake_memory_reset();
345 if (tc->scenario == FS_CREATE_STREAM_SCENARIO_OOM && tc->fail_call_idx > 0) {
346 fake_memory_fail_only_on_call(tc->fail_call_idx);
347 }
348
349 osal_memset(fx->backing, 0, sizeof(fx->backing));
350 fake_file_set_backing(fx->backing, sizeof(fx->backing), 0);
351 fake_file_set_pos(0);
352 fake_file_fail_disable();
353
354 if (tc->scenario == FS_CREATE_STREAM_SCENARIO_OPEN_FAIL) {
355 fake_file_fail_enable(FAKE_FILE_OP_OPEN, 1, tc->open_fail_status);
356 }
357
358 // DI
359 fx->env.file_env.mem = osal_mem_test_fake_ops();
360 fx->env.file_ops = osal_file_test_fake_ops();
361 fx->env.port_env.mem = osal_mem_test_fake_ops();
362
363 fx->args.path = "crazy_injection.txt";
365 fx->args.autoclose = true;
366
367 fx->cfg.reserved = 0; /* Reserved for future use. */
368
369 *state = fx;
370 return 0;
371}
372
376static int teardown_fs_stream_create_stream(void **state)
377{
378 test_fs_stream_create_stream_fixture_t *fx =
379 (test_fs_stream_create_stream_fixture_t *)(*state);
380
381 if (fx->out) {
382 stream_destroy(&fx->out);
383 fx->out = NULL;
384 }
385
386 assert_true(fake_memory_no_leak());
387 assert_true(fake_memory_no_invalid_free());
388 assert_true(fake_memory_no_double_free());
389
390 free(fx);
391 return 0;
392}
393
394//-----------------------------------------------------------------------------
395// TEST
396//-----------------------------------------------------------------------------
397
401static void test_fs_stream_create_stream(void **state)
402{
403 test_fs_stream_create_stream_fixture_t *fx =
404 (test_fs_stream_create_stream_fixture_t *)(*state);
405 const test_fs_stream_create_stream_case_t *tc = fx->tc;
406
407 // ARRANGE
410
411 stream_t **out_arg = &fx->out;
412 const fs_stream_args_t *args_arg = &fx->args;
413 const fs_stream_cfg_t *cfg_arg = &fx->cfg;
414 const fs_stream_env_t *env_arg = &fx->env;
415
416 // invalid args
417 if (tc->scenario == FS_CREATE_STREAM_SCENARIO_OUT_NULL) out_arg = NULL;
418 if (tc->scenario == FS_CREATE_STREAM_SCENARIO_ARGS_NULL) args_arg = NULL;
419 if (tc->scenario == FS_CREATE_STREAM_SCENARIO_CFG_NULL) cfg_arg = NULL;
420 if (tc->scenario == FS_CREATE_STREAM_SCENARIO_ENV_NULL) env_arg = NULL;
421 if (tc->scenario == FS_CREATE_STREAM_SCENARIO_PATH_NULL) fx->args.path = NULL;
422 if (tc->scenario == FS_CREATE_STREAM_SCENARIO_PATH_EMPTY) fx->args.path = "";
423 if (tc->scenario == FS_CREATE_STREAM_SCENARIO_FLAGS_ZERO) fx->args.flags = (uint32_t)0;
424
425 // ensure OUT_EXPECT_UNCHANGED is meaningful
426 if (tc->out_expect == OUT_EXPECT_UNCHANGED && out_arg != NULL) {
427 fx->out = (stream_t *)(uintptr_t)0xDEADC0DEu; // sentinel
428 }
429
430 stream_t *out_arg_snapshot = fx->out;
431
432 // ACT
433 ret = fs_stream_create_stream(out_arg, args_arg, cfg_arg, env_arg);
434
435 // ASSERT
436 assert_int_equal(ret, tc->expected_ret);
437
438 switch (tc->out_expect) {
439 case OUT_CHECK_NONE: break;
440 case OUT_EXPECT_NULL: assert_null(fx->out); break;
441 case OUT_EXPECT_NON_NULL: assert_non_null(fx->out); break;
442 case OUT_EXPECT_UNCHANGED:
443 assert_ptr_equal(out_arg_snapshot, fx->out);
444 fx->out = NULL; // prevent teardown from destroying sentinel
445 break;
446 default: assert_true(false);
447 }
448
449 if (tc->scenario == FS_CREATE_STREAM_SCENARIO_OK) {
450 assert_non_null(fx->out);
451 const char msg[] = "hello";
452 size_t w = stream_write(fx->out, msg, sizeof(msg) - 1, &st);
453 assert_int_equal((int)w, (int)(sizeof(msg) - 1));
454 assert_true(st == STREAM_STATUS_OK);
455 assert_int_equal(fake_file_backing_len(), sizeof(msg) - 1);
456 assert_memory_equal(fx->backing, msg, sizeof(msg) - 1);
457 assert_int_equal(stream_flush(fx->out), STREAM_STATUS_OK);
458 }
459}
460
461//-----------------------------------------------------------------------------
462// CASES
463//-----------------------------------------------------------------------------
464
465static const test_fs_stream_create_stream_case_t CASE_FS_OK = {
466 .name = "fs_create_stream_ok",
468 .fail_call_idx = 0,
469 .open_fail_status = OSAL_FILE_OK,
470
471 .expected_ret = STREAM_STATUS_OK,
472 .out_expect = OUT_EXPECT_NON_NULL
473};
474
475static const test_fs_stream_create_stream_case_t CASE_FS_OUT_NULL = {
476 .name = "fs_create_stream_out_null",
478 .fail_call_idx = 0,
479 .open_fail_status = OSAL_FILE_OK,
480
481 .expected_ret = STREAM_STATUS_INVALID,
482 .out_expect = OUT_CHECK_NONE
483};
484
485static const test_fs_stream_create_stream_case_t CASE_FS_ARGS_NULL = {
486 .name = "fs_create_stream_args_null",
488 .fail_call_idx = 0,
489 .open_fail_status = OSAL_FILE_OK,
490
491 .expected_ret = STREAM_STATUS_INVALID,
492 .out_expect = OUT_EXPECT_UNCHANGED
493};
494
495static const test_fs_stream_create_stream_case_t CASE_FS_CFG_NULL = {
496 .name = "fs_create_stream_cfg_null",
498 .fail_call_idx = 0,
499 .open_fail_status = OSAL_FILE_OK,
500
501 .expected_ret = STREAM_STATUS_INVALID,
502 .out_expect = OUT_EXPECT_UNCHANGED
503};
504
505static const test_fs_stream_create_stream_case_t CASE_FS_ENV_NULL = {
506 .name = "fs_create_stream_env_null",
508 .fail_call_idx = 0,
509 .open_fail_status = OSAL_FILE_OK,
510
511 .expected_ret = STREAM_STATUS_INVALID,
512 .out_expect = OUT_EXPECT_UNCHANGED
513};
514
515static const test_fs_stream_create_stream_case_t CASE_FS_PATH_NULL = {
516 .name = "fs_create_stream_path_null",
518 .fail_call_idx = 0,
519 .open_fail_status = OSAL_FILE_OK,
520
521 .expected_ret = STREAM_STATUS_INVALID,
522 .out_expect = OUT_EXPECT_UNCHANGED
523};
524
525static const test_fs_stream_create_stream_case_t CASE_FS_PATH_EMPTY = {
526 .name = "fs_create_stream_path_empty",
528 .fail_call_idx = 0,
529 .open_fail_status = OSAL_FILE_OK,
530
531 .expected_ret = STREAM_STATUS_INVALID,
532 .out_expect = OUT_EXPECT_UNCHANGED
533};
534
535static const test_fs_stream_create_stream_case_t CASE_FS_FLAGS_ZERO = {
536 .name = "fs_create_stream_flags_zero",
538 .fail_call_idx = 0,
539 .open_fail_status = OSAL_FILE_OK,
540
541 .expected_ret = STREAM_STATUS_INVALID,
542 .out_expect = OUT_EXPECT_UNCHANGED
543};
544
545static const test_fs_stream_create_stream_case_t CASE_FS_OOM_1 = {
546 .name = "fs_create_stream_oom_1",
548 .fail_call_idx = 1,
549 .open_fail_status = OSAL_FILE_OK,
550
551 .expected_ret = STREAM_STATUS_OOM,
552 .out_expect = OUT_EXPECT_UNCHANGED
553};
554
555static const test_fs_stream_create_stream_case_t CASE_FS_OPEN_FAIL_NOT_FOUND = {
556 .name = "fs_create_stream_open_fail_not_found",
558 .fail_call_idx = 0,
559 .open_fail_status = OSAL_FILE_NOENT,
560
561 .expected_ret = STREAM_STATUS_IO_ERROR,
562 .out_expect = OUT_EXPECT_UNCHANGED
563};
564
565//-----------------------------------------------------------------------------
566// CASES REGISTRY
567//-----------------------------------------------------------------------------
568
569#define FS_STREAM_CREATE_STREAM_CASES(X) \
570X(CASE_FS_OK) \
571X(CASE_FS_OUT_NULL) \
572X(CASE_FS_ARGS_NULL) \
573X(CASE_FS_PATH_NULL) \
574X(CASE_FS_PATH_EMPTY) \
575X(CASE_FS_FLAGS_ZERO) \
576X(CASE_FS_CFG_NULL) \
577X(CASE_FS_ENV_NULL) \
578X(CASE_FS_OOM_1) \
579X(CASE_FS_OPEN_FAIL_NOT_FOUND)
580
581#define FS_STREAM_MAKE_CREATE_STREAM_TEST(case_sym) \
582LEXLEO_MAKE_TEST(fs_stream_create_stream, case_sym)
583
584static const struct CMUnitTest fs_stream_stream_create_stream_tests[] = {
585 FS_STREAM_CREATE_STREAM_CASES(FS_STREAM_MAKE_CREATE_STREAM_TEST)
586};
587
588#undef FS_STREAM_CREATE_STREAM_CASES
589#undef FS_STREAM_MAKE_CREATE_STREAM_TEST
590
699
705typedef enum {
706 DESC_CHECK_NONE,
707 DESC_EXPECT_EMPTY,
708 DESC_EXPECT_VALID
709} desc_expect_t;
710
718typedef struct {
719 const char *name;
720
721 // arrange
723 size_t fail_call_idx; // 0 = no OOM, otherwise 1-based (scenario == FS_STREAM_CREATE_DESC_SCENARIO_OOM)
724
725 // assert
726 stream_status_t expected_ret;
727 desc_expect_t desc_expect;
728} test_fs_stream_create_desc_case_t;
729
740typedef struct {
741 // runtime resources
743
744 // injection
745 fs_stream_env_t env;
746 const osal_mem_ops_t *mem;
747
748 stream_key_t key;
749 fs_stream_cfg_t cfg;
750
751 const test_fs_stream_create_desc_case_t *tc;
752} test_fs_stream_create_desc_fixture_t;
753
754//-----------------------------------------------------------------------------
755// FIXTURES
756//-----------------------------------------------------------------------------
757
761static int setup_fs_stream_create_desc(void **state)
762{
763 const test_fs_stream_create_desc_case_t *tc =
764 (const test_fs_stream_create_desc_case_t *)(*state);
765
766 test_fs_stream_create_desc_fixture_t *fx =
767 (test_fs_stream_create_desc_fixture_t *)malloc(sizeof(*fx));
768 if (!fx) return -1;
769
770 osal_memset(fx, 0, sizeof(*fx));
771 fx->tc = tc;
772
773 fake_memory_reset();
774 if (tc->scenario == FS_STREAM_CREATE_DESC_SCENARIO_OOM && tc->fail_call_idx > 0) {
775 fake_memory_fail_only_on_call(tc->fail_call_idx);
776 }
777
778 // DI
779 fx->env.file_env.mem = osal_mem_test_fake_ops();
780 fx->env.file_ops = osal_file_test_fake_ops();
781 fx->env.port_env.mem = osal_mem_test_fake_ops();
782 fx->mem = osal_mem_test_fake_ops();
783
784 fx->key = "fs";
785
786 fx->cfg.reserved = 0; /* Reserved for future use. */
787
788 *state = fx;
789 return 0;
790}
791
795static int teardown_fs_stream_create_desc(void **state)
796{
797 test_fs_stream_create_desc_fixture_t *fx =
798 (test_fs_stream_create_desc_fixture_t *)(*state);
799
800 if (fx->out.ud_dtor) fx->out.ud_dtor(fx->out.ud, fx->mem);
801
802 assert_true(fake_memory_no_leak());
803 assert_true(fake_memory_no_invalid_free());
804 assert_true(fake_memory_no_double_free());
805
806 free(fx);
807 return 0;
808}
809
810//-----------------------------------------------------------------------------
811// TEST
812//-----------------------------------------------------------------------------
813
817static void test_fs_stream_create_desc(void **state)
818{
819 test_fs_stream_create_desc_fixture_t *fx =
820 (test_fs_stream_create_desc_fixture_t *)(*state);
821 const test_fs_stream_create_desc_case_t *tc = fx->tc;
822
823 // ARRANGE
825
826 stream_adapter_desc_t *out_arg = &fx->out;
827 stream_key_t key_arg = fx->key;
828 const fs_stream_cfg_t *cfg_arg = &fx->cfg;
829 const fs_stream_env_t *env_arg = &fx->env;
830 const osal_mem_ops_t *mem_arg = fx->mem;
831
832 // invalid args
833 if (tc->scenario == FS_STREAM_CREATE_DESC_SCENARIO_OUT_NULL) out_arg = NULL;
834 if (tc->scenario == FS_STREAM_CREATE_DESC_SCENARIO_KEY_NULL) key_arg = NULL;
835 if (tc->scenario == FS_STREAM_CREATE_DESC_SCENARIO_KEY_EMPTY) key_arg = "";
836 if (tc->scenario == FS_STREAM_CREATE_DESC_SCENARIO_CFG_NULL) cfg_arg = NULL;
837 if (tc->scenario == FS_STREAM_CREATE_DESC_SCENARIO_ENV_NULL) env_arg = NULL;
838 if (tc->scenario == FS_STREAM_CREATE_DESC_SCENARIO_MEM_NULL) mem_arg = NULL;
839
840 if (tc->desc_expect == DESC_EXPECT_EMPTY && out_arg != NULL) {
841 fx->out.key = (stream_key_t)(uintptr_t)0xDEADC0DEu;
842 fx->out.ctor = (void *)(uintptr_t)0xDEADC0DEu;
843 fx->out.ud = (void *)(uintptr_t)0xDEADC0DEu;
844 fx->out.ud_dtor = (void *)(uintptr_t)0xDEADC0DEu;
845 }
846
847 // ACT
848 ret = fs_stream_create_desc(out_arg, key_arg, cfg_arg, env_arg, mem_arg);
849
850 // ASSERT
851 assert_int_equal(ret, tc->expected_ret);
852
853 if (tc->desc_expect == DESC_EXPECT_EMPTY) {
854 assert_null(fx->out.key);
855 assert_null(fx->out.ctor);
856 assert_null(fx->out.ud);
857 assert_null(fx->out.ud_dtor);
858 }
859 else if (tc->desc_expect == DESC_EXPECT_VALID) {
860 assert_true(fx->out.key != (stream_key_t)(uintptr_t)0xDEADC0DEu);
861 assert_non_null(fx->out.key);
862 assert_true(*fx->out.key != '\0');
863 assert_true(fx->out.ctor != (void *)(uintptr_t)0xDEADC0DEu);
864 assert_non_null(fx->out.ctor);
865 assert_true(fx->out.ud != (void *)(uintptr_t)0xDEADC0DEu);
866 assert_non_null(fx->out.ud);
867 assert_true(fx->out.ud_dtor != (void *)(uintptr_t)0xDEADC0DEu);
868 assert_non_null(fx->out.ud_dtor);
869 }
870 else {
871 assert_true(tc->desc_expect == DESC_CHECK_NONE);
872 }
873}
874
875//-----------------------------------------------------------------------------
876// CASES
877//-----------------------------------------------------------------------------
878
879static const test_fs_stream_create_desc_case_t CASE_FS_STREAM_CREATE_DESC_OK = {
880 .name = "fs_stream_create_desc_ok",
882 .fail_call_idx = 0,
883
884 .expected_ret = STREAM_STATUS_OK,
885 .desc_expect = DESC_EXPECT_VALID
886};
887
888static const test_fs_stream_create_desc_case_t CASE_FS_STREAM_CREATE_DESC_OUT_NULL = {
889 .name = "fs_stream_create_desc_out_null",
891 .fail_call_idx = 0,
892
893 .expected_ret = STREAM_STATUS_INVALID,
894 .desc_expect = DESC_CHECK_NONE
895};
896
897static const test_fs_stream_create_desc_case_t CASE_FS_STREAM_CREATE_DESC_KEY_NULL = {
898 .name = "fs_stream_create_desc_key_null",
900 .fail_call_idx = 0,
901
902 .expected_ret = STREAM_STATUS_INVALID,
903 .desc_expect = DESC_EXPECT_EMPTY
904};
905
906static const test_fs_stream_create_desc_case_t CASE_FS_STREAM_CREATE_DESC_KEY_EMPTY = {
907 .name = "fs_stream_create_desc_key_empty",
909 .fail_call_idx = 0,
910
911 .expected_ret = STREAM_STATUS_INVALID,
912 .desc_expect = DESC_EXPECT_EMPTY
913};
914
915static const test_fs_stream_create_desc_case_t CASE_FS_STREAM_CREATE_DESC_CFG_NULL = {
916 .name = "fs_stream_create_desc_cfg_null",
918 .fail_call_idx = 0,
919
920 .expected_ret = STREAM_STATUS_INVALID,
921 .desc_expect = DESC_EXPECT_EMPTY
922};
923
924static const test_fs_stream_create_desc_case_t CASE_FS_STREAM_CREATE_DESC_ENV_NULL = {
925 .name = "fs_stream_create_desc_env_null",
927 .fail_call_idx = 0,
928
929 .expected_ret = STREAM_STATUS_INVALID,
930 .desc_expect = DESC_EXPECT_EMPTY
931};
932
933static const test_fs_stream_create_desc_case_t CASE_FS_STREAM_CREATE_DESC_MEM_NULL = {
934 .name = "fs_stream_create_desc_mem_null",
936 .fail_call_idx = 0,
937
938 .expected_ret = STREAM_STATUS_INVALID,
939 .desc_expect = DESC_EXPECT_EMPTY
940};
941
942static const test_fs_stream_create_desc_case_t CASE_FS_STREAM_CREATE_DESC_OOM_1 = {
943 .name = "fs_stream_create_desc_oom_1",
945 .fail_call_idx = 1,
946
947 .expected_ret = STREAM_STATUS_OOM,
948 .desc_expect = DESC_EXPECT_EMPTY
949};
950
951//-----------------------------------------------------------------------------
952// CASES REGISTRY
953//-----------------------------------------------------------------------------
954
955#define FS_STREAM_CREATE_DESC_CASES(X) \
956X(CASE_FS_STREAM_CREATE_DESC_OK) \
957X(CASE_FS_STREAM_CREATE_DESC_OUT_NULL) \
958X(CASE_FS_STREAM_CREATE_DESC_KEY_NULL) \
959X(CASE_FS_STREAM_CREATE_DESC_KEY_EMPTY) \
960X(CASE_FS_STREAM_CREATE_DESC_CFG_NULL) \
961X(CASE_FS_STREAM_CREATE_DESC_ENV_NULL) \
962X(CASE_FS_STREAM_CREATE_DESC_MEM_NULL) \
963X(CASE_FS_STREAM_CREATE_DESC_OOM_1)
964
965#define FS_STREAM_MAKE_CREATE_DESC_TEST(case_sym) \
966LEXLEO_MAKE_TEST(fs_stream_create_desc, case_sym)
967
968static const struct CMUnitTest create_desc_fs_stream_tests[] = {
969 FS_STREAM_CREATE_DESC_CASES(FS_STREAM_MAKE_CREATE_DESC_TEST)
970};
971
972#undef FS_STREAM_CREATE_DESC_CASES
973#undef FS_STREAM_MAKE_CREATE_DESC_TEST
974
1093
1106typedef struct {
1107 const char *name;
1108
1109 // arrange
1111 size_t fail_call_idx; // 0 = no OOM, otherwise 1-based
1112 osal_file_status_t open_fail_status; // e.g. OSAL_FILE_NOENT
1113
1114 // assert
1115 stream_status_t expected_ret;
1116 out_expect_t out_expect;
1117} test_fs_stream_desc_ctor_case_t;
1118
1131typedef struct {
1132 // descriptor under test
1134
1135 // runtime resource produced by desc.ctor()
1136 stream_t *out;
1137
1138 // dependencies / descriptor inputs
1139 fs_stream_env_t env;
1140 const osal_mem_ops_t *mem;
1141 fs_stream_cfg_t cfg;
1142
1143 // ctor call inputs
1144 fs_stream_args_t args;
1145
1146 // fake file backing
1147 uint8_t backing[64];
1148
1149 // reference to test case
1150 const test_fs_stream_desc_ctor_case_t *tc;
1151} test_fs_stream_desc_ctor_fixture_t;
1152
1153//-----------------------------------------------------------------------------
1154// FIXTURES
1155//-----------------------------------------------------------------------------
1156
1161static int setup_fs_stream_desc_ctor(void **state)
1162{
1163 const test_fs_stream_desc_ctor_case_t *tc =
1164 (const test_fs_stream_desc_ctor_case_t *)(*state);
1165
1166 test_fs_stream_desc_ctor_fixture_t *fx =
1167 (test_fs_stream_desc_ctor_fixture_t *)malloc(sizeof(*fx));
1168 if (!fx) return -1;
1169
1170 osal_memset(fx, 0, sizeof(*fx));
1171 fx->tc = tc;
1172
1173 fake_file_reset();
1174 fake_memory_reset();
1175
1176 osal_memset(fx->backing, 0, sizeof(fx->backing));
1177 fake_file_set_backing(fx->backing, sizeof(fx->backing), 0);
1178 fake_file_set_pos(0);
1179 fake_file_fail_disable();
1180
1181 if (tc->scenario == FS_STREAM_DESC_CTOR_SCENARIO_OPEN_FAIL) {
1182 fake_file_fail_enable(FAKE_FILE_OP_OPEN, 1, tc->open_fail_status);
1183 }
1184
1185 // DI
1186 fx->env.file_env.mem = osal_mem_test_fake_ops();
1187 fx->env.file_ops = osal_file_test_fake_ops();
1188 fx->env.port_env.mem = osal_mem_test_fake_ops();
1189 fx->mem = osal_mem_test_fake_ops();
1190
1191 fx->cfg.reserved = 0; /* Reserved for future use. */
1192
1193 stream_status_t st = fs_stream_create_desc(&fx->desc, "fs", &fx->cfg, &fx->env, fx->mem);
1194 assert_true(st == STREAM_STATUS_OK);
1195
1196 if (tc->scenario == FS_STREAM_DESC_CTOR_SCENARIO_OOM && tc->fail_call_idx > 0) {
1197 fake_memory_fail_only_on_call(tc->fail_call_idx);
1198 }
1199
1200 fx->args.path = "crazy_injection.txt";
1202 fx->args.autoclose = true;
1203
1204 *state = fx;
1205 return 0;
1206}
1207
1212static int teardown_fs_stream_desc_ctor(void **state)
1213{
1214 test_fs_stream_desc_ctor_fixture_t *fx =
1215 (test_fs_stream_desc_ctor_fixture_t *)(*state);
1216
1217 if (fx->out) {
1218 stream_destroy(&fx->out);
1219 fx->out = NULL;
1220 }
1221
1222 if (fx->desc.ud_dtor) fx->desc.ud_dtor(fx->desc.ud, fx->mem);
1223
1224 assert_true(fake_memory_no_leak());
1225 assert_true(fake_memory_no_invalid_free());
1226 assert_true(fake_memory_no_double_free());
1227
1228 free(fx);
1229 return 0;
1230}
1231
1232//-----------------------------------------------------------------------------
1233// TEST
1234//-----------------------------------------------------------------------------
1235
1240static void test_fs_stream_desc_ctor(void **state)
1241{
1242 test_fs_stream_desc_ctor_fixture_t *fx =
1243 (test_fs_stream_desc_ctor_fixture_t *)(*state);
1244 const test_fs_stream_desc_ctor_case_t *tc = fx->tc;
1245
1246 // ARRANGE
1249
1250 stream_t **out_arg = &fx->out;
1251 const fs_stream_args_t *args_arg = &fx->args;
1252
1253 // invalid args
1254 if (tc->scenario == FS_STREAM_DESC_CTOR_SCENARIO_OUT_NULL) out_arg = NULL;
1255 if (tc->scenario == FS_STREAM_DESC_CTOR_SCENARIO_ARGS_NULL) args_arg = NULL;
1256 if (tc->scenario == FS_STREAM_DESC_CTOR_SCENARIO_PATH_NULL) fx->args.path = NULL;
1257 if (tc->scenario == FS_STREAM_DESC_CTOR_SCENARIO_PATH_EMPTY) fx->args.path = "";
1258 if (tc->scenario == FS_STREAM_DESC_CTOR_SCENARIO_FLAGS_ZERO) fx->args.flags = (uint32_t)0;
1259
1260 // ensure OUT_EXPECT_UNCHANGED is meaningful
1261 if (tc->out_expect == OUT_EXPECT_UNCHANGED && out_arg != NULL) {
1262 fx->out = (stream_t *)(uintptr_t)0xDEADC0DEu; // sentinel
1263 }
1264
1265 stream_t *out_arg_snapshot = fx->out;
1266
1267 // ACT
1268 ret = fx->desc.ctor(fx->desc.ud, args_arg, out_arg);
1269
1270 // ASSERT
1271 assert_int_equal(ret, tc->expected_ret);
1272
1273 switch (tc->out_expect) {
1274 case OUT_CHECK_NONE: break;
1275 case OUT_EXPECT_NULL: assert_null(fx->out); break;
1276 case OUT_EXPECT_NON_NULL: assert_non_null(fx->out); break;
1277 case OUT_EXPECT_UNCHANGED:
1278 assert_ptr_equal(out_arg_snapshot, fx->out);
1279 fx->out = NULL; // prevent teardown from destroying sentinel
1280 break;
1281 default: assert_true(false);
1282 }
1283
1284 if (tc->scenario == FS_STREAM_DESC_CTOR_SCENARIO_OK) {
1285 assert_non_null(fx->out);
1286 const char msg[] = "hello";
1287 size_t w = stream_write(fx->out, msg, sizeof(msg) - 1, &st);
1288 assert_int_equal((int)w, (int)(sizeof(msg) - 1));
1289 assert_true(st == STREAM_STATUS_OK);
1290 assert_int_equal(fake_file_backing_len(), sizeof(msg) - 1);
1291 assert_memory_equal(fx->backing, msg, sizeof(msg) - 1);
1292 assert_int_equal(stream_flush(fx->out), STREAM_STATUS_OK);
1293 }
1294}
1295
1296//-----------------------------------------------------------------------------
1297// CASES
1298//-----------------------------------------------------------------------------
1299
1300static const test_fs_stream_desc_ctor_case_t CASE_FS_STREAM_DESC_CTOR_OK = {
1301 .name = "fs_stream_desc_ctor_create_stream_ok",
1303 .fail_call_idx = 0,
1304 .open_fail_status = OSAL_FILE_OK,
1305
1306 .expected_ret = STREAM_STATUS_OK,
1307 .out_expect = OUT_EXPECT_NON_NULL
1308};
1309
1310static const test_fs_stream_desc_ctor_case_t CASE_FS_STREAM_DESC_CTOR_ARGS_NULL = {
1311 .name = "fs_stream_desc_ctor_create_stream_args_null",
1313 .fail_call_idx = 0,
1314 .open_fail_status = OSAL_FILE_OK,
1315
1316 .expected_ret = STREAM_STATUS_INVALID,
1317 .out_expect = OUT_EXPECT_UNCHANGED
1318};
1319
1320static const test_fs_stream_desc_ctor_case_t CASE_FS_STREAM_DESC_CTOR_OUT_NULL = {
1321 .name = "fs_stream_desc_ctor_create_stream_out_null",
1323 .fail_call_idx = 0,
1324 .open_fail_status = OSAL_FILE_OK,
1325
1326 .expected_ret = STREAM_STATUS_INVALID,
1327 .out_expect = OUT_CHECK_NONE
1328};
1329
1330static const test_fs_stream_desc_ctor_case_t CASE_FS_STREAM_DESC_CTOR_PATH_NULL = {
1331 .name = "fs_stream_desc_ctor_create_stream_path_null",
1333 .fail_call_idx = 0,
1334 .open_fail_status = OSAL_FILE_OK,
1335
1336 .expected_ret = STREAM_STATUS_INVALID,
1337 .out_expect = OUT_EXPECT_UNCHANGED
1338};
1339
1340static const test_fs_stream_desc_ctor_case_t CASE_FS_STREAM_DESC_CTOR_PATH_EMPTY = {
1341 .name = "fs_stream_desc_ctor_create_stream_path_empty",
1343 .fail_call_idx = 0,
1344 .open_fail_status = OSAL_FILE_OK,
1345
1346 .expected_ret = STREAM_STATUS_INVALID,
1347 .out_expect = OUT_EXPECT_UNCHANGED
1348};
1349
1350static const test_fs_stream_desc_ctor_case_t CASE_FS_STREAM_DESC_CTOR_FLAGS_ZERO = {
1351 .name = "fs_stream_desc_ctor_create_stream_flags_zero",
1353 .fail_call_idx = 0,
1354 .open_fail_status = OSAL_FILE_OK,
1355
1356 .expected_ret = STREAM_STATUS_INVALID,
1357 .out_expect = OUT_EXPECT_UNCHANGED
1358};
1359
1360static const test_fs_stream_desc_ctor_case_t CASE_FS_STREAM_DESC_CTOR_OOM_1 = {
1361 .name = "fs_stream_desc_ctor_create_stream_oom_1",
1363 .fail_call_idx = 1,
1364 .open_fail_status = OSAL_FILE_OK,
1365
1366 .expected_ret = STREAM_STATUS_OOM,
1367 .out_expect = OUT_EXPECT_UNCHANGED
1368};
1369
1370static const test_fs_stream_desc_ctor_case_t CASE_FS_STREAM_DESC_CTOR_OPEN_FAIL = {
1371 .name = "fs_stream_desc_ctor_create_stream_open_fail",
1373 .fail_call_idx = 0,
1374 .open_fail_status = OSAL_FILE_NOENT,
1375
1376 .expected_ret = STREAM_STATUS_IO_ERROR,
1377 .out_expect = OUT_EXPECT_UNCHANGED
1378};
1379
1380//-----------------------------------------------------------------------------
1381// CASES REGISTRY
1382//-----------------------------------------------------------------------------
1383
1384#define FS_STREAM_DESC_CTOR_CASES(X) \
1385X(CASE_FS_STREAM_DESC_CTOR_OK) \
1386X(CASE_FS_STREAM_DESC_CTOR_ARGS_NULL) \
1387X(CASE_FS_STREAM_DESC_CTOR_OUT_NULL) \
1388X(CASE_FS_STREAM_DESC_CTOR_PATH_NULL) \
1389X(CASE_FS_STREAM_DESC_CTOR_PATH_EMPTY) \
1390X(CASE_FS_STREAM_DESC_CTOR_FLAGS_ZERO) \
1391X(CASE_FS_STREAM_DESC_CTOR_OOM_1) \
1392X(CASE_FS_STREAM_DESC_CTOR_OPEN_FAIL)
1393
1394#define FS_STREAM_MAKE_DESC_CTOR_TEST(case_sym) \
1395LEXLEO_MAKE_TEST(fs_stream_desc_ctor, case_sym)
1396
1397static const struct CMUnitTest desc_ctor_fs_stream_tests[] = {
1398 FS_STREAM_DESC_CTOR_CASES(FS_STREAM_MAKE_DESC_CTOR_TEST)
1399};
1400
1401#undef FS_STREAM_DESC_CTOR_CASES
1402#undef FS_STREAM_MAKE_DESC_CTOR_TEST
1403
1404//-----------------------------------------------------------------------------
1405// MAIN
1406//-----------------------------------------------------------------------------
1407
1408int main(void) {
1409 static const struct CMUnitTest fs_stream_tests[] = {
1410 cmocka_unit_test(test_fs_stream_default_cfg),
1411 cmocka_unit_test(test_fs_stream_default_env),
1412 };
1413
1414 int failed = 0;
1415 failed += cmocka_run_group_tests(fs_stream_tests, NULL, NULL);
1416 failed += cmocka_run_group_tests(fs_stream_stream_create_stream_tests, NULL, NULL);
1417 failed += cmocka_run_group_tests(create_desc_fs_stream_tests, NULL, NULL);
1418 failed += cmocka_run_group_tests(desc_ctor_fs_stream_tests, NULL, NULL);
1419 return failed;
1420}
1421
Composition Root API for wiring the fs_stream adapter into the stream factory.
stream_status_t fs_stream_create_stream(stream_t **out, const fs_stream_args_t *args, const fs_stream_cfg_t *cfg, const fs_stream_env_t *env)
Create a file-backed stream instance.
Definition fs_stream.c:208
fs_stream_cfg_t fs_stream_default_cfg(void)
Return a default configuration for the fs_stream adapter.
Definition fs_stream.c:294
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
fs_stream_env_t fs_stream_default_env(const osal_file_env_t *file_env, const osal_file_ops_t *file_ops, const stream_env_t *port_env)
Build a default environment for the fs_stream adapter.
Definition fs_stream.c:298
@ OSAL_FILE_WRITE
@ OSAL_FILE_TRUNC
@ OSAL_FILE_CREATE
@ OSAL_FILE_READ
osal_file_status_t
@ OSAL_FILE_OK
@ OSAL_FILE_NOENT
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_test_fake_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
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_OOM
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.
int reserved
Reserved configuration field.
Injected dependencies for the fs_stream adapter.
osal_file_env_t file_env
Borrowed OSAL file environment.
stream_env_t port_env
Borrowed stream port environment.
const osal_file_ops_t * file_ops
Borrowed OSAL file operations table.
Public descriptor used to register a concrete stream adapter.
Runtime environment for the stream port.
Definition stream_env.h:35
Private handle structure for a stream_t.
static void test_fs_stream_default_cfg(void **state)
Test fs_stream_default_cfg().
fs_create_stream_scenario_t
Scenarios for fs_stream_create_stream().
@ FS_CREATE_STREAM_SCENARIO_OUT_NULL
@ FS_CREATE_STREAM_SCENARIO_ENV_NULL
@ FS_CREATE_STREAM_SCENARIO_OPEN_FAIL
@ FS_CREATE_STREAM_SCENARIO_ARGS_NULL
@ FS_CREATE_STREAM_SCENARIO_OK
@ FS_CREATE_STREAM_SCENARIO_FLAGS_ZERO
@ FS_CREATE_STREAM_SCENARIO_OOM
@ FS_CREATE_STREAM_SCENARIO_PATH_NULL
@ FS_CREATE_STREAM_SCENARIO_PATH_EMPTY
@ FS_CREATE_STREAM_SCENARIO_CFG_NULL
fs_stream_create_desc_scenario_t
Scenarios for fs_stream_create_desc().
@ FS_STREAM_CREATE_DESC_SCENARIO_OOM
@ FS_STREAM_CREATE_DESC_SCENARIO_ENV_NULL
@ FS_STREAM_CREATE_DESC_SCENARIO_OK
@ FS_STREAM_CREATE_DESC_SCENARIO_OUT_NULL
@ FS_STREAM_CREATE_DESC_SCENARIO_KEY_NULL
@ FS_STREAM_CREATE_DESC_SCENARIO_KEY_EMPTY
@ FS_STREAM_CREATE_DESC_SCENARIO_MEM_NULL
@ FS_STREAM_CREATE_DESC_SCENARIO_CFG_NULL
static void test_fs_stream_default_env(void **state)
Test fs_stream_default_env().
fs_stream_desc_ctor_scenario_t
Scenarios for fs_stream_create_desc() descriptor constructor usage.
@ FS_STREAM_DESC_CTOR_SCENARIO_ARGS_NULL
@ FS_STREAM_DESC_CTOR_SCENARIO_OPEN_FAIL
@ FS_STREAM_DESC_CTOR_SCENARIO_FLAGS_ZERO
@ FS_STREAM_DESC_CTOR_SCENARIO_PATH_EMPTY
@ FS_STREAM_DESC_CTOR_SCENARIO_OK
@ FS_STREAM_DESC_CTOR_SCENARIO_OOM
@ FS_STREAM_DESC_CTOR_SCENARIO_OUT_NULL
@ FS_STREAM_DESC_CTOR_SCENARIO_PATH_NULL