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-result-action.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-actions.h"
8
#include "sieve-comparators.h"
9
#include "sieve-match-types.h"
10
#include "sieve-validator.h"
11
#include "sieve-generator.h"
12
#include "sieve-interpreter.h"
13
#include "sieve-code.h"
14
#include "sieve-binary.h"
15
#include "sieve-result.h"
16
#include "sieve-dump.h"
17
#include "sieve-match.h"
18
19
#include "testsuite-common.h"
20
#include "testsuite-result.h"
21
22
/*
23
 * test_result_action command
24
 *
25
 * Syntax:
26
 *   test_result_action [MATCH-TYPE] [COMPARATOR] [:index number]
27
 *     <key-list: string-list>
28
 */
29
30
static bool tst_test_result_action_registered
31
  (struct sieve_validator *validator, const struct sieve_extension *ext,
32
    struct sieve_command_registration *cmd_reg);
33
static bool tst_test_result_action_validate
34
  (struct sieve_validator *validator, struct sieve_command *cmd);
35
static bool tst_test_result_action_generate
36
  (const struct sieve_codegen_env *cgenv, struct sieve_command *ctx);
37
38
const struct sieve_command_def tst_test_result_action = {
39
  .identifier = "test_result_action",
40
  .type = SCT_TEST,
41
  .positional_args = 1,
42
  .subtests = 0,
43
  .block_allowed = FALSE,
44
  .block_required = FALSE,
45
  .registered = tst_test_result_action_registered,
46
  .validate = tst_test_result_action_validate,
47
  .generate = tst_test_result_action_generate
48
};
49
50
/*
51
 * Operation
52
 */
53
54
static bool tst_test_result_action_operation_dump
55
  (const struct sieve_dumptime_env *denv, sieve_size_t *address);
56
static int tst_test_result_action_operation_execute
57
  (const struct sieve_runtime_env *renv, sieve_size_t *address);
58
59
const struct sieve_operation_def test_result_action_operation = {
60
  .mnemonic = "TEST_RESULT_ACTION",
61
  .ext_def = &testsuite_extension,
62
  .code = TESTSUITE_OPERATION_TEST_RESULT_ACTION,
63
  .dump = tst_test_result_action_operation_dump,
64
  .execute = tst_test_result_action_operation_execute
65
};
66
67
/*
68
 * Tagged arguments
69
 */
70
71
/* FIXME: merge this with the test_error version of this tag */
72
73
static bool tst_test_result_action_validate_index_tag
74
  (struct sieve_validator *validator, struct sieve_ast_argument **arg,
75
    struct sieve_command *cmd);
76
77
static const struct sieve_argument_def test_result_action_index_tag = {
78
  .identifier = "index",
79
  .validate = tst_test_result_action_validate_index_tag
80
};
81
82
enum tst_test_result_action_optional {
83
  OPT_INDEX = SIEVE_MATCH_OPT_LAST,
84
};
85
86
/*
87
 * Argument implementation
88
 */
89
90
static bool tst_test_result_action_validate_index_tag
91
(struct sieve_validator *validator, 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
    (validator, 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_result_action_registered
118
(struct sieve_validator *validator, 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(validator, cmd_reg, SIEVE_MATCH_OPT_COMPARATOR);
123
0
  sieve_match_types_link_tags(validator, cmd_reg, SIEVE_MATCH_OPT_MATCH_TYPE);
124
125
0
  sieve_validator_register_tag
126
0
    (validator, cmd_reg, ext, &test_result_action_index_tag, OPT_INDEX);
127
128
0
  return TRUE;
129
0
}
130
131
/*
132
 * Validation
133
 */
134
135
static bool tst_test_result_action_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_result_action_generate
162
(const struct sieve_codegen_env *cgenv, struct sieve_command *tst)
163
0
{
164
0
  sieve_operation_emit(cgenv->sblock, tst->ext, &test_result_action_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_result_action_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_RESULT_ACTION:");
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_result_action_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_MATCH_TYPE_DEFAULT(is_match_type);
213
0
  struct sieve_stringlist *value_list, *key_list;
214
0
  int index = 0;
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
  sieve_runtime_trace(renv, SIEVE_TRLVL_TESTS,
252
0
    "testsuite: test_result_action test; match result name (index: %d)", index);
253
254
  /* Create value stringlist */
255
0
  value_list = testsuite_result_stringlist_create(renv, index);
256
257
  /* Perform match */
258
0
  if ( (match=sieve_match(renv, &mcht, &cmp, value_list, key_list, &ret)) < 0 )
259
0
    return ret;
260
261
  /* Set test result for subsequent conditional jump */
262
0
  sieve_interpreter_set_test_result(renv->interp, match > 0);
263
0
  return SIEVE_EXEC_OK;
264
0
}
265
266
267