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

aremmell / libsir / 1876

11 Mar 2025 07:49AM UTC coverage: 95.473% (-0.03%) from 95.499%
1876

Pull #449

gitlab-ci

johnsonjh
Avoid memset

Signed-off-by: Jeffrey H. Johnson <trnsz@pobox.com>
Pull Request #449: Portability improvements

3691 of 3866 relevant lines covered (95.47%)

354984.01 hits per line

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

97.86
/tests/tests.c
1
/*
2
 * tests.c
3
 *
4
 * Version: 2.2.6
5
 *
6
 * ----------------------------------------------------------------------------
7
 *
8
 * SPDX-License-Identifier: MIT
9
 *
10
 * Copyright (c) 2018-2024 Ryan M. Lederman <lederman@gmail.com>
11
 * Copyright (c) 2018-2024 Jeffrey H. Johnson <trnsz@pobox.com>
12
 *
13
 * Permission is hereby granted, free of charge, to any person obtaining a copy of
14
 * this software and associated documentation files (the "Software"), to deal in
15
 * the Software without restriction, including without limitation the rights to
16
 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
17
 * the Software, and to permit persons to whom the Software is furnished to do so,
18
 * subject to the following conditions:
19
 *
20
 * The above copyright notice and this permission notice shall be included in all
21
 * copies or substantial portions of the Software.
22
 *
23
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
25
 * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
26
 * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
27
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
28
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29
 *
30
 * ----------------------------------------------------------------------------
31
 */
32

33
//-V:_sir_logv:575
34

35
#include "tests.h"
36
#include "tests_malloc_bsd.h"
37

38
static sir_test sir_tests[] = {
39
    {SIR_CL_PERFNAME,           sirtest_perf, false, true},
40
    {"thread-race",             sirtest_threadrace, false, true},
41
    {"thread-pool",             sirtest_threadpool, false, true},
42
    {"exceed-max-buffer-size",  sirtest_exceedmaxsize, false, true},
43
    {"no-output-destination",   sirtest_failnooutputdest, false, true},
44
    {"null-pointers",           sirtest_failnulls, false, true},
45
    {"empty-message",           sirtest_failemptymessage, false, true},
46
    {"file-cache-sanity",       sirtest_filecachesanity, false, true},
47
    {"file-invalid-name",       sirtest_failinvalidfilename, false, true},
48
    {"file-bad-permissions",    sirtest_failfilebadpermission, false, true},
49
    {"file-duplicate-name",     sirtest_faildupefile, false, true},
50
    {"file-remove-nonexistent", sirtest_failremovebadfile, false, true},
51
    {"file-archive-large",      sirtest_rollandarchivefile, false, true},
52
    {"init-output-before",      sirtest_failwithoutinit, false, true},
53
    {"init-check-state",        sirtest_isinitialized, false, true},
54
    {"init-superfluous",        sirtest_failinittwice, false, true},
55
    {"init-bad-data",           sirtest_failinvalidinitdata, false, true},
56
    {"init-cleanup-init",       sirtest_initcleanupinit, false, true},
57
    {"init-with-makeinit",      sirtest_initmakeinit, false, true},
58
    {"cleanup-output-after",    sirtest_failaftercleanup, false, true},
59
    {"sanity-errors",           sirtest_errorsanity, false, true},
60
    {"sanity-text-styles",      sirtest_textstylesanity, false, true},
61
    {"sanity-options",          sirtest_optionssanity, false, true},
62
    {"sanity-levels",           sirtest_levelssanity, false, true},
63
    {"sanity-mutexes",          sirtest_mutexsanity, false, true},
64
    {"sanity-update-config",    sirtest_updatesanity, false, true},
65
    {"sanity-thread-ids",       sirtest_threadidsanity, false, true},
66
    {"sanity-file-write",       sirtest_logwritesanity, false, true},
67
    {"syslog",                  sirtest_syslog, false, true},
68
    {"os_log",                  sirtest_os_log, false, true},
69
    {"wineventlog",             sirtest_win_eventlog, false, true},
70
    {"filesystem",              sirtest_filesystem, false, true},
71
    {"squelch-spam",            sirtest_squelchspam, false, true},
72
    {"plugin-loader",           sirtest_pluginloader, false, true},
73
    {"string-utils",            sirtest_stringutils, false, true},
74
    {"get-cpu-count",           sirtest_getcpucount, false, true},
75
    {"get-version-info",        sirtest_getversioninfo, false, true}
76
};
77

78
/** List of available command line arguments. */
79
static const sir_cl_arg cl_args[] = {
80
    {SIR_CL_PERFFLAG,      "", SIR_CL_PERFDESC},
81
    {SIR_CL_ONLYFLAG,      ""  SIR_CL_ONLYUSAGE, SIR_CL_ONLYDESC},
82
    {SIR_CL_LISTFLAG,      "", SIR_CL_LISTDESC},
83
    {SIR_CL_LEAVELOGSFLAG, "", SIR_CL_LEAVELOGSDESC},
84
    {SIR_CL_WAITFLAG,      "", SIR_CL_WAITDESC},
85
    {SIR_CL_VERSIONFLAG,   "", SIR_CL_VERSIONDESC},
86
    {SIR_CL_HELPFLAG,      "", SIR_CL_HELPDESC}
87
};
88

89
static sir_cl_config cl_cfg = {0};
90

91
int main(int argc, char** argv) {
38✔
92
#if defined(__HAIKU__) && !defined(DEBUG)
93
    disable_debugger(1);
94
#endif
95

96
#include "tests_malloc.h"
97

98
#if !defined(__WIN__) && !defined(__HAIKU__) && !defined(__EMSCRIPTEN__)
99
    /* Disallow execution by root / sudo; some of the tests rely on lack of permissions. */
100
    if (geteuid() == 0) {
38✔
101
        (void)fprintf(stderr, "Sorry, but this program may not be executed by root." SIR_EOL);
1✔
102
        return EXIT_FAILURE;
1✔
103
    }
104
#else /* __WIN__ */
105
# if defined(_DEBUG) && defined(SIR_ASSERT_ENABLED)
106
    /* Prevents assert() from calling abort() before the user is able to:
107
     * a.) break into the code and debug (Retry button)
108
     * b.) ignore the assert() and continue. */
109
    _set_error_mode(_OUT_TO_MSGBOX);
110
# endif
111
#endif
112

113
    bool parsed = parse_cmd_line(argc, argv, cl_args, _sir_countof(cl_args),
37✔
114
        sir_tests, _sir_countof(sir_tests), &cl_cfg);
115
    if (!parsed)
37✔
116
        return EXIT_FAILURE;
6✔
117

118
    size_t first     = (cl_cfg.only ? 0 : 1);
31✔
119
    size_t tgt_tests = (cl_cfg.only ? cl_cfg.to_run : _sir_countof(sir_tests) - first);
31✔
120
    size_t passed    =  0;
27✔
121
    size_t ran       =  0;
27✔
122
    sir_time timer   = {0};
31✔
123

124
    print_intro(tgt_tests);
31✔
125
    sir_timer_start(&timer);
31✔
126

127
    for (size_t n = first; n < _sir_countof(sir_tests); n++) {
1,150✔
128
        if (cl_cfg.only && !sir_tests[n].run) {
1,119✔
129
            _sir_selflog("skipping '%s'; not marked to run", sir_tests[n].name);
108✔
130
            continue;
108✔
131
        }
132

133
        print_test_intro(ran + 1, tgt_tests, sir_tests[n].name);
1,011✔
134

135
        sir_tests[n].pass = sir_tests[n].fn();
1,011✔
136
        if (sir_tests[n].pass)
1,011✔
137
            passed++;
952✔
138

139
        ran++;
867✔
140

141
        print_test_outro(ran, tgt_tests, sir_tests[n].name, sir_tests[n].pass);
1,011✔
142
    }
143

144
    print_test_summary(tgt_tests, passed, sir_timer_elapsed(&timer));
31✔
145

146
    if (passed != tgt_tests) {
31✔
147
        print_failed_test_intro(tgt_tests, passed);
20✔
148

149
        for (size_t t = 0; t < _sir_countof(sir_tests); t++)
760✔
150
            if (!sir_tests[t].pass)
740✔
151
                print_failed_test(sir_tests[t].name);
59✔
152
        (void)printf(SIR_EOL);
20✔
153
    }
154

155
    if (cl_cfg.wait)
31✔
156
        wait_for_keypress();
1✔
157

158
    return passed == tgt_tests ? EXIT_SUCCESS : EXIT_FAILURE;
31✔
159
}
160

161
bool sirtest_exceedmaxsize(void) {
28✔
162
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
163
    bool pass = si_init;
24✔
164

165
    char toobig[SIR_MAXMESSAGE + 100] = {0};
24✔
166
    (void)memset(toobig, 'a', SIR_MAXMESSAGE + 100);
24✔
167
    toobig[SIR_MAXMESSAGE + 99] = '\0';
28✔
168

169
    _sir_eqland(pass, sir_info("%s", toobig));
28✔
170

171
    _sir_eqland(pass, sir_cleanup());
28✔
172
    return PRINT_RESULT_RETURN(pass);
28✔
173
}
174

175
bool sirtest_logwritesanity(void) {
28✔
176
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
177
    bool pass = si_init;
24✔
178

179
    static const char* logfilename = MAKE_LOG_NAME("write-validate.log");
180
    static const char* message     = "Lorem ipsum dolor sit amet, sea ei dicit"
181
                                     " regione laboramus, eos cu minim putent."
182
                                     " Sale omnium conceptam est in, cu nam possim"
183
                                     " prompta eleifend. Duo purto nostrud eu."
184
                                     " Alia accumsan has cu, mentitum invenire"
185
                                     " mel an, dicta noster legendos et pro."
186
                                     " Solum nobis laboramus et quo, nam putant"
187
                                     " dolores consequuntur ex. Sit veniam eruditi"
188
                                     " contentiones at. Cu ponderum oporteat"
189
                                     " oportere mel, has et saperet accusata"
190
                                     " complectitur.";
191

192
    TEST_MSG("adding log file '%s' to libsir...", logfilename);
28✔
193
    sirfileid id = sir_addfile(logfilename, SIRL_DEBUG, SIRO_NOHDR | SIRO_NOHOST);
28✔
194
    _sir_eqland(pass, 0U != id);
28✔
195

196
    (void)print_test_error(pass, false);
28✔
197

198
    TEST_MSG("writing message to stdout and %s...", logfilename);
28✔
199

200
    _sir_eqland(pass, sir_debug("%s", message));
28✔
201

202
    (void)print_test_error(pass, false);
28✔
203

204
    TEST_MSG("removing %s from libsir...", logfilename);
28✔
205
    _sir_eqland(pass, sir_remfile(id));
28✔
206

207
    (void)print_test_error(pass, false);
28✔
208

209
    TEST_MSG("opening %s for reading...", logfilename);
28✔
210

211
    FILE* f = fopen(logfilename, "r");
28✔
212
    if (!f) {
28✔
213
        pass = false;
3✔
214
    } else {
215
        char buf[512] = {0};
25✔
216
        _sir_eqland(pass, 0 != sir_readline(f, buf, 512));
25✔
217

218
        bool found = NULL != strstr(buf, message);
25✔
219
        _sir_eqland(pass, found);
25✔
220

221
        if (found)
25✔
222
            TEST_MSG(SIR_GREEN("found '%s'"), message);
21✔
223
        else
224
            TEST_MSG(SIR_RED("did not find '%s'"), message);
×
225

226
        _sir_safefclose(&f);
25✔
227
        TEST_MSG("deleting %s...", logfilename);
25✔
228
        rmfile(logfilename, cl_cfg.leave_logs);
25✔
229
    }
230

231
    _sir_eqland(pass, sir_cleanup());
28✔
232
    return PRINT_RESULT_RETURN(pass);
28✔
233
}
234

235
bool sirtest_threadidsanity(void)
28✔
236
{
237
#if defined(SIR_NO_THREAD_NAMES)
238
    TEST_MSG_0(SIR_DGRAY("test skipped for this system configuration"));
239
    return true;
240
#endif
241
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
242
    bool pass = si_init;
24✔
243

244
    static const char* thread_name = "mythread";
245
    static const char* logfilename = MAKE_LOG_NAME("thread-id-name.log");
246

247
    TEST_MSG("adding log file '%s' to libsir...", logfilename);
28✔
248
    sirfileid id = sir_addfile(logfilename, SIRL_DEBUG, SIRO_NOHDR | SIRO_NOHOST);
28✔
249
    _sir_eqland(pass, 0U != id);
28✔
250

251
    (void)print_test_error(pass, false);
28✔
252

253
    TEST_MSG_0("logging a message normally...");
24✔
254
    _sir_eqland(pass, sir_debug("this is a test of the libsir system"));
28✔
255

256
    TEST_MSG("setting the thread name to '%s' and logging again...", thread_name);
28✔
257

258
    _sir_eqland(pass, _sir_setthreadname(thread_name));
28✔
259
    sir_sleep_msec((uint32_t)SIR_THRD_CHK_INTERVAL + 200U);
28✔
260

261
    (void)print_test_error(pass, false);
28✔
262

263
    _sir_eqland(pass, sir_debug("this is a test of the libsir system after setting thread name"));
28✔
264

265
    TEST_MSG_0("setting the thread name to '' and logging again...");
24✔
266

267
    _sir_eqland(pass, _sir_setthreadname(""));
28✔
268
    sir_sleep_msec((uint32_t)SIR_THRD_CHK_INTERVAL + 200U);
28✔
269

270
    (void)print_test_error(pass, false);
28✔
271

272
    _sir_eqland(pass, sir_debug("this is a test of the libsir system after clearing thread name"));
28✔
273

274
     /* remove the log file from libsir, then open it and read it line by line. */
275
    TEST_MSG("removing %s from libsir...", logfilename);
28✔
276
    _sir_eqland(pass, sir_remfile(id));
28✔
277

278
    TEST_MSG("opening %s for reading...", logfilename);
28✔
279

280
    FILE* f = fopen(logfilename, "r");
28✔
281
    if (!f) {
28✔
282
        pass = false;
3✔
283
    } else {
284
        /* look for, in order, TID, thread name, TID. */
285
        for (size_t n = 0; n < 3; n++) {
100✔
286
            char buf[256] = {0};
75✔
287
            _sir_eqland(pass, 0 != sir_readline(f, buf, 256));
75✔
288
            TEST_MSG("read line %zu: '%s'", n, buf);
63✔
289

290
            char search[SIR_MAXPID] = {0};
75✔
291
            switch (n) {
75✔
292
                case 0:
50✔
293
                case 2:
294
                    (void)snprintf(search, SIR_MAXPID, SIR_TIDFORMAT, _sir_gettid());
50✔
295
                break;
42✔
296
                case 1:
25✔
297
                    (void)_sir_strncpy(search, SIR_MAXPID, thread_name, strlen(thread_name));
25✔
298
                break;
25✔
299
                default: break; // GCOVR_EXCL_LINE
300
            }
301

302
            bool found = NULL != strstr(buf, search);
75✔
303
            _sir_eqland(pass, found);
75✔
304

305
            if (found)
75✔
306
                TEST_MSG(SIR_GREEN("line %zu: found '%s'"), n, search);
60✔
307
            else
308
                TEST_MSG(SIR_RED("line %zu: did not find '%s'"), n, search);
3✔
309
        }
310

311
        _sir_safefclose(&f);
25✔
312
        TEST_MSG("deleting %s...", logfilename);
25✔
313
        rmfile(logfilename, cl_cfg.leave_logs);
25✔
314
    }
315

316
    _sir_eqland(pass, sir_cleanup());
28✔
317
    return PRINT_RESULT_RETURN(pass);
28✔
318
}
319

320
bool sirtest_failnooutputdest(void) {
28✔
321
    INIT(si, 0, 0, 0, 0);
28✔
322
    bool pass = si_init;
24✔
323

324
    _sir_eqland(pass, !sir_notice("this goes nowhere!"));
28✔
325

326
    if (pass) {
24✔
327
        static const char* logfilename = MAKE_LOG_NAME("nodestination.log");
328
        PRINT_EXPECTED_ERROR();
28✔
329

330
        _sir_eqland(pass, sir_stdoutlevels(SIRL_INFO));
28✔
331
        _sir_eqland(pass, sir_info("this goes to stdout"));
28✔
332
        _sir_eqland(pass, sir_stdoutlevels(SIRL_NONE));
28✔
333

334
        sirfileid fid = sir_addfile(logfilename, SIRL_INFO, SIRO_DEFAULT);
28✔
335
        _sir_eqland(pass, 0U != fid);
28✔
336
        _sir_eqland(pass, sir_info("this goes to %s", logfilename));
28✔
337
        _sir_eqland(pass, sir_filelevels(fid, SIRL_NONE));
28✔
338
        _sir_eqland(pass, !sir_notice("this goes nowhere!"));
28✔
339

340
        if (0U != fid)
28✔
341
            _sir_eqland(pass, sir_remfile(fid));
25✔
342

343
        rmfile(logfilename, cl_cfg.leave_logs);
28✔
344
    }
345

346
    _sir_eqland(pass, sir_cleanup());
28✔
347
    return PRINT_RESULT_RETURN(pass);
28✔
348
}
349

