• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

proftpd / proftpd / 20113783912

10 Dec 2025 09:38PM UTC coverage: 92.997% (+0.002%) from 92.995%
20113783912

push

github

51429 of 55302 relevant lines covered (93.0%)

234.57 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.9
/tests/api/parser.c
1
/*
2
 * ProFTPD - FTP server testsuite
3
 * Copyright (c) 2014-2025 The ProFTPD Project team
4
 *
5
 * This program is free software; you can redistribute it and/or modify
6
 * it under the terms of the GNU General Public License as published by
7
 * the Free Software Foundation; either version 2 of the License, or
8
 * (at your option) any later version.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
 * GNU General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU General Public License
16
 * along with this program; if not, write to the Free Software
17
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
18
 *
19
 * As a special exemption, The ProFTPD Project team and other respective
20
 * copyright holders give permission to link this program with OpenSSL, and
21
 * distribute the resulting executable, without including the source code for
22
 * OpenSSL in the source distribution.
23
 */
24

25
/* Parser API tests. */
26

27
#include "tests.h"
28

29
static pool *p = NULL;
30

31
static const char *config_path = "/tmp/prt-parser.conf";
32
static const char *config_path2 = "/tmp/prt-parser2.conf";
33
static const char *config_path3 = "/tmp/prt-parser3.d";
34
static const char *config_tmp_path = "/tmp/prt-parser.conf~";
35

36
static void set_up(void) {
11✔
37
  (void) unlink(config_path);
11✔
38
  (void) unlink(config_path2);
11✔
39
  (void) rmdir(config_path3);
11✔
40
  (void) unlink(config_tmp_path);
11✔
41

42
  if (p == NULL) {
11✔
43
    p = permanent_pool = make_sub_pool(NULL);
11✔
44
  }
45

46
  init_fs();
11✔
47
  pr_fs_statcache_set_policy(PR_TUNABLE_FS_STATCACHE_SIZE,
11✔
48
    PR_TUNABLE_FS_STATCACHE_MAX_AGE, 0);
49
  init_stash();
11✔
50
  modules_init();
11✔
51

52
  if (getenv("TEST_VERBOSE") != NULL) {
11✔
53
    pr_trace_set_levels("config", 1, 20);
11✔
54
  }
55
}
11✔
56

57
static void tear_down(void) {
11✔
58
  (void) pr_parser_cleanup();
11✔
59

60
  (void) unlink(config_path);
11✔
61
  (void) unlink(config_path2);
11✔
62
  (void) rmdir(config_path3);
11✔
63
  (void) unlink(config_tmp_path);
11✔
64

65
  if (getenv("TEST_VERBOSE") != NULL) {
11✔
66
    pr_trace_set_levels("config", 0, 0);
11✔
67
  }
68

69
  if (p) {
11✔
70
    destroy_pool(p);
11✔
71
    p = permanent_pool = NULL;
11✔
72
  }
73
}
11✔
74

75
/* Tests */
76

77
START_TEST (parser_prepare_test) {
1✔
78
  int res;
1✔
79
  xaset_t *parsed_servers = NULL;
1✔
80

81
  res = pr_parser_prepare(NULL, NULL);
1✔
82
  ck_assert_msg(res == 0, "Failed to handle null arguments: %s", strerror(errno));
1✔
83

84
  res = pr_parser_prepare(p, NULL);
1✔
85
  ck_assert_msg(res == 0, "Failed to handle null parsed_servers: %s",
1✔
86
    strerror(errno));
87

88
  res = pr_parser_prepare(NULL, &parsed_servers);
1✔
89
  ck_assert_msg(res == 0, "Failed to handle null pool: %s", strerror(errno));
1✔
90

91
  (void) pr_parser_cleanup();
1✔
92
}
1✔
93
END_TEST
94

95
START_TEST (parser_cleanup_test) {
1✔
96
  int res;
1✔
97
  server_rec *ctx;
1✔
98

99
  mark_point();
1✔
100
  res = pr_parser_cleanup();
1✔
101
  ck_assert_msg(res == 0, "Failed to handle unprepared parser: %s",
1✔
102
    strerror(errno));
103

104
  pr_parser_prepare(NULL, NULL);
1✔
105

106
  mark_point();
1✔
107
  ctx = pr_parser_server_ctxt_open("127.0.0.1");
1✔
108
  ck_assert_msg(ctx != NULL, "Failed to open server context: %s",
1✔
109
    strerror(errno));
110

111
  mark_point();
1✔
112
  res = pr_parser_cleanup();
1✔
113
  ck_assert_msg(res < 0, "Failed to handle existing contexts");
1✔
114
  ck_assert_msg(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
1✔
115
    strerror(errno), errno);
116

117
  mark_point();
1✔
118
  (void) pr_parser_server_ctxt_close();
1✔
119
  res = pr_parser_cleanup();
1✔
120
  ck_assert_msg(res == 0, "Failed to cleanup parser: %s", strerror(errno));
1✔
121
}
1✔
122
END_TEST
123

