1
#include <libgen.h>
2
#include <stdio.h>
3
#include <stdarg.h>
4
#include <unistd.h>
5
#include <stdio.h>
6
#include <stdlib.h>
7
#include <sys/wait.h>
8
#include <ctype.h>
9
#include <errno.h>
10
#include <sys/time.h>
11
#include <getopt.h>
12
// #include "subprocess.h"
13
/*
14
 * The MIT License (MIT)
15
 *
16
 * Copyright (c) 2019 Erik Moqvist
17
 *
18
 * Permission is hereby granted, free of charge, to any person
19
 * obtaining a copy of this software and associated documentation
20
 * files (the "Software"), to deal in the Software without
21
 * restriction, including without limitation the rights to use, copy,
22
 * modify, merge, publish, distribute, sublicense, and/or sell copies
23
 * of the Software, and to permit persons to whom the Software is
24
 * furnished to do so, subject to the following conditions:
25
 *
26
 * The above copyright notice and this permission notice shall be
27
 * included in all copies or substantial portions of the Software.
28
 *
29
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
33
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
34
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
35
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36
 * SOFTWARE.
37
 *
38
 * This file is part of the subprocess project.
39
 */
40

41
#ifndef NALA_SUBPROCESS_H
42
#define NALA_SUBPROCESS_H
43

44
#include <string.h>
45
#include <stdbool.h>
46

47
#define NALA_SUBPROCESS_VERSION "0.5.0"
48

49
typedef void (*nala_subprocess_entry_t)(void *arg_p);
50

51
struct nala_subprocess_output_t {
52
    /* Always null-terminated. */
53
    char *buf_p;
54
    /* Buffer length, not incuding last null-termination. */
55
    size_t length;
56
    /* Buffer size, including unused bytes. */
57
    size_t size;
58
};
59

60
struct nala_subprocess_result_t {
61
    int exit_code;
62
    int signal_number;
63
    struct nala_subprocess_output_t stdout;
64
    struct nala_subprocess_output_t stderr;
65
};
66

67
/**
68
 * Call given function with given argument in a subprocess. Returns
69
 * captured subprocess' exit code, or NULL if the subprocess could not
70
 * be started.
71
 */
72
struct nala_subprocess_result_t *nala_subprocess_call(nala_subprocess_entry_t entry,
73
                                                      void *arg_p);
74

75
/**
76
 * Call given function with given argument in a subprocess. Returns
77
 * captured subprocess' stdout, stderr and exit code, or NULL if the
78
 * subprocess could not be started.
79
 */
80
struct nala_subprocess_result_t *nala_subprocess_call_output(nala_subprocess_entry_t entry,
81
                                                             void *arg_p);
82

83
/**
84
 * Execute given command in a subprocess. Returns captured subprocess'
85
 * exit code, or NULL if the subprocess could not be started.
86
 */
87
struct nala_subprocess_result_t *nala_subprocess_exec(const char *command_p);
88

89
/**
90
 * Execute given command in a subprocess. Returns captured subprocess'
91
 * stdout, stderr and exit code, or NULL if the subprocess could not
92
 * be started.
93
 */
94
struct nala_subprocess_result_t *nala_subprocess_exec_output(const char *command_p);
95

96
/**
97
 * Returns true if the subprocess was started and exited with 0,
98
 * otherwise false.
99
 */
100
bool nala_subprocess_completed_successfully(struct nala_subprocess_result_t *result_p);
101

102
/**
103
 * Print subprocess exit code, stdout and stderr.
104
 */
105
void nala_subprocess_result_print(struct nala_subprocess_result_t *self_p);
106

107
/**
108
 * Free given result.
109
 */
110
void nala_subprocess_result_free(struct nala_subprocess_result_t *self_p);
111

112
#endif
113

114
// #include "traceback.h"
115
/*
116
 * The MIT License (MIT)
117
 *
118
 * Copyright (c) 2019 Erik Moqvist
119
 *
120
 * Permission is hereby granted, free of charge, to any person
121
 * obtaining a copy of this software and associated documentation
122
 * files (the "Software"), to deal in the Software without
123
 * restriction, including without limitation the rights to use, copy,
124
 * modify, merge, publish, distribute, sublicense, and/or sell copies
125
 * of the Software, and to permit persons to whom the Software is
126
 * furnished to do so, subject to the following conditions:
127
 *
128
 * The above copyright notice and this permission notice shall be
129
 * included in all copies or substantial portions of the Software.
130
 *
131
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
132
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
133
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
134
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
135
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
136
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
137
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
138
 * SOFTWARE.
139
 *
140
 * This file is part of the traceback project.
141
 */
142

143
#include <stdbool.h>
144

145
#define NALA_TRACEBACK_VERSION "0.8.0"
146

147
typedef bool (*nala_traceback_skip_filter_t)(void *arg_p, const char *line_p);
148

149
/**
150
 * Format given traceback. buffer_pp and depth are compatible with
151
 * backtrace() output.
152
 */
153
char *nala_traceback_format(void **buffer_pp,
154
                       int depth,
155
                       const char *prefix_p,
156
                       const char *header_p,
157
                       nala_traceback_skip_filter_t skip_filter,
158
                       void *arg_p);
159

160
/**
161
 * Create a traceback string.
162
 */
163
char *nala_traceback_string(const char *prefix_p,
164
                       const char *header_p,
165
                       nala_traceback_skip_filter_t skip_filter,
166
                       void *arg_p);
167

168
/**
169
 * Print a traceback.
170
 */
171
void nala_traceback_print(const char *prefix_p,
172
                     const char *header_p,
173
                     nala_traceback_skip_filter_t skip_filter,
174
                     void *arg_p);
175

176
#include "nala.h"
177
// #include "diff/diff.h"
178
#ifndef NALA_DIFF_H
179
#define NALA_DIFF_H
180

181
#include <stdlib.h>
182

183
struct NalaDiffMatrix
184
{
185
    size_t rows;
186
    size_t columns;
187
    int *content;
188
};
189

190
enum NalaDiffChunkType
191
{
192
    NALA_DIFF_CHUNK_TYPE_MATCHED,
193
    NALA_DIFF_CHUNK_TYPE_ADDED,
194
    NALA_DIFF_CHUNK_TYPE_REPLACED,
195
    NALA_DIFF_CHUNK_TYPE_DELETED
196
};
197

198
struct NalaDiff
199
{
200
    size_t size;
201
    struct NalaDiffChunk *chunks;
202
};
203

204
struct NalaDiffChunk
205
{
206
    enum NalaDiffChunkType type;
207
    size_t original_start;
208
    size_t original_end;
209
    size_t modified_start;
210
    size_t modified_end;
211
};
212

213
struct NalaDiffMatrix *nala_new_diff_matrix(size_t rows, size_t columns);
214
struct NalaDiffMatrix *nala_new_diff_matrix_from_lengths(size_t original_length,
215
                                                         size_t modified_lengths);
216
void nala_diff_matrix_fill_from_strings(struct NalaDiffMatrix *diff_matrix,
217
                                        const char *original,
218
                                        const char *modified);
219
void nala_diff_matrix_fill_from_lines(struct NalaDiffMatrix *diff_matrix,
220
                                      const char *original,
221
                                      const char *modified);
222
struct NalaDiff nala_diff_matrix_get_diff(const struct NalaDiffMatrix *diff_matrix);
223

224
size_t nala_diff_matrix_index(const struct NalaDiffMatrix *diff_matrix,
225
                              size_t row,
226
                              size_t column);
227
int nala_diff_matrix_get(const struct NalaDiffMatrix *diff_matrix,
228
                         size_t row,
229
                         size_t column);
230
void nala_diff_matrix_set(const struct NalaDiffMatrix *diff_matrix,
231
                          size_t row,
232
                          size_t column,
233
                          int value);
234

235
struct NalaDiff nala_diff_strings_lengths(const char *original,
236
                                          size_t original_length,
237
                                          const char *modified,
238
                                          size_t modified_length);
239
struct NalaDiff nala_diff_strings(const char *original, const char *modified);
240
struct NalaDiff nala_diff_lines(const char *original, const char *modified);
241

242
void nala_free_diff_matrix(struct NalaDiffMatrix *diff_matrix);
243

244
#endif
245

246
// #include "hexdump/hexdump.h"
247
#ifndef NALA_HEXDUMP_H
248
#define NALA_HEXDUMP_H
249

250
#include <stdint.h>
251
#include <stdlib.h>
252

253
char *nala_hexdump(const uint8_t *buffer, size_t size, size_t bytes_per_row);
254

255
#endif
256

257
// #include "utils.h"
258
#ifndef NALA_UTILS_H
259
#define NALA_UTILS_H
260

261
#include <stdbool.h>
262
#include <stdio.h>
263

264
int nala_min_int(int a, int b);
265
size_t nala_min_size_t(size_t a, size_t b);
266
size_t nala_count_chars(const char *string, char chr);
267
const char *nala_next_line(const char *string);
268
const char *nala_next_lines(const char *string, size_t lines);
269

270
#endif
271

272
// #include "hf.h"
273
/*
274
 * The MIT License (MIT)
275
 *
276
 * Copyright (c) 2019 Erik Moqvist
277
 *
278
 * Permission is hereby granted, free of charge, to any person
279
 * obtaining a copy of this software and associated documentation
280
 * files (the "Software"), to deal in the Software without
281
 * restriction, including without limitation the rights to use, copy,
282
 * modify, merge, publish, distribute, sublicense, and/or sell copies
283
 * of the Software, and to permit persons to whom the Software is
284
 * furnished to do so, subject to the following conditions:
285
 *
286
 * The above copyright notice and this permission notice shall be
287
 * included in all copies or substantial portions of the Software.
288
 *
289
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
290
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
291
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
292
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
293
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
294
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
295
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
296
 * SOFTWARE.
297
 *
298
 * This file is part of the humanfriendly project.
299
 */
300

301
#include <unistd.h>
302

303
#define NALA_HF_VERSION "0.2.0"
304

305
/**
306
 * Get the username of the currently logged in user. Returns the
307
 * current username, the default username, or NULL if the current user
308
 * cannot be determined and default_p is NULL.
309
 */
310
char *nala_hf_get_username(char *buf_p, size_t size, const char *default_p);
311

312
/**
313
 * Get the hostname. Returns the hostname, the default hostname, or
314
 * NULL if the hostname cannot be determined and default_p is NULL.
315
 */
316
char *nala_hf_get_hostname(char *buf_p, size_t size, const char *default_p);
317

318
/**
319
 * Format given timespan in milliseconds into given buffer.
320
 */
321
char *nala_hf_format_timespan(char *buf_p,
322
                              size_t size,
323
                              unsigned long long timespan_ms);
324

325

326
#define ANSI_COLOR_RED "\x1b[31m"
327
#define ANSI_COLOR_GREEN "\x1b[32m"
328
#define ANSI_COLOR_YELLOW "\x1b[33m"
329
#define ANSI_COLOR_BLUE "\x1b[34m"
330
#define ANSI_COLOR_MAGENTA "\x1b[35m"
331
#define ANSI_COLOR_CYAN "\x1b[36m"
332

333
#define ANSI_BOLD "\x1b[1m"
334
#define ANSI_RESET "\x1b[0m"
335

336
#define COLOR(color, ...) ANSI_RESET ANSI_COLOR_##color __VA_ARGS__ ANSI_RESET
337

338
#define BOLD(...) ANSI_RESET ANSI_BOLD __VA_ARGS__ ANSI_RESET
339

340
#define COLOR_BOLD(color, ...)                                          \
341
    ANSI_RESET ANSI_COLOR_##color ANSI_BOLD __VA_ARGS__ ANSI_RESET
342

343
struct job_request_t {
344
    struct nala_test_t *test_p;
345
    int number;
346
};
347

348
struct job_response_t {
349
    struct nala_test_t *test_p;
350
    struct nala_test_t test;
351
};
352

353
struct tests_t {
354
    struct nala_test_t *head_p;
355
    struct nala_test_t *tail_p;
356
};
357

358
struct capture_output_t {
359
    bool running;
360
    char **output_pp;
361
    size_t length;
362
    int original_fd;
363
    FILE *temporary_file_p;
364
    FILE *original_file_p;
365
    FILE *stdout_p;
366
};
367

368
static struct nala_test_t *current_test_p = NULL;
369

370
static struct tests_t tests = {
371
    .head_p = NULL,
372
    .tail_p = NULL
373
};
374

375
static struct capture_output_t capture_stdout;
376
static struct capture_output_t capture_stderr;
377

378 1
__attribute__ ((weak)) void nala_assert_all_mocks_completed(void)
379
{
380
}
381

382 1
__attribute__ ((weak)) void nala_reset_all_mocks(void)
383
{
384
}
385

386 1
__attribute__ ((weak)) void nala_suspend_all_mocks(void)
387
{
388
}
389

390 0
__attribute__ ((weak)) void nala_resume_all_mocks(void)
391
{
392
}
393

394
__attribute__ ((weak)) int nala_print_call_mask = 0;
395

396
static bool continue_on_failure = false;
397
static const char *report_json_file_p = "report.json";
398
static int number_of_jobs = 1;
399

400 1
static const char *get_node(void)
401
{
402
    static char buf[128];
403

404 1
    return (nala_hf_get_hostname(&buf[0], sizeof(buf), "*** unknown ***"));
405
}
406

407 1
static const char *get_user(void)
408
{
409
    static char buf[128];
410

411 1
    return (nala_hf_get_username(&buf[0], sizeof(buf), "*** unknown ***"));
412
}
413

414 1
static const char *format_timespan(float elapsed_time_ms)
415
{
416
    static char buf[128];
417

418 1
    return (nala_hf_format_timespan(&buf[0],
419
                                    sizeof(buf),
420
                                    (unsigned long long)elapsed_time_ms));
421
}
422