350
bool sirtest_failnulls(void) {
28✔
351
    INIT_BASE(si, SIRL_ALL, 0, 0, 0, "", false);
28✔
352
    bool pass = true;
24✔
353

354
    _sir_eqland(pass, !sir_init(NULL));
28✔
355

356
    if (pass)
24✔
357
        PRINT_EXPECTED_ERROR();
28✔
358

359
    _sir_eqland(pass, sir_init(&si));
28✔
360
    _sir_eqland(pass, !sir_info(NULL)); //-V618 //-V575
28✔
361

362
    if (pass)
24✔
363
        PRINT_EXPECTED_ERROR();
28✔
364

365
    _sir_eqland(pass, 0U == sir_addfile(NULL, SIRL_ALL, SIRO_MSGONLY));
28✔
366

367
    if (pass)
24✔
368
        PRINT_EXPECTED_ERROR();
28✔
369

370
    _sir_eqland(pass, !sir_remfile(0U));
28✔
371

372
    if (pass)
24✔
373
        PRINT_EXPECTED_ERROR();
28✔
374

375
    _sir_eqland(pass, sir_cleanup());
28✔
376
    return PRINT_RESULT_RETURN(pass);
28✔
377
}
378

379
bool sirtest_failemptymessage(void) {
28✔
380
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
381
    bool pass = si_init;
24✔
382

383
    _sir_eqland(pass, !sir_debug("%s", ""));
28✔
384

385
    _sir_eqland(pass, sir_cleanup());
28✔
386
    return PRINT_RESULT_RETURN(pass);
28✔
387
}
388

389
bool sirtest_filecachesanity(void) {
28✔
390
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
391
    bool pass = si_init;
24✔
392

393
    size_t numfiles             = SIR_MAXFILES + 1;
24✔
394
    sirfileid ids[SIR_MAXFILES] = {0};
28✔
395

396
    sir_options even = SIRO_MSGONLY;
24✔
397
    sir_options odd  = SIRO_ALL;
24✔
398

399
    for (size_t n = 0; n < numfiles - 1; n++) {
476✔
400
        char path[SIR_MAXPATH] = {0};
448✔
401
        (void)snprintf(path, SIR_MAXPATH, MAKE_LOG_NAME("test-%zu.log"), n);
384✔
402
        rmfile(path, cl_cfg.leave_logs);
448✔
403
        ids[n] = sir_addfile(path, SIRL_ALL, (n % 2) ? odd : even);
480✔
404
        _sir_eqland(pass, 0U != ids[n] && sir_info("test %zu", n));
448✔
405
    }
406

407
    _sir_eqland(pass, sir_info("test test test"));
28✔
408

409
    /* this one should fail; max files already added. */
410
    _sir_eqland(pass, 0U == sir_addfile(MAKE_LOG_NAME("should-fail.log"),
28✔
411
        SIRL_ALL, SIRO_MSGONLY));
412

413
    if (pass)
24✔
414
        PRINT_EXPECTED_ERROR();
24✔
415

416
    _sir_eqland(pass, sir_info("test test test"));
28✔
417

418
    /* now remove previously added files in a different order. */
419
    size_t removeorder[SIR_MAXFILES];
420
    (void)memset(removeorder, -1, sizeof(removeorder));
24✔
421

422
    long processed = 0L;
24✔
423
    TEST_MSG_0("creating random file ID order...");
24✔
424

425
    do {
1,106✔
426
        size_t rnd = (size_t)getrand(SIR_MAXFILES);
1,367✔
427
        bool skip  = false;
1,130✔
428

429
        for (size_t n = 0; n < SIR_MAXFILES; n++)
13,899✔
430
            if (removeorder[n] == rnd) {
13,451✔
431
                skip = true;
746✔
432
                break;
746✔
433
            }
434

435
        if (skip)
1,367✔
436
            continue;
919✔
437

438
        removeorder[processed++] = rnd;
448✔
439

440
        if (processed == SIR_MAXFILES)
448✔
441
            break;
24✔
442
    } while (true);
443

444
    (void)printf("\tremove order: {");
24✔
445
    for (size_t n = 0; n < SIR_MAXFILES; n++)
476✔
446
        (void)printf(" %zu%s", removeorder[n], (n < SIR_MAXFILES - 1) ? "," : "");
452✔
447
    (void)printf(" }..." SIR_EOL);
24✔
448

449
    for (size_t n = 0; n < SIR_MAXFILES; n++) {
476✔
450
        _sir_eqland(pass, sir_remfile(ids[removeorder[n]]));
448✔
451

452
        char path[SIR_MAXPATH] = {0};
448✔
453
        (void)snprintf(path, SIR_MAXPATH, MAKE_LOG_NAME("test-%zu.log"), removeorder[n]);
448✔
454
        rmfile(path, cl_cfg.leave_logs);
448✔
455
    }
456

457
    _sir_eqland(pass, sir_info("test test test"));
28✔
458

459
    _sir_eqland(pass, sir_cleanup());
28✔
460
    return PRINT_RESULT_RETURN(pass);
28✔
461
}
462

463
bool sirtest_failinvalidfilename(void) {
28✔
464
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
465
    bool pass = si_init;
24✔
466

467
    _sir_eqland(pass, 0U == sir_addfile("bad file!/name", SIRL_ALL, SIRO_MSGONLY));
28✔
468

469
    if (pass)
24✔
470
        PRINT_EXPECTED_ERROR();
28✔
471

472
    _sir_eqland(pass, sir_cleanup());
28✔
473
    return PRINT_RESULT_RETURN(pass);
28✔
474
}
475

476
bool sirtest_failfilebadpermission(void) {
28✔
477
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
478
    bool pass = si_init;
24✔
479

480
#if !defined(__WIN__)
481
    static const char* path = "/noperms";
482
#else /* __WIN__ */
483
# if defined(__CYGWIN__)
484
    static const char* path = "/cygdrive/c/Windows/System32/noperms";
485
# else
486
    static const char* path;
487
    if (get_wineversion()) {
488
        path = "Z:\\noperms";
489
    } else {
490
        path = "C:\\Windows\\System32\\noperms";
491
    }
492
# endif
493
#endif
494

495
    _sir_eqland(pass, 0U == sir_addfile(path, SIRL_ALL, SIRO_MSGONLY));
28✔
496

497
    if (pass)
24✔
498
        PRINT_EXPECTED_ERROR();
28✔
499

500
    _sir_eqland(pass, sir_cleanup());
28✔
501
    return PRINT_RESULT_RETURN(pass);
28✔
502
}
503

504
bool sirtest_faildupefile(void) {
28✔
505
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
506
    bool pass = si_init;
24✔
507

508
#if !defined(__WIN__)
509
    static const char* filename1 = "./logs/faildupefile.log";
510
    static const char* filename2 = "logs/faildupefile.log";
511
#else
512
    static const char* filename1 = "logs\\faildupefile.log";
513
    static const char* filename2 = "logs/faildupefile.log";
514
#endif
515

516
    static const char* filename3 = "logs/not-a-dupe.log";
517
    static const char* filename4 = "logs/also-not-a-dupe.log";
518

519
    TEST_MSG("adding log file '%s'...", filename1);
28✔
520

521
    /* should be fine; no other files added yet. */
522
    sirfileid fid = sir_addfile(filename1, SIRL_ALL, SIRO_DEFAULT);
28✔
523
    _sir_eqland(pass, 0U != fid);
28✔
524

525
    TEST_MSG("trying again to add log file '%s'...", filename1);
28✔
526

527
    /* should fail. this is the same file we already added. */
528
    _sir_eqland(pass, 0U == sir_addfile(filename1, SIRL_ALL, SIRO_DEFAULT));
28✔
529

530
    if (pass)
24✔
531
        PRINT_EXPECTED_ERROR();
25✔
532

533
    TEST_MSG("adding log file '%s'...", filename2);
28✔
534

535
    /* should also fail. this is the same file we already added, even
536
     * if the path strings don't match. */
537
    _sir_eqland(pass, 0U == sir_addfile(filename2, SIRL_ALL, SIRO_DEFAULT));
28✔
538

539
    if (pass)
24✔
540
        PRINT_EXPECTED_ERROR();
25✔
541

542
    TEST_MSG("adding log file '%s'...", filename3);
28✔
543

544
    /* should pass. this is a different file. */
545
    sirfileid fid2 = sir_addfile(filename3, SIRL_ALL, SIRO_DEFAULT);
28✔
546
    _sir_eqland(pass, 0U != fid2);
28✔
547

548
    /* should also pass. */
549
    sirfileid fid3 = sir_addfile(filename4, SIRL_ALL, SIRO_DEFAULT);
28✔
550
    _sir_eqland(pass, 0U != fid3);
28✔
551

552
    _sir_eqland(pass, sir_info("hello three valid files"));
28✔
553

554
    /* should now fail since we added it earlier. */
555
    _sir_eqland(pass, 0U == sir_addfile(filename3, SIRL_ALL, SIRO_DEFAULT));
28✔
556

557
    if (pass)
24✔
558
        PRINT_EXPECTED_ERROR();
24✔
559

560
    /* don't remove all of the log files in order to also test
561
     * cache tear-down. */
562
    _sir_eqland(pass, sir_remfile(fid));
28✔
563
    _sir_eqland(pass, sir_cleanup());
28✔
564

565
    rmfile(filename1, cl_cfg.leave_logs);
28✔
566
    rmfile(filename2, cl_cfg.leave_logs);
28✔
567
    rmfile(filename3, cl_cfg.leave_logs);
28✔
568
    rmfile(filename4, cl_cfg.leave_logs);
28✔
569

570
    return PRINT_RESULT_RETURN(pass);
28✔
571
}
572

573
bool sirtest_failremovebadfile(void) {
28✔
574
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
575
    bool pass = si_init;
24✔
576

577
    sirfileid invalidid = 9999999;
24✔
578
    _sir_eqland(pass, !sir_remfile(invalidid));
28✔
579

580
    if (pass)
24✔
581
        PRINT_EXPECTED_ERROR();
28✔
582

583
    _sir_eqland(pass, sir_cleanup());
28✔
584
    return PRINT_RESULT_RETURN(pass);
28✔
585
}
586

587
bool sirtest_rollandarchivefile(void) {
29✔
588
    bool pass = true;
25✔
589

590
    _sir_eqland(pass, roll_and_archive("rollandarchive1", ".log"));
29✔
591
    _sir_eqland(pass, roll_and_archive("rollandarchive2", ""));
29✔
592

593
    return pass;
29✔
594
}
595

596
bool sirtest_failwithoutinit(void) {
28✔
597
    bool pass = !sir_info("sir isn't initialized; this needs to fail");
28✔
598

599
    if (pass)
28✔
600
        PRINT_EXPECTED_ERROR();
28✔
601

602
    return PRINT_RESULT_RETURN(pass);
28✔
603
}
604

605
bool sirtest_isinitialized(void) {
28✔
606

607
    bool pass = true;
24✔
608

609
    TEST_MSG_0("checking sir_isinitialized before initialization...");
24✔
610
    _sir_eqland(pass, !sir_isinitialized());
28✔
611

612
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
613
    _sir_eqland(pass, si_init);
28✔
614

615
    TEST_MSG_0("checking sir_isinitialized after initialization...");
24✔
616
    _sir_eqland(pass, sir_isinitialized());
28✔
617

618
    _sir_eqland(pass, sir_cleanup());
28✔
619

620
    TEST_MSG_0("checking sir_isinitialized after cleanup...");
24✔
621
    _sir_eqland(pass, !sir_isinitialized());
28✔
622

623
    return PRINT_RESULT_RETURN(pass);
28✔
624
}
625

626
bool sirtest_failinittwice(void) {
28✔
627
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
628
    bool pass = si_init;
24✔
629

630
    INIT(si2, SIRL_ALL, 0, 0, 0);
28✔
631
    _sir_eqland(pass, !si2_init);
28✔
632

633
    if (pass)
28✔
634
        PRINT_EXPECTED_ERROR();
28✔
635

636
    _sir_eqland(pass, sir_cleanup());
28✔
637
    return PRINT_RESULT_RETURN(pass);
28✔
638
}
639

640
bool sirtest_failinvalidinitdata(void) {
28✔
641
    sirinit si;
642

643
    /* fill with bad data. */
644
    (void)memset(&si, 0xab, sizeof(sirinit));
24✔
645

646
    TEST_MSG_0("calling sir_init with invalid data...");
24✔
647
    bool pass = !sir_init(&si);
28✔
648

649
    if (pass)
28✔
650
        PRINT_EXPECTED_ERROR();
28✔
651

652
    (void)sir_cleanup();
28✔
653
    return PRINT_RESULT_RETURN(pass);
28✔
654
}
655

656
bool sirtest_initcleanupinit(void) {
28✔
657
    INIT(si1, SIRL_ALL, 0, 0, 0);
28✔
658
    bool pass = si1_init;
24✔
659

660
    _sir_eqland(pass, sir_info("init called once; testing output..."));
28✔
661
    _sir_eqland(pass, sir_cleanup());
28✔
662

663
    INIT(si2, SIRL_ALL, 0, 0, 0);
28✔
664
    _sir_eqland(pass, si2_init);
28✔
665

666
    _sir_eqland(pass, sir_info("init called again after re-init; testing output..."));
28✔
667
    _sir_eqland(pass, sir_cleanup());
28✔
668

669
    return PRINT_RESULT_RETURN(pass);
28✔
670
}
671

672
bool sirtest_initmakeinit(void) {
28✔
673
    bool pass = true;
24✔
674

675
    sirinit si;
676
    _sir_eqland(pass, sir_makeinit(&si));
28✔
677
    _sir_eqland(pass, sir_init(&si));
28✔
678
    _sir_eqland(pass, sir_info("initialized with sir_makeinit"));
28✔
679
    _sir_eqland(pass, sir_cleanup());
28✔
680

681
    return PRINT_RESULT_RETURN(pass);
28✔
682
}
683

684
bool sirtest_failaftercleanup(void) {
28✔
685
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
686
    bool pass = si_init;
24✔
687

688
    _sir_eqland(pass, sir_cleanup());
28✔
689
    _sir_eqland(pass, !sir_info("already cleaned up; this needs to fail"));
28✔
690

691
    if (pass)
24✔
692
        PRINT_EXPECTED_ERROR();
28✔
693

694
    return PRINT_RESULT_RETURN(pass);
28✔
695
}
696