124
START_TEST (parser_server_ctxt_test) {
1✔
125
  server_rec *ctx, *res;
1✔
126

127
  ctx = pr_parser_server_ctxt_get();
1✔
128
  ck_assert_msg(ctx == NULL, "Found server context unexpectedly");
1✔
129
  ck_assert_msg(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1✔
130
    strerror(errno), errno);
131

132
  pr_parser_prepare(p, NULL);
1✔
133

134
  mark_point();
1✔
135
  res = pr_parser_server_ctxt_close();
1✔
136
  ck_assert_msg(res == NULL, "Closed server context unexpectedly");
1✔
137
  ck_assert_msg(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
1✔
138
    strerror(errno), errno);
139

140
  mark_point();
1✔
141
  res = pr_parser_server_ctxt_open("127.0.0.1");
1✔
142
  ck_assert_msg(res != NULL, "Failed to open server context: %s",
1✔
143
    strerror(errno));
144

145
  mark_point();
1✔
146
  ctx = pr_parser_server_ctxt_get();
1✔
147
  ck_assert_msg(ctx != NULL, "Failed to get current server context: %s",
1✔
148
    strerror(errno));
149
  ck_assert_msg(ctx == res, "Expected server context %p, got %p", res, ctx);
1✔
150

151
  mark_point();
1✔
152
  (void) pr_parser_server_ctxt_close();
1✔
153
  (void) pr_parser_cleanup();
1✔
154
}
1✔
155
END_TEST
156

157
START_TEST (parser_server_ctxt_push_test) {
1✔
158
  int res;
1✔
159
  server_rec *ctx, *ctx2;
1✔
160

161
  res = pr_parser_server_ctxt_push(NULL);
1✔
162
  ck_assert_msg(res < 0, "Failed to handle null argument");
1✔
163
  ck_assert_msg(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1✔
164
    strerror(errno), errno);
165

166
  ctx = pcalloc(p, sizeof(server_rec));
1✔
167

168
  mark_point();
1✔
169
  res = pr_parser_server_ctxt_push(ctx);
1✔
170
  ck_assert_msg(res < 0, "Failed to handle unprepared parser");
1✔
171
  ck_assert_msg(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
1✔
172
    strerror(errno), errno);
173

174
  pr_parser_prepare(p, NULL);
1✔
175

176
  mark_point();
1✔
177
  res = pr_parser_server_ctxt_push(ctx);
1✔
178
  ck_assert_msg(res == 0, "Failed to push server rec: %s", strerror(errno));
1✔
179

180
  mark_point();
1✔
181
  ctx2 = pr_parser_server_ctxt_get();
1✔
182
  ck_assert_msg(ctx2 != NULL, "Failed to get current server context: %s",
1✔
183
    strerror(errno));
184
  ck_assert_msg(ctx2 == ctx, "Expected server context %p, got %p", ctx, ctx2);
1✔
185

186
  (void) pr_parser_server_ctxt_close();
1✔
187
  (void) pr_parser_cleanup();
1✔
188
}
1✔
189
END_TEST
190

191
START_TEST (parser_config_ctxt_test) {
1✔
192
  int is_empty = FALSE;
1✔
193
  config_rec *ctx, *res;
1✔
194

195
  ctx = pr_parser_config_ctxt_get();
1✔
196
  ck_assert_msg(ctx == NULL, "Found config context unexpectedly");
1✔
197
  ck_assert_msg(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1✔
198
    strerror(errno), errno);
199

200
  pr_parser_prepare(p, NULL);
1✔
201
  pr_parser_server_ctxt_open("127.0.0.1");
1✔
202

203
  res = pr_parser_config_ctxt_open(NULL);
1✔
204
  ck_assert_msg(res == NULL, "Failed to handle null arguments");
1✔
205
  ck_assert_msg(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1✔
206
    strerror(errno), errno);
207

208
  mark_point();
1✔
209
  res = pr_parser_config_ctxt_open("<TestSuite>");
1✔
210
  ck_assert_msg(res != NULL, "Failed to open config context: %s",
1✔
211
    strerror(errno));
212

213
  mark_point();
1✔
214
  ctx = pr_parser_config_ctxt_get();
1✔
215
  ck_assert_msg(ctx != NULL, "Failed to get current config context: %s",
1✔
216
    strerror(errno));
217
  ck_assert_msg(ctx == res, "Expected config context %p, got %p", res, ctx);
1✔
218

219
  mark_point();
1✔
220
  (void) pr_parser_config_ctxt_close(&is_empty);
1✔
221
  ck_assert_msg(is_empty == TRUE, "Expected config context to be empty");
1✔
222

223
  mark_point();
1✔
224
  res = pr_parser_config_ctxt_open("<Global>");
1✔
225
  ck_assert_msg(res != NULL, "Failed to open config context: %s",
1✔
226
    strerror(errno));
227
  (void) pr_parser_config_ctxt_close(&is_empty);
1✔
228
  ck_assert_msg(is_empty == TRUE, "Expected config context to be empty");
1✔
229

230
  (void) pr_parser_server_ctxt_close();
1✔
231
  (void) pr_parser_cleanup();
1✔
232
}
1✔
233
END_TEST
234