423 0
static void color_start(FILE *file_p, const char *color_p)
424
{
425 0
    fprintf(file_p, "%s%s%s", ANSI_RESET, color_p, ANSI_BOLD);
426
}
427

428 0
static void color_reset(FILE *file_p)
429
{
430 0
    fprintf(file_p, "%s", ANSI_RESET);
431
}
432

433 1
static char *format_suite_prefix(struct nala_test_t *test_p,
434
                                 char *buf_p,
435
                                 size_t size)
436
{
437
    size_t length;
438

439 1
    strncpy(buf_p, test_p->file_p, size);
440 1
    buf_p = basename(buf_p);
441 1
    length = strlen(buf_p);
442

443 1
    if (length < 2) {
444 0
        return ("");
445
    }
446

447 1
    buf_p[length - 2] = '\0';
448

449 1
    if (strcmp(buf_p, "main") == 0) {
450 1
        return ("");
451
    }
452

453 0
    strcat(buf_p, "::");
454

455 0
    return (buf_p);
456
}
457

458 1
static char *full_test_name(struct nala_test_t *test_p)
459
{
460
    static char buf[512];
461
    char suite[512];
462
    char *suite_p;
463

464 1
    suite_p = format_suite_prefix(test_p, &suite[0], sizeof(suite));
465 1
    snprintf(&buf[0], sizeof(buf), "%s%s", suite_p, test_p->name_p);
466

467 1
    return (&buf[0]);
468
}
469

470 1
static void capture_output_init(struct capture_output_t *self_p,
471
                                FILE *file_p)
472
{
473 1
    self_p->output_pp = NULL;
474 1
    self_p->length = 0;
475 1
    self_p->original_file_p = file_p;
476 1
    self_p->stdout_p = fdopen(dup(fileno(file_p)), "w");
477
}
478

479 1
static void capture_output_destroy(struct capture_output_t *self_p)
480
{
481 1
    if (self_p->output_pp != NULL) {
482 0
        if (*self_p->output_pp != NULL) {
483 0
            free(*self_p->output_pp);
484
        }
485

486 0
        self_p->output_pp = NULL;
487
    }
488

489 1
    if (self_p->stdout_p != NULL) {
490 1
        fflush(self_p->stdout_p);
491 1
        fclose(self_p->stdout_p);
492
    }
493
}
494

495 0
static void capture_output_redirect(struct capture_output_t *self_p)
496
{
497 0
    fflush(self_p->original_file_p);
498

499 0
    self_p->temporary_file_p = tmpfile();
500 0
    self_p->original_fd = dup(fileno(self_p->original_file_p));
501

502 0
    while ((dup2(fileno(self_p->temporary_file_p),
503
                 fileno(self_p->original_file_p)) == -1)
504 0
           && (errno == EINTR));
505
}
506

507 0
static void capture_output_restore(struct capture_output_t *self_p)
508
{
509 0
    fflush(self_p->original_file_p);
510

511 0
    while ((dup2(self_p->original_fd, fileno(self_p->original_file_p)) == -1)
512 0
           && (errno == EINTR));
513

514 0
    close(self_p->original_fd);
515
}
516

517 0
static void capture_output_start(struct capture_output_t *self_p,
518
                                 char **output_pp)
519
{
520 0
    self_p->output_pp = output_pp;
521 0
    self_p->length = 0;
522 0
    self_p->running = true;
523 0
    capture_output_redirect(self_p);
524
}
525

526 0
static void capture_output_stop(struct capture_output_t *self_p)
527
{
528
    size_t nmembers;
529

530 0
    if (!self_p->running) {
531 0
        return;
532
    }
533

534 0
    self_p->running = false;
535 0
    capture_output_restore(self_p);
536

537 0
    self_p->length = (size_t)ftell(self_p->temporary_file_p);
538 0
    fseek(self_p->temporary_file_p, 0, SEEK_SET);
539 0
    *self_p->output_pp = malloc(self_p->length + 1);
540

541 0
    if (*self_p->output_pp == NULL) {
542 0
        printf("Failed to allocate memory.\n");
543 0
        exit(1);
544
    }
545

546 0
    if (self_p->length > 0) {
547 0
        nmembers = fread(*self_p->output_pp,
548
                         self_p->length,
549
                         1,
550
                         self_p->temporary_file_p);
551

552 0
        if (nmembers != 1) {
553 0
            printf("Failed to read capture output.\n");
554 0
            exit(1);
555
        }
556
    }
557

558 0
    (*self_p->output_pp)[self_p->length] = '\0';
559 0
    fclose(self_p->temporary_file_p);
560

561 0
    printf("%s", *self_p->output_pp);
562
}
563

564 0
FILE *nala_get_stdout(void)
565
{
566 0
    if (capture_stdout.running) {
567 0
        return (capture_stdout.stdout_p);
568
    } else {
569 0
        return (stdout);
570
    }
571
}
572

573 1
static float timeval_to_ms(struct timeval *timeval_p)
574
{
575
    float res;
576

577 1
    res = (float)timeval_p->tv_usec;
578 1
    res /= 1000;
579 1
    res += (float)(1000 * timeval_p->tv_sec);
580

581 1
    return (res);
582
}
583

584 0
static void print_test_failure_report_begin(void)
585
{
586 0
    printf("\n"
587
           "------------------------------"
588
           "--------------------"
589
           "-----------------------------\n");
590 0
    printf("\n");
591
}
592

593 0
static void print_test_failure_report_end(void)
594
{
595 0
    printf("\n");
596
}
597

598 0
static void print_signal_failure(struct nala_test_t *test_p)
599
{
600 0
    print_test_failure_report_begin();
601 0
    printf("  Test:  " COLOR_BOLD(CYAN, "%s\n"), full_test_name(current_test_p));
602 0
    printf("  Error: " COLOR_BOLD(RED, "Terminated by signal %d.\n"),
603
           test_p->signal_number);
604 0
    print_test_failure_report_end();
605
}
606

607 1
static const char *test_result(struct nala_test_t *test_p, bool color)
608
{
609
    const char *result_p;
610

611 1
    if (test_p->executed) {
612 1
        if (test_p->exit_code == 0) {
613 1
            if (color) {
614 1
                result_p = COLOR_BOLD(GREEN, "PASSED");
615
            } else {
616 1
                result_p = "PASSED";
617
            }
618
        } else {
619 0
            if (color) {
620 0
                result_p = COLOR_BOLD(RED, "FAILED");
621
            } else {
622 0
                result_p = "FAILED";
623
            }
624
        }
625
    } else {
626 0
        if (color) {
627 0
            result_p = COLOR_BOLD(YELLOW, "SKIPPED");
628
        } else {
629 0
            result_p = "SKIPPED";
630
        }
631
    }
632

633 1
    return (result_p);
634
}
635

636 1
static void print_test_result(struct nala_test_t *test_p)
637
{
638 1
    printf("%s %s (" COLOR_BOLD(YELLOW, "%s") ")",
639
           test_result(test_p, true),
640
           full_test_name(test_p),
641
           format_timespan(test_p->elapsed_time_ms));
642

643 1
    if (test_p->signal_number != -1) {
644 0
        printf(" (signal: %d)", test_p->signal_number);
645
    }
646

647 1
    printf("\n");
648 1
    fflush(stdout);
649
}
650

651 1
static void print_summary(struct nala_test_t *test_p,
652
                          float elapsed_time_ms)
653
{
654
    int total;
655
    int passed;
656
    int failed;
657
    int skipped;
658

659 1
    total = 0;
660 1
    passed = 0;
661 1
    failed = 0;
662 1
    skipped = 0;
663

664 1
    while (test_p != NULL) {
665 1
        total++;
666

667 1
        if (test_p->executed) {
668 1
            if (test_p->exit_code == 0) {
669 1
                passed++;
670
            } else {
671 0
                failed++;
672
            }
673
        } else {
674 0
            skipped++;
675
        }
676

677 1
        test_p = test_p->next_p;
678
    }
679

680 1
    printf("\nTests: ");
681

682 1
    if (failed > 0) {
683 0
        printf(COLOR_BOLD(RED, "%d failed") ", ", failed);
684
    }
685

686 1
    if (passed > 0) {
687 1
        printf(COLOR_BOLD(GREEN, "%d passed") ", ", passed);
688
    }
689

690 1
    if (skipped > 0) {
691 0
        printf(COLOR_BOLD(YELLOW, "%d skipped") ", ", skipped);
692
    }
693

694 1
    printf("%d total\n", total);
695 1
    printf("Time: " COLOR_BOLD(YELLOW, "%s") "\n",
696
           format_timespan(elapsed_time_ms));
697
}
698

699 1
static void write_report_json(struct nala_test_t *test_p)
700
{
701
    FILE *file_p;
702

703 1
    file_p = fopen(report_json_file_p, "w");
704

705 1
    if (file_p == NULL) {
706 0
        fprintf(stderr,
707
                "error: Failed to open JSON report '%s' with '%s'.\n",
708
                report_json_file_p,
709 0
                strerror(errno));
710 0
        exit(1);
711
    }
712

713 1
    fprintf(file_p,
714
            "{\n"
715
            "    \"name\": \"-\",\n"
716
            "    \"date\": \"-\",\n"
717
            "    \"node\": \"%s\",\n"
718
            "    \"user\": \"%s\",\n"
719
            "    \"testcases\": [\n",
720
            get_node(),
721
            get_user());
722

723 1
    while (test_p != NULL) {
724 1
        fprintf(file_p,
725
                "        {\n"
726
                "            \"name\": \"%s\",\n"
727
                "            \"description\": [],\n"
728
                "            \"result\": \"%s\",\n"
729
                "            \"execution_time\": \"%s\"\n"
730
                "        }%s\n",
731
                full_test_name(test_p),
732
                test_result(test_p, false),
733
                format_timespan(test_p->elapsed_time_ms),
734 1
                (test_p->next_p != NULL ? "," : ""));
735 1
        test_p = test_p->next_p;
736
    }
737

738 1
    fprintf(file_p,
739
            "    ]\n"
740
            "}\n");
741 1
    fclose(file_p);
742
}
743

744 1
static void test_entry(void *arg_p)
745
{
746
    struct nala_test_t *test_p;
747

748 1
    test_p = (struct nala_test_t *)arg_p;
749 1
    capture_output_init(&capture_stdout, stdout);
750 1
    capture_output_init(&capture_stderr, stderr);
751 1
    nala_reset_all_mocks();
752 1
    test_p->func();
753 1
    nala_exit(0);
754
}
755

756 1
static int run_test(struct nala_test_t *test_p)
757
{
758
    int res;
759
    struct timeval start_time;
760
    struct timeval end_time;
761
    struct timeval elapsed_time;
762
    struct nala_subprocess_result_t *result_p;
763

764 1
    res = 0;
765 1
    gettimeofday(&start_time, NULL);
766 1
    current_test_p = test_p;
767 1
    test_p->before_fork_func();
768

769 1
    result_p = nala_subprocess_call(test_entry, test_p);
770

771 1
    test_p->executed = true;
772 1
    test_p->exit_code = result_p->exit_code;
773 1
    test_p->signal_number = result_p->signal_number;
774 1
    nala_subprocess_result_free(result_p);
775

776 1
    if (test_p->exit_code != 0) {
777 0
        res = 1;
778
    }
779

780 1
    gettimeofday(&end_time, NULL);
781 1
    timersub(&end_time, &start_time, &elapsed_time);
782 1
    test_p->elapsed_time_ms = timeval_to_ms(&elapsed_time);
783

784 1
    if (test_p->signal_number != -1) {
785 0
        print_signal_failure(test_p);
786
    }
787

788 1
    print_test_result(test_p);
789

790 1
    return (res);
791
}
792

793 1
static int run_tests_sequentially(struct nala_test_t *test_p)
794
{
795
    int res;
796
    int exit_code;
797

798 1
    exit_code = 0;
799

800 1
    while (test_p != NULL) {
801 1
        res = run_test(test_p);
802

803 1
        if (res != 0) {
804 0
            exit_code = res;
805

806 0
            if (!continue_on_failure) {
807 0
                break;
808
            }
809
        }
810

811 1
        test_p = test_p->next_p;
812
    }
813

814 1
    return (exit_code);
815
}
816

817 0
static int run_tests_in_parallel_child(struct nala_test_t *test_p,
818
                                       int request_fds[2],
819
                                       int response_fds[2])
820
{
821
    int previous_number;
822
    ssize_t size;
823
    int exit_code;
824
    struct job_request_t request;
825
    struct job_response_t response;
826
    int res;
827

828 0
    close(request_fds[1]);
829 0
    close(response_fds[0]);
830

831 0
    exit_code = 0;
832 0
    previous_number = 0;
833

834
    while (true) {
835 0
        size = read(request_fds[0], &request, sizeof(request));
836

837 0
        if (size == 0) {
838 0
            break;
839
        }
840

841 0
        if (size != sizeof(request)) {
842 0
            perror("request read");
843 0
            exit(1);
844
        }
845

846 0
        while (previous_number < request.number) {
847 0
            previous_number++;
848 0
            test_p = test_p->next_p;
849
        }
850

851 0
        res = run_test(test_p);
852

853 0
        if (res != 0) {
854 0
            exit_code = res;
855
        }
856

857 0
        response.test_p = request.test_p;
858 0
        response.test = *test_p;
859

860 0
        size = write(response_fds[1], &response, sizeof(response));
861

862 0
        if (size != sizeof(response)) {
863 0
            perror("response write");
864 0
            exit(1);
865
        }
866
    }
867

868 0
    close(request_fds[0]);
869 0
    close(response_fds[1]);
870

871 0
    return (exit_code);
872
}
873