697
bool sirtest_errorsanity(void) {
28✔
698
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
699
    bool pass = si_init;
24✔
700

701
    struct {
702
        uint16_t code;
703
        const char* name;
704
    } errors[] = {
28✔
705
        {SIR_E_NOERROR,   "SIR_E_NOERROR"},   /**< The operation completed successfully (1) */
706
        {SIR_E_NOTREADY,  "SIR_E_NOTREADY"},  /**< libsir has not been initialized (2) */
707
        {SIR_E_ALREADY,   "SIR_E_ALREADY"},   /**< libsir is already initialized (3) */
708
        {SIR_E_DUPITEM,   "SIR_E_DUPITEM"},   /**< Item already managed by libsir (4) */
709
        {SIR_E_NOITEM,    "SIR_E_NOITEM"},    /**< Item not managed by libsir (5) */
710
        {SIR_E_NOROOM,    "SIR_E_NOROOM"},    /**< Maximum number of items already stored (6) */
711
        {SIR_E_OPTIONS,   "SIR_E_OPTIONS"},   /**< Option flags are invalid (7) */
712
        {SIR_E_LEVELS,    "SIR_E_LEVELS"},    /**< Level flags are invalid (8) */
713
        {SIR_E_TEXTSTYLE, "SIR_E_TEXTSTYLE"}, /**< Text style is invalid (9) */
714
        {SIR_E_STRING,    "SIR_E_STRING"},    /**< Invalid string argument (10) */
715
        {SIR_E_NULLPTR,   "SIR_E_NULLPTR"},   /**< NULL pointer argument (11) */
716
        {SIR_E_INVALID,   "SIR_E_INVALID"},   /**< Invalid argument (12) */
717
        {SIR_E_NODEST,    "SIR_E_NODEST"},    /**< No destinations registered for level (13) */
718
        {SIR_E_UNAVAIL,   "SIR_E_UNAVAIL"},   /**< Feature is disabled or unavailable (14) */
719
        {SIR_E_INTERNAL,  "SIR_E_INTERNAL"},  /**< An internal error has occurred (15) */
720
        {SIR_E_COLORMODE, "SIR_E_COLORMODE"}, /**< Invalid color mode (16) */
721
        {SIR_E_TEXTATTR,  "SIR_E_TEXTATTR"},  /**< Invalid text attributes (17) */
722
        {SIR_E_TEXTCOLOR, "SIR_E_TEXTCOLOR"}, /**< Invalid text color (18) */
723
        {SIR_E_PLUGINBAD, "SIR_E_PLUGINBAD"}, /**< Plugin module is malformed (19) */
724
        {SIR_E_PLUGINDAT, "SIR_E_PLUGINDAT"}, /**< Data produced by plugin is invalid (20) */
725
        {SIR_E_PLUGINVER, "SIR_E_PLUGINVER"}, /**< Plugin interface version unsupported (21) */
726
        {SIR_E_PLUGINERR, "SIR_E_PLUGINERR"}, /**< Plugin reported failure (22) */
727
        {SIR_E_PLATFORM,  "SIR_E_PLATFORM"},  /**< Platform error code %d: %s (23) */
728
        {SIR_E_UNKNOWN,   "SIR_E_UNKNOWN"},   /**< Unknown error (4095) */
729
    };
730

731
    char message[SIR_MAXERROR] = {0};
28✔
732
    for (size_t n = 0; n < _sir_countof(errors); n++) {
700✔
733
        if (SIR_E_PLATFORM == errors[n].code) {
672✔
734
            /* cause an actual platform error. */
735
            (void)sir_addfile("invalid/file!name", SIRL_ALL, SIRO_DEFAULT);
28✔
736
        } else {
737
            (void)_sir_seterror(_sir_mkerror(errors[n].code));
644✔
738
        }
739

740
        (void)memset(message, 0, SIR_MAXERROR);
576✔
741
        uint16_t err = sir_geterror(message);
672✔
742
        _sir_eqland(pass, errors[n].code == err && *message != '\0');
672✔
743
        TEST_MSG("%s = %s", errors[n].name, message);
672✔
744

745
        /* ensure that sir_geterrorinfo agrees with sir_geterror, and
746
         * that it returns sane data. */
747
        sir_errorinfo errinfo = {0};
672✔
748
        sir_geterrorinfo(&errinfo);
672✔
749

750
        TEST_MSG("errinfo = {'%s', '%s', %"PRIu32", %"PRIu16", '%s', %d, '%s'}",
672✔
751
            errinfo.func, errinfo.file, errinfo.line, errinfo.code, errinfo.msg,
752
            errinfo.os_code, errinfo.os_msg);
753

754
        _sir_eqland(pass, errinfo.code == err);
672✔
755
        _sir_eqland(pass, errinfo.line != 0U);
672✔
756
        _sir_eqland(pass, _sir_validstrnofail(errinfo.msg));
672✔
757

758
        if (errinfo.code == SIR_E_PLATFORM) {
672✔
759
            _sir_eqland(pass, errinfo.os_code != 0);
26✔
760
            _sir_eqland(pass, _sir_validstrnofail(errinfo.os_msg));
26✔
761
            _sir_eqland(pass, _sir_validstrnofail(errinfo.func));
26✔
762
            _sir_eqland(pass, _sir_validstrnofail(errinfo.file));
26✔
763
        } else {
764
            _sir_eqland(pass, _sir_strsame(__func__, errinfo.func, strlen(__func__)));
646✔
765
            _sir_eqland(pass, _sir_strsame(__file__, errinfo.file, SIR_MAXPATH));
646✔
766
        }
767
    }
768

769
    _sir_eqland(pass, sir_cleanup());
28✔
770
    return PRINT_RESULT_RETURN(pass);
28✔
771
}
772

773
bool sirtest_textstylesanity(void) {
28✔
774
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
775
    bool pass = si_init;
24✔
776

777
#if !defined(SIR_NO_TEXT_STYLING)
778
    TEST_MSG_0(SIR_WHITEB("--- explicitly invalid ---"));
22✔
779
    _sir_eqland(pass, !sir_settextstyle(SIRL_INFO, (sir_textattr)0xbbb, 800, 920));
25✔
780
    _sir_eqland(pass, sir_info("I have set an invalid text style."));
25✔
781

782
    _sir_eqland(pass, !sir_settextstyle(SIRL_DEBUG, SIRTA_NORMAL, SIRTC_BLACK, SIRTC_BLACK));
25✔
783
    _sir_eqland(pass, sir_info("oops, did it again..."));
25✔
784

785
    _sir_eqland(pass, !sir_settextstyle(SIRL_ALERT, SIRTA_NORMAL, 0xff, 0xff));
25✔
786
    _sir_eqland(pass, sir_info("and again."));
25✔
787
    PASSFAIL_MSG(pass, "\t--- explicitly invalid: %s ---" SIR_EOL SIR_EOL, PRN_PASS(pass));
22✔
788

789
    TEST_MSG_0(SIR_WHITEB("--- unusual but valid ---"));
22✔
790
    _sir_eqland(pass, sir_settextstyle(SIRL_INFO, SIRTA_NORMAL, SIRTC_DEFAULT, SIRTC_DEFAULT));
25✔
791
    _sir_eqland(pass, sir_info("system default fg and bg"));
25✔
792
    PASSFAIL_MSG(pass, "\t--- unusual but valid: %s ---" SIR_EOL SIR_EOL, PRN_PASS(pass));
22✔
793

794
    TEST_MSG_0(SIR_WHITEB("--- override defaults ---"));
22✔
795
    _sir_eqland(pass, sir_resettextstyles());
25✔
796

797
    _sir_eqland(pass, sir_debug("default style"));
25✔
798
    _sir_eqland(pass, sir_settextstyle(SIRL_DEBUG, SIRTA_NORMAL, SIRTC_BYELLOW, SIRTC_DGRAY));
25✔
799
    _sir_eqland(pass, sir_debug("override style"));
25✔
800

801
    _sir_eqland(pass, sir_info("default style"));
25✔
802
    _sir_eqland(pass, sir_settextstyle(SIRL_INFO, SIRTA_NORMAL, SIRTC_GREEN, SIRTC_MAGENTA));
25✔
803
    _sir_eqland(pass, sir_info("override style"));
25✔
804

805
    _sir_eqland(pass, sir_notice("default style"));
25✔
806
    _sir_eqland(pass, sir_settextstyle(SIRL_NOTICE, SIRTA_NORMAL, SIRTC_BLACK, SIRTC_BYELLOW));
25✔
807
    _sir_eqland(pass, sir_notice("override style"));
25✔
808

809
    _sir_eqland(pass, sir_warn("default style"));
25✔
810
    _sir_eqland(pass, sir_settextstyle(SIRL_WARN, SIRTA_NORMAL, SIRTC_BLACK, SIRTC_WHITE));
25✔
811
    _sir_eqland(pass, sir_warn("override style"));
25✔
812

813
    _sir_eqland(pass, sir_error("default style"));
25✔
814
    _sir_eqland(pass, sir_settextstyle(SIRL_ERROR, SIRTA_NORMAL, SIRTC_WHITE, SIRTC_BLUE));
25✔
815
    _sir_eqland(pass, sir_error("override style"));
25✔
816

817
    _sir_eqland(pass, sir_crit("default style"));
25✔
818
    _sir_eqland(pass, sir_settextstyle(SIRL_CRIT, SIRTA_EMPH, SIRTC_DGRAY, SIRTC_BGREEN));
25✔
819
    _sir_eqland(pass, sir_crit("override style"));
25✔
820

821
    _sir_eqland(pass, sir_alert("default style"));
25✔
822
    _sir_eqland(pass, sir_settextstyle(SIRL_ALERT, SIRTA_ULINE, SIRTC_BBLUE, SIRTC_DEFAULT));
25✔
823
    _sir_eqland(pass, sir_alert("override style"));
25✔
824

825
    _sir_eqland(pass, sir_emerg("default style"));
25✔
826
    _sir_eqland(pass, sir_settextstyle(SIRL_EMERG, SIRTA_BOLD, SIRTC_DGRAY, SIRTC_DEFAULT));
25✔
827
    _sir_eqland(pass, sir_emerg("override style"));
25✔
828
    PASSFAIL_MSG(pass, "\t--- override defaults: %s ---" SIR_EOL SIR_EOL, PRN_PASS(pass));
22✔
829

830
    TEST_MSG_0(SIR_WHITEB("--- reset to defaults ---"));
22✔
831
    _sir_eqland(pass, sir_resettextstyles());
25✔
832

833
    _sir_eqland(pass, sir_debug("default style (debug)"));
25✔
834
    _sir_eqland(pass, sir_info("default style (info)"));
25✔
835
    _sir_eqland(pass, sir_notice("default style (notice)"));
25✔
836
    _sir_eqland(pass, sir_warn("default style (warning)"));
25✔
837
    _sir_eqland(pass, sir_error("default style (error)"));
25✔
838
    _sir_eqland(pass, sir_crit("default style (crit)"));
25✔
839
    _sir_eqland(pass, sir_alert("default style (alert)"));
25✔
840
    _sir_eqland(pass, sir_emerg("default style (emergency)"));
25✔
841
    PASSFAIL_MSG(pass, "\t--- reset to defaults: %s ---" SIR_EOL SIR_EOL, PRN_PASS(pass));
22✔
842

843
    TEST_MSG_0(SIR_WHITEB("--- change mode: 256-color ---"));
22✔
844
    _sir_eqland(pass, sir_setcolormode(SIRCM_256));
25✔
845

846
    for (sir_textcolor fg = 0, bg = 255; (fg < 256 && bg > 0); fg++, bg--) {
6,400✔
847
        if (fg != bg) {
6,375✔
848
            _sir_eqland(pass, sir_settextstyle(SIRL_DEBUG, SIRTA_NORMAL, fg, bg));
6,375✔
849
            _sir_eqland(pass, sir_debug("this is 256-color mode (fg: %"PRIu32", bg: %"PRIu32")",
6,375✔
850
                fg, bg));
851
        }
852
    }
853

854
    PASSFAIL_MSG(pass, "\t--- change mode: 256-color: %s ---" SIR_EOL SIR_EOL, PRN_PASS(pass));
25✔
855

856
    TEST_MSG_0(SIR_WHITEB("--- change mode: RGB-color ---"));
22✔
857
    _sir_eqland(pass, sir_setcolormode(SIRCM_RGB));
25✔
858

859
    for (size_t n = 0; n < 256; n++) {
6,425✔
860
        sir_textcolor fg = sir_makergb(getrand(255U), getrand(255U), getrand(255U));
6,400✔
861
        sir_textcolor bg = sir_makergb(getrand(255U), getrand(255U), getrand(255U));
6,400✔
862
        _sir_eqland(pass, sir_settextstyle(SIRL_DEBUG, SIRTA_NORMAL, fg, bg));
6,400✔
863
        _sir_eqland(pass, sir_debug("this is RGB-color mode (fg: %"PRIu32", %"PRIu32", %"PRIu32
6,400✔
864
            ", bg: %"PRIu32", %"PRIu32", %"PRIu32")", _sir_getredfromcolor(fg),
865
            _sir_getgreenfromcolor(fg), _sir_getbluefromcolor(fg), _sir_getredfromcolor(bg),
866
            _sir_getgreenfromcolor(bg), _sir_getbluefromcolor(bg)));
867
    }
868
    PASSFAIL_MSG(pass, "\t--- change mode: RGB-color: %s ---" SIR_EOL SIR_EOL, PRN_PASS(pass));
25✔
869

870
    TEST_MSG_0(SIR_WHITEB("--- change mode: invalid mode ---"));
22✔
871
    _sir_eqland(pass, !sir_setcolormode(SIRCM_INVALID));
25✔
872
    sir_textcolor fg = sir_makergb(255, 0, 0);
25✔
873
    sir_textcolor bg = sir_makergb(0, 0, 0);
25✔
874
    _sir_eqland(pass, sir_settextstyle(SIRL_DEBUG, SIRTA_NORMAL, fg, bg));
25✔
875
    _sir_eqland(pass, sir_debug("this is still RGB color mode"));
25✔
876
    PASSFAIL_MSG(pass, "\t--- change mode: invalid mode %s ---" SIR_EOL SIR_EOL, PRN_PASS(pass));
22✔
877

878
    TEST_MSG_0(SIR_WHITEB("--- change mode: 16-color ---"));
22✔
879
    _sir_eqland(pass, sir_setcolormode(SIRCM_16));
25✔
880
    _sir_eqland(pass, sir_settextstyle(SIRL_DEBUG, SIRTA_EMPH, SIRTC_BMAGENTA, SIRTC_DEFAULT));
25✔
881
    _sir_eqland(pass, sir_debug("this is 16-color mode (fg: %"PRId32", bg: default)",
25✔
882
        SIRTC_BMAGENTA));
883
    PASSFAIL_MSG(pass, "\t--- change mode: 16-color: %s ---" SIR_EOL SIR_EOL, PRN_PASS(pass));
22✔
884
#else /* SIR_NO_TEXT_STYLING */
885
    TEST_MSG_0("SIR_NO_TEXT_STYLING is defined; skipping");
2✔
886
#endif
887

888
    _sir_eqland(pass, sir_cleanup());
28✔
889

890
    return PRINT_RESULT_RETURN(pass);
28✔
891
}
892

893
bool sirtest_optionssanity(void) {
28✔
894
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
895
    bool pass = si_init;
24✔
896

897
    static const size_t iterations = 10;
898

899
    /*
900
     * TODO(aremmell): Update printf -> TEST_MSG,
901
     * rename INDENT_ITEM to BULLETED_ITEM.
902
     */
903

904
    /* these should all be valid. */
905
    TEST_MSG_0(SIR_WHITEB("--- individual valid options ---"));
24✔
906
    _sir_eqland(pass, _sir_validopts(SIRO_ALL));
28✔
907
    (void)printf(INDENT_ITEM SIR_WHITE("valid option: %08"PRIx32) SIR_EOL, SIRO_ALL);
24✔
908
    _sir_eqland(pass, _sir_validopts(SIRO_NOTIME));
28✔
909
    (void)printf(INDENT_ITEM SIR_WHITE("valid option: %08"PRIx32) SIR_EOL, SIRO_NOTIME);
24✔
910
    _sir_eqland(pass, _sir_validopts(SIRO_NOHOST));
28✔
911
    (void)printf(INDENT_ITEM SIR_WHITE("valid option: %08"PRIx32) SIR_EOL, SIRO_NOHOST);
24✔
912
    _sir_eqland(pass, _sir_validopts(SIRO_NOLEVEL));
28✔
913
    (void)printf(INDENT_ITEM SIR_WHITE("valid option: %08"PRIx32) SIR_EOL, SIRO_NOLEVEL);
24✔
914
    _sir_eqland(pass, _sir_validopts(SIRO_NONAME));
28✔
915
    (void)printf(INDENT_ITEM SIR_WHITE("valid option: %08"PRIx32) SIR_EOL, SIRO_NONAME);
24✔
916
    _sir_eqland(pass, _sir_validopts(SIRO_NOPID));
28✔
917
    (void)printf(INDENT_ITEM SIR_WHITE("valid option: %08"PRIx32) SIR_EOL, SIRO_NOPID);
24✔
918
    _sir_eqland(pass, _sir_validopts(SIRO_NOTID));
28✔
919
    (void)printf(INDENT_ITEM SIR_WHITE("valid option: %08"PRIx32) SIR_EOL, SIRO_NOTID);
24✔
920
    _sir_eqland(pass, _sir_validopts(SIRO_NOHDR));
28✔
921
    (void)printf(INDENT_ITEM SIR_WHITE("valid option: %08"PRIx32) SIR_EOL, SIRO_NOHDR);
24✔
922
    _sir_eqland(pass, _sir_validopts(SIRO_MSGONLY));
28✔
923
    (void)printf(INDENT_ITEM SIR_WHITE("valid option: %08"PRIx32) SIR_EOL, SIRO_MSGONLY);
24✔
924
    PASSFAIL_MSG(pass, "\t--- individual valid options: %s ---" SIR_EOL SIR_EOL, PRN_PASS(pass));
28✔
925

926
    /* any combination these bitwise OR'd together
927
     * to form a bitmask should also be valid. */
928
    static const sir_option option_arr[SIR_NUMOPTIONS] = {
929
        SIRO_NOTIME,
930
        SIRO_NOHOST,
931
        SIRO_NOLEVEL,
932
        SIRO_NONAME,
933
        SIRO_NOMSEC,
934
        SIRO_NOPID,
935
        SIRO_NOTID,
936
        SIRO_NOHDR
937
    };
938

939
    TEST_MSG_0(SIR_WHITEB("--- random bitmask of valid options ---"));
24✔
940
    uint32_t last_count = SIR_NUMOPTIONS;
24✔
941
    for (size_t n = 0; n < iterations; n++) {
308✔
942
        sir_options opts    = 0;
240✔
943
        uint32_t rand_count = 0;
240✔
944
        size_t last_idx     = 0;
240✔
945

946
        do {
947
            rand_count = getrand(SIR_NUMOPTIONS);
451✔
948
        } while (rand_count == last_count || rand_count <= 1);
451✔
949

950
        last_count = rand_count;
240✔
951

952
        for (size_t i = 0; i < rand_count; i++) {
1,489✔
953
            size_t rand_idx = 0;
1,031✔
954
            size_t tries    = 0;
1,031✔
955

956
            do {
957
                if (++tries > SIR_NUMOPTIONS - 2)
1,790✔
958
                    break;
12✔
959
                rand_idx = (size_t)getrand(SIR_NUMOPTIONS);
1,776✔
960
            } while (rand_idx == last_idx || _sir_bittest(opts, option_arr[rand_idx]));
1,776✔
961

962
            last_idx = rand_idx;
1,031✔
963
            opts |= option_arr[rand_idx];
1,209✔
964
        }
965

966
        _sir_eqland(pass, _sir_validopts(opts));
280✔
967
        (void)printf(INDENT_ITEM SIR_WHITE("(%zu/%zu): random valid (count: %"PRIu32
280✔
968
            ", options: %08"PRIx32")") SIR_EOL, n + 1, iterations, rand_count, opts);
969
    }
970
    PASSFAIL_MSG(pass, "\t--- random bitmask of valid options: %s ---" SIR_EOL SIR_EOL, PRN_PASS(pass));
28✔
971

972
    TEST_MSG_0(SIR_WHITEB("--- invalid values ---"));
24✔
973

974
    /* the lowest byte is not valid. */
975
    sir_options invalid = 0x000000ff;
24✔
976
    _sir_eqland(pass, !_sir_validopts(invalid));
28✔
977
    (void)printf(INDENT_ITEM SIR_WHITE("lowest byte: %08"PRIx32) SIR_EOL, invalid);
24✔
978

979
    /* gaps in between valid options. */
980
    invalid = 0x0001ff00U & ~(SIRO_NOTIME | SIRO_NOHOST | SIRO_NOLEVEL | SIRO_NONAME |
24✔
981
                             SIRO_NOMSEC | SIRO_NOPID | SIRO_NOTID  | SIRO_NOHDR);
982
    _sir_eqland(pass, !_sir_validopts(invalid));
28✔
983
    (void)printf(INDENT_ITEM SIR_WHITE("gaps in 0x001ff00U: %08"PRIx32) SIR_EOL, invalid);
24✔
984

985
    /* greater than SIRO_MSGONLY and less than SIRO_NOHDR. */
986
    for (sir_option o = 0x00008f00U; o < SIRO_NOHDR; o += 0x1000U) {
252✔
987
        _sir_eqland(pass, !_sir_validopts(o));
224✔
988
        (void)printf(INDENT_ITEM SIR_WHITE("SIRO_MSGONLY >< SIRO_NOHDR: %08"PRIx32) SIR_EOL, o);
192✔
989
    }
990

991
    /* greater than SIRO_NOHDR. */
992
    invalid = (0xFFFF0000 & ~SIRO_NOHDR);
24✔
993
    _sir_eqland(pass, !_sir_validopts(invalid));
28✔
994
    (void)printf(INDENT_ITEM SIR_WHITE("greater than SIRO_NOHDR: %08"PRIx32) SIR_EOL, invalid);
24✔
995

996
    PASSFAIL_MSG(pass, "\t--- invalid values: %s ---" SIR_EOL SIR_EOL, PRN_PASS(pass));
28✔
997

998
    _sir_eqland(pass, sir_cleanup());
28✔
999
    return PRINT_RESULT_RETURN(pass);
28✔
1000
}
1001