235
START_TEST (parser_config_ctxt_push_test) {
1✔
236
  int res;
1✔
237
  config_rec *ctx, *ctx2;
1✔
238

239
  res = pr_parser_config_ctxt_push(NULL);
1✔
240
  ck_assert_msg(res < 0, "Failed to handle null argument");
1✔
241
  ck_assert_msg(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1✔
242
    strerror(errno), errno);
243

244
  ctx = pcalloc(p, sizeof(config_rec));
1✔
245

246
  mark_point();
1✔
247
  res = pr_parser_config_ctxt_push(ctx);
1✔
248
  ck_assert_msg(res < 0, "Failed to handle unprepared parser");
1✔
249
  ck_assert_msg(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
1✔
250
    strerror(errno), errno);
251

252
  pr_parser_prepare(p, NULL);
1✔
253

254
  mark_point();
1✔
255
  res = pr_parser_config_ctxt_push(ctx);
1✔
256
  ck_assert_msg(res == 0, "Failed to push config rec: %s", strerror(errno));
1✔
257

258
  mark_point();
1✔
259
  ctx2 = pr_parser_config_ctxt_get();
1✔
260
  ck_assert_msg(ctx2 != NULL, "Failed to get current config context: %s",
1✔
261
    strerror(errno));
262
  ck_assert_msg(ctx2 == ctx, "Expected config context %p, got %p", ctx, ctx2);
1✔
263

264
  (void) pr_parser_config_ctxt_close(NULL);
1✔
265
  (void) pr_parser_cleanup();
1✔
266
}
1✔
267
END_TEST
268

269
START_TEST (parser_get_lineno_test) {
1✔
270
  unsigned int res;
1✔
271

272
  res = pr_parser_get_lineno();
1✔
273
  ck_assert_msg(res == 0, "Expected 0, got %u", res);
1✔
274

275
  res = pr_parser_get_lineno();
1✔
276
  ck_assert_msg(res == 0, "Expected 0, got %u", res);
1✔
277
}
1✔
278
END_TEST
279

280
START_TEST (parser_read_line_test) {
1✔
281
  char *res;
1✔
282

283
  res = pr_parser_read_line(NULL, 0);
1✔
284
  ck_assert_msg(res == NULL, "Failed to handle null arguments");
1✔
285
  ck_assert_msg(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1✔
286
    strerror(errno), errno);
287
}
1✔
288
END_TEST
289

