Skip to content

Commit 1e421ff

Browse files
authoredJan 22, 2025··
Merge pull request #111 from clar-test/ethomson/invoke
invoke: preserve line numbers during helper methods
2 parents a23a73e + baa977e commit 1e421ff

File tree

4 files changed

+73
-25
lines changed

4 files changed

+73
-25
lines changed
 

‎README.md

+17-13
Original file line numberDiff line numberDiff line change
@@ -250,11 +250,16 @@ suite.
250250

251251
- `cl_fixture(const char *)`: Gets the full path to a fixture file.
252252

253-
Please do note that these methods are *always* available whilst running a
254-
test, even when calling auxiliary/static functions inside the same file.
253+
### Auxiliary / helper functions
255254

256-
It's strongly encouraged to perform test assertions in auxiliary methods,
257-
instead of returning error values. This is considered good Clar style.
255+
The clar API is always available while running a test, even when calling
256+
"auxiliary" (helper) functions.
257+
258+
You're encouraged to perform test assertions in those auxiliary
259+
methods, instead of returning error values. This is considered good
260+
Clar style. _However_, when you do this, you need to call `cl_invoke`
261+
to preserve the current state; this ensures that failures are reported
262+
as coming from the actual test, instead of the auxiliary method.
258263
259264
Style Example:
260265
@@ -309,20 +314,19 @@ static void check_string(const char *str)
309314
310315
void test_example__a_test_with_auxiliary_methods(void)
311316
{
312-
check_string("foo");
313-
check_string("bar");
317+
cl_invoke(check_string("foo"));
318+
cl_invoke(check_string("bar"));
314319
}
315320
~~~~
316321
317322
About Clar
318323
==========
319324
320-
Clar has been written from scratch by [Vicent Martí](https://github.com/vmg),
321-
to replace the old testing framework in [libgit2][libgit2].
322-
323-
Do you know what languages are *in* on the SF startup scene? Node.js *and*
324-
Latin. Follow [@vmg](https://www.twitter.com/vmg) on Twitter to
325-
receive more lessons on word etymology. You can be hip too.
326-
325+
Clar was originally written by [Vicent Martí](https://github.com/vmg),
326+
to replace the old testing framework in [libgit2][libgit2]. It is
327+
currently maintained by [Edward Thomson](https://github.com/ethomson),
328+
and used by the [libgit2][libgit2] and [git][git] projects, amongst
329+
others.
327330
328331
[libgit2]: https://github.com/libgit2/libgit2
332+
[git]: https://github.com/git/git

‎clar.c

+26-3
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,10 @@ static struct {
164164
struct clar_report *reports;
165165
struct clar_report *last_report;
166166

167+
const char *invoke_file;
168+
const char *invoke_func;
169+
size_t invoke_line;
170+
167171
void (*local_cleanup)(void *);
168172
void *local_cleanup_payload;
169173

@@ -328,6 +332,8 @@ clar_run_test(
328332
if (_clar.local_cleanup != NULL)
329333
_clar.local_cleanup(_clar.local_cleanup_payload);
330334

335+
clar__clear_invokepoint();
336+
331337
if (cleanup->ptr != NULL)
332338
cleanup->ptr();
333339

@@ -716,9 +722,9 @@ void clar__fail(
716722

717723
_clar.last_report->last_error = error;
718724

719-
error->file = file;
720-
error->function = function;
721-
error->line_number = line;
725+
error->file = _clar.invoke_file ? _clar.invoke_file : file;
726+
error->function = _clar.invoke_func ? _clar.invoke_func : function;
727+
error->line_number = _clar.invoke_line ? _clar.invoke_line : line;
722728
error->error_msg = error_msg;
723729

724730
if (description != NULL &&
@@ -872,6 +878,23 @@ void cl_set_cleanup(void (*cleanup)(void *), void *opaque)
872878
_clar.local_cleanup_payload = opaque;
873879
}
874880

881+
void clar__set_invokepoint(
882+
const char *file,
883+
const char *func,
884+
size_t line)
885+
{
886+
_clar.invoke_file = file;
887+
_clar.invoke_func = func;
888+
_clar.invoke_line = line;
889+
}
890+
891+
void clar__clear_invokepoint(void)
892+
{
893+
_clar.invoke_file = NULL;
894+
_clar.invoke_func = NULL;
895+
_clar.invoke_line = 0;
896+
}
897+
875898
#include "clar/sandbox.h"
876899
#include "clar/fixtures.h"
877900
#include "clar/fs.h"

‎clar.h

+21
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,20 @@ void cl_fixture_cleanup(const char *fixture_name);
9393
const char *cl_fixture_basename(const char *fixture_name);
9494
#endif
9595

96+
/**
97+
* Invoke a helper function, which itself will use `cl_assert`
98+
* constructs. This will preserve the stack information of the
99+
* current call point, so that function name and line number
100+
* information is shown from the line of the test, instead of
101+
* the helper function.
102+
*/
103+
#define cl_invoke(expr) \
104+
do { \
105+
clar__set_invokepoint(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE); \
106+
expr; \
107+
clar__clear_invokepoint(); \
108+
} while(0)
109+
96110
/**
97111
* Assertion macros with explicit error message
98112
*/
@@ -180,4 +194,11 @@ void clar__assert_equal(
180194
const char *fmt,
181195
...);
182196

197+
void clar__set_invokepoint(
198+
const char *file,
199+
const char *func,
200+
size_t line);
201+
202+
void clar__clear_invokepoint(void);
203+
183204
#endif

‎test/selftest.c

+9-9
Original file line numberDiff line numberDiff line change
@@ -239,51 +239,51 @@ static void run(const char *expected_output_file, int expected_error_code, ...)
239239

240240
void test_selftest__help(void)
241241
{
242-
run("help", 1, "-h", NULL);
242+
cl_invoke(run("help", 1, "-h", NULL));
243243
}
244244

245245
void test_selftest__without_arguments(void)
246246
{
247-
run("without_arguments", 8, NULL);
247+
cl_invoke(run("without_arguments", 8, NULL));
248248
}
249249

250250
void test_selftest__specific_test(void)
251251
{
252-
run("specific_test", 1, "-sselftest::suite::bool", NULL);
252+
cl_invoke(run("specific_test", 1, "-sselftest::suite::bool", NULL));
253253
}
254254

255255
void test_selftest__stop_on_failure(void)
256256
{
257-
run("stop_on_failure", 1, "-Q", NULL);
257+
cl_invoke(run("stop_on_failure", 1, "-Q", NULL));
258258
}
259259

260260
void test_selftest__quiet(void)
261261
{
262-
run("quiet", 8, "-q", NULL);
262+
cl_invoke(run("quiet", 8, "-q", NULL));
263263
}
264264

265265
void test_selftest__tap(void)
266266
{
267-
run("tap", 8, "-t", NULL);
267+
cl_invoke(run("tap", 8, "-t", NULL));
268268
}
269269

270270
void test_selftest__suite_names(void)
271271
{
272-
run("suite_names", 0, "-l", NULL);
272+
cl_invoke(run("suite_names", 0, "-l", NULL));
273273
}
274274

275275
void test_selftest__summary_without_filename(void)
276276
{
277277
struct stat st;
278-
run("summary_without_filename", 8, "-r", NULL);
278+
cl_invoke(run("summary_without_filename", 8, "-r", NULL));
279279
/* The summary contains timestamps, so we cannot verify its contents. */
280280
cl_must_pass(stat("summary.xml", &st));
281281
}
282282

283283
void test_selftest__summary_with_filename(void)
284284
{
285285
struct stat st;
286-
run("summary_with_filename", 8, "-rdifferent.xml", NULL);
286+
cl_invoke(run("summary_with_filename", 8, "-rdifferent.xml", NULL));
287287
/* The summary contains timestamps, so we cannot verify its contents. */
288288
cl_must_pass(stat("different.xml", &st));
289289
}

0 commit comments

Comments
 (0)
Please sign in to comment.