1002
bool sirtest_levelssanity(void) {
28✔
1003
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
1004
    bool pass = si_init;
24✔
1005

1006
    static const size_t iterations = 10;
1007

1008
    /* these should all be valid. */
1009
    TEST_MSG_0(SIR_WHITEB("--- individual valid levels ---"));
24✔
1010
    _sir_eqland(pass, _sir_validlevel(SIRL_INFO) && _sir_validlevels(SIRL_INFO));
28✔
1011
    (void)printf(INDENT_ITEM SIR_WHITE("valid level: %04x") SIR_EOL, SIRL_INFO);
24✔
1012
    _sir_eqland(pass, _sir_validlevel(SIRL_DEBUG) && _sir_validlevels(SIRL_DEBUG));
28✔
1013
    (void)printf(INDENT_ITEM SIR_WHITE("valid level: %04x") SIR_EOL, SIRL_DEBUG);
24✔
1014
    _sir_eqland(pass, _sir_validlevel(SIRL_NOTICE) && _sir_validlevels(SIRL_NOTICE));
28✔
1015
    (void)printf(INDENT_ITEM SIR_WHITE("valid level: %04x") SIR_EOL, SIRL_NOTICE);
24✔
1016
    _sir_eqland(pass, _sir_validlevel(SIRL_WARN) && _sir_validlevels(SIRL_WARN));
28✔
1017
    (void)printf(INDENT_ITEM SIR_WHITE("valid level: %04x") SIR_EOL, SIRL_WARN);
24✔
1018
    _sir_eqland(pass, _sir_validlevel(SIRL_ERROR) && _sir_validlevels(SIRL_ERROR));
28✔
1019
    (void)printf(INDENT_ITEM SIR_WHITE("valid level: %04x") SIR_EOL, SIRL_ERROR);
24✔
1020
    _sir_eqland(pass, _sir_validlevel(SIRL_CRIT) && _sir_validlevels(SIRL_CRIT));
28✔
1021
    (void)printf(INDENT_ITEM SIR_WHITE("valid level: %04x") SIR_EOL, SIRL_CRIT);
24✔
1022
    _sir_eqland(pass, _sir_validlevel(SIRL_ALERT) && _sir_validlevels(SIRL_ALERT));
28✔
1023
    (void)printf(INDENT_ITEM SIR_WHITE("valid level: %04x") SIR_EOL, SIRL_ALERT);
24✔
1024
    _sir_eqland(pass, _sir_validlevel(SIRL_EMERG) && _sir_validlevels(SIRL_EMERG));
28✔
1025
    (void)printf(INDENT_ITEM SIR_WHITE("valid level: %04x") SIR_EOL, SIRL_EMERG);
24✔
1026
    _sir_eqland(pass, _sir_validlevels(SIRL_ALL));
28✔
1027
    (void)printf(INDENT_ITEM SIR_WHITE("valid levels: %04x") SIR_EOL, SIRL_ALL);
24✔
1028
    _sir_eqland(pass, _sir_validlevels(SIRL_NONE));
28✔
1029
    (void)printf(INDENT_ITEM SIR_WHITE("valid levels: %04x") SIR_EOL, SIRL_NONE);
24✔
1030
    PASSFAIL_MSG(pass, "\t--- individual valid levels: %s ---" SIR_EOL SIR_EOL, PRN_PASS(pass));
28✔
1031

1032
    /* any combination these bitwise OR'd together
1033
     * to form a bitmask should also be valid. */
1034
    static const sir_levels levels_arr[SIR_NUMLEVELS] = {
1035
        SIRL_EMERG,
1036
        SIRL_ALERT,
1037
        SIRL_CRIT,
1038
        SIRL_ERROR,
1039
        SIRL_WARN,
1040
        SIRL_NOTICE,
1041
        SIRL_INFO,
1042
        SIRL_DEBUG
1043
    };
1044

1045
    TEST_MSG_0(SIR_WHITEB("--- random bitmask of valid levels ---"));
24✔
1046
    uint32_t last_count = SIR_NUMLEVELS;
24✔
1047
    for (size_t n = 0; n < iterations; n++) {
308✔
1048
        sir_levels levels   = 0U;
240✔
1049
        uint32_t rand_count = 0U;
240✔
1050
        size_t last_idx     = 0UL;
240✔
1051

1052
        do {
1053
            rand_count = getrand(SIR_NUMLEVELS);
454✔
1054
        } while (rand_count == last_count || rand_count <= 1U);
454✔
1055

1056
        last_count = rand_count;
240✔
1057

1058
        for (size_t i = 0; i < rand_count; i++) {
1,535✔
1059
            size_t rand_idx = 0;
1,070✔
1060
            size_t tries    = 0;
1,070✔
1061

1062
            do {
1063
                if (++tries > SIR_NUMLEVELS - 2)
1,986✔
1064
                    break;
22✔
1065
                rand_idx = (size_t)getrand(SIR_NUMLEVELS);
1,962✔
1066
            } while (rand_idx == last_idx || _sir_bittest(levels, levels_arr[rand_idx]));
1,962✔
1067

1068
            last_idx = rand_idx;
1,070✔
1069
            levels |= levels_arr[rand_idx];
1,255✔
1070
        }
1071

1072
        _sir_eqland(pass, _sir_validlevels(levels));
280✔
1073
        (void)printf(INDENT_ITEM SIR_WHITE("(%zu/%zu): random valid (count: %"PRIu32", levels:"
280✔
1074
                                 " %04"PRIx16) ")" SIR_EOL, n + 1, iterations, rand_count, levels);
1075
    }
1076
    PASSFAIL_MSG(pass, "\t--- random bitmask of valid levels: %s ---" SIR_EOL SIR_EOL, PRN_PASS(pass));
28✔
1077

1078
    TEST_MSG_0(SIR_WHITEB("--- invalid values ---"));
24✔
1079

1080
    /* greater than SIRL_ALL. */
1081
    sir_levels invalid = (0xffffU & ~SIRL_ALL);
24✔
1082
    _sir_eqland(pass, !_sir_validlevels(invalid));
28✔
1083
    (void)printf(INDENT_ITEM SIR_WHITE("greater than SIRL_ALL: %04"PRIx16) SIR_EOL, invalid);
24✔
1084

1085
    /* individual invalid level. */
1086
    sir_level invalid2 = 0x1337U;
24✔
1087
    _sir_eqland(pass, !_sir_validlevel(invalid2));
28✔
1088
    (void)printf(INDENT_ITEM SIR_WHITE("individual invalid level: %04"PRIx16) SIR_EOL, invalid2);
24✔
1089

1090
    PASSFAIL_MSG(pass, "\t--- invalid values: %s ---" SIR_EOL, PRN_PASS(pass));
28✔
1091

1092
    _sir_eqland(pass, sir_cleanup());
28✔
1093
    return PRINT_RESULT_RETURN(pass);
28✔
1094
}
1095

1096
bool sirtest_mutexsanity(void) {
28✔
1097
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
1098
    bool pass = si_init;
24✔
1099

1100
    TEST_MSG_0(SIR_WHITEB("create, lock, unlock, destroy"));
24✔
1101
    (void)printf(INDENT_ITEM SIR_WHITE("creating mutex...") SIR_EOL);
24✔
1102

1103
#if !defined(__IMPORTC__)
1104
    sir_mutex m1 = SIR_MUTEX_INIT;
28✔
1105
#else
1106
    sir_mutex m1 = {0};
1107
#endif
1108
    _sir_eqland(pass, _sir_mutexcreate(&m1));
28✔
1109

1110
    (void)print_test_error(pass, pass);
28✔
1111

1112
    if (pass) {
28✔
1113
        (void)printf(INDENT_ITEM SIR_WHITE("locking (wait)...") SIR_EOL);
24✔
1114
        _sir_eqland(pass, _sir_mutexlock(&m1));
28✔
1115

1116
        (void)print_test_error(pass, pass);
28✔
1117

1118
        (void)printf(INDENT_ITEM SIR_WHITE("entered; unlocking...") SIR_EOL);
24✔
1119
        _sir_eqland(pass, _sir_mutexunlock(&m1));
28✔
1120

1121
        (void)print_test_error(pass, pass);
28✔
1122

1123
        (void)printf(INDENT_ITEM SIR_WHITE("locking (without wait)...") SIR_EOL);
24✔
1124
        _sir_eqland(pass, _sir_mutextrylock(&m1));
28✔
1125

1126
        (void)print_test_error(pass, pass);
28✔
1127

1128
        (void)printf(INDENT_ITEM SIR_WHITE("unlocking...") SIR_EOL);
24✔
1129
        _sir_eqland(pass, _sir_mutexunlock(&m1));
28✔
1130

1131
        (void)print_test_error(pass, pass);
28✔
1132

1133
        (void)printf(INDENT_ITEM SIR_WHITE("destroying...") SIR_EOL);
24✔
1134
        _sir_eqland(pass, _sir_mutexdestroy(&m1));
28✔
1135

1136
        (void)print_test_error(pass, pass);
28✔
1137

1138
    }
1139
    PASSFAIL_MSG(pass, "\t--- create, lock, unlock, destroy: %s ---" SIR_EOL SIR_EOL, PRN_PASS(pass));
28✔
1140

1141
    TEST_MSG_0(SIR_WHITEB("invalid arguments"));
24✔
1142
    (void)printf(INDENT_ITEM SIR_WHITE("create with NULL pointer...") SIR_EOL);
24✔
1143
    _sir_eqland(pass, !_sir_mutexcreate(NULL));
28✔
1144
    (void)printf(INDENT_ITEM SIR_WHITE("lock with NULL pointer...") SIR_EOL);
24✔
1145
    _sir_eqland(pass, !_sir_mutexlock(NULL));
28✔
1146
    (void)printf(INDENT_ITEM SIR_WHITE("trylock with NULL pointer...") SIR_EOL);
24✔
1147
    _sir_eqland(pass, !_sir_mutextrylock(NULL));
28✔
1148
    (void)printf(INDENT_ITEM SIR_WHITE("unlock with NULL pointer...") SIR_EOL);
24✔
1149
    _sir_eqland(pass, !_sir_mutexunlock(NULL));
28✔
1150
    (void)printf(INDENT_ITEM SIR_WHITE("destroy with NULL pointer...") SIR_EOL);
24✔
1151
    _sir_eqland(pass, !_sir_mutexdestroy(NULL));
28✔
1152
    PASSFAIL_MSG(pass, "\t--- pass invalid arguments: %s ---" SIR_EOL SIR_EOL, PRN_PASS(pass));
24✔
1153

1154
    _sir_eqland(pass, sir_cleanup());
28✔
1155
    return PRINT_RESULT_RETURN(pass); //-V1020
28✔
1156
}
1157

1158
bool sirtest_perf(void) {
1✔
1159
    static const char* logbasename = "libsir-perf";
1160
    static const char* logext      = "";
1161

1162
#if !defined(DUMA)
1163
# if !defined(SIR_PERF_PROFILE)
1164
#  if !defined(__WIN__)
1165
    static const size_t perflines = 1000000;
1166
#  else
1167
    static const size_t perflines = 100000;
1168
#  endif
1169
# else
1170
    static const size_t perflines = 4000000;
1171
# endif
1172
#else /* DUMA */
1173
    static const size_t perflines = 100000;
1174
#endif
1175

1176
    INIT_N(si, SIRL_ALL, SIRO_NOMSEC | SIRO_NOHOST, 0, 0, "perf");
1✔
1177
    bool pass = si_init;
1✔
1178

1179
    if (pass) {
1✔
1180
        double stdioelapsed  = 0.0;
1✔
1181
        double fileelapsed   = 0.0;
1✔
1182
#if !defined(SIR_PERF_PROFILE)
1183
        double printfelapsed = 0.0;
1✔
1184

1185
        TEST_MSG(SIR_BLUE("%zu lines printf..."), perflines);
1✔
1186

1187
        sir_time printftimer = {0};
1✔
1188
        sir_timer_start(&printftimer);
1✔
1189

1190
        for (size_t n = 0; n < perflines; n++)
1,000,001✔
1191
            (void)printf(SIR_WHITE("%.2f: lorem ipsum foo bar %s: %zu") SIR_EOL,
1,000,000✔
1192
                sir_timer_elapsed(&printftimer), "baz", 1234 + n);
1193

1194
        printfelapsed = sir_timer_elapsed(&printftimer);
1✔
1195
#endif
1196

1197
        TEST_MSG(SIR_BLUE("%zu lines libsir (stdout)..."), perflines);
1✔
1198

1199
        sir_time stdiotimer = {0};
1✔
1200
        sir_timer_start(&stdiotimer);
1✔
1201

1202
        for (size_t n = 0; n < perflines; n++)
1,000,001✔
1203
            (void)sir_debug("%.2f: lorem ipsum foo bar %s: %zu",
1,000,000✔
1204
                sir_timer_elapsed(&stdiotimer), "baz", 1234 + n);
1205

1206
        stdioelapsed = sir_timer_elapsed(&stdiotimer);
1✔
1207

1208
        _sir_eqland(pass, sir_cleanup());
1✔
1209

1210
        INIT(si2, 0, 0, 0, 0);
1✔
1211
        _sir_eqland(pass, si2_init);
1✔
1212

1213
        char logfilename[SIR_MAXPATH] = {0};
1✔
1214
        (void)snprintf(logfilename, SIR_MAXPATH, MAKE_LOG_NAME("%s%s"), logbasename, logext);
1✔
1215

1216
        sirfileid logid = sir_addfile(logfilename, SIRL_ALL, SIRO_NOMSEC | SIRO_NONAME);
1✔
1217
        _sir_eqland(pass, 0 != logid);
1✔
1218

1219
        if (pass) {
1✔
1220
            TEST_MSG(SIR_BLUE("%zu lines libsir (file)..."), perflines);
1✔
1221

1222
            sir_time filetimer = {0};
1✔
1223
            sir_timer_start(&filetimer);
1✔
1224

1225
            for (size_t n = 0; n < perflines; n++)
1,000,001✔
1226
                (void)sir_debug("lorem ipsum foo bar %s: %zu", "baz", 1234 + n);
1,000,000✔
1227

1228
            fileelapsed = sir_timer_elapsed(&filetimer);
1✔
1229

1230
            _sir_eqland(pass, sir_remfile(logid));
1✔
1231
        }
1232

1233
        if (pass) {
1✔
1234
#if !defined(SIR_PERF_PROFILE)
1235
            TEST_MSG(SIR_WHITEB("printf: ") SIR_CYAN("%zu lines in %.3fsec (%.1f lines/sec)"),
1✔
1236
                perflines, printfelapsed / 1e3, (double)perflines / (printfelapsed / 1e3));
1237
#endif
1238
            TEST_MSG(SIR_WHITEB("libsir (stdout): ")
1✔
1239
                   SIR_CYAN("%zu lines in %.3fsec (%.1f lines/sec)"), perflines,
1240
                    stdioelapsed / 1e3, (double)perflines / (stdioelapsed / 1e3));
1241

1242
            TEST_MSG(SIR_WHITEB("libsir (file): ")
1✔
1243
                   SIR_CYAN("%zu lines in %.3fsec (%.1f lines/sec)"), perflines,
1244
                    fileelapsed / 1e3, (double)perflines / (fileelapsed / 1e3));
1245

1246
            TEST_MSG(SIR_WHITEB("timer resolution: ") SIR_CYAN("~%ldnsec"), sir_timer_getres());
1✔
1247
        }
1248
    }
1249

1250
    unsigned deleted = 0U;
1✔
1251
    (void)enumfiles(SIR_TESTLOGDIR, logbasename, !cl_cfg.leave_logs, &deleted);
1✔
1252

1253
    if (deleted > 0U)
1✔
1254
        TEST_MSG(SIR_DGRAY("deleted %u log file(s)"), deleted);
1✔
1255

1256
    _sir_eqland(pass, sir_cleanup());
1✔
1257
    return PRINT_RESULT_RETURN(pass);
1✔
1258
}
1259

