xref: /minix3/external/bsd/kyua-testers/dist/atf_result.c (revision 3260d16f34636651fb9ef891a1ffe03fd23b513d)
111be35a1SLionel Sambuc // Copyright 2012 Google Inc.
211be35a1SLionel Sambuc // All rights reserved.
311be35a1SLionel Sambuc //
411be35a1SLionel Sambuc // Redistribution and use in source and binary forms, with or without
511be35a1SLionel Sambuc // modification, are permitted provided that the following conditions are
611be35a1SLionel Sambuc // met:
711be35a1SLionel Sambuc //
811be35a1SLionel Sambuc // * Redistributions of source code must retain the above copyright
911be35a1SLionel Sambuc //   notice, this list of conditions and the following disclaimer.
1011be35a1SLionel Sambuc // * Redistributions in binary form must reproduce the above copyright
1111be35a1SLionel Sambuc //   notice, this list of conditions and the following disclaimer in the
1211be35a1SLionel Sambuc //   documentation and/or other materials provided with the distribution.
1311be35a1SLionel Sambuc // * Neither the name of Google Inc. nor the names of its contributors
1411be35a1SLionel Sambuc //   may be used to endorse or promote products derived from this software
1511be35a1SLionel Sambuc //   without specific prior written permission.
1611be35a1SLionel Sambuc //
1711be35a1SLionel Sambuc // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
1811be35a1SLionel Sambuc // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
1911be35a1SLionel Sambuc // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
2011be35a1SLionel Sambuc // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
2111be35a1SLionel Sambuc // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2211be35a1SLionel Sambuc // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
2311be35a1SLionel Sambuc // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2411be35a1SLionel Sambuc // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2511be35a1SLionel Sambuc // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2611be35a1SLionel Sambuc // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
2711be35a1SLionel Sambuc // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2811be35a1SLionel Sambuc 
2911be35a1SLionel Sambuc #include "atf_result.h"
3011be35a1SLionel Sambuc 
3111be35a1SLionel Sambuc #include <sys/types.h>
3211be35a1SLionel Sambuc #include <sys/wait.h>
3311be35a1SLionel Sambuc 
3411be35a1SLionel Sambuc #include <assert.h>
3511be35a1SLionel Sambuc #include <errno.h>
3611be35a1SLionel Sambuc #include <limits.h>
3711be35a1SLionel Sambuc #include <stdbool.h>
3811be35a1SLionel Sambuc #include <stdio.h>
3911be35a1SLionel Sambuc #include <stdlib.h>
4011be35a1SLionel Sambuc #include <string.h>
4111be35a1SLionel Sambuc 
4211be35a1SLionel Sambuc #include "error.h"
4311be35a1SLionel Sambuc #include "result.h"
4411be35a1SLionel Sambuc 
4511be35a1SLionel Sambuc 
4611be35a1SLionel Sambuc // Enumeration of the different result types returned by an ATF test case.
4711be35a1SLionel Sambuc enum atf_status {
4811be35a1SLionel Sambuc     ATF_STATUS_EXPECTED_DEATH,
4911be35a1SLionel Sambuc     ATF_STATUS_EXPECTED_EXIT,
5011be35a1SLionel Sambuc     ATF_STATUS_EXPECTED_FAILURE,
5111be35a1SLionel Sambuc     ATF_STATUS_EXPECTED_SIGNAL,
5211be35a1SLionel Sambuc     ATF_STATUS_EXPECTED_TIMEOUT,
5311be35a1SLionel Sambuc     ATF_STATUS_FAILED,
5411be35a1SLionel Sambuc     ATF_STATUS_PASSED,
5511be35a1SLionel Sambuc     ATF_STATUS_SKIPPED,
5611be35a1SLionel Sambuc 
5711be35a1SLionel Sambuc     // The broken status below is never returned by the test cases themselves.
5811be35a1SLionel Sambuc     // We use it internally to pass around problems detected while dealing with
5911be35a1SLionel Sambuc     // the test case itself (like an invalid result file).
6011be35a1SLionel Sambuc     ATF_STATUS_BROKEN,
6111be35a1SLionel Sambuc };
6211be35a1SLionel Sambuc 
6311be35a1SLionel Sambuc 
6411be35a1SLionel Sambuc /// Magic number representing a missing argument to the test result status.
6511be35a1SLionel Sambuc ///
6611be35a1SLionel Sambuc /// Use this to specify that an expected_exit or expected_signal result accepts
6711be35a1SLionel Sambuc /// any exit code or signal, respectively.
6811be35a1SLionel Sambuc #define NO_STATUS_ARG -1
6911be35a1SLionel Sambuc 
7011be35a1SLionel Sambuc 
7111be35a1SLionel Sambuc /// Removes a trailing newline from a string (supposedly read by fgets(3)).
7211be35a1SLionel Sambuc ///
7311be35a1SLionel Sambuc /// \param [in,out] str The string to remove the trailing newline from.
7411be35a1SLionel Sambuc ///
7511be35a1SLionel Sambuc /// \return True if there was a newline character; false otherwise.
7611be35a1SLionel Sambuc static bool
trim_newline(char * str)7711be35a1SLionel Sambuc trim_newline(char* str)
7811be35a1SLionel Sambuc {
7911be35a1SLionel Sambuc     const size_t length = strlen(str);
8011be35a1SLionel Sambuc     if (length == 0) {
8111be35a1SLionel Sambuc         return false;
8211be35a1SLionel Sambuc     } else {
8311be35a1SLionel Sambuc         if (str[length - 1] == '\n') {
8411be35a1SLionel Sambuc             str[length - 1] = '\0';
8511be35a1SLionel Sambuc             return true;
8611be35a1SLionel Sambuc         } else {
8711be35a1SLionel Sambuc             return false;
8811be35a1SLionel Sambuc         }
8911be35a1SLionel Sambuc     }
9011be35a1SLionel Sambuc }
9111be35a1SLionel Sambuc 
9211be35a1SLionel Sambuc 
9311be35a1SLionel Sambuc /// Force read on stream to see if we are really at EOF.
9411be35a1SLionel Sambuc ///
9511be35a1SLionel Sambuc /// A call to fgets(3) will not return EOF when it returns valid data.  But
9611be35a1SLionel Sambuc /// because of our semantics below, we need to be able to tell if more lines are
9711be35a1SLionel Sambuc /// available before actually reading them.
9811be35a1SLionel Sambuc ///
9911be35a1SLionel Sambuc /// \param input The stream to check for EOF.
10011be35a1SLionel Sambuc ///
10111be35a1SLionel Sambuc /// \return True if the stream is not at EOF yet; false otherwise.
10211be35a1SLionel Sambuc static bool
is_really_eof(FILE * input)10311be35a1SLionel Sambuc is_really_eof(FILE* input)
10411be35a1SLionel Sambuc {
10511be35a1SLionel Sambuc     const int ch = getc(input);
10611be35a1SLionel Sambuc     const bool real_eof = feof(input);
10711be35a1SLionel Sambuc     (void)ungetc(ch, input);
10811be35a1SLionel Sambuc     return real_eof;
10911be35a1SLionel Sambuc }
11011be35a1SLionel Sambuc 
11111be35a1SLionel Sambuc 
11211be35a1SLionel Sambuc /// Parses the optional argument to a result status.
11311be35a1SLionel Sambuc ///
11411be35a1SLionel Sambuc /// \param str Pointer to the argument.  May be \0 in those cases where the
11511be35a1SLionel Sambuc ///     status does not have any argument.
11611be35a1SLionel Sambuc /// \param [out] status_arg Value of the parsed argument.
11711be35a1SLionel Sambuc ///
11811be35a1SLionel Sambuc /// \return OK if the argument exists and is valid, or if it does not exist; an
11911be35a1SLionel Sambuc /// error otherwise.
12011be35a1SLionel Sambuc static kyua_error_t
parse_status_arg(const char * str,int * status_arg)12111be35a1SLionel Sambuc parse_status_arg(const char* str, int* status_arg)
12211be35a1SLionel Sambuc {
12311be35a1SLionel Sambuc     if (*str == '\0') {
12411be35a1SLionel Sambuc         *status_arg = NO_STATUS_ARG;
12511be35a1SLionel Sambuc         return kyua_error_ok();
12611be35a1SLionel Sambuc     }
12711be35a1SLionel Sambuc 
12811be35a1SLionel Sambuc     const size_t length = strlen(str);
12911be35a1SLionel Sambuc     if (*str != '(' || *(str + length - 1) != ')')
13011be35a1SLionel Sambuc         return kyua_generic_error_new("Invalid status argument %s", str);
13111be35a1SLionel Sambuc     const char* const arg = str + 1;
13211be35a1SLionel Sambuc 
13311be35a1SLionel Sambuc     char* endptr;
13411be35a1SLionel Sambuc     const long value = strtol(arg, &endptr, 10);
13511be35a1SLionel Sambuc     if (arg[0] == '\0' || endptr != str + length - 1)
13611be35a1SLionel Sambuc         return kyua_generic_error_new("Invalid status argument %s: not a "
13711be35a1SLionel Sambuc                                       "number", str);
13811be35a1SLionel Sambuc     if (errno == ERANGE && (value == LONG_MAX || value == LONG_MIN))
13911be35a1SLionel Sambuc         return kyua_generic_error_new("Invalid status argument %s: out of "
14011be35a1SLionel Sambuc                                       "range", str);
14111be35a1SLionel Sambuc     if (value < INT_MIN || value > INT_MAX)
14211be35a1SLionel Sambuc         return kyua_generic_error_new("Invalid status argument %s: out of "
14311be35a1SLionel Sambuc                                       "range", str);
14411be35a1SLionel Sambuc 
14511be35a1SLionel Sambuc     *status_arg = (int)value;
14611be35a1SLionel Sambuc     return kyua_error_ok();
14711be35a1SLionel Sambuc }
14811be35a1SLionel Sambuc 
14911be35a1SLionel Sambuc 
15011be35a1SLionel Sambuc /// Parses a textual result status.
15111be35a1SLionel Sambuc ///
15211be35a1SLionel Sambuc /// \param str The text to parse.
15311be35a1SLionel Sambuc /// \param [out] status Status type if the input is valid.
15411be35a1SLionel Sambuc /// \param [out] status_arg Optional integral argument to the status.
15511be35a1SLionel Sambuc /// \param [out] need_reason Whether the detected status requires a reason.
15611be35a1SLionel Sambuc ///
15711be35a1SLionel Sambuc /// \return An error if the status is not valid.
15811be35a1SLionel Sambuc static kyua_error_t
parse_status(const char * str,enum atf_status * status,int * status_arg,bool * need_reason)15911be35a1SLionel Sambuc parse_status(const char* str, enum atf_status* status, int* status_arg,
16011be35a1SLionel Sambuc              bool* need_reason)
16111be35a1SLionel Sambuc {
16211be35a1SLionel Sambuc     if (strcmp(str, "passed") == 0) {
16311be35a1SLionel Sambuc         *status = ATF_STATUS_PASSED;
16411be35a1SLionel Sambuc         *need_reason = false;
16511be35a1SLionel Sambuc         return kyua_error_ok();
16611be35a1SLionel Sambuc     } else if (strcmp(str, "failed") == 0) {
16711be35a1SLionel Sambuc         *status = ATF_STATUS_FAILED;
16811be35a1SLionel Sambuc         *need_reason = true;
16911be35a1SLionel Sambuc         return kyua_error_ok();
17011be35a1SLionel Sambuc     } else if (strcmp(str, "skipped") == 0) {
17111be35a1SLionel Sambuc         *status = ATF_STATUS_SKIPPED;
17211be35a1SLionel Sambuc         *need_reason = true;
17311be35a1SLionel Sambuc         return kyua_error_ok();
17411be35a1SLionel Sambuc     } else if (strcmp(str, "expected_death") == 0) {
17511be35a1SLionel Sambuc         *status = ATF_STATUS_EXPECTED_DEATH;
17611be35a1SLionel Sambuc         *need_reason = true;
17711be35a1SLionel Sambuc         return kyua_error_ok();
17811be35a1SLionel Sambuc     } else if (strncmp(str, "expected_exit", 13) == 0) {
17911be35a1SLionel Sambuc         *status = ATF_STATUS_EXPECTED_EXIT;
18011be35a1SLionel Sambuc         *need_reason = true;
18111be35a1SLionel Sambuc         return parse_status_arg(str + 13, status_arg);
18211be35a1SLionel Sambuc     } else if (strcmp(str, "expected_failure") == 0) {
18311be35a1SLionel Sambuc         *status = ATF_STATUS_EXPECTED_FAILURE;
18411be35a1SLionel Sambuc         *need_reason = true;
18511be35a1SLionel Sambuc         return kyua_error_ok();
18611be35a1SLionel Sambuc     } else if (strncmp(str, "expected_signal", 15) == 0){
18711be35a1SLionel Sambuc         *status = ATF_STATUS_EXPECTED_SIGNAL;
18811be35a1SLionel Sambuc         *need_reason = true;
18911be35a1SLionel Sambuc         return parse_status_arg(str + 15, status_arg);
19011be35a1SLionel Sambuc     } else if (strcmp(str, "expected_timeout") == 0) {
19111be35a1SLionel Sambuc         *status = ATF_STATUS_EXPECTED_TIMEOUT;
19211be35a1SLionel Sambuc         *need_reason = true;
19311be35a1SLionel Sambuc         return kyua_error_ok();
19411be35a1SLionel Sambuc     } else {
19511be35a1SLionel Sambuc         return kyua_generic_error_new("Unknown test case result status %s",
19611be35a1SLionel Sambuc                                       str);
19711be35a1SLionel Sambuc     }
19811be35a1SLionel Sambuc }
19911be35a1SLionel Sambuc 
20011be35a1SLionel Sambuc 
20111be35a1SLionel Sambuc /// Advances a pointer to a buffer to its end.
20211be35a1SLionel Sambuc ///
20311be35a1SLionel Sambuc /// \param [in,out] buffer Current buffer contents; updated on exit to point to
20411be35a1SLionel Sambuc ///     the termination character.
20511be35a1SLionel Sambuc /// \param [in,out] buffer_size Current buffer size; updated on exit to account
20611be35a1SLionel Sambuc ///     for the decreased capacity due to the pointer increase.
20711be35a1SLionel Sambuc static void
advance(char ** buffer,size_t * buffer_size)20811be35a1SLionel Sambuc advance(char** buffer, size_t* buffer_size)
20911be35a1SLionel Sambuc {
21011be35a1SLionel Sambuc     const size_t increment = strlen(*buffer);
21111be35a1SLionel Sambuc     *buffer += increment;
21211be35a1SLionel Sambuc     *buffer_size -= increment;
21311be35a1SLionel Sambuc }
21411be35a1SLionel Sambuc 
21511be35a1SLionel Sambuc 
21611be35a1SLionel Sambuc /// Extracts the result reason from the input file.
21711be35a1SLionel Sambuc ///
21811be35a1SLionel Sambuc /// \pre This can only be called for those result types that require a reason.
21911be35a1SLionel Sambuc ///
22011be35a1SLionel Sambuc /// \param [in,out] input The file from which to read.
22111be35a1SLionel Sambuc /// \param first_line The first line of the reason.  Because this is part of the
22211be35a1SLionel Sambuc ///     same line in which the result status is printed, this line has already
22311be35a1SLionel Sambuc ///     been read by the caller and thus must be provided here.
22411be35a1SLionel Sambuc /// \param [out] output Buffer to which to write the full reason.
22511be35a1SLionel Sambuc /// \param output_size Size of the output buffer.
22611be35a1SLionel Sambuc ///
22711be35a1SLionel Sambuc /// \return An error if there was no reason in the input or if there is a
22811be35a1SLionel Sambuc /// problem reading it.
22911be35a1SLionel Sambuc static kyua_error_t
read_reason(FILE * input,const char * first_line,char * output,size_t output_size)23011be35a1SLionel Sambuc read_reason(FILE* input, const char* first_line, char* output,
23111be35a1SLionel Sambuc             size_t output_size)
23211be35a1SLionel Sambuc {
23311be35a1SLionel Sambuc     if (first_line == NULL || *first_line == '\0')
23411be35a1SLionel Sambuc         return kyua_generic_error_new("Test case should have reported a "
23511be35a1SLionel Sambuc                                       "failure reason but didn't");
23611be35a1SLionel Sambuc 
23711be35a1SLionel Sambuc     snprintf(output, output_size, "%s", first_line);
23811be35a1SLionel Sambuc     advance(&output, &output_size);
23911be35a1SLionel Sambuc 
24011be35a1SLionel Sambuc     bool had_newline = true;
24111be35a1SLionel Sambuc     while (!is_really_eof(input)) {
24211be35a1SLionel Sambuc         if (had_newline) {
24311be35a1SLionel Sambuc             snprintf(output, output_size, "<<NEWLINE>>");
24411be35a1SLionel Sambuc             advance(&output, &output_size);
24511be35a1SLionel Sambuc         }
24611be35a1SLionel Sambuc 
24711be35a1SLionel Sambuc         if (fgets(output, output_size, input) == NULL) {
24811be35a1SLionel Sambuc             assert(ferror(input));
24911be35a1SLionel Sambuc             return kyua_libc_error_new(errno, "Failed to read reason from "
25011be35a1SLionel Sambuc                                        "result file");
25111be35a1SLionel Sambuc         }
25211be35a1SLionel Sambuc         had_newline = trim_newline(output);
25311be35a1SLionel Sambuc         advance(&output, &output_size);
25411be35a1SLionel Sambuc     }
25511be35a1SLionel Sambuc 
25611be35a1SLionel Sambuc     return kyua_error_ok();
25711be35a1SLionel Sambuc }
25811be35a1SLionel Sambuc 
25911be35a1SLionel Sambuc 
26011be35a1SLionel Sambuc /// Parses a results file written by an ATF test case.
26111be35a1SLionel Sambuc ///
26211be35a1SLionel Sambuc /// \param input_name Path to the result file to parse.
26311be35a1SLionel Sambuc /// \param [out] status Type of result.
26411be35a1SLionel Sambuc /// \param [out] status_arg Optional integral argument to the status.
26511be35a1SLionel Sambuc /// \param [out] reason Textual explanation of the result, if any.
26611be35a1SLionel Sambuc /// \param reason_size Length of the reason output buffer.
26711be35a1SLionel Sambuc ///
26811be35a1SLionel Sambuc /// \return An error if the input_name file has an invalid syntax; OK otherwise.
26911be35a1SLionel Sambuc static kyua_error_t
read_atf_result(const char * input_name,enum atf_status * status,int * status_arg,char * const reason,const size_t reason_size)27011be35a1SLionel Sambuc read_atf_result(const char* input_name, enum atf_status* status,
27111be35a1SLionel Sambuc                 int* status_arg, char* const reason, const size_t reason_size)
27211be35a1SLionel Sambuc {
27311be35a1SLionel Sambuc     kyua_error_t error = kyua_error_ok();
27411be35a1SLionel Sambuc 
27511be35a1SLionel Sambuc     FILE* input = fopen(input_name, "r");
27611be35a1SLionel Sambuc     if (input == NULL) {
27711be35a1SLionel Sambuc         error = kyua_generic_error_new("Premature exit");
27811be35a1SLionel Sambuc         goto out;
27911be35a1SLionel Sambuc     }
28011be35a1SLionel Sambuc 
28111be35a1SLionel Sambuc     char line[1024];
28211be35a1SLionel Sambuc     if (fgets(line, sizeof(line), input) == NULL) {
28311be35a1SLionel Sambuc         if (ferror(input)) {
28411be35a1SLionel Sambuc             error = kyua_libc_error_new(errno, "Failed to read result from "
28511be35a1SLionel Sambuc                                         "file %s", input_name);
28611be35a1SLionel Sambuc             goto out_input;
28711be35a1SLionel Sambuc         } else {
28811be35a1SLionel Sambuc             assert(feof(input));
28911be35a1SLionel Sambuc             error = kyua_generic_error_new("Empty result file %s", input_name);
29011be35a1SLionel Sambuc             goto out_input;
29111be35a1SLionel Sambuc         }
29211be35a1SLionel Sambuc     }
29311be35a1SLionel Sambuc 
29411be35a1SLionel Sambuc     if (!trim_newline(line)) {
29511be35a1SLionel Sambuc         error = kyua_generic_error_new("Missing newline in result file");
29611be35a1SLionel Sambuc         goto out_input;
29711be35a1SLionel Sambuc     }
29811be35a1SLionel Sambuc 
29911be35a1SLionel Sambuc     char* reason_start = strstr(line, ": ");
30011be35a1SLionel Sambuc     if (reason_start != NULL) {
30111be35a1SLionel Sambuc         *reason_start = '\0';
30211be35a1SLionel Sambuc         *(reason_start + 1) = '\0';
30311be35a1SLionel Sambuc         reason_start += 2;
30411be35a1SLionel Sambuc     }
30511be35a1SLionel Sambuc 
30611be35a1SLionel Sambuc     bool need_reason = false;  // Initialize to shut up gcc warning.
30711be35a1SLionel Sambuc     error = parse_status(line, status, status_arg, &need_reason);
30811be35a1SLionel Sambuc     if (kyua_error_is_set(error))
30911be35a1SLionel Sambuc         goto out_input;
31011be35a1SLionel Sambuc 
31111be35a1SLionel Sambuc     if (need_reason) {
31211be35a1SLionel Sambuc         error = read_reason(input, reason_start, reason, reason_size);
31311be35a1SLionel Sambuc     } else {
31411be35a1SLionel Sambuc         if (reason_start != NULL || !is_really_eof(input)) {
31511be35a1SLionel Sambuc             error = kyua_generic_error_new("Found unexpected reason in passed "
31611be35a1SLionel Sambuc                                            "test result");
31711be35a1SLionel Sambuc             goto out_input;
31811be35a1SLionel Sambuc         }
31911be35a1SLionel Sambuc         reason[0] = '\0';
32011be35a1SLionel Sambuc     }
32111be35a1SLionel Sambuc 
32211be35a1SLionel Sambuc out_input:
32311be35a1SLionel Sambuc     fclose(input);
32411be35a1SLionel Sambuc out:
32511be35a1SLionel Sambuc     return error;
32611be35a1SLionel Sambuc }
32711be35a1SLionel Sambuc 
32811be35a1SLionel Sambuc 
32911be35a1SLionel Sambuc /// Writes a generic result file for an ATF broken result.
33011be35a1SLionel Sambuc ///
33111be35a1SLionel Sambuc /// \param reason Textual explanation of the result.
33211be35a1SLionel Sambuc /// \param status Exit code of the test program as returned by wait().
33311be35a1SLionel Sambuc /// \param output Path to the generic result file to create.
33411be35a1SLionel Sambuc /// \param [out] success Whether the result should be considered a success or
33511be35a1SLionel Sambuc ///     not; e.g. passed and skipped are successful, but failed is not.
33611be35a1SLionel Sambuc ///
33711be35a1SLionel Sambuc /// \return An error if the conversion fails; OK otherwise.
33811be35a1SLionel Sambuc static kyua_error_t
convert_broken(const char * reason,int status,const char * output,bool * success)33911be35a1SLionel Sambuc convert_broken(const char* reason, int status, const char* output,
34011be35a1SLionel Sambuc                bool* success)
34111be35a1SLionel Sambuc {
34211be35a1SLionel Sambuc     if (WIFEXITED(status)) {
34311be35a1SLionel Sambuc         *success = false;
34411be35a1SLionel Sambuc         return kyua_result_write(
34511be35a1SLionel Sambuc             output, KYUA_RESULT_BROKEN, "%s; test case exited with code %d",
34611be35a1SLionel Sambuc             reason, WEXITSTATUS(status));
34711be35a1SLionel Sambuc     } else {
34811be35a1SLionel Sambuc         assert(WIFSIGNALED(status));
34911be35a1SLionel Sambuc         *success = false;
35011be35a1SLionel Sambuc         return kyua_result_write(
35111be35a1SLionel Sambuc             output, KYUA_RESULT_BROKEN, "%s; test case received signal %d%s",
35211be35a1SLionel Sambuc             reason, WTERMSIG(status),
35311be35a1SLionel Sambuc             WCOREDUMP(status) ? " (core dumped)" : "");
35411be35a1SLionel Sambuc     }
35511be35a1SLionel Sambuc }
35611be35a1SLionel Sambuc 
35711be35a1SLionel Sambuc 
35811be35a1SLionel Sambuc /// Writes a generic result file for an ATF expected_death result.
35911be35a1SLionel Sambuc ///
36011be35a1SLionel Sambuc /// \param reason Textual explanation of the result.
36111be35a1SLionel Sambuc /// \param status Exit code of the test program as returned by wait().
36211be35a1SLionel Sambuc /// \param output Path to the generic result file to create.
36311be35a1SLionel Sambuc /// \param [out] success Whether the result should be considered a success or
36411be35a1SLionel Sambuc ///     not; e.g. passed and skipped are successful, but failed is not.
36511be35a1SLionel Sambuc ///
36611be35a1SLionel Sambuc /// \return An error if the conversion fails; OK otherwise.
36711be35a1SLionel Sambuc static kyua_error_t
convert_expected_death(const char * reason,int status,const char * output,bool * success)36811be35a1SLionel Sambuc convert_expected_death(const char* reason, int status, const char* output,
36911be35a1SLionel Sambuc                        bool* success)
37011be35a1SLionel Sambuc {
37111be35a1SLionel Sambuc     if (WIFEXITED(status) && WEXITSTATUS(status) == EXIT_SUCCESS) {
37211be35a1SLionel Sambuc         *success = false;
37311be35a1SLionel Sambuc         return kyua_result_write(
37411be35a1SLionel Sambuc             output, KYUA_RESULT_FAILED, "Test case expected to die but exited "
37511be35a1SLionel Sambuc             "successfully");
37611be35a1SLionel Sambuc     } else {
37711be35a1SLionel Sambuc         *success = true;
37811be35a1SLionel Sambuc         return kyua_result_write(
37911be35a1SLionel Sambuc             output, KYUA_RESULT_EXPECTED_FAILURE, "%s", reason);
38011be35a1SLionel Sambuc     }
38111be35a1SLionel Sambuc }
38211be35a1SLionel Sambuc 
38311be35a1SLionel Sambuc 
38411be35a1SLionel Sambuc /// Writes a generic result file for an ATF expected_exit result
38511be35a1SLionel Sambuc ///
38611be35a1SLionel Sambuc /// \param status_arg Optional integral argument to the status.
38711be35a1SLionel Sambuc /// \param reason Textual explanation of the result.
38811be35a1SLionel Sambuc /// \param status Exit code of the test program as returned by wait().
38911be35a1SLionel Sambuc /// \param output Path to the generic result file to create.
39011be35a1SLionel Sambuc /// \param [out] success Whether the result should be considered a success or
39111be35a1SLionel Sambuc ///     not; e.g. passed and skipped are successful, but failed is not.
39211be35a1SLionel Sambuc ///
39311be35a1SLionel Sambuc /// \return An error if the conversion fails; OK otherwise.
39411be35a1SLionel Sambuc static kyua_error_t
convert_expected_exit(const int status_arg,const char * reason,int status,const char * output,bool * success)39511be35a1SLionel Sambuc convert_expected_exit(const int status_arg, const char* reason, int status,
39611be35a1SLionel Sambuc                       const char* output, bool* success)
39711be35a1SLionel Sambuc {
39811be35a1SLionel Sambuc     if (WIFEXITED(status)) {
39911be35a1SLionel Sambuc         if (status_arg == NO_STATUS_ARG || status_arg == WEXITSTATUS(status)) {
40011be35a1SLionel Sambuc             *success = true;
40111be35a1SLionel Sambuc             return kyua_result_write(
40211be35a1SLionel Sambuc                 output, KYUA_RESULT_EXPECTED_FAILURE, "%s", reason);
40311be35a1SLionel Sambuc         } else {
40411be35a1SLionel Sambuc             *success = false;
40511be35a1SLionel Sambuc             return kyua_result_write(
40611be35a1SLionel Sambuc                 output, KYUA_RESULT_FAILED, "Test case expected to exit with "
40711be35a1SLionel Sambuc                 "code %d but got code %d", status_arg, WEXITSTATUS(status));
40811be35a1SLionel Sambuc         }
40911be35a1SLionel Sambuc     } else {
41011be35a1SLionel Sambuc         assert(WIFSIGNALED(status));
41111be35a1SLionel Sambuc         *success = false;
41211be35a1SLionel Sambuc         return kyua_result_write(
41311be35a1SLionel Sambuc             output, KYUA_RESULT_FAILED, "Test case expected to exit normally "
41411be35a1SLionel Sambuc             "but received signal %d%s", WTERMSIG(status),
41511be35a1SLionel Sambuc             WCOREDUMP(status) ? " (core dumped)" : "");
41611be35a1SLionel Sambuc     }
41711be35a1SLionel Sambuc }
41811be35a1SLionel Sambuc 
41911be35a1SLionel Sambuc 
42011be35a1SLionel Sambuc /// Writes a generic result file for an ATF expected_failure result.
42111be35a1SLionel Sambuc ///
42211be35a1SLionel Sambuc /// \param reason Textual explanation of the result.
42311be35a1SLionel Sambuc /// \param status Exit code of the test program as returned by wait().
42411be35a1SLionel Sambuc /// \param output Path to the generic result file to create.
42511be35a1SLionel Sambuc /// \param [out] success Whether the result should be considered a success or
42611be35a1SLionel Sambuc ///     not; e.g. passed and skipped are successful, but failed is not.
42711be35a1SLionel Sambuc ///
42811be35a1SLionel Sambuc /// \return An error if the conversion fails; OK otherwise.
42911be35a1SLionel Sambuc static kyua_error_t
convert_expected_failure(const char * reason,int status,const char * output,bool * success)43011be35a1SLionel Sambuc convert_expected_failure(const char* reason, int status, const char* output,
43111be35a1SLionel Sambuc                          bool* success)
43211be35a1SLionel Sambuc {
43311be35a1SLionel Sambuc     if (WIFEXITED(status)) {
43411be35a1SLionel Sambuc         if (WEXITSTATUS(status) == EXIT_SUCCESS) {
43511be35a1SLionel Sambuc             *success = true;
43611be35a1SLionel Sambuc             return kyua_result_write(
43711be35a1SLionel Sambuc                 output, KYUA_RESULT_EXPECTED_FAILURE, "%s", reason);
43811be35a1SLionel Sambuc         } else {
43911be35a1SLionel Sambuc             *success = false;
44011be35a1SLionel Sambuc             return kyua_result_write(
44111be35a1SLionel Sambuc                 output, KYUA_RESULT_FAILED, "Test case expected a failure but "
44211be35a1SLionel Sambuc                 "exited with error code %d", WEXITSTATUS(status));
44311be35a1SLionel Sambuc         }
44411be35a1SLionel Sambuc     } else {
44511be35a1SLionel Sambuc         assert(WIFSIGNALED(status));
44611be35a1SLionel Sambuc         *success = false;
44711be35a1SLionel Sambuc         return kyua_result_write(
44811be35a1SLionel Sambuc             output, KYUA_RESULT_FAILED, "Test case expected a failure but "
44911be35a1SLionel Sambuc             "received signal %d%s", WTERMSIG(status),
45011be35a1SLionel Sambuc             WCOREDUMP(status) ? " (core dumped)" : "");
45111be35a1SLionel Sambuc     }
45211be35a1SLionel Sambuc }
45311be35a1SLionel Sambuc 
45411be35a1SLionel Sambuc 
45511be35a1SLionel Sambuc /// Writes a generic result file for an ATF expected_signal result.
45611be35a1SLionel Sambuc ///
45711be35a1SLionel Sambuc /// \param status_arg Optional integral argument to the status.
45811be35a1SLionel Sambuc /// \param reason Textual explanation of the result.
45911be35a1SLionel Sambuc /// \param status Exit code of the test program as returned by wait().
46011be35a1SLionel Sambuc /// \param output Path to the generic result file to create.
46111be35a1SLionel Sambuc /// \param [out] success Whether the result should be considered a success or
46211be35a1SLionel Sambuc ///     not; e.g. passed and skipped are successful, but failed is not.
46311be35a1SLionel Sambuc ///
46411be35a1SLionel Sambuc /// \return An error if the conversion fails; OK otherwise.
46511be35a1SLionel Sambuc static kyua_error_t
convert_expected_signal(const int status_arg,const char * reason,int status,const char * output,bool * success)46611be35a1SLionel Sambuc convert_expected_signal(const int status_arg, const char* reason, int status,
46711be35a1SLionel Sambuc                         const char* output, bool* success)
46811be35a1SLionel Sambuc {
46911be35a1SLionel Sambuc     if (WIFSIGNALED(status)) {
47011be35a1SLionel Sambuc         if (status_arg == NO_STATUS_ARG || status_arg == WTERMSIG(status)) {
47111be35a1SLionel Sambuc             *success = true;
47211be35a1SLionel Sambuc             return kyua_result_write(
47311be35a1SLionel Sambuc                 output, KYUA_RESULT_EXPECTED_FAILURE, "%s", reason);
47411be35a1SLionel Sambuc         } else {
47511be35a1SLionel Sambuc             *success = false;
47611be35a1SLionel Sambuc             return kyua_result_write(
47711be35a1SLionel Sambuc                 output, KYUA_RESULT_FAILED, "Test case expected to receive "
47811be35a1SLionel Sambuc                 "signal %d but got %d", status_arg, WTERMSIG(status));
47911be35a1SLionel Sambuc         }
48011be35a1SLionel Sambuc     } else {
48111be35a1SLionel Sambuc         assert(WIFEXITED(status));
48211be35a1SLionel Sambuc         *success = false;
48311be35a1SLionel Sambuc         return kyua_result_write(
48411be35a1SLionel Sambuc             output, KYUA_RESULT_FAILED, "Test case expected to receive a "
48511be35a1SLionel Sambuc             "signal but exited with code %d", WEXITSTATUS(status));
48611be35a1SLionel Sambuc     }
48711be35a1SLionel Sambuc }
48811be35a1SLionel Sambuc 
48911be35a1SLionel Sambuc 
49011be35a1SLionel Sambuc /// Writes a generic result file for an ATF expected_timeout result.
49111be35a1SLionel Sambuc ///
49211be35a1SLionel Sambuc /// \param status Exit code of the test program as returned by wait().
49311be35a1SLionel Sambuc /// \param output Path to the generic result file to create.
49411be35a1SLionel Sambuc /// \param [out] success Whether the result should be considered a success or
49511be35a1SLionel Sambuc ///     not; e.g. passed and skipped are successful, but failed is not.
49611be35a1SLionel Sambuc ///
49711be35a1SLionel Sambuc /// \return An error if the conversion fails; OK otherwise.
49811be35a1SLionel Sambuc static kyua_error_t
convert_expected_timeout(int status,const char * output,bool * success)49911be35a1SLionel Sambuc convert_expected_timeout(int status, const char* output, bool* success)
50011be35a1SLionel Sambuc {
50111be35a1SLionel Sambuc     if (WIFEXITED(status)) {
50211be35a1SLionel Sambuc         *success = false;
50311be35a1SLionel Sambuc         return kyua_result_write(
50411be35a1SLionel Sambuc             output, KYUA_RESULT_FAILED, "Test case expected to time out but "
50511be35a1SLionel Sambuc             "exited with code %d", WEXITSTATUS(status));
50611be35a1SLionel Sambuc     } else {
50711be35a1SLionel Sambuc         assert(WIFSIGNALED(status));
50811be35a1SLionel Sambuc         *success = false;
50911be35a1SLionel Sambuc         return kyua_result_write(
51011be35a1SLionel Sambuc             output, KYUA_RESULT_FAILED, "Test case expected to time out but "
51111be35a1SLionel Sambuc             "received signal %d%s", WTERMSIG(status),
51211be35a1SLionel Sambuc             WCOREDUMP(status) ? " (core dumped)" : "");
51311be35a1SLionel Sambuc     }
51411be35a1SLionel Sambuc }
51511be35a1SLionel Sambuc 
51611be35a1SLionel Sambuc 
51711be35a1SLionel Sambuc /// Writes a generic result file for an ATF failed result.
51811be35a1SLionel Sambuc ///
51911be35a1SLionel Sambuc /// \param reason Textual explanation of the result.
52011be35a1SLionel Sambuc /// \param status Exit code of the test program as returned by wait().
52111be35a1SLionel Sambuc /// \param output Path to the generic result file to create.
52211be35a1SLionel Sambuc /// \param [out] success Whether the result should be considered a success or
52311be35a1SLionel Sambuc ///     not; e.g. passed and skipped are successful, but failed is not.
52411be35a1SLionel Sambuc ///
52511be35a1SLionel Sambuc /// \return An error if the conversion fails; OK otherwise.
52611be35a1SLionel Sambuc static kyua_error_t
convert_failed(const char * reason,int status,const char * output,bool * success)52711be35a1SLionel Sambuc convert_failed(const char* reason, int status, const char* output,
52811be35a1SLionel Sambuc                bool* success)
52911be35a1SLionel Sambuc {
53011be35a1SLionel Sambuc     if (WIFEXITED(status)) {
53111be35a1SLionel Sambuc         if (WEXITSTATUS(status) == EXIT_SUCCESS) {
53211be35a1SLionel Sambuc             *success = false;
53311be35a1SLionel Sambuc             return kyua_result_write(
53411be35a1SLionel Sambuc                 output, KYUA_RESULT_BROKEN, "Test case reported a failed "
53511be35a1SLionel Sambuc                 "result but exited with a successful exit code");
53611be35a1SLionel Sambuc         } else {
53711be35a1SLionel Sambuc             *success = false;
53811be35a1SLionel Sambuc             return kyua_result_write(
53911be35a1SLionel Sambuc                 output, KYUA_RESULT_FAILED, "%s", reason);
54011be35a1SLionel Sambuc         }
54111be35a1SLionel Sambuc     } else {
54211be35a1SLionel Sambuc         assert(WIFSIGNALED(status));
54311be35a1SLionel Sambuc         *success = false;
54411be35a1SLionel Sambuc         return kyua_result_write(
54511be35a1SLionel Sambuc             output, KYUA_RESULT_BROKEN, "Test case reported a failed result "
54611be35a1SLionel Sambuc             "but received signal %d%s", WTERMSIG(status),
54711be35a1SLionel Sambuc             WCOREDUMP(status) ? " (core dumped)" : "");
54811be35a1SLionel Sambuc     }
54911be35a1SLionel Sambuc }
55011be35a1SLionel Sambuc 
55111be35a1SLionel Sambuc 
55211be35a1SLionel Sambuc /// Writes a generic result file for an ATF passed result.
55311be35a1SLionel Sambuc ///
55411be35a1SLionel Sambuc /// \param status Exit code of the test program as returned by wait().
55511be35a1SLionel Sambuc /// \param output Path to the generic result file to create.
55611be35a1SLionel Sambuc /// \param [out] success Whether the result should be considered a success or
55711be35a1SLionel Sambuc ///     not; e.g. passed and skipped are successful, but failed is not.
55811be35a1SLionel Sambuc ///
55911be35a1SLionel Sambuc /// \return An error if the conversion fails; OK otherwise.
56011be35a1SLionel Sambuc static kyua_error_t
convert_passed(int status,const char * output,bool * success)56111be35a1SLionel Sambuc convert_passed(int status, const char* output, bool* success)
56211be35a1SLionel Sambuc {
56311be35a1SLionel Sambuc     if (WIFEXITED(status)) {
56411be35a1SLionel Sambuc         if (WEXITSTATUS(status) == EXIT_SUCCESS) {
56511be35a1SLionel Sambuc             *success = true;
56611be35a1SLionel Sambuc             return kyua_result_write(output, KYUA_RESULT_PASSED, NULL);
56711be35a1SLionel Sambuc         } else {
56811be35a1SLionel Sambuc             *success = false;
56911be35a1SLionel Sambuc             return kyua_result_write(
57011be35a1SLionel Sambuc                 output, KYUA_RESULT_BROKEN, "Test case reported a passed "
57111be35a1SLionel Sambuc                 "result but returned a non-zero exit code %d",
57211be35a1SLionel Sambuc                 WEXITSTATUS(status));
57311be35a1SLionel Sambuc         }
57411be35a1SLionel Sambuc     } else {
57511be35a1SLionel Sambuc         assert(WIFSIGNALED(status));
57611be35a1SLionel Sambuc         *success = false;
57711be35a1SLionel Sambuc         return kyua_result_write(
57811be35a1SLionel Sambuc             output, KYUA_RESULT_BROKEN, "Test case reported a passed result "
57911be35a1SLionel Sambuc             "but received signal %d%s", WTERMSIG(status),
58011be35a1SLionel Sambuc             WCOREDUMP(status) ? " (core dumped)" : "");
58111be35a1SLionel Sambuc     }
58211be35a1SLionel Sambuc }
58311be35a1SLionel Sambuc 
58411be35a1SLionel Sambuc 
58511be35a1SLionel Sambuc /// Writes a generic result file for an ATF skipped result.
58611be35a1SLionel Sambuc ///
58711be35a1SLionel Sambuc /// \param reason Textual explanation of the result.
58811be35a1SLionel Sambuc /// \param status Exit code of the test program as returned by wait().
58911be35a1SLionel Sambuc /// \param output Path to the generic result file to create.
59011be35a1SLionel Sambuc /// \param [out] success Whether the result should be considered a success or
59111be35a1SLionel Sambuc ///     not; e.g. passed and skipped are successful, but failed is not.
59211be35a1SLionel Sambuc ///
59311be35a1SLionel Sambuc /// \return An error if the conversion fails; OK otherwise.
59411be35a1SLionel Sambuc static kyua_error_t
convert_skipped(const char * reason,int status,const char * output,bool * success)59511be35a1SLionel Sambuc convert_skipped(const char* reason, int status, const char* output,
59611be35a1SLionel Sambuc                 bool* success)
59711be35a1SLionel Sambuc {
59811be35a1SLionel Sambuc     if (WIFEXITED(status)) {
59911be35a1SLionel Sambuc         if (WEXITSTATUS(status) == EXIT_SUCCESS) {
60011be35a1SLionel Sambuc             *success = true;
60111be35a1SLionel Sambuc             return kyua_result_write(output, KYUA_RESULT_SKIPPED, "%s", reason);
60211be35a1SLionel Sambuc         } else {
60311be35a1SLionel Sambuc             *success = false;
60411be35a1SLionel Sambuc             return kyua_result_write(
60511be35a1SLionel Sambuc                 output, KYUA_RESULT_BROKEN, "Test case reported a skipped "
60611be35a1SLionel Sambuc                 "result but returned a non-zero exit code %d",
60711be35a1SLionel Sambuc                 WEXITSTATUS(status));
60811be35a1SLionel Sambuc         }
60911be35a1SLionel Sambuc     } else {
61011be35a1SLionel Sambuc         *success = false;
61111be35a1SLionel Sambuc         assert(WIFSIGNALED(status));
61211be35a1SLionel Sambuc         return kyua_result_write(
61311be35a1SLionel Sambuc             output, KYUA_RESULT_BROKEN, "Test case reported a skipped result "
61411be35a1SLionel Sambuc             "but received signal %d%s", WTERMSIG(status),
61511be35a1SLionel Sambuc             WCOREDUMP(status) ? " (core dumped)" : "");
61611be35a1SLionel Sambuc     }
61711be35a1SLionel Sambuc }
61811be35a1SLionel Sambuc 
61911be35a1SLionel Sambuc 
62011be35a1SLionel Sambuc /// Writes a generic result file based on an ATF result and an exit code.
62111be35a1SLionel Sambuc ///
62211be35a1SLionel Sambuc /// \param status Type of the ATF result.
62311be35a1SLionel Sambuc /// \param status_arg Optional integral argument to the status.
62411be35a1SLionel Sambuc /// \param reason Textual explanation of the result.
62511be35a1SLionel Sambuc /// \param wait_status Exit code of the test program as returned by wait().
62611be35a1SLionel Sambuc /// \param timed_out Whether the test program timed out or not.
62711be35a1SLionel Sambuc /// \param output Path to the generic result file to create.
62811be35a1SLionel Sambuc /// \param [out] success Whether the result should be considered a success or
62911be35a1SLionel Sambuc ///     not; e.g. passed and skipped are successful, but failed is not.
63011be35a1SLionel Sambuc ///
63111be35a1SLionel Sambuc /// \return An error if the conversion fails; OK otherwise.
63211be35a1SLionel Sambuc static kyua_error_t
convert_result(const enum atf_status status,const int status_arg,const char * reason,const int wait_status,const bool timed_out,const char * output,bool * success)63311be35a1SLionel Sambuc convert_result(const enum atf_status status, const int status_arg,
63411be35a1SLionel Sambuc                const char* reason, const int wait_status, const bool timed_out,
63511be35a1SLionel Sambuc                const char* output, bool* success)
63611be35a1SLionel Sambuc {
63711be35a1SLionel Sambuc     if (timed_out) {
63811be35a1SLionel Sambuc         if (status == ATF_STATUS_EXPECTED_TIMEOUT) {
63911be35a1SLionel Sambuc             *success = true;
64011be35a1SLionel Sambuc             return kyua_result_write(
64111be35a1SLionel Sambuc                 output, KYUA_RESULT_EXPECTED_FAILURE, "%s", reason);
64211be35a1SLionel Sambuc         } else {
64311be35a1SLionel Sambuc             assert(status == ATF_STATUS_BROKEN);
64411be35a1SLionel Sambuc             *success = false;
64511be35a1SLionel Sambuc             return kyua_result_write(
64611be35a1SLionel Sambuc                 output, KYUA_RESULT_BROKEN, "Test case body timed out");
64711be35a1SLionel Sambuc         }
64811be35a1SLionel Sambuc     }
64911be35a1SLionel Sambuc 
65011be35a1SLionel Sambuc     switch (status) {
65111be35a1SLionel Sambuc     case ATF_STATUS_BROKEN:
65211be35a1SLionel Sambuc         return convert_broken(reason, wait_status, output, success);
65311be35a1SLionel Sambuc 
65411be35a1SLionel Sambuc     case ATF_STATUS_EXPECTED_DEATH:
65511be35a1SLionel Sambuc         return convert_expected_death(reason, wait_status, output, success);
65611be35a1SLionel Sambuc 
65711be35a1SLionel Sambuc     case ATF_STATUS_EXPECTED_EXIT:
65811be35a1SLionel Sambuc         return convert_expected_exit(status_arg, reason, wait_status, output,
65911be35a1SLionel Sambuc                                      success);
66011be35a1SLionel Sambuc 
66111be35a1SLionel Sambuc     case ATF_STATUS_EXPECTED_FAILURE:
66211be35a1SLionel Sambuc         return convert_expected_failure(reason, wait_status, output, success);
66311be35a1SLionel Sambuc 
66411be35a1SLionel Sambuc     case ATF_STATUS_EXPECTED_SIGNAL:
66511be35a1SLionel Sambuc         return convert_expected_signal(status_arg, reason, wait_status, output,
66611be35a1SLionel Sambuc                                        success);
66711be35a1SLionel Sambuc 
66811be35a1SLionel Sambuc     case ATF_STATUS_EXPECTED_TIMEOUT:
66911be35a1SLionel Sambuc         return convert_expected_timeout(wait_status, output, success);
67011be35a1SLionel Sambuc 
67111be35a1SLionel Sambuc     case ATF_STATUS_FAILED:
67211be35a1SLionel Sambuc         return convert_failed(reason, wait_status, output, success);
67311be35a1SLionel Sambuc 
67411be35a1SLionel Sambuc     case ATF_STATUS_PASSED:
67511be35a1SLionel Sambuc         return convert_passed(wait_status, output, success);
67611be35a1SLionel Sambuc 
67711be35a1SLionel Sambuc     case ATF_STATUS_SKIPPED:
67811be35a1SLionel Sambuc         return convert_skipped(reason, wait_status, output, success);
67911be35a1SLionel Sambuc     }
68011be35a1SLionel Sambuc 
68111be35a1SLionel Sambuc     assert(false);
682*3260d16fSLionel Sambuc #if defined(__minix) && defined(NDEBUG)
683*3260d16fSLionel Sambuc     abort();
684*3260d16fSLionel Sambuc #endif /* defined(__minix) && !defined(NDEBUG) */
68511be35a1SLionel Sambuc }
68611be35a1SLionel Sambuc 
68711be35a1SLionel Sambuc 
68811be35a1SLionel Sambuc /// Writes a generic result file based on an ATF result file and an exit code.
68911be35a1SLionel Sambuc ///
69011be35a1SLionel Sambuc /// \param input_name Path to the ATF result file to parse.
69111be35a1SLionel Sambuc /// \param output_name Path to the generic result file to create.
69211be35a1SLionel Sambuc /// \param wait_status Exit code of the test program as returned by wait().
69311be35a1SLionel Sambuc /// \param timed_out Whether the test program timed out or not.
69411be35a1SLionel Sambuc /// \param [out] success Whether the result should be considered a success or
69511be35a1SLionel Sambuc ///     not; e.g. passed and skipped are successful, but failed is not.
69611be35a1SLionel Sambuc ///
69711be35a1SLionel Sambuc /// \return An error if the conversion fails; OK otherwise.
69811be35a1SLionel Sambuc kyua_error_t
kyua_atf_result_rewrite(const char * input_name,const char * output_name,const int wait_status,const bool timed_out,bool * success)69911be35a1SLionel Sambuc kyua_atf_result_rewrite(const char* input_name, const char* output_name,
70011be35a1SLionel Sambuc                         const int wait_status, const bool timed_out,
70111be35a1SLionel Sambuc                         bool* success)
70211be35a1SLionel Sambuc {
70311be35a1SLionel Sambuc     enum atf_status status; int status_arg; char reason[1024];
70411be35a1SLionel Sambuc     status = ATF_STATUS_BROKEN;  // Initialize to shut up gcc warning.
70511be35a1SLionel Sambuc     const kyua_error_t error = read_atf_result(input_name, &status, &status_arg,
70611be35a1SLionel Sambuc                                                reason, sizeof(reason));
70711be35a1SLionel Sambuc     if (kyua_error_is_set(error)) {
70811be35a1SLionel Sambuc         // Errors while parsing the ATF result file can often be attributed to
70911be35a1SLionel Sambuc         // the result file being bogus.  Therefore, just mark the test case as
71011be35a1SLionel Sambuc         // broken, because it possibly is.
71111be35a1SLionel Sambuc         status = ATF_STATUS_BROKEN;
71211be35a1SLionel Sambuc         kyua_error_format(error, reason, sizeof(reason));
71311be35a1SLionel Sambuc         kyua_error_free(error);
71411be35a1SLionel Sambuc     }
71511be35a1SLionel Sambuc 
71611be35a1SLionel Sambuc     // Errors converting the loaded result to the final result file are not due
71711be35a1SLionel Sambuc     // to a bad test program: they are because our own code fails (e.g. cannot
71811be35a1SLionel Sambuc     // create the output file).  These need to be returned to the caller.
71911be35a1SLionel Sambuc     return convert_result(status, status_arg, reason, wait_status, timed_out,
72011be35a1SLionel Sambuc                           output_name, success);
72111be35a1SLionel Sambuc }
72211be35a1SLionel Sambuc 
72311be35a1SLionel Sambuc 
72411be35a1SLionel Sambuc /// Creates a result file for a failed cleanup routine.
72511be35a1SLionel Sambuc ///
72611be35a1SLionel Sambuc /// This function is supposed to be invoked after the body has had a chance to
72711be35a1SLionel Sambuc /// create its own result file, and only if the body has terminated with a
72811be35a1SLionel Sambuc /// non-failure result.
72911be35a1SLionel Sambuc ///
73011be35a1SLionel Sambuc /// \param output_name Path to the generic result file to create.
73111be35a1SLionel Sambuc /// \param wait_status Exit code of the test program as returned by wait().
73211be35a1SLionel Sambuc /// \param timed_out Whether the test program timed out or not.
73311be35a1SLionel Sambuc /// \param [out] success Whether the result should be considered a success or
73411be35a1SLionel Sambuc ///     not; i.e. a clean exit is successful, but anything else is a failure.
73511be35a1SLionel Sambuc ///
73611be35a1SLionel Sambuc /// \return An error if there is a problem writing the result; OK otherwise.
73711be35a1SLionel Sambuc kyua_error_t
kyua_atf_result_cleanup_rewrite(const char * output_name,int wait_status,const bool timed_out,bool * success)73811be35a1SLionel Sambuc kyua_atf_result_cleanup_rewrite(const char* output_name, int wait_status,
73911be35a1SLionel Sambuc                                 const bool timed_out, bool* success)
74011be35a1SLionel Sambuc {
74111be35a1SLionel Sambuc     if (timed_out) {
74211be35a1SLionel Sambuc         *success = false;
74311be35a1SLionel Sambuc         return kyua_result_write(
74411be35a1SLionel Sambuc             output_name, KYUA_RESULT_BROKEN, "Test case cleanup timed out");
74511be35a1SLionel Sambuc     } else {
74611be35a1SLionel Sambuc         if (WIFEXITED(wait_status)) {
74711be35a1SLionel Sambuc             if (WEXITSTATUS(wait_status) == EXIT_SUCCESS) {
74811be35a1SLionel Sambuc                 *success = true;
74911be35a1SLionel Sambuc                 // Reuse the result file created by the body.  I.e. avoid
75011be35a1SLionel Sambuc                 // creating a new file here.
75111be35a1SLionel Sambuc                 return kyua_error_ok();
75211be35a1SLionel Sambuc             } else {
75311be35a1SLionel Sambuc                 *success = false;
75411be35a1SLionel Sambuc                 return kyua_result_write(
75511be35a1SLionel Sambuc                     output_name, KYUA_RESULT_BROKEN, "Test case cleanup exited "
75611be35a1SLionel Sambuc                     "with code %d", WEXITSTATUS(wait_status));
75711be35a1SLionel Sambuc             }
75811be35a1SLionel Sambuc         } else {
75911be35a1SLionel Sambuc             *success = false;
76011be35a1SLionel Sambuc             return kyua_result_write(
76111be35a1SLionel Sambuc                 output_name, KYUA_RESULT_BROKEN, "Test case cleanup received "
76211be35a1SLionel Sambuc                 "signal %d%s", WTERMSIG(wait_status),
76311be35a1SLionel Sambuc                 WCOREDUMP(wait_status) ? " (core dumped)" : "");
76411be35a1SLionel Sambuc         }
76511be35a1SLionel Sambuc     }
76611be35a1SLionel Sambuc }
767