xref: /xnu-8792.61.2/osfmk/tests/ktest_emit.c (revision 42e220869062b56f8d7d0726fd4c88954f87902c)
1 /*
2  * Copyright (c) 2015 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 
29 #include <tests/ktest_internal.h>
30 #include <kern/misc_protos.h>
31 #include <kern/debug.h>
32 
33 #define EMIT(buf, size) do {\
34 	console_write(buf, size); \
35 	} while(0)
36 
37 /* TODO: intelligently truncate messages if possible */
38 #define BOUNDS_CHECK_AND_UPDATE(ret, size) do {\
39 	if(ret < 0 || ret >= size) {\
40 	        panic("Internal ktest error in %s", __func__);\
41 	}\
42 	size -= ret;\
43 	msg += ret;\
44 } while(0)
45 
46 int vsnprintf(char *, size_t, const char *, va_list);
47 
48 void
ktest_emit_start(void)49 ktest_emit_start(void)
50 {
51 	char str[] = "\n[KTEST]\tSTART\t" KTEST_VERSION_STR "\n";
52 	EMIT((char *)&str[0], sizeof(str) - 1);
53 }
54 
55 void
ktest_emit_finish(void)56 ktest_emit_finish(void)
57 {
58 	char str[] = "\n[KTEST]\tFINISH\n";
59 	EMIT((char *)&str[0], sizeof(str) - 1);
60 }
61 
62 void
ktest_emit_testbegin(const char * test_name)63 ktest_emit_testbegin(const char * test_name)
64 {
65 	char * msg = ktest_output_buf;
66 	int size = sizeof(ktest_output_buf);
67 	int ret;
68 
69 	/* left trim the file path for readability */
70 	const char *fname = strnstr((char *)(uintptr_t)ktest_current_file, "xnu", 100);
71 
72 	ret = snprintf(msg,
73 	    size,
74 	    "\n[KTEST]\t"                 /* header */
75 	    "TESTBEGIN\t"               /* type */
76 	    "%lld\t"                    /* time */
77 	    "%d\t"                      /* index */
78 	    "%s\t"                      /* file */
79 	    "%d\t"                      /* line */
80 	    "%s\n",                     /* name */
81 	    ktest_current_time,
82 	    ktest_test_index,
83 	    fname,
84 	    ktest_current_line,
85 	    test_name);
86 	BOUNDS_CHECK_AND_UPDATE(ret, size);
87 
88 	EMIT(ktest_output_buf, (int)(msg - ktest_output_buf));
89 }
90 
91 void
ktest_emit_testskip(const char * skip_msg,va_list args)92 ktest_emit_testskip(const char * skip_msg, va_list args)
93 {
94 	char * msg = ktest_output_buf;
95 	int size = sizeof(ktest_output_buf);
96 	int ret;
97 
98 	const char *fname = strnstr((char *)(uintptr_t)ktest_current_file, "xnu", 100);
99 
100 	ret = snprintf(msg,
101 	    size,
102 	    "\n[KTEST]\t"                /* header */
103 	    "TESTSKIP\t"               /* type */
104 	    "%lld\t"                   /* time */
105 	    "%s\t"                     /* file */
106 	    "%d\t",                    /* line */
107 	    ktest_current_time,
108 	    fname,
109 	    ktest_current_line);
110 	BOUNDS_CHECK_AND_UPDATE(ret, size);
111 
112 	ret = vsnprintf(msg, size, skip_msg, args);
113 	BOUNDS_CHECK_AND_UPDATE(ret, size);
114 
115 	ret = snprintf(msg, size, "\n");
116 	BOUNDS_CHECK_AND_UPDATE(ret, size);
117 
118 	EMIT(ktest_output_buf, (int)(msg - ktest_output_buf));
119 }
120 
121 void
ktest_emit_testend()122 ktest_emit_testend()
123 {
124 	char * msg = ktest_output_buf;
125 	int size = sizeof(ktest_output_buf);
126 	int ret;
127 
128 	const char *fname = strnstr((char *)(uintptr_t)ktest_current_file, "xnu", 100);
129 
130 	ret = snprintf(msg,
131 	    size,
132 	    "\n[KTEST]\t"                 /* header */
133 	    "TESTEND\t"                 /* type */
134 	    "%lld\t"                    /* time */
135 	    "%d\t"                      /* index */
136 	    "%s\t"                      /* file */
137 	    "%d\t"                      /* line */
138 	    "%s\n",                     /* name */
139 	    ktest_current_time,
140 	    ktest_test_index,
141 	    fname,
142 	    ktest_current_line,
143 	    ktest_test_name);
144 	BOUNDS_CHECK_AND_UPDATE(ret, size);
145 
146 	EMIT(ktest_output_buf, (int)(msg - ktest_output_buf));
147 }
148 
149 void
ktest_emit_log(const char * log_msg,va_list args)150 ktest_emit_log(const char * log_msg, va_list args)
151 {
152 	char * msg = ktest_output_buf;
153 	int size = sizeof(ktest_output_buf);
154 	int ret;
155 
156 	const char *fname = strnstr((char *)(uintptr_t)ktest_current_file, "xnu", 100);
157 
158 	ret = snprintf(msg,
159 	    size,
160 	    "\n[KTEST]\t"            /* header */
161 	    "LOG\t"                /* type */
162 	    "%lld\t"               /* time */
163 	    "%s\t"                 /* file */
164 	    "%d\t",                /* line */
165 	    ktest_current_time,
166 	    fname,
167 	    ktest_current_line);
168 	BOUNDS_CHECK_AND_UPDATE(ret, size);
169 
170 	ret = vsnprintf(msg, size, log_msg, args);
171 	BOUNDS_CHECK_AND_UPDATE(ret, size);
172 
173 	ret = snprintf(msg, size, "\n");
174 	BOUNDS_CHECK_AND_UPDATE(ret, size);
175 
176 	EMIT(ktest_output_buf, (int)(msg - ktest_output_buf));
177 }
178 
179 void
ktest_emit_perfdata(const char * metric,const char * unit,double value,const char * desc)180 ktest_emit_perfdata(const char * metric, const char * unit, double value, const char * desc)
181 {
182 	static const char * perfstr = "%s\t%lld\t%s\t\"%s\"";
183 	char * msg = ktest_output_buf;
184 	int64_t print_value = (int64_t)value;
185 	int size   = sizeof(ktest_output_buf);
186 	int ret;
187 
188 	const char *fname = strnstr((char *)(uintptr_t)ktest_current_file, "xnu", 100);
189 
190 	ret = snprintf(msg, size,
191 	    "\n[KTEST]\t"            /* header */
192 	    "PERF\t"               /* type */
193 	    "%lld\t"               /* time */
194 	    "%s\t"                 /* file */
195 	    "%d\t",                /* line */
196 	    ktest_current_time,
197 	    fname,
198 	    ktest_current_line);
199 	BOUNDS_CHECK_AND_UPDATE(ret, size);
200 
201 	ret = snprintf(msg, size, perfstr, metric, print_value, unit, desc);
202 	BOUNDS_CHECK_AND_UPDATE(ret, size);
203 
204 	ret = snprintf(msg, size, "\n");
205 	BOUNDS_CHECK_AND_UPDATE(ret, size);
206 
207 	EMIT(ktest_output_buf, (int)(msg - ktest_output_buf));
208 }
209 
210 void
ktest_emit_testcase(void)211 ktest_emit_testcase(void)
212 {
213 	char * msg = ktest_output_buf;
214 	int size = sizeof(ktest_output_buf);
215 	int ret;
216 
217 	const char *fname = strnstr((char *)(uintptr_t)ktest_current_file, "xnu", 100);
218 
219 	ret = snprintf(msg,
220 	    size,
221 	    "\n[KTEST]\t"            /* header */
222 	    "%s\t"                 /* type */
223 	    "%lld\t"               /* time */
224 	    "%d\t"                 /* index */
225 	    "%s\t"                 /* file */
226 	    "%d\t"                 /* line */
227 	    "%s\t"                 /* message */
228 	    "%s",                  /* current_expr */
229 	    ktest_testcase_result_tokens[ktest_testcase_mode]
230 	    [ktest_testcase_result],
231 	    ktest_current_time,
232 	    ktest_expression_index,
233 	    fname,
234 	    ktest_current_line,
235 	    ktest_current_msg,
236 	    ktest_current_expr);
237 	BOUNDS_CHECK_AND_UPDATE(ret, size);
238 
239 	for (int i = 0; ktest_current_var_names[i][0]; i++) {
240 		ret = snprintf(msg,
241 		    size,
242 		    "\t%s\t%s",
243 		    ktest_current_var_names[i],
244 		    ktest_current_var_values[i]);
245 		BOUNDS_CHECK_AND_UPDATE(ret, size);
246 	}
247 
248 	ret = snprintf(msg, size, "\n");
249 	BOUNDS_CHECK_AND_UPDATE(ret, size);
250 
251 	EMIT(ktest_output_buf, (int)(msg - ktest_output_buf));
252 }
253