874 0
static void write_job_request(int fd,
875
                              struct nala_test_t *test_p,
876
                              int number)
877
{
878
    struct job_request_t request;
879
    ssize_t size;
880

881 0
    request.test_p = test_p;
882 0
    request.number = number;
883

884 0
    size = write(fd, &request, sizeof(request));
885

886 0
    if (size != sizeof(request)) {
887 0
        perror("request write");
888 0
        exit(1);
889
    }
890
}
891

892 0
static int read_job_response(int fd)
893
{
894
    struct job_response_t response;
895
    ssize_t size;
896
    struct nala_test_t *test_p;
897

898 0
    size = read(fd, &response, sizeof(response));
899

900 0
    if (size == 0) {
901 0
        return (1);
902
    }
903

904 0
    if (size != sizeof(response)) {
905 0
        perror("response read");
906 0
        exit(1);
907
    }
908

909
    /* Copy test result to this process's list. */
910 0
    test_p = response.test_p;
911 0
    test_p->executed = response.test.executed;
912 0
    test_p->exit_code = response.test.exit_code;
913 0
    test_p->signal_number = response.test.signal_number;
914 0
    test_p->elapsed_time_ms = response.test.elapsed_time_ms;
915

916 0
    return (test_p->exit_code);
917
}
918

919 0
static int run_tests_in_parallel(struct nala_test_t *test_p)
920
{
921
    int res;
922
    int request_fds[2];
923
    int response_fds[2];
924
    int i;
925
    pid_t *pids_p;
926
    int status;
927
    int exit_code;
928
    int number_of_outstanding_requests;
929
    int number;
930

931 0
    res = pipe(&request_fds[0]);
932

933 0
    if (res != 0) {
934 0
        fprintf(stderr, "error: request pipe open\n");
935 0
        exit(1);
936
    }
937

938 0
    res = pipe(&response_fds[0]);
939

940 0
    if (res != 0) {
941 0
        fprintf(stderr, "error: response pipe open\n");
942 0
        exit(1);
943
    }
944

945
    /* Create workers. */
946 0
    pids_p = alloca((size_t)number_of_jobs * sizeof(*pids_p));
947

948 0
    for (i = 0; i < number_of_jobs; i++) {
949 0
        pids_p[i] = fork();
950

951 0
        if (pids_p[i] < 0) {
952 0
            fprintf(stderr, "error: Failed to create worker process\n");
953 0
            exit(1);
954 0
        } else if (pids_p[i] == 0) {
955 0
            exit(run_tests_in_parallel_child(test_p,
956
                                             request_fds,
957
                                             response_fds));
958
        }
959
    }
960

961 0
    close(response_fds[1]);
962

963
    /* Keep the workers busy. */
964 0
    number_of_outstanding_requests = 0;
965 0
    number = 0;
966

967 0
    while (test_p != NULL) {
968 0
        if (number_of_outstanding_requests == number_of_jobs) {
969 0
            res = read_job_response(response_fds[0]);
970 0
            number_of_outstanding_requests--;
971

972 0
            if ((res != 0) && !continue_on_failure) {
973 0
                break;
974
            }
975
        }
976

977 0
        write_job_request(request_fds[1], test_p, number);
978 0
        number_of_outstanding_requests++;
979 0
        number++;
980 0
        test_p = test_p->next_p;
981
    }
982

983 0
    close(request_fds[1]);
984

985
    /* Read remaining responses. */
986 0
    while (number_of_outstanding_requests > 0) {
987 0
        (void)read_job_response(response_fds[0]);
988 0
        number_of_outstanding_requests--;
989
    }
990

991 0
    close(request_fds[0]);
992 0
    close(response_fds[0]);
993

994
    /* Wait for all workers to exit. */
995 0
    exit_code = 0;
996

997 0
    for (i = 0; i < number_of_jobs; i++) {
998 0
        waitpid(pids_p[i], &status, 0);
999

1000 0
        if (WIFEXITED(status)) {
1001 0
            if (WEXITSTATUS(status) != 0) {
1002 0
                exit_code = 1;
1003
            }
1004
        }
1005

1006 0
        if (WIFSIGNALED(status)) {
1007 0
            exit_code = 1;
1008
        }
1009
    }
1010

1011 0
    return (exit_code);
1012
}
1013

1014 1
static int run_tests(struct nala_test_t *tests_p)
1015
{
1016
    int exit_code;
1017
    struct timeval start_time;
1018
    struct timeval end_time;
1019
    struct timeval elapsed_time;
1020
    struct nala_test_t *test_p;
1021

1022 1
    test_p = tests_p;
1023

1024 1
    while (test_p != NULL) {
1025 1
        test_p->executed = false;
1026 1
        test_p = test_p->next_p;
1027
    }
1028

1029 1
    test_p = tests_p;
1030 1
    gettimeofday(&start_time, NULL);
1031

1032 1
    if (number_of_jobs == 1) {
1033 1
        exit_code = run_tests_sequentially(test_p);
1034
    } else {
1035 0
        exit_code = run_tests_in_parallel(test_p);
1036
    }
1037

1038 1
    gettimeofday(&end_time, NULL);
1039 1
    timersub(&end_time, &start_time, &elapsed_time);
1040 1
    print_summary(tests_p, timeval_to_ms(&elapsed_time));
1041 1
    fflush(stdout);
1042 1
    write_report_json(tests_p);
1043

1044 1
    return (exit_code);
1045
}
1046

1047 0
bool nala_check_string_equal(const char *actual_p, const char *expected_p)
1048
{
1049 0
    if (actual_p == expected_p) {
1050 0
        return (true);
1051
    }
1052

1053 0
    return ((actual_p != NULL)
1054 0
            && (expected_p != NULL)
1055 0
            && (strcmp(actual_p, expected_p) == 0));
1056
}
1057

1058 0
const char *nala_format(const char *format_p, ...)
1059
{
1060
    va_list vl;
1061
    size_t size;
1062
    char *buf_p;
1063
    FILE *file_p;
1064

1065 0
    nala_suspend_all_mocks();
1066 0
    file_p = open_memstream(&buf_p, &size);
1067 0
    color_start(file_p, ANSI_COLOR_RED);
1068 0
    va_start(vl, format_p);
1069 0
    vfprintf(file_p, format_p, vl);
1070 0
    va_end(vl);
1071 0
    color_reset(file_p);
1072 0
    fputc('\0', file_p);
1073 0
    fclose(file_p);
1074 0
    nala_resume_all_mocks();
1075

1076 0
    return (buf_p);
1077
}
1078

1079 0
static const char *display_inline_diff(FILE *file_p,
1080
                                       const struct NalaDiff *inline_diff,
1081
                                       size_t lines,
1082
                                       const char *string,
1083
                                       size_t *line_number,
1084
                                       bool use_original)
1085
{
1086 0
    struct NalaDiffChunk *inline_chunk = &inline_diff->chunks[0];
1087 0
    size_t line_index = 0;
1088 0
    size_t index = 0;
1089

1090 0
    for (size_t i = 0; i < lines; i++) {
1091 0
        const char *next = nala_next_line(string);
1092 0
        size_t line_length = (size_t)(next - string);
1093

1094
        char line_prefix[64];
1095

1096 0
        if (use_original) {
1097 0
            snprintf(line_prefix,
1098
                     sizeof(line_prefix),
1099
                     "- " BOLD("%ld"),
1100
                     *line_number);
1101 0
            fprintf(file_p, " %19s" " |  ", line_prefix);
1102
        } else {
1103 0
            snprintf(line_prefix,
1104
                     sizeof(line_prefix),
1105
                     COLOR(RED, "+ ") COLOR_BOLD(RED, "%ld"),
1106
                     *line_number);
1107 0
            fprintf(file_p, " %37s" COLOR(RED, " |  "), line_prefix);
1108
        }
1109

1110 0
        while (index - line_index < line_length) {
1111 0
            size_t chunk_end =
1112 0
                use_original ? inline_chunk->original_end : inline_chunk->modified_end;
1113

1114 0
            size_t start = index - line_index;
1115 0
            size_t end = nala_min_size_t(chunk_end - line_index, line_length);
1116

1117 0
            size_t characters = end - start;
1118

1119 0
            if (inline_chunk->type == NALA_DIFF_CHUNK_TYPE_MATCHED) {
1120 0
                fprintf(file_p, "%.*s", (int)characters, string + index - line_index);
1121 0
            } else if (characters > 0) {
1122 0
                if (use_original) {
1123 0
                    fprintf(file_p,
1124
                            BOLD("%.*s"),
1125
                            (int)characters,
1126 0
                            string + index - line_index);
1127
                } else {
1128 0
                    fprintf(file_p,
1129
                            COLOR_BOLD(RED, "%.*s"),
1130
                            (int)characters,
1131 0
                            string + index - line_index);
1132
                }
1133
            }
1134

1135 0
            index += characters;
1136

1137 0
            if (index >= chunk_end) {
1138 0
                inline_chunk++;
1139
            }
1140
        }
1141

1142 0
        fprintf(file_p, "\n");
1143

1144 0
        if (!use_original) {
1145 0
            (*line_number)++;
1146
        }
1147

1148 0
        string = next + 1;
1149 0
        line_index += line_length + 1;
1150 0
        index = line_index;
1151
    }
1152

1153 0
    return string;
1154
}
1155

1156 0
static void print_string_diff(FILE *file_p,
1157
                              const char *original,
1158
                              const char *modified)
1159
{
1160 0
    nala_suspend_all_mocks();
1161 0
    fprintf(file_p, "  Diff:\n\n");
1162

1163 0
    struct NalaDiff diff = nala_diff_lines(original, modified);
1164

1165 0
    size_t line_number = 1;
1166

1167 0
    for (size_t chunk_index = 0; chunk_index < diff.size; chunk_index++) {
1168 0
        struct NalaDiffChunk *chunk = &diff.chunks[chunk_index];
1169

1170 0
        size_t original_lines = chunk->original_end - chunk->original_start;
1171 0
        size_t modified_lines = chunk->modified_end - chunk->modified_start;
1172

1173 0
        if (chunk->type == NALA_DIFF_CHUNK_TYPE_MATCHED) {
1174 0
            for (size_t i = 0; i < original_lines; i++) {
1175 0
                const char *original_next = nala_next_line(original);
1176 0
                const char *modified_next = nala_next_line(modified);
1177

1178 0
                if (original_lines < 7 || (i < 2 && chunk_index > 0) ||
1179 0
                    (original_lines - i < 3 && chunk_index < diff.size - 1)) {
1180 0
                    fprintf(file_p, COLOR(MAGENTA, "%8zu"), line_number);
1181 0
                    fprintf(file_p, " |  %.*s\n", (int)(original_next - original), original);
1182 0
                } else if (i == 2) {
1183 0
                    fprintf(file_p, "   :\n");
1184
                }
1185

1186 0
                line_number++;
1187 0
                original = original_next + 1;
1188 0
                modified = modified_next + 1;
1189
            }
1190 0
        } else if (chunk->type == NALA_DIFF_CHUNK_TYPE_REPLACED) {
1191 0
            const char *original_end = nala_next_lines(original, original_lines);
1192 0
            const char *modified_end = nala_next_lines(modified, modified_lines);
1193

1194 0
            size_t original_length = (size_t)(original_end - original);
1195 0
            size_t modified_length = (size_t)(modified_end - modified);
1196

1197 0
            struct NalaDiff inline_diff =
1198
                nala_diff_strings_lengths(original,
1199
                                          original_length,
1200
                                          modified,
1201
                                          modified_length);
1202

1203 0
            original = display_inline_diff(file_p,
1204
                                           &inline_diff,
1205
                                           original_lines,
1206
                                           original,
1207
                                           &line_number,
1208
                                           true);
1209 0
            modified = display_inline_diff(file_p,
1210
                                           &inline_diff,
1211
                                           modified_lines,
1212
                                           modified,
1213
                                           &line_number,
1214
                                           false);
1215

1216 0
            free(inline_diff.chunks);
1217 0
        } else if (chunk->type == NALA_DIFF_CHUNK_TYPE_DELETED) {
1218 0
            for (size_t i = 0; i < original_lines; i++) {
1219 0
                const char *original_next = nala_next_line(original);
1220

1221
                char line_prefix[64];
1222 0
                snprintf(line_prefix,
1223
                         sizeof(line_prefix),
1224
                         COLOR(RED, "- ") COLOR_BOLD(RED, "%ld"),
1225
                         line_number);
1226

1227 0
                fprintf(file_p, " %37s", line_prefix);
1228 0
                fprintf(file_p, COLOR(RED, " |  ") COLOR_BOLD(RED, "%.*s\n"),
1229 0
                        (int)(original_next - original),
1230
                        original);
1231

1232 0
                original = original_next + 1;
1233
            }
1234 0
        } else if (chunk->type == NALA_DIFF_CHUNK_TYPE_ADDED) {
1235 0
            for (size_t i = 0; i < modified_lines; i++) {
1236 0
                const char *modified_next = nala_next_line(modified);
1237

1238
                char line_prefix[64];
1239 0
                snprintf(line_prefix,
1240
                         sizeof(line_prefix),
1241
                         COLOR(RED, "+ ") COLOR_BOLD(RED, "%ld"),
1242
                         line_number);
1243

1244 0
                fprintf(file_p, " %37s", line_prefix);
1245 0
                fprintf(file_p, COLOR(RED, " |  ") COLOR_BOLD(RED, "%.*s\n"),
1246 0
                        (int)(modified_next - modified),
1247
                        modified);
1248

1249 0
                line_number++;
1250 0
                modified = modified_next + 1;
1251
            }
1252
        }
1253
    }
1254

1255 0
    free(diff.chunks);
1256 0
    fprintf(file_p, "\n");
1257 0
    nala_resume_all_mocks();
1258
}
1259

