mathematical 1.2.0 → 1.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|