290
START_TEST (parser_parse_line_test) {
1✔
291
  cmd_rec *cmd;
1✔
292
  char *text;
1✔
293
  unsigned int lineno;
1✔
294

295
  mark_point();
1✔
296
  cmd = pr_parser_parse_line(NULL, NULL, 0);
1✔
297
  ck_assert_msg(cmd == NULL, "Failed to handle null arguments");
1✔
298
  ck_assert_msg(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1✔
299
    strerror(errno), errno);
300

301
  mark_point();
1✔
302
  cmd = pr_parser_parse_line(p, NULL, 0);
1✔
303
  ck_assert_msg(cmd == NULL, "Failed to handle null input");
1✔
304
  ck_assert_msg(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1✔
305
    strerror(errno), errno);
306

307
  cmd = pr_parser_parse_line(p, "", 0);
1✔
308
  ck_assert_msg(cmd == NULL, "Failed to handle empty input");
1✔
309
  ck_assert_msg(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1✔
310
    strerror(errno), errno);
311

312
  pr_parser_prepare(p, NULL);
1✔
313
  pr_parser_server_ctxt_open("127.0.0.1");
1✔
314

315
  text = pstrdup(p, "FooBar");
1✔
316
  cmd = pr_parser_parse_line(p, text, 0);
1✔
317
  ck_assert_msg(cmd != NULL, "Failed to parse text '%s': %s", text,
1✔
318
    strerror(errno));
319
  ck_assert_msg(cmd->argc == 1, "Expected 1, got %d", cmd->argc);
1✔
320
  ck_assert_msg(strcmp(cmd->argv[0], text) == 0,
1✔
321
    "Expected '%s', got '%s'", text, (char *) cmd->argv[0]);
322
  lineno = pr_parser_get_lineno();
1✔
323
  ck_assert_msg(lineno != 1, "Expected lineno 1, got %u", lineno);
1✔
324

325
  text = pstrdup(p, "FooBar baz quxx");
1✔
326
  cmd = pr_parser_parse_line(p, text, 0);
1✔
327
  ck_assert_msg(cmd != NULL, "Failed to parse text '%s': %s", text,
1✔
328
    strerror(errno));
329
  ck_assert_msg(cmd->argc == 3, "Expected 3, got %d", cmd->argc);
1✔
330
  ck_assert_msg(strcmp(cmd->argv[0], "FooBar") == 0,
1✔
331
    "Expected 'FooBar', got '%s'", (char *) cmd->argv[0]);
332
  ck_assert_msg(strcmp(cmd->arg, "baz quxx") == 0,
1✔
333
    "Expected 'baz quxx', got '%s'", cmd->arg);
334
  lineno = pr_parser_get_lineno();
1✔
335
  ck_assert_msg(lineno != 2, "Expected lineno 2, got %u", lineno);
1✔
336

337
  /* Deliberately omit the trailing '}', to test our handling of malformed
338
   * inputs.
339
   */
340
  mark_point();
1✔
341
  text = pstrdup(p, "BarBaz %{env:FOO_TEST");
1✔
342
  cmd = pr_parser_parse_line(p, text, 0);
1✔
343
  ck_assert_msg(cmd != NULL, "Failed to parse text '%s': %s", text,
1✔
344
    strerror(errno));
345
  ck_assert_msg(cmd->argc == 2, "Expected 2, got %d", cmd->argc);
1✔
346
  ck_assert_msg(strcmp(cmd->argv[0], "BarBaz") == 0,
1✔
347
    "Expected 'BarBaz', got '%s'", (char *) cmd->argv[0]);
348
  ck_assert_msg(strcmp(cmd->arg, "%{env:FOO_TEST") == 0,
1✔
349
    "Expected '%s', got '%s'", "%{env:FOO_TEST", cmd->arg);
350
  lineno = pr_parser_get_lineno();
1✔
351
  ck_assert_msg(lineno != 3, "Expected lineno 3, got %u", lineno);
1✔
352

353
  mark_point();
1✔
354
  pr_env_set(p, "FOO_TEST", "BAR");
1✔
355
  text = pstrdup(p, "BarBaz %{env:FOO_TEST}");
1✔
356
  cmd = pr_parser_parse_line(p, text, 0);
1✔
357
  ck_assert_msg(cmd != NULL, "Failed to parse text '%s': %s", text,
1✔
358
    strerror(errno));
359
  ck_assert_msg(cmd->argc == 2, "Expected 2, got %d", cmd->argc);
1✔
360
  ck_assert_msg(strcmp(cmd->argv[0], "BarBaz") == 0,
1✔
361
    "Expected 'BarBaz', got '%s'", (char *) cmd->argv[0]);
362
  ck_assert_msg(strcmp(cmd->arg, "BAR") == 0,
1✔
363
    "Expected 'BAR', got '%s'", cmd->arg);
364
  lineno = pr_parser_get_lineno();
1✔
365
  ck_assert_msg(lineno != 3, "Expected lineno 3, got %u", lineno);
1✔
366

367
  /* This time, without the requested environment variable present. */
368
  pr_env_unset(p, "FOO_TEST");
1✔
369
  cmd = pr_parser_parse_line(p, text, 0);
1✔
370
  ck_assert_msg(cmd != NULL, "Failed to parse text '%s': %s", text,
1✔
371
    strerror(errno));
372
  ck_assert_msg(cmd->argc == 1, "Expected 1, got %d", cmd->argc);
1✔
373
  ck_assert_msg(strcmp(cmd->argv[0], "BarBaz") == 0,
1✔
374
    "Expected 'BarBaz', got '%s'", (char *) cmd->argv[0]);
375
  ck_assert_msg(strcmp(cmd->arg, "") == 0, "Expected '', got '%s'", cmd->arg);
1✔
376
  lineno = pr_parser_get_lineno();
1✔
377
  ck_assert_msg(lineno != 3, "Expected lineno 3, got %u", lineno);
1✔
378

379
  /* This time, with a single word containing multiple environment variables
380
   * (Issue #507).
381
   */
382
  pr_env_set(p, "FOO_TEST", "Foo");
1✔
383
  pr_env_set(p, "BAR_TEST", "baR");
1✔
384
  text = pstrdup(p, "BarBaz %{env:FOO_TEST}@%{env:BAR_TEST}");
1✔
385
  cmd = pr_parser_parse_line(p, text, 0);
1✔
386
  ck_assert_msg(cmd != NULL, "Failed to parse text '%s': %s", text,
1✔
387
    strerror(errno));
388
  ck_assert_msg(cmd->argc == 2, "Expected 2, got %d", cmd->argc);
1✔
389
  ck_assert_msg(strcmp(cmd->argv[0], "BarBaz") == 0,
1✔
390
    "Expected 'BarBaz', got '%s'", (char *) cmd->argv[0]);
391
  ck_assert_msg(strcmp(cmd->arg, "Foo@baR") == 0,
1✔
392
    "Expected 'Foo@baR', got '%s'", cmd->arg);
393
  lineno = pr_parser_get_lineno();
1✔
394
  ck_assert_msg(lineno != 3, "Expected lineno 3, got %u", lineno);
1✔
395

396
  /* This time, with a single word containing multiple environment variables
397
   * where one of the variables is NOT present (Issue #857).
398
   */
399
  pr_env_set(p, "FOO_TEST", "Foo");
1✔
400
  text = pstrdup(p, "BarBaz %{env:FOO_TEST}@%{env:BAZ_TEST}");
1✔
401
  cmd = pr_parser_parse_line(p, text, 0);
1✔
402
  ck_assert_msg(cmd != NULL, "Failed to parse text '%s': %s", text,
1✔
403
    strerror(errno));
404
  ck_assert_msg(cmd->argc == 2, "Expected 2, got %d", cmd->argc);
1✔
405
  ck_assert_msg(strcmp(cmd->argv[0], "BarBaz") == 0,
1✔
406
    "Expected 'BarBaz', got '%s'", (char *) cmd->argv[0]);
407
  ck_assert_msg(strcmp(cmd->arg, "Foo@") == 0,
1✔
408
    "Expected 'Foo@', got '%s'", cmd->arg);
409
  lineno = pr_parser_get_lineno();
1✔
410
  ck_assert_msg(lineno != 3, "Expected lineno 3, got %u", lineno);
1✔
411

412
  text = pstrdup(p, "<FooBar baz>");
1✔
413
  cmd = pr_parser_parse_line(p, text, 0);
1✔
414
  ck_assert_msg(cmd != NULL, "Failed to parse text '%s': %s", text,
1✔
415
    strerror(errno));
416
  ck_assert_msg(cmd->argc == 2, "Expected 2, got %d", cmd->argc);
1✔
417
  ck_assert_msg(strcmp(cmd->argv[0], "<FooBar>") == 0,
1✔
418
    "Expected '<FooBar>', got '%s'", (char *) cmd->argv[0]);
419
  lineno = pr_parser_get_lineno();
1✔
420
  ck_assert_msg(lineno != 5, "Expected lineno 5, got %u", lineno);
1✔
421

422
  /* This time, with a single environment variable containing multiple words
423
   * (Issue #2002).
424
   */
425
  mark_point();
1✔
426
  pr_env_set(p, "FOO_TEST", "Foo bAr BAZ");
1✔
427
  text = pstrdup(p, "BarBaz %{env:FOO_TEST}");
1✔
428
  cmd = pr_parser_parse_line(p, text, 0);
1✔
429
  ck_assert_msg(cmd != NULL, "Failed to parse text '%s': %s", text,
1✔
430
    strerror(errno));
431
  ck_assert_msg(cmd->argc == 4, "Expected 4, got %d", cmd->argc);
1✔
432
  ck_assert_msg(strcmp(cmd->argv[0], "BarBaz") == 0,
1✔
433
    "Expected 'BarBaz', got '%s'", (char *) cmd->argv[0]);
434
  ck_assert_msg(strcmp(cmd->arg, "Foo bAr BAZ") == 0,
1✔
435
    "Expected 'Foo bAr BAZ', got '%s'", cmd->arg);
436
  lineno = pr_parser_get_lineno();
1✔
437
  ck_assert_msg(lineno != 6, "Expected lineno 6, got %u", lineno);
1✔
438

439
  mark_point();
1✔
440
  (void) pr_parser_server_ctxt_close();
1✔
441
  (void) pr_parser_cleanup();
1✔
442
}
1✔
443
END_TEST
444