1260 0
const char *nala_format_string(const char *format_p, ...)
1261
{
1262
    size_t size;
1263
    char *buf_p;
1264
    FILE *file_p;
1265
    va_list vl;
1266
    const char *left_p;
1267
    const char *right_p;
1268

1269 0
    nala_suspend_all_mocks();
1270

1271 0
    va_start(vl, format_p);
1272 0
    left_p = va_arg(vl, const char *);
1273 0
    right_p = va_arg(vl, const char *);
1274 0
    va_end(vl);
1275

1276 0
    file_p = open_memstream(&buf_p, &size);
1277 0
    color_start(file_p, ANSI_COLOR_RED);
1278 0
    fprintf(file_p, format_p, left_p, right_p);
1279 0
    fprintf(file_p, " See diff for details.\n");
1280 0
    color_reset(file_p);
1281

1282 0
    if (right_p == NULL) {
1283 0
        right_p = "<null>";
1284
    }
1285

1286 0
    if (left_p == NULL) {
1287 0
        left_p = "<null>";
1288
    }
1289

1290 0
    print_string_diff(file_p, right_p, left_p);
1291 0
    fputc('\0', file_p);
1292 0
    fclose(file_p);
1293

1294 0
    nala_resume_all_mocks();
1295

1296 0
    return (buf_p);
1297
}
1298

1299 0
static void print_with_line_prefix(FILE *file_p,
1300
                                   const char *prefix_p,
1301
                                   const char *string_p)
1302
{
1303 0
    fprintf(file_p, "%s", prefix_p);
1304

1305 0
    while (*string_p != '\0') {
1306 0
        fputc(string_p[0], file_p);
1307

1308 0
        if (*string_p == '\n') {
1309 0
            fprintf(file_p, "%s", prefix_p);
1310
        }
1311

1312 0
        string_p++;
1313
    }
1314
}
1315

1316 0
const char *nala_format_substring(const char *format_p,
1317
                                  const char *haystack_p,
1318
                                  const char *needle_p)
1319
{
1320
    size_t size;
1321
    char *buf_p;
1322
    FILE *file_p;
1323

1324 0
    nala_suspend_all_mocks();
1325

1326 0
    file_p = open_memstream(&buf_p, &size);
1327 0
    color_start(file_p, ANSI_COLOR_RED);
1328 0
    fprintf(file_p, "%s", format_p);
1329 0
    fprintf(file_p, " See below for details.\n");
1330 0
    color_reset(file_p);
1331

1332 0
    if (haystack_p == NULL) {
1333 0
        haystack_p = "<null>";
1334
    }
1335

1336 0
    if (needle_p == NULL) {
1337 0
        needle_p = "<null>";
1338
    }
1339

1340 0
    fprintf(file_p, "  Haystack:\n\n");
1341 0
    print_with_line_prefix(file_p, "    ", haystack_p);
1342 0
    fprintf(file_p, "\n");
1343 0
    fprintf(file_p, "  Needle:\n\n");
1344 0
    print_with_line_prefix(file_p, "    ", needle_p);
1345 0
    fprintf(file_p, "\n");
1346 0
    fputc('\0', file_p);
1347 0
    fclose(file_p);
1348

1349 0
    nala_resume_all_mocks();
1350

1351 0
    return (buf_p);
1352
}
1353

1354 0
const char *nala_format_memory(const char *prefix_p,
1355
                               const void *left_p,
1356
                               const void *right_p,
1357
                               size_t size)
1358
{
1359
    size_t file_size;
1360
    char *buf_p;
1361
    FILE *file_p;
1362
    char *left_hexdump_p;
1363
    char *right_hexdump_p;
1364

1365 0
    nala_suspend_all_mocks();
1366

1367 0
    file_p = open_memstream(&buf_p, &file_size);
1368 0
    fprintf(file_p,
1369
            COLOR_BOLD(RED, "%sMemory mismatch. See diff for details.\n"),
1370
            prefix_p);
1371

1372 0
    if (left_p == NULL) {
1373 0
        left_p = "<null>";
1374
    }
1375

1376 0
    if (right_p == NULL) {
1377 0
        right_p = "<null>";
1378
    }
1379

1380 0
    left_hexdump_p = nala_hexdump(left_p, size, 16);
1381 0
    right_hexdump_p = nala_hexdump(right_p, size, 16);
1382 0
    print_string_diff(file_p, right_hexdump_p, left_hexdump_p);
1383 0
    free(left_hexdump_p);
1384 0
    free(right_hexdump_p);
1385 0
    fputc('\0', file_p);
1386 0
    fclose(file_p);
1387

1388 0
    nala_resume_all_mocks();
1389

1390 0
    return (buf_p);
1391
}
1392

1393 0
bool nala_check_substring(const char *string_p, const char *substring_p)
1394
{
1395 0
    return ((string_p != NULL)
1396 0
            && (substring_p != NULL)
1397 0
            && (strstr(string_p, substring_p) != NULL));
1398
}
1399

1400 1
bool nala_check_memory(const void *left_p, const void *right_p, size_t size)
1401
{
1402 1
    return !(((left_p == NULL) && (right_p != NULL))
1403 1
             || ((left_p != NULL) && (right_p == NULL))
1404 1
             || (memcmp(left_p, right_p, size) != 0));
1405
}
1406

1407 0
static bool traceback_skip_filter(void *arg_p, const char *line_p)
1408
{
1409
    (void)arg_p;
1410

1411 0
    if (strstr(line_p, "nala.c:") != NULL) {
1412 0
        return (true);
1413
    }
1414

1415 0
    if (strstr(line_p, "??") != NULL) {
1416 0
        return (true);
1417
    }
1418

1419 0
    return (false);
1420
}
1421

1422 0
void nala_test_failure(const char *message_p)
1423
{
1424 0
    nala_suspend_all_mocks();
1425 0
    nala_capture_output_stop();
1426 0
    capture_output_destroy(&capture_stdout);
1427 0
    capture_output_destroy(&capture_stderr);
1428 0
    print_test_failure_report_begin();
1429 0
    printf("  Test:  " COLOR_BOLD(CYAN, "%s\n"), full_test_name(current_test_p));
1430 0
    printf("  Error: %s", message_p);
1431 0
    printf("\n");
1432 0
    nala_traceback_print("  ",
1433
                         "Assert traceback (most recent call last):",
1434
                         traceback_skip_filter,
1435
                         NULL);
1436 0
    print_test_failure_report_end();
1437 0
    free((void *)message_p);
1438 0
    exit(1);
1439
}
1440

1441 0
void nala_capture_output_start(char **output_pp, char **errput_pp)
1442
{
1443 0
    nala_suspend_all_mocks();
1444 0
    capture_output_start(&capture_stdout, output_pp);
1445 0
    capture_output_start(&capture_stderr, errput_pp);
1446 0
    nala_resume_all_mocks();
1447
}
1448

1449 0
void nala_capture_output_stop(void)
1450
{
1451 0
    nala_suspend_all_mocks();
1452 0
    capture_output_stop(&capture_stdout);
1453 0
    capture_output_stop(&capture_stderr);
1454 0
    nala_resume_all_mocks();
1455
}
1456

1457 1
void nala_register_test(struct nala_test_t *test_p)
1458
{
1459 1
    if (tests.head_p == NULL) {
1460 1
        tests.head_p = test_p;
1461
    } else {
1462 1
        tests.tail_p->next_p = test_p;
1463
    }
1464

1465 1
    tests.tail_p = test_p;
1466
}
1467

1468 1
int nala_run_tests(void)
1469
{
1470 1
    return (run_tests(tests.head_p));
1471
}
1472

1473 0
static void print_usage_and_exit(const char *program_name_p, int exit_code)
1474
{
1475 0
    printf("usage: %s [-h] [-v] [-c] [-a] [-r] [-f] [-j] [<test-pattern>]\n"
1476
           "\n"
1477
           "Run tests.\n"
1478
           "\n"
1479
           "positional arguments:\n"
1480
           "  test-pattern                  Only run tests matching given pattern. "
1481
           "'^' matches\n"
1482
           "                                the beginning and '$' matches the end "
1483
           "of the test\n"
1484
           "                                name.\n"
1485
           "\n"
1486
           "optional arguments:\n"
1487
           "  -h, --help                    Show this help message and exit.\n"
1488
           "  -v, --version                 Print version information.\n"
1489
           "  -c, --continue-on-failure     Continue on test failure.\n"
1490
           "  -a, --print-all-calls         Print all calls to ease debugging.\n"
1491
           "  -r, --report-json-file        JSON test report file (default: "
1492
           "report.json).\n"
1493
           "  -f, --print-test-file-func    Print file:function for exactly "
1494
           "one test.\n"
1495
           "  -j, --jobs                    Run given number of tests in "
1496
           "parallel\n"
1497
           "                                (default: 1).\n",
1498
           program_name_p);
1499 0
    exit(exit_code);
1500
}
1501

1502 0
static void print_version_and_exit(void)
1503
{
1504 0
    printf("%s\n", NALA_VERSION);
1505 0
    exit(0);
1506
}
1507

1508 0
static bool is_test_match(struct nala_test_t *test_p, const char *full_pattern_p)
1509
{
1510
    const char *full_test_name_p;
1511
    size_t full_test_name_length;
1512
    size_t pattern_length;
1513
    size_t offset;
1514
    bool match_beginning;
1515
    bool match_end;
1516
    char *pattern_p;
1517

1518 0
    pattern_length = strlen(full_pattern_p);
1519

1520 0
    if (pattern_length == 0) {
1521 0
        return (true);
1522
    }
1523

1524 0
    match_beginning = (full_pattern_p[0] == '^');
1525 0
    match_end = (full_pattern_p[pattern_length - 1] == '$');
1526 0
    pattern_p = alloca(pattern_length + 1);
1527 0
    strcpy(pattern_p, full_pattern_p);
1528

1529 0
    if (match_beginning) {
1530 0
        pattern_p++;
1531 0
        pattern_length--;
1532
    }
1533

1534 0
    if (match_end) {
1535 0
        pattern_length--;
1536
    }
1537

1538 0
    full_test_name_p = full_test_name(test_p);
1539 0
    full_test_name_length = strlen(full_test_name_p);
1540

1541 0
    if (pattern_length > full_test_name_length) {
1542 0
        return (false);
1543
    }
1544

1545 0
    if (match_beginning || match_end) {
1546 0
        if ((pattern_length == 0) && match_beginning && match_end) {
1547 0
            return (false);
1548
        }
1549

1550 0
        if (match_beginning) {
1551 0
            if (strncmp(full_test_name_p, pattern_p, pattern_length) != 0) {
1552 0
                return (false);
1553
            }
1554
        }
1555

1556 0
        if (match_end) {
1557 0
            offset = (full_test_name_length - pattern_length);
1558

1559 0
            if (strncmp(&full_test_name_p[offset],
1560
                        pattern_p,
1561
                        pattern_length) != 0) {
1562 0
                return (false);
1563
            }
1564
        }
1565 0
    } else if (strstr(full_test_name_p, pattern_p) == NULL) {
1566 0
        return (false);
1567
    }
1568

1569 0
    return (true);
1570
}
1571

1572 0
static void filter_tests(const char *test_pattern_p)
1573
{
1574
    struct nala_test_t *test_p;
1575

1576 0
    test_p = tests.head_p;
1577 0
    tests.head_p = NULL;
1578 0
    tests.tail_p = NULL;
1579

1580 0
    while (test_p != NULL) {
1581 0
        if (is_test_match(test_p, test_pattern_p)) {
1582 0
            nala_register_test(test_p);
1583
        }
1584

1585 0
        test_p = test_p->next_p;
1586
    }
1587

1588 0
    if (tests.tail_p != NULL) {
1589 0
        tests.tail_p->next_p = NULL;
1590
    }
1591
}
1592

1593 0
static struct nala_test_t *find_test(const char *test_pattern_p)
1594
{
1595
    struct nala_test_t *test_p;
1596
    struct nala_test_t *found_p;
1597

1598 0
    test_p = tests.head_p;
1599 0
    found_p = NULL;
1600

1601 0
    while (test_p != NULL) {
1602 0
        if (is_test_match(test_p, test_pattern_p)) {
1603 0
            if (found_p == NULL) {
1604 0
                found_p = test_p;
1605
            } else {
1606 0
                fprintf(stderr,
1607
                        "error: '%s' matches more than one test.\n",
1608
                        test_pattern_p);
1609

1610 0
                return (NULL);
1611
            }
1612
        }
1613

1614 0
        test_p = test_p->next_p;
1615
    }
1616

1617 0
    if (found_p == NULL) {
1618 0
        fprintf(stderr,
1619
                "error: '%s' does not match any test.\n",
1620
                test_pattern_p);
1621

1622 0
        return (NULL);
1623
    }
1624

1625 0
    return (found_p);
1626
}
1627

1628 0
static int print_test_file_func(const char *test_pattern_p)
1629
{
1630
    struct nala_test_t *test_p;
1631

1632 0
    test_p = find_test(test_pattern_p);
1633

1634 0
    if (test_p == NULL) {
1635 0
        return (1);
1636
    }
1637

1638 0
    printf("%s:%s\n", test_p->file_p, test_p->name_p);
1639

1640 0
    return (0);
1641
}
1642

