Coverage Report

Created: 2026-07-16 07:09

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/pigeonhole/src/testsuite/tst-test-error.c
Line
Count
Source
1
/* Copyright (c) Pigeonhole authors, see top-level COPYING file */
2
3
#include "sieve-common.h"
4
#include "sieve-error.h"
5
#include "sieve-script.h"
6
#include "sieve-commands.h"
7
#include "sieve-comparators.h"
8
#include "sieve-match-types.h"
9
#include "sieve-validator.h"
10
#include "sieve-generator.h"
11
#include "sieve-interpreter.h"
12
#include "sieve-code.h"
13
#include "sieve-binary.h"
14
#include "sieve-dump.h"
15
#include "sieve-match.h"
16
17
#include "testsuite-common.h"
18
#include "testsuite-log.h"
19
20
/*
21
 * Test_error command
22
 *
23
 * Syntax:
24
 *   test [MATCH-TYPE] [COMPARATOR] [:index number] <key-list: string-list>
25
 */
26
27
static bool tst_test_error_registered
28
  (struct sieve_validator *valdtr, const struct sieve_extension *ext,
29
    struct sieve_command_registration *cmd_reg);
30
static bool tst_test_error_validate
31
  (struct sieve_validator *valdtr, struct sieve_command *cmd);
32
static bool tst_test_error_generate
33
  (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
34
35
const struct sieve_command_def tst_test_error = {
36
  .identifier = "test_error",
37
  .type = SCT_TEST,
38
  .positional_args = 1,
39
  .subtests = 0,
40
  .block_allowed = FALSE,
41
  .block_required = FALSE,
42
  .registered = tst_test_error_registered,
43
  .validate = tst_test_error_validate,
44
  .generate = tst_test_error_generate
45
};
46
47
/*
48
 * Operation
49
 */
50
51
static bool tst_test_error_operation_dump
52
  (const struct sieve_dumptime_env *denv, sieve_size_t *address);
53
static int tst_test_error_operation_execute
54
  (const struct sieve_runtime_env *renv, sieve_size_t *address);
55
56
const struct sieve_operation_def test_error_operation = {
57
  .mnemonic = "TEST_ERROR",
58
  .ext_def = &testsuite_extension,
59
  .code = TESTSUITE_OPERATION_TEST_ERROR,
60
  .dump = tst_test_error_operation_dump,
61
  .execute = tst_test_error_operation_execute
62
};
63
64
/*
65
 * Tagged arguments
66
 */
67
68
/* NOTE: This will be merged with the date-index extension when it is
69
 * implemented.
70
 */
71
72
static bool tst_test_error_validate_index_tag
73
  (struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
74
    struct sieve_command *cmd);
75
76
static const struct sieve_argument_def test_error_index_tag = {
77
  .identifier = "index",
78
  .validate = tst_test_error_validate_index_tag
79
};
80
81
enum tst_test_error_optional {
82
  OPT_INDEX = SIEVE_MATCH_OPT_LAST,
83
};
84
85
86
/*
87
 * Argument implementation
88
 */
89
90
static bool tst_test_error_validate_index_tag
91
(struct sieve_validator *valdtr, struct sieve_ast_argument **arg,
92
  struct sieve_command *cmd)
93
0
{
94
0
  struct sieve_ast_argument *tag = *arg;
95
96
  /* Detach the tag itself */
97
0
  *arg = sieve_ast_arguments_detach(*arg,1);
98
99
  /* Check syntax:
100
   *   :index number
101
   */
102
0
  if ( !sieve_validate_tag_parameter
103
0
    (valdtr, cmd, tag, *arg, NULL, 0, SAAT_NUMBER, FALSE) ) {
104
0
    return FALSE;
105
0
  }
106
107
  /* Skip parameter */
108
0
  *arg = sieve_ast_argument_next(*arg);
109
0
  return TRUE;
110
0
}
111
112
113
/*
114
 * Command registration
115
 */
116
117
static bool tst_test_error_registered
118
(struct sieve_validator *valdtr, const struct sieve_extension *ext,
119
  struct sieve_command_registration *cmd_reg)
120
0
{
121
  /* The order of these is not significant */
122
0
  sieve_comparators_link_tag(valdtr, cmd_reg, SIEVE_MATCH_OPT_COMPARATOR);
123
0
  sieve_match_types_link_tags(valdtr, cmd_reg, SIEVE_MATCH_OPT_MATCH_TYPE);
124
125
0
  sieve_validator_register_tag
126
0
    (valdtr, cmd_reg, ext, &test_error_index_tag, OPT_INDEX);
127
128
0
  return TRUE;
129
0
}
130
131
/*
132
 * Validation
133
 */
134
135
static bool tst_test_error_validate
136
(struct sieve_validator *valdtr ATTR_UNUSED, struct sieve_command *tst)
137
0
{
138
0
  struct sieve_ast_argument *arg = tst->first_positional;
139
0
  struct sieve_comparator cmp_default =
140
0
    SIEVE_COMPARATOR_DEFAULT(i_octet_comparator);
141
0
  struct sieve_match_type mcht_default =
142
0
    SIEVE_COMPARATOR_DEFAULT(is_match_type);
143
144
0
  if ( !sieve_validate_positional_argument
145
0
    (valdtr, tst, arg, "key list", 2, SAAT_STRING_LIST) ) {
146
0
    return FALSE;
147
0
  }
148
149
0
  if ( !sieve_validator_argument_activate(valdtr, tst, arg, FALSE) )
150
0
    return FALSE;
151
152
  /* Validate the key argument to a specified match type */
153
0
  return sieve_match_type_validate
154
0
    (valdtr, tst, arg, &mcht_default, &cmp_default);
155
0
}
156
157
/*
158
 * Code generation
159
 */
160
161
static bool tst_test_error_generate
162
(const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
163
0
{
164
0
  sieve_operation_emit(cgenv->sblock, tst->ext, &test_error_operation);
165
166
  /* Generate arguments */
167
0
  return sieve_generate_arguments(cgenv, tst, NULL);
168
0
}
169
170
/*
171
 * Code dump
172
 */
173
174
static bool tst_test_error_operation_dump
175
(const struct sieve_dumptime_env *denv, sieve_size_t *address)
176
0
{
177
0
  int opt_code = 0;
178
179
0
  sieve_code_dumpf(denv, "TEST_ERROR:");
180
0
  sieve_code_descend(denv);
181
182
  /* Handle any optional arguments */
183
0
  for (;;) {
184
0
    int opt;
185
186
0
    if ( (opt=sieve_match_opr_optional_dump(denv, address, &opt_code))
187
0
      < 0 )
188
0
      return FALSE;
189
190
0
    if ( opt == 0 ) break;
191
192
0
    if ( opt_code == OPT_INDEX ) {
193
0
      if ( !sieve_opr_number_dump(denv, address, "index") )
194
0
        return FALSE;
195
0
    } else {
196
0
      return FALSE;
197
0
    }
198
0
  }
199
200
0
  return sieve_opr_stringlist_dump(denv, address, "key list");
201
0
}
202
203
/*
204
 * Intepretation
205
 */
206
207
static int tst_test_error_operation_execute
208
(const struct sieve_runtime_env *renv, sieve_size_t *address)
209
0
{
210
0
  int opt_code = 0;
211
0
  struct sieve_comparator cmp = SIEVE_COMPARATOR_DEFAULT(i_octet_comparator);
212
0
  struct sieve_match_type mcht = SIEVE_COMPARATOR_DEFAULT(is_match_type);
213
0
  struct sieve_stringlist *value_list, *key_list;
214
0
  int index = -1;
215
0
  int match, ret;
216
217
  /*
218
   * Read operands
219
   */
220
221
  /* Read optional operands */
222
0
  for (;;) {
223
0
    sieve_number_t number;
224
0
    int opt;
225
226
0
    if ( (opt=sieve_match_opr_optional_read
227
0
      (renv, address, &opt_code, &ret, &cmp, &mcht)) < 0 )
228
0
      return ret;
229
230
0
    if ( opt == 0 ) break;
231
232
0
    if ( opt_code == OPT_INDEX ) {
233
0
      if ( (ret=sieve_opr_number_read(renv, address, "index", &number)) <= 0 )
234
0
        return ret;
235
0
      index = (int) number;
236
0
    } else {
237
0
      sieve_runtime_trace_error(renv, "invalid optional operand");
238
0
      return SIEVE_EXEC_BIN_CORRUPT;
239
0
    }
240
0
  }
241
242
  /* Read key-list */
243
0
  if ( (ret=sieve_opr_stringlist_read(renv, address, "key_list", &key_list))
244
0
    <= 0 )
245
0
    return ret;
246
247
  /*
248
   * Perform operation
249
   */
250
251
0
  if ( index > 0 )
252
0
    sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
253
0
      "testsuite: test_error test; match error message [index=%d]", index);
254
0
  else
255
0
    sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
256
0
      "testsuite: test_error test; match error messages");
257
258
  /* Create value stringlist */
259
0
  value_list = testsuite_log_stringlist_create(renv, index);
260
261
  /* Perform match */
262
0
  if ( (match=sieve_match(renv, &mcht, &cmp, value_list, key_list, &ret)) < 0 )
263
0
    return ret;
264
265
  /* Set test result for subsequent conditional jump */
266
0
  sieve_interpreter_set_test_result(renv->interp, match > 0);
267
0
  return SIEVE_EXEC_OK;
268
0
}
269
270
271
272