Skip to content

Commit 0d03c04

Browse files
committed
tempdir and sandboxes are now separate entities
clar now has the concept of a _temporary directory_, which is the temporary directory for the entirety of a `clar` invocation (a set of test runs) and a sandbox, which is the temporary directory for a single test invocation. This allows us to ensure that a well-written test (that only writes into its sandbox) doesn't poison the well for future test invocations if it fails to clean up its sandbox.
1 parent 9b0eab9 commit 0d03c04

File tree

5 files changed

+113
-35
lines changed

5 files changed

+113
-35
lines changed

clar.c

+10-4
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,10 @@ static void clar_print_onabortv(const char *msg, va_list argp);
199199
static void clar_print_onabort(const char *msg, ...);
200200

201201
/* From clar_sandbox.c */
202-
static void clar_unsandbox(void);
203-
static void clar_sandbox(void);
202+
static void clar_tempdir_init(void);
203+
static void clar_tempdir_shutdown(void);
204+
static int clar_sandbox_create(const char *suite_name, const char *test_name);
205+
static int clar_sandbox_cleanup(void);
204206

205207
/* From summary.h */
206208
static struct clar_summary *clar_summary_init(const char *filename);
@@ -304,6 +306,8 @@ clar_run_test(
304306

305307
CL_TRACE(CL_TRACE__TEST__BEGIN);
306308

309+
clar_sandbox_create(suite->name, test->name);
310+
307311
_clar.last_report->start = time(NULL);
308312
clar_time_now(&start);
309313

@@ -331,6 +335,8 @@ clar_run_test(
331335
if (cleanup->ptr != NULL)
332336
cleanup->ptr();
333337

338+
clar_sandbox_cleanup();
339+
334340
CL_TRACE(CL_TRACE__TEST__END);
335341

336342
_clar.tests_ran++;
@@ -604,7 +610,7 @@ clar_test_init(int argc, char **argv)
604610
if (_clar.write_summary)
605611
_clar.summary = clar_summary_init(_clar.summary_filename);
606612

607-
clar_sandbox();
613+
clar_tempdir_init();
608614
}
609615

610616
int
@@ -636,7 +642,7 @@ clar_test_shutdown(void)
636642
_clar.total_errors
637643
);
638644

639-
clar_unsandbox();
645+
clar_tempdir_shutdown();
640646

641647
if (_clar.write_summary && clar_summary_shutdown(_clar.summary) < 0)
642648
clar_abort("Failed to write the summary file '%s: %s.\n",

clar.h

+5-2
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,12 @@
99

1010
#include <stdlib.h>
1111

12-
#ifdef CLAR_WIN32_LONGPATHS
12+
#if defined(_WIN32) && defined(CLAR_WIN32_LONGPATHS)
1313
# define CLAR_MAX_PATH 4096
14-
#else
14+
#elif defined(_WIN32)
1515
# define CLAR_MAX_PATH MAX_PATH
16+
#else
17+
# define CLAR_MAX_PATH PATH_MAX
1618
#endif
1719

1820
#ifndef CLAR_SELFTEST
@@ -46,6 +48,7 @@ void clar_test_shutdown(void);
4648
int clar_test(int argc, char *argv[]);
4749

4850
const char *clar_sandbox_path(void);
51+
const char *clar_tempdir_path(void);
4952

5053
void cl_set_cleanup(void (*cleanup)(void *), void *opaque);
5154
void cl_fs_cleanup(void);

clar/fixtures.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ const char *cl_fixture(const char *fixture_name)
2828

2929
void cl_fixture_sandbox(const char *fixture_name)
3030
{
31-
fs_copy(cl_fixture(fixture_name), _clar_path);
31+
fs_copy(cl_fixture(fixture_name), clar_sandbox_path());
3232
}
3333

3434
const char *cl_fixture_basename(const char *fixture_name)
@@ -45,6 +45,6 @@ const char *cl_fixture_basename(const char *fixture_name)
4545

4646
void cl_fixture_cleanup(const char *fixture_name)
4747
{
48-
fs_rm(fixture_path(_clar_path, cl_fixture_basename(fixture_name)));
48+
fs_rm(fixture_path(clar_sandbox_path(), cl_fixture_basename(fixture_name)));
4949
}
5050
#endif

clar/fs.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -512,7 +512,7 @@ fs_rm(const char *path)
512512
void
513513
cl_fs_cleanup(void)
514514
{
515-
clar_unsandbox();
516-
clar_sandbox();
515+
clar_tempdir_shutdown();
516+
clar_tempdir_init();
517517
}
518518
#endif

clar/sandbox.h

+94-25
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,17 @@
22
#include <sys/syslimits.h>
33
#endif
44

5-
static char _clar_path[CLAR_MAX_PATH];
5+
/*
6+
* The tempdir is the temporary directory for the entirety of the clar
7+
* process execution. The sandbox is an individual temporary directory
8+
* for the execution of an individual test. Sandboxes are deleted
9+
* entirely after test execution to avoid pollution across tests.
10+
*/
11+
12+
static char _clar_tempdir[CLAR_MAX_PATH];
13+
size_t _clar_tempdir_len;
14+
15+
static char _clar_sandbox[CLAR_MAX_PATH];
616

717
static int
818
is_valid_tmp_path(const char *path)
@@ -108,17 +118,17 @@ static int canonicalize_tmp_path(char *buffer)
108118
#endif
109119
}
110120

111-
static void clar_unsandbox(void)
121+
static void clar_tempdir_shutdown(void)
112122
{
113-
if (_clar_path[0] == '\0')
123+
if (_clar_tempdir[0] == '\0')
114124
return;
115125

116126
cl_must_pass(chdir(".."));
117127

118-
fs_rm(_clar_path);
128+
fs_rm(_clar_tempdir);
119129
}
120130

