mathematical 1.2.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +3 -3
- data/Rakefile +4 -0
- data/ext/mathematical/extconf.rb +9 -15
- data/ext/mathematical/mtex2MML/build/mtex2MML.h +73 -0
- data/ext/mathematical/mtex2MML/{src/deps → deps}/uthash/utarray.h +0 -0
- data/ext/mathematical/mtex2MML/{src/deps → deps}/uthash/uthash.h +0 -0
- data/ext/mathematical/mtex2MML/{src/deps → deps}/uthash/utlist.h +0 -0
- data/ext/mathematical/mtex2MML/{src/deps → deps}/uthash/utstring.h +0 -0
- data/ext/mathematical/mtex2MML/src/color_definitions.c +1 -1
- data/ext/mathematical/mtex2MML/src/lex.yy.c +1100 -1098
- data/ext/mathematical/mtex2MML/src/main.c +137 -0
- data/ext/mathematical/mtex2MML/src/mtex2MML.h +11 -1
- data/ext/mathematical/mtex2MML/src/parse_extras.c +2 -2
- data/ext/mathematical/mtex2MML/src/parse_extras.h +36 -36
- data/ext/mathematical/mtex2MML/src/string_extras.c +0 -6
- data/ext/mathematical/mtex2MML/src/string_extras.h +1 -1
- data/ext/mathematical/mtex2MML/src/y.tab.c +3904 -3583
- data/ext/mathematical/mtex2MML/tests/array.c +127 -0
- data/ext/mathematical/mtex2MML/tests/basic.c +85 -0
- data/ext/mathematical/mtex2MML/tests/clar.c +642 -0
- data/ext/mathematical/mtex2MML/tests/clar.h +163 -0
- data/ext/mathematical/mtex2MML/tests/clar/fixtures.h +38 -0
- data/ext/mathematical/mtex2MML/tests/clar/fs.h +333 -0
- data/ext/mathematical/mtex2MML/tests/clar/print.h +66 -0
- data/ext/mathematical/mtex2MML/tests/clar/sandbox.h +139 -0
- data/ext/mathematical/mtex2MML/tests/clar_test.h +20 -0
- data/ext/mathematical/mtex2MML/tests/cornercases.c +45 -0
- data/ext/mathematical/mtex2MML/tests/deps/file2str/file2str.c +64 -0
- data/ext/mathematical/mtex2MML/tests/deps/file2str/file2str.h +12 -0
- data/ext/mathematical/mtex2MML/tests/deps/trim/trim.c +24 -0
- data/ext/mathematical/mtex2MML/tests/deps/trim/trim.h +7 -0
- data/ext/mathematical/mtex2MML/tests/env.c +333 -0
- data/ext/mathematical/mtex2MML/tests/functions.c +45 -0
- data/ext/mathematical/mtex2MML/tests/helpers.c +27 -0
- data/ext/mathematical/mtex2MML/tests/helpers.h +8 -0
- data/ext/mathematical/mtex2MML/tests/main.c +35 -0
- data/ext/mathematical/mtex2MML/tests/maliciousness.c +82 -0
- data/ext/mathematical/mtex2MML/tests/mathjax.c +2030 -0
- data/ext/mathematical/mtex2MML/tests/numbered_equations.c +47 -0
- data/lib/mathematical.rb +3 -48
- data/lib/mathematical/validator.rb +52 -0
- data/lib/mathematical/version.rb +1 -1
- data/test/mathematical/basic_test.rb +7 -0
- data/test/mathematical/maliciousness_test.rb +26 -1
- data/test/mathematical/mathjax_test.rb +2 -2
- metadata +31 -7
- data/ext/mathematical/mtex2MML/ext/extconf.rb +0 -4
@@ -0,0 +1,127 @@
|
|
1
|
+
#include "clar.h"
|
2
|
+
#include "clar_test.h"
|
3
|
+
#include <stdio.h>
|
4
|
+
#include <string.h>
|
5
|
+
|
6
|
+
static char *fixture_tex;
|
7
|
+
static char *fixture_mml;
|
8
|
+
static char *result;
|
9
|
+
|
10
|
+
void test_array__initialize(void)
|
11
|
+
{
|
12
|
+
global_test_counter++;
|
13
|
+
}
|
14
|
+
|
15
|
+
void test_array__cleanup(void)
|
16
|
+
{
|
17
|
+
if (fixture_tex != NULL) {
|
18
|
+
free(fixture_tex);
|
19
|
+
}
|
20
|
+
|
21
|
+
if (fixture_mml != NULL) {
|
22
|
+
free(fixture_mml);
|
23
|
+
}
|
24
|
+
|
25
|
+
if (result != NULL) {
|
26
|
+
free(result);
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
void test_array__basic_array(void)
|
31
|
+
{
|
32
|
+
fixture_tex = read_fixture_tex("array/basic_array.txt");
|
33
|
+
fixture_mml = read_fixture_mml("array/basic_array.html");
|
34
|
+
result = mtex2MML_parse(fixture_tex, strlen(fixture_tex));
|
35
|
+
|
36
|
+
cl_assert_equal_s(fixture_mml, result);
|
37
|
+
}
|
38
|
+
|
39
|
+
void test_array__array_with_hline(void)
|
40
|
+
{
|
41
|
+
fixture_tex = read_fixture_tex("array/array_with_hline.txt");
|
42
|
+
fixture_mml = read_fixture_mml("array/array_with_hline.html");
|
43
|
+
result = mtex2MML_parse(fixture_tex, strlen(fixture_tex));
|
44
|
+
|
45
|
+
cl_assert_equal_s(fixture_mml, result);
|
46
|
+
}
|
47
|
+
|
48
|
+
void test_array__array_with_hline_and_hdashline(void)
|
49
|
+
{
|
50
|
+
fixture_tex = read_fixture_tex("array/array_with_hline_and_hdashline.txt");
|
51
|
+
fixture_mml = read_fixture_mml("array/array_with_hline_and_hdashline.html");
|
52
|
+
result = mtex2MML_parse(fixture_tex, strlen(fixture_tex));
|
53
|
+
|
54
|
+
cl_assert_equal_s(fixture_mml, result);
|
55
|
+
}
|
56
|
+
|
57
|
+
void test_array__array_pos_alignment(void)
|
58
|
+
{
|
59
|
+
fixture_tex = read_fixture_tex("array/array_pos_alignment.txt");
|
60
|
+
fixture_mml = read_fixture_mml("array/array_pos_alignment.html");
|
61
|
+
result = mtex2MML_parse(fixture_tex, strlen(fixture_tex));
|
62
|
+
|
63
|
+
cl_assert_equal_s(fixture_mml, result);
|
64
|
+
}
|
65
|
+
|
66
|
+
void test_array__array_pos_alignment_with_hline(void)
|
67
|
+
{
|
68
|
+
fixture_tex = read_fixture_tex("array/array_pos_alignment_with_hline.txt");
|
69
|
+
fixture_mml = read_fixture_mml("array/array_pos_alignment_with_hline.html");
|
70
|
+
result = mtex2MML_parse(fixture_tex, strlen(fixture_tex));
|
71
|
+
|
72
|
+
cl_assert_equal_s(fixture_mml, result);
|
73
|
+
}
|
74
|
+
|
75
|
+
void test_array__array_vertical_column(void)
|
76
|
+
{
|
77
|
+
fixture_tex = read_fixture_tex("array/array_vertical_column.txt");
|
78
|
+
fixture_mml = read_fixture_mml("array/array_vertical_column.html");
|
79
|
+
result = mtex2MML_parse(fixture_tex, strlen(fixture_tex));
|
80
|
+
|
81
|
+
cl_assert_equal_s(fixture_mml, result);
|
82
|
+
}
|
83
|
+
|
84
|
+
void test_array__array_vertical_column_with_align(void)
|
85
|
+
{
|
86
|
+
fixture_tex = read_fixture_tex("array/array_vertical_column_with_align.txt");
|
87
|
+
fixture_mml = read_fixture_mml("array/array_vertical_column_with_align.html");
|
88
|
+
result = mtex2MML_parse(fixture_tex, strlen(fixture_tex));
|
89
|
+
|
90
|
+
cl_assert_equal_s(fixture_mml, result);
|
91
|
+
}
|
92
|
+
|
93
|
+
void test_array__array_with_vertical_and_horizontal_dashes(void)
|
94
|
+
{
|
95
|
+
fixture_tex = read_fixture_tex("array/array_with_vertical_and_horizontal_dashes.txt");
|
96
|
+
fixture_mml = read_fixture_mml("array/array_with_vertical_and_horizontal_dashes.html");
|
97
|
+
result = mtex2MML_parse(fixture_tex, strlen(fixture_tex));
|
98
|
+
|
99
|
+
cl_assert_equal_s(fixture_mml, result);
|
100
|
+
}
|
101
|
+
|
102
|
+
void test_array__array_nesting(void)
|
103
|
+
{
|
104
|
+
fixture_tex = read_fixture_tex("array/array_nesting.txt");
|
105
|
+
fixture_mml = read_fixture_mml("array/array_nesting.html");
|
106
|
+
result = mtex2MML_parse(fixture_tex, strlen(fixture_tex));
|
107
|
+
|
108
|
+
cl_assert_equal_s(fixture_mml, result);
|
109
|
+
}
|
110
|
+
|
111
|
+
void test_array__strip_excess_whitespace_in_array_attributes(void)
|
112
|
+
{
|
113
|
+
fixture_tex = read_fixture_tex("array/strip_excess_whitespace_in_array_attributes.txt");
|
114
|
+
fixture_mml = read_fixture_mml("array/strip_excess_whitespace_in_array_attributes.html");
|
115
|
+
result = mtex2MML_parse(fixture_tex, strlen(fixture_tex));
|
116
|
+
|
117
|
+
cl_assert_equal_s(fixture_mml, result);
|
118
|
+
}
|
119
|
+
|
120
|
+
void test_array__augmented_matrix(void)
|
121
|
+
{
|
122
|
+
fixture_tex = read_fixture_tex("array/augmented_matrix.txt");
|
123
|
+
fixture_mml = read_fixture_mml("array/augmented_matrix.html");
|
124
|
+
result = mtex2MML_parse(fixture_tex, strlen(fixture_tex));
|
125
|
+
|
126
|
+
cl_assert_equal_s(fixture_mml, result);
|
127
|
+
}
|
@@ -0,0 +1,85 @@
|
|
1
|
+
#include "clar.h"
|
2
|
+
#include "clar_test.h"
|
3
|
+
#include "deps/trim/trim.h"
|
4
|
+
#include <stdio.h>
|
5
|
+
|
6
|
+
static char *fixture_tex;
|
7
|
+
static char *fixture_mml;
|
8
|
+
static char *result;
|
9
|
+
|
10
|
+
void test_basic__initialize(void)
|
11
|
+
{
|
12
|
+
global_test_counter++;
|
13
|
+
}
|
14
|
+
|
15
|
+
void test_basic__cleanup(void)
|
16
|
+
{
|
17
|
+
if (fixture_tex != NULL) {
|
18
|
+
free(fixture_tex);
|
19
|
+
}
|
20
|
+
|
21
|
+
if (fixture_mml != NULL) {
|
22
|
+
free(fixture_mml);
|
23
|
+
}
|
24
|
+
|
25
|
+
if (result != NULL) {
|
26
|
+
free(result);
|
27
|
+
}
|
28
|
+
}
|
29
|
+
|
30
|
+
void test_basic__inline(void)
|
31
|
+
{
|
32
|
+
fixture_tex = read_fixture_tex("basic/inline.txt");
|
33
|
+
fixture_mml = read_fixture_mml("basic/inline.html");
|
34
|
+
result = mtex2MML_parse(fixture_tex, strlen(fixture_tex));
|
35
|
+
|
36
|
+
cl_assert_equal_s(fixture_mml, result);
|
37
|
+
}
|
38
|
+
|
39
|
+
void test_basic__block(void)
|
40
|
+
{
|
41
|
+
fixture_tex = read_fixture_tex("basic/block.txt");
|
42
|
+
fixture_mml = read_fixture_mml("basic/block.html");
|
43
|
+
result = mtex2MML_parse(fixture_tex, strlen(fixture_tex));
|
44
|
+
|
45
|
+
cl_assert_equal_s(fixture_mml, result);
|
46
|
+
}
|
47
|
+
|
48
|
+
void test_basic__comments(void)
|
49
|
+
{
|
50
|
+
fixture_tex = read_fixture_tex("basic/comments.txt");
|
51
|
+
fixture_mml = read_fixture_mml("basic/comments.html");
|
52
|
+
result = mtex2MML_parse(fixture_tex, strlen(fixture_tex));
|
53
|
+
|
54
|
+
cl_assert_equal_s(fixture_mml, result);
|
55
|
+
}
|
56
|
+
|
57
|
+
void test_basic__filter(void)
|
58
|
+
{
|
59
|
+
fixture_tex = read_fixture_tex("basic/filter.txt");
|
60
|
+
fixture_mml = read_fixture_mml("basic/filter.html");
|
61
|
+
int status = mtex2MML_filter(fixture_tex, strlen(fixture_tex));
|
62
|
+
result = mtex2MML_output();
|
63
|
+
|
64
|
+
cl_assert_equal_s(fixture_mml, result);
|
65
|
+
}
|
66
|
+
|
67
|
+
void test_basic__html_filter(void)
|
68
|
+
{
|
69
|
+
fixture_tex = read_fixture_tex("basic/html_filter.txt");
|
70
|
+
fixture_mml = read_fixture_mml("basic/html_filter.html");
|
71
|
+
mtex2MML_html_filter(fixture_tex, strlen(fixture_tex));
|
72
|
+
result = mtex2MML_output();
|
73
|
+
|
74
|
+
cl_assert_equal_s(fixture_mml, trim(result));
|
75
|
+
}
|
76
|
+
|
77
|
+
void test_basic__strict_html_filter(void)
|
78
|
+
{
|
79
|
+
fixture_tex = read_fixture_tex("basic/strict_html_filter.txt");
|
80
|
+
fixture_mml = read_fixture_mml("basic/strict_html_filter.html");
|
81
|
+
mtex2MML_strict_html_filter(fixture_tex, strlen(fixture_tex));
|
82
|
+
result = mtex2MML_output();
|
83
|
+
|
84
|
+
cl_assert_equal_s(fixture_mml, trim(result));
|
85
|
+
}
|
@@ -0,0 +1,642 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright (c) Vicent Marti. All rights reserved.
|
3
|
+
*
|
4
|
+
* This file is part of clar, distributed under the ISC license.
|
5
|
+
* For full terms see the included COPYING file.
|
6
|
+
*/
|
7
|
+
#include <assert.h>
|
8
|
+
#include <setjmp.h>
|
9
|
+
#include <stdlib.h>
|
10
|
+
#include <stdio.h>
|
11
|
+
#include <string.h>
|
12
|
+
#include <math.h>
|
13
|
+
#include <stdarg.h>
|
14
|
+
#include <wchar.h>
|
15
|
+
|
16
|
+
/* required for sandboxing */
|
17
|
+
#include <sys/types.h>
|
18
|
+
#include <sys/stat.h>
|
19
|
+
|
20
|
+
#ifdef _WIN32
|
21
|
+
# include <windows.h>
|
22
|
+
# include <io.h>
|
23
|
+
# include <shellapi.h>
|
24
|
+
# include <direct.h>
|
25
|
+
|
26
|
+
# define _MAIN_CC __cdecl
|
27
|
+
|
28
|
+
# ifndef stat
|
29
|
+
# define stat(path, st) _stat(path, st)
|
30
|
+
# endif
|
31
|
+
# ifndef mkdir
|
32
|
+
# define mkdir(path, mode) _mkdir(path)
|
33
|
+
# endif
|
34
|
+
# ifndef chdir
|
35
|
+
# define chdir(path) _chdir(path)
|
36
|
+
# endif
|
37
|
+
# ifndef access
|
38
|
+
# define access(path, mode) _access(path, mode)
|
39
|
+
# endif
|
40
|
+
# ifndef strdup
|
41
|
+
# define strdup(str) _strdup(str)
|
42
|
+
# endif
|
43
|
+
# ifndef strcasecmp
|
44
|
+
# define strcasecmp(a,b) _stricmp(a,b)
|
45
|
+
# endif
|
46
|
+
|
47
|
+
# ifndef __MINGW32__
|
48
|
+
# pragma comment(lib, "shell32")
|
49
|
+
# ifndef strncpy
|
50
|
+
# define strncpy(to, from, to_size) strncpy_s(to, to_size, from, _TRUNCATE)
|
51
|
+
# endif
|
52
|
+
# ifndef W_OK
|
53
|
+
# define W_OK 02
|
54
|
+
# endif
|
55
|
+
# ifndef S_ISDIR
|
56
|
+
# define S_ISDIR(x) ((x & _S_IFDIR) != 0)
|
57
|
+
# endif
|
58
|
+
# define p_snprintf(buf,sz,fmt,...) _snprintf_s(buf,sz,_TRUNCATE,fmt,__VA_ARGS__)
|
59
|
+
# else
|
60
|
+
# define p_snprintf snprintf
|
61
|
+
# endif
|
62
|
+
|
63
|
+
# ifndef PRIuZ
|
64
|
+
# define PRIuZ "Iu"
|
65
|
+
# endif
|
66
|
+
# ifndef PRIxZ
|
67
|
+
# define PRIxZ "Ix"
|
68
|
+
# endif
|
69
|
+
|
70
|
+
# ifdef _MSC_VER
|
71
|
+
typedef struct stat STAT_T;
|
72
|
+
# else
|
73
|
+
typedef struct _stat STAT_T;
|
74
|
+
# endif
|
75
|
+
#else
|
76
|
+
# include <sys/wait.h> /* waitpid(2) */
|
77
|
+
# include <unistd.h>
|
78
|
+
# define _MAIN_CC
|
79
|
+
# define p_snprintf snprintf
|
80
|
+
# ifndef PRIuZ
|
81
|
+
# define PRIuZ "zu"
|
82
|
+
# endif
|
83
|
+
# ifndef PRIxZ
|
84
|
+
# define PRIxZ "zx"
|
85
|
+
# endif
|
86
|
+
typedef struct stat STAT_T;
|
87
|
+
#endif
|
88
|
+
|
89
|
+
#include "clar.h"
|
90
|
+
|
91
|
+
static void fs_rm(const char *_source);
|
92
|
+
static void fs_copy(const char *_source, const char *dest);
|
93
|
+
|
94
|
+
static const char *
|
95
|
+
fixture_path(const char *base, const char *fixture_name);
|
96
|
+
|
97
|
+
struct clar_error {
|
98
|
+
const char *test;
|
99
|
+
int test_number;
|
100
|
+
const char *suite;
|
101
|
+
const char *file;
|
102
|
+
int line_number;
|
103
|
+
const char *error_msg;
|
104
|
+
char *description;
|
105
|
+
|
106
|
+
struct clar_error *next;
|
107
|
+
};
|
108
|
+
|
109
|
+
static struct {
|
110
|
+
int argc;
|
111
|
+
char **argv;
|
112
|
+
|
113
|
+
enum cl_test_status test_status;
|
114
|
+
const char *active_test;
|
115
|
+
const char *active_suite;
|
116
|
+
|
117
|
+
int total_skipped;
|
118
|
+
int total_errors;
|
119
|
+
|
120
|
+
int tests_ran;
|
121
|
+
int suites_ran;
|
122
|
+
|
123
|
+
int report_errors_only;
|
124
|
+
int exit_on_error;
|
125
|
+
int report_suite_names;
|
126
|
+
|
127
|
+
struct clar_error *errors;
|
128
|
+
struct clar_error *last_error;
|
129
|
+
|
130
|
+
void (*local_cleanup)(void *);
|
131
|
+
void *local_cleanup_payload;
|
132
|
+
|
133
|
+
jmp_buf trampoline;
|
134
|
+
int trampoline_enabled;
|
135
|
+
|
136
|
+
cl_trace_cb *pfn_trace_cb;
|
137
|
+
void *trace_payload;
|
138
|
+
|
139
|
+
} _clar;
|
140
|
+
|
141
|
+
struct clar_func {
|
142
|
+
const char *name;
|
143
|
+
void (*ptr)(void);
|
144
|
+
};
|
145
|
+
|
146
|
+
struct clar_suite {
|
147
|
+
const char *name;
|
148
|
+
struct clar_func initialize;
|
149
|
+
struct clar_func cleanup;
|
150
|
+
const struct clar_func *tests;
|
151
|
+
size_t test_count;
|
152
|
+
int enabled;
|
153
|
+
};
|
154
|
+
|
155
|
+
/* From clar_print_*.c */
|
156
|
+
static void clar_print_init(int test_count, int suite_count, const char *suite_names);
|
157
|
+
static void clar_print_shutdown(int test_count, int suite_count, int error_count);
|
158
|
+
static void clar_print_error(int num, const struct clar_error *error);
|
159
|
+
static void clar_print_ontest(const char *test_name, int test_number, enum cl_test_status failed);
|
160
|
+
static void clar_print_onsuite(const char *suite_name, int suite_index);
|
161
|
+
static void clar_print_onabort(const char *msg, ...);
|
162
|
+
|
163
|
+
/* From clar_sandbox.c */
|
164
|
+
static void clar_unsandbox(void);
|
165
|
+
static int clar_sandbox(void);
|
166
|
+
|
167
|
+
/* Load the declarations for the test suite */
|
168
|
+
#include "clar.suite"
|
169
|
+
|
170
|
+
|
171
|
+
#define CL_TRACE(ev) \
|
172
|
+
do { \
|
173
|
+
if (_clar.pfn_trace_cb) \
|
174
|
+
_clar.pfn_trace_cb(ev, \
|
175
|
+
_clar.active_suite, \
|
176
|
+
_clar.active_test, \
|
177
|
+
_clar.trace_payload); \
|
178
|
+
} while (0)
|
179
|
+
|
180
|
+
void cl_trace_register(cl_trace_cb *cb, void *payload)
|
181
|
+
{
|
182
|
+
_clar.pfn_trace_cb = cb;
|
183
|
+
_clar.trace_payload = payload;
|
184
|
+
}
|
185
|
+
|
186
|
+
|
187
|
+
/* Core test functions */
|
188
|
+
static void
|
189
|
+
clar_report_errors(void)
|
190
|
+
{
|
191
|
+
int i = 1;
|
192
|
+
struct clar_error *error, *next;
|
193
|
+
|
194
|
+
error = _clar.errors;
|
195
|
+
while (error != NULL) {
|
196
|
+
next = error->next;
|
197
|
+
clar_print_error(i++, error);
|
198
|
+
free(error->description);
|
199
|
+
free(error);
|
200
|
+
error = next;
|
201
|
+
}
|
202
|
+
|
203
|
+
_clar.errors = _clar.last_error = NULL;
|
204
|
+
}
|
205
|
+
|
206
|
+
static void
|
207
|
+
clar_run_test(
|
208
|
+
const struct clar_func *test,
|
209
|
+
const struct clar_func *initialize,
|
210
|
+
const struct clar_func *cleanup)
|
211
|
+
{
|
212
|
+
_clar.test_status = CL_TEST_OK;
|
213
|
+
_clar.trampoline_enabled = 1;
|
214
|
+
|
215
|
+
CL_TRACE(CL_TRACE__TEST__BEGIN);
|
216
|
+
|
217
|
+
if (setjmp(_clar.trampoline) == 0) {
|
218
|
+
if (initialize->ptr != NULL)
|
219
|
+
initialize->ptr();
|
220
|
+
|
221
|
+
CL_TRACE(CL_TRACE__TEST__RUN_BEGIN);
|
222
|
+
test->ptr();
|
223
|
+
CL_TRACE(CL_TRACE__TEST__RUN_END);
|
224
|
+
}
|
225
|
+
|
226
|
+
_clar.trampoline_enabled = 0;
|
227
|
+
|
228
|
+
if (_clar.local_cleanup != NULL)
|
229
|
+
_clar.local_cleanup(_clar.local_cleanup_payload);
|
230
|
+
|
231
|
+
if (cleanup->ptr != NULL)
|
232
|
+
cleanup->ptr();
|
233
|
+
|
234
|
+
CL_TRACE(CL_TRACE__TEST__END);
|
235
|
+
|
236
|
+
_clar.tests_ran++;
|
237
|
+
|
238
|
+
/* remove any local-set cleanup methods */
|
239
|
+
_clar.local_cleanup = NULL;
|
240
|
+
_clar.local_cleanup_payload = NULL;
|
241
|
+
|
242
|
+
if (_clar.report_errors_only) {
|
243
|
+
clar_report_errors();
|
244
|
+
} else {
|
245
|
+
clar_print_ontest(test->name, _clar.tests_ran, _clar.test_status);
|
246
|
+
}
|
247
|
+
}
|
248
|
+
|
249
|
+
static void
|
250
|
+
clar_run_suite(const struct clar_suite *suite, const char *filter)
|
251
|
+
{
|
252
|
+
const struct clar_func *test = suite->tests;
|
253
|
+
size_t i, matchlen;
|
254
|
+
|
255
|
+
if (!suite->enabled)
|
256
|
+
return;
|
257
|
+
|
258
|
+
if (_clar.exit_on_error && _clar.total_errors)
|
259
|
+
return;
|
260
|
+
|
261
|
+
if (!_clar.report_errors_only)
|
262
|
+
clar_print_onsuite(suite->name, ++_clar.suites_ran);
|
263
|
+
|
264
|
+
_clar.active_suite = suite->name;
|
265
|
+
_clar.active_test = NULL;
|
266
|
+
CL_TRACE(CL_TRACE__SUITE_BEGIN);
|
267
|
+
|
268
|
+
if (filter) {
|
269
|
+
size_t suitelen = strlen(suite->name);
|
270
|
+
matchlen = strlen(filter);
|
271
|
+
if (matchlen <= suitelen) {
|
272
|
+
filter = NULL;
|
273
|
+
} else {
|
274
|
+
filter += suitelen;
|
275
|
+
while (*filter == ':')
|
276
|
+
++filter;
|
277
|
+
matchlen = strlen(filter);
|
278
|
+
}
|
279
|
+
}
|
280
|
+
|
281
|
+
for (i = 0; i < suite->test_count; ++i) {
|
282
|
+
if (filter && strncmp(test[i].name, filter, matchlen))
|
283
|
+
continue;
|
284
|
+
|
285
|
+
_clar.active_test = test[i].name;
|
286
|
+
clar_run_test(&test[i], &suite->initialize, &suite->cleanup);
|
287
|
+
|
288
|
+
if (_clar.exit_on_error && _clar.total_errors)
|
289
|
+
return;
|
290
|
+
}
|
291
|
+
|
292
|
+
_clar.active_test = NULL;
|
293
|
+
CL_TRACE(CL_TRACE__SUITE_END);
|
294
|
+
}
|
295
|
+
|
296
|
+
static void
|
297
|
+
clar_usage(const char *arg)
|
298
|
+
{
|
299
|
+
printf("Usage: %s [options]\n\n", arg);
|
300
|
+
printf("Options:\n");
|
301
|
+
printf(" -sname\tRun only the suite with `name` (can go to individual test name)\n");
|
302
|
+
printf(" -iname\tInclude the suite with `name`\n");
|
303
|
+
printf(" -xname\tExclude the suite with `name`\n");
|
304
|
+
printf(" -v \tIncrease verbosity (show suite names)\n");
|
305
|
+
printf(" -q \tOnly report tests that had an error\n");
|
306
|
+
printf(" -Q \tQuit as soon as a test fails\n");
|
307
|
+
printf(" -l \tPrint suite names\n");
|
308
|
+
exit(-1);
|
309
|
+
}
|
310
|
+
|
311
|
+
static void
|
312
|
+
clar_parse_args(int argc, char **argv)
|
313
|
+
{
|
314
|
+
int i;
|
315
|
+
|
316
|
+
for (i = 1; i < argc; ++i) {
|
317
|
+
char *argument = argv[i];
|
318
|
+
|
319
|
+
if (argument[0] != '-')
|
320
|
+
clar_usage(argv[0]);
|
321
|
+
|
322
|
+
switch (argument[1]) {
|
323
|
+
case 's':
|
324
|
+
case 'i':
|
325
|
+
case 'x': { /* given suite name */
|
326
|
+
int offset = (argument[2] == '=') ? 3 : 2, found = 0;
|
327
|
+
char action = argument[1];
|
328
|
+
size_t j, arglen, suitelen, cmplen;
|
329
|
+
|
330
|
+
argument += offset;
|
331
|
+
arglen = strlen(argument);
|
332
|
+
|
333
|
+
if (arglen == 0)
|
334
|
+
clar_usage(argv[0]);
|
335
|
+
|
336
|
+
for (j = 0; j < _clar_suite_count; ++j) {
|
337
|
+
suitelen = strlen(_clar_suites[j].name);
|
338
|
+
cmplen = (arglen < suitelen) ? arglen : suitelen;
|
339
|
+
|
340
|
+
if (strncmp(argument, _clar_suites[j].name, cmplen) == 0) {
|
341
|
+
int exact = (arglen >= suitelen);
|
342
|
+
|
343
|
+
++found;
|
344
|
+
|
345
|
+
if (!exact)
|
346
|
+
_clar.report_suite_names = 1;
|
347
|
+
|
348
|
+
switch (action) {
|
349
|
+
case 's': _clar_suites[j].enabled = 1; clar_run_suite(&_clar_suites[j], argument); break;
|
350
|
+
case 'i': _clar_suites[j].enabled = 1; break;
|
351
|
+
case 'x': _clar_suites[j].enabled = 0; break;
|
352
|
+
}
|
353
|
+
|
354
|
+
if (exact)
|
355
|
+
break;
|
356
|
+
}
|
357
|
+
}
|
358
|
+
|
359
|
+
if (!found) {
|
360
|
+
clar_print_onabort("No suite matching '%s' found.\n", argument);
|
361
|
+
exit(-1);
|
362
|
+
}
|
363
|
+
break;
|
364
|
+
}
|
365
|
+
|
366
|
+
case 'q':
|
367
|
+
_clar.report_errors_only = 1;
|
368
|
+
break;
|
369
|
+
|
370
|
+
case 'Q':
|
371
|
+
_clar.exit_on_error = 1;
|
372
|
+
break;
|
373
|
+
|
374
|
+
case 'l': {
|
375
|
+
size_t j;
|
376
|
+
printf("Test suites (use -s<name> to run just one):\n");
|
377
|
+
for (j = 0; j < _clar_suite_count; ++j)
|
378
|
+
printf(" %3d: %s\n", (int)j, _clar_suites[j].name);
|
379
|
+
|
380
|
+
exit(0);
|
381
|
+
}
|
382
|
+
|
383
|
+
case 'v':
|
384
|
+
_clar.report_suite_names = 1;
|
385
|
+
break;
|
386
|
+
|
387
|
+
default:
|
388
|
+
clar_usage(argv[0]);
|
389
|
+
}
|
390
|
+
}
|
391
|
+
}
|
392
|
+
|
393
|
+
void
|
394
|
+
clar_test_init(int argc, char **argv)
|
395
|
+
{
|
396
|
+
clar_print_init(
|
397
|
+
(int)_clar_callback_count,
|
398
|
+
(int)_clar_suite_count,
|
399
|
+
""
|
400
|
+
);
|
401
|
+
|
402
|
+
if (clar_sandbox() < 0) {
|
403
|
+
clar_print_onabort("Failed to sandbox the test runner.\n");
|
404
|
+
exit(-1);
|
405
|
+
}
|
406
|
+
|
407
|
+
_clar.argc = argc;
|
408
|
+
_clar.argv = argv;
|
409
|
+
}
|
410
|
+
|
411
|
+
int
|
412
|
+
clar_test_run()
|
413
|
+
{
|
414
|
+
if (_clar.argc > 1)
|
415
|
+
clar_parse_args(_clar.argc, _clar.argv);
|
416
|
+
|
417
|
+
if (!_clar.suites_ran) {
|
418
|
+
size_t i;
|
419
|
+
for (i = 0; i < _clar_suite_count; ++i)
|
420
|
+
clar_run_suite(&_clar_suites[i], NULL);
|
421
|
+
}
|
422
|
+
|
423
|
+
return _clar.total_errors;
|
424
|
+
}
|
425
|
+
|
426
|
+
void
|
427
|
+
clar_test_shutdown()
|
428
|
+
{
|
429
|
+
clar_print_shutdown(
|
430
|
+
_clar.tests_ran,
|
431
|
+
(int)_clar_suite_count,
|
432
|
+
_clar.total_errors
|
433
|
+
);
|
434
|
+
|
435
|
+
clar_unsandbox();
|
436
|
+
}
|
437
|
+
|
438
|
+
int
|
439
|
+
clar_test(int argc, char **argv)
|
440
|
+
{
|
441
|
+
int errors;
|
442
|
+
|
443
|
+
clar_test_init(argc, argv);
|
444
|
+
errors = clar_test_run();
|
445
|
+
clar_test_shutdown();
|
446
|
+
|
447
|
+
return errors;
|
448
|
+
}
|
449
|
+
|
450
|
+
static void abort_test(void)
|
451
|
+
{
|
452
|
+
if (!_clar.trampoline_enabled) {
|
453
|
+
clar_print_onabort(
|
454
|
+
"Fatal error: a cleanup method raised an exception.");
|
455
|
+
clar_report_errors();
|
456
|
+
exit(-1);
|
457
|
+
}
|
458
|
+
|
459
|
+
CL_TRACE(CL_TRACE__TEST__LONGJMP);
|
460
|
+
longjmp(_clar.trampoline, -1);
|
461
|
+
}
|
462
|
+
|
463
|
+
void clar__skip(void)
|
464
|
+
{
|
465
|
+
_clar.test_status = CL_TEST_SKIP;
|
466
|
+
_clar.total_skipped++;
|
467
|
+
abort_test();
|
468
|
+
}
|
469
|
+
|
470
|
+
void clar__fail(
|
471
|
+
const char *file,
|
472
|
+
int line,
|
473
|
+
const char *error_msg,
|
474
|
+
const char *description,
|
475
|
+
int should_abort)
|
476
|
+
{
|
477
|
+
struct clar_error *error = calloc(1, sizeof(struct clar_error));
|
478
|
+
|
479
|
+
if (_clar.errors == NULL)
|
480
|
+
_clar.errors = error;
|
481
|
+
|
482
|
+
if (_clar.last_error != NULL)
|
483
|
+
_clar.last_error->next = error;
|
484
|
+
|
485
|
+
_clar.last_error = error;
|
486
|
+
|
487
|
+
error->test = _clar.active_test;
|
488
|
+
error->test_number = _clar.tests_ran;
|
489
|
+
error->suite = _clar.active_suite;
|
490
|
+
error->file = file;
|
491
|
+
error->line_number = line;
|
492
|
+
error->error_msg = error_msg;
|
493
|
+
|
494
|
+
if (description != NULL)
|
495
|
+
error->description = strdup(description);
|
496
|
+
|
497
|
+
_clar.total_errors++;
|
498
|
+
_clar.test_status = CL_TEST_FAILURE;
|
499
|
+
|
500
|
+
if (should_abort)
|
501
|
+
abort_test();
|
502
|
+
}
|
503
|
+
|
504
|
+
void clar__assert(
|
505
|
+
int condition,
|
506
|
+
const char *file,
|
507
|
+
int line,
|
508
|
+
const char *error_msg,
|
509
|
+
const char *description,
|
510
|
+
int should_abort)
|
511
|
+
{
|
512
|
+
if (condition)
|
513
|
+
return;
|
514
|
+
|
515
|
+
clar__fail(file, line, error_msg, description, should_abort);
|
516
|
+
}
|
517
|
+
|
518
|
+
void clar__assert_equal(
|
519
|
+
const char *file,
|
520
|
+
int line,
|
521
|
+
const char *err,
|
522
|
+
int should_abort,
|
523
|
+
const char *fmt,
|
524
|
+
...)
|
525
|
+
{
|
526
|
+
va_list args;
|
527
|
+
char buf[4096];
|
528
|
+
int is_equal = 1;
|
529
|
+
|
530
|
+
va_start(args, fmt);
|
531
|
+
|
532
|
+
if (!strcmp("%s", fmt)) {
|
533
|
+
const char *s1 = va_arg(args, const char *);
|
534
|
+
const char *s2 = va_arg(args, const char *);
|
535
|
+
is_equal = (!s1 || !s2) ? (s1 == s2) : !strcmp(s1, s2);
|
536
|
+
|
537
|
+
if (!is_equal) {
|
538
|
+
if (s1 && s2) {
|
539
|
+
int pos;
|
540
|
+
for (pos = 0; s1[pos] == s2[pos] && s1[pos] && s2[pos]; ++pos)
|
541
|
+
/* find differing byte offset */;
|
542
|
+
p_snprintf(buf, sizeof(buf), "'%s' != '%s' (at byte %d)",
|
543
|
+
s1, s2, pos);
|
544
|
+
} else {
|
545
|
+
p_snprintf(buf, sizeof(buf), "'%s' != '%s'", s1, s2);
|
546
|
+
}
|
547
|
+
}
|
548
|
+
}
|
549
|
+
else if(!strcmp("%.*s", fmt)) {
|
550
|
+
const char *s1 = va_arg(args, const char *);
|
551
|
+
const char *s2 = va_arg(args, const char *);
|
552
|
+
int len = va_arg(args, int);
|
553
|
+
is_equal = (!s1 || !s2) ? (s1 == s2) : !strncmp(s1, s2, len);
|
554
|
+
|
555
|
+
if (!is_equal) {
|
556
|
+
if (s1 && s2) {
|
557
|
+
int pos;
|
558
|
+
for (pos = 0; s1[pos] == s2[pos] && pos < len; ++pos)
|
559
|
+
/* find differing byte offset */;
|
560
|
+
p_snprintf(buf, sizeof(buf), "'%.*s' != '%.*s' (at byte %d)",
|
561
|
+
len, s1, len, s2, pos);
|
562
|
+
} else {
|
563
|
+
p_snprintf(buf, sizeof(buf), "'%.*s' != '%.*s'", len, s1, len, s2);
|
564
|
+
}
|
565
|
+
}
|
566
|
+
}
|
567
|
+
else if (!strcmp("%ls", fmt)) {
|
568
|
+
const wchar_t *wcs1 = va_arg(args, const wchar_t *);
|
569
|
+
const wchar_t *wcs2 = va_arg(args, const wchar_t *);
|
570
|
+
is_equal = (!wcs1 || !wcs2) ? (wcs1 == wcs2) : !wcscmp(wcs1, wcs2);
|
571
|
+
|
572
|
+
if (!is_equal) {
|
573
|
+
if (wcs1 && wcs2) {
|
574
|
+
int pos;
|
575
|
+
for (pos = 0; wcs1[pos] == wcs2[pos] && wcs1[pos] && wcs2[pos]; ++pos)
|
576
|
+
/* find differing byte offset */;
|
577
|
+
p_snprintf(buf, sizeof(buf), "'%ls' != '%ls' (at byte %d)",
|
578
|
+
wcs1, wcs2, pos);
|
579
|
+
} else {
|
580
|
+
p_snprintf(buf, sizeof(buf), "'%ls' != '%ls'", wcs1, wcs2);
|
581
|
+
}
|
582
|
+
}
|
583
|
+
}
|
584
|
+
else if(!strcmp("%.*ls", fmt)) {
|
585
|
+
const wchar_t *wcs1 = va_arg(args, const wchar_t *);
|
586
|
+
const wchar_t *wcs2 = va_arg(args, const wchar_t *);
|
587
|
+
int len = va_arg(args, int);
|
588
|
+
is_equal = (!wcs1 || !wcs2) ? (wcs1 == wcs2) : !wcsncmp(wcs1, wcs2, len);
|
589
|
+
|
590
|
+
if (!is_equal) {
|
591
|
+
if (wcs1 && wcs2) {
|
592
|
+
int pos;
|
593
|
+
for (pos = 0; wcs1[pos] == wcs2[pos] && pos < len; ++pos)
|
594
|
+
/* find differing byte offset */;
|
595
|
+
p_snprintf(buf, sizeof(buf), "'%.*ls' != '%.*ls' (at byte %d)",
|
596
|
+
len, wcs1, len, wcs2, pos);
|
597
|
+
} else {
|
598
|
+
p_snprintf(buf, sizeof(buf), "'%.*ls' != '%.*ls'", len, wcs1, len, wcs2);
|
599
|
+
}
|
600
|
+
}
|
601
|
+
}
|
602
|
+
else if (!strcmp("%"PRIuZ, fmt) || !strcmp("%"PRIxZ, fmt)) {
|
603
|
+
size_t sz1 = va_arg(args, size_t), sz2 = va_arg(args, size_t);
|
604
|
+
is_equal = (sz1 == sz2);
|
605
|
+
if (!is_equal) {
|
606
|
+
int offset = p_snprintf(buf, sizeof(buf), fmt, sz1);
|
607
|
+
strncat(buf, " != ", sizeof(buf) - offset);
|
608
|
+
p_snprintf(buf + offset + 4, sizeof(buf) - offset - 4, fmt, sz2);
|
609
|
+
}
|
610
|
+
}
|
611
|
+
else if (!strcmp("%p", fmt)) {
|
612
|
+
void *p1 = va_arg(args, void *), *p2 = va_arg(args, void *);
|
613
|
+
is_equal = (p1 == p2);
|
614
|
+
if (!is_equal)
|
615
|
+
p_snprintf(buf, sizeof(buf), "%p != %p", p1, p2);
|
616
|
+
}
|
617
|
+
else {
|
618
|
+
int i1 = va_arg(args, int), i2 = va_arg(args, int);
|
619
|
+
is_equal = (i1 == i2);
|
620
|
+
if (!is_equal) {
|
621
|
+
int offset = p_snprintf(buf, sizeof(buf), fmt, i1);
|
622
|
+
strncat(buf, " != ", sizeof(buf) - offset);
|
623
|
+
p_snprintf(buf + offset + 4, sizeof(buf) - offset - 4, fmt, i2);
|
624
|
+
}
|
625
|
+
}
|
626
|
+
|
627
|
+
va_end(args);
|
628
|
+
|
629
|
+
if (!is_equal)
|
630
|
+
clar__fail(file, line, err, buf, should_abort);
|
631
|
+
}
|
632
|
+
|
633
|
+
void cl_set_cleanup(void (*cleanup)(void *), void *opaque)
|
634
|
+
{
|
635
|
+
_clar.local_cleanup = cleanup;
|
636
|
+
_clar.local_cleanup_payload = opaque;
|
637
|
+
}
|
638
|
+
|
639
|
+
#include "clar/sandbox.h"
|
640
|
+
#include "clar/fixtures.h"
|
641
|
+
#include "clar/fs.h"
|
642
|
+
#include "clar/print.h"
|