1260
bool sirtest_updatesanity(void) {
28✔
1261
    INIT_N(si, SIRL_DEFAULT, 0, SIRL_DEFAULT, 0, "update_sanity");
28✔
1262
    bool pass = si_init;
24✔
1263

1264
#define UPDATE_SANITY_ARRSIZE 10
1265

1266
    static const char* logfile = MAKE_LOG_NAME("update-sanity.log");
1267
    static const sir_options opts_array[UPDATE_SANITY_ARRSIZE] = {
1268
        SIRO_NOHOST | SIRO_NOTIME | SIRO_NOLEVEL,
1269
        SIRO_MSGONLY,
1270
        SIRO_NONAME | SIRO_NOTID,
1271
        SIRO_NOPID | SIRO_NOTIME,
1272
        SIRO_NOTIME | SIRO_NOLEVEL | SIRO_NONAME,
1273
        SIRO_NOTIME,
1274
        SIRO_NOMSEC | SIRO_NOHOST,
1275
        SIRO_NOPID | SIRO_NOTID,
1276
        SIRO_NOHOST | SIRO_NOTID,
1277
        SIRO_ALL
1278
    };
1279

1280
    static const sir_levels levels_array[UPDATE_SANITY_ARRSIZE] = {
1281
        SIRL_NONE,
1282
        SIRL_ALL,
1283
        SIRL_EMERG,
1284
        SIRL_ALERT,
1285
        SIRL_CRIT,
1286
        SIRL_ERROR,
1287
        SIRL_WARN,
1288
        SIRL_NOTICE,
1289
        SIRL_INFO,
1290
        SIRL_DEBUG
1291
    };
1292

1293
    rmfile(logfile, cl_cfg.leave_logs);
28✔
1294
    sirfileid id1 = sir_addfile(logfile, SIRL_DEFAULT, SIRO_DEFAULT);
28✔
1295
    _sir_eqland(pass, 0 != id1);
28✔
1296

1297
    for (int i = 0; i < 10; i++) {
269✔
1298
        if (!pass)
245✔
1299
            break;
4✔
1300

1301
        /* reset to defaults*/
1302
        _sir_eqland(pass, sir_stdoutlevels(SIRL_DEFAULT));
241✔
1303
        _sir_eqland(pass, sir_stderrlevels(SIRL_DEFAULT));
241✔
1304
        _sir_eqland(pass, sir_stdoutopts(SIRO_DEFAULT));
241✔
1305
        _sir_eqland(pass, sir_stderropts(SIRO_DEFAULT));
241✔
1306

1307
        _sir_eqland(pass, sir_debug("default config (debug)"));
241✔
1308
        _sir_eqland(pass, sir_info("default config (info)"));
241✔
1309
        _sir_eqland(pass, sir_notice("default config (notice)"));
241✔
1310
        _sir_eqland(pass, sir_warn("default config (warning)"));
241✔
1311
        _sir_eqland(pass, sir_error("default config (error)"));
241✔
1312
        _sir_eqland(pass, sir_crit("default config (critical)"));
241✔
1313
        _sir_eqland(pass, sir_alert("default config (alert)"));
241✔
1314
        _sir_eqland(pass, sir_emerg("default config (emergency)"));
241✔
1315

1316
        /* pick random options to set/unset */
1317
        uint32_t rnd = getrand(UPDATE_SANITY_ARRSIZE);
241✔
1318
        _sir_eqland(pass, sir_stdoutlevels(levels_array[rnd]));
241✔
1319
        _sir_eqland(pass, sir_stdoutopts(opts_array[rnd]));
241✔
1320
        TEST_MSG(SIR_WHITE("set random config #%"PRIu32" for stdout"), rnd);
201✔
1321

1322
        rnd = getrand(UPDATE_SANITY_ARRSIZE);
241✔
1323
        _sir_eqland(pass, sir_stderrlevels(levels_array[rnd]));
241✔
1324
        _sir_eqland(pass, sir_stderropts(opts_array[rnd]));
241✔
1325
        TEST_MSG(SIR_WHITE("set random config #%"PRIu32" for stderr"), rnd);
201✔
1326

1327
        rnd = getrand(UPDATE_SANITY_ARRSIZE);
241✔
1328
        _sir_eqland(pass, sir_filelevels(id1, levels_array[rnd]));
241✔
1329
        _sir_eqland(pass, sir_fileopts(id1, opts_array[rnd]));
241✔
1330
        TEST_MSG(SIR_WHITE("set random config #%"PRIu32" for %s"), rnd, logfile);
241✔
1331

1332
        _sir_eqland(pass, filter_error(sir_debug("modified config #%"PRIu32" (debug)", rnd), SIR_E_NODEST));
241✔
1333
        _sir_eqland(pass, filter_error(sir_info("modified config #%"PRIu32" (info)", rnd), SIR_E_NODEST));
241✔
1334
        _sir_eqland(pass, filter_error(sir_notice("modified config #%"PRIu32" (notice)", rnd), SIR_E_NODEST));
241✔
1335
        _sir_eqland(pass, filter_error(sir_warn("modified config #%"PRIu32" (warning)", rnd), SIR_E_NODEST));
241✔
1336
        _sir_eqland(pass, filter_error(sir_error("modified config #%"PRIu32" (error)", rnd), SIR_E_NODEST));
241✔
1337
        _sir_eqland(pass, filter_error(sir_crit("modified config #%"PRIu32" (critical)", rnd), SIR_E_NODEST));
241✔
1338
        _sir_eqland(pass, filter_error(sir_alert("modified config #%"PRIu32" (alert)", rnd), SIR_E_NODEST));
241✔
1339
        _sir_eqland(pass, filter_error(sir_emerg("modified config #%"PRIu32" (emergency)", rnd), SIR_E_NODEST));
241✔
1340
    }
1341

1342
    if (pass) {
28✔
1343
        /* restore to default config and run again */
1344
        _sir_eqland(pass, sir_stdoutlevels(SIRL_DEFAULT));
24✔
1345
        _sir_eqland(pass, sir_stderrlevels(SIRL_DEFAULT));
24✔
1346
        _sir_eqland(pass, sir_stdoutopts(SIRO_DEFAULT));
24✔
1347
        _sir_eqland(pass, sir_stderropts(SIRO_DEFAULT));
24✔
1348

1349
        _sir_eqland(pass, sir_debug("default config (debug)"));
24✔
1350
        _sir_eqland(pass, sir_info("default config (info)"));
24✔
1351
        _sir_eqland(pass, sir_notice("default config (notice)"));
24✔
1352
        _sir_eqland(pass, sir_warn("default config (warning)"));
24✔
1353
        _sir_eqland(pass, sir_error("default config (error)"));
24✔
1354
        _sir_eqland(pass, sir_crit("default config (critical)"));
24✔
1355
        _sir_eqland(pass, sir_alert("default config (alert)"));
24✔
1356
        _sir_eqland(pass, sir_emerg("default config (emergency)"));
24✔
1357
    }
1358

1359
    _sir_eqland(pass, sir_remfile(id1));
28✔
1360
    rmfile(logfile, cl_cfg.leave_logs);
28✔
1361

1362
    _sir_eqland(pass, sir_cleanup());
28✔
1363
    return PRINT_RESULT_RETURN(pass);
28✔
1364
}
1365

1366
#if defined(SIR_SYSLOG_ENABLED) || defined(SIR_OS_LOG_ENABLED) || \
1367
    defined(SIR_EVENTLOG_ENABLED)
1368
static
1369
bool generic_syslog_test(const char* sl_name, const char* identity, const char* category) {
22✔
1370
    static const int runs = 5;
1371

1372
    /* repeat initializing, opening, logging, closing, cleaning up n times. */
1373
    (void)printf("\trunning %d passes of random configs (system logger: '%s', "
18✔
1374
                 "identity: '%s', category: '%s')..." SIR_EOL, runs, sl_name, identity, category);
1375

1376
# if !defined(__WIN__)
1377
    uint32_t rnd = (uint32_t)(_sir_getpid() + _sir_gettid());
22✔
1378
# else
1379
    uint32_t rnd = (uint32_t)GetTickCount64();
1380
# endif
1381

1382
    bool pass = true;
18✔
1383
    for (int i = 1; i <= runs; i++) {
132✔
1384
        /* randomly skip setting process name, identity/category to thoroughly
1385
         * test fallback routines; randomly update the config mid-run. */
1386
        bool set_procname = getrand_bool(rnd ^ 0x5a5a5a5aU);
110✔
1387
        bool set_identity = getrand_bool(rnd ^ 0xc9c9c9c9U);
110✔
1388
        bool set_category = getrand_bool(rnd ^ 0x32323232U);
110✔
1389
        bool do_update    = getrand_bool(rnd ^ 0xe7e7e7e7U);
110✔
1390

1391
        TEST_MSG("set_procname: %d, set_identity: %d, set_category: %d, do_update: %d",
110✔
1392
            set_procname, set_identity, set_category, do_update);
1393

1394
        INIT_SL(si, SIRL_ALL, SIRO_NOHOST | SIRO_NOTID, 0, 0, (set_procname ? "sir_sltest" : ""));
123✔
1395
        si.d_syslog.opts   = SIRO_DEFAULT;
110✔
1396
        si.d_syslog.levels = SIRL_DEFAULT;
110✔
1397

1398
        if (set_identity)
110✔
1399
            (void)_sir_strncpy(si.d_syslog.identity, SIR_MAX_SYSLOG_CAT, identity, SIR_MAX_SYSLOG_ID);
57✔
1400

1401
        if (set_category)
110✔
1402
            (void)_sir_strncpy(si.d_syslog.category, SIR_MAX_SYSLOG_CAT, category, SIR_MAX_SYSLOG_CAT);
50✔
1403

1404
        _sir_eqland(pass, sir_init(&si));
110✔
1405

1406
        if (do_update)
110✔
1407
            _sir_eqland(pass, sir_sysloglevels(SIRL_ALL));
47✔
1408

1409
        _sir_eqland(pass, sir_debug("%d/%d: this debug message sent to stdout and %s.", i, runs, sl_name));
110✔
1410
        _sir_eqland(pass, sir_info("%d/%d: this info message sent to stdout and %s.", i, runs, sl_name));
110✔
1411

1412
        _sir_eqland(pass, sir_notice("%d/%d: this notice message sent to stdout and %s.", i, runs, sl_name));
110✔
1413
        _sir_eqland(pass, sir_warn("%d/%d: this warning message sent to stdout and %s.", i, runs, sl_name));
110✔
1414
        _sir_eqland(pass, sir_error("%d/%d: this error message sent to stdout and %s.", i, runs, sl_name));
110✔
1415

1416
        if (set_identity) {
110✔
1417
            _sir_eqland(pass, sir_syslogid("my test ID"));
57✔
1418
            _sir_eqland(pass, sir_syslogid("my test ID")); /* test deduping. */
57✔
1419
        }
1420

1421
        if (set_category) {
110✔
1422
            _sir_eqland(pass, sir_syslogcat("my test category"));
50✔
1423
            _sir_eqland(pass, sir_syslogcat("my test category")); /* test deduping. */
50✔
1424
        }
1425

1426
        if (do_update)
110✔
1427
            _sir_eqland(pass, sir_syslogopts(SIRO_MSGONLY & ~(SIRO_NOLEVEL | SIRO_NOPID)));
47✔
1428

1429
        _sir_eqland(pass, sir_crit("%d/%d: this critical message sent to stdout and %s.", i, runs, sl_name));
110✔
1430
        _sir_eqland(pass, sir_alert("%d/%d: this alert message sent to stdout and %s.", i, runs, sl_name));
110✔
1431
        _sir_eqland(pass, sir_emerg("%d/%d: this emergency message sent to stdout and %s.", i, runs, sl_name));
110✔
1432

1433
# if defined(SIR_OS_LOG_ENABLED)
1434
#  if defined(__MACOS__) && !defined(__INTEL_COMPILER)
1435
        if (i == runs -1 && 0 == strncmp(sl_name, "os_log", 6)) {
1436
            TEST_MSG_0("testing os_log activity feature...");
1437

1438
            /* also test activity grouping in Console. there's only one way to validate
1439
             * this and that's by manually viewing the log. */
1440
            os_activity_t parent = os_activity_create("flying to the moon", //-V530
1441
                OS_ACTIVITY_NONE, OS_ACTIVITY_FLAG_DETACHED);
1442

1443
            /* execution now passes to os_log_parent_activity(), where some logging
1444
             * will occur, then a sub-activity will be created, and more logging. */
1445
            os_activity_apply_f(parent, (void*)parent, os_log_parent_activity);
1446
        }
1447
#  endif
1448
# endif
1449

1450
        _sir_eqland(pass, sir_cleanup());
110✔
1451

1452
        if (!pass)
90✔
1453
            break;
×
1454
    }
1455

1456
    return PRINT_RESULT_RETURN(pass);
22✔
1457
}
1458
#endif
1459

1460
#if defined(SIR_NO_SYSTEM_LOGGERS)
1461
static bool generic_disabled_syslog_test(const char* sl_name, const char* identity,
18✔
1462
    const char* category) {
1463
    INIT_SL(si, SIRL_ALL, SIRO_NOHOST | SIRO_NOTID, 0U, 0U, "sir_disabled_sltest");
18✔
1464
    si.d_syslog.opts   = SIRO_DEFAULT;
18✔
1465
    si.d_syslog.levels = SIRL_DEFAULT;
18✔
1466
    bool pass = true;
18✔
1467

1468
    SIR_UNUSED(sl_name);
1469

1470
    TEST_MSG_0("SIR_NO_SYSTEM_LOGGERS is defined; expecting calls to fail...");
18✔
1471

1472
    /* init should just ignore the syslog settings. */
1473
    _sir_eqland(pass, sir_init(&si));
18✔
1474

1475
    /* these calls should all fail. */
1476
    TEST_MSG_0("setting levels...");
18✔
1477
    _sir_eqland(pass, !sir_sysloglevels(SIRL_ALL));
18✔
1478

1479
    if (pass)
18✔
1480
        PRINT_EXPECTED_ERROR();
18✔
1481

1482
    TEST_MSG_0("setting options...");
18✔
1483
    _sir_eqland(pass, !sir_syslogopts(SIRO_DEFAULT));
18✔
1484

1485
    if (pass)
18✔
1486
        PRINT_EXPECTED_ERROR();
18✔
1487

1488
    TEST_MSG_0("setting identity...");
18✔
1489
    _sir_eqland(pass, !sir_syslogid(identity));
18✔
1490

1491
    if (pass)
18✔
1492
        PRINT_EXPECTED_ERROR();
18✔
1493

1494
    TEST_MSG_0("setting category...");
18✔
1495
    _sir_eqland(pass, !sir_syslogcat(category));
18✔
1496

1497
    if (pass)
18✔
1498
        PRINT_EXPECTED_ERROR();
18✔
1499

1500
    _sir_eqland(pass, sir_cleanup());
18✔
1501
    return PRINT_RESULT_RETURN(pass);
18✔
1502
}
1503
#endif
1504

