Coverage Report

Created: 2026-07-16 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/testsuite/testsuite-log.c
Line
Count
Source
1
/* Copyright (c) Pigeonhole authors, see top-level COPYING file */
2
3
#include "lib.h"
4
#include "str.h"
5
#include "array.h"
6
7
#include "sieve-common.h"
8
#include "sieve-stringlist.h"
9
#include "sieve-error-private.h"
10
11
#include "testsuite-common.h"
12
#include "testsuite-log.h"
13
14
/*
15
 * Configuration
16
 */
17
18
bool _testsuite_log_stdout = FALSE;
19
20
/*
21
 * Testsuite log error handlers
22
 */
23
24
struct sieve_error_handler *testsuite_log_ehandler = NULL;
25
struct sieve_error_handler *testsuite_log_main_ehandler = NULL;
26
27
struct _testsuite_log_message {
28
  const char *location;
29
  const char *message;
30
};
31
32
static pool_t _testsuite_logmsg_pool = NULL;
33
ARRAY(struct _testsuite_log_message) _testsuite_log_errors;
34
ARRAY(struct _testsuite_log_message) _testsuite_log_warnings;
35
ARRAY(struct _testsuite_log_message) _testsuite_log_messages;
36
37
static inline void
38
_testsuite_stdout_log(const struct sieve_error_params *params,
39
          const char *prefix, const char *message)
40
0
{
41
0
  if (_testsuite_log_stdout) {
42
0
    if (params->location == NULL || *params->location == '\0') {
43
0
      fprintf(stdout, "LOG: %s: %s\n",
44
0
        prefix, message);
45
0
    } else {
46
0
      fprintf(stdout, "LOG: %s: %s: %s\n",
47
0
        params->location, prefix, message);
48
0
    }
49
0
  }
50
0
}
51
52
static void
53
_testsuite_log(struct sieve_error_handler *ehandler ATTR_UNUSED,
54
         const struct sieve_error_params *params,
55
         enum sieve_error_flags flags ATTR_UNUSED, const char *message)
56
0
{
57
0
  pool_t pool = _testsuite_logmsg_pool;
58
0
  struct _testsuite_log_message msg;
59
0
  const char *prefix;
60
61
0
  switch (params->log_type) {
62
0
  case LOG_TYPE_ERROR:
63
0
    prefix = "error";
64
0
    break;
65
0
  case LOG_TYPE_WARNING:
66
0
    prefix = "warning";
67
0
    break;
68
0
  case LOG_TYPE_INFO:
69
0
    prefix = "info";
70
0
    break;
71
0
  case LOG_TYPE_DEBUG:
72
0
    prefix = "debug";
73
0
    break;
74
0
  default:
75
0
    i_unreached();
76
0
  }
77
78
0
  _testsuite_stdout_log(params, prefix, message);
79
80
0
  msg.location = p_strdup(pool, params->location);
81
0
  msg.message = p_strdup(pool, message);
82
83
0
  switch (params->log_type) {
84
0
  case LOG_TYPE_ERROR:
85
0
    array_append(&_testsuite_log_errors, &msg, 1);
86
0
    break;
87
0
  case LOG_TYPE_WARNING:
88
0
    array_append(&_testsuite_log_warnings, &msg, 1);
89
0
    break;
90
0
  case LOG_TYPE_INFO:
91
0
    array_append(&_testsuite_log_messages, &msg, 1);
92
0
    break;
93
0
  case LOG_TYPE_DEBUG:
94
0
    break;
95
0
  default:
96
0
    i_unreached();
97
0
  }
98
0
}
99
100
static void
101
_testsuite_main_log(struct sieve_error_handler *ehandler,
102
        const struct sieve_error_params *params,
103
        enum sieve_error_flags flags, const char *message)