1643 1
__attribute__((weak)) int main(int argc, char *argv[])
1644
{
1645
    static struct option long_options[] = {
1646
        { "help",                 no_argument,       NULL, 'h' },
1647
        { "version",              no_argument,       NULL, 'v' },
1648
        { "continue-on-failure",  no_argument,       NULL, 'c' },
1649
        { "print-all-calls",      no_argument,       NULL, 'a' },
1650
        { "report-json-file",     required_argument, NULL, 'r' },
1651
        { "print-test-file-func", required_argument, NULL, 'f' },
1652
        { "jobs",                 required_argument, NULL, 'j' },
1653
        { NULL,                   no_argument,       NULL, 0 }
1654
    };
1655
    int option;
1656

1657
    /* Do not print function calls outside tests. */
1658 1
    nala_suspend_all_mocks();
1659

1660
    while (1) {
1661 1
        option = getopt_long(argc, argv, "hvcar:f:j:", &long_options[0], NULL);
1662

1663 1
        if (option == -1) {
1664 1
            break;
1665
        }
1666

1667 0
        switch (option) {
1668

1669
        case 'h':
1670 0
            print_usage_and_exit(argv[0], 0);
1671 0
            break;
1672

1673
        case 'v':
1674 0
            print_version_and_exit();
1675 0
            break;
1676

1677
        case 'c':
1678 0
            continue_on_failure = true;
1679 0
            break;
1680

1681
        case 'a':
1682 0
            nala_print_call_mask = 0xff;
1683 0
            break;
1684

1685
        case 'r':
1686 0
            report_json_file_p = optarg;
1687 0
            break;
1688

1689
        case 'f':
1690 0
            return (print_test_file_func(optarg));
1691

1692
        case 'j':
1693 0
            number_of_jobs = atoi(optarg);
1694

1695 0
            if (number_of_jobs < 1) {
1696 0
                printf("error: At least one job is required, %d given.\n",
1697
                       number_of_jobs);
1698 0
                exit(1);
1699
            }
1700

1701 0
            break;
1702

1703
        default:
1704 0
            print_usage_and_exit(argv[0], 1);
1705
        }
1706
    }
1707

1708 1
    if (optind < argc) {
1709 0
        filter_tests(argv[optind]);
1710
    }
1711

1712 1
    return (nala_run_tests());
1713
}
1714

1715 0
static bool mock_traceback_skip_filter(void *arg_p, const char *line_p)
1716
{
1717
    (void)arg_p;
1718

1719 0
    if (strstr(line_p, "nala.c:") != NULL) {
1720 0
        return (true);
1721
    }
1722

1723 0
    if (strstr(line_p, "nala_mocks.c:") != NULL) {
1724 0
        return (true);
1725
    }
1726

1727 0
    if (strstr(line_p, "??") != NULL) {
1728 0
        return (true);
1729
    }
1730

1731 0
    return (false);
1732
}
1733

1734 0
char *nala_mock_traceback_format(void **buffer_pp, int depth)
1735
{
1736 0
    return (nala_traceback_format(buffer_pp,
1737
                                  depth,
1738
                                  "  ",
1739
                                  "Mock traceback (most recent call last):",
1740
                                  mock_traceback_skip_filter,
1741
                                  NULL));
1742
}
1743

1744
#define CHECK_EQ(actual, expected) ((actual) == (expected))
1745

1746
#define CHECK_NE(actual, expected) ((actual) != (expected))
1747

1748
#define CHECK_LT(actual, expected) ((actual) < (expected))
1749

1750
#define CHECK_LE(actual, expected) ((actual) <= (expected))
1751

1752
#define CHECK_GT(actual, expected) ((actual) > (expected))
1753

1754
#define CHECK_GE(actual, expected) ((actual) >= (expected))
1755

1756
#define PRINT_FORMAT(value)                     \
1757
    _Generic((value),                           \
1758
             char: "%c",                        \
1759
             signed char: "%hhd",               \
1760
             unsigned char: "%hhu",             \
1761
             signed short: "%hd",               \
1762
             unsigned short: "%hu",             \
1763
             signed int: "%d",                  \
1764
             unsigned int: "%u",                \
1765
             long int: "%ld",                   \
1766
             unsigned long int: "%lu",          \
1767
             long long int: "%lld",             \
1768
             unsigned long long int: "%llu",    \
1769
             float: "%f",                       \
1770
             double: "%f",                      \
1771
             long double: "%Lf",                \
1772
             const char *: "\"%s\"",            \
1773
             bool: "%d",                        \
1774
             const void *: "%p")
1775

1776
#define PRINT_FORMAT_HEX(value)                 \
1777
    _Generic((value),                           \
1778
             signed char: "%hhx",               \
1779
             unsigned char: "%hhx",             \
1780
             signed short: "%hx",               \
1781
             unsigned short: "%hx",             \
1782
             signed int: "%x",                  \
1783
             unsigned int: "%x",                \
1784
             long int: "%lx",                   \
1785
             unsigned long int: "%lx",          \
1786
             long long int: "%llx",             \
1787
             unsigned long long int: "%llx")
1788

1789
#define ASSERTION(actual, expected, check, format, formatter)   \
1790
    do {                                                        \
1791
        if (!check(actual, expected)) {                         \
1792
            nala_reset_all_mocks();                             \
1793
            char _nala_assert_format[512];                      \
1794
                                                                \
1795
            snprintf(&_nala_assert_format[0],                   \
1796
                     sizeof(_nala_assert_format),               \
1797
                     format,                                    \
1798
                     PRINT_FORMAT(actual),                      \
1799
                     PRINT_FORMAT(expected));                   \
1800
            nala_test_failure(formatter(_nala_assert_format,    \
1801
                                        actual,                 \
1802
                                        expected));             \
1803
        }                                                       \
1804
    } while (0);
1805

1806
#define ASSERTION_WITH_HEX(actual, expected, check, format, formatter)  \
1807
    do {                                                                \
1808
        if (!check(actual, expected)) {                                 \
1809
            nala_reset_all_mocks();                                     \
1810
            char _nala_assert_format[512];                              \
1811
                                                                        \
1812
            snprintf(&_nala_assert_format[0],                           \
1813
                     sizeof(_nala_assert_format),                       \
1814
                     format,                                            \
1815
                     PRINT_FORMAT(actual),                              \
1816
                     PRINT_FORMAT(expected),                            \
1817
                     PRINT_FORMAT_HEX(actual),                          \
1818
                     PRINT_FORMAT_HEX(expected));                       \
1819
            nala_test_failure(formatter(_nala_assert_format,            \
1820
                                        actual,                         \
1821
                                        expected,                       \
1822
                                        actual,                         \
1823
                                        expected));                     \
1824
        }                                                               \
1825
    } while (0);
1826

1827
#define BINARY_ASSERTION(actual, expected, op)                          \
1828
    switch (op) {                                                       \
1829
                                                                        \
1830
    case NALA_CHECK_EQ:                                                 \
1831
        ASSERTION(actual, expected, CHECK_EQ, "%s != %s\n", nala_format); \
1832
        break;                                                          \
1833
                                                                        \
1834
    case NALA_CHECK_NE:                                                 \
1835
        ASSERTION(actual, expected, CHECK_NE, "%s == %s\n", nala_format); \
1836
        break;                                                          \
1837
                                                                        \
1838
    case NALA_CHECK_LT:                                                 \
1839
        ASSERTION(actual, expected, CHECK_LT, "%s >= %s\n", nala_format); \
1840
        break;                                                          \
1841
                                                                        \
1842
    case NALA_CHECK_LE:                                                 \
1843
        ASSERTION(actual, expected, CHECK_LE, "%s > %s\n", nala_format); \
1844
        break;                                                          \
1845
                                                                        \
1846
    case NALA_CHECK_GT:                                                 \
1847
        ASSERTION(actual, expected, CHECK_GT, "%s <= %s\n", nala_format); \
1848
        break;                                                          \
1849
                                                                        \
1850
    case NALA_CHECK_GE:                                                 \
1851
        ASSERTION(actual, expected, CHECK_GE, "%s < %s\n", nala_format); \
1852
        break;                                                          \
1853
                                                                        \
1854
    default:                                                            \
1855
        FAIL("Internal nala error.");                                   \
1856
        break;                                                          \
1857
    }
1858

1859
#define BINARY_ASSERTION_WITH_HEX(actual, expected, op)                 \
1860
    switch (op) {                                                       \
1861
                                                                        \
1862
    case NALA_CHECK_EQ:                                                 \
1863
        ASSERTION_WITH_HEX(actual,                                      \
1864
                           expected,                                    \
1865
                           CHECK_EQ,                                    \
1866
                           "%s != %s (0x%s != 0x%s)\n",                 \
1867
                           nala_format);                                \
1868
        break;                                                          \
1869
                                                                        \
1870
    case NALA_CHECK_NE:                                                 \
1871
        ASSERTION_WITH_HEX(actual,                                      \
1872
                           expected,                                    \
1873
                           CHECK_NE,                                    \
1874
                           "%s == %s (0x%s == 0x%s)\n",                 \
1875
                           nala_format);                                \
1876
        break;                                                          \
1877
                                                                        \
1878
    default:                                                            \
1879
        BINARY_ASSERTION(actual, expected, op);                         \
1880
        break;                                                          \
1881
    }
1882

1883 0
void nala_assert_char(char actual, char expected, int op)
1884
{
1885 0
    BINARY_ASSERTION(actual, expected, op);
1886
}
1887

1888 0
void nala_assert_schar(signed char actual, signed char expected, int op)
1889
{
1890 0
    BINARY_ASSERTION(actual, expected, op);
1891
}
1892

1893 1
void nala_assert_uchar(unsigned char actual, unsigned char expected, int op)
1894
{
1895 1
    BINARY_ASSERTION(actual, expected, op);
1896
}
1897

1898 0
void nala_assert_short(short actual, short expected, int op)
1899
{
1900 0
    BINARY_ASSERTION_WITH_HEX(actual, expected, op);
1901
}
1902

1903 1
void nala_assert_ushort(unsigned short actual, unsigned short expected, int op)
1904
{
1905 1
    BINARY_ASSERTION_WITH_HEX(actual, expected, op);
1906
}
1907

1908 1
void nala_assert_int(int actual, int expected, int op)
1909
{
1910 1
    BINARY_ASSERTION_WITH_HEX(actual, expected, op);
1911
}
1912

1913 1
void nala_assert_uint(unsigned int actual, unsigned int expected, int op)
1914
{
1915 1
    BINARY_ASSERTION_WITH_HEX(actual, expected, op);
1916
}
1917

1918 0
void nala_assert_long(long actual, long expected, int op)
1919
{
1920 0
    BINARY_ASSERTION_WITH_HEX(actual, expected, op);
1921
}
1922

1923 1
void nala_assert_ulong(unsigned long actual, unsigned long expected, int op)
1924
{
1925 1
    BINARY_ASSERTION_WITH_HEX(actual, expected, op);
1926
}
1927

1928 0
void nala_assert_llong(long long actual, long long expected, int op)
1929
{
1930 0
    BINARY_ASSERTION_WITH_HEX(actual, expected, op);
1931
}
1932

1933 0
void nala_assert_ullong(unsigned long long actual,
1934
                        unsigned long long expected,
1935
                        int op)
1936
{
1937 0
    BINARY_ASSERTION_WITH_HEX(actual, expected, op);
1938
}
1939

1940 0
void nala_assert_float(float actual, float expected, int op)
1941
{
1942 0
    BINARY_ASSERTION(actual, expected, op);
1943
}
1944

1945 0
void nala_assert_double(double actual, double expected, int op)
1946
{
1947 0
    BINARY_ASSERTION(actual, expected, op);
1948
}
1949

1950 0
void nala_assert_ldouble(long double actual, long double expected, int op)
1951
{
1952 0
    BINARY_ASSERTION(actual, expected, op);
1953
}
1954

1955 0
void nala_assert_bool(bool actual, bool expected, int op)
1956
{
1957 0
    BINARY_ASSERTION(actual, expected, op);
1958
}
1959

1960 0
void nala_assert_ptr(const void *actual_p, const void *expected_p, int op)
1961
{
1962 0
    BINARY_ASSERTION(actual_p, expected_p, op);
1963
}
1964

1965
typedef void (*format_array_item_t)(FILE *file_p, const void *value_p);
1966

1967 0
static char *format_array(const void *buf_p,
1968
                          size_t item_size,
1969
                          size_t size,
1970
                          int i,
1971
                          format_array_item_t format_item)
1972
{
1973
    size_t file_size;
1974
    char *string_p;
1975
    FILE *file_p;
1976
    int length;
1977
    int begin;
1978
    int end;
1979
    const char *c_buf_p;
1980
    const char *delim_p;
1981

1982 0
    c_buf_p = (const char *)buf_p;
1983 0
    length = (int)(size / item_size);
1984 0
    begin = (i - 3);
1985

1986 0
    if (begin < 0) {
1987 0
        begin = 0;
1988
    }
1989

1990 0
    end = (i + 4);
1991

1992 0
    if (end > length) {
1993 0
        end = length;
1994
    }
1995

1996 0
    file_p = open_memstream(&string_p, &file_size);
1997 0
    fprintf(file_p, "{ ");
1998

1999 0
    if (begin != 0) {
2000 0
        fprintf(file_p, "..., ");
2001
    }
2002

2003 0
    delim_p = "";
2004

2005 0
    for (i = begin; i < end; i++) {
2006 0
        fprintf(file_p, "%s", delim_p);
2007 0
        format_item(file_p, &c_buf_p[i * (int)item_size]);
2008 0
        delim_p = ", ";
2009
    }
2010

2011 0
    if (end != length) {
2012 0
        fprintf(file_p, ", ...");
2013
    }
2014

2015 0
    fprintf(file_p, " }");
2016 0
    fputc('\0', file_p);
2017 0
    fclose(file_p);
2018

2019 0
    return (string_p);
2020
}
2021

2022 0
static void assert_array_failure(const void *actual_p,
2023
                                 const void *expected_p,
2024
                                 size_t item_size,
2025
                                 size_t size,
2026
                                 int i,
2027
                                 format_array_item_t format_item)
