Coverage Report

Created: 2026-10-28 07:15

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/cups/cups/test-internal.h
Line
Count
Source
1
//
2
// Unit test header for C/C++ programs.
3
//
4
// Copyright © 2021-2026 by Michael R Sweet.
5
//
6
// Redistribution and use in source and binary forms, with or without
7
// modification, are permitted provided that the following conditions are met:
8
//
9
// 1. Redistributions of source code must retain the above copyright notice,
10
//    this list of conditions and the following disclaimer.
11
// 2. Redistributions in binary form must reproduce the above copyright notice,
12
//    this list of conditions and the following disclaimer in the documentation
13
//    and/or other materials provided with the distribution.
14
//
15
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25
// POSSIBILITY OF SUCH DAMAGE.
26
//
27
28
#ifndef TEST_H
29
#  define TEST_H
30
#  include <stdio.h>
31
#  include <stdlib.h>
32
#  include <stdarg.h>
33
#  include <stdbool.h>
34
#  include <string.h>
35
#  if _WIN32
36
#    define isatty(f) _isatty(f)
37
#  elif defined(__ZEPHYR__)
38
#    define isatty(f) 0
39
#  else
40
#    include <unistd.h>
41
#  endif // !_WIN32
42
#  ifdef __cplusplus
43
extern "C" {
44
#  endif // __cplusplus
45
46
47
//
48
// This header implements a simple unit test framework for C/C++ programs.
49
// Inline functions are provided to write a test summary to stdout and the
50
// details to stderr.  This allows unit test programs to output a summary to
51
// stdout with details sent to stderr, e.g.:
52
//
53
//     mytestprogram 2>test.log
54
//
55
// Documentation:
56
//
57
// void testBegin(const char *title, ...)
58
//
59
//     Start a test with a printf-style title message.  "Title:" (the formatted
60
//     title followed by a colon) is output.
61
//
62
// void testEnd(bool pass)
63
//
64
//     End a test without an additional message.  "pass" should be `true` if the
65
//     test passed and `false` otherwise.  "PASS" or "FAIL" is output.
66
//
67
// void testEndMessage(bool pass, const char *message, ...)
68
//
69
//     End a test with an additional printf-style message.  "pass" should be
70
//     `true` if the test passed and `false` otherwise.  "PASS (message)" or
71
//     "FAIL (message)" is output.
72
//
73
// testError(const char *error, ...)
74
//
75
//     Sends a formatted error string to stderr.
76
//
77
// testHexDump(const unsigned char *buffer, size_t bytes)
78
//
79
//     Sends a hex dump of the specified buffer to stderr.
80
//
81
// testMessage(const char *error, ...)
82
//
83
//     Outputs a formatted message string.
84
//
85
// testProgress(void)
86
//
87
//     Shows a progress spinner for long-running tests.
88
//
89
// bool testsPassed
90
//
91
//     This global variable specifies whether all tests have passed (`true`)
92
//     or one or more have failed (`false`).
93
//
94
95
static bool testsPassed = true;   // All tests passed?
96
static int test_progress;   // Current progress
97
static char test_title[1024] = "";  // Current test title
98
99
100
// Write a string to a file, escaping special characters...
101
static inline void
102
test_safe_puts(const char *s,   // I - String to write
103
               FILE       *fp)    // I - Output file
104
0
{
105
0
  while (*s)
106
0
  {
107
0
    if ((*s & 255) < ' ' || *s == 127)
108
0
    {
109
0
      if (*s == '\b')
110
0
        fputs("\\b", fp);
111
0
      else if (*s == '\f')
112
0
        fputs("\\f", fp);
113
0
      else if (*s == '\n')
114
0
        fputs("\\n", fp);
115
0
      else if (*s == '\r')
116
0
        fputs("\\r", fp);
117
0
      else if (*s == '\t')
118
0
        fputs("\\t", fp);
119
0
      else
120
0
        fprintf(fp, "\\%03o", *s & 255);
121
0
    }
122
0
    else if (*s == '\\')
123
0
    {
124
0
      fputs("\\\\", fp);
125
0
    }
126
0
    else
127
0
    {
128
0
      putc(*s, fp);
129
0
    }
130
0
131
0
    s ++;
132
0
  }
133
0
}
134
135
136
// Start a test
137
static inline void
138
testBegin(const char *title, ...) // I - printf-style title string
139
0
{
140
0
  va_list ap;     // Pointer to additional arguments
141
0
142
0
143
0
  // Format the title string
144
0
  va_start(ap, title);
145
0
  vsnprintf(test_title, sizeof(test_title), title, ap);
146
0
  va_end(ap);
147
0
148
0
  // Send the title to stdout and stderr...
149
0
  test_progress = 0;
150
0
151
0
  test_safe_puts(test_title, stdout);
152
0
  fputs(": ", stdout);
153
0
  fflush(stdout);
154
0
155
0
  if (!isatty(2))
156
0
  {
157
0
    test_safe_puts(test_title, stderr);
158
0
    fputs(": ", stderr);
159
0
  }
160
0
}
161
162
163
// End a test with no additional information
164
static inline void
165
testEnd(bool pass)      // I - `true` if the test passed, `false` otherwise
166
0
{
167
0
  // Send the test result to stdout and stderr
168
0
  if (test_progress)
169
0
    putchar('\b');
170
0
171
0
  if (!pass)
172
0
    testsPassed = false;
173
0
174
0
  puts(pass ? "PASS" : "FAIL");
175
0
  if (!isatty(2))
176
0
    fputs(pass ? "PASS\n" : "FAIL\n", stderr);
177
0
178
0
  test_title[0] = '\0';
179
0
}
180
181
182
// End a test with no additional information
183
static inline void
184
testEndMessage(bool       pass,   // I - `true` if the test passed, `false` otherwise
185
               const char *message, ...)// I - printf-style message
186
0
{
187
0
  char    buffer[1024];   // Formatted title string
188
0
  va_list ap;     // Pointer to additional arguments
189
0
190
0
191
0
  // Format the title string
192
0
  va_start(ap, message);
193
0
  vsnprintf(buffer, sizeof(buffer), message, ap);
194
0
  va_end(ap);
195
0
196
0
  // Send the test result to stdout and stderr
197
0
  if (test_progress)
198
0
    putchar('\b');
199
0
200
0
  if (!pass)
201
0
    testsPassed = false;
202
0
203
0
  fputs(pass ? "PASS (" : "FAIL (", stdout);
204
0
  test_safe_puts(buffer, stdout);
205
0
  fputs(")\n", stdout);
206
0
207
0
  if (!isatty(2))
208
0
  {
209
0
    fputs(pass ? "PASS (" : "FAIL (", stderr);
210
0
    test_safe_puts(buffer, stderr);
211
0
    fputs(")\n", stderr);
212
0
  }
213
0
214
0
  test_title[0] = '\0';
215
0
}
216
217
218
// Show/update a progress spinner
219
static inline void
220
testProgress(void)
221
0
{
222
0
  if (test_progress)
223
0
    putchar('\b');
224
0
  putchar("-\\|/"[test_progress & 3]);
225
0
  fflush(stdout);
226
0
227
0
  test_progress ++;
228
0
}
229
230
231
// Show an error to stderr...
232
static inline void
233
testError(const char *error, ...) // I - printf-style error string
234
0
{
235
0
  char    buffer[1024];   // Formatted title string
236
0
  va_list ap;     // Pointer to additional arguments
237
0
238
0
239
0
  // Format the error string
240
0
  va_start(ap, error);
241
0
  vsnprintf(buffer, sizeof(buffer), error, ap);
242
0
  va_end(ap);
243
0
244
0
  // Send the error to stderr...
245
0
  test_safe_puts(buffer, stderr);
246
0
  fputs("\n", stderr);
247
0
248
0
  if (test_title[0])
249
0
  {
250
0
    test_safe_puts(test_title, stderr);
251
0
    fputs(": ", stderr);
252
0
  }
253
0
}
254
255
256
// Show a message to stdout and stderr...
257
static inline void
258
testMessage(const char *error, ...) // I - printf-style error string
259
0
{
260
0
  char    buffer[1024];   // Formatted title string
261
0
  va_list ap;     // Pointer to additional arguments
262
0
263
0
264
0
  // Format the error string
265
0
  va_start(ap, error);
266
0
  vsnprintf(buffer, sizeof(buffer), error, ap);
267
0
  va_end(ap);
268
0
269
0
  // Send the message to stdout and stderr too if needed...
270
0
  test_safe_puts(buffer, stdout);
271
0
  fputs("\n", stdout);
272
0
273
0
  if (test_title[0])
274
0
  {
275
0
    test_safe_puts(test_title, stdout);
276
0
    fputs(": ", stdout);
277
0
  }
278
0
279
0
  if (!isatty(2))
280
0
  {
281
0
    test_safe_puts(buffer, stderr);
282
0
    fputs("\n", stderr);
283
0
284
0
    if (test_title[0])
285
0
    {
286
0
      test_safe_puts(test_title, stderr);
287
0
      fputs(": ", stderr);
288
0
    }
289
0
  }
290
0
}
291
292
293
// Show a hex dump of a buffer to stderr...
294
static inline void
295
testHexDump(const unsigned char *buffer,// I - Buffer
296
            size_t              bytes)  // I - Number of bytes
297
0
{
298
0
  size_t  i, j;     // Looping vars
299
0
  int   ch;     // Current ASCII char
300
0
301
0
302
0
  if (test_title[0])
303
0
    fputs("\n", stderr);
304
0
305
0
  // Show lines of 16 bytes at a time...
306
0
  for (i = 0; i < bytes; i += 16)
307
0
  {
308
0
    // Show the offset...
309
0
    fprintf(stderr, "%04x ", (unsigned)i);
310
0
311
0
    // Then up to 16 bytes in hex...
312
0
    for (j = 0; j < 16; j ++)
313
0
    {
314
0
      if ((i + j) < bytes)
315
0
        fprintf(stderr, " %02x", buffer[i + j]);
316
0
      else
317
0
        fputs("   ", stderr);
318
0
    }
319
0
320
0
    // Then the ASCII representation of the bytes...
321
0
    fputs("  ", stderr);
322
0
323
0
    for (j = 0; j < 16 && (i + j) < bytes; j ++)
324
0
    {
325
0
      ch = buffer[i + j] & 127;
326
0
327
0
      if (ch < ' ' || ch == 127)
328
0
        fputc('.', stderr);
329
0
      else
330
0
        fputc(ch, stderr);
331
0
    }
332
0
333
0
    fputc('\n', stderr);
334
0
  }
335
0
336
0
  if (test_title[0])
337
0
  {
338
0
    test_safe_puts(test_title, stderr);
339
0
    fputs(": ", stderr);
340
0
  }
341
0
}
342
343
#  ifdef __cplusplus
344
}
345
#  endif // __cplusplus
346
#endif // !TEST_H