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
|
|