2028
{
2029
    size_t file_size;
2030
    char *buf_p;
2031
    FILE *file_p;
2032
    char *actual_string_p;
2033
    char *expected_string_p;
2034

2035 0
    nala_suspend_all_mocks();
2036

2037 0
    file_p = open_memstream(&buf_p, &file_size);
2038 0
    fprintf(file_p,
2039
            COLOR_BOLD(RED, "The arrays differ at index %u. See diff for details.\n"),
2040
            (unsigned)i);
2041 0
    actual_string_p = format_array(actual_p,
2042
                                   item_size,
2043
                                   size,
2044
                                   i,
2045
                                   format_item);
2046 0
    expected_string_p = format_array(expected_p,
2047
                                     item_size,
2048
                                     size,
2049
                                     i,
2050
                                     format_item);
2051 0
    print_string_diff(file_p, expected_string_p, actual_string_p);
2052 0
    free(actual_string_p);
2053 0
    free(expected_string_p);
2054 0
    fputc('\0', file_p);
2055 0
    fclose(file_p);
2056

2057 0
    nala_resume_all_mocks();
2058

2059 0
    nala_test_failure(buf_p);
2060
}
2061

2062 0
static void format_array_item_char(FILE *file_p, const void *value_p)
2063
{
2064 0
    fprintf(file_p, "%hhd", (int)*(char *)value_p);
2065
}
2066

2067 0
static void format_array_item_schar(FILE *file_p, const void *value_p)
2068
{
2069 0
    fprintf(file_p, "%hhd", *(signed char *)value_p);
2070
}
2071

2072 0
static void format_array_item_uchar(FILE *file_p, const void *value_p)
2073
{
2074 0
    fprintf(file_p, "%hhu", *(unsigned char *)value_p);
2075
}
2076

2077 0
static void format_array_item_short(FILE *file_p, const void *value_p)
2078
{
2079 0
    fprintf(file_p, "%hd", *(short *)value_p);
2080
}
2081

2082 0
static void format_array_item_ushort(FILE *file_p, const void *value_p)
2083
{
2084 0
    fprintf(file_p, "%hu", *(unsigned short *)value_p);
2085
}
2086

2087 0
static void format_array_item_int(FILE *file_p, const void *value_p)
2088
{
2089 0
    fprintf(file_p, "%d", *(int *)value_p);
2090
}
2091

2092 0
static void format_array_item_uint(FILE *file_p, const void *value_p)
2093
{
2094 0
    fprintf(file_p, "%u", *(unsigned *)value_p);
2095
}
2096

2097 0
static void format_array_item_long(FILE *file_p, const void *value_p)
2098
{
2099 0
    fprintf(file_p, "%ld", *(long *)value_p);
2100
}
2101

2102 0
static void format_array_item_ulong(FILE *file_p, const void *value_p)
2103
{
2104 0
    fprintf(file_p, "%lu", *(unsigned long *)value_p);
2105
}
2106

2107 0
static void format_array_item_llong(FILE *file_p, const void *value_p)
2108
{
2109 0
    fprintf(file_p, "%lld", *(long long *)value_p);
2110
}
2111

2112 0
static void format_array_item_ullong(FILE *file_p, const void *value_p)
2113
{
2114 0
    fprintf(file_p, "%llu", *(unsigned long long *)value_p);
2115
}
2116

2117 0
static void format_array_item_float(FILE *file_p, const void *value_p)
2118
{
2119 0
    fprintf(file_p, "%f", *(float *)value_p);
2120
}
2121

2122 0
static void format_array_item_double(FILE *file_p, const void *value_p)
2123
{
2124 0
    fprintf(file_p, "%f", *(double *)value_p);
2125
}
2126

2127 0
static void format_array_item_ldouble(FILE *file_p, const void *value_p)
2128
{
2129 0
    fprintf(file_p, "%Lf", *(long double *)value_p);
2130
}
2131

2132 0
static void format_array_item_bool(FILE *file_p, const void *value_p)
2133
{
2134 0
    fprintf(file_p, "%d", *(bool *)value_p);
2135
}
2136

2137
#define ASSERT_ARRAY_TYPE(type, actual_p, expected_p, item_size, size) \
2138
    size_t i;                                                           \
2139
                                                                        \
