blob: 4b0a8576dbf8e0dba3d969cc9a6a06064ed39f82 [file] [log] [blame]
Sandrine Bailleux3cd87d72018-10-09 11:12:55 +02001/*
2 * Copyright (c) 2018, Arm Limited. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <assert.h>
8#include <debug.h>
9#include <platform_def.h> /* For TESTCASE_OUTPUT_MAX_SIZE */
10#include <semihosting.h>
11#include <stdio.h>
12#include <string.h>
13#include <tftf.h>
14
15struct tftf_report_ops {
16 long (*open)(const char *fname);
17 void (*write)(long handle, const char *str);
18 void (*close)(long handle);
19};
20
21#define TEST_REPORT_JUNIT_FILENAME "tftf_report_junit.xml"
22#define TEST_REPORT_RAW_FILENAME "tftf_report_raw.txt"
23
24#if defined(TEST_REPORT_UART_RAW) || defined(TEST_REPORT_UART_JUNIT)
25static long tftf_report_uart_open(const char *fname)
26{
27 printf("********** %s **********\n", fname);
28 return 0;
29}
30
31static void tftf_report_uart_write(long handle, const char *str)
32{
33 (void)handle;
34 assert(str);
35 /* Not using printf to avoid doing two copies. */
36 while (*str) {
37 putchar(*str++);
38 }
39}
40
41static void tftf_report_uart_close(long handle)
42{
43 (void)handle;
44 printf("************************\n");
45}
46
47const struct tftf_report_ops tftf_report_uart_ops = {
48 .open = tftf_report_uart_open,
49 .write = tftf_report_uart_write,
50 .close = tftf_report_uart_close,
51};
52#endif /* defined(TEST_REPORT_UART_RAW) || defined(TEST_REPORT_UART_JUNIT) */
53
54#if defined(TEST_REPORT_UART_RAW) || defined(TEST_REPORT_SEMIHOSTING_RAW)
55static unsigned int total_tests;
56static unsigned int tests_stats[TEST_RESULT_MAX];
57
58static void tftf_update_tests_statistics(test_result_t result)
59{
60 assert(TEST_RESULT_IS_VALID(result));
61 total_tests++;
62 tests_stats[result]++;
63}
64
65static const char *test_result_strings[TEST_RESULT_MAX] = {
66 "Skipped", "Passed", "Failed", "Crashed",
67};
68
69const char *test_result_to_string(test_result_t result)
70{
71 assert(TEST_RESULT_IS_VALID(result));
72 return test_result_strings[result];
73}
74
75static void tftf_report_generate_raw(const struct tftf_report_ops *rops,
76 const char *fname)
77{
78#define WRITE(str) rops->write(file_handle, str)
79#define BUFFER_SIZE 200
80 unsigned i, j;
81 long file_handle;
82 char buffer[BUFFER_SIZE];
83 const test_case_t *testcases;
84 TESTCASE_RESULT testcase_result;
85 char test_output[TESTCASE_OUTPUT_MAX_SIZE];
86 STATUS status;
87
88 file_handle = rops->open(fname);
89 if (file_handle == -1)
90 return;
91
92 /* Extract the result of all the testcases */
93 WRITE("========== TEST REPORT ==========\n");
94 for (i = 0; testsuites[i].name != NULL; i++) {
95 snprintf(buffer, BUFFER_SIZE, "# Test suite '%s':\n", testsuites[i].name);
96 WRITE(buffer);
97 testcases = testsuites[i].testcases;
98
99 for (j = 0; testcases[j].name != NULL; j++) {
100 status = tftf_testcase_get_result(&testcases[j], &testcase_result, test_output);
101 if (status != STATUS_SUCCESS) {
102 WRITE("Failed to get test result.\n");
103 continue;
104 }
105
106 tftf_update_tests_statistics(testcase_result.result);
107 /* TODO: print test duration */
108 snprintf(buffer, BUFFER_SIZE, "\t - %s: %s\n", testcases[j].name,
109 test_result_to_string(testcase_result.result));
110 WRITE(buffer);
111
112 if (strlen(test_output) != 0) {
113 WRITE("--- output ---\n");
114 snprintf(buffer, BUFFER_SIZE, "%s", test_output);
115 WRITE(buffer);
116 WRITE("--------------\n");
117 }
118 }
119 }
120 WRITE("=================================\n");
121
122 for (i = TEST_RESULT_MIN; i < TEST_RESULT_MAX; i++) {
123 snprintf(buffer, BUFFER_SIZE, "Tests %-8s: %d\n",
124 test_result_to_string(i), tests_stats[i]);
125 WRITE(buffer);
126 }
127 snprintf(buffer, BUFFER_SIZE, "%-14s: %d\n", "Total tests", total_tests);
128 WRITE(buffer);
129 WRITE("=================================\n");
130
131 rops->close(file_handle);
132#undef BUFFER_SIZE
133#undef WRITE
134}
135#endif /* defined(TEST_REPORT_UART_RAW) || defined(TEST_REPORT_SEMIHOSTING_RAW) */
136
137#if defined(TEST_REPORT_SEMIHOSTING_RAW) || defined(TEST_REPORT_SEMIHOSTING_JUNIT)
138static long tftf_report_semihosting_open(const char *fname)
139{
140 /* Create the report on the semihosting */
141 long handle = semihosting_file_open(fname, FOPEN_MODE_WPLUS);
142 if (handle == -1) {
143 ERROR("Failed to create test report file \"%s\" on semihosting"
144 " [status = %ld].\n", fname, handle);
145 }
146 NOTICE("Opened file \"%s\" on semihosting with handle %ld.\n", fname, handle);
147 return handle;
148}
149
150static void tftf_report_semihosting_write(long handle, const char *str)
151{
152 size_t length = strlen(str);
153 semihosting_file_write(handle, &length, (const uintptr_t) str);
154}
155
156static void tftf_report_semihosting_close(long handle)
157{
158 semihosting_file_close(handle);
159 NOTICE("Closing file with handle %ld on semihosting.\n", handle);
160}
161
162const struct tftf_report_ops tftf_report_semihosting_ops = {
163 .open = tftf_report_semihosting_open,
164 .write = tftf_report_semihosting_write,
165 .close = tftf_report_semihosting_close,
166};
167#endif /* defined(TEST_REPORT_SEMIHOSTING_RAW) || defined(TEST_REPORT_SEMIHOSTING_JUNIT) */
168
169
170#if defined(TEST_REPORT_UART_JUNIT) || defined(TEST_REPORT_SEMIHOSTING_JUNIT)
171static void tftf_report_generate_junit(const struct tftf_report_ops *rops,
172 const char *fname)
173{
174#define WRITE(str) rops->write(file_handle, str)
175#define BUFFER_SIZE 200
176
177 long file_handle;
178 unsigned i, j;
179 const test_case_t *testcases;
180 TESTCASE_RESULT result;
181 char buffer[BUFFER_SIZE];
182 char test_output[TESTCASE_OUTPUT_MAX_SIZE];
183
184 file_handle = rops->open(fname);
185
186 if (file_handle == -1) {
187 return;
188 }
189 WRITE("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
190 WRITE("<testsuites>\n");
191
192 /* Extract the result of all the testcases */
193 for (i = 0; testsuites[i].name != NULL; i++) {
194 snprintf(buffer, BUFFER_SIZE, "<testsuite name=\"%s\">\n",
195 testsuites[i].name);
196 WRITE(buffer);
197 testcases = testsuites[i].testcases;
198 for (j = 0; testcases[j].name != NULL; j++) {
199 tftf_testcase_get_result(&testcases[j], &result, test_output);
200
201 snprintf(buffer, BUFFER_SIZE, " <testcase name=\"%s\" time=\"%llu\"",
202 testcases[j].name, result.duration);
203 WRITE(buffer);
204 if (result.result == TEST_RESULT_SUCCESS) {
205 WRITE("/>\n");
206 } else {
207 WRITE(">\n");
208 if (result.result == TEST_RESULT_SKIPPED) {
209 WRITE(" <skipped/>\n");
210 } else {
211 WRITE(" <error type=\"failed\">\n");
212 WRITE(test_output);
213 WRITE(" </error>\n");
214 }
215 WRITE(" </testcase>\n");
216 }
217 }
218 WRITE("</testsuite>\n");
219 }
220
221 WRITE("</testsuites>\n");
222 rops->close(file_handle);
223#undef BUFFER_SIZE
224#undef WRITE
225}
226#endif /* defined(TEST_REPORT_UART_JUNIT) || defined(TEST_REPORT_SEMIHOSTING_JUNIT) */
227
228void tftf_report_generate(void)
229{
230 int nb_reports = 0;
231#ifdef TEST_REPORT_UART_RAW
232 tftf_report_generate_raw(&tftf_report_uart_ops, "raw");
233 nb_reports++;
234#endif
235#ifdef TEST_REPORT_UART_JUNIT
236 tftf_report_generate_junit(&tftf_report_uart_ops, "junit");
237 nb_reports++;
238#endif
239#ifdef TEST_REPORT_SEMIHOSTING_RAW
240 tftf_report_generate_raw(&tftf_report_semihosting_ops,
241 TEST_REPORT_RAW_FILENAME);
242 nb_reports++;
243#endif
244#ifdef TEST_REPORT_SEMIHOSTING_JUNIT
245 tftf_report_generate_junit(&tftf_report_semihosting_ops,
246 TEST_REPORT_JUNIT_FILENAME);
247 nb_reports++;
248#endif
249 assert(nb_reports > 0);
250}