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,163 @@
|
|
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
|
+
#ifndef __CLAR_TEST_H__
|
8
|
+
#define __CLAR_TEST_H__
|
9
|
+
|
10
|
+
#include <stdlib.h>
|
11
|
+
|
12
|
+
extern int global_test_counter;
|
13
|
+
|
14
|
+
enum cl_test_status {
|
15
|
+
CL_TEST_OK,
|
16
|
+
CL_TEST_FAILURE,
|
17
|
+
CL_TEST_SKIP
|
18
|
+
};
|
19
|
+
|
20
|
+
void clar_test_init(int argc, char *argv[]);
|
21
|
+
int clar_test_run(void);
|
22
|
+
void clar_test_shutdown(void);
|
23
|
+
|
24
|
+
int clar_test(int argc, char *argv[]);
|
25
|
+
|
26
|
+
const char *clar_sandbox_path(void);
|
27
|
+
|
28
|
+
void cl_set_cleanup(void (*cleanup)(void *), void *opaque);
|
29
|
+
void cl_fs_cleanup(void);
|
30
|
+
|
31
|
+
/**
|
32
|
+
* cl_trace_* is a hook to provide a simple global tracing
|
33
|
+
* mechanism.
|
34
|
+
*
|
35
|
+
* The goal here is to let main() provide clar-proper
|
36
|
+
* with a callback to optionally write log info for
|
37
|
+
* test operations into the same stream used by their
|
38
|
+
* actual tests. This would let them print test names
|
39
|
+
* and maybe performance data as they choose.
|
40
|
+
*
|
41
|
+
* The goal is NOT to alter the flow of control or to
|
42
|
+
* override test selection/skipping. (So the callback
|
43
|
+
* does not return a value.)
|
44
|
+
*
|
45
|
+
* The goal is NOT to duplicate the existing
|
46
|
+
* pass/fail/skip reporting. (So the callback
|
47
|
+
* does not accept a status/errorcode argument.)
|
48
|
+
*
|
49
|
+
*/
|
50
|
+
typedef enum cl_trace_event {
|
51
|
+
CL_TRACE__SUITE_BEGIN,
|
52
|
+
CL_TRACE__SUITE_END,
|
53
|
+
CL_TRACE__TEST__BEGIN,
|
54
|
+
CL_TRACE__TEST__END,
|
55
|
+
CL_TRACE__TEST__RUN_BEGIN,
|
56
|
+
CL_TRACE__TEST__RUN_END,
|
57
|
+
CL_TRACE__TEST__LONGJMP,
|
58
|
+
} cl_trace_event;
|
59
|
+
|
60
|
+
typedef void (cl_trace_cb)(
|
61
|
+
cl_trace_event ev,
|
62
|
+
const char *suite_name,
|
63
|
+
const char *test_name,
|
64
|
+
void *payload);
|
65
|
+
|
66
|
+
/**
|
67
|
+
* Register a callback into CLAR to send global trace events.
|
68
|
+
* Pass NULL to disable.
|
69
|
+
*/
|
70
|
+
void cl_trace_register(cl_trace_cb *cb, void *payload);
|
71
|
+
|
72
|
+
|
73
|
+
#ifdef CLAR_FIXTURE_PATH
|
74
|
+
const char *cl_fixture(const char *fixture_name);
|
75
|
+
void cl_fixture_sandbox(const char *fixture_name);
|
76
|
+
void cl_fixture_cleanup(const char *fixture_name);
|
77
|
+
#endif
|
78
|
+
|
79
|
+
/**
|
80
|
+
* Assertion macros with explicit error message
|
81
|
+
*/
|
82
|
+
#define cl_must_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __LINE__, "Function call failed: " #expr, desc, 1)
|
83
|
+
#define cl_must_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __LINE__, "Expected function call to fail: " #expr, desc, 1)
|
84
|
+
#define cl_assert_(expr, desc) clar__assert((expr) != 0, __FILE__, __LINE__, "Expression is not true: " #expr, desc, 1)
|
85
|
+
|
86
|
+
/**
|
87
|
+
* Check macros with explicit error message
|
88
|
+
*/
|
89
|
+
#define cl_check_pass_(expr, desc) clar__assert((expr) >= 0, __FILE__, __LINE__, "Function call failed: " #expr, desc, 0)
|
90
|
+
#define cl_check_fail_(expr, desc) clar__assert((expr) < 0, __FILE__, __LINE__, "Expected function call to fail: " #expr, desc, 0)
|
91
|
+
#define cl_check_(expr, desc) clar__assert((expr) != 0, __FILE__, __LINE__, "Expression is not true: " #expr, desc, 0)
|
92
|
+
|
93
|
+
/**
|
94
|
+
* Assertion macros with no error message
|
95
|
+
*/
|
96
|
+
#define cl_must_pass(expr) cl_must_pass_(expr, NULL)
|
97
|
+
#define cl_must_fail(expr) cl_must_fail_(expr, NULL)
|
98
|
+
#define cl_assert(expr) cl_assert_(expr, NULL)
|
99
|
+
|
100
|
+
/**
|
101
|
+
* Check macros with no error message
|
102
|
+
*/
|
103
|
+
#define cl_check_pass(expr) cl_check_pass_(expr, NULL)
|
104
|
+
#define cl_check_fail(expr) cl_check_fail_(expr, NULL)
|
105
|
+
#define cl_check(expr) cl_check_(expr, NULL)
|
106
|
+
|
107
|
+
/**
|
108
|
+
* Forced failure/warning
|
109
|
+
*/
|
110
|
+
#define cl_fail(desc) clar__fail(__FILE__, __LINE__, "Test failed.", desc, 1)
|
111
|
+
#define cl_warning(desc) clar__fail(__FILE__, __LINE__, "Warning during test execution:", desc, 0)
|
112
|
+
|
113
|
+
#define cl_skip() clar__skip()
|
114
|
+
|
115
|
+
/**
|
116
|
+
* Typed assertion macros
|
117
|
+
*/
|
118
|
+
#define cl_assert_equal_s(s1,s2) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #s1 " != " #s2, 1, "%s", (s1), (s2))
|
119
|
+
#define cl_assert_equal_s_(s1,s2,note) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%s", (s1), (s2))
|
120
|
+
|
121
|
+
#define cl_assert_equal_wcs(wcs1,wcs2) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2, 1, "%ls", (wcs1), (wcs2))
|
122
|
+
#define cl_assert_equal_wcs_(wcs1,wcs2,note) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%ls", (wcs1), (wcs2))
|
123
|
+
|
124
|
+
#define cl_assert_equal_strn(s1,s2,len) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #s1 " != " #s2, 1, "%.*s", (s1), (s2), (int)(len))
|
125
|
+
#define cl_assert_equal_strn_(s1,s2,len,note) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #s1 " != " #s2 " (" #note ")", 1, "%.*s", (s1), (s2), (int)(len))
|
126
|
+
|
127
|
+
#define cl_assert_equal_wcsn(wcs1,wcs2,len) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2, 1, "%.*ls", (wcs1), (wcs2), (int)(len))
|
128
|
+
#define cl_assert_equal_wcsn_(wcs1,wcs2,len,note) clar__assert_equal(__FILE__,__LINE__,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%.*ls", (wcs1), (wcs2), (int)(len))
|
129
|
+
|
130
|
+
#define cl_assert_equal_i(i1,i2) clar__assert_equal(__FILE__,__LINE__,#i1 " != " #i2, 1, "%d", (int)(i1), (int)(i2))
|
131
|
+
#define cl_assert_equal_i_(i1,i2,note) clar__assert_equal(__FILE__,__LINE__,#i1 " != " #i2 " (" #note ")", 1, "%d", (i1), (i2))
|
132
|
+
#define cl_assert_equal_i_fmt(i1,i2,fmt) clar__assert_equal(__FILE__,__LINE__,#i1 " != " #i2, 1, (fmt), (int)(i1), (int)(i2))
|
133
|
+
|
134
|
+
#define cl_assert_equal_b(b1,b2) clar__assert_equal(__FILE__,__LINE__,#b1 " != " #b2, 1, "%d", (int)((b1) != 0),(int)((b2) != 0))
|
135
|
+
|
136
|
+
#define cl_assert_equal_p(p1,p2) clar__assert_equal(__FILE__,__LINE__,"Pointer mismatch: " #p1 " != " #p2, 1, "%p", (p1), (p2))
|
137
|
+
|
138
|
+
void clar__skip(void);
|
139
|
+
|
140
|
+
void clar__fail(
|
141
|
+
const char *file,
|
142
|
+
int line,
|
143
|
+
const char *error,
|
144
|
+
const char *description,
|
145
|
+
int should_abort);
|
146
|
+
|
147
|
+
void clar__assert(
|
148
|
+
int condition,
|
149
|
+
const char *file,
|
150
|
+
int line,
|
151
|
+
const char *error,
|
152
|
+
const char *description,
|
153
|
+
int should_abort);
|
154
|
+
|
155
|
+
void clar__assert_equal(
|
156
|
+
const char *file,
|
157
|
+
int line,
|
158
|
+
const char *err,
|
159
|
+
int should_abort,
|
160
|
+
const char *fmt,
|
161
|
+
...);
|
162
|
+
|
163
|
+
#endif
|
@@ -0,0 +1,38 @@
|
|
1
|
+
static const char *
|
2
|
+
fixture_path(const char *base, const char *fixture_name)
|
3
|
+
{
|
4
|
+
static char _path[4096];
|
5
|
+
size_t root_len;
|
6
|
+
|
7
|
+
root_len = strlen(base);
|
8
|
+
strncpy(_path, base, sizeof(_path));
|
9
|
+
|
10
|
+
if (_path[root_len - 1] != '/')
|
11
|
+
_path[root_len++] = '/';
|
12
|
+
|
13
|
+
if (fixture_name[0] == '/')
|
14
|
+
fixture_name++;
|
15
|
+
|
16
|
+
strncpy(_path + root_len,
|
17
|
+
fixture_name,
|
18
|
+
sizeof(_path) - root_len);
|
19
|
+
|
20
|
+
return _path;
|
21
|
+
}
|
22
|
+
|
23
|
+
#ifdef CLAR_FIXTURE_PATH
|
24
|
+
const char *cl_fixture(const char *fixture_name)
|
25
|
+
{
|
26
|
+
return fixture_path(CLAR_FIXTURE_PATH, fixture_name);
|
27
|
+
}
|
28
|
+
|
29
|
+
void cl_fixture_sandbox(const char *fixture_name)
|
30
|
+
{
|
31
|
+
fs_copy(cl_fixture(fixture_name), _clar_path);
|
32
|
+
}
|
33
|
+
|
34
|
+
void cl_fixture_cleanup(const char *fixture_name)
|
35
|
+
{
|
36
|
+
fs_rm(fixture_path(_clar_path, fixture_name));
|
37
|
+
}
|
38
|
+
#endif
|
@@ -0,0 +1,333 @@
|
|
1
|
+
#ifdef _WIN32
|
2
|
+
|
3
|
+
#define RM_RETRY_COUNT 5
|
4
|
+
#define RM_RETRY_DELAY 10
|
5
|
+
|
6
|
+
#ifdef __MINGW32__
|
7
|
+
|
8
|
+
/* These security-enhanced functions are not available
|
9
|
+
* in MinGW, so just use the vanilla ones */
|
10
|
+
#define wcscpy_s(a, b, c) wcscpy((a), (c))
|
11
|
+
#define wcscat_s(a, b, c) wcscat((a), (c))
|
12
|
+
|
13
|
+
#endif /* __MINGW32__ */
|
14
|
+
|
15
|
+
static int
|
16
|
+
fs__dotordotdot(WCHAR *_tocheck)
|
17
|
+
{
|
18
|
+
return _tocheck[0] == '.' &&
|
19
|
+
(_tocheck[1] == '\0' ||
|
20
|
+
(_tocheck[1] == '.' && _tocheck[2] == '\0'));
|
21
|
+
}
|
22
|
+
|
23
|
+
static int
|
24
|
+
fs_rmdir_rmdir(WCHAR *_wpath)
|
25
|
+
{
|
26
|
+
unsigned retries = 1;
|
27
|
+
|
28
|
+
while (!RemoveDirectoryW(_wpath)) {
|
29
|
+
/* Only retry when we have retries remaining, and the
|
30
|
+
* error was ERROR_DIR_NOT_EMPTY. */
|
31
|
+
if (retries++ > RM_RETRY_COUNT ||
|
32
|
+
ERROR_DIR_NOT_EMPTY != GetLastError())
|
33
|
+
return -1;
|
34
|
+
|
35
|
+
/* Give whatever has a handle to a child item some time
|
36
|
+
* to release it before trying again */
|
37
|
+
Sleep(RM_RETRY_DELAY * retries * retries);
|
38
|
+
}
|
39
|
+
|
40
|
+
return 0;
|
41
|
+
}
|
42
|
+
|
43
|
+
static void
|
44
|
+
fs_rmdir_helper(WCHAR *_wsource)
|
45
|
+
{
|
46
|
+
WCHAR buffer[MAX_PATH];
|
47
|
+
HANDLE find_handle;
|
48
|
+
WIN32_FIND_DATAW find_data;
|
49
|
+
size_t buffer_prefix_len;
|
50
|
+
|
51
|
+
/* Set up the buffer and capture the length */
|
52
|
+
wcscpy_s(buffer, MAX_PATH, _wsource);
|
53
|
+
wcscat_s(buffer, MAX_PATH, L"\\");
|
54
|
+
buffer_prefix_len = wcslen(buffer);
|
55
|
+
|
56
|
+
/* FindFirstFile needs a wildcard to match multiple items */
|
57
|
+
wcscat_s(buffer, MAX_PATH, L"*");
|
58
|
+
find_handle = FindFirstFileW(buffer, &find_data);
|
59
|
+
cl_assert(INVALID_HANDLE_VALUE != find_handle);
|
60
|
+
|
61
|
+
do {
|
62
|
+
/* FindFirstFile/FindNextFile gives back . and ..
|
63
|
+
* entries at the beginning */
|
64
|
+
if (fs__dotordotdot(find_data.cFileName))
|
65
|
+
continue;
|
66
|
+
|
67
|
+
wcscpy_s(buffer + buffer_prefix_len, MAX_PATH - buffer_prefix_len, find_data.cFileName);
|
68
|
+
|
69
|
+
if (FILE_ATTRIBUTE_DIRECTORY & find_data.dwFileAttributes)
|
70
|
+
fs_rmdir_helper(buffer);
|
71
|
+
else {
|
72
|
+
/* If set, the +R bit must be cleared before deleting */
|
73
|
+
if (FILE_ATTRIBUTE_READONLY & find_data.dwFileAttributes)
|
74
|
+
cl_assert(SetFileAttributesW(buffer, find_data.dwFileAttributes & ~FILE_ATTRIBUTE_READONLY));
|
75
|
+
|
76
|
+
cl_assert(DeleteFileW(buffer));
|
77
|
+
}
|
78
|
+
}
|
79
|
+
while (FindNextFileW(find_handle, &find_data));
|
80
|
+
|
81
|
+
/* Ensure that we successfully completed the enumeration */
|
82
|
+
cl_assert(ERROR_NO_MORE_FILES == GetLastError());
|
83
|
+
|
84
|
+
/* Close the find handle */
|
85
|
+
FindClose(find_handle);
|
86
|
+
|
87
|
+
/* Now that the directory is empty, remove it */
|
88
|
+
cl_assert(0 == fs_rmdir_rmdir(_wsource));
|
89
|
+
}
|
90
|
+
|
91
|
+
static int
|
92
|
+
fs_rm_wait(WCHAR *_wpath)
|
93
|
+
{
|
94
|
+
unsigned retries = 1;
|
95
|
+
DWORD last_error;
|
96
|
+
|
97
|
+
do {
|
98
|
+
if (INVALID_FILE_ATTRIBUTES == GetFileAttributesW(_wpath))
|
99
|
+
last_error = GetLastError();
|
100
|
+
else
|
101
|
+
last_error = ERROR_SUCCESS;
|
102
|
+
|
103
|
+
/* Is the item gone? */
|
104
|
+
if (ERROR_FILE_NOT_FOUND == last_error ||
|
105
|
+
ERROR_PATH_NOT_FOUND == last_error)
|
106
|
+
return 0;
|
107
|
+
|
108
|
+
Sleep(RM_RETRY_DELAY * retries * retries);
|
109
|
+
}
|
110
|
+
while (retries++ <= RM_RETRY_COUNT);
|
111
|
+
|
112
|
+
return -1;
|
113
|
+
}
|
114
|
+
|
115
|
+
static void
|
116
|
+
fs_rm(const char *_source)
|
117
|
+
{
|
118
|
+
WCHAR wsource[MAX_PATH];
|
119
|
+
DWORD attrs;
|
120
|
+
|
121
|
+
/* The input path is UTF-8. Convert it to wide characters
|
122
|
+
* for use with the Windows API */
|
123
|
+
cl_assert(MultiByteToWideChar(CP_UTF8,
|
124
|
+
MB_ERR_INVALID_CHARS,
|
125
|
+
_source,
|
126
|
+
-1, /* Indicates NULL termination */
|
127
|
+
wsource,
|
128
|
+
MAX_PATH));
|
129
|
+
|
130
|
+
/* Does the item exist? If not, we have no work to do */
|
131
|
+
attrs = GetFileAttributesW(wsource);
|
132
|
+
|
133
|
+
if (INVALID_FILE_ATTRIBUTES == attrs)
|
134
|
+
return;
|
135
|
+
|
136
|
+
if (FILE_ATTRIBUTE_DIRECTORY & attrs)
|
137
|
+
fs_rmdir_helper(wsource);
|
138
|
+
else {
|
139
|
+
/* The item is a file. Strip the +R bit */
|
140
|
+
if (FILE_ATTRIBUTE_READONLY & attrs)
|
141
|
+
cl_assert(SetFileAttributesW(wsource, attrs & ~FILE_ATTRIBUTE_READONLY));
|
142
|
+
|
143
|
+
cl_assert(DeleteFileW(wsource));
|
144
|
+
}
|
145
|
+
|
146
|
+
/* Wait for the DeleteFile or RemoveDirectory call to complete */
|
147
|
+
cl_assert(0 == fs_rm_wait(wsource));
|
148
|
+
}
|
149
|
+
|
150
|
+
static void
|
151
|
+
fs_copydir_helper(WCHAR *_wsource, WCHAR *_wdest)
|
152
|
+
{
|
153
|
+
WCHAR buf_source[MAX_PATH], buf_dest[MAX_PATH];
|
154
|
+
HANDLE find_handle;
|
155
|
+
WIN32_FIND_DATAW find_data;
|
156
|
+
size_t buf_source_prefix_len, buf_dest_prefix_len;
|
157
|
+
|
158
|
+
wcscpy_s(buf_source, MAX_PATH, _wsource);
|
159
|
+
wcscat_s(buf_source, MAX_PATH, L"\\");
|
160
|
+
buf_source_prefix_len = wcslen(buf_source);
|
161
|
+
|
162
|
+
wcscpy_s(buf_dest, MAX_PATH, _wdest);
|
163
|
+
wcscat_s(buf_dest, MAX_PATH, L"\\");
|
164
|
+
buf_dest_prefix_len = wcslen(buf_dest);
|
165
|
+
|
166
|
+
/* Get an enumerator for the items in the source. */
|
167
|
+
wcscat_s(buf_source, MAX_PATH, L"*");
|
168
|
+
find_handle = FindFirstFileW(buf_source, &find_data);
|
169
|
+
cl_assert(INVALID_HANDLE_VALUE != find_handle);
|
170
|
+
|
171
|
+
/* Create the target directory. */
|
172
|
+
cl_assert(CreateDirectoryW(_wdest, NULL));
|
173
|
+
|
174
|
+
do {
|
175
|
+
/* FindFirstFile/FindNextFile gives back . and ..
|
176
|
+
* entries at the beginning */
|
177
|
+
if (fs__dotordotdot(find_data.cFileName))
|
178
|
+
continue;
|
179
|
+
|
180
|
+
wcscpy_s(buf_source + buf_source_prefix_len, MAX_PATH - buf_source_prefix_len, find_data.cFileName);
|
181
|
+
wcscpy_s(buf_dest + buf_dest_prefix_len, MAX_PATH - buf_dest_prefix_len, find_data.cFileName);
|
182
|
+
|
183
|
+
if (FILE_ATTRIBUTE_DIRECTORY & find_data.dwFileAttributes)
|
184
|
+
fs_copydir_helper(buf_source, buf_dest);
|
185
|
+
else
|
186
|
+
cl_assert(CopyFileW(buf_source, buf_dest, TRUE));
|
187
|
+
}
|
188
|
+
while (FindNextFileW(find_handle, &find_data));
|
189
|
+
|
190
|
+
/* Ensure that we successfully completed the enumeration */
|
191
|
+
cl_assert(ERROR_NO_MORE_FILES == GetLastError());
|
192
|
+
|
193
|
+
/* Close the find handle */
|
194
|
+
FindClose(find_handle);
|
195
|
+
}
|
196
|
+
|
197
|
+
static void
|
198
|
+
fs_copy(const char *_source, const char *_dest)
|
199
|
+
{
|
200
|
+
WCHAR wsource[MAX_PATH], wdest[MAX_PATH];
|
201
|
+
DWORD source_attrs, dest_attrs;
|
202
|
+
HANDLE find_handle;
|
203
|
+
WIN32_FIND_DATAW find_data;
|
204
|
+
|
205
|
+
/* The input paths are UTF-8. Convert them to wide characters
|
206
|
+
* for use with the Windows API. */
|
207
|
+
cl_assert(MultiByteToWideChar(CP_UTF8,
|
208
|
+
MB_ERR_INVALID_CHARS,
|
209
|
+
_source,
|
210
|
+
-1,
|
211
|
+
wsource,
|
212
|
+
MAX_PATH));
|
213
|
+
|
214
|
+
cl_assert(MultiByteToWideChar(CP_UTF8,
|
215
|
+
MB_ERR_INVALID_CHARS,
|
216
|
+
_dest,
|
217
|
+
-1,
|
218
|
+
wdest,
|
219
|
+
MAX_PATH));
|
220
|
+
|
221
|
+
/* Check the source for existence */
|
222
|
+
source_attrs = GetFileAttributesW(wsource);
|
223
|
+
cl_assert(INVALID_FILE_ATTRIBUTES != source_attrs);
|
224
|
+
|
225
|
+
/* Check the target for existence */
|
226
|
+
dest_attrs = GetFileAttributesW(wdest);
|
227
|
+
|
228
|
+
if (INVALID_FILE_ATTRIBUTES != dest_attrs) {
|
229
|
+
/* Target exists; append last path part of source to target.
|
230
|
+
* Use FindFirstFile to parse the path */
|
231
|
+
find_handle = FindFirstFileW(wsource, &find_data);
|
232
|
+
cl_assert(INVALID_HANDLE_VALUE != find_handle);
|
233
|
+
wcscat_s(wdest, MAX_PATH, L"\\");
|
234
|
+
wcscat_s(wdest, MAX_PATH, find_data.cFileName);
|
235
|
+
FindClose(find_handle);
|
236
|
+
|
237
|
+
/* Check the new target for existence */
|
238
|
+
cl_assert(INVALID_FILE_ATTRIBUTES == GetFileAttributesW(wdest));
|
239
|
+
}
|
240
|
+
|
241
|
+
if (FILE_ATTRIBUTE_DIRECTORY & source_attrs)
|
242
|
+
fs_copydir_helper(wsource, wdest);
|
243
|
+
else
|
244
|
+
cl_assert(CopyFileW(wsource, wdest, TRUE));
|
245
|
+
}
|
246
|
+
|
247
|
+
void
|
248
|
+
cl_fs_cleanup(void)
|
249
|
+
{
|
250
|
+
fs_rm(fixture_path(_clar_path, "*"));
|
251
|
+
}
|
252
|
+
|
253
|
+
#else
|
254
|
+
|
255
|
+
#include <errno.h>
|
256
|
+
#include <string.h>
|
257
|
+
|
258
|
+
static int
|
259
|
+
shell_out(char * const argv[])
|
260
|
+
{
|
261
|
+
int status, piderr;
|
262
|
+
pid_t pid;
|
263
|
+
|
264
|
+
pid = fork();
|
265
|
+
|
266
|
+
if (pid < 0) {
|
267
|
+
fprintf(stderr,
|
268
|
+
"System error: `fork()` call failed (%d) - %s\n",
|
269
|
+
errno, strerror(errno));
|
270
|
+
exit(-1);
|
271
|
+
}
|
272
|
+
|
273
|
+
if (pid == 0) {
|
274
|
+
execv(argv[0], argv);
|
275
|
+
}
|
276
|
+
|
277
|
+
do {
|
278
|
+
piderr = waitpid(pid, &status, WUNTRACED);
|
279
|
+
} while (piderr < 0 && (errno == EAGAIN || errno == EINTR));
|
280
|
+
|
281
|
+
return WEXITSTATUS(status);
|
282
|
+
}
|
283
|
+
|
284
|
+
static void
|
285
|
+
fs_copy(const char *_source, const char *dest)
|
286
|
+
{
|
287
|
+
char *argv[5];
|
288
|
+
char *source;
|
289
|
+
size_t source_len;
|
290
|
+
|
291
|
+
source = strdup(_source);
|
292
|
+
source_len = strlen(source);
|
293
|
+
|
294
|
+
if (source[source_len - 1] == '/')
|
295
|
+
source[source_len - 1] = 0;
|
296
|
+
|
297
|
+
argv[0] = "/bin/cp";
|
298
|
+
argv[1] = "-R";
|
299
|
+
argv[2] = source;
|
300
|
+
argv[3] = (char *)dest;
|
301
|
+
argv[4] = NULL;
|
302
|
+
|
303
|
+
cl_must_pass_(
|
304
|
+
shell_out(argv),
|
305
|
+
"Failed to copy test fixtures to sandbox"
|
306
|
+
);
|
307
|
+
|
308
|
+
free(source);
|
309
|
+
}
|
310
|
+
|
311
|
+
static void
|
312
|
+
fs_rm(const char *source)
|
313
|
+
{
|
314
|
+
char *argv[4];
|
315
|
+
|
316
|
+
argv[0] = "/bin/rm";
|
317
|
+
argv[1] = "-Rf";
|
318
|
+
argv[2] = (char *)source;
|
319
|
+
argv[3] = NULL;
|
320
|
+
|
321
|
+
cl_must_pass_(
|
322
|
+
shell_out(argv),
|
323
|
+
"Failed to cleanup the sandbox"
|
324
|
+
);
|
325
|
+
}
|
326
|
+
|
327
|
+
void
|
328
|
+
cl_fs_cleanup(void)
|
329
|
+
{
|
330
|
+
clar_unsandbox();
|
331
|
+
clar_sandbox();
|
332
|
+
}
|
333
|
+
#endif
|