2140
    for (i = 0; i < size / item_size; i++) {                            \
2141
        if (actual_p[i] != expected_p[i]) {                             \
2142
            assert_array_failure(actual_p,                             \
2143
                                  expected_p,                           \
2144
                                  item_size,                            \
2145
                                  size,                                 \
2146
                                  (int)i,                               \
2147
                                  format_array_item_ ## type);          \
2148
        }                                                               \
2149
    }                                                                   \
2150

2151 0
void nala_assert_array_char(const char *actual_p,
2152
                             const char *expected_p,
2153
                             size_t item_size,
2154
                             size_t size)
2155
{
2156 0
    ASSERT_ARRAY_TYPE(char, actual_p, expected_p, item_size, size);
2157
}
2158

2159 0
void nala_assert_array_schar(const signed char *actual_p,
2160
                              const signed char *expected_p,
2161
                              size_t item_size,
2162
                              size_t size)
2163
{
2164 0
    ASSERT_ARRAY_TYPE(schar, actual_p, expected_p, item_size, size);
2165
}
2166

2167 0
void nala_assert_array_uchar(const unsigned char *actual_p,
2168
                              const unsigned char *expected_p,
2169
                              size_t item_size,
2170
                              size_t size)
2171
{
2172 0
    ASSERT_ARRAY_TYPE(uchar, actual_p, expected_p, item_size, size);
2173
}
2174

2175 0
void nala_assert_array_short(const short *actual_p,
2176
                              const short *expected_p,
2177
                              size_t item_size,
2178
                              size_t size)
2179
{
2180 0
    ASSERT_ARRAY_TYPE(short, actual_p, expected_p, item_size, size);
2181
}
2182

2183 0
void nala_assert_array_ushort(const unsigned short *actual_p,
2184
                               const unsigned short *expected_p,
2185
                               size_t item_size,
2186
                               size_t size)
2187
{
2188 0
    ASSERT_ARRAY_TYPE(ushort, actual_p, expected_p, item_size, size);
2189
}
2190

2191 0
void nala_assert_array_int(const int *actual_p,
2192
                            const int *expected_p,
2193
                            size_t item_size,
2194
                            size_t size)
2195
{
2196 0
    ASSERT_ARRAY_TYPE(int, actual_p, expected_p, item_size, size);
2197
}
2198

2199 0
void nala_assert_array_uint(const unsigned int *actual_p,
2200
                             const unsigned int *expected_p,
2201
                             size_t item_size,
2202
                             size_t size)
2203
{
2204 0
    ASSERT_ARRAY_TYPE(uint, actual_p, expected_p, item_size, size);
2205
}
2206

2207 0
void nala_assert_array_long(const long *actual_p,
2208
                             const long *expected_p,
2209
                             size_t item_size,
2210
                             size_t size)
2211
{
2212 0
    ASSERT_ARRAY_TYPE(long, actual_p, expected_p, item_size, size);
2213
}
2214

2215 0
void nala_assert_array_ulong(const unsigned long *actual_p,
2216
                              const unsigned long *expected_p,
2217
                              size_t item_size,
2218
                              size_t size)
2219
{
2220 0
    ASSERT_ARRAY_TYPE(ulong, actual_p, expected_p, item_size, size);
2221
}
2222

2223 0
void nala_assert_array_llong(const long long *actual_p,
2224
                              const long long *expected_p,
2225
                              size_t item_size,
2226
                              size_t size)
2227
{
2228 0
    ASSERT_ARRAY_TYPE(llong, actual_p, expected_p, item_size, size);
2229
}
2230

2231 0
void nala_assert_array_ullong(const unsigned long long *actual_p,
2232
                               const unsigned long long *expected_p,
2233
                               size_t item_size,
2234
                               size_t size)
2235
{
2236 0
    ASSERT_ARRAY_TYPE(ullong, actual_p, expected_p, item_size, size);
2237
}
2238

2239 0
void nala_assert_array_float(const float *actual_p,
2240
                              const float *expected_p,
2241
                              size_t item_size,
2242
                              size_t size)
2243
{
2244 0
    ASSERT_ARRAY_TYPE(float, actual_p, expected_p, item_size, size);
2245
}
2246

2247 0
void nala_assert_array_double(const double *actual_p,
2248
                               const double *expected_p,
2249
                               size_t item_size,
2250
                               size_t size)
2251
{
2252 0
    ASSERT_ARRAY_TYPE(double, actual_p, expected_p, item_size, size);
2253
}
2254

2255 0
void nala_assert_array_ldouble(const long double *actual_p,
2256
                                const long double *expected_p,
2257
                                size_t item_size,
2258
                                size_t size)
2259
{
2260 0
    ASSERT_ARRAY_TYPE(ldouble, actual_p, expected_p, item_size, size);
2261
}
2262

2263 0
void nala_assert_array_bool(const bool *actual_p,
2264
                             const bool *expected_p,
2265
                             size_t item_size,
2266
                             size_t size)
2267
{
2268 0
    ASSERT_ARRAY_TYPE(bool, actual_p, expected_p, item_size, size);
2269
}
2270

2271 0
void nala_assert_array(const void *actual_p,
2272
                       const void *expected_p,
2273
                       size_t item_size,
2274
                       size_t size)
2275
{
2276
    const char *c_actual_p;
2277
    const char *c_expected_p;
2278
    size_t i;
2279
    char buf[512];
2280

2281 0
    c_actual_p = (const char *)actual_p;
2282 0
    c_expected_p = (const char *)expected_p;
2283

2284 0
    for (i = 0; i < size; i += item_size) {
2285 0
        if (memcmp(&c_actual_p[i], &c_expected_p[i], item_size) != 0) {
2286 0
            snprintf(&buf[0],
2287
                     sizeof(buf),
2288
                     "The arrays differ at index %u. ",
2289 0
                     (unsigned)(i / item_size));
2290 0
            nala_test_failure(nala_format_memory(&buf[0],
2291
                                                 &c_actual_p[i],
2292
                                                 &c_expected_p[i],
2293
                                                 item_size));
2294
        }
2295
    }
2296
}
2297

2298 0
void nala_assert_string(const char *actual_p, const char *expected_p, int op)
2299
{
2300 0
    switch (op) {
2301

2302
    case NALA_CHECK_EQ:
2303 0
        if (!nala_check_string_equal(actual_p, expected_p)) {
2304 0
            nala_reset_all_mocks();
2305 0
            nala_test_failure(nala_format_string("The strings are not equal.",
2306
                                                 actual_p,
2307
                                                 expected_p));
2308
        }
2309

2310 0
        break;
2311

2312
    case NALA_CHECK_NE:
2313 0
        if (nala_check_string_equal(actual_p, expected_p)) {
2314 0
            nala_reset_all_mocks();
2315 0
            nala_test_failure(nala_format("\"%s\" == \"%s\"\n",
2316
                                          actual_p,
2317
                                          expected_p));
2318
        }
2319

2320 0
        break;
2321

2322
    default:
2323 0
        FAIL("Internal nala error.");
2324 0
        break;
2325
    }
2326
}
2327

2328 0
void nala_assert_substring(const char *haystack_p, const char *needle_p)
2329
{
2330 0
    if (!nala_check_substring(haystack_p, needle_p)) {
2331 0
        nala_reset_all_mocks();
2332 0
        nala_test_failure(
2333
            nala_format_substring(
2334
                "The haystack doesn't contain the needle.",
2335
                haystack_p,
2336
                needle_p));
2337
    }
2338
}
2339

2340 0
void nala_assert_not_substring(const char *haystack_p, const char *needle_p)
2341
{
2342 0
    ASSERTION(haystack_p,
2343
              needle_p,
2344
              !nala_check_substring,
2345
              "%s contains %s\n",
2346
              nala_format);
2347
}
2348

2349 1
void nala_assert_memory(const void *actual_p, const void *expected_p, size_t size)
2350
{
2351 1
    if (!nala_check_memory(actual_p, expected_p, size)) {
2352 0
        nala_reset_all_mocks();
2353 0
        nala_test_failure(nala_format_memory("", actual_p, expected_p, size));
2354
    }
2355
}
2356

2357 0
void nala_assert(bool cond)
2358
{
2359 0
    if (!cond) {
2360 0
        nala_reset_all_mocks();
2361 0
        nala_test_failure(nala_format("false != true\n"));
2362
    }
2363
}
2364

2365 0
void nala_fail(const char *message_p)
2366
{
2367 0
    nala_reset_all_mocks();
2368 0
    char message[strlen(message_p) + 2];
2369 0
    strcpy(&message[0], message_p);
2370 0
    strcat(&message[0], "\n");
2371 0
    nala_test_failure(nala_format(&message[0]));
2372
}
2373

2374 1
void nala_exit(int status)
2375
{
2376
    (void)status;
2377

2378 1
    nala_assert_all_mocks_completed();
2379 1
    nala_reset_all_mocks();
2380 1
    nala_suspend_all_mocks();
2381 1
    capture_output_destroy(&capture_stdout);
2382 1
    capture_output_destroy(&capture_stderr);
2383 1
    exit(0);
2384
}
2385
/*
2386
 * The MIT License (MIT)
2387
 *
2388
 * Copyright (c) 2019 Erik Moqvist
2389
 *
2390
 * Permission is hereby granted, free of charge, to any person
2391
 * obtaining a copy of this software and associated documentation
2392
 * files (the "Software"), to deal in the Software without
2393
 * restriction, including without limitation the rights to use, copy,
2394
 * modify, merge, publish, distribute, sublicense, and/or sell copies
2395
 * of the Software, and to permit persons to whom the Software is
2396
 * furnished to do so, subject to the following conditions:
2397
 *
2398
 * The above copyright notice and this permission notice shall be
2399
 * included in all copies or substantial portions of the Software.
2400
 *
2401
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2402
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2403
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2404
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2405
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2406
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2407
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2408
 * SOFTWARE.
2409
 *
2410
 * This file is part of the subprocess project.
2411
 */
2412

2413
#include <unistd.h>
2414
#include <errno.h>
2415
#include <stdio.h>
2416
#include <stdlib.h>
2417
#include <sys/types.h>
2418
#include <sys/wait.h>
2419
#include <poll.h>
2420
#include <fcntl.h>
2421
// #include "subprocess.h"
2422

2423

2424 0
static void fatal_error(const char *message_p)
2425
{
2426 0
    perror(message_p);
2427 0
    exit(1);
2428
}
2429

2430 1
static int output_init(struct nala_subprocess_output_t *self_p)
2431
{
2432
    int res;
2433

2434 1
    res = -1;
2435 1
    self_p->length = 0;
2436 1
    self_p->size = 4096;
2437 1
    self_p->buf_p = malloc(self_p->size);
2438

2439 1
    if (self_p->buf_p != NULL) {
2440 1
        self_p->buf_p[0] = '\0';
2441 1
        res = 0;
2442
    }
2443

2444 1
    return (res);
2445
}
2446

2447 0
static void output_append(struct nala_subprocess_output_t *self_p, int fd)
2448
{
2449
    ssize_t res;
2450

2451
    while (1) {
2452 0
        res = read(fd,
2453 0
                   &self_p->buf_p[self_p->length],
2454 0
                   self_p->size - self_p->length - 1);
2455

2456 0
        if (res == 0) {
2457 0
            break;
2458 0
        } else if (res > 0) {
2459 0
            self_p->length += (size_t)res;
2460 0
            self_p->buf_p[self_p->length] = '\0';
2461

2462 0
            if ((self_p->length + 1) == self_p->size) {
2463 0
                self_p->size += 4096;
2464 0
                self_p->buf_p = realloc(self_p->buf_p, self_p->size);
2465
            }
2466 0
        } else if (errno == EAGAIN) {
2467 0
            break;
2468 0
        } else if (errno != EINTR) {
2469
            /* ToDo: Fix. */
2470 0
            fatal_error("read");
2471
        }
2472
    }
2473
}
2474

2475 0
static void output_print(struct nala_subprocess_output_t *self_p,
2476
                         const char *name_p)
2477
{
2478 0
    printf("%s (length: %ld):\n", name_p, self_p->length);
2479 0
    printf("%s\n", self_p->buf_p);
2480
}
2481

2482 0
static void redirect_output(int *fds_p, int fileno)
2483
{
2484 0
    close(fds_p[0]);
2485 0
    while ((dup2(fds_p[1], fileno) == -1) && (errno == EINTR));
2486 0
    close(fds_p[1]);
2487
}
2488

2489 0
static void close_fds(int *fds_p)
2490
{
2491 0
    close(fds_p[0]);
2492 0
    close(fds_p[1]);
2493
}
2494

2495 1
static struct nala_subprocess_result_t *result_new(void)
2496
{
2497
    struct nala_subprocess_result_t *result_p;
2498
    int res;
2499

2500 1
    result_p = malloc(sizeof(*result_p));
2501

2502 1
    if (result_p == NULL) {
2503 0
        return (NULL);
2504
    }
2505

2506 1
    result_p->exit_code = -1;
2507 1
    result_p->signal_number = -1;
2508 1
    res = output_init(&result_p->stdout);
2509

2510 1
    if (res != 0) {
2511 0
        goto out1;
2512
    }
2513

2514 1
    res = output_init(&result_p->stderr);
2515

2516 1
    if (res != 0) {
2517 0
        goto out2;
2518
    }
2519

2520 1
    return (result_p);
2521

2522
 out2:
2523 0
    free(result_p->stdout.buf_p);
2524

2525
 out1:
2526 0
    free(result_p);
2527

2528 0
    return (NULL);
2529
}
2530

2531 1
static void call_child(nala_subprocess_entry_t entry,
2532
                       void *arg_p)
2533
{
2534 1
    entry(arg_p);
2535
}
2536

2537 1
static struct nala_subprocess_result_t *wait_for_pid(pid_t child_pid,
2538
                                                     struct nala_subprocess_result_t *result_p)
2539
{
2540
    int status;
2541

2542 1
    waitpid(child_pid, &status, 0);
2543

2544 1
    if (result_p != NULL) {
2545 1
        if (WIFEXITED(status)) {
2546 1
            result_p->exit_code = WEXITSTATUS(status);
2547
        }
2548

2549 1
        if (WIFSIGNALED(status)) {
2550 0
            result_p->signal_number = WTERMSIG(status);
2551
        }
2552
    }
2553

2554 1
    return (result_p);
2555
}
2556

2557 1
static struct nala_subprocess_result_t *call_parent(pid_t child_pid)
2558
{
2559 1
    return (wait_for_pid(child_pid, result_new()));
2560
}
2561

2562 0
static void call_output_child(nala_subprocess_entry_t entry,
2563
                              void *arg_p,
2564
                              int *stdoutfds_p,
2565
                              int *stderrfds_p)
2566
{
2567 0
    redirect_output(stdoutfds_p, STDOUT_FILENO);
2568 0
    redirect_output(stderrfds_p, STDERR_FILENO);
2569 0
    call_child(entry, arg_p);
2570
}
2571

2572 0
static int prepare_for_poll(struct pollfd *fd_p, int fd)
2573
{
2574
    int res;
2575

2576 0
    res = fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
2577 0
    fd_p->fd = fd;
2578 0
    fd_p->events = (POLLIN | POLLHUP);
2579

2580 0
    return (res);
2581
}
2582

2583 0
static struct nala_subprocess_result_t *read_output(int stdout_fd, int stderr_fd)
2584
{
2585
    struct nala_subprocess_result_t *result_p;
2586
    struct pollfd fds[2];
2587
    int res;
2588

2589 0
    result_p = result_new();
2590

2591 0
    if (result_p == NULL) {
2592 0
        return (NULL);
2593
    }
2594

2595 0
    prepare_for_poll(&fds[0], stdout_fd);
2596 0
    prepare_for_poll(&fds[1], stderr_fd);
2597

2598
    while (1) {
2599 0
        res = poll(&fds[0], 2, -1);
2600

2601 0
        if (res >= 0) {
2602 0
            if (fds[0].revents & POLLIN) {
2603 0
                output_append(&result_p->stdout, stdout_fd);
2604
            }
2605

2606 0
            if (fds[1].revents & POLLIN) {
2607 0
                output_append(&result_p->stderr, stderr_fd);
2608
            }
2609

2610 0
            if (fds[0].revents & POLLHUP) {
2611 0
                break;
2612
            }
2613

2614 0
            if (fds[1].revents & POLLHUP) {
2615 0
                break;
2616
            }
2617 0
        } else if (errno != EINTR) {
2618
            /* ToDo: Fix. */
2619 0
            fatal_error("poll");
2620
        }
2621
    }
2622

2623 0
    return (result_p);
2624
}
2625

2626 0
static struct nala_subprocess_result_t *call_output_parent(pid_t child_pid,
2627
                                                           int *stdoutfds_p,
2628
                                                           int *stderrfds_p)
2629
{
2630
    struct nala_subprocess_result_t *result_p;
2631

2632
    /* Close write ends. */
2633 0
    close(stdoutfds_p[1]);
2634 0
    close(stderrfds_p[1]);
2635

2636
    /* Read data from stdout and stderr pipes. */
2637 0
    result_p = read_output(stdoutfds_p[0], stderrfds_p[0]);
2638 0
    wait_for_pid(child_pid, result_p);
2639

2640 0
    close(stdoutfds_p[0]);
2641 0
    close(stderrfds_p[0]);
2642

2643 0
    return (result_p);
2644
}
2645

2646 0
static void exec_entry(const char *command_p)
2647
{
2648
    int res;
2649

2650 0
    res = execl("/bin/sh", "sh", "-c", command_p, NULL);
2651

2652 0
    if (res != 0) {
2653 0
        exit(1);
2654
    }
2655
}
2656

2657 1
struct nala_subprocess_result_t *nala_subprocess_call(nala_subprocess_entry_t entry,
2658
                                                      void *arg_p)
2659
{
2660
    pid_t pid;
2661
    struct nala_subprocess_result_t *result_p;
2662

2663 1
    fflush(stdout);
2664 1
    fflush(stderr);
2665

2666 1
    pid = fork();
2667

2668 1
    if (pid < 0) {
2669 0
        result_p = NULL;
2670 1
    } else if (pid == 0) {
2671 1
        call_child(entry, arg_p);
2672 0
        exit(0);
2673
    } else {
2674 1
        result_p = call_parent(pid);
2675
    }
2676

2677 1
    return (result_p);
2678
}
2679

2680 0
struct nala_subprocess_result_t *nala_subprocess_call_output(nala_subprocess_entry_t entry,
2681
                                                             void *arg_p)
2682
{
2683
    pid_t pid;
2684
    int stdoutfds[2];
2685
    int stderrfds[2];
2686
    struct nala_subprocess_result_t *result_p;
2687

2688 0
    fflush(stdout);
2689 0
    fflush(stderr);
2690

2691 0
    if (pipe(stdoutfds) < 0) {
2692 0
        return (NULL);
2693
    }
2694

2695 0
    if (pipe(stderrfds) < 0) {
2696 0
        goto out1;
2697
    }
2698

2699 0
    pid = fork();
2700

2701 0
    if (pid < 0) {
2702 0
        goto out2;
2703 0
    } else if (pid == 0) {
2704 0
        call_output_child(entry, arg_p, &stdoutfds[0], &stderrfds[0]);
2705 0
        exit(0);
2706
    } else {
2707 0
        result_p = call_output_parent(pid, &stdoutfds[0], &stderrfds[0]);
2708
    }
2709

2710 0
    return (result_p);
2711

2712
 out2:
2713 0
    close_fds(&stderrfds[0]);
2714

2715
 out1:
2716 0
    close_fds(&stdoutfds[0]);
2717

2718 0
    return (NULL);
2719
}
2720

2721 0
struct nala_subprocess_result_t *nala_subprocess_exec(const char *command_p)
2722
{
2723 0
    return (nala_subprocess_call((nala_subprocess_entry_t)exec_entry,
2724
                                 (void *)command_p));
2725
}
2726

2727 0
struct nala_subprocess_result_t *nala_subprocess_exec_output(const char *command_p)
2728
{
2729 0
    return (nala_subprocess_call_output((nala_subprocess_entry_t)exec_entry,
2730
                                        (void *)command_p));
2731
}
2732

2733 0
bool nala_subprocess_completed_successfully(struct nala_subprocess_result_t *result_p)
2734
{
2735 0
    return ((result_p != NULL) && (result_p->exit_code == 0));
2736
}
2737

2738 0
void nala_subprocess_result_print(struct nala_subprocess_result_t *self_p)
2739
{
2740 0
    printf("exit_code: %d\n", self_p->exit_code);
2741 0
    output_print(&self_p->stdout, "stdout");
2742 0
    output_print(&self_p->stderr, "stderr");
2743
}
2744

2745 1
void nala_subprocess_result_free(struct nala_subprocess_result_t *self_p)
2746
{
2747 1
    free(self_p->stdout.buf_p);
2748 1
    free(self_p->stderr.buf_p);
2749 1
    free(self_p);
2750
}
2751
/*
2752
 * The MIT License (MIT)
2753
 *
2754
 * Copyright (c) 2019 Erik Moqvist
2755
 *
2756
 * Permission is hereby granted, free of charge, to any person
2757
 * obtaining a copy of this software and associated documentation
2758
 * files (the "Software"), to deal in the Software without
2759
 * restriction, including without limitation the rights to use, copy,
2760
 * modify, merge, publish, distribute, sublicense, and/or sell copies
2761
 * of the Software, and to permit persons to whom the Software is
2762
 * furnished to do so, subject to the following conditions:
2763
 *
2764
 * The above copyright notice and this permission notice shall be
2765
 * included in all copies or substantial portions of the Software.
2766
 *
2767
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2768
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2769
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2770
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2771
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2772
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2773
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2774
 * SOFTWARE.
2775
 *
2776
 * This file is part of the traceback project.
2777
 */
2778

2779
#include <stdio.h>
2780
#include <stdint.h>
2781
#include <execinfo.h>
2782
#include <stdlib.h>
2783
#include <unistd.h>
2784
// #include "traceback.h"
2785

2786
// #include "subprocess.h"
2787

2788

2789
#define DEPTH_MAX 100
2790

2791
#define ANSI_COLOR_GREEN "\x1b[32m"
2792
#define ANSI_COLOR_CYAN  "\x1b[36m"
2793
#define ANSI_RESET       "\x1b[0m"
2794

2795
#define COLOR(color, ...) ANSI_RESET ANSI_COLOR_##color __VA_ARGS__ ANSI_RESET
2796

2797 0
static void *fixaddr(void *address_p)
2798
{
2799 0
    return ((void *)(((uintptr_t)address_p) - 1));
2800
}
2801

2802 0
static bool is_traceback_line(const char *line_p)
2803
{
2804 0
    if (strncmp(line_p, "traceback_print at ", 19) == 0) {
2805 0
        return (true);
2806
    }
2807

2808 0
    if (strncmp(line_p, "traceback_string at ", 20) == 0) {
2809 0
        return (true);
2810
    }
2811

2812 0
    return (false);
2813
}
2814

2815 0
static char *strip_discriminator(char *line_p)
2816
{
2817
    char *discriminator_p;
2818

2819 0
    discriminator_p = strstr(line_p, " (discriminator");
2820

2821 0
    if (discriminator_p != NULL) {
2822 0
        discriminator_p[0] = '\n';
2823 0
        discriminator_p[1] = '\0';
2824
    }
2825

2826 0
    return (line_p);
2827
}
2828

2829 0
static void print_line(FILE *stream_p, const char *prefix_p, char *line_p)
2830
{
2831
    char *at_p;
2832
    char *function_p;
2833
    char *location_p;
2834

2835 0
    function_p = line_p;
2836 0
    at_p = strstr(line_p, " at ");
2837

2838 0
    if (at_p == NULL) {
2839 0
        fprintf(stream_p, "%s  %s", prefix_p, line_p);
2840 0
        return;
2841
    }
2842

2843 0
    at_p[0] = '\0';
2844 0
    location_p = &at_p[4];
2845

2846 0
    fprintf(stream_p,
2847
            "%s  " COLOR(GREEN, "%s") " at " COLOR(CYAN, "%s"),
2848
            prefix_p,
2849
            function_p,
2850
            location_p);
2851
}
2852

2853 0
char *nala_traceback_format(void **buffer_pp,
2854
                       int depth,
2855
                       const char *prefix_p,
2856
                       const char *header_p,
2857
                       nala_traceback_skip_filter_t skip_filter,
2858
                       void *arg_p)
2859
{
2860
    char exe[256];
2861
    char command[384];
2862
    ssize_t size;
2863
    int i;
2864
    FILE *stream_p;
2865
    size_t stream_size;
2866
    struct nala_subprocess_result_t *result_p;
2867
    char *string_p;
2868

2869 0
    if (prefix_p == NULL) {
2870 0
        prefix_p = "";
2871
    }
2872

2873 0
    if (header_p == NULL) {
2874 0
        header_p = "Traceback (most recent call last):";
2875
    }
2876

2877 0
    size = readlink("/proc/self/exe", &exe[0], sizeof(exe) - 1);
2878

2879 0
    if (size == -1) {
2880 0
        return (NULL);
2881
    }
2882

2883 0
    exe[size] = '\0';
2884

2885 0
    stream_p = open_memstream(&string_p, &stream_size);
2886

2887 0
    if (stream_p == NULL) {
2888 0
        return (NULL);
2889
    }
2890

2891 0
    fprintf(stream_p, "%s%s\n", prefix_p, header_p);
2892

2893 0
    for (i = (depth - 1); i >= 0; i--) {
2894 0
        snprintf(&command[0],
2895
                 sizeof(command),
2896
                 "addr2line -f -p -e %s %p",
2897
                 &exe[0],
2898 0
                 fixaddr(buffer_pp[i]));
2899

2900 0
        result_p = nala_subprocess_exec_output(&command[0]);
2901

2902 0
        if (result_p->exit_code != 0) {
2903 0
            nala_subprocess_result_free(result_p);
2904 0
            continue;
2905
        }
2906

2907 0
        if (is_traceback_line(result_p->stdout.buf_p)) {
2908 0
            nala_subprocess_result_free(result_p);
2909 0
            continue;
2910
        }
2911

2912 0
        if (skip_filter != NULL) {
2913 0
            if (skip_filter(arg_p, result_p->stdout.buf_p)) {
2914 0
                nala_subprocess_result_free(result_p);
2915 0
                continue;
2916
            }
2917
        }
2918

2919 0
        print_line(stream_p,
2920
                   prefix_p,
2921
                   strip_discriminator(result_p->stdout.buf_p));
2922 0
        nala_subprocess_result_free(result_p);
2923
    }
2924

2925 0
    fclose(stream_p);
2926

2927 0
    return (string_p);
2928
}
2929

2930 0
char *nala_traceback_string(const char *prefix_p,
2931
                       const char *header_p,
2932
                       nala_traceback_skip_filter_t skip_filter,
2933
                       void *arg_p)
2934
{
2935
    int depth;
2936
    void *addresses[DEPTH_MAX];
2937

2938 0
    depth = backtrace(&addresses[0], DEPTH_MAX);
2939

2940 0
    return (nala_traceback_format(addresses,
2941
                             depth,
2942
                             prefix_p,
2943
                             header_p,
2944
                             skip_filter,
2945
                             arg_p));
2946
}
2947

2948 0
void nala_traceback_print(const char *prefix_p,
2949
                       const char *header_p,
2950
                     nala_traceback_skip_filter_t skip_filter,
2951
                     void *arg_p)
2952
{
2953
    char *string_p;
2954

2955 0
    string_p = nala_traceback_string(prefix_p, header_p, skip_filter, arg_p);
2956 0
    printf("%s", string_p);
2957 0
    free(string_p);
2958
}
2959
/*
2960
 * The MIT License (MIT)
2961
 *
2962
 * Copyright (c) 2019 Erik Moqvist
2963
 *
2964
 * Permission is hereby granted, free of charge, to any person
2965
 * obtaining a copy of this software and associated documentation
2966
 * files (the "Software"), to deal in the Software without
2967
 * restriction, including without limitation the rights to use, copy,
2968
 * modify, merge, publish, distribute, sublicense, and/or sell copies
2969
 * of the Software, and to permit persons to whom the Software is
2970
 * furnished to do so, subject to the following conditions:
2971
 *
2972
 * The above copyright notice and this permission notice shall be
2973
 * included in all copies or substantial portions of the Software.
2974
 *
2975
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
2976
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
2977
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
2978
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
2979
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2980
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
2981
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2982
 * SOFTWARE.
2983
 *
2984
 * This file is part of the humanfriendly project.
2985
 */
2986

2987
#include <string.h>
2988
#include <stdbool.h>
2989
#include <stdio.h>
2990
#include <pwd.h>
2991
// #include "hf.h"
2992

2993

2994
#define TIME_UNITS_MAX 7
2995

2996 1
static void nala_hf_null_last(char *buf_p, size_t size)
2997
{
2998 1
    buf_p[size - 1] = '\0';
2999
}
3000

3001 1
char *nala_hf_get_username(char *buf_p, size_t size, const char *default_p)
3002
{
3003
    char *res_p;
3004
    struct passwd *passwd_p;
3005

3006 1
    res_p = buf_p;
3007 1
    passwd_p = getpwuid(geteuid());
3008

3009 1
    if (passwd_p == NULL) {
3010 0
        if (default_p == NULL) {
3011 0
            res_p = NULL;
3012
        } else {
3013 0
            strncpy(buf_p, default_p, size);
3014
        }
3015
    } else {
3016 1
        strncpy(buf_p, passwd_p->pw_name, size);
3017

3018 1
        if (size > 0) {
3019 1
            nala_hf_null_last(buf_p, size);
3020
        }
3021
    }
3022

3023 1
    nala_hf_null_last(buf_p, size);
3024

3025 1
    return (res_p);
3026
}
3027

3028 1
char *nala_hf_get_hostname(char *buf_p, size_t size, const char *default_p)
3029
{
3030
    int res;
3031
    char *res_p;
3032

3033 1
    res_p = buf_p;
3034 1
    res = gethostname(buf_p, size);
3035

3036 1
    if (res != 0) {
3037 0
        if (default_p == NULL) {
3038 0
            res_p = NULL;
3039
        } else {
3040 0
            strncpy(buf_p, default_p, size);
3041
        }
3042
    }
3043

3044 1
    nala_hf_null_last(buf_p, size);
3045

3046 1
    return (res_p);
3047
}
3048

3049
/* Common time units, used for formatting of time spans. */
3050
struct time_unit_t {
3051
    unsigned long divider;
3052
    const char *unit_p;
3053
};
3054

3055
static struct time_unit_t time_units[TIME_UNITS_MAX] = {
3056
    {
3057
        .divider = 60 * 60 * 24 * 7 * 52 * 1000ul,
3058
        .unit_p = "y"
3059
    },
3060
    {
3061
        .divider = 60 * 60 * 24 * 7 * 1000ul,
3062
        .unit_p = "w"
3063
    },
3064
    {
3065
        .divider = 60 * 60 * 24 * 1000ul,
3066
        .unit_p = "d"
3067
    },
3068
    {
3069
        .divider = 60 * 60 * 1000ul,
3070
        .unit_p = "h"
3071
    },
3072
    {
3073
        .divider = 60 * 1000ul,
3074
        .unit_p = "m"
3075
    },
3076
    {
3077
        .divider = 1000ul,
3078
        .unit_p = "s"
3079
    },
3080
    {
3081
        .divider = 1ul,
3082
        .unit_p = "ms"
3083
    }
3084
};
3085

3086 1
static const char *get_delimiter(bool is_first, bool is_last)
3087
{
3088 1
    if (is_first) {
3089 1
        return ("");
3090 0
    } else if (is_last) {
3091 0
        return (" and ");
3092
    } else {
3093 0
        return (", ");
3094
    }
3095
}
3096

3097 1
char *nala_hf_format_timespan(char *buf_p,
3098
                              size_t size,
3099
                              unsigned long long timespan_ms)
3100
{
3101
    int i;
3102
    int res;
3103
    unsigned long long count;
3104
    size_t offset;
3105

3106 1
    strncpy(buf_p, "", size);
3107 1
    offset = 0;
3108

3109 1
    for (i = 0; i < TIME_UNITS_MAX; i++) {
3110 1
        count = (timespan_ms / time_units[i].divider);
3111 1
        timespan_ms -= (count * time_units[i].divider);
3112

3113 1
        if (count == 0) {
3114 1
            continue;
3115
        }
3116

3117 1
        res = snprintf(&buf_p[offset],
3118
                       size - offset,
3119
                       "%s%llu%s",
3120 1
                       get_delimiter(strlen(buf_p) == 0, timespan_ms == 0),
3121
                       count,
3122
                       time_units[i].unit_p);
3123 1
        nala_hf_null_last(buf_p, size);
3124

3125 1
        if (res > 0) {
3126 1
            offset += (size_t)res;
3127
        }
3128
    }
3129

3130 1
    if (strlen(buf_p) == 0) {
3131 1
        strncpy(buf_p, "0s", size);
3132 1
        nala_hf_null_last(buf_p, size);
3133
    }
3134

3135 1
    return (buf_p);
3136
}
3137
#include <stdio.h>
3138
#include <stdlib.h>
3139
#include <string.h>
3140
#include <sys/types.h>
3141
// #include "utils.h"
3142

3143

3144 0
int nala_min_int(int a, int b)
3145
{
3146 0
    return a < b ? a : b;
3147
}
3148

3149 0
size_t nala_min_size_t(size_t a, size_t b)
3150
{
3151 0
    return a < b ? a : b;
3152
}
3153

3154 0
size_t nala_count_chars(const char *string, char chr)
3155
{
3156 0
    size_t count = 0;
3157

3158 0
    for (size_t i = 0; string[i] != '\0'; i++) {
3159 0
        if (string[i] == chr) {
3160 0
            count++;
3161
        }
3162
    }
3163

3164 0
    return count;
3165
}
3166

3167 0
const char *nala_next_line(const char *string)
3168
{
3169 0
    char *next_line = strchr(string, '\n');
3170

3171 0
    if (next_line != NULL) {
3172 0
        return next_line;
3173
    } else {
3174 0
        return string + strlen(string);
3175
    }
3176
}
3177

3178 0
const char *nala_next_lines(const char *string, size_t lines)
3179
{
3180 0
    const char *next_line = string;
3181

3182 0
    for (size_t i = 0; i < lines; i++) {
3183 0
        next_line = nala_next_line(next_line) + 1;
3184
    }
3185

3186 0
    return next_line;
3187
}
3188
// #include "diff.h"
3189

3190

3191
#include <stdlib.h>
3192
#include <string.h>
3193
#include <sys/types.h>
3194

3195
// #include "../utils.h"
3196
#ifndef NALA_UTILS_H
3197
#define NALA_UTILS_H
3198

3199
#include <stdbool.h>
3200
#include <stdio.h>
3201

3202
int nala_min_int(int a, int b);
3203
size_t nala_min_size_t(size_t a, size_t b);
3204
size_t nala_count_chars(const char *string, char chr);
3205
const char *nala_next_line(const char *string);
3206
const char *nala_next_lines(const char *string, size_t lines);
3207

3208
#endif
3209

3210

3211
/*
3212
 * Diff matrix initialization
3213
 */
3214

3215 0
static void initialize_diff_matrix(struct NalaDiffMatrix *diff_matrix,
3216
                                   size_t rows,
3217
                                   size_t columns)
3218
{
3219 0
    diff_matrix->rows = rows;
3220 0
    diff_matrix->columns = columns;
3221 0
    diff_matrix->content = malloc(rows * columns * sizeof(int));
3222
}
3223

3224 0
struct NalaDiffMatrix *nala_new_diff_matrix(size_t rows, size_t columns)
3225
{
3226 0
    struct NalaDiffMatrix *diff_matrix = malloc(sizeof(struct NalaDiffMatrix));
3227 0
    initialize_diff_matrix(diff_matrix, rows, columns);
3228

3229 0
    return diff_matrix;
3230
}
3231

3232
/*
3233
 * Diff matrix operations
3234
 */
3235

3236 0
struct NalaDiffMatrix *nala_new_diff_matrix_from_lengths(size_t original_length,
3237
                                                         size_t modified_length)
3238
{
3239 0
    struct NalaDiffMatrix *diff_matrix =
3240 0
        nala_new_diff_matrix(modified_length + 1, original_length + 1);
3241

3242 0
    for (size_t i = 0; i < diff_matrix->rows; i++) {
3243 0
        nala_diff_matrix_set(diff_matrix, i, 0, (int)i);
3244
    }
3245

3246 0
    for (size_t j = 0; j < diff_matrix->columns; j++) {
3247 0
        nala_diff_matrix_set(diff_matrix, 0, j, (int)j);
3248
    }
3249

3250