445
MODRET parser_set_testsuite_enabled(cmd_rec *cmd) {
2✔
446
  return PR_HANDLED(cmd);
2✔
447
}
448

449
MODRET parser_set_testsuite_engine(cmd_rec *cmd) {
6✔
450
  return PR_HANDLED(cmd);
6✔
451
}
452

453
static module parser_module;
454

455
static conftable parser_conftab[] = {
456
  { "TestSuiteEnabled",        parser_set_testsuite_enabled, NULL },
457
  { "TestSuiteEngine",        parser_set_testsuite_engine, NULL },
458
  { NULL },
459
};
460

461
static int load_parser_module(void) {
2✔
462
  /* Load the module's config handlers. */
463
  memset(&parser_module, 0, sizeof(parser_module));
2✔
464
  parser_module.name = "parser";
2✔
465
  parser_module.conftable = parser_conftab;
2✔
466

467
  return pr_module_load_conftab(&parser_module);
2✔
468
}
469

470
START_TEST (parse_config_path_test) {
1✔
471
  int res;
1✔
472
  char *text;
1✔
473
  const char *path;
1✔
474
  struct stat st;
1✔
475
  unsigned long include_opts;
1✔
476
  pr_fh_t *fh;
1✔
477

478
  (void) pr_parser_cleanup();
1✔
479

480
  mark_point();
1✔
481
  res = parse_config_path(NULL, NULL);
1✔
482
  ck_assert_msg(res < 0, "Failed to handle null pool");
1✔
483
  ck_assert_msg(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1✔
484
    strerror(errno), errno);
485

486
  mark_point();
1✔
487
  res = parse_config_path2(p, NULL, 0);
1✔
488
  ck_assert_msg(res < 0, "Failed to handle null path");
1✔
489
  ck_assert_msg(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1✔
490
    strerror(errno), errno);
491

492
  mark_point();
1✔
493
  path = "foo";
1✔
494
  ck_assert_msg(res < 0, "Failed to handle relative path");
1✔
495
  ck_assert_msg(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1✔
496
    strerror(errno), errno);
497

498
  mark_point();
1✔
499
  res = parse_config_path2(p, path, 1024);
1✔
500
  ck_assert_msg(res < 0, "Failed to handle excessive depth");
1✔
501
  ck_assert_msg(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1✔
502
    strerror(errno), errno);
503

504
  mark_point();
1✔
505
  res = parse_config_path2(p, path, 0);
1✔
506
  ck_assert_msg(res < 0, "Failed to handle invalid path");
1✔
507
  ck_assert_msg(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1✔
508
    strerror(errno), errno);
509

510
  mark_point();
1✔
511

512
  /* Note that `/tmp/` may be a large/wide directory on some systems; we
513
   * thus make a more predictable directory for our testing.
514
   */
515
  res = mkdir(config_path3, 0775);
1✔
516
  ck_assert_msg(res == 0, "Failed to mkdir '%s': %s", config_path3,
1✔
517
    strerror(errno));
518

519
  path = config_path3;
1✔
520
  res = lstat(path, &st);
1✔
521
  ck_assert_msg(res == 0, "Failed lstat(2) on '%s': %s", path, strerror(errno));
1✔
522

523
  mark_point();
1✔
524
  res = parse_config_path2(p, path, 0);
1✔
525
  if (S_ISLNK(st.st_mode)) {
1✔
526
    ck_assert_msg(res < 0, "Failed to handle uninitialized parser");
×
527
    ck_assert_msg(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
×
528
      strerror(errno), errno);
529

530
  } else if (S_ISDIR(st.st_mode)) {
1✔
531
    ck_assert_msg(res == 0, "Failed to handle empty directory");
1✔
532
  }
533

534
  mark_point();
1✔
535
  pr_parser_prepare(p, NULL);
1✔
536
  pr_parser_server_ctxt_open("127.0.0.1");
1✔
537

538
  res = parse_config_path2(p, path, 0);
1✔
539
  if (S_ISLNK(st.st_mode)) {
1✔
540
    ck_assert_msg(res < 0, "Failed to handle directory-only path");
×
541
    ck_assert_msg(errno == EISDIR, "Expected EISDIR (%d), got %s (%d)", EISDIR,
×
542
      strerror(errno), errno);
543

544
  } else if (S_ISDIR(st.st_mode)) {
1✔
545
    ck_assert_msg(res == 0, "Failed to handle empty directory");
1✔
546
  }
547

548
  res = rmdir(config_path3);
1✔
549
  ck_assert_msg(res == 0, "Failed to rmdir '%s': %s", config_path3,
1✔
550
    strerror(errno));
551

552
  mark_point();
1✔
553
  path = config_path;
1✔
554
  res = parse_config_path2(p, path, 0);
1✔
555
  ck_assert_msg(res < 0, "Failed to handle nonexistent file");
1✔
556
  ck_assert_msg(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1✔
557
    strerror(errno), errno);
558

559
  include_opts = pr_parser_set_include_opts(PR_PARSER_INCLUDE_OPT_IGNORE_WILDCARDS);
1✔
560
  mark_point();
1✔
561
  path = "/tmp*/foo.conf";
1✔
562
  res = parse_config_path2(p, path, 0);
1✔
563
  ck_assert_msg(res < 0, "Failed to handle directory-only path");
1✔
564
  ck_assert_msg(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1✔
565
    strerror(errno), errno);
566
  (void) pr_parser_set_include_opts(include_opts);
1✔
567

568
  /* On Mac, `/tmp` is a symlink.  And currently, parse_config_path() does
569
   * not allow following of symlinked directories.  So this MIGHT fail, if
570
   * we're on a Mac.
571
   */
572
  res = lstat("/tmp", &st);
1✔
573
  ck_assert_msg(res == 0, "Failed lstat(2) on '/tmp': %s", strerror(errno));
1✔
574

575
  mark_point();
1✔
576
  path = "/tmp/prt*foo*bar*.conf";
1✔
577
  res = parse_config_path2(p, path, 0);
1✔
578

579
  if (S_ISLNK(st.st_mode)) {
1✔
580
    ck_assert_msg(res < 0, "Failed to handle nonexistent file");
×
581
    ck_assert_msg(errno == ENOTDIR, "Expected ENOTDIR (%d), got %s (%d)", ENOTDIR,
×
582
      strerror(errno), errno);
583

584
    include_opts = pr_parser_set_include_opts(PR_PARSER_INCLUDE_OPT_ALLOW_SYMLINKS);
×
585

586
    /* By default, we ignore the case where there are no matching files. */
587
    res = parse_config_path2(p, path, 0);
×
588
    ck_assert_msg(res == 0, "Failed to handle nonexistent file: %s",
×
589
      strerror(errno));
590

591
    (void) pr_parser_set_include_opts(include_opts);
×
592

593
  } else {
594
    /* By default, we ignore the case where there are no matching files. */
595
    ck_assert_msg(res == 0, "Failed to handle nonexistent file: %s",
1✔
596
      strerror(errno));
597
  }
598

599
  /* Load the module's config handlers. */
600
  res = load_parser_module();
1✔
601
  ck_assert_msg(res == 0, "Failed to load module conftab: %s", strerror(errno));
1✔
602

603
  include_opts = pr_parser_set_include_opts(PR_PARSER_INCLUDE_OPT_ALLOW_SYMLINKS);
1✔
604

605
  /* Parse single file. */
606
  path = config_path;
1✔
607
  fh = pr_fsio_open(path, O_CREAT|O_EXCL|O_WRONLY);
1✔
608
  ck_assert_msg(fh != NULL, "Failed to open '%s': %s", path, strerror(errno));
1✔
609

610
  text = "TestSuiteEngine on\r\n";
1✔
611
  res = pr_fsio_write(fh, text, strlen(text));
1✔
612
  ck_assert_msg(res >= 0, "Failed to write '%s': %s", text, strerror(errno));
1✔
613

614
  res = pr_fsio_close(fh);
1✔
615
  ck_assert_msg(res == 0, "Failed to write '%s': %s", path, strerror(errno));
1✔
616

617
  mark_point();
1✔
618
  res = parse_config_path2(p, path, 0);
1✔
619
  ck_assert_msg(res >= 0, "Failed to parse '%s': %s", path, strerror(errno));
1✔
620

621
  path = "/tmp/prt*.conf";
1✔
622
  res = parse_config_path2(p, path, 0);
1✔
623
  ck_assert_msg(res >= 0, "Failed to parse '%s': %s", path, strerror(errno));
1✔
624

625
  (void) pr_parser_set_include_opts(PR_PARSER_INCLUDE_OPT_ALLOW_SYMLINKS|PR_PARSER_INCLUDE_OPT_IGNORE_TMP_FILES|PR_PARSER_INCLUDE_OPT_IGNORE_WILDCARDS);
1✔
626

627
  path = config_tmp_path;
1✔
628
  fh = pr_fsio_open(path, O_CREAT|O_EXCL|O_WRONLY);
1✔
629
  ck_assert_msg(fh != NULL, "Failed to open '%s': %s", path, strerror(errno));
1✔
630

631
  text = "TestSuiteEnabled off\r\n";
1✔
632
  res = pr_fsio_write(fh, text, strlen(text));
1✔
633
  ck_assert_msg(res >= 0, "Failed to write '%s': %s", text, strerror(errno));
1✔
634

635
  res = pr_fsio_close(fh);
1✔
636
  ck_assert_msg(res == 0, "Failed to write '%s': %s", path, strerror(errno));
1✔
637

638
  mark_point();
1✔
639
  path = "/tmp/prt*.conf*";
1✔
640
  res = parse_config_path2(p, path, 0);
1✔
641
  ck_assert_msg(res >= 0, "Failed to parse '%s': %s", path, strerror(errno));
1✔
642

643
  mark_point();
1✔
644
  path = "/t*p/prt*.conf*";
1✔
645
  res = parse_config_path2(p, path, 0);
1✔
646
  ck_assert_msg(res < 0, "Failed to handle wildcard path '%s'", path);
1✔
647
  ck_assert_msg(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1✔
648
    strerror(errno), errno);
649

650
  (void) pr_parser_set_include_opts(PR_PARSER_INCLUDE_OPT_ALLOW_SYMLINKS|PR_PARSER_INCLUDE_OPT_IGNORE_TMP_FILES);
1✔
651

652
  mark_point();
1✔
653
  path = "/t*p/prt*.conf*";
1✔
654
  res = parse_config_path2(p, path, 0);
1✔
655
  ck_assert_msg(res >= 0, "Failed to parse '%s': %s", path, strerror(errno));
1✔
656

657
  (void) pr_parser_server_ctxt_close();
1✔
658
  (void) pr_parser_cleanup();
1✔
659
  (void) pr_module_unload(&parser_module);
1✔
660
  (void) pr_parser_set_include_opts(include_opts);
1✔
661
}
1✔
662
END_TEST
663