121-
static int build_sandbox_path(void)
131+
static int build_tempdir_path(void)
122132
{
123133
#ifdef CLAR_TMPDIR
124134
const char path_tail[] = CLAR_TMPDIR "_XXXXXX";
@@ -128,57 +138,116 @@ static int build_sandbox_path(void)
128138

129139
size_t len;
130140

131-
if (find_tmp_path(_clar_path, sizeof(_clar_path)) < 0 ||
132-
canonicalize_tmp_path(_clar_path) < 0)
141+
if (find_tmp_path(_clar_tempdir, sizeof(_clar_tempdir)) < 0 ||
142+
canonicalize_tmp_path(_clar_tempdir) < 0)
133143
return -1;
134144

135-
len = strlen(_clar_path);
145+
len = strlen(_clar_tempdir);
136146

137147
if (len + strlen(path_tail) + 1 > CLAR_MAX_PATH)
138148
return -1;
139149

140-
if (_clar_path[len - 1] != '/')
141-
_clar_path[len++] = '/';
150+
if (_clar_tempdir[len - 1] != '/')
151+
_clar_tempdir[len++] = '/';
142152

143-
strncpy(_clar_path + len, path_tail, sizeof(_clar_path) - len);
153+
strncpy(_clar_tempdir + len, path_tail, sizeof(_clar_tempdir) - len);
144154

145155
#if defined(__MINGW32__)
146-
if (_mktemp(_clar_path) == NULL)
156+
if (_mktemp(_clar_tempdir) == NULL)
147157
return -1;
148158

149-
if (mkdir(_clar_path, 0700) != 0)
159+
if (mkdir(_clar_tempdir, 0700) != 0)
150160
return -1;
151161
#elif defined(_WIN32)
152-
if (_mktemp_s(_clar_path, sizeof(_clar_path)) != 0)
162+
if (_mktemp_s(_clar_tempdir, sizeof(_clar_tempdir)) != 0)
153163
return -1;
154164

155-
if (mkdir(_clar_path, 0700) != 0)
165+
if (mkdir(_clar_tempdir, 0700) != 0)
156166
return -1;
157167
#elif defined(__sun) || defined(__TANDEM)
158-
if (mktemp(_clar_path) == NULL)
168+
if (mktemp(_clar_tempdir) == NULL)
159169
return -1;
160170

161-
if (mkdir(_clar_path, 0700) != 0)
171+
if (mkdir(_clar_tempdir, 0700) != 0)
162172
return -1;
163173
#else
164-
if (mkdtemp(_clar_path) == NULL)
174+
if (mkdtemp(_clar_tempdir) == NULL)
165175
return -1;
166176
#endif
167177

178+
_clar_tempdir_len = strlen(_clar_tempdir);
168179
return 0;
169180
}
170181

171-
static void clar_sandbox(void)
182+
static void clar_tempdir_init(void)
183+
{
184+
if (_clar_tempdir[0] == '\0' && build_tempdir_path() < 0)
185+
clar_abort("Failed to build tempdir path.\n");
186+
187+
if (chdir(_clar_tempdir) != 0)
188+
clar_abort("Failed to change into tempdir '%s': %s.\n",
189+
_clar_tempdir, strerror(errno));
190+
}
191+
192+
static void append(char *dst, const char *src)
193+
{
194+
char *d;
195+
const char *s;
196+
197+
for (d = dst; *d; d++)
198+
;
199+
200+
for (s = src; *s; d++, s++)
201+
if (*s == ':')
202+
*d = '_';
203+
else
204+
*d = *s;
205+
206+
*d = '\0';
207+
}
208+
209+
static int clar_sandbox_create(const char *suite_name, const char *test_name)
172210
{
173-
if (_clar_path[0] == '\0' && build_sandbox_path() < 0)
174-
clar_abort("Failed to build sandbox path.\n");
211+
cl_assert(_clar_sandbox[0] == '\0');
175212

176-
if (chdir(_clar_path) != 0)
177-
clar_abort("Failed to change into sandbox directory '%s': %s.\n",
178-
_clar_path, strerror(errno));
213+
cl_assert(strlen(_clar_tempdir) + strlen(suite_name) + strlen(test_name) + 2 < CLAR_MAX_PATH);
214+
215+
strcpy(_clar_sandbox, _clar_tempdir);
216+
_clar_sandbox[_clar_tempdir_len] = '/';
217+
_clar_sandbox[_clar_tempdir_len + 1] = '\0';
218+
219+
append(_clar_sandbox, suite_name);
220+
append(_clar_sandbox, "__");
221+
append(_clar_sandbox, test_name);
222+
223+
if (mkdir(_clar_sandbox, 0700) != 0)
224+
return -1;
225+
226+
if (chdir(_clar_sandbox) != 0)
227+
return -1;
228+
229+
return 0;
230+
}
231+
232+
static int clar_sandbox_cleanup(void)
233+
{
234+
cl_assert(_clar_sandbox[0] != '\0');
235+
236+
fs_rm(_clar_sandbox);
237+
_clar_sandbox[0] = '\0';
238+
239+
if (chdir(_clar_tempdir) != 0)
240+
return -1;
241+
242+
return 0;
243+
}
244+
245+
const char *clar_tempdir_path(void)
246+
{
247+
return _clar_tempdir;
179248
}
180249

181250
const char *clar_sandbox_path(void)
182251
{
183-
return _clar_path;
252+
return _clar_sandbox;
184253
}

0 commit comments

Comments
 (0)