1505
bool sirtest_syslog(void) {
28✔
1506
#if !defined(SIR_SYSLOG_ENABLED)
1507
# if defined(SIR_NO_SYSTEM_LOGGERS)
1508
    bool pass = generic_disabled_syslog_test("syslog", "sirtests", "tests");
6✔
1509
    return PRINT_RESULT_RETURN(pass);
6✔
1510
# else
1511
    TEST_MSG_0(SIR_DGRAY("SIR_SYSLOG_ENABLED is not defined; skipping"));
1512
    return true;
1513
# endif
1514
#else
1515
    bool pass = generic_syslog_test("syslog", "sirtests", "tests");
22✔
1516
    return PRINT_RESULT_RETURN(pass);
22✔
1517
#endif
1518
}
1519

1520
bool sirtest_os_log(void) {
28✔
1521
#if !defined(SIR_OS_LOG_ENABLED)
1522
# if defined(SIR_NO_SYSTEM_LOGGERS)
1523
    bool pass = generic_disabled_syslog_test("os_log", "com.aremmell.libsir.tests", "tests");
6✔
1524
    return PRINT_RESULT_RETURN(pass);
6✔
1525
# else
1526
    TEST_MSG_0(SIR_DGRAY("SIR_OS_LOG_ENABLED is not defined; skipping"));
18✔
1527
    return true;
22✔
1528
# endif
1529
#else
1530
    bool pass = generic_syslog_test("os_log", "com.aremmell.libsir.tests", "tests");
1531
    return PRINT_RESULT_RETURN(pass);
1532
#endif
1533
}
1534

1535
bool sirtest_win_eventlog(void) {
28✔
1536
#if !defined(SIR_EVENTLOG_ENABLED)
1537
# if defined(SIR_NO_SYSTEM_LOGGERS)
1538
    bool pass = generic_disabled_syslog_test("eventlog", "sirtests", "tests");
6✔
1539
    return PRINT_RESULT_RETURN(pass);
6✔
1540
# else
1541
    TEST_MSG_0(SIR_DGRAY("SIR_EVENTLOG_ENABLED is not defined; skipping"));
18✔
1542
    return true;
22✔
1543
# endif
1544
#else
1545
    bool pass = generic_syslog_test("eventlog", "sirtests", "tests");
1546
    return PRINT_RESULT_RETURN(pass);
1547
#endif
1548
}
1549

1550
bool sirtest_filesystem(void) {
29✔
1551
    INIT(si, SIRL_ALL, 0, 0, 0);
29✔
1552
    bool pass = si_init;
25✔
1553

1554
    /* Wine version */
1555
    TEST_MSG("Running under Wine: %s",
29✔
1556
            get_wineversion() ? get_wineversion() : "no");
1557

1558
    /* current working directory. */
1559
    char* cwd = _sir_getcwd();
29✔
1560
    _sir_eqland(pass, NULL != cwd);
29✔
1561
    TEST_MSG("_sir_getcwd: '%s'", PRN_STR(cwd));
29✔
1562

1563
    if (NULL != cwd) {
29✔
1564
        /* path to this binary file. */
1565
        char* filename = _sir_getappfilename();
29✔
1566
        _sir_eqland(pass, NULL != filename);
29✔
1567
        TEST_MSG("_sir_getappfilename: '%s'", PRN_STR(filename));
29✔
1568

1569
        if (NULL != filename) {
29✔
1570
            /* _sir_get[base|dir]name() can potentially modify filename,
1571
             * so make a copy for each call. */
1572
            char* filename2 = strndup(filename, strnlen(filename, SIR_MAXPATH));
26✔
1573
            _sir_eqland(pass, NULL != filename2);
26✔
1574

1575
            if (NULL != filename2) {
26✔
1576
                /* filename, stripped of directory component(s). */
1577
                char* _basename = _sir_getbasename(filename2);
25✔
1578
                TEST_MSG("_sir_getbasename: '%s'", PRN_STR(_basename));
25✔
1579

1580
                if (!_basename) {
25✔
1581
                    pass = false;
×
1582
                } else {
1583
                    /* the last strlen(_basename) chars of filename should match. */
1584
                    size_t len    = strnlen(_basename, SIR_MAXPATH);
25✔
1585
                    size_t offset = strnlen(filename, SIR_MAXPATH) - len;
25✔
1586
                    size_t n      = 0;
21✔
1587

1588
                    while (n < len) {
225✔
1589
                        if (filename[offset++] != _basename[n++]) {
200✔
1590
                            pass = false;
×
1591
                            break;
×
1592
                        }
1593
                    }
1594
                }
1595
            }
1596

1597
            /* directory this binary file resides in. */
1598
            char* appdir = _sir_getappdir();
26✔
1599
            _sir_eqland(pass, NULL != appdir);
26✔
1600
            TEST_MSG("_sir_getappdir: '%s'", PRN_STR(appdir));
26✔
1601

1602
            /* _sir_get[base|dir]name can potentially modify filename,
1603
             * so make a copy for each call. */
1604
            char* filename3 = strndup(filename, strnlen(filename, SIR_MAXPATH));
26✔
1605
            _sir_eqland(pass, NULL != filename3);
26✔
1606

1607
            if (NULL != appdir && NULL != filename3) {
26✔
1608
                /* should yield the same result as _sir_getappdir(). */
1609
                char* _dirname = _sir_getdirname(filename3);
25✔
1610
                TEST_MSG("_sir_getdirname: '%s'", PRN_STR(_dirname));
25✔
1611

1612
                _sir_eqland(pass, 0 == strncmp(filename, appdir, strnlen(appdir, SIR_MAXPATH)));
25✔
1613
                _sir_eqland(pass, NULL != _dirname &&
25✔
1614
                    0 == strncmp(filename, _dirname, strnlen(_dirname, SIR_MAXPATH)));
1615
            }
1616

1617
            _sir_safefree(&appdir);
26✔
1618
            _sir_safefree(&filename);
26✔
1619
            _sir_safefree(&filename2);
26✔
1620
            _sir_safefree(&filename3);
26✔
1621
        }
1622

1623
        _sir_safefree(&cwd);
29✔
1624
    }
1625

1626
    /* this next section doesn't really yield any useful boolean pass/fail
1627
     * information, but could be helpful to review manually. */
1628
    char* dubious_dirnames[] = {
29✔
1629
#if !defined(__WIN__)
1630
        "/foo",
1631
        "/foo/",
1632
        "/foo/bar",
1633
        "/foo/bar/bad:filename",
1634
        "/",
1635
        ""
1636
#else /* __WIN__ */
1637
        "C:\\foo",
1638
        "C:\\foo\\",
1639
        "C:\\foo\\bar",
1640
        "C:\\foo\\bar\\bad:>filename",
1641
        "C:\\",
1642
        "//network-share/myfolder",
1643
        ""
1644
#endif
1645
    };
1646

1647
    for (size_t n = 0; n < _sir_countof(dubious_dirnames); n++) {
203✔
1648
        char* tmp = strndup(dubious_dirnames[n], strnlen(dubious_dirnames[n], SIR_MAXPATH));
174✔
1649
        if (NULL != tmp) {
174✔
1650
            TEST_MSG("_sir_getdirname(" SIR_WHITE("'%s'") ") = " SIR_WHITE("'%s'") "",
168✔
1651
                tmp, _sir_getdirname(tmp));
1652
            _sir_safefree(&tmp);
168✔
1653
        }
1654
    }
1655

1656
    char* dubious_filenames[] = {
29✔
1657
#if !defined(__WIN__)
1658
        "foo/bar/file-or-directory",
1659
        "/foo/bar/file-or-directory",
1660
        "/foo/bar/illegal:filename",
1661
        "/",
1662
        ""
1663
#else /* __WIN__ */
1664
        "foo\\bar\\file.with.many.full.stops",
1665
        "C:\\foo\\bar\\poorly-renamed.txt.pdf",
1666
        "C:\\foo\\bar\\illegal>filename.txt",
1667
        "C:\\",
1668
        "\\Program Files\\foo.bar",
1669
        ""
1670
#endif
1671
    };
1672

1673
    for (size_t n = 0; n < _sir_countof(dubious_filenames); n++) {
174✔
1674
        char* tmp = strndup(dubious_filenames[n], strnlen(dubious_filenames[n], SIR_MAXPATH));
145✔
1675
        if (NULL != tmp) {
145✔
1676
            TEST_MSG("_sir_getbasename(" SIR_WHITE("'%s'") ") = " SIR_WHITE("'%s'") "",
140✔
1677
                tmp, _sir_getbasename(tmp));
1678
            _sir_safefree(&tmp);
140✔
1679
        }
1680
    }
1681

1682
    /* absolute/relative paths. */
1683
    static const struct {
1684
        const char* const path;
1685
        bool abs;
1686
    } abs_or_rel_paths[] = {
1687
        {"this/is/relative", false},
1688
        {"relative", false},
1689
        {"./relative", false},
1690
        {"../../relative", false},
1691
#if !defined(__WIN__)
1692
        {"/usr/local/bin", true},
1693
        {"/", true},
1694
        {"/home/foo/.config", true},
1695
        {"~/.config", true}
1696
#else /* __WIN__ */
1697
        {"D:\\absolute", true},
1698
        {"C:\\Program Files\\FooBar", true},
1699
        {"C:\\", true},
1700
        {"\\absolute", true},
1701
#endif
1702
    };
1703

1704
    for (size_t n = 0; n < _sir_countof(abs_or_rel_paths); n++) {
261✔
1705
        bool relative = false;
232✔
1706
        bool ret      = _sir_ispathrelative(abs_or_rel_paths[n].path, &relative);
232✔
1707

1708
        if (relative == abs_or_rel_paths[n].abs) {
232✔
1709
            pass = false;
×
1710
            TEST_MSG(SIR_RED("_sir_ispathrelative('%s') = %s"), abs_or_rel_paths[n].path,
×
1711
                relative ? "true" : "false");
1712
        } else {
1713
            TEST_MSG(SIR_GREEN("_sir_ispathrelative('%s') = %s"), abs_or_rel_paths[n].path,
232✔
1714
                relative ? "true" : "false");
1715
        }
1716

1717
        _sir_eqland(pass, ret);
232✔
1718
        if (!ret) {
232✔
1719
            bool unused = print_test_error(false, false);
×
1720
            SIR_UNUSED(unused);
1721
        }
1722
    }
1723

1724
    /* file existence. */
1725
    static const struct {
1726
        const char* const path;
1727
        bool exists;
1728
    } real_or_not[] = {
1729
        {"../foobarbaz", false},
1730
        {"foobarbaz", false},
1731
#if !defined(__WIN__)
1732
        {"/", true},
1733
# if !defined(__HAIKU__)
1734
        {"/usr/bin", true},
1735
# else
1736
        {"/bin", true},
1737
# endif
1738
        {"/dev", true},
1739
#else /* __WIN__ */
1740
        {"C:\\Windows", true},
1741
        {"C:\\Program Files", true},
1742
        {"\\", true},
1743
        {".\\", true},
1744
        {"..\\", true},
1745
#endif
1746
        {"../../LICENSES/MIT.txt", true},
1747
        {"../../msvs/libsir.sln", true},
1748
        {"./", true},
1749
        {"../", true},
1750
        {"file.exists", true}
1751
    };
1752

1753
    for (size_t n = 0; n < _sir_countof(real_or_not); n++) {
319✔
1754
        bool exists = false;
290✔
1755
        bool ret    = _sir_pathexists(real_or_not[n].path, &exists, SIR_PATH_REL_TO_APP);
290✔
1756

1757
        if (exists != real_or_not[n].exists) {
290✔
1758
            pass = false;
29✔
1759
            TEST_MSG(SIR_RED("_sir_pathexists('%s') = %s"), real_or_not[n].path,
29✔
1760
                exists ? "true" : "false");
1761
        } else {
1762
            TEST_MSG(SIR_GREEN("_sir_pathexists('%s') = %s"), real_or_not[n].path,
261✔
1763
                exists ? "true" : "false");
1764
        }
1765

1766
        _sir_eqland(pass, ret);
290✔
1767
        if (!ret) {
290✔
1768
            bool unused = print_test_error(false, false);
38✔
1769
            SIR_UNUSED(unused);
1770
        }
1771
    }
1772

1773
    /* checking file descriptors. */
1774
    static int bad_fds[] = {
1775
        0,
1776
        1,
1777
        2,
1778
        1234
1779
    };
1780

1781
    if (get_wineversion()) {
29✔
1782
        bad_fds[3] = 0;
×
1783
    }
1784

1785
    for (size_t n = 0; n < _sir_countof(bad_fds); n++) {
145✔
1786
        if (_sir_validfd(bad_fds[n])) {
116✔
1787
            pass = false;
×
1788
            TEST_MSG(SIR_RED("_sir_validfd(%d) = true"), bad_fds[n]);
×
1789
        } else {
1790
            TEST_MSG(SIR_GREEN("_sir_validfd(%d) = false"), bad_fds[n]);
116✔
1791
        }
1792
    }
1793

1794
    FILE* f = NULL;
29✔
1795
    bool ret = _sir_openfile(&f, "file.exists", "r", SIR_PATH_REL_TO_APP);
29✔
1796
    if (!ret) {
29✔
1797
        pass = false;
5✔
1798
        HANDLE_OS_ERROR(true, "fopen(%s) failed!", "file.exists");
5✔
1799
    } else {
1800
        int fd = fileno(f);
24✔
1801
        if (!_sir_validfd(fd)) {
24✔
1802
            pass = false;
×
1803
            TEST_MSG(SIR_RED("_sir_validfd(%d) = false"), fd);
×
1804
        } else {
1805
            TEST_MSG(SIR_GREEN("_sir_validfd(%d) = true"), fd);
20✔
1806
        }
1807
    }
1808

1809
    _sir_safefclose(&f);
29✔
1810

1811
    _sir_eqland(pass, sir_cleanup());
29✔
1812
    return PRINT_RESULT_RETURN(pass);
29✔
1813
}
1814

1815
bool sirtest_squelchspam(void) {
28✔
1816
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
1817
    bool pass = si_init;
24✔
1818

1819
    static const size_t alternate  = 50;
1820
    static const size_t sequence[] = {
1821
        1000, /* non-repeating messages. */
1822
        1000, /* repeating messages. */
1823
        1000, /* alternating repeating and non-repeating messages. */
1824
        100   /* repeating messages, but on different levels. */
1825
    };
1826

1827
    sir_time timer;
1828
    sir_timer_start(&timer);
28✔
1829

1830
    TEST_MSG(SIR_BLUE("%zu non-repeating messages..."), sequence[0]);
24✔
1831

1832
    for (size_t n = 0, ascii_idx = 33; n < sequence[0]; n++, ascii_idx++) {
28,028✔
1833
        _sir_eqland(pass, sir_debug("%c%c a non-repeating message", (char)ascii_idx,
28,000✔
1834
            (char)ascii_idx + 1));
1835

1836
        if (ascii_idx == 125)
28,000✔
1837
            ascii_idx = 33;
240✔
1838
    }
1839

1840
    TEST_MSG(SIR_BLUE("%zu repeating messages..."), sequence[1]);
24✔
1841

1842
    for (size_t n = 0; n < sequence[1]; n++) {
28,028✔
1843
        bool ret = sir_debug("a repeating message");
28,000✔
1844

1845
        if (n >= SIR_SQUELCH_THRESHOLD - 1)
28,000✔
1846
            _sir_eqland(pass, !ret);
27,888✔
1847
        else
1848
            _sir_eqland(pass, ret);
112✔
1849
    }
1850

1851
    TEST_MSG(SIR_BLUE("%zu alternating repeating and non-repeating messages..."),
24✔
1852
        sequence[2]);
1853

1854
    bool repeating   = false;
24✔
1855
    size_t counter   = 0;
24✔
1856
    size_t repeat_id = 0;
24✔
1857
    for (size_t n = 0, ascii_idx = 33; n < sequence[2]; n++, counter++, ascii_idx++) {
28,028✔
1858
        if (!repeating) {
28,000✔
1859
            _sir_eqland(pass, sir_debug("%c%c a non-repeating message", (char)ascii_idx,
14,028✔
1860
                (char)ascii_idx + 1));
1861
        } else {
1862
            bool ret = sir_debug("%zu a repeating message", repeat_id);
13,972✔
1863

1864
            if (counter - 1 >= SIR_SQUELCH_THRESHOLD - 1)
13,972✔
1865
                _sir_eqland(pass, !ret);
12,852✔
1866
            else
1867
                _sir_eqland(pass, ret);
1,120✔
1868
        }
1869

1870
        if (counter == alternate) {
27,840✔
1871
            repeating = !repeating;
532✔
1872
            counter = 0;
456✔
1873
            repeat_id++;
532✔
1874
        }
1875

1876
        if (ascii_idx == 125)
28,000✔
1877
            ascii_idx = 33;
240✔
1878
    }
1879

1880
    TEST_MSG(SIR_BLUE("%zu repeating messages, but on different levels..."), sequence[3]);
24✔
1881

1882
    for (size_t n = 0; n < sequence[3]; n++) {
2,828✔
1883
        if (n % 2 == 0)
2,800✔
1884
            _sir_eqland(pass, sir_debug("a repeating message"));
1,400✔
1885
        else
1886
            _sir_eqland(pass, sir_info("a repeating message"));
1,400✔
1887
    }
1888

1889
    _sir_eqland(pass, sir_cleanup());
28✔
1890
    return PRINT_RESULT_RETURN(pass);
28✔
1891
}
1892

