tools/llvm: Do not build with symbols
[minix3.git] / external / bsd / kyua-testers / dist / atf_result.c
blob1665cbbbd8f6903ec81deee651a0c08f581728c9
1 // Copyright 2012 Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of Google Inc. nor the names of its contributors
14 // may be used to endorse or promote products derived from this software
15 // without specific prior written permission.
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "atf_result.h"
31 #include <sys/types.h>
32 #include <sys/wait.h>
34 #include <assert.h>
35 #include <errno.h>
36 #include <limits.h>
37 #include <stdbool.h>
38 #include <stdio.h>
39 #include <stdlib.h>
40 #include <string.h>
42 #include "error.h"
43 #include "result.h"
46 // Enumeration of the different result types returned by an ATF test case.
47 enum atf_status {
48 ATF_STATUS_EXPECTED_DEATH,
49 ATF_STATUS_EXPECTED_EXIT,
50 ATF_STATUS_EXPECTED_FAILURE,
51 ATF_STATUS_EXPECTED_SIGNAL,
52 ATF_STATUS_EXPECTED_TIMEOUT,
53 ATF_STATUS_FAILED,
54 ATF_STATUS_PASSED,
55 ATF_STATUS_SKIPPED,
57 // The broken status below is never returned by the test cases themselves.
58 // We use it internally to pass around problems detected while dealing with
59 // the test case itself (like an invalid result file).
60 ATF_STATUS_BROKEN,
64 /// Magic number representing a missing argument to the test result status.
65 ///
66 /// Use this to specify that an expected_exit or expected_signal result accepts
67 /// any exit code or signal, respectively.
68 #define NO_STATUS_ARG -1
71 /// Removes a trailing newline from a string (supposedly read by fgets(3)).
72 ///
73 /// \param [in,out] str The string to remove the trailing newline from.
74 ///
75 /// \return True if there was a newline character; false otherwise.
76 static bool
77 trim_newline(char* str)
79 const size_t length = strlen(str);
80 if (length == 0) {
81 return false;
82 } else {
83 if (str[length - 1] == '\n') {
84 str[length - 1] = '\0';
85 return true;
86 } else {
87 return false;
93 /// Force read on stream to see if we are really at EOF.
94 ///
95 /// A call to fgets(3) will not return EOF when it returns valid data. But
96 /// because of our semantics below, we need to be able to tell if more lines are
97 /// available before actually reading them.
98 ///
99 /// \param input The stream to check for EOF.
101 /// \return True if the stream is not at EOF yet; false otherwise.
102 static bool
103 is_really_eof(FILE* input)
105 const int ch = getc(input);
106 const bool real_eof = feof(input);
107 (void)ungetc(ch, input);
108 return real_eof;
112 /// Parses the optional argument to a result status.
114 /// \param str Pointer to the argument. May be \0 in those cases where the
115 /// status does not have any argument.
116 /// \param [out] status_arg Value of the parsed argument.
118 /// \return OK if the argument exists and is valid, or if it does not exist; an
119 /// error otherwise.
120 static kyua_error_t
121 parse_status_arg(const char* str, int* status_arg)
123 if (*str == '\0') {
124 *status_arg = NO_STATUS_ARG;
125 return kyua_error_ok();
128 const size_t length = strlen(str);
129 if (*str != '(' || *(str + length - 1) != ')')
130 return kyua_generic_error_new("Invalid status argument %s", str);
131 const char* const arg = str + 1;
133 char* endptr;
134 const long value = strtol(arg, &endptr, 10);
135 if (arg[0] == '\0' || endptr != str + length - 1)
136 return kyua_generic_error_new("Invalid status argument %s: not a "
137 "number", str);
138 if (errno == ERANGE && (value == LONG_MAX || value == LONG_MIN))
139 return kyua_generic_error_new("Invalid status argument %s: out of "
140 "range", str);
141 if (value < INT_MIN || value > INT_MAX)
142 return kyua_generic_error_new("Invalid status argument %s: out of "
143 "range", str);
145 *status_arg = (int)value;
146 return kyua_error_ok();
150 /// Parses a textual result status.
152 /// \param str The text to parse.
153 /// \param [out] status Status type if the input is valid.
154 /// \param [out] status_arg Optional integral argument to the status.
155 /// \param [out] need_reason Whether the detected status requires a reason.
157 /// \return An error if the status is not valid.
158 static kyua_error_t
159 parse_status(const char* str, enum atf_status* status, int* status_arg,
160 bool* need_reason)
162 if (strcmp(str, "passed") == 0) {
163 *status = ATF_STATUS_PASSED;
164 *need_reason = false;
165 return kyua_error_ok();
166 } else if (strcmp(str, "failed") == 0) {
167 *status = ATF_STATUS_FAILED;
168 *need_reason = true;
169 return kyua_error_ok();
170 } else if (strcmp(str, "skipped") == 0) {
171 *status = ATF_STATUS_SKIPPED;
172 *need_reason = true;
173 return kyua_error_ok();
174 } else if (strcmp(str, "expected_death") == 0) {
175 *status = ATF_STATUS_EXPECTED_DEATH;
176 *need_reason = true;
177 return kyua_error_ok();
178 } else if (strncmp(str, "expected_exit", 13) == 0) {
179 *status = ATF_STATUS_EXPECTED_EXIT;
180 *need_reason = true;
181 return parse_status_arg(str + 13, status_arg);
182 } else if (strcmp(str, "expected_failure") == 0) {
183 *status = ATF_STATUS_EXPECTED_FAILURE;
184 *need_reason = true;
185 return kyua_error_ok();
186 } else if (strncmp(str, "expected_signal", 15) == 0){
187 *status = ATF_STATUS_EXPECTED_SIGNAL;
188 *need_reason = true;
189 return parse_status_arg(str + 15, status_arg);
190 } else if (strcmp(str, "expected_timeout") == 0) {
191 *status = ATF_STATUS_EXPECTED_TIMEOUT;
192 *need_reason = true;
193 return kyua_error_ok();
194 } else {
195 return kyua_generic_error_new("Unknown test case result status %s",
196 str);
201 /// Advances a pointer to a buffer to its end.
203 /// \param [in,out] buffer Current buffer contents; updated on exit to point to
204 /// the termination character.
205 /// \param [in,out] buffer_size Current buffer size; updated on exit to account
206 /// for the decreased capacity due to the pointer increase.
207 static void
208 advance(char** buffer, size_t* buffer_size)
210 const size_t increment = strlen(*buffer);
211 *buffer += increment;
212 *buffer_size -= increment;
216 /// Extracts the result reason from the input file.
218 /// \pre This can only be called for those result types that require a reason.
220 /// \param [in,out] input The file from which to read.
221 /// \param first_line The first line of the reason. Because this is part of the
222 /// same line in which the result status is printed, this line has already
223 /// been read by the caller and thus must be provided here.
224 /// \param [out] output Buffer to which to write the full reason.
225 /// \param output_size Size of the output buffer.
227 /// \return An error if there was no reason in the input or if there is a
228 /// problem reading it.
229 static kyua_error_t
230 read_reason(FILE* input, const char* first_line, char* output,
231 size_t output_size)
233 if (first_line == NULL || *first_line == '\0')
234 return kyua_generic_error_new("Test case should have reported a "
235 "failure reason but didn't");
237 snprintf(output, output_size, "%s", first_line);
238 advance(&output, &output_size);
240 bool had_newline = true;
241 while (!is_really_eof(input)) {
242 if (had_newline) {
243 snprintf(output, output_size, "<<NEWLINE>>");
244 advance(&output, &output_size);
247 if (fgets(output, output_size, input) == NULL) {
248 assert(ferror(input));
249 return kyua_libc_error_new(errno, "Failed to read reason from "
250 "result file");
252 had_newline = trim_newline(output);
253 advance(&output, &output_size);
256 return kyua_error_ok();
260 /// Parses a results file written by an ATF test case.
262 /// \param input_name Path to the result file to parse.
263 /// \param [out] status Type of result.
264 /// \param [out] status_arg Optional integral argument to the status.
265 /// \param [out] reason Textual explanation of the result, if any.
266 /// \param reason_size Length of the reason output buffer.
268 /// \return An error if the input_name file has an invalid syntax; OK otherwise.
269 static kyua_error_t
270 read_atf_result(const char* input_name, enum atf_status* status,
271 int* status_arg, char* const reason, const size_t reason_size)
273 kyua_error_t error = kyua_error_ok();
275 FILE* input = fopen(input_name, "r");
276 if (input == NULL) {
277 error = kyua_generic_error_new("Premature exit");
278 goto out;
281 char line[1024];
282 if (fgets(line, sizeof(line), input) == NULL) {
283 if (ferror(input)) {
284 error = kyua_libc_error_new(errno, "Failed to read result from "
285 "file %s", input_name);
286 goto out_input;
287 } else {
288 assert(feof(input));
289 error = kyua_generic_error_new("Empty result file %s", input_name);
290 goto out_input;
294 if (!trim_newline(line)) {
295 error = kyua_generic_error_new("Missing newline in result file");
296 goto out_input;
299 char* reason_start = strstr(line, ": ");
300 if (reason_start != NULL) {
301 *reason_start = '\0';
302 *(reason_start + 1) = '\0';
303 reason_start += 2;
306 bool need_reason = false; // Initialize to shut up gcc warning.
307 error = parse_status(line, status, status_arg, &need_reason);
308 if (kyua_error_is_set(error))
309 goto out_input;
311 if (need_reason) {
312 error = read_reason(input, reason_start, reason, reason_size);
313 } else {
314 if (reason_start != NULL || !is_really_eof(input)) {
315 error = kyua_generic_error_new("Found unexpected reason in passed "
316 "test result");
317 goto out_input;
319 reason[0] = '\0';
322 out_input:
323 fclose(input);
324 out:
325 return error;
329 /// Writes a generic result file for an ATF broken result.
331 /// \param reason Textual explanation of the result.
332 /// \param status Exit code of the test program as returned by wait().
333 /// \param output Path to the generic result file to create.
334 /// \param [out] success Whether the result should be considered a success or
335 /// not; e.g. passed and skipped are successful, but failed is not.
337 /// \return An error if the conversion fails; OK otherwise.
338 static kyua_error_t
339 convert_broken(const char* reason, int status, const char* output,
340 bool* success)
342 if (WIFEXITED(status)) {
343 *success = false;
344 return kyua_result_write(
345 output, KYUA_RESULT_BROKEN, "%s; test case exited with code %d",
346 reason, WEXITSTATUS(status));
347 } else {
348 assert(WIFSIGNALED(status));
349 *success = false;
350 return kyua_result_write(
351 output, KYUA_RESULT_BROKEN, "%s; test case received signal %d%s",
352 reason, WTERMSIG(status),
353 WCOREDUMP(status) ? " (core dumped)" : "");
358 /// Writes a generic result file for an ATF expected_death result.
360 /// \param reason Textual explanation of the result.
361 /// \param status Exit code of the test program as returned by wait().
362 /// \param output Path to the generic result file to create.
363 /// \param [out] success Whether the result should be considered a success or
364 /// not; e.g. passed and skipped are successful, but failed is not.
366 /// \return An error if the conversion fails; OK otherwise.
367 static kyua_error_t
368 convert_expected_death(const char* reason, int status, const char* output,
369 bool* success)
371 if (WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS) {
372 *success = false;
373 return kyua_result_write(
374 output, KYUA_RESULT_FAILED, "Test case expected to die but exited "
375 "successfully");
376 } else {
377 *success = true;
378 return kyua_result_write(
379 output, KYUA_RESULT_EXPECTED_FAILURE, "%s", reason);
384 /// Writes a generic result file for an ATF expected_exit result
386 /// \param status_arg Optional integral argument to the status.
387 /// \param reason Textual explanation of the result.
388 /// \param status Exit code of the test program as returned by wait().
389 /// \param output Path to the generic result file to create.
390 /// \param [out] success Whether the result should be considered a success or
391 /// not; e.g. passed and skipped are successful, but failed is not.
393 /// \return An error if the conversion fails; OK otherwise.
394 static kyua_error_t
395 convert_expected_exit(const int status_arg, const char* reason, int status,
396 const char* output, bool* success)
398 if (WIFEXITED(status)) {
399 if (status_arg == NO_STATUS_ARG || status_arg == WEXITSTATUS(status)) {
400 *success = true;
401 return kyua_result_write(
402 output, KYUA_RESULT_EXPECTED_FAILURE, "%s", reason);
403 } else {
404 *success = false;
405 return kyua_result_write(
406 output, KYUA_RESULT_FAILED, "Test case expected to exit with "
407 "code %d but got code %d", status_arg, WEXITSTATUS(status));
409 } else {
410 assert(WIFSIGNALED(status));
411 *success = false;
412 return kyua_result_write(
413 output, KYUA_RESULT_FAILED, "Test case expected to exit normally "
414 "but received signal %d%s", WTERMSIG(status),
415 WCOREDUMP(status) ? " (core dumped)" : "");
420 /// Writes a generic result file for an ATF expected_failure result.
422 /// \param reason Textual explanation of the result.
423 /// \param status Exit code of the test program as returned by wait().
424 /// \param output Path to the generic result file to create.
425 /// \param [out] success Whether the result should be considered a success or
426 /// not; e.g. passed and skipped are successful, but failed is not.
428 /// \return An error if the conversion fails; OK otherwise.
429 static kyua_error_t
430 convert_expected_failure(const char* reason, int status, const char* output,
431 bool* success)
433 if (WIFEXITED(status)) {
434 if (WEXITSTATUS(status) == EXIT_SUCCESS) {
435 *success = true;
436 return kyua_result_write(
437 output, KYUA_RESULT_EXPECTED_FAILURE, "%s", reason);
438 } else {
439 *success = false;
440 return kyua_result_write(
441 output, KYUA_RESULT_FAILED, "Test case expected a failure but "
442 "exited with error code %d", WEXITSTATUS(status));
444 } else {
445 assert(WIFSIGNALED(status));
446 *success = false;
447 return kyua_result_write(
448 output, KYUA_RESULT_FAILED, "Test case expected a failure but "
449 "received signal %d%s", WTERMSIG(status),
450 WCOREDUMP(status) ? " (core dumped)" : "");
455 /// Writes a generic result file for an ATF expected_signal result.
457 /// \param status_arg Optional integral argument to the status.
458 /// \param reason Textual explanation of the result.
459 /// \param status Exit code of the test program as returned by wait().
460 /// \param output Path to the generic result file to create.
461 /// \param [out] success Whether the result should be considered a success or
462 /// not; e.g. passed and skipped are successful, but failed is not.
464 /// \return An error if the conversion fails; OK otherwise.
465 static kyua_error_t
466 convert_expected_signal(const int status_arg, const char* reason, int status,
467 const char* output, bool* success)
469 if (WIFSIGNALED(status)) {
470 if (status_arg == NO_STATUS_ARG || status_arg == WTERMSIG(status)) {
471 *success = true;
472 return kyua_result_write(
473 output, KYUA_RESULT_EXPECTED_FAILURE, "%s", reason);
474 } else {
475 *success = false;
476 return kyua_result_write(
477 output, KYUA_RESULT_FAILED, "Test case expected to receive "
478 "signal %d but got %d", status_arg, WTERMSIG(status));
480 } else {
481 assert(WIFEXITED(status));
482 *success = false;
483 return kyua_result_write(
484 output, KYUA_RESULT_FAILED, "Test case expected to receive a "
485 "signal but exited with code %d", WEXITSTATUS(status));
490 /// Writes a generic result file for an ATF expected_timeout result.
492 /// \param status Exit code of the test program as returned by wait().
493 /// \param output Path to the generic result file to create.
494 /// \param [out] success Whether the result should be considered a success or
495 /// not; e.g. passed and skipped are successful, but failed is not.
497 /// \return An error if the conversion fails; OK otherwise.
498 static kyua_error_t
499 convert_expected_timeout(int status, const char* output, bool* success)
501 if (WIFEXITED(status)) {
502 *success = false;
503 return kyua_result_write(
504 output, KYUA_RESULT_FAILED, "Test case expected to time out but "
505 "exited with code %d", WEXITSTATUS(status));
506 } else {
507 assert(WIFSIGNALED(status));
508 *success = false;
509 return kyua_result_write(
510 output, KYUA_RESULT_FAILED, "Test case expected to time out but "
511 "received signal %d%s", WTERMSIG(status),
512 WCOREDUMP(status) ? " (core dumped)" : "");
517 /// Writes a generic result file for an ATF failed result.
519 /// \param reason Textual explanation of the result.
520 /// \param status Exit code of the test program as returned by wait().
521 /// \param output Path to the generic result file to create.
522 /// \param [out] success Whether the result should be considered a success or
523 /// not; e.g. passed and skipped are successful, but failed is not.
525 /// \return An error if the conversion fails; OK otherwise.
526 static kyua_error_t
527 convert_failed(const char* reason, int status, const char* output,
528 bool* success)
530 if (WIFEXITED(status)) {
531 if (WEXITSTATUS(status) == EXIT_SUCCESS) {
532 *success = false;
533 return kyua_result_write(
534 output, KYUA_RESULT_BROKEN, "Test case reported a failed "
535 "result but exited with a successful exit code");
536 } else {
537 *success = false;
538 return kyua_result_write(
539 output, KYUA_RESULT_FAILED, "%s", reason);
541 } else {
542 assert(WIFSIGNALED(status));
543 *success = false;
544 return kyua_result_write(
545 output, KYUA_RESULT_BROKEN, "Test case reported a failed result "
546 "but received signal %d%s", WTERMSIG(status),
547 WCOREDUMP(status) ? " (core dumped)" : "");
552 /// Writes a generic result file for an ATF passed result.
554 /// \param status Exit code of the test program as returned by wait().
555 /// \param output Path to the generic result file to create.
556 /// \param [out] success Whether the result should be considered a success or
557 /// not; e.g. passed and skipped are successful, but failed is not.
559 /// \return An error if the conversion fails; OK otherwise.
560 static kyua_error_t
561 convert_passed(int status, const char* output, bool* success)
563 if (WIFEXITED(status)) {
564 if (WEXITSTATUS(status) == EXIT_SUCCESS) {
565 *success = true;
566 return kyua_result_write(output, KYUA_RESULT_PASSED, NULL);
567 } else {
568 *success = false;
569 return kyua_result_write(
570 output, KYUA_RESULT_BROKEN, "Test case reported a passed "
571 "result but returned a non-zero exit code %d",
572 WEXITSTATUS(status));
574 } else {
575 assert(WIFSIGNALED(status));
576 *success = false;
577 return kyua_result_write(
578 output, KYUA_RESULT_BROKEN, "Test case reported a passed result "
579 "but received signal %d%s", WTERMSIG(status),
580 WCOREDUMP(status) ? " (core dumped)" : "");
585 /// Writes a generic result file for an ATF skipped result.
587 /// \param reason Textual explanation of the result.
588 /// \param status Exit code of the test program as returned by wait().
589 /// \param output Path to the generic result file to create.
590 /// \param [out] success Whether the result should be considered a success or
591 /// not; e.g. passed and skipped are successful, but failed is not.
593 /// \return An error if the conversion fails; OK otherwise.
594 static kyua_error_t
595 convert_skipped(const char* reason, int status, const char* output,
596 bool* success)
598 if (WIFEXITED(status)) {
599 if (WEXITSTATUS(status) == EXIT_SUCCESS) {
600 *success = true;
601 return kyua_result_write(output, KYUA_RESULT_SKIPPED, "%s", reason);
602 } else {
603 *success = false;
604 return kyua_result_write(
605 output, KYUA_RESULT_BROKEN, "Test case reported a skipped "
606 "result but returned a non-zero exit code %d",
607 WEXITSTATUS(status));
609 } else {
610 *success = false;
611 assert(WIFSIGNALED(status));
612 return kyua_result_write(
613 output, KYUA_RESULT_BROKEN, "Test case reported a skipped result "
614 "but received signal %d%s", WTERMSIG(status),
615 WCOREDUMP(status) ? " (core dumped)" : "");
620 /// Writes a generic result file based on an ATF result and an exit code.
622 /// \param status Type of the ATF result.
623 /// \param status_arg Optional integral argument to the status.
624 /// \param reason Textual explanation of the result.
625 /// \param wait_status Exit code of the test program as returned by wait().
626 /// \param timed_out Whether the test program timed out or not.
627 /// \param output Path to the generic result file to create.
628 /// \param [out] success Whether the result should be considered a success or
629 /// not; e.g. passed and skipped are successful, but failed is not.
631 /// \return An error if the conversion fails; OK otherwise.
632 static kyua_error_t
633 convert_result(const enum atf_status status, const int status_arg,
634 const char* reason, const int wait_status, const bool timed_out,
635 const char* output, bool* success)
637 if (timed_out) {
638 if (status == ATF_STATUS_EXPECTED_TIMEOUT) {
639 *success = true;
640 return kyua_result_write(
641 output, KYUA_RESULT_EXPECTED_FAILURE, "%s", reason);
642 } else {
643 assert(status == ATF_STATUS_BROKEN);
644 *success = false;
645 return kyua_result_write(
646 output, KYUA_RESULT_BROKEN, "Test case body timed out");
650 switch (status) {
651 case ATF_STATUS_BROKEN:
652 return convert_broken(reason, wait_status, output, success);
654 case ATF_STATUS_EXPECTED_DEATH:
655 return convert_expected_death(reason, wait_status, output, success);
657 case ATF_STATUS_EXPECTED_EXIT:
658 return convert_expected_exit(status_arg, reason, wait_status, output,
659 success);
661 case ATF_STATUS_EXPECTED_FAILURE:
662 return convert_expected_failure(reason, wait_status, output, success);
664 case ATF_STATUS_EXPECTED_SIGNAL:
665 return convert_expected_signal(status_arg, reason, wait_status, output,
666 success);
668 case ATF_STATUS_EXPECTED_TIMEOUT:
669 return convert_expected_timeout(wait_status, output, success);
671 case ATF_STATUS_FAILED:
672 return convert_failed(reason, wait_status, output, success);
674 case ATF_STATUS_PASSED:
675 return convert_passed(wait_status, output, success);
677 case ATF_STATUS_SKIPPED:
678 return convert_skipped(reason, wait_status, output, success);
681 assert(false);
682 #if defined(__minix) && defined(NDEBUG)
683 abort();
684 #endif /* defined(__minix) && !defined(NDEBUG) */
688 /// Writes a generic result file based on an ATF result file and an exit code.
690 /// \param input_name Path to the ATF result file to parse.
691 /// \param output_name Path to the generic result file to create.
692 /// \param wait_status Exit code of the test program as returned by wait().
693 /// \param timed_out Whether the test program timed out or not.
694 /// \param [out] success Whether the result should be considered a success or
695 /// not; e.g. passed and skipped are successful, but failed is not.
697 /// \return An error if the conversion fails; OK otherwise.
698 kyua_error_t
699 kyua_atf_result_rewrite(const char* input_name, const char* output_name,
700 const int wait_status, const bool timed_out,
701 bool* success)
703 enum atf_status status; int status_arg; char reason[1024];
704 status = ATF_STATUS_BROKEN; // Initialize to shut up gcc warning.
705 const kyua_error_t error = read_atf_result(input_name, &status, &status_arg,
706 reason, sizeof(reason));
707 if (kyua_error_is_set(error)) {
708 // Errors while parsing the ATF result file can often be attributed to
709 // the result file being bogus. Therefore, just mark the test case as
710 // broken, because it possibly is.
711 status = ATF_STATUS_BROKEN;
712 kyua_error_format(error, reason, sizeof(reason));
713 kyua_error_free(error);
716 // Errors converting the loaded result to the final result file are not due
717 // to a bad test program: they are because our own code fails (e.g. cannot
718 // create the output file). These need to be returned to the caller.
719 return convert_result(status, status_arg, reason, wait_status, timed_out,
720 output_name, success);
724 /// Creates a result file for a failed cleanup routine.
726 /// This function is supposed to be invoked after the body has had a chance to
727 /// create its own result file, and only if the body has terminated with a
728 /// non-failure result.
730 /// \param output_name Path to the generic result file to create.
731 /// \param wait_status Exit code of the test program as returned by wait().
732 /// \param timed_out Whether the test program timed out or not.
733 /// \param [out] success Whether the result should be considered a success or
734 /// not; i.e. a clean exit is successful, but anything else is a failure.
736 /// \return An error if there is a problem writing the result; OK otherwise.
737 kyua_error_t
738 kyua_atf_result_cleanup_rewrite(const char* output_name, int wait_status,
739 const bool timed_out, bool* success)
741 if (timed_out) {
742 *success = false;
743 return kyua_result_write(
744 output_name, KYUA_RESULT_BROKEN, "Test case cleanup timed out");
745 } else {
746 if (WIFEXITED(wait_status)) {
747 if (WEXITSTATUS(wait_status) == EXIT_SUCCESS) {
748 *success = true;
749 // Reuse the result file created by the body. I.e. avoid
750 // creating a new file here.
751 return kyua_error_ok();
752 } else {
753 *success = false;
754 return kyua_result_write(
755 output_name, KYUA_RESULT_BROKEN, "Test case cleanup exited "
756 "with code %d", WEXITSTATUS(wait_status));
758 } else {
759 *success = false;
760 return kyua_result_write(
761 output_name, KYUA_RESULT_BROKEN, "Test case cleanup received "
762 "signal %d%s", WTERMSIG(wait_status),
763 WCOREDUMP(wait_status) ? " (core dumped)" : "");