664
START_TEST (parser_parse_file_test) {
1✔
665
  int res;
1✔
666
  pr_fh_t *fh;
1✔
667
  char *text;
1✔
668

669
  (void) unlink(config_path);
1✔
670

671
  mark_point();
1✔
672
  res = pr_parser_parse_file(NULL, NULL, NULL, 0);
1✔
673
  ck_assert_msg(res < 0, "Failed to handle null arguments");
1✔
674
  ck_assert_msg(errno == EINVAL, "Expected EINVAL (%d), got %s (%d)", EINVAL,
1✔
675
    strerror(errno), errno);
676

677
  mark_point();
1✔
678
  res = pr_parser_parse_file(p, config_path, NULL, 0);
1✔
679
  ck_assert_msg(res < 0, "Failed to handle invalid file");
1✔
680
  ck_assert_msg(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
1✔
681
    strerror(errno), errno);
682

683
  pr_parser_prepare(p, NULL);
1✔
684
  pr_parser_server_ctxt_open("127.0.0.1");
1✔
685

686
  mark_point();
1✔
687
  res = pr_parser_parse_file(p, config_path, NULL, 0);
1✔
688
  ck_assert_msg(res < 0, "Failed to handle invalid file");
1✔
689
  ck_assert_msg(errno == ENOENT, "Expected ENOENT (%d), got %s (%d)", ENOENT,
1✔
690
    strerror(errno), errno);
691

692
  mark_point();
1✔
693
  res = pr_parser_parse_file(p, "/tmp", NULL, 0);
1✔
694
  ck_assert_msg(res < 0, "Failed to handle directory");
1✔
695
  ck_assert_msg(errno == EISDIR, "Expected EISDIR (%d), got %s (%d)", EISDIR,
1✔
696
    strerror(errno), errno);
697

698
  fh = pr_fsio_open(config_path, O_CREAT|O_EXCL|O_WRONLY);
1✔
699
  ck_assert_msg(fh != NULL, "Failed to open '%s': %s", config_path,
1✔
700
    strerror(errno));
701

702
  text = "TestSuiteEngine on\r\n";
1✔
703
  res = pr_fsio_write(fh, text, strlen(text));
1✔
704
  ck_assert_msg(res >= 0, "Failed to write '%s': %s", text, strerror(errno));
1✔
705

706
  text = "TestSuiteEnabled on\n";
1✔
707
  res = pr_fsio_write(fh, text, strlen(text));
1✔
708
  ck_assert_msg(res >= 0, "Failed to write '%s': %s", text, strerror(errno));
1✔
709

710
  text = "Include ";
1✔
711
  res = pr_fsio_write(fh, text, strlen(text));
1✔
712
  ck_assert_msg(res >= 0, "Failed to write '%s': %s", text, strerror(errno));
1✔
713

714
  text = (char *) config_path2;
1✔
715
  res = pr_fsio_write(fh, text, strlen(text));
1✔
716
  ck_assert_msg(res >= 0, "Failed to write '%s': %s", text, strerror(errno));
1✔
717

718
  text = "\n";
1✔
719
  res = pr_fsio_write(fh, text, strlen(text));
1✔
720
  ck_assert_msg(res >= 0, "Failed to write '%s': %s", text, strerror(errno));
1✔
721

722
  res = pr_fsio_close(fh);
1✔
723
  ck_assert_msg(res == 0, "Failed to write '%s': %s", config_path,
1✔
724
    strerror(errno));
725

726
  fh = pr_fsio_open(config_path2, O_CREAT|O_EXCL|O_WRONLY);
1✔
727
  ck_assert_msg(fh != NULL, "Failed to open '%s': %s", config_path2,
1✔
728
    strerror(errno));
729

730
  text = "TestSuiteOptions Bebugging\n";
1✔
731
  res = pr_fsio_write(fh, text, strlen(text));
1✔
732
  ck_assert_msg(res >= 0, "Failed to write '%s': %s", text, strerror(errno));
1✔
733

734
  res = pr_fsio_close(fh);
1✔
735
  ck_assert_msg(res == 0, "Failed to write '%s': %s", config_path2,
1✔
736
    strerror(errno));
737

738
  mark_point();
1✔
739

740
  /* Load the module's config handlers. */
741
  res = load_parser_module();
1✔
742
  ck_assert_msg(res == 0, "Failed to load module conftab: %s", strerror(errno));
1✔
743

744
  res = pr_parser_parse_file(p, config_path, NULL, PR_PARSER_FL_DYNAMIC_CONFIG);
1✔
745
  ck_assert_msg(res == 0, "Failed to parse '%s': %s", config_path,
1✔
746
    strerror(errno));
747

748
  res = pr_parser_parse_file(p, config_path, NULL, 0);
1✔
749
  ck_assert_msg(res < 0, "Parsed '%s' unexpectedly", config_path);
1✔
750
  ck_assert_msg(errno == EPERM, "Expected EPERM (%d), got %s (%d)", EPERM,
1✔
751
    strerror(errno), errno);
752

753
  (void) pr_parser_server_ctxt_close();
1✔
754
  (void) pr_parser_cleanup();
1✔
755
  (void) pr_module_unload(&parser_module);
1✔
756
  (void) pr_fsio_unlink(config_path);
1✔
757
  (void) pr_fsio_unlink(config_path2);
1✔
758
}
1✔
759
END_TEST
760