104
0
{
105
0
  if (params->log_type != LOG_TYPE_ERROR)
106
0
    return _testsuite_log(ehandler, params, flags, message);
107
108
0
  if (testsuite_silent)
109
0
    return;
110
0
  if (params->location == NULL || *params->location == '\0')
111
0
    fprintf(stderr, "error: %s\n", message);
112
0
  else
113
0
    fprintf(stderr, "%s: error: %s\n", params->location, message);
114
0
}
115
116
static struct sieve_error_handler *_testsuite_log_ehandler_create(void)
117
0
{
118
0
  pool_t pool;
119
0
  struct sieve_error_handler *ehandler;
120
121
0
  pool = pool_alloconly_create("testsuite_log_ehandler",
122
0
             sizeof(struct sieve_error_handler));
123
0
  ehandler = p_new(pool, struct sieve_error_handler, 1);
124
0
  sieve_error_handler_init(ehandler, testsuite_sieve_instance, pool, 0);
125
126
0
  ehandler->log = _testsuite_log;
127
128
0
  return ehandler;
129
0
}
130
131
static struct sieve_error_handler *_testsuite_log_main_ehandler_create(void)
132
0
{
133
0
  pool_t pool;
134
0
  struct sieve_error_handler *ehandler;
135
136
0
  pool = pool_alloconly_create("testsuite_log_main_ehandler",
137
0
             sizeof(struct sieve_error_handler));
138
0
  ehandler = p_new(pool, struct sieve_error_handler, 1);
139
0
  sieve_error_handler_init(ehandler, testsuite_sieve_instance, pool, 0);
140
141
0
  ehandler->log = _testsuite_main_log;
142
143
0
  return ehandler;
144
0
}
145
146
static void ATTR_FORMAT(2, 0)
147
testsuite_error_handler(const struct failure_context *ctx, const char *fmt,
148
      va_list args)
149
0
{
150
0
  struct sieve_error_params params = {
151
0
    .location = NULL,
152
0
  };
153
0
  pool_t pool = _testsuite_logmsg_pool;
154
0
  struct _testsuite_log_message msg;
155
156
0
  i_zero(&msg);
157
0
  switch (ctx->type) {
158
0
  case LOG_TYPE_DEBUG:
159
0
    T_BEGIN {
160
0
      _testsuite_stdout_log(&params, "debug",
161
0
                t_strdup_vprintf(fmt, args));
162
0
    } T_END;
163
0
    break;
164
0
  case LOG_TYPE_INFO:
165
0
    msg.message = p_strdup_vprintf(pool, fmt, args);
166
0
    array_append(&_testsuite_log_messages, &msg, 1);
167
168
0
    _testsuite_stdout_log(&params, "info", msg.message);
169
0
    break;
170
0
  case LOG_TYPE_WARNING:
171
0
    msg.message = p_strdup_vprintf(pool, fmt, args);
172
0
    array_append(&_testsuite_log_warnings, &msg, 1);
173
174
0
    _testsuite_stdout_log(&params, "warning", msg.message);
175
0
    break;
176
0
  case LOG_TYPE_ERROR:
177
0
    msg.message = p_strdup_vprintf(pool, fmt, args);
178
0
    array_append(&_testsuite_log_errors, &msg, 1);
179
180
0
    _testsuite_stdout_log(&params, "error", msg.message);
181
0
    break;
182
0
  default:
183
0
    default_error_handler(ctx, fmt, args);
184
0
    break;
185
0
  }
186
0
}
187
188
/*
189
 *
190
 */
191
192
void testsuite_log_clear_messages(void)
193
0
{
194
0
  if (_testsuite_logmsg_pool != NULL) {
195
0
    if (array_count(&_testsuite_log_errors) == 0)
196
0
      return;
197
0
    pool_unref(&_testsuite_logmsg_pool);
198
0
  }
199
200
0
  _testsuite_logmsg_pool =
201
0
    pool_alloconly_create("testsuite_log_messages", 8192);
202
203
0
  p_array_init(&_testsuite_log_errors, _testsuite_logmsg_pool, 128);
204
0
  p_array_init(&_testsuite_log_warnings, _testsuite_logmsg_pool, 128);
205
0
  p_array_init(&_testsuite_log_messages, _testsuite_logmsg_pool, 128);
206
207
0
  sieve_error_handler_reset(testsuite_log_ehandler);
208
0
}
209
210
/*
211
 *
212
 */