1893
bool sirtest_pluginloader(void) {
28✔
1894
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
1895
    bool pass = si_init;
24✔
1896

1897
#if !defined(__WIN__)
1898
# define PLUGIN_EXT "so"
1899
#else
1900
# define PLUGIN_EXT "dll"
1901
#endif
1902

1903
    static const char* plugin1 = "build/lib/plugin_dummy."PLUGIN_EXT;
1904
    static const char* plugin2 = "build/lib/plugin_dummy_bad1."PLUGIN_EXT;
1905
    static const char* plugin3 = "build/lib/plugin_dummy_bad2."PLUGIN_EXT;
1906
    static const char* plugin4 = "build/lib/plugin_dummy_bad3."PLUGIN_EXT;
1907
    static const char* plugin5 = "build/lib/plugin_dummy_bad4."PLUGIN_EXT;
1908
    static const char* plugin6 = "build/lib/plugin_dummy_bad5."PLUGIN_EXT;
1909
    static const char* plugin7 = "build/lib/plugin_dummy_bad6."PLUGIN_EXT;
1910
    static const char* plugin8 = "build/lib/i_dont_exist."PLUGIN_EXT;
1911

1912
#if defined(SIR_NO_PLUGINS)
1913
    SIR_UNUSED(plugin2);
1914
    SIR_UNUSED(plugin3);
1915
    SIR_UNUSED(plugin4);
1916
    SIR_UNUSED(plugin5);
1917
    SIR_UNUSED(plugin6);
1918
    SIR_UNUSED(plugin7);
1919
    SIR_UNUSED(plugin8);
1920

1921
    TEST_MSG_0("SIR_NO_PLUGINS is defined; expecting calls to fail");
1✔
1922

1923
    TEST_MSG("loading good plugin: '%s'...", plugin1);
1✔
1924
    /* load a valid, well-behaved plugin. */
1925
    sirpluginid id = sir_loadplugin(plugin1);
1✔
1926
    _sir_eqland(pass, 0 == id);
1✔
1927

1928
    if (pass)
1✔
1929
        PRINT_EXPECTED_ERROR();
1✔
1930

1931
    TEST_MSG("unloading good plugin: '%s'...", plugin1);
1✔
1932
    /* also try the unload function. */
1933
    _sir_eqland(pass, !sir_unloadplugin(id));
1✔
1934

1935
    if (pass)
1✔
1936
        PRINT_EXPECTED_ERROR();
1✔
1937
#else
1938
    /* load a valid, well-behaved plugin. */
1939
    TEST_MSG("loading good plugin: '%s'...", plugin1);
27✔
1940
    sirpluginid id = sir_loadplugin(plugin1);
27✔
1941
    _sir_eqland(pass, 0 != id);
27✔
1942

1943
    (void)print_test_error(pass, pass);
27✔
1944

1945
    _sir_eqland(pass, sir_info("this message will be dispatched to the plugin."));
27✔
1946
    _sir_eqland(pass, sir_warn("this message will *not* be dispatched to the plugin."));
27✔
1947

1948
    /* re-loading the same plugin should fail. */
1949
    TEST_MSG("loading duplicate plugin: '%s'...", plugin1);
27✔
1950
    sirpluginid badid = sir_loadplugin(plugin1);
27✔
1951
    _sir_eqland(pass, 0 == badid);
27✔
1952

1953
    (void)print_test_error(pass, pass);
27✔
1954

1955
    /* the following are all invalid or misbehaved, and should all fail. */
1956
    TEST_MSG("loading bad plugin: '%s'...", plugin2);
27✔
1957
    badid = sir_loadplugin(plugin2);
27✔
1958
    _sir_eqland(pass, 0 == badid);
27✔
1959

1960
    (void)print_test_error(pass, pass);
27✔
1961

1962
    TEST_MSG("loading bad plugin: '%s'...", plugin3);
27✔
1963
    badid = sir_loadplugin(plugin3);
27✔
1964
    _sir_eqland(pass, 0 == badid);
27✔
1965

1966
    (void)print_test_error(pass, pass);
27✔
1967

1968
    TEST_MSG("loading bad plugin: '%s'...", plugin4);
27✔
1969
    badid = sir_loadplugin(plugin4);
27✔
1970
    _sir_eqland(pass, 0 == badid);
27✔
1971

1972
    (void)print_test_error(pass, pass);
27✔
1973

1974
    TEST_MSG("loading bad plugin: '%s'...", plugin5);
27✔
1975
    badid = sir_loadplugin(plugin5);
27✔
1976
    _sir_eqland(pass, 0 == badid);
27✔
1977

1978
    (void)print_test_error(pass, pass);
27✔
1979

1980
    TEST_MSG("loading bad plugin: '%s'...", plugin6);
27✔
1981
    badid = sir_loadplugin(plugin6);
27✔
1982
    _sir_eqland(pass, 0 == badid);
27✔
1983

1984
    (void)print_test_error(pass, pass);
27✔
1985

1986
    TEST_MSG("loading bad plugin: '%s'...", plugin7);
27✔
1987
    badid = sir_loadplugin(plugin7);
27✔
1988
    _sir_eqland(pass, 0 != badid); /* this one should load, just return false from write */
27✔
1989

1990
    _sir_eqland(pass, !sir_info("should fail; a plugin failed to process the message."));
27✔
1991

1992
    (void)print_test_error(pass, pass);
27✔
1993

1994
    TEST_MSG("loading nonexistent plugin: '%s'...", plugin8);
27✔
1995
    badid = sir_loadplugin(plugin8);
27✔
1996
    _sir_eqland(pass, 0 == badid);
27✔
1997

1998
    (void)print_test_error(pass, pass);
27✔
1999

2000
    /* unload the good plugin manually. */
2001
    TEST_MSG("unloading good plugin: '%s'...", plugin1);
27✔
2002
    _sir_eqland(pass, sir_unloadplugin(id));
27✔
2003

2004
    (void)print_test_error(pass, pass);
27✔
2005

2006
    /* try to unload the plugin again. */
2007
    TEST_MSG("unloading already unloaded plugin '%s'...", plugin1);
27✔
2008
    _sir_eqland(pass, !sir_unloadplugin(id));
27✔
2009

2010
    (void)print_test_error(pass, pass);
27✔
2011

2012
    /* test bad paths. */
2013
    TEST_MSG_0("trying to load plugin with NULL path...");
23✔
2014
    badid = sir_loadplugin(NULL);
27✔
2015
    _sir_eqland(pass, 0 == badid);
27✔
2016

2017
    (void)print_test_error(pass, pass);
27✔
2018
#endif
2019
    _sir_eqland(pass, sir_cleanup());
28✔
2020
    return PRINT_RESULT_RETURN(pass);
28✔
2021
}
2022

2023
bool sirtest_stringutils(void) {
28✔
2024
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
2025
    bool pass = si_init;
24✔
2026

2027
    char str[] = "Kneel  \f \n  before  \t \r \v  Zod!?";
28✔
2028

2029
    TEST_MSG_0(SIR_WHITEB("--- valid string utility usage ---"));
24✔
2030

2031
    _sir_eqland(pass, _sir_strsqueeze(str) && 0 == strncmp(str, "Kneel before Zod!?", 18));
28✔
2032
    TEST_MSG("_sir_strsqueeze:            '%s'", str);
24✔
2033

2034
    _sir_eqland(pass, _sir_strremove(str, "!") && 0 == strncmp(str, "Kneel before Zod?", 17));
28✔
2035
    TEST_MSG("_sir_strremove(\"!\"):        '%s'", str);
24✔
2036

2037
    _sir_eqland(pass, _sir_strreplace(str, '?', '.') && 0 == strncmp(str, "Kneel before Zod.", 17));
28✔
2038
    TEST_MSG("_sir_strreplace(\"?\", \".\"):  '%s'", str);
24✔
2039

2040
    _sir_eqland(pass, 1 == _sir_strcreplace(str, '.', '!', 1) && 0 == strncmp(str, "Kneel before Zod!", 17));
28✔
2041
    TEST_MSG("_sir_strcreplace(\".\", \"!\"): '%s'", str);
24✔
2042

2043
    _sir_eqland(pass, _sir_strredact(str, "e", '*') && 0 == strncmp(str, "Kn**l b*for* Zod!", 17));
28✔
2044
    TEST_MSG("_sir_strredact(\"e\", \"*\"):   '%s'", str);
24✔
2045

2046
    _sir_eqland(pass, _sir_strredact(str, "X", 'Y') && 0 == strncmp(str, "Kn**l b*for* Zod!", 17));
28✔
2047
    TEST_MSG("_sir_strredact(\"X\", \"Y\"):   '%s'", str);
24✔
2048

2049
    PASSFAIL_MSG(pass, "\t--- valid string utility usage: %s ---" SIR_EOL SIR_EOL, PRN_PASS(pass));
28✔
2050

2051
    TEST_MSG_0(SIR_WHITEB("--- invalid string utility usage - NULL pointer ---"));
24✔
2052

2053
    TEST_MSG_0("_sir_strsqueeze:  NULL pointer");
24✔
2054
    _sir_eqland(pass, !_sir_strsqueeze(NULL));
28✔
2055

2056
    TEST_MSG_0("_sir_strremove:   NULL pointer");
24✔
2057
    _sir_eqland(pass, !_sir_strremove(NULL, "sub"));
28✔
2058

2059
    TEST_MSG_0("_sir_strreplace:  NULL pointer");
24✔
2060
    _sir_eqland(pass, !_sir_strreplace(NULL, 'c', 'n'));
28✔
2061

2062
    TEST_MSG_0("_sir_strcreplace: NULL pointer");
24✔
2063
    _sir_eqland(pass, !_sir_strcreplace(NULL, 'c', 'n', -1));
28✔
2064

2065
    TEST_MSG_0("_sir_strredact:   NULL pointer");
24✔
2066
    _sir_eqland(pass, !_sir_strredact(NULL, "s", '*'));
28✔
2067

2068
    PASSFAIL_MSG(pass, "\t--- invalid string utility usage - NULL pointer: %s ---" SIR_EOL SIR_EOL, PRN_PASS(pass));
24✔
2069

2070
    TEST_MSG_0(SIR_WHITEB("--- invalid string utility usage - bad parameters ---"));
24✔
2071

2072
    TEST_MSG_0("_sir_strremove:   bad parameter \"sub\"");
24✔
2073
    _sir_eqland(pass, _sir_strremove(str, NULL));
28✔
2074

2075
    TEST_MSG_0("_sir_strreplace:  bad parameter 'c'");
24✔
2076
    _sir_eqland(pass, _sir_strreplace(str, 0, 'n'));
28✔
2077

2078
    TEST_MSG_0("_sir_strreplace:  bad parameter 'n'");
24✔
2079
    _sir_eqland(pass, _sir_strreplace(str, 'c', 0));
28✔
2080

2081
    TEST_MSG_0("_sir_strcreplace: bad parameter 'c'");
24✔
2082
    _sir_eqland(pass, !_sir_strcreplace(str, 0, 'n', -1));
28✔
2083

2084
    TEST_MSG_0("_sir_strcreplace: bad parameter 'n'");
24✔
2085
    _sir_eqland(pass, !_sir_strcreplace(str, 'c', 0, -1));
28✔
2086

2087
    TEST_MSG_0("_sir_strcreplace: bad parameter 'max'");
24✔
2088
    _sir_eqland(pass, !_sir_strcreplace(str, 'c', 'n', 0));
28✔
2089

2090
    TEST_MSG_0("_sir_strredact:   bad parameter \"sub\"");
24✔
2091
    _sir_eqland(pass, _sir_strredact(str, NULL, '*'));
28✔
2092

2093
    TEST_MSG_0("_sir_strredact:   bad parameter 'c'");
24✔
2094
    _sir_eqland(pass, _sir_strredact(str, "sub", 0));
28✔
2095

2096
    PASSFAIL_MSG(pass, "\t--- invalid string utility usage - bad parameters: %s ---" SIR_EOL, PRN_PASS(pass));
24✔
2097

2098
    _sir_eqland(pass, sir_cleanup());
28✔
2099
    return PRINT_RESULT_RETURN(pass);
28✔
2100
}
2101

2102
bool sirtest_getcpucount(void) {
28✔
2103
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
2104
    bool pass = si_init;
24✔
2105

2106
    TEST_MSG_0("checking processor counting function...");
24✔
2107

2108
    const long cpus = _sir_nprocs_test();
28✔
2109
    _sir_eqland(pass, 0 < cpus);
28✔
2110

2111
    TEST_MSG("processor(s) detected: %ld", cpus);
24✔
2112

2113
    _sir_eqland(pass, sir_cleanup());
28✔
2114
    return PRINT_RESULT_RETURN(pass);
28✔
2115
}
2116

2117
bool sirtest_getversioninfo(void) {
28✔
2118
    INIT(si, SIRL_ALL, 0, 0, 0);
28✔
2119
    bool pass = si_init;
24✔
2120

2121
    TEST_MSG_0("checking version retrieval functions...");
24✔
2122

2123
    const char* str = sir_getversionstring();
28✔
2124
    _sir_eqland(pass, _sir_validstrnofail(str));
28✔
2125

2126
    TEST_MSG("version as string: '%s'", _SIR_PRNSTR(str));
28✔
2127

2128
    uint32_t hex = sir_getversionhex();
28✔
2129
    _sir_eqland(pass, 0 != hex);
28✔
2130

2131
    TEST_MSG("version as hex: 0x%08"PRIx32"", hex);
24✔
2132

2133
    bool prerel = sir_isprerelease();
28✔
2134
    TEST_MSG("prerelease: %s", prerel ? "true" : "false");
28✔
2135

2136
    _sir_eqland(pass, sir_cleanup());
28✔
2137
    return PRINT_RESULT_RETURN(pass);
28✔
2138
}
2139

2140
enum {
2141
    NUM_THREADS = 4
2142
};
2143

2144
static bool threadpool_pseudojob(void* arg) {
208✔
2145
    char thread_name[SIR_MAXPID] = {0};
208✔
2146

2147
    _sir_snprintf_trunc(thread_name, SIR_MAXPID, "pool.%p", arg);
208✔
2148
    (void)_sir_setthreadname(thread_name);
208✔
2149

2150
    (void)sir_debug("start of pseudo job that does nothing (arg: %p)", arg);
207✔
2151
    sir_sleep_msec(1000);
208✔
2152
    (void)sir_debug("end of pseudo job that does nothing (arg: %p)", arg);
205✔
2153

2154
    return true;
208✔
2155
}
2156

2157
bool sirtest_threadpool(void) {
28✔
2158
    INIT(si, SIRL_ALL, SIRO_NOTIME | SIRO_NOHOST | SIRO_NONAME, 0, 0);
28✔
2159
    bool pass = si_init;
24✔
2160

2161
    static const size_t num_jobs = 30;
2162
    sir_threadpool* pool         = NULL;
28✔
2163

2164
    _sir_eqland(pass, _sir_threadpool_create(&pool, NUM_THREADS));
28✔
2165
    if (pass) {
24✔
2166
        /* dispatch a whole bunch of jobs. */
2167
        for (size_t n = 0; n < num_jobs; n++) {
806✔
2168
            sir_threadpool_job* job = calloc(1, sizeof(sir_threadpool_job));
780✔
2169
            _sir_eqland(pass, NULL != job);
780✔
2170
            if (job) {
780✔
2171
                job->fn = &threadpool_pseudojob;
780✔
2172
                job->data = (void*)(n + 1);
780✔
2173
                _sir_eqland(pass, _sir_threadpool_add_job(pool, job));
780✔
2174
                _sir_eqland(pass, sir_info("dispatched job (fn: %"PRIxPTR", data: %p)",
780✔
2175
                    (uintptr_t)job->fn, job->data));
2176
            }
2177
        }
2178

2179
        sir_sleep_msec(1000);
26✔
2180

2181
        _sir_eqland(pass, sir_info("destroying thread pool..."));
26✔
2182
        _sir_eqland(pass, _sir_threadpool_destroy(&pool));
26✔
2183
    }
2184

2185
    _sir_eqland(pass, sir_cleanup());
28✔
2186
    return PRINT_RESULT_RETURN(pass);
28✔
2187
}
2188

