1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include <fwk_module.h>
9 #include <fwk_module_idx.h>
10 #include <fwk_noreturn.h>
11 #include <fwk_status.h>
12 #include <fwk_test.h>
13 
14 #include <setjmp.h>
15 #include <stdbool.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 /*
19  * This variable is used by arm architecture to ensure spurious nested calls
20  * won't enable interrupts. This is been accessed from inline function defined
21  * in arch_helpers.h
22  */
23 unsigned int critical_section_nest_level;
24 
25 /* Test information provided by the test suite */
26 extern struct fwk_test_suite_desc test_suite;
27 
28 static jmp_buf test_buf_context;
29 
30 struct fwk_module *module_table[FWK_MODULE_IDX_COUNT];
31 struct fwk_module_config *module_config_table[FWK_MODULE_IDX_COUNT];
32 
fake_init(fwk_id_t module_id,unsigned int element_count,const void * data)33 static int fake_init(
34     fwk_id_t module_id,
35     unsigned int element_count,
36     const void *data)
37 {
38     return FWK_SUCCESS;
39 }
40 
__assert_fail(const char * assertion,const char * file,unsigned int line,const char * function)41 noreturn void __assert_fail(const char *assertion,
42     const char *file, unsigned int line, const char *function)
43 {
44     printf("Assertion failed: %s\n", assertion);
45     printf("    Function: %s\n", function);
46     printf("    File: %-66s\n", file);
47     printf("    Line: %u\n", line);
48     longjmp(test_buf_context, !FWK_SUCCESS);
49 }
50 
print_separator(void)51 static void print_separator(void)
52 {
53     printf("----------------------------------------");
54     printf("----------------------------------------\n");
55 }
print_prologue(void)56 static void print_prologue(void)
57 {
58     printf("\nStarting tests for %s\n", test_suite.name);
59     print_separator();
60 }
61 
print_epilogue(unsigned int successful_tests)62 static void print_epilogue(unsigned int successful_tests)
63 {
64     int pass_rate = (successful_tests * 100) / test_suite.test_case_count;
65 
66     print_separator();
67     printf("%u / %u passed (%d%% pass rate)\n\n", successful_tests,
68         test_suite.test_case_count, pass_rate);
69 }
70 
print_result(const char * name,bool success)71 static void print_result(const char *name, bool success)
72 {
73     /* The name is truncated to 72 characters */
74     printf("%-72s %s\n", name, (success ? "SUCCESS" : "FAILURE"));
75 }
76 
run_tests(void)77 static unsigned int run_tests(void)
78 {
79     unsigned int i;
80     bool success;
81     unsigned int successful_tests = 0;
82     const struct fwk_test_case_desc *test_case;
83 
84     if (test_suite.test_suite_setup != NULL) {
85         if (test_suite.test_suite_setup() != FWK_SUCCESS)
86             return 0;
87     }
88 
89     for (i = 0; i < test_suite.test_case_count; i++) {
90         test_case = &test_suite.test_case_table[i];
91 
92         if ((test_case->test_execute == NULL) || (test_case->name == NULL)) {
93             print_result("Test case undefined!", false);
94 
95             continue;
96         }
97 
98         if (test_suite.test_case_setup != NULL)
99             test_suite.test_case_setup();
100 
101         /*
102          * The setjmp function stores the execution context of the processor at
103          * that point in time. When called, 0 is returned by default.
104          * If an assertion fails in the test case following, execution returns
105          * to an undefined point within setjmp() which then returns a non-zero
106          * value. See __assert_fail() for exactly how assertion failure is
107          * handled.
108          */
109         if (setjmp(test_buf_context) == FWK_SUCCESS) {
110             test_case->test_execute();
111 
112             success = true;
113             successful_tests++;
114         } else
115             success = false;
116 
117         if (test_suite.test_case_teardown != NULL)
118             test_suite.test_case_teardown();
119 
120         print_result(test_case->name, success);
121     }
122 
123     if (test_suite.test_suite_teardown != NULL)
124         test_suite.test_suite_teardown();
125 
126     return successful_tests;
127 }
128 
main(void)129 int main(void)
130 {
131     unsigned int successful_tests;
132 
133     for (enum fwk_module_idx i = 0; i < FWK_MODULE_IDX_COUNT; i++) {
134 
135         struct fwk_module *module = malloc(sizeof(*module));
136         struct fwk_module_config *config = malloc(sizeof(*config));
137 
138         *module = (struct fwk_module){
139             .type = FWK_MODULE_TYPE_SERVICE,
140             .init = fake_init,
141         };
142 
143         *config = (struct fwk_module_config){ 0 };
144 
145         module_table[i] = module;
146         module_config_table[i] = config;
147     }
148 
149     fwk_module_init();
150 
151     if (test_suite.test_case_count != 0) {
152         print_prologue();
153         successful_tests = run_tests();
154         print_epilogue(successful_tests);
155 
156         if (successful_tests != test_suite.test_case_count)
157             return EXIT_FAILURE;
158     }
159 
160     return EXIT_SUCCESS;
161 }
162