213
214
void testsuite_log_init(bool log_stdout)
215
0
{
216
0
  _testsuite_log_stdout = log_stdout;
217
218
0
  testsuite_log_ehandler = _testsuite_log_ehandler_create();
219
0
  sieve_error_handler_accept_infolog(testsuite_log_ehandler, TRUE);
220
0
  sieve_error_handler_accept_debuglog(testsuite_log_ehandler, TRUE);
221
222
0
  testsuite_log_main_ehandler = _testsuite_log_main_ehandler_create();
223
0
  sieve_error_handler_accept_infolog(testsuite_log_main_ehandler, TRUE);
224
0
  sieve_error_handler_accept_debuglog(testsuite_log_main_ehandler, TRUE);
225
226
0
  i_set_error_handler(testsuite_error_handler);
227
0
  i_set_info_handler(testsuite_error_handler);
228
0
  i_set_debug_handler(testsuite_error_handler);
229
230
0
  testsuite_log_clear_messages();
231
0
}
232
233
void testsuite_log_deinit(void)
234
0
{
235
0
  sieve_error_handler_unref(&testsuite_log_ehandler);
236
0
  sieve_error_handler_unref(&testsuite_log_main_ehandler);
237
238
0
  i_set_error_handler(default_error_handler);
239
0
  i_set_info_handler(default_error_handler);
240
0
  i_set_debug_handler(default_error_handler);
241
242
0
  pool_unref(&_testsuite_logmsg_pool);
243
0
}
244
245
/*
246
 * Log stringlist
247
 */
248
249
/* Forward declarations */
250
251
static int
252
testsuite_log_stringlist_next_item(struct sieve_stringlist *_strlist,
253
           string_t **str_r);
254
static void testsuite_log_stringlist_reset(struct sieve_stringlist *_strlist);
255
256
/* Stringlist object */
257
258
struct testsuite_log_stringlist {
259
  struct sieve_stringlist strlist;
260
261
  int pos, index;
262
};
263
264
struct sieve_stringlist *
265
testsuite_log_stringlist_create(const struct sieve_runtime_env *renv,
266
        int index)
267
0
{
268
0
  struct testsuite_log_stringlist *strlist;
269
270
0
  strlist = t_new(struct testsuite_log_stringlist, 1);
271
0
  strlist->strlist.runenv = renv;
272
0
  strlist->strlist.exec_status = SIEVE_EXEC_OK;
273
0
  strlist->strlist.next_item = testsuite_log_stringlist_next_item;
274
0
  strlist->strlist.reset = testsuite_log_stringlist_reset;
275
276
0
  strlist->index = index;
277
0
  strlist->pos = 0;
278
279
0
  return &strlist->strlist;
280
0
}
281
282
static int
283
testsuite_log_stringlist_next_item(struct sieve_stringlist *_strlist,
284
           string_t **str_r)
285
0
{
286
0
  struct testsuite_log_stringlist *strlist =
287
0
    (struct testsuite_log_stringlist *) _strlist;
288
0
  const struct _testsuite_log_message *msg;
289
0
  int pos;
290
291
0
  *str_r = NULL;
292
293
0
  if (strlist->pos < 0)
294
0
    return 0;
295
296
0
  if (strlist->index > 0) {
297
0
    pos = strlist->index - 1;
298
0
    strlist->pos = -1;
299
0
  } else {
300
0
    pos = strlist->pos++;
301
0
  }
302
303
0
  if (pos >= (int) array_count(&_testsuite_log_errors)) {
304
0
    strlist->pos = -1;
305
0
    return 0;
306
0
  }
307
308
0
  msg = array_idx(&_testsuite_log_errors, (unsigned int) pos);
309
310
0
  *str_r = t_str_new_const(msg->message, strlen(msg->message));
311
0
  return 1;
312
0
}
313
314
static void testsuite_log_stringlist_reset(struct sieve_stringlist *_strlist)
315
0
{
316
0
  struct testsuite_log_stringlist *strlist =
317
0
    (struct testsuite_log_stringlist *) _strlist;
318
319
0
  strlist->pos = 0;
320
0
}