2189
#if !defined(__WIN__)
2190
static void* threadrace_thread(void* arg);
2191
#else /* __WIN__ */
2192
static unsigned __stdcall threadrace_thread(void* arg);
2193
#endif
2194

2195
typedef struct {
2196
    char log_file[SIR_MAXPATH];
2197
    bool pass;
2198
} thread_args;
2199

2200
bool sirtest_threadrace(void) {
28✔
2201
#if !defined(__WIN__)
2202
    pthread_t thrds[NUM_THREADS] = {0};
28✔
2203
#else /* __WIN__ */
2204
    uintptr_t thrds[NUM_THREADS] = {0};
2205
#endif
2206

2207
    INIT_N(si, SIRL_DEFAULT, SIRO_NOPID | SIRO_NOHOST, 0, 0, "thread-race");
28✔
2208
    bool pass           = si_init;
24✔
2209
    bool any_created    = false;
24✔
2210
    size_t last_created = 0;
24✔
2211

2212
    thread_args* heap_args = (thread_args*)calloc(NUM_THREADS, sizeof(thread_args));
28✔
2213
    if (!heap_args) {
28✔
2214
        HANDLE_OS_ERROR(true, "calloc() %zu bytes failed!", NUM_THREADS * sizeof(thread_args));
1✔
2215
        return false;
1✔
2216
    }
2217

2218
    for (size_t n = 0; n < NUM_THREADS; n++) {
131✔
2219
        if (!pass)
105✔
2220
            break;
×
2221

2222
        heap_args[n].pass = true;
105✔
2223
        (void)snprintf(heap_args[n].log_file, SIR_MAXPATH,
105✔
2224
            MAKE_LOG_NAME("multi-thread-race-%zu.log"), n);
2225

2226
#if !defined(__WIN__)
2227
        int create = pthread_create(&thrds[n], NULL, threadrace_thread, (void*)&heap_args[n]);
105✔
2228
        if (0 != create) {
105✔
2229
            errno = create;
1✔
2230
            HANDLE_OS_ERROR(true, "pthread_create() for thread #%zu failed!", n + 1);
1✔
2231
#else /* __WIN__ */
2232
        thrds[n] = _beginthreadex(NULL, 0, threadrace_thread, (void*)&heap_args[n], 0, NULL);
2233
        if (0 == thrds[n]) {
2234
            HANDLE_OS_ERROR(true, "_beginthreadex() for thread #%zu failed!", n + 1);
2235
#endif
2236
            pass = false;
1✔
2237
            break;
1✔
2238
        }
2239

2240
        last_created = n;
88✔
2241
        any_created  = true;
88✔
2242
    }
2243

2244
    if (any_created) {
27✔
2245
        for (size_t j = 0; j < last_created + 1; j++) {
130✔
2246
            bool joined = true;
88✔
2247
            TEST_MSG("waiting for thread %zu/%zu...", j + 1, last_created + 1);
104✔
2248
#if !defined(__WIN__)
2249
            int join = pthread_join(thrds[j], NULL);
104✔
2250
            if (0 != join) {
104✔
2251
                joined = false;
×
2252
                errno  = join;
×
2253
                HANDLE_OS_ERROR(true, "pthread_join() for thread #%zu failed!", j + 1);
×
2254
            }
2255
#else /* __WIN__ */
2256
            DWORD wait = WaitForSingleObject((HANDLE)thrds[j], INFINITE);
2257
            if (WAIT_OBJECT_0 != wait) {
2258
                joined = false;
2259
                HANDLE_OS_ERROR(false, "WaitForSingleObject() for thread #%zu (%p) failed!", j + 1,
2260
                    (HANDLE)thrds[j]);
2261
            }
2262
#endif
2263
            _sir_eqland(pass, joined);
88✔
2264
            if (joined) {
88✔
2265
                TEST_MSG("thread %zu/%zu joined", j + 1, last_created + 1);
88✔
2266

2267
                _sir_eqland(pass, heap_args[j].pass);
104✔
2268
                if (heap_args[j].pass)
104✔
2269
                    TEST_MSG(SIR_GREEN("thread #%zu returned pass = true"), j + 1);
88✔
2270
                else
2271
                    TEST_MSG(SIR_RED("thread #%zu returned pass = false!"), j + 1);
×
2272
            }
2273
        }
2274
    }
2275

2276
    _sir_safefree(&heap_args);
27✔
2277

2278
    _sir_eqland(pass, sir_cleanup());
27✔
2279
    return PRINT_RESULT_RETURN(pass);
27✔
2280
}
2281

2282
#if !defined(__WIN__)
2283
static void* threadrace_thread(void* arg) {
104✔
2284
#else /* __WIN__ */
2285
unsigned __stdcall threadrace_thread(void* arg) {
2286
#endif
2287
    pid_t threadid       = _sir_gettid();
104✔
2288
    thread_args* my_args = (thread_args*)arg;
88✔
2289

2290
    rmfile(my_args->log_file, cl_cfg.leave_logs);
104✔
2291
    sirfileid id = sir_addfile(my_args->log_file, SIRL_ALL, SIRO_MSGONLY);
104✔
2292

2293
    if (0U == id) {
104✔
2294
        bool unused = print_test_error(false, false);
8✔
2295
        SIR_UNUSED(unused);
2296
#if !defined(__WIN__)
2297
        return NULL;
8✔
2298
#else /* __WIN__ */
2299
        return 0;
2300
#endif
2301
    }
2302

2303
    TEST_MSG("hi, i'm thread (id: " SIR_TIDFORMAT "), logging to: '%s'...",
80✔
2304
            PID_CAST threadid, my_args->log_file);
2305

2306
#if !defined(DUMA)
2307
# if !defined(__EMSCRIPTEN__)
2308
#  define NUM_ITERATIONS 400
2309
# else
2310
#  define NUM_ITERATIONS 200
2311
# endif
2312
#else
2313
# define NUM_ITERATIONS 100
2314
#endif
2315

2316
    for (size_t n = 0; n < NUM_ITERATIONS; n++) {
38,495✔
2317
        /* choose a random level, and colors. */
2318
        sir_textcolor fg = SIRTC_DEFAULT;
32,000✔
2319
        sir_textcolor bg = SIRTC_DEFAULT;
32,000✔
2320

2321
        if (n % 2 == 0) {
38,399✔
2322
            fg = SIRTC_CYAN;
16,000✔
2323
            bg = SIRTC_BLACK;
16,000✔
2324
            (void)sir_debug("log message #%zu", n);
19,199✔
2325
        } else {
2326
            fg = SIRTC_BLACK;
16,000✔
2327
            bg = SIRTC_CYAN;
16,000✔
2328
            (void)sir_info("log message #%zu", n);
19,200✔
2329
        }
2330

2331
        /* sometimes remove and re-add the log file, and set some options/styles.
2332
         * other times, just set different options/styles. */
2333
        uint32_t rnd = (uint32_t)(n + threadid);
38,396✔
2334
        if (getrand_bool(rnd > 1U ? rnd : 1U)) {
38,396✔
2335
            my_args->pass = print_test_error(sir_remfile(id), false);
19,486✔
2336
            my_args->pass = print_test_error(0 != sir_addfile(my_args->log_file,
19,491✔
2337
                SIRL_ALL, SIRO_MSGONLY), false);
2338

2339
            bool test = sir_settextstyle(SIRL_DEBUG, SIRTA_EMPH, fg, bg) &&
36,503✔
2340
                        sir_settextstyle(SIRL_INFO, SIRTA_BOLD, fg, bg);
17,011✔
2341
            my_args->pass = print_test_error(test, false);
19,492✔
2342

2343
            test = sir_stdoutopts(SIRO_NONAME | SIRO_NOHOST | SIRO_NOMSEC);
19,492✔
2344
            my_args->pass = print_test_error(test, false);
19,492✔
2345
        } else {
2346
            bool test = sir_settextstyle(SIRL_DEBUG, SIRTA_ULINE, fg, bg) &&
35,493✔
2347
                        sir_settextstyle(SIRL_INFO, SIRTA_NORMAL, fg, bg);
16,589✔
2348
            my_args->pass = print_test_error(test, false);
18,907✔
2349

2350
            test = sir_fileopts(id, SIRO_NOPID | SIRO_NOHOST);
18,906✔
2351
            my_args->pass = print_test_error(test, false);
18,904✔
2352

2353
            test = sir_stdoutopts(SIRO_NOTIME | SIRO_NOLEVEL);
18,904✔
2354
            my_args->pass = print_test_error(test, false);
18,908✔
2355
        }
2356

2357
        if (!my_args->pass)
38,399✔
2358
            break;
×
2359
    }
2360

2361
    my_args->pass = print_test_error(sir_remfile(id), false);
96✔
2362

2363
    rmfile(my_args->log_file, cl_cfg.leave_logs);
96✔
2364

2365
#if !defined(__WIN__)
2366
    return NULL;
96✔
2367
#else /* __WIN__ */
2368
    return 0U;
2369
#endif
2370
}
2371

2372
/*
2373
bool sirtest_XXX(void) {
2374
    INIT(si, SIRL_ALL, 0, 0, 0);
2375
    bool pass = si_init;
2376

2377
    _sir_eqland(pass, sir_cleanup());
2378
    return PRINT_RESULT_RETURN(pass);
2379
}
2380
*/
2381

2382
#if defined(SIR_OS_LOG_ENABLED)
2383
void os_log_parent_activity(void* ctx) {
2384
    (void)sir_debug("confirming with ground control that we are a go...");
2385
    (void)sir_info("all systems go; initiating launch sequence");
2386
    (void)sir_warn("getting some excessive vibration here");
2387
    (void)sir_info("safely reached escape velocity. catch you on the flip side");
2388
    (void)sir_info("(3 days later) we have landed on the lunar surface");
2389
    (void)sir_notice("beginning rock counting...");
2390

2391
    os_activity_t parent = (os_activity_t)ctx;
2392
    os_activity_t child = os_activity_create("counting moon rocks", parent, //-V530
2393
        OS_ACTIVITY_FLAG_DEFAULT);
2394

2395
    float rock_count = 0.0f;
2396
    os_activity_apply_f(child, (void*)&rock_count, os_log_child_activity);
2397
    (void)sir_info("astronauts safely back on board. official count: ~%.02f moon rocks",
2398
        (double)rock_count);
2399
}
2400

2401
void os_log_child_activity(void* ctx) {
2402
    (void)sir_info("there are a lot of rocks here; we're going to be here a while");
2403

2404
    for (size_t n = 0; n < 10; n++) {
2405
        (void)sir_info("counting rocks in sector %zu...", n);
2406
    }
2407

2408
    float* rock_count = (float*)ctx;
2409
    *rock_count = 1e12f;
2410
    (void)sir_info("all sectors counted; heading back to the lunar lander");
2411
}
2412
#endif
2413

2414
/* ========================== end tests ========================== */
2415

2416
bool filter_error(bool pass, uint16_t err) {
1,928✔
2417
    if (!pass) {
1,928✔
2418
        char msg[SIR_MAXERROR] = {0};
1,087✔
2419
        if (sir_geterror(msg) != err)
1,087✔
2420
            return false;
×
2421
    }
2422
    return true;
1,608✔
2423
}
2424

2425
char *get_wineversion(void) {
58✔
2426
#if !defined(__WIN__)
2427
    return NULL;
58✔
2428
#else /* __WIN__ */
2429
    typedef char* (__stdcall *get_wine_ver_proc)(void);
2430
    static get_wine_ver_proc _p_wine_get_version = NULL;
2431

2432
    HMODULE _h_ntdll = GetModuleHandle("ntdll.dll");
2433
    if (_h_ntdll != NULL) {
2434
        _p_wine_get_version = (get_wine_ver_proc)GetProcAddress(_h_ntdll, "wine_get_version");
2435
        if (_p_wine_get_version) {
2436
            char *wine_version = _p_wine_get_version();
2437
            if (wine_version)
2438
                return wine_version;
2439
        }
2440
    }
2441
    return NULL;
2442
#endif
2443
}
2444

2445
bool roll_and_archive(const char* filename, const char* extension) {
58✔
2446
    /* roll size minus 1KiB so we can write until it maxes. */
2447
    static const long deltasize = 1024L;
2448
    const long fillsize         = SIR_FROLLSIZE - deltasize;
50✔
2449

2450
    char logfilename[SIR_MAXPATH] = {0};
58✔
2451
    (void)snprintf(logfilename, SIR_MAXPATH, MAKE_LOG_NAME("%s%s"), filename, extension);
50✔
2452

2453
    TEST_MSG_0("deleting any stale logs from a previous run...");
50✔
2454

2455
    unsigned delcount = 0U;
58✔
2456
    if (!enumfiles(SIR_TESTLOGDIR, filename, !cl_cfg.leave_logs, &delcount)) {
58✔
2457
        HANDLE_OS_ERROR(false, "failed to enumerate log files with base name: %s!", filename);
6✔
2458
        return false;
6✔
2459
    }
2460

2461
    if (delcount > 0U)
52✔
2462
        TEST_MSG("found and removed %u log file(s)", delcount);
×
2463

2464
    FILE* f = NULL;
52✔
2465
    _sir_fopen(&f, logfilename, "w");
52✔
2466

2467
    if (NULL == f)
52✔
2468
        return print_test_error(false, false);
×
2469

2470
    TEST_MSG("filling %s nearly to SIR_FROLLSIZE...", logfilename);
44✔
2471

2472
    if (0 != fseek(f, fillsize, SEEK_SET)) {
52✔
2473
        HANDLE_OS_ERROR(true, "fseek in file %s failed!", logfilename);
2✔
2474
        _sir_safefclose(&f);
2✔
2475
        return false;
2✔
2476
    }
2477

2478
    if (EOF == fputc('\0', f)) {
50✔
2479
        HANDLE_OS_ERROR(true, "fputc in file %s failed!", logfilename);
2✔
2480
        _sir_safefclose(&f);
2✔
2481
        return false;
2✔
2482
    }
2483

2484
    _sir_safefclose(&f);
48✔
2485

2486
    INIT(si, 0, 0, 0, 0);
48✔
2487
    bool pass = si_init;
40✔
2488

2489
    TEST_MSG("adding %s to libsir...", logfilename);
40✔
2490

2491
    sirfileid fileid = sir_addfile(logfilename, SIRL_DEBUG, SIRO_MSGONLY | SIRO_NOHDR);
48✔
2492
    _sir_eqland(pass, 0U != fileid);
48✔
2493

2494
    (void)print_test_error(pass, false);
48✔
2495

2496
    if (pass) {
48✔
2497
        static const char* line = "hello, i am some data. nice to meet you.";
2498
        TEST_MSG("writing to %s until SIR_FROLLSIZE has been exceeded...", logfilename);
36✔
2499

2500
        /* write an (approximately) known quantity until we should have rolled */
2501
        size_t written  = 0;
36✔
2502
        size_t linesize = strnlen(line, SIR_MAXMESSAGE);
44✔
2503

2504
        do {
2505
            _sir_eqland(pass, sir_debug("%zu %s", written, line));
3,344✔
2506
            written += linesize;
3,344✔
2507
        } while (pass && (written < deltasize + (linesize * 50)));
3,344✔
2508

2509
        TEST_MSG_0("looking for two log files, since it should have been rolled...");
36✔
2510

2511
        /* look for files matching the original name. */
2512
        unsigned foundlogs = 0U;
44✔
2513
        if (!enumfiles(SIR_TESTLOGDIR, filename, false, &foundlogs)) {
44✔
2514
            HANDLE_OS_ERROR(false, "failed to enumerate log files with base name: %s!", filename);
×
2515
            pass = false;
×
2516
        }
2517

2518
        /* if two (or more) are present, the test is a pass. */
2519
        TEST_MSG("found %u log files with base name: %s", foundlogs, filename);
44✔
2520
        _sir_eqland(pass, foundlogs >= 2U);
44✔
2521
    }
2522

2523
    _sir_eqland(pass, sir_remfile(fileid));
48✔
2524

2525
    delcount = 0U;
48✔
2526
    if (!enumfiles(SIR_TESTLOGDIR, filename, !cl_cfg.leave_logs, &delcount)) {
48✔
2527
        HANDLE_OS_ERROR(false, "failed to enumerate log files with base name: %s!", filename);
×
2528
        pass = false;
×
2529
    }
2530

2531
    if (delcount > 0U)
48✔
2532
        TEST_MSG("found and removed %u log file(s)", delcount);
40✔
2533

2534
    _sir_eqland(pass, sir_cleanup());
48✔
2535
    return PRINT_RESULT_RETURN(pass);
48✔
2536
}
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

© 2025 Coveralls, Inc