File: test.h

package info (click to toggle)
pdfio 1.6.2%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 10,112 kB
  • sloc: ansic: 23,127; sh: 3,774; makefile: 237
file content (282 lines) | stat: -rw-r--r-- 7,306 bytes parent folder | download | duplicates (2)
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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
//
// Unit test header for C/C++ programs.
//
// Copyright © 2021-2025 by Michael R Sweet.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// 1. Redistributions of source code must retain the above copyright notice,
//    this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright notice,
//    this list of conditions and the following disclaimer in the documentation
//    and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//

#ifndef TEST_H
#  define TEST_H
#  include <stdio.h>
#  include <stdlib.h>
#  include <stdarg.h>
#  include <stdbool.h>
#  include <string.h>
#  if _WIN32
#    include <io.h>
#    define isatty(f) _isatty(f)
#  else
#    include <unistd.h>
#  endif // !_WIN32
#  ifdef __cplusplus
extern "C" {
#  endif // __cplusplus


//
// This header implements a simple unit test framework for C/C++ programs.
// Inline functions are provided to write a test summary to stdout and the
// details to stderr.  This allows unit test programs to output a summary to
// stdout with details sent to stderr, e.g.:
//
//     mytestprogram 2>test.log
//
// Documentation:
//
// void testBegin(const char *title, ...)
//
//     Start a test with a printf-style title message.  "Title:" (the formatted
//     title followed by a colon) is output.
//
// void testEnd(bool pass)
//
//     End a test without an additional message.  "pass" should be `true` if the
//     test passed and `false` otherwise.  "PASS" or "FAIL" is output.
//
// void testEndMessage(bool pass, const char *message, ...)
//
//     End a test with an additional printf-style message.  "pass" should be
//     `true` if the test passed and `false` otherwise.  "PASS (message)" or
//     "FAIL (message)" is output.
//
// testError(const char *error, ...)
//
//     Sends a formatted error string to stderr.
//
// testHexDump(const unsigned char *buffer, size_t bytes)
//
//     Sends a hex dump of the specified buffer to stderr.
//
// testMessage(const char *error, ...)
//
//     Outputs a formatted message string.
//
// testProgress(void)
//
//     Shows a progress spinner for long-running tests.
//
// bool testsPassed
//
//     This global variable specifies whether all tests have passed (`true`)
//     or one or more have failed (`false`).
//

static bool testsPassed = true;		// All tests passed?
static int test_progress;		// Current progress
static char test_title[1024] = "";	// Current test title


// Start a test
static inline void
testBegin(const char *title, ...)	// I - printf-style title string
{
  va_list	ap;			// Pointer to additional arguments


  // Format the title string
  va_start(ap, title);
  vsnprintf(test_title, sizeof(test_title), title, ap);
  va_end(ap);

  // Send the title to stdout and stderr...
  test_progress = 0;

  printf("%s: ", test_title);
  fflush(stdout);

  if (!isatty(2))
    fprintf(stderr, "%s: ", test_title);
}


// End a test with no additional information
static inline void
testEnd(bool pass)			// I - `true` if the test passed, `false` otherwise
{
  // Send the test result to stdout and stderr
  if (test_progress)
    putchar('\b');

  if (!pass)
    testsPassed = false;

  puts(pass ? "PASS" : "FAIL");
  if (!isatty(2))
    fputs(pass ? "PASS\n" : "FAIL\n", stderr);

  test_title[0] = '\0';
}


// End a test with no additional information
static inline void
testEndMessage(bool       pass,		// I - `true` if the test passed, `false` otherwise
               const char *message, ...)// I - printf-style message
{
  char		buffer[1024];		// Formatted title string
  va_list	ap;			// Pointer to additional arguments


  // Format the title string
  va_start(ap, message);
  vsnprintf(buffer, sizeof(buffer), message, ap);
  va_end(ap);

  // Send the test result to stdout and stderr
  if (test_progress)
    putchar('\b');

  printf(pass ? "PASS (%s)\n" : "FAIL (%s)\n", buffer);
  if (!isatty(2))
    fprintf(stderr, pass ? "PASS (%s)\n" : "FAIL (%s)\n", buffer);

  test_title[0] = '\0';
}


// Show/update a progress spinner
static inline void
testProgress(void)
{
  if (test_progress)
    putchar('\b');
  putchar("-\\|/"[test_progress & 3]);
  fflush(stdout);

  test_progress ++;
}


// Show an error to stderr...
static inline void
testError(const char *error, ...)	// I - printf-style error string
{
  char		buffer[1024];		// Formatted title string
  va_list	ap;			// Pointer to additional arguments


  // Format the error string
  va_start(ap, error);
  vsnprintf(buffer, sizeof(buffer), error, ap);
  va_end(ap);

  // Send the error to stderr...
  fprintf(stderr, "%s\n", buffer);

  if (test_title[0])
    fprintf(stderr, "%s: ", test_title);
}


// Show a message to stdout and stderr...
static inline void
testMessage(const char *error, ...)	// I - printf-style error string
{
  char		buffer[1024];		// Formatted title string
  va_list	ap;			// Pointer to additional arguments


  // Format the error string
  va_start(ap, error);
  vsnprintf(buffer, sizeof(buffer), error, ap);
  va_end(ap);

  // Send the message to stdout and stderr too if needed...
  printf("%s\n", buffer);
  if (test_title[0])
  {
    printf("%s: ", test_title);
    fflush(stdout);
  }

  if (!isatty(2))
  {
    fprintf(stderr, "%s\n", buffer);

    if (test_title[0])
      fprintf(stderr, "%s: ", test_title);
  }
}


// Show a hex dump of a buffer to stderr...
static inline void
testHexDump(const unsigned char *buffer,// I - Buffer
            size_t              bytes)	// I - Number of bytes
{
  size_t	i, j;			// Looping vars
  int		ch;			// Current ASCII char


  if (test_title[0])
    fputs("\n", stderr);

  // Show lines of 16 bytes at a time...
  for (i = 0; i < bytes; i += 16)
  {
    // Show the offset...
    fprintf(stderr, "%04x ", (unsigned)i);

    // Then up to 16 bytes in hex...
    for (j = 0; j < 16; j ++)
    {
      if ((i + j) < bytes)
        fprintf(stderr, " %02x", buffer[i + j]);
      else
        fputs("   ", stderr);
    }

    // Then the ASCII representation of the bytes...
    fputs("  ", stderr);

    for (j = 0; j < 16 && (i + j) < bytes; j ++)
    {
      ch = buffer[i + j] & 127;

      if (ch < ' ' || ch == 127)
        fputc('.', stderr);
      else
        fputc(ch, stderr);
    }

    fputc('\n', stderr);
  }

  if (test_title[0])
    fprintf(stderr, "%s: ", test_title);
}

#  ifdef __cplusplus
}
#  endif // __cplusplus
#endif // !TEST_H