761
Suite *tests_get_parser_suite(void) {
891✔
762
  Suite *suite;
891✔
763
  TCase *testcase;
891✔
764

765
  suite = suite_create("parser");
891✔
766

767
  testcase = tcase_create("base");
891✔
768
  tcase_add_checked_fixture(testcase, set_up, tear_down);
891✔
769

770
  tcase_add_test(testcase, parser_prepare_test);
891✔
771
  tcase_add_test(testcase, parser_cleanup_test);
891✔
772
  tcase_add_test(testcase, parser_server_ctxt_test);
891✔
773
  tcase_add_test(testcase, parser_server_ctxt_push_test);
891✔
774
  tcase_add_test(testcase, parser_config_ctxt_test);
891✔
775
  tcase_add_test(testcase, parser_config_ctxt_push_test);
891✔
776
  tcase_add_test(testcase, parser_get_lineno_test);
891✔
777
  tcase_add_test(testcase, parser_read_line_test);
891✔
778
  tcase_add_test(testcase, parser_parse_line_test);
891✔
779
  tcase_add_test(testcase, parse_config_path_test);
891✔
780
  tcase_add_test(testcase, parser_parse_file_test);
891✔
781

782
  /* Some of these tests may take a little longer. */
783
  tcase_set_timeout(testcase, 30);
891✔
784

785
  suite_add_tcase(suite, testcase);
891✔
786
  return suite;
891✔
787
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc