about summary refs log tree commit diff
path: root/support/check.h
blob: 55a6f09f42a53cf2cbdab3b0540e4bc2c7dc75fe (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
/* Functionality for reporting test results.
   Copyright (C) 2016-2017 Free Software Foundation, Inc.
   This file is part of the GNU C Library.

   The GNU C Library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public
   License as published by the Free Software Foundation; either
   version 2.1 of the License, or (at your option) any later version.

   The GNU C Library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Lesser General Public License for more details.

   You should have received a copy of the GNU Lesser General Public
   License along with the GNU C Library; if not, see
   <http://www.gnu.org/licenses/>.  */

#ifndef SUPPORT_CHECK_H
#define SUPPORT_CHECK_H

#include <sys/cdefs.h>

__BEGIN_DECLS

/* Record a test failure, print the failure message to standard output
   and return 1.  */
#define FAIL_RET(...) \
  return support_print_failure_impl (__FILE__, __LINE__, __VA_ARGS__)

/* Print the failure message and terminate the process with STATUS.
   Record a the process as failed if STATUS is neither EXIT_SUCCESS
   nor EXIT_UNSUPPORTED.  */
#define FAIL_EXIT(status, ...) \
  support_exit_failure_impl (status, __FILE__, __LINE__, __VA_ARGS__)

/* Record a test failure, print the failure message and terminate with
   exit status 1.  */
#define FAIL_EXIT1(...) \
  support_exit_failure_impl (1, __FILE__, __LINE__, __VA_ARGS__)

/* Print failure message and terminate with as unsupported test (exit
   status of 77).  */
#define FAIL_UNSUPPORTED(...) \
  support_exit_failure_impl (77, __FILE__, __LINE__, __VA_ARGS__)

/* Record a test failure (but continue executing) if EXPR evaluates to
   false.  */
#define TEST_VERIFY(expr)                                       \
  ({                                                            \
    if (expr)                                                   \
      ;                                                         \
    else                                                        \
      support_test_verify_impl (__FILE__, __LINE__, #expr);     \
  })

/* Record a test failure and exit if EXPR evaluates to false.  */
#define TEST_VERIFY_EXIT(expr)                                  \
  ({                                                            \
    if (expr)                                                   \
      ;                                                         \
    else                                                        \
      support_test_verify_exit_impl                             \
        (1, __FILE__, __LINE__, #expr);                         \
  })

int support_print_failure_impl (const char *file, int line,
                                const char *format, ...)
  __attribute__ ((nonnull (1), format (printf, 3, 4)));
void support_exit_failure_impl (int exit_status,
                                const char *file, int line,
                                const char *format, ...)
  __attribute__ ((noreturn, nonnull (2), format (printf, 4, 5)));
void support_test_verify_impl (const char *file, int line,
                               const char *expr);
void support_test_verify_exit_impl (int status, const char *file, int line,
                                    const char *expr)
  __attribute__ ((noreturn));

/* Record a test failure.  This function returns and does not
   terminate the process.  The failure counter is stored in a shared
   memory mapping, so that failures reported in child processes are
   visible to the parent process and test driver.  This function
   depends on initialization by an ELF constructor, so it can only be
   invoked after the test driver has run.  Note that this function
   does not support reporting failures from a DSO.  */
void support_record_failure (void);

/* Compare the two integers LEFT and RIGHT and report failure if they
   are different.  */
#define TEST_COMPARE(left, right)                                       \
  ({                                                                    \
    /* + applies the integer promotions, for bitfield support.   */     \
    typedef __typeof__ (+ (left)) __left_type;                          \
    typedef __typeof__ (+ (right)) __right_type;                        \
    __left_type __left_value = (left);                                  \
    __right_type __right_value = (right);                               \
    /* Prevent use with floating-point and boolean types.  */           \
    _Static_assert ((__left_type) 1.0 == (__left_type) 1.5,             \
                    "left value has floating-point type");              \
    _Static_assert ((__right_type) 1.0 == (__right_type) 1.5,           \
                    "right value has floating-point type");             \
    /* Prevent accidental use with larger-than-long long types.  */     \
    _Static_assert (sizeof (__left_value) <= sizeof (long long),        \
                    "left value fits into long long");                  \
    _Static_assert (sizeof (__right_value) <= sizeof (long long),       \
                    "right value fits into long long");                 \
    /* Make sure that integer conversions does not alter the sign.   */ \
    enum                                                                \
    {                                                                   \
      __left_is_unsigned = (__left_type) -1 > 0,                        \
      __right_is_unsigned = (__right_type) -1 > 0,                      \
      __unsigned_left_converts_to_wider = (__left_is_unsigned           \
                                           && (sizeof (__left_value)    \
                                               < sizeof (__right_value))), \
      __unsigned_right_converts_to_wider = (__right_is_unsigned         \
                                            && (sizeof (__right_value)  \
                                                < sizeof (__left_value))) \
    };                                                                  \
    _Static_assert (__left_is_unsigned == __right_is_unsigned           \
                    || __unsigned_left_converts_to_wider                \
                    || __unsigned_right_converts_to_wider,              \
                    "integer conversions may alter sign of operands");  \
    /* Compare the value.  */                                           \
    if (__left_value != __right_value)                                  \
      /* Pass the sign for printing the correct value.  */              \
      support_test_compare_failure                                      \
        (__FILE__, __LINE__,                                            \
         #left, __left_value, __left_value < 0, sizeof (__left_type),   \
         #right, __right_value, __right_value < 0, sizeof (__right_type)); \
  })

/* Internal implementation of TEST_COMPARE.  LEFT_NEGATIVE and
   RIGHT_NEGATIVE are used to store the sign separately, so that both
   unsigned long long and long long arguments fit into LEFT_VALUE and
   RIGHT_VALUE, and the function can still print the original value.
   LEFT_SIZE and RIGHT_SIZE specify the size of the argument in bytes,
   for hexadecimal formatting.  */
void support_test_compare_failure (const char *file, int line,
                                   const char *left_expr,
                                   long long left_value,
                                   int left_negative,
                                   int left_size,
                                   const char *right_expr,
                                   long long right_value,
                                   int right_negative,
                                   int right_size);


/* Internal function called by the test driver.  */
int support_report_failure (int status)
  __attribute__ ((weak, warn_unused_result));

/* Internal function used to test the failure recording framework.  */
void support_record_failure_reset (void);

__END_DECLS

#endif /* SUPPORT_CHECK_H */