* [PATCH 0/2] Update clar for improved integer handling
@ 2025-12-05 12:57 Patrick Steinhardt
2025-12-05 12:57 ` [PATCH 1/2] t/unit-tests: update clar to 39f11fe Patrick Steinhardt
` (2 more replies)
0 siblings, 3 replies; 19+ messages in thread
From: Patrick Steinhardt @ 2025-12-05 12:57 UTC (permalink / raw)
To: git; +Cc: Jeff King, Phillip Wood
Hi,
this patch series updates clar. Most importantly, the update contains
properly typed handling of integers as well as a set of new asserts that
perform relative comparisons, like "less than" or "greater or equal".
Thanks!
Patrick
---
Patrick Steinhardt (2):
t/unit-tests: update clar to 39f11fe
t/unit-tests: demonstrate use of integer comparison assertions
t/unit-tests/clar/.github/workflows/ci.yml | 2 +-
t/unit-tests/clar/clar.c | 146 ++++++++++++++++++++-
t/unit-tests/clar/clar.h | 82 +++++++++++-
t/unit-tests/clar/clar/print.h | 2 +-
t/unit-tests/clar/test/expected/quiet | 40 +++++-
.../clar/test/expected/summary_with_filename | 42 +++++-
.../clar/test/expected/summary_without_filename | 42 +++++-
t/unit-tests/clar/test/expected/tap | 88 +++++++++++--
t/unit-tests/clar/test/expected/without_arguments | 42 +++++-
t/unit-tests/clar/test/selftest.c | 10 +-
t/unit-tests/clar/test/suites/combined.c | 65 ++++++++-
t/unit-tests/u-reftable-record.c | 22 ++--
t/unit-tests/unit-test.h | 6 -
13 files changed, 519 insertions(+), 70 deletions(-)
---
base-commit: f0ef5b6d9bcc258e4cbef93839d1b7465d5212b9
change-id: 20251205-b4-pks-clar-update-4fb022908ced
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 1/2] t/unit-tests: update clar to 39f11fe
2025-12-05 12:57 [PATCH 0/2] Update clar for improved integer handling Patrick Steinhardt
@ 2025-12-05 12:57 ` Patrick Steinhardt
2025-12-05 18:40 ` Jeff King
2025-12-06 5:27 ` Junio C Hamano
2025-12-05 12:57 ` [PATCH 2/2] t/unit-tests: demonstrate use of integer comparison assertions Patrick Steinhardt
2025-12-06 11:47 ` [PATCH v2 0/3] Update clar for improved integer handling Patrick Steinhardt
2 siblings, 2 replies; 19+ messages in thread
From: Patrick Steinhardt @ 2025-12-05 12:57 UTC (permalink / raw)
To: git; +Cc: Jeff King, Phillip Wood
Update clar to commit 39f11fe (Merge pull request #131 from
pks-gitlab/pks-integer-double-evaluation, 2025-12-05). This commit
includes the following changes relevant to Git:
- There are now typesafe integer comparison functions. Furthermore,
the range of comparison functions has been included to also have
relative comparisons, like "greater than".
- There is a new `cl_failf()` macro that allows the caller to specify
an error message with formatting directives.
- The TAP format has been fixed to correctly terminate YAML blocks
with "...\n" instead of "---\n".
Note that we already had a `cl_failf()` function declared in our own
sources. This function is equivalent to the upstreamed function, so we
can simply drop it now.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
t/unit-tests/clar/.github/workflows/ci.yml | 2 +-
t/unit-tests/clar/clar.c | 146 ++++++++++++++++++++-
t/unit-tests/clar/clar.h | 82 +++++++++++-
t/unit-tests/clar/clar/print.h | 2 +-
t/unit-tests/clar/test/expected/quiet | 40 +++++-
.../clar/test/expected/summary_with_filename | 42 +++++-
.../clar/test/expected/summary_without_filename | 42 +++++-
t/unit-tests/clar/test/expected/tap | 88 +++++++++++--
t/unit-tests/clar/test/expected/without_arguments | 42 +++++-
t/unit-tests/clar/test/selftest.c | 10 +-
t/unit-tests/clar/test/suites/combined.c | 65 ++++++++-
t/unit-tests/unit-test.h | 6 -
12 files changed, 508 insertions(+), 59 deletions(-)
diff --git a/t/unit-tests/clar/.github/workflows/ci.yml b/t/unit-tests/clar/.github/workflows/ci.yml
index 4d4724222c..14cb4ed1d4 100644
--- a/t/unit-tests/clar/.github/workflows/ci.yml
+++ b/t/unit-tests/clar/.github/workflows/ci.yml
@@ -53,7 +53,7 @@ jobs:
if: matrix.platform.image == 'i386/debian:latest'
run: apt -q update && apt -q -y install cmake gcc libc6-amd64 lib64stdc++6 make python3
- name: Check out
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
- name: Build
shell: bash
run: |
diff --git a/t/unit-tests/clar/clar.c b/t/unit-tests/clar/clar.c
index d6176e50b2..e959a5ae02 100644
--- a/t/unit-tests/clar/clar.c
+++ b/t/unit-tests/clar/clar.c
@@ -24,6 +24,14 @@
#include <sys/types.h>
#include <sys/stat.h>
+#ifndef va_copy
+# ifdef __va_copy
+# define va_copy(dst, src) __va_copy(dst, src)
+# else
+# define va_copy(dst, src) ((dst) = (src))
+# endif
+#endif
+
#if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_WCHAR__)
/*
* uClibc can optionally be built without wchar support, in which case
@@ -76,8 +84,10 @@
# define S_ISDIR(x) ((x & _S_IFDIR) != 0)
# endif
# define p_snprintf(buf,sz,fmt,...) _snprintf_s(buf,sz,_TRUNCATE,fmt,__VA_ARGS__)
+# define p_vsnprintf _vsnprintf
# else
# define p_snprintf snprintf
+# define p_vsnprintf vsnprintf
# endif
# define localtime_r(timer, buf) (localtime_s(buf, timer) == 0 ? buf : NULL)
@@ -86,6 +96,7 @@
# include <unistd.h>
# define _MAIN_CC
# define p_snprintf snprintf
+# define p_vsnprintf vsnprintf
typedef struct stat STAT_T;
#endif
@@ -699,13 +710,14 @@ void clar__skip(void)
abort_test();
}
-void clar__fail(
+static void clar__failv(
const char *file,
const char *function,
size_t line,
+ int should_abort,
const char *error_msg,
const char *description,
- int should_abort)
+ va_list args)
{
struct clar_error *error;
@@ -725,9 +737,19 @@ void clar__fail(
error->line_number = _clar.invoke_line ? _clar.invoke_line : line;
error->error_msg = error_msg;
- if (description != NULL &&
- (error->description = strdup(description)) == NULL)
- clar_abort("Failed to allocate description.\n");
+ if (description != NULL) {
+ va_list args_copy;
+ int len;
+
+ va_copy(args_copy, args);
+ if ((len = p_vsnprintf(NULL, 0, description, args_copy)) < 0)
+ clar_abort("Failed to compute description.");
+ va_end(args_copy);
+
+ if ((error->description = calloc(1, len + 1)) == NULL)
+ clar_abort("Failed to allocate buffer.");
+ p_vsnprintf(error->description, len + 1, description, args);
+ }
_clar.total_errors++;
_clar.last_report->status = CL_TEST_FAILURE;
@@ -736,6 +758,34 @@ void clar__fail(
abort_test();
}
+void clar__failf(
+ const char *file,
+ const char *function,
+ size_t line,
+ int should_abort,
+ const char *error_msg,
+ const char *description,
+ ...)
+{
+ va_list args;
+ va_start(args, description);
+ clar__failv(file, function, line, should_abort, error_msg,
+ description, args);
+ va_end(args);
+}
+
+void clar__fail(
+ const char *file,
+ const char *function,
+ size_t line,
+ const char *error_msg,
+ const char *description,
+ int should_abort)
+{
+ clar__failf(file, function, line, should_abort, error_msg,
+ description ? "%s" : NULL, description);
+}
+
void clar__assert(
int condition,
const char *file,
@@ -889,6 +939,92 @@ void clar__assert_equal(
clar__fail(file, function, line, err, buf, should_abort);
}
+void clar__assert_compare_i(
+ const char *file,
+ const char *func,
+ size_t line,
+ int should_abort,
+ enum clar_comparison cmp,
+ intmax_t value1,
+ intmax_t value2,
+ const char *error,
+ const char *description,
+ ...)
+{
+ int fulfilled;
+ switch (cmp) {
+ case CLAR_COMPARISON_EQ:
+ fulfilled = value1 == value2;
+ break;
+ case CLAR_COMPARISON_LT:
+ fulfilled = value1 < value2;
+ break;
+ case CLAR_COMPARISON_LE:
+ fulfilled = value1 <= value2;
+ break;
+ case CLAR_COMPARISON_GT:
+ fulfilled = value1 > value2;
+ break;
+ case CLAR_COMPARISON_GE:
+ fulfilled = value1 >= value2;
+ break;
+ default:
+ cl_assert(0);
+ return;
+ }
+
+ if (!fulfilled) {
+ va_list args;
+ va_start(args, description);
+ clar__failv(file, func, line, should_abort, error,
+ description, args);
+ va_end(args);
+ }
+}
+
+void clar__assert_compare_u(
+ const char *file,
+ const char *func,
+ size_t line,
+ int should_abort,
+ enum clar_comparison cmp,
+ uintmax_t value1,
+ uintmax_t value2,
+ const char *error,
+ const char *description,
+ ...)
+{
+ int fulfilled;
+ switch (cmp) {
+ case CLAR_COMPARISON_EQ:
+ fulfilled = value1 == value2;
+ break;
+ case CLAR_COMPARISON_LT:
+ fulfilled = value1 < value2;
+ break;
+ case CLAR_COMPARISON_LE:
+ fulfilled = value1 <= value2;
+ break;
+ case CLAR_COMPARISON_GT:
+ fulfilled = value1 > value2;
+ break;
+ case CLAR_COMPARISON_GE:
+ fulfilled = value1 >= value2;
+ break;
+ default:
+ cl_assert(0);
+ return;
+ }
+
+ if (!fulfilled) {
+ va_list args;
+ va_start(args, description);
+ clar__failv(file, func, line, should_abort, error,
+ description, args);
+ va_end(args);
+ }
+}
+
void cl_set_cleanup(void (*cleanup)(void *), void *opaque)
{
_clar.local_cleanup = cleanup;
diff --git a/t/unit-tests/clar/clar.h b/t/unit-tests/clar/clar.h
index ca72292ae9..f7e4363022 100644
--- a/t/unit-tests/clar/clar.h
+++ b/t/unit-tests/clar/clar.h
@@ -7,6 +7,7 @@
#ifndef __CLAR_TEST_H__
#define __CLAR_TEST_H__
+#include <inttypes.h>
#include <stdlib.h>
#include <limits.h>
@@ -149,6 +150,7 @@ const char *cl_fixture_basename(const char *fixture_name);
* Forced failure/warning
*/
#define cl_fail(desc) clar__fail(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Test failed.", desc, 1)
+#define cl_failf(desc,...) clar__failf(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, "Test failed.", desc, __VA_ARGS__)
#define cl_warning(desc) clar__fail(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Warning during test execution:", desc, 0)
#define cl_skip() clar__skip()
@@ -168,9 +170,42 @@ const char *cl_fixture_basename(const char *fixture_name);
#define cl_assert_equal_wcsn(wcs1,wcs2,len) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #wcs1 " != " #wcs2, 1, "%.*ls", (wcs1), (wcs2), (int)(len))
#define cl_assert_equal_wcsn_(wcs1,wcs2,len,note) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%.*ls", (wcs1), (wcs2), (int)(len))
-#define cl_assert_equal_i(i1,i2) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#i1 " != " #i2, 1, "%d", (int)(i1), (int)(i2))
-#define cl_assert_equal_i_(i1,i2,note) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#i1 " != " #i2 " (" #note ")", 1, "%d", (i1), (i2))
-#define cl_assert_equal_i_fmt(i1,i2,fmt) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#i1 " != " #i2, 1, (fmt), (int)(i1), (int)(i2))
+#define cl_assert_compare_i_(i1, i2, cmp, error, ...) clar__assert_compare_i(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, cmp, \
+ (i1), (i2), "Expected comparison to hold: " error, __VA_ARGS__)
+#define cl_assert_compare_i(i1, i2, cmp, error, fmt) do { \
+ intmax_t v1 = (i1), v2 = (i2); \
+ clar__assert_compare_i(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, cmp, \
+ v1, v2, "Expected comparison to hold: " error, fmt, v1, v2); \
+} while (0)
+#define cl_assert_equal_i_(i1, i2, ...) cl_assert_compare_i_(i1, i2, CLAR_COMPARISON_EQ, #i1 " == " #i2, __VA_ARGS__)
+#define cl_assert_equal_i(i1, i2) cl_assert_compare_i (i1, i2, CLAR_COMPARISON_EQ, #i1 " == " #i2, "%"PRIdMAX " != %"PRIdMAX)
+#define cl_assert_equal_i_fmt(i1, i2, fmt) cl_assert_compare_i_(i1, i2, CLAR_COMPARISON_EQ, #i1 " == " #i2, fmt " != " fmt, (int)(i1), (int)(i2))
+#define cl_assert_lt_i_(i1, i2, ...) cl_assert_compare_i_(i1, i2, CLAR_COMPARISON_LT, #i1 " < " #i2, __VA_ARGS__)
+#define cl_assert_lt_i(i1, i2) cl_assert_compare_i (i1, i2, CLAR_COMPARISON_LT, #i1 " < " #i2, "%"PRIdMAX " >= %"PRIdMAX)
+#define cl_assert_le_i_(i1, i2, ...) cl_assert_compare_i_(i1, i2, CLAR_COMPARISON_LE, #i1 " <= " #i2, __VA_ARGS__)
+#define cl_assert_le_i(i1, i2) cl_assert_compare_i (i1, i2, CLAR_COMPARISON_LE, #i1 " <= " #i2, "%"PRIdMAX " > %"PRIdMAX)
+#define cl_assert_gt_i_(i1, i2, ...) cl_assert_compare_i_(i1, i2, CLAR_COMPARISON_GT, #i1 " > " #i2, __VA_ARGS__)
+#define cl_assert_gt_i(i1, i2) cl_assert_compare_i (i1, i2, CLAR_COMPARISON_GT, #i1 " > " #i2, "%"PRIdMAX " <= %"PRIdMAX)
+#define cl_assert_ge_i_(i1, i2, ...) cl_assert_compare_i_(i1, i2, CLAR_COMPARISON_GE, #i1 " >= " #i2, __VA_ARGS__)
+#define cl_assert_ge_i(i1, i2) cl_assert_compare_i (i1, i2, CLAR_COMPARISON_GE, #i1 " >= " #i2, "%"PRIdMAX " < %"PRIdMAX)
+
+#define cl_assert_compare_u_(u1, u2, cmp, error, ...) clar__assert_compare_u(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, cmp, \
+ (u1), (u2), "Expected comparison to hold: " error, __VA_ARGS__)
+#define cl_assert_compare_u(u1, u2, cmp, error, fmt) do { \
+ uintmax_t v1 = (u1), v2 = (u2); \
+ clar__assert_compare_u(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, cmp, \
+ v1, v2, "Expected comparison to hold: " error, fmt, v1, v2); \
+} while (0)
+#define cl_assert_equal_u_(u1, u2, ...) cl_assert_compare_u_(u1, u2, CLAR_COMPARISON_EQ, #u1 " == " #u2, __VA_ARGS__)
+#define cl_assert_equal_u(u1, u2) cl_assert_compare_u (u1, u2, CLAR_COMPARISON_EQ, #u1 " == " #u2, "%"PRIuMAX " != %"PRIuMAX)
+#define cl_assert_lt_u_(u1, u2, ...) cl_assert_compare_u_(u1, u2, CLAR_COMPARISON_LT, #u1 " < " #u2, __VA_ARGS__)
+#define cl_assert_lt_u(u1, u2) cl_assert_compare_u (u1, u2, CLAR_COMPARISON_LT, #u1 " < " #u2, "%"PRIuMAX " >= %"PRIuMAX)
+#define cl_assert_le_u_(u1, u2, ...) cl_assert_compare_u_(u1, u2, CLAR_COMPARISON_LE, #u1 " <= " #u2, __VA_ARGS__)
+#define cl_assert_le_u(u1, u2) cl_assert_compare_u (u1, u2, CLAR_COMPARISON_LE, #u1 " <= " #u2, "%"PRIuMAX " > %"PRIuMAX)
+#define cl_assert_gt_u_(u1, u2, ...) cl_assert_compare_u_(u1, u2, CLAR_COMPARISON_GT, #u1 " > " #u2, __VA_ARGS__)
+#define cl_assert_gt_u(u1, u2) cl_assert_compare_u (u1, u2, CLAR_COMPARISON_GT, #u1 " > " #u2, "%"PRIuMAX " <= %"PRIuMAX)
+#define cl_assert_ge_u_(u1, u2, ...) cl_assert_compare_u_(u1, u2, CLAR_COMPARISON_GE, #u1 " >= " #u2, __VA_ARGS__)
+#define cl_assert_ge_u(u1, u2) cl_assert_compare_u (u1, u2, CLAR_COMPARISON_GE, #u1 " >= " #u2, "%"PRIuMAX " < %"PRIuMAX)
#define cl_assert_equal_b(b1,b2) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#b1 " != " #b2, 1, "%d", (int)((b1) != 0),(int)((b2) != 0))
@@ -186,6 +221,15 @@ void clar__fail(
const char *description,
int should_abort);
+void clar__failf(
+ const char *file,
+ const char *func,
+ size_t line,
+ int should_abort,
+ const char *error,
+ const char *description,
+ ...);
+
void clar__assert(
int condition,
const char *file,
@@ -204,6 +248,38 @@ void clar__assert_equal(
const char *fmt,
...);
+enum clar_comparison {
+ CLAR_COMPARISON_EQ,
+ CLAR_COMPARISON_LT,
+ CLAR_COMPARISON_LE,
+ CLAR_COMPARISON_GT,
+ CLAR_COMPARISON_GE,
+};
+
+void clar__assert_compare_i(
+ const char *file,
+ const char *func,
+ size_t line,
+ int should_abort,
+ enum clar_comparison cmp,
+ intmax_t value1,
+ intmax_t value2,
+ const char *error,
+ const char *description,
+ ...);
+
+void clar__assert_compare_u(
+ const char *file,
+ const char *func,
+ size_t line,
+ int should_abort,
+ enum clar_comparison cmp,
+ uintmax_t value1,
+ uintmax_t value2,
+ const char *error,
+ const char *description,
+ ...);
+
void clar__set_invokepoint(
const char *file,
const char *func,
diff --git a/t/unit-tests/clar/clar/print.h b/t/unit-tests/clar/clar/print.h
index 89b66591d7..6a2321b399 100644
--- a/t/unit-tests/clar/clar/print.h
+++ b/t/unit-tests/clar/clar/print.h
@@ -164,7 +164,7 @@ static void clar_print_tap_ontest(const char *suite_name, const char *test_name,
printf(" file: '"); print_escaped(error->file); printf("'\n");
printf(" line: %" PRIuMAX "\n", error->line_number);
printf(" function: '%s'\n", error->function);
- printf(" ---\n");
+ printf(" ...\n");
}
break;
diff --git a/t/unit-tests/clar/test/expected/quiet b/t/unit-tests/clar/test/expected/quiet
index 280c99d8ad..a93273b5a2 100644
--- a/t/unit-tests/clar/test/expected/quiet
+++ b/t/unit-tests/clar/test/expected/quiet
@@ -18,27 +18,57 @@ combined::strings_with_length [file:42]
5) Failure:
combined::int [file:42]
- 101 != value ("extra note on failing test")
+ Expected comparison to hold: 101 == value
101 != 100
6) Failure:
+combined::int_note [file:42]
+ Expected comparison to hold: 101 == value
+ extra note on failing test
+
+ 7) Failure:
combined::int_fmt [file:42]
- 022 != value
+ Expected comparison to hold: 022 == value
0022 != 0144
- 7) Failure:
+ 8) Failure:
combined::bool [file:42]
0 != value
0 != 1
- 8) Failure:
+ 9) Failure:
combined::multiline_description [file:42]
Function call failed: -1
description line 1
description line 2
- 9) Failure:
+ 10) Failure:
combined::null_string [file:42]
String mismatch: "expected" != actual ("this one fails")
'expected' != NULL
+ 11) Failure:
+combined::failf [file:42]
+ Test failed.
+ some reason: foo
+
+ 12) Failure:
+combined::compare_i [file:42]
+ Expected comparison to hold: two < 1
+ 2 >= 1
+
+ 13) Failure:
+combined::compare_i_with_format [file:42]
+ Expected comparison to hold: two < 1
+ foo: bar
+
+ 14) Failure:
+combined::compare_u [file:42]
+ Expected comparison to hold: two < 1
+ 2 >= 1
+
+ 15) Failure:
+combined::compare_u_with_format [file:42]
+ Expected comparison to hold: two < 1
+ foo: bar
+
diff --git a/t/unit-tests/clar/test/expected/summary_with_filename b/t/unit-tests/clar/test/expected/summary_with_filename
index 460160791d..a9471cc7d5 100644
--- a/t/unit-tests/clar/test/expected/summary_with_filename
+++ b/t/unit-tests/clar/test/expected/summary_with_filename
@@ -1,6 +1,6 @@
Loaded 1 suites:
Started (test status codes: OK='.' FAILURE='F' SKIPPED='S')
-FFFFFFFFF
+FFFFFFFFFFFFFFF
1) Failure:
combined::1 [file:42]
@@ -22,28 +22,58 @@ combined::strings_with_length [file:42]
5) Failure:
combined::int [file:42]
- 101 != value ("extra note on failing test")
+ Expected comparison to hold: 101 == value
101 != 100
6) Failure:
+combined::int_note [file:42]
+ Expected comparison to hold: 101 == value
+ extra note on failing test
+
+ 7) Failure:
combined::int_fmt [file:42]
- 022 != value
+ Expected comparison to hold: 022 == value
0022 != 0144
- 7) Failure:
+ 8) Failure:
combined::bool [file:42]
0 != value
0 != 1
- 8) Failure:
+ 9) Failure:
combined::multiline_description [file:42]
Function call failed: -1
description line 1
description line 2
- 9) Failure:
+ 10) Failure:
combined::null_string [file:42]
String mismatch: "expected" != actual ("this one fails")
'expected' != NULL
+ 11) Failure:
+combined::failf [file:42]
+ Test failed.
+ some reason: foo
+
+ 12) Failure:
+combined::compare_i [file:42]
+ Expected comparison to hold: two < 1
+ 2 >= 1
+
+ 13) Failure:
+combined::compare_i_with_format [file:42]
+ Expected comparison to hold: two < 1
+ foo: bar
+
+ 14) Failure:
+combined::compare_u [file:42]
+ Expected comparison to hold: two < 1
+ 2 >= 1
+
+ 15) Failure:
+combined::compare_u_with_format [file:42]
+ Expected comparison to hold: two < 1
+ foo: bar
+
written summary file to different.xml
diff --git a/t/unit-tests/clar/test/expected/summary_without_filename b/t/unit-tests/clar/test/expected/summary_without_filename
index 7874c1d98b..83ba770d00 100644
--- a/t/unit-tests/clar/test/expected/summary_without_filename
+++ b/t/unit-tests/clar/test/expected/summary_without_filename
@@ -1,6 +1,6 @@
Loaded 1 suites:
Started (test status codes: OK='.' FAILURE='F' SKIPPED='S')
-FFFFFFFFF
+FFFFFFFFFFFFFFF
1) Failure:
combined::1 [file:42]
@@ -22,28 +22,58 @@ combined::strings_with_length [file:42]
5) Failure:
combined::int [file:42]
- 101 != value ("extra note on failing test")
+ Expected comparison to hold: 101 == value
101 != 100
6) Failure:
+combined::int_note [file:42]
+ Expected comparison to hold: 101 == value
+ extra note on failing test
+
+ 7) Failure:
combined::int_fmt [file:42]
- 022 != value
+ Expected comparison to hold: 022 == value
0022 != 0144
- 7) Failure:
+ 8) Failure:
combined::bool [file:42]
0 != value
0 != 1
- 8) Failure:
+ 9) Failure:
combined::multiline_description [file:42]
Function call failed: -1
description line 1
description line 2
- 9) Failure:
+ 10) Failure:
combined::null_string [file:42]
String mismatch: "expected" != actual ("this one fails")
'expected' != NULL
+ 11) Failure:
+combined::failf [file:42]
+ Test failed.
+ some reason: foo
+
+ 12) Failure:
+combined::compare_i [file:42]
+ Expected comparison to hold: two < 1
+ 2 >= 1
+
+ 13) Failure:
+combined::compare_i_with_format [file:42]
+ Expected comparison to hold: two < 1
+ foo: bar
+
+ 14) Failure:
+combined::compare_u [file:42]
+ Expected comparison to hold: two < 1
+ 2 >= 1
+
+ 15) Failure:
+combined::compare_u_with_format [file:42]
+ Expected comparison to hold: two < 1
+ foo: bar
+
written summary file to summary.xml
diff --git a/t/unit-tests/clar/test/expected/tap b/t/unit-tests/clar/test/expected/tap
index bddbd5dfe9..e67118d3ae 100644
--- a/t/unit-tests/clar/test/expected/tap
+++ b/t/unit-tests/clar/test/expected/tap
@@ -8,7 +8,7 @@ not ok 1 - combined::1
file: 'file'
line: 42
function: 'func'
- ---
+ ...
not ok 2 - combined::2
---
reason: |
@@ -17,7 +17,7 @@ not ok 2 - combined::2
file: 'file'
line: 42
function: 'func'
- ---
+ ...
not ok 3 - combined::strings
---
reason: |
@@ -27,7 +27,7 @@ not ok 3 - combined::strings
file: 'file'
line: 42
function: 'func'
- ---
+ ...
not ok 4 - combined::strings_with_length
---
reason: |
@@ -37,28 +37,38 @@ not ok 4 - combined::strings_with_length
file: 'file'
line: 42
function: 'func'
- ---
+ ...
not ok 5 - combined::int
---
reason: |
- 101 != value ("extra note on failing test")
+ Expected comparison to hold: 101 == value
101 != 100
at:
file: 'file'
line: 42
function: 'func'
+ ...
+not ok 6 - combined::int_note
---
-not ok 6 - combined::int_fmt
+ reason: |
+ Expected comparison to hold: 101 == value
+ extra note on failing test
+ at:
+ file: 'file'
+ line: 42
+ function: 'func'
+ ...
+not ok 7 - combined::int_fmt
---
reason: |
- 022 != value
+ Expected comparison to hold: 022 == value
0022 != 0144
at:
file: 'file'
line: 42
function: 'func'
- ---
-not ok 7 - combined::bool
+ ...
+not ok 8 - combined::bool
---
reason: |
0 != value
@@ -67,8 +77,8 @@ not ok 7 - combined::bool
file: 'file'
line: 42
function: 'func'
- ---
-not ok 8 - combined::multiline_description
+ ...
+not ok 9 - combined::multiline_description
---
reason: |
Function call failed: -1
@@ -78,8 +88,8 @@ not ok 8 - combined::multiline_description
file: 'file'
line: 42
function: 'func'
- ---
-not ok 9 - combined::null_string
+ ...
+not ok 10 - combined::null_string
---
reason: |
String mismatch: "expected" != actual ("this one fails")
@@ -88,5 +98,55 @@ not ok 9 - combined::null_string
file: 'file'
line: 42
function: 'func'
+ ...
+not ok 11 - combined::failf
+ ---
+ reason: |
+ Test failed.
+ some reason: foo
+ at:
+ file: 'file'
+ line: 42
+ function: 'func'
+ ...
+not ok 12 - combined::compare_i
---
-1..9
+ reason: |
+ Expected comparison to hold: two < 1
+ 2 >= 1
+ at:
+ file: 'file'
+ line: 42
+ function: 'func'
+ ...
+not ok 13 - combined::compare_i_with_format
+ ---
+ reason: |
+ Expected comparison to hold: two < 1
+ foo: bar
+ at:
+ file: 'file'
+ line: 42
+ function: 'func'
+ ...
+not ok 14 - combined::compare_u
+ ---
+ reason: |
+ Expected comparison to hold: two < 1
+ 2 >= 1
+ at:
+ file: 'file'
+ line: 42
+ function: 'func'
+ ...
+not ok 15 - combined::compare_u_with_format
+ ---
+ reason: |
+ Expected comparison to hold: two < 1
+ foo: bar
+ at:
+ file: 'file'
+ line: 42
+ function: 'func'
+ ...
+1..15
diff --git a/t/unit-tests/clar/test/expected/without_arguments b/t/unit-tests/clar/test/expected/without_arguments
index 1111d418a0..9891f45a70 100644
--- a/t/unit-tests/clar/test/expected/without_arguments
+++ b/t/unit-tests/clar/test/expected/without_arguments
@@ -1,6 +1,6 @@
Loaded 1 suites:
Started (test status codes: OK='.' FAILURE='F' SKIPPED='S')
-FFFFFFFFF
+FFFFFFFFFFFFFFF
1) Failure:
combined::1 [file:42]
@@ -22,27 +22,57 @@ combined::strings_with_length [file:42]
5) Failure:
combined::int [file:42]
- 101 != value ("extra note on failing test")
+ Expected comparison to hold: 101 == value
101 != 100
6) Failure:
+combined::int_note [file:42]
+ Expected comparison to hold: 101 == value
+ extra note on failing test
+
+ 7) Failure:
combined::int_fmt [file:42]
- 022 != value
+ Expected comparison to hold: 022 == value
0022 != 0144
- 7) Failure:
+ 8) Failure:
combined::bool [file:42]
0 != value
0 != 1
- 8) Failure:
+ 9) Failure:
combined::multiline_description [file:42]
Function call failed: -1
description line 1
description line 2
- 9) Failure:
+ 10) Failure:
combined::null_string [file:42]
String mismatch: "expected" != actual ("this one fails")
'expected' != NULL
+ 11) Failure:
+combined::failf [file:42]
+ Test failed.
+ some reason: foo
+
+ 12) Failure:
+combined::compare_i [file:42]
+ Expected comparison to hold: two < 1
+ 2 >= 1
+
+ 13) Failure:
+combined::compare_i_with_format [file:42]
+ Expected comparison to hold: two < 1
+ foo: bar
+
+ 14) Failure:
+combined::compare_u [file:42]
+ Expected comparison to hold: two < 1
+ 2 >= 1
+
+ 15) Failure:
+combined::compare_u_with_format [file:42]
+ Expected comparison to hold: two < 1
+ foo: bar
+
diff --git a/t/unit-tests/clar/test/selftest.c b/t/unit-tests/clar/test/selftest.c
index eed83e4512..6eadc64c48 100644
--- a/t/unit-tests/clar/test/selftest.c
+++ b/t/unit-tests/clar/test/selftest.c
@@ -298,7 +298,7 @@ void test_selftest__help(void)
void test_selftest__without_arguments(void)
{
- cl_invoke(assert_output("combined", "without_arguments", 9, NULL));
+ cl_invoke(assert_output("combined", "without_arguments", 15, NULL));
}
void test_selftest__specific_test(void)
@@ -313,12 +313,12 @@ void test_selftest__stop_on_failure(void)
void test_selftest__quiet(void)
{
- cl_invoke(assert_output("combined", "quiet", 9, "-q", NULL));
+ cl_invoke(assert_output("combined", "quiet", 15, "-q", NULL));
}
void test_selftest__tap(void)
{
- cl_invoke(assert_output("combined", "tap", 9, "-t", NULL));
+ cl_invoke(assert_output("combined", "tap", 15, "-t", NULL));
}
void test_selftest__suite_names(void)
@@ -329,7 +329,7 @@ void test_selftest__suite_names(void)
void test_selftest__summary_without_filename(void)
{
struct stat st;
- cl_invoke(assert_output("combined", "summary_without_filename", 9, "-r", NULL));
+ cl_invoke(assert_output("combined", "summary_without_filename", 15, "-r", NULL));
/* The summary contains timestamps, so we cannot verify its contents. */
cl_must_pass(stat("summary.xml", &st));
}
@@ -337,7 +337,7 @@ void test_selftest__summary_without_filename(void)
void test_selftest__summary_with_filename(void)
{
struct stat st;
- cl_invoke(assert_output("combined", "summary_with_filename", 9, "-rdifferent.xml", NULL));
+ cl_invoke(assert_output("combined", "summary_with_filename", 15, "-rdifferent.xml", NULL));
/* The summary contains timestamps, so we cannot verify its contents. */
cl_must_pass(stat("different.xml", &st));
}
diff --git a/t/unit-tests/clar/test/suites/combined.c b/t/unit-tests/clar/test/suites/combined.c
index e8b41c98c3..9e9dbc2fb1 100644
--- a/t/unit-tests/clar/test/suites/combined.c
+++ b/t/unit-tests/clar/test/suites/combined.c
@@ -55,7 +55,12 @@ void test_combined__strings_with_length(void)
void test_combined__int(void)
{
int value = 100;
- cl_assert_equal_i(100, value);
+ cl_assert_equal_i(101, value);
+}
+
+void test_combined__int_note(void)
+{
+ int value = 100;
cl_assert_equal_i_(101, value, "extra note on failing test");
}
@@ -83,3 +88,61 @@ void test_combined__null_string(void)
cl_assert_equal_s(actual, actual);
cl_assert_equal_s_("expected", actual, "this one fails");
}
+
+void test_combined__failf(void)
+{
+ cl_failf("some reason: %s", "foo");
+}
+
+void test_combined__compare_i(void)
+{
+ int one = 1, two = 2;
+
+ cl_assert_equal_i(one, 1);
+ cl_assert_equal_i(one, 1);
+ cl_assert_equal_i_(one, 1, "format");
+ cl_assert_lt_i(one, 2);
+ cl_assert_lt_i_(one, 2, "format");
+ cl_assert_le_i(one, 2);
+ cl_assert_le_i(two, 2);
+ cl_assert_le_i_(two, 2, "format");
+ cl_assert_gt_i(two, 1);
+ cl_assert_gt_i_(two, 1, "format");
+ cl_assert_ge_i(two, 2);
+ cl_assert_ge_i(3, two);
+ cl_assert_ge_i_(3, two, "format");
+
+ cl_assert_lt_i(two, 1); /* this one fails */
+}
+
+void test_combined__compare_i_with_format(void)
+{
+ int two = 2;
+ cl_assert_lt_i_(two, 1, "foo: %s", "bar");
+}
+
+void test_combined__compare_u(void)
+{
+ unsigned one = 1, two = 2;
+
+ cl_assert_equal_u(one, 1);
+ cl_assert_equal_u_(one, 1, "format");
+ cl_assert_lt_u(one, 2);
+ cl_assert_lt_u_(one, 2, "format");
+ cl_assert_le_u(one, 2);
+ cl_assert_le_u(two, 2);
+ cl_assert_le_u_(two, 2, "format");
+ cl_assert_gt_u(two, 1);
+ cl_assert_gt_u_(two, 1, "format");
+ cl_assert_ge_u(two, 2);
+ cl_assert_ge_u(3, two);
+ cl_assert_ge_u_(3, two, "format");
+
+ cl_assert_lt_u(two, 1); /* this one fails */
+}
+
+void test_combined__compare_u_with_format(void)
+{
+ unsigned two = 2;
+ cl_assert_lt_u_(two, 1, "foo: %s", "bar");
+}
diff --git a/t/unit-tests/unit-test.h b/t/unit-tests/unit-test.h
index 39a0b72a05..5398b44917 100644
--- a/t/unit-tests/unit-test.h
+++ b/t/unit-tests/unit-test.h
@@ -7,9 +7,3 @@
#else
# include GIT_CLAR_DECLS_H
#endif
-
-#define cl_failf(fmt, ...) do { \
- char desc[4096]; \
- snprintf(desc, sizeof(desc), fmt, __VA_ARGS__); \
- clar__fail(__FILE__, __func__, __LINE__, "Test failed.", desc, 1); \
-} while (0)
--
2.52.0.239.gd5f0c6e74e.dirty
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH 2/2] t/unit-tests: demonstrate use of integer comparison assertions
2025-12-05 12:57 [PATCH 0/2] Update clar for improved integer handling Patrick Steinhardt
2025-12-05 12:57 ` [PATCH 1/2] t/unit-tests: update clar to 39f11fe Patrick Steinhardt
@ 2025-12-05 12:57 ` Patrick Steinhardt
2025-12-06 11:47 ` [PATCH v2 0/3] Update clar for improved integer handling Patrick Steinhardt
2 siblings, 0 replies; 19+ messages in thread
From: Patrick Steinhardt @ 2025-12-05 12:57 UTC (permalink / raw)
To: git; +Cc: Jeff King, Phillip Wood
The clar project has introduced a couple of new assertions that perform
relative integer comparisons, like "greater than" or "less or equal".
Adapt the reftable-record unit tests to demonstrate their usage.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
t/unit-tests/u-reftable-record.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/t/unit-tests/u-reftable-record.c b/t/unit-tests/u-reftable-record.c
index 6c8c0d5374..1bf2e170dc 100644
--- a/t/unit-tests/u-reftable-record.c
+++ b/t/unit-tests/u-reftable-record.c
@@ -51,10 +51,10 @@ void test_reftable_record__varint_roundtrip(void)
int n = put_var_int(&out, in);
uint64_t got = 0;
- cl_assert(n > 0);
+ cl_assert_gt_i(n, 0);
out.len = n;
n = get_var_int(&got, &out);
- cl_assert(n > 0);
+ cl_assert_gt_i(n, 0);
cl_assert_equal_i(got, in);
}
@@ -110,7 +110,7 @@ void test_reftable_record__ref_record_comparison(void)
cl_assert(reftable_record_equal(&in[1], &in[2],
REFTABLE_HASH_SIZE_SHA1) == 0);
cl_assert_equal_i(reftable_record_cmp(&in[1], &in[2], &cmp), 0);
- cl_assert(cmp > 0);
+ cl_assert_gt_i(cmp, 0);
in[1].u.ref.value_type = in[0].u.ref.value_type;
cl_assert(reftable_record_equal(&in[0], &in[1],
@@ -184,7 +184,7 @@ void test_reftable_record__ref_record_roundtrip(void)
reftable_record_key(&in, &key);
n = reftable_record_encode(&in, dest, REFTABLE_HASH_SIZE_SHA1);
- cl_assert(n > 0);
+ cl_assert_gt_i(n, 0);
/* decode into a non-zero reftable_record to test for leaks. */
m = reftable_record_decode(&out, key, i, dest, REFTABLE_HASH_SIZE_SHA1, &scratch);
@@ -228,11 +228,11 @@ void test_reftable_record__log_record_comparison(void)
cl_assert_equal_i(reftable_record_equal(&in[1], &in[2],
REFTABLE_HASH_SIZE_SHA1), 0);
cl_assert_equal_i(reftable_record_cmp(&in[1], &in[2], &cmp), 0);
- cl_assert(cmp > 0);
+ cl_assert_gt_i(cmp, 0);
/* comparison should be reversed for equal keys, because
* comparison is now performed on the basis of update indices */
cl_assert_equal_i(reftable_record_cmp(&in[0], &in[1], &cmp), 0);
- cl_assert(cmp < 0);
+ cl_assert_lt_i(cmp, 0);
in[1].u.log.update_index = in[0].u.log.update_index;
cl_assert(reftable_record_equal(&in[0], &in[1],
@@ -344,7 +344,7 @@ void test_reftable_record__log_record_roundtrip(void)
reftable_record_key(&rec, &key);
n = reftable_record_encode(&rec, dest, REFTABLE_HASH_SIZE_SHA1);
- cl_assert(n >= 0);
+ cl_assert_ge_i(n, 0);
valtype = reftable_record_val_type(&rec);
m = reftable_record_decode(&out, key, valtype, dest,
REFTABLE_HASH_SIZE_SHA1, &scratch);
@@ -382,7 +382,7 @@ void test_reftable_record__key_roundtrip(void)
extra = 6;
n = reftable_encode_key(&restart, dest, last_key, key, extra);
cl_assert(!restart);
- cl_assert(n > 0);
+ cl_assert_gt_i(n, 0);
cl_assert_equal_i(reftable_buf_addstr(&roundtrip,
"refs/heads/master"), 0);
@@ -432,7 +432,7 @@ void test_reftable_record__obj_record_comparison(void)
cl_assert_equal_i(reftable_record_equal(&in[1], &in[2],
REFTABLE_HASH_SIZE_SHA1), 0);
cl_assert_equal_i(reftable_record_cmp(&in[1], &in[2], &cmp), 0);
- cl_assert(cmp > 0);
+ cl_assert_gt_i(cmp, 0);
in[1].u.obj.offset_len = in[0].u.obj.offset_len;
cl_assert(reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1) != 0);
@@ -485,7 +485,7 @@ void test_reftable_record__obj_record_roundtrip(void)
t_copy(&in);
reftable_record_key(&in, &key);
n = reftable_record_encode(&in, dest, REFTABLE_HASH_SIZE_SHA1);
- cl_assert(n > 0);
+ cl_assert_gt_i(n, 0);
extra = reftable_record_val_type(&in);
m = reftable_record_decode(&out, key, extra, dest,
REFTABLE_HASH_SIZE_SHA1, &scratch);
@@ -535,7 +535,7 @@ void test_reftable_record__index_record_comparison(void)
cl_assert_equal_i(reftable_record_equal(&in[1], &in[2],
REFTABLE_HASH_SIZE_SHA1), 0);
cl_assert_equal_i(reftable_record_cmp(&in[1], &in[2], &cmp), 0);
- cl_assert(cmp > 0);
+ cl_assert_gt_i(cmp, 0);
in[1].u.idx.offset = in[0].u.idx.offset;
cl_assert(reftable_record_equal(&in[0], &in[1],
--
2.52.0.239.gd5f0c6e74e.dirty
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH 1/2] t/unit-tests: update clar to 39f11fe
2025-12-05 12:57 ` [PATCH 1/2] t/unit-tests: update clar to 39f11fe Patrick Steinhardt
@ 2025-12-05 18:40 ` Jeff King
2025-12-06 11:39 ` Patrick Steinhardt
2025-12-06 5:27 ` Junio C Hamano
1 sibling, 1 reply; 19+ messages in thread
From: Jeff King @ 2025-12-05 18:40 UTC (permalink / raw)
To: Patrick Steinhardt; +Cc: git, Phillip Wood
On Fri, Dec 05, 2025 at 01:57:52PM +0100, Patrick Steinhardt wrote:
> -#define cl_assert_equal_i(i1,i2) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#i1 " != " #i2, 1, "%d", (int)(i1), (int)(i2))
> -#define cl_assert_equal_i_(i1,i2,note) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#i1 " != " #i2 " (" #note ")", 1, "%d", (i1), (i2))
> -#define cl_assert_equal_i_fmt(i1,i2,fmt) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#i1 " != " #i2, 1, (fmt), (int)(i1), (int)(i2))
> +#define cl_assert_compare_i_(i1, i2, cmp, error, ...) clar__assert_compare_i(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, cmp, \
> + (i1), (i2), "Expected comparison to hold: " error, __VA_ARGS__)
OK, so "i" use to always mean "int", and now...
> +#define cl_assert_compare_i(i1, i2, cmp, error, fmt) do { \
> + intmax_t v1 = (i1), v2 = (i2); \
> + clar__assert_compare_i(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, cmp, \
> + v1, v2, "Expected comparison to hold: " error, fmt, v1, v2); \
> +} while (0)
we use intmax_t. That seems OK, and lets us handle any size integer; the
caller just needs to distinguish signed from unsigned (having "i"
meaning "signed" is a little funny, but I don't have a better
suggestion).
This one is a little odd, though:
> +#define cl_assert_equal_i_fmt(i1, i2, fmt) cl_assert_compare_i_(i1, i2, CLAR_COMPARISON_EQ, #i1 " == " #i2, fmt " != " fmt, (int)(i1), (int)(i2))
Here we still cast to int. I guess we have to in order to keep custom
"%o" and friends working. They probably ought to be using PRIoMAX, but
that would require changes to the tests to do so (and I wonder if we
might hit any portability issues).
-Peff
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/2] t/unit-tests: update clar to 39f11fe
2025-12-05 12:57 ` [PATCH 1/2] t/unit-tests: update clar to 39f11fe Patrick Steinhardt
2025-12-05 18:40 ` Jeff King
@ 2025-12-06 5:27 ` Junio C Hamano
2025-12-06 11:46 ` Patrick Steinhardt
1 sibling, 1 reply; 19+ messages in thread
From: Junio C Hamano @ 2025-12-06 5:27 UTC (permalink / raw)
To: Patrick Steinhardt; +Cc: git, Jeff King, Phillip Wood
Patrick Steinhardt <ps@pks.im> writes:
> diff --git a/t/unit-tests/clar/test/expected/quiet b/t/unit-tests/clar/test/expected/quiet
> index 280c99d8ad..a93273b5a2 100644
> --- a/t/unit-tests/clar/test/expected/quiet
> +++ b/t/unit-tests/clar/test/expected/quiet
> @@ -18,27 +18,57 @@ combined::strings_with_length [file:42]
> ...
> + 15) Failure:
> +combined::compare_u_with_format [file:42]
> + Expected comparison to hold: two < 1
> + foo: bar
> +
> diff ...
If these files in t/unit-tests/clar/test/expected/ directory are
expected to end in a blank line, can we teach our .gitattributes
file that these are OK?
Thanks.
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/2] t/unit-tests: update clar to 39f11fe
2025-12-05 18:40 ` Jeff King
@ 2025-12-06 11:39 ` Patrick Steinhardt
0 siblings, 0 replies; 19+ messages in thread
From: Patrick Steinhardt @ 2025-12-06 11:39 UTC (permalink / raw)
To: Jeff King; +Cc: git, Phillip Wood
On Fri, Dec 05, 2025 at 01:40:20PM -0500, Jeff King wrote:
> On Fri, Dec 05, 2025 at 01:57:52PM +0100, Patrick Steinhardt wrote:
> > +#define cl_assert_equal_i_fmt(i1, i2, fmt) cl_assert_compare_i_(i1, i2, CLAR_COMPARISON_EQ, #i1 " == " #i2, fmt " != " fmt, (int)(i1), (int)(i2))
>
> Here we still cast to int. I guess we have to in order to keep custom
> "%o" and friends working. They probably ought to be using PRIoMAX, but
> that would require changes to the tests to do so (and I wonder if we
> might hit any portability issues).
It certainly is the oddball in this context, yes. I would honestly just
want to drop it entirely, but I can't because it would potentially break
other users. libgit2 for example uses it :/
Patrick
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/2] t/unit-tests: update clar to 39f11fe
2025-12-06 5:27 ` Junio C Hamano
@ 2025-12-06 11:46 ` Patrick Steinhardt
0 siblings, 0 replies; 19+ messages in thread
From: Patrick Steinhardt @ 2025-12-06 11:46 UTC (permalink / raw)
To: Junio C Hamano; +Cc: git, Jeff King, Phillip Wood
On Sat, Dec 06, 2025 at 02:27:55PM +0900, Junio C Hamano wrote:
> Patrick Steinhardt <ps@pks.im> writes:
>
> > diff --git a/t/unit-tests/clar/test/expected/quiet b/t/unit-tests/clar/test/expected/quiet
> > index 280c99d8ad..a93273b5a2 100644
> > --- a/t/unit-tests/clar/test/expected/quiet
> > +++ b/t/unit-tests/clar/test/expected/quiet
> > @@ -18,27 +18,57 @@ combined::strings_with_length [file:42]
> > ...
> > + 15) Failure:
> > +combined::compare_u_with_format [file:42]
> > + Expected comparison to hold: two < 1
> > + foo: bar
> > +
> > diff ...
>
> If these files in t/unit-tests/clar/test/expected/ directory are
> expected to end in a blank line, can we teach our .gitattributes
> file that these are OK?
Yup, will do. Thanks!
Patrick
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 0/3] Update clar for improved integer handling
2025-12-05 12:57 [PATCH 0/2] Update clar for improved integer handling Patrick Steinhardt
2025-12-05 12:57 ` [PATCH 1/2] t/unit-tests: update clar to 39f11fe Patrick Steinhardt
2025-12-05 12:57 ` [PATCH 2/2] t/unit-tests: demonstrate use of integer comparison assertions Patrick Steinhardt
@ 2025-12-06 11:47 ` Patrick Steinhardt
2025-12-06 11:47 ` [PATCH v2 1/3] t/unit-tests: update clar to 39f11fe Patrick Steinhardt
` (3 more replies)
2 siblings, 4 replies; 19+ messages in thread
From: Patrick Steinhardt @ 2025-12-06 11:47 UTC (permalink / raw)
To: git; +Cc: Jeff King, Phillip Wood, Junio C Hamano
Hi,
this patch series updates clar. Most importantly, the update contains
properly typed handling of integers as well as a set of new asserts that
perform relative comparisons, like "less than" or "greater or equal".
Thanks!
Patrick
---
Changes in v2:
- EDITME: describe what is new in this series revision.
- EDITME: use bulletpoints and terse descriptions.
- Link to v1: https://lore.kernel.org/r/20251205-b4-pks-clar-update-v1-0-fd70aac2ab90@pks.im
---
Patrick Steinhardt (3):
t/unit-tests: update clar to 39f11fe
t/unit-tests: demonstrate use of integer comparison assertions
gitattributes: disable blank-at-eof errors for clar test expectations
.gitattributes | 1 +
t/unit-tests/clar/.github/workflows/ci.yml | 2 +-
t/unit-tests/clar/clar.c | 146 ++++++++++++++++++++-
t/unit-tests/clar/clar.h | 82 +++++++++++-
t/unit-tests/clar/clar/print.h | 2 +-
t/unit-tests/clar/test/expected/quiet | 40 +++++-
.../clar/test/expected/summary_with_filename | 42 +++++-
.../clar/test/expected/summary_without_filename | 42 +++++-
t/unit-tests/clar/test/expected/tap | 88 +++++++++++--
t/unit-tests/clar/test/expected/without_arguments | 42 +++++-
t/unit-tests/clar/test/selftest.c | 10 +-
t/unit-tests/clar/test/suites/combined.c | 65 ++++++++-
t/unit-tests/u-reftable-record.c | 22 ++--
t/unit-tests/unit-test.h | 6 -
14 files changed, 520 insertions(+), 70 deletions(-)
Range-diff versus v1:
1: 58f8836bde = 1: d709d75f25 t/unit-tests: update clar to 39f11fe
2: 1b4e93d5b4 = 2: 6b56ad714e t/unit-tests: demonstrate use of integer comparison assertions
-: ---------- > 3: a1b6aec468 gitattributes: disable blank-at-eof errors for clar test expectations
---
base-commit: f0ef5b6d9bcc258e4cbef93839d1b7465d5212b9
change-id: 20251205-b4-pks-clar-update-4fb022908ced
^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH v2 1/3] t/unit-tests: update clar to 39f11fe
2025-12-06 11:47 ` [PATCH v2 0/3] Update clar for improved integer handling Patrick Steinhardt
@ 2025-12-06 11:47 ` Patrick Steinhardt
2026-01-06 10:59 ` Karthik Nayak
2025-12-06 11:47 ` [PATCH v2 2/3] t/unit-tests: demonstrate use of integer comparison assertions Patrick Steinhardt
` (2 subsequent siblings)
3 siblings, 1 reply; 19+ messages in thread
From: Patrick Steinhardt @ 2025-12-06 11:47 UTC (permalink / raw)
To: git; +Cc: Jeff King, Phillip Wood
Update clar to commit 39f11fe (Merge pull request #131 from
pks-gitlab/pks-integer-double-evaluation, 2025-12-05). This commit
includes the following changes relevant to Git:
- There are now typesafe integer comparison functions. Furthermore,
the range of comparison functions has been included to also have
relative comparisons, like "greater than".
- There is a new `cl_failf()` macro that allows the caller to specify
an error message with formatting directives.
- The TAP format has been fixed to correctly terminate YAML blocks
with "...\n" instead of "---\n".
Note that we already had a `cl_failf()` function declared in our own
sources. This function is equivalent to the upstreamed function, so we
can simply drop it now.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
t/unit-tests/clar/.github/workflows/ci.yml | 2 +-
t/unit-tests/clar/clar.c | 146 ++++++++++++++++++++-
t/unit-tests/clar/clar.h | 82 +++++++++++-
t/unit-tests/clar/clar/print.h | 2 +-
t/unit-tests/clar/test/expected/quiet | 40 +++++-
.../clar/test/expected/summary_with_filename | 42 +++++-
.../clar/test/expected/summary_without_filename | 42 +++++-
t/unit-tests/clar/test/expected/tap | 88 +++++++++++--
t/unit-tests/clar/test/expected/without_arguments | 42 +++++-
t/unit-tests/clar/test/selftest.c | 10 +-
t/unit-tests/clar/test/suites/combined.c | 65 ++++++++-
t/unit-tests/unit-test.h | 6 -
12 files changed, 508 insertions(+), 59 deletions(-)
diff --git a/t/unit-tests/clar/.github/workflows/ci.yml b/t/unit-tests/clar/.github/workflows/ci.yml
index 4d4724222c..14cb4ed1d4 100644
--- a/t/unit-tests/clar/.github/workflows/ci.yml
+++ b/t/unit-tests/clar/.github/workflows/ci.yml
@@ -53,7 +53,7 @@ jobs:
if: matrix.platform.image == 'i386/debian:latest'
run: apt -q update && apt -q -y install cmake gcc libc6-amd64 lib64stdc++6 make python3
- name: Check out
- uses: actions/checkout@v4
+ uses: actions/checkout@v6
- name: Build
shell: bash
run: |
diff --git a/t/unit-tests/clar/clar.c b/t/unit-tests/clar/clar.c
index d6176e50b2..e959a5ae02 100644
--- a/t/unit-tests/clar/clar.c
+++ b/t/unit-tests/clar/clar.c
@@ -24,6 +24,14 @@
#include <sys/types.h>
#include <sys/stat.h>
+#ifndef va_copy
+# ifdef __va_copy
+# define va_copy(dst, src) __va_copy(dst, src)
+# else
+# define va_copy(dst, src) ((dst) = (src))
+# endif
+#endif
+
#if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_WCHAR__)
/*
* uClibc can optionally be built without wchar support, in which case
@@ -76,8 +84,10 @@
# define S_ISDIR(x) ((x & _S_IFDIR) != 0)
# endif
# define p_snprintf(buf,sz,fmt,...) _snprintf_s(buf,sz,_TRUNCATE,fmt,__VA_ARGS__)
+# define p_vsnprintf _vsnprintf
# else
# define p_snprintf snprintf
+# define p_vsnprintf vsnprintf
# endif
# define localtime_r(timer, buf) (localtime_s(buf, timer) == 0 ? buf : NULL)
@@ -86,6 +96,7 @@
# include <unistd.h>
# define _MAIN_CC
# define p_snprintf snprintf
+# define p_vsnprintf vsnprintf
typedef struct stat STAT_T;
#endif
@@ -699,13 +710,14 @@ void clar__skip(void)
abort_test();
}
-void clar__fail(
+static void clar__failv(
const char *file,
const char *function,
size_t line,
+ int should_abort,
const char *error_msg,
const char *description,
- int should_abort)
+ va_list args)
{
struct clar_error *error;
@@ -725,9 +737,19 @@ void clar__fail(
error->line_number = _clar.invoke_line ? _clar.invoke_line : line;
error->error_msg = error_msg;
- if (description != NULL &&
- (error->description = strdup(description)) == NULL)
- clar_abort("Failed to allocate description.\n");
+ if (description != NULL) {
+ va_list args_copy;
+ int len;
+
+ va_copy(args_copy, args);
+ if ((len = p_vsnprintf(NULL, 0, description, args_copy)) < 0)
+ clar_abort("Failed to compute description.");
+ va_end(args_copy);
+
+ if ((error->description = calloc(1, len + 1)) == NULL)
+ clar_abort("Failed to allocate buffer.");
+ p_vsnprintf(error->description, len + 1, description, args);
+ }
_clar.total_errors++;
_clar.last_report->status = CL_TEST_FAILURE;
@@ -736,6 +758,34 @@ void clar__fail(
abort_test();
}
+void clar__failf(
+ const char *file,
+ const char *function,
+ size_t line,
+ int should_abort,
+ const char *error_msg,
+ const char *description,
+ ...)
+{
+ va_list args;
+ va_start(args, description);
+ clar__failv(file, function, line, should_abort, error_msg,
+ description, args);
+ va_end(args);
+}
+
+void clar__fail(
+ const char *file,
+ const char *function,
+ size_t line,
+ const char *error_msg,
+ const char *description,
+ int should_abort)
+{
+ clar__failf(file, function, line, should_abort, error_msg,
+ description ? "%s" : NULL, description);
+}
+
void clar__assert(
int condition,
const char *file,
@@ -889,6 +939,92 @@ void clar__assert_equal(
clar__fail(file, function, line, err, buf, should_abort);
}
+void clar__assert_compare_i(
+ const char *file,
+ const char *func,
+ size_t line,
+ int should_abort,
+ enum clar_comparison cmp,
+ intmax_t value1,
+ intmax_t value2,
+ const char *error,
+ const char *description,
+ ...)
+{
+ int fulfilled;
+ switch (cmp) {
+ case CLAR_COMPARISON_EQ:
+ fulfilled = value1 == value2;
+ break;
+ case CLAR_COMPARISON_LT:
+ fulfilled = value1 < value2;
+ break;
+ case CLAR_COMPARISON_LE:
+ fulfilled = value1 <= value2;
+ break;
+ case CLAR_COMPARISON_GT:
+ fulfilled = value1 > value2;
+ break;
+ case CLAR_COMPARISON_GE:
+ fulfilled = value1 >= value2;
+ break;
+ default:
+ cl_assert(0);
+ return;
+ }
+
+ if (!fulfilled) {
+ va_list args;
+ va_start(args, description);
+ clar__failv(file, func, line, should_abort, error,
+ description, args);
+ va_end(args);
+ }
+}
+
+void clar__assert_compare_u(
+ const char *file,
+ const char *func,
+ size_t line,
+ int should_abort,
+ enum clar_comparison cmp,
+ uintmax_t value1,
+ uintmax_t value2,
+ const char *error,
+ const char *description,
+ ...)
+{
+ int fulfilled;
+ switch (cmp) {
+ case CLAR_COMPARISON_EQ:
+ fulfilled = value1 == value2;
+ break;
+ case CLAR_COMPARISON_LT:
+ fulfilled = value1 < value2;
+ break;
+ case CLAR_COMPARISON_LE:
+ fulfilled = value1 <= value2;
+ break;
+ case CLAR_COMPARISON_GT:
+ fulfilled = value1 > value2;
+ break;
+ case CLAR_COMPARISON_GE:
+ fulfilled = value1 >= value2;
+ break;
+ default:
+ cl_assert(0);
+ return;
+ }
+
+ if (!fulfilled) {
+ va_list args;
+ va_start(args, description);
+ clar__failv(file, func, line, should_abort, error,
+ description, args);
+ va_end(args);
+ }
+}
+
void cl_set_cleanup(void (*cleanup)(void *), void *opaque)
{
_clar.local_cleanup = cleanup;
diff --git a/t/unit-tests/clar/clar.h b/t/unit-tests/clar/clar.h
index ca72292ae9..f7e4363022 100644
--- a/t/unit-tests/clar/clar.h
+++ b/t/unit-tests/clar/clar.h
@@ -7,6 +7,7 @@
#ifndef __CLAR_TEST_H__
#define __CLAR_TEST_H__
+#include <inttypes.h>
#include <stdlib.h>
#include <limits.h>
@@ -149,6 +150,7 @@ const char *cl_fixture_basename(const char *fixture_name);
* Forced failure/warning
*/
#define cl_fail(desc) clar__fail(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Test failed.", desc, 1)
+#define cl_failf(desc,...) clar__failf(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, "Test failed.", desc, __VA_ARGS__)
#define cl_warning(desc) clar__fail(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Warning during test execution:", desc, 0)
#define cl_skip() clar__skip()
@@ -168,9 +170,42 @@ const char *cl_fixture_basename(const char *fixture_name);
#define cl_assert_equal_wcsn(wcs1,wcs2,len) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #wcs1 " != " #wcs2, 1, "%.*ls", (wcs1), (wcs2), (int)(len))
#define cl_assert_equal_wcsn_(wcs1,wcs2,len,note) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%.*ls", (wcs1), (wcs2), (int)(len))
-#define cl_assert_equal_i(i1,i2) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#i1 " != " #i2, 1, "%d", (int)(i1), (int)(i2))
-#define cl_assert_equal_i_(i1,i2,note) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#i1 " != " #i2 " (" #note ")", 1, "%d", (i1), (i2))
-#define cl_assert_equal_i_fmt(i1,i2,fmt) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#i1 " != " #i2, 1, (fmt), (int)(i1), (int)(i2))
+#define cl_assert_compare_i_(i1, i2, cmp, error, ...) clar__assert_compare_i(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, cmp, \
+ (i1), (i2), "Expected comparison to hold: " error, __VA_ARGS__)
+#define cl_assert_compare_i(i1, i2, cmp, error, fmt) do { \
+ intmax_t v1 = (i1), v2 = (i2); \
+ clar__assert_compare_i(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, cmp, \
+ v1, v2, "Expected comparison to hold: " error, fmt, v1, v2); \
+} while (0)
+#define cl_assert_equal_i_(i1, i2, ...) cl_assert_compare_i_(i1, i2, CLAR_COMPARISON_EQ, #i1 " == " #i2, __VA_ARGS__)
+#define cl_assert_equal_i(i1, i2) cl_assert_compare_i (i1, i2, CLAR_COMPARISON_EQ, #i1 " == " #i2, "%"PRIdMAX " != %"PRIdMAX)
+#define cl_assert_equal_i_fmt(i1, i2, fmt) cl_assert_compare_i_(i1, i2, CLAR_COMPARISON_EQ, #i1 " == " #i2, fmt " != " fmt, (int)(i1), (int)(i2))
+#define cl_assert_lt_i_(i1, i2, ...) cl_assert_compare_i_(i1, i2, CLAR_COMPARISON_LT, #i1 " < " #i2, __VA_ARGS__)
+#define cl_assert_lt_i(i1, i2) cl_assert_compare_i (i1, i2, CLAR_COMPARISON_LT, #i1 " < " #i2, "%"PRIdMAX " >= %"PRIdMAX)
+#define cl_assert_le_i_(i1, i2, ...) cl_assert_compare_i_(i1, i2, CLAR_COMPARISON_LE, #i1 " <= " #i2, __VA_ARGS__)
+#define cl_assert_le_i(i1, i2) cl_assert_compare_i (i1, i2, CLAR_COMPARISON_LE, #i1 " <= " #i2, "%"PRIdMAX " > %"PRIdMAX)
+#define cl_assert_gt_i_(i1, i2, ...) cl_assert_compare_i_(i1, i2, CLAR_COMPARISON_GT, #i1 " > " #i2, __VA_ARGS__)
+#define cl_assert_gt_i(i1, i2) cl_assert_compare_i (i1, i2, CLAR_COMPARISON_GT, #i1 " > " #i2, "%"PRIdMAX " <= %"PRIdMAX)
+#define cl_assert_ge_i_(i1, i2, ...) cl_assert_compare_i_(i1, i2, CLAR_COMPARISON_GE, #i1 " >= " #i2, __VA_ARGS__)
+#define cl_assert_ge_i(i1, i2) cl_assert_compare_i (i1, i2, CLAR_COMPARISON_GE, #i1 " >= " #i2, "%"PRIdMAX " < %"PRIdMAX)
+
+#define cl_assert_compare_u_(u1, u2, cmp, error, ...) clar__assert_compare_u(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, cmp, \
+ (u1), (u2), "Expected comparison to hold: " error, __VA_ARGS__)
+#define cl_assert_compare_u(u1, u2, cmp, error, fmt) do { \
+ uintmax_t v1 = (u1), v2 = (u2); \
+ clar__assert_compare_u(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, cmp, \
+ v1, v2, "Expected comparison to hold: " error, fmt, v1, v2); \
+} while (0)
+#define cl_assert_equal_u_(u1, u2, ...) cl_assert_compare_u_(u1, u2, CLAR_COMPARISON_EQ, #u1 " == " #u2, __VA_ARGS__)
+#define cl_assert_equal_u(u1, u2) cl_assert_compare_u (u1, u2, CLAR_COMPARISON_EQ, #u1 " == " #u2, "%"PRIuMAX " != %"PRIuMAX)
+#define cl_assert_lt_u_(u1, u2, ...) cl_assert_compare_u_(u1, u2, CLAR_COMPARISON_LT, #u1 " < " #u2, __VA_ARGS__)
+#define cl_assert_lt_u(u1, u2) cl_assert_compare_u (u1, u2, CLAR_COMPARISON_LT, #u1 " < " #u2, "%"PRIuMAX " >= %"PRIuMAX)
+#define cl_assert_le_u_(u1, u2, ...) cl_assert_compare_u_(u1, u2, CLAR_COMPARISON_LE, #u1 " <= " #u2, __VA_ARGS__)
+#define cl_assert_le_u(u1, u2) cl_assert_compare_u (u1, u2, CLAR_COMPARISON_LE, #u1 " <= " #u2, "%"PRIuMAX " > %"PRIuMAX)
+#define cl_assert_gt_u_(u1, u2, ...) cl_assert_compare_u_(u1, u2, CLAR_COMPARISON_GT, #u1 " > " #u2, __VA_ARGS__)
+#define cl_assert_gt_u(u1, u2) cl_assert_compare_u (u1, u2, CLAR_COMPARISON_GT, #u1 " > " #u2, "%"PRIuMAX " <= %"PRIuMAX)
+#define cl_assert_ge_u_(u1, u2, ...) cl_assert_compare_u_(u1, u2, CLAR_COMPARISON_GE, #u1 " >= " #u2, __VA_ARGS__)
+#define cl_assert_ge_u(u1, u2) cl_assert_compare_u (u1, u2, CLAR_COMPARISON_GE, #u1 " >= " #u2, "%"PRIuMAX " < %"PRIuMAX)
#define cl_assert_equal_b(b1,b2) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#b1 " != " #b2, 1, "%d", (int)((b1) != 0),(int)((b2) != 0))
@@ -186,6 +221,15 @@ void clar__fail(
const char *description,
int should_abort);
+void clar__failf(
+ const char *file,
+ const char *func,
+ size_t line,
+ int should_abort,
+ const char *error,
+ const char *description,
+ ...);
+
void clar__assert(
int condition,
const char *file,
@@ -204,6 +248,38 @@ void clar__assert_equal(
const char *fmt,
...);
+enum clar_comparison {
+ CLAR_COMPARISON_EQ,
+ CLAR_COMPARISON_LT,
+ CLAR_COMPARISON_LE,
+ CLAR_COMPARISON_GT,
+ CLAR_COMPARISON_GE,
+};
+
+void clar__assert_compare_i(
+ const char *file,
+ const char *func,
+ size_t line,
+ int should_abort,
+ enum clar_comparison cmp,
+ intmax_t value1,
+ intmax_t value2,
+ const char *error,
+ const char *description,
+ ...);
+
+void clar__assert_compare_u(
+ const char *file,
+ const char *func,
+ size_t line,
+ int should_abort,
+ enum clar_comparison cmp,
+ uintmax_t value1,
+ uintmax_t value2,
+ const char *error,
+ const char *description,
+ ...);
+
void clar__set_invokepoint(
const char *file,
const char *func,
diff --git a/t/unit-tests/clar/clar/print.h b/t/unit-tests/clar/clar/print.h
index 89b66591d7..6a2321b399 100644
--- a/t/unit-tests/clar/clar/print.h
+++ b/t/unit-tests/clar/clar/print.h
@@ -164,7 +164,7 @@ static void clar_print_tap_ontest(const char *suite_name, const char *test_name,
printf(" file: '"); print_escaped(error->file); printf("'\n");
printf(" line: %" PRIuMAX "\n", error->line_number);
printf(" function: '%s'\n", error->function);
- printf(" ---\n");
+ printf(" ...\n");
}
break;
diff --git a/t/unit-tests/clar/test/expected/quiet b/t/unit-tests/clar/test/expected/quiet
index 280c99d8ad..a93273b5a2 100644
--- a/t/unit-tests/clar/test/expected/quiet
+++ b/t/unit-tests/clar/test/expected/quiet
@@ -18,27 +18,57 @@ combined::strings_with_length [file:42]
5) Failure:
combined::int [file:42]
- 101 != value ("extra note on failing test")
+ Expected comparison to hold: 101 == value
101 != 100
6) Failure:
+combined::int_note [file:42]
+ Expected comparison to hold: 101 == value
+ extra note on failing test
+
+ 7) Failure:
combined::int_fmt [file:42]
- 022 != value
+ Expected comparison to hold: 022 == value
0022 != 0144
- 7) Failure:
+ 8) Failure:
combined::bool [file:42]
0 != value
0 != 1
- 8) Failure:
+ 9) Failure:
combined::multiline_description [file:42]
Function call failed: -1
description line 1
description line 2
- 9) Failure:
+ 10) Failure:
combined::null_string [file:42]
String mismatch: "expected" != actual ("this one fails")
'expected' != NULL
+ 11) Failure:
+combined::failf [file:42]
+ Test failed.
+ some reason: foo
+
+ 12) Failure:
+combined::compare_i [file:42]
+ Expected comparison to hold: two < 1
+ 2 >= 1
+
+ 13) Failure:
+combined::compare_i_with_format [file:42]
+ Expected comparison to hold: two < 1
+ foo: bar
+
+ 14) Failure:
+combined::compare_u [file:42]
+ Expected comparison to hold: two < 1
+ 2 >= 1
+
+ 15) Failure:
+combined::compare_u_with_format [file:42]
+ Expected comparison to hold: two < 1
+ foo: bar
+
diff --git a/t/unit-tests/clar/test/expected/summary_with_filename b/t/unit-tests/clar/test/expected/summary_with_filename
index 460160791d..a9471cc7d5 100644
--- a/t/unit-tests/clar/test/expected/summary_with_filename
+++ b/t/unit-tests/clar/test/expected/summary_with_filename
@@ -1,6 +1,6 @@
Loaded 1 suites:
Started (test status codes: OK='.' FAILURE='F' SKIPPED='S')
-FFFFFFFFF
+FFFFFFFFFFFFFFF
1) Failure:
combined::1 [file:42]
@@ -22,28 +22,58 @@ combined::strings_with_length [file:42]
5) Failure:
combined::int [file:42]
- 101 != value ("extra note on failing test")
+ Expected comparison to hold: 101 == value
101 != 100
6) Failure:
+combined::int_note [file:42]
+ Expected comparison to hold: 101 == value
+ extra note on failing test
+
+ 7) Failure:
combined::int_fmt [file:42]
- 022 != value
+ Expected comparison to hold: 022 == value
0022 != 0144
- 7) Failure:
+ 8) Failure:
combined::bool [file:42]
0 != value
0 != 1
- 8) Failure:
+ 9) Failure:
combined::multiline_description [file:42]
Function call failed: -1
description line 1
description line 2
- 9) Failure:
+ 10) Failure:
combined::null_string [file:42]
String mismatch: "expected" != actual ("this one fails")
'expected' != NULL
+ 11) Failure:
+combined::failf [file:42]
+ Test failed.
+ some reason: foo
+
+ 12) Failure:
+combined::compare_i [file:42]
+ Expected comparison to hold: two < 1
+ 2 >= 1
+
+ 13) Failure:
+combined::compare_i_with_format [file:42]
+ Expected comparison to hold: two < 1
+ foo: bar
+
+ 14) Failure:
+combined::compare_u [file:42]
+ Expected comparison to hold: two < 1
+ 2 >= 1
+
+ 15) Failure:
+combined::compare_u_with_format [file:42]
+ Expected comparison to hold: two < 1
+ foo: bar
+
written summary file to different.xml
diff --git a/t/unit-tests/clar/test/expected/summary_without_filename b/t/unit-tests/clar/test/expected/summary_without_filename
index 7874c1d98b..83ba770d00 100644
--- a/t/unit-tests/clar/test/expected/summary_without_filename
+++ b/t/unit-tests/clar/test/expected/summary_without_filename
@@ -1,6 +1,6 @@
Loaded 1 suites:
Started (test status codes: OK='.' FAILURE='F' SKIPPED='S')
-FFFFFFFFF
+FFFFFFFFFFFFFFF
1) Failure:
combined::1 [file:42]
@@ -22,28 +22,58 @@ combined::strings_with_length [file:42]
5) Failure:
combined::int [file:42]
- 101 != value ("extra note on failing test")
+ Expected comparison to hold: 101 == value
101 != 100
6) Failure:
+combined::int_note [file:42]
+ Expected comparison to hold: 101 == value
+ extra note on failing test
+
+ 7) Failure:
combined::int_fmt [file:42]
- 022 != value
+ Expected comparison to hold: 022 == value
0022 != 0144
- 7) Failure:
+ 8) Failure:
combined::bool [file:42]
0 != value
0 != 1
- 8) Failure:
+ 9) Failure:
combined::multiline_description [file:42]
Function call failed: -1
description line 1
description line 2
- 9) Failure:
+ 10) Failure:
combined::null_string [file:42]
String mismatch: "expected" != actual ("this one fails")
'expected' != NULL
+ 11) Failure:
+combined::failf [file:42]
+ Test failed.
+ some reason: foo
+
+ 12) Failure:
+combined::compare_i [file:42]
+ Expected comparison to hold: two < 1
+ 2 >= 1
+
+ 13) Failure:
+combined::compare_i_with_format [file:42]
+ Expected comparison to hold: two < 1
+ foo: bar
+
+ 14) Failure:
+combined::compare_u [file:42]
+ Expected comparison to hold: two < 1
+ 2 >= 1
+
+ 15) Failure:
+combined::compare_u_with_format [file:42]
+ Expected comparison to hold: two < 1
+ foo: bar
+
written summary file to summary.xml
diff --git a/t/unit-tests/clar/test/expected/tap b/t/unit-tests/clar/test/expected/tap
index bddbd5dfe9..e67118d3ae 100644
--- a/t/unit-tests/clar/test/expected/tap
+++ b/t/unit-tests/clar/test/expected/tap
@@ -8,7 +8,7 @@ not ok 1 - combined::1
file: 'file'
line: 42
function: 'func'
- ---
+ ...
not ok 2 - combined::2
---
reason: |
@@ -17,7 +17,7 @@ not ok 2 - combined::2
file: 'file'
line: 42
function: 'func'
- ---
+ ...
not ok 3 - combined::strings
---
reason: |
@@ -27,7 +27,7 @@ not ok 3 - combined::strings
file: 'file'
line: 42
function: 'func'
- ---
+ ...
not ok 4 - combined::strings_with_length
---
reason: |
@@ -37,28 +37,38 @@ not ok 4 - combined::strings_with_length
file: 'file'
line: 42
function: 'func'
- ---
+ ...
not ok 5 - combined::int
---
reason: |
- 101 != value ("extra note on failing test")
+ Expected comparison to hold: 101 == value
101 != 100
at:
file: 'file'
line: 42
function: 'func'
+ ...
+not ok 6 - combined::int_note
---
-not ok 6 - combined::int_fmt
+ reason: |
+ Expected comparison to hold: 101 == value
+ extra note on failing test
+ at:
+ file: 'file'
+ line: 42
+ function: 'func'
+ ...
+not ok 7 - combined::int_fmt
---
reason: |
- 022 != value
+ Expected comparison to hold: 022 == value
0022 != 0144
at:
file: 'file'
line: 42
function: 'func'
- ---
-not ok 7 - combined::bool
+ ...
+not ok 8 - combined::bool
---
reason: |
0 != value
@@ -67,8 +77,8 @@ not ok 7 - combined::bool
file: 'file'
line: 42
function: 'func'
- ---
-not ok 8 - combined::multiline_description
+ ...
+not ok 9 - combined::multiline_description
---
reason: |
Function call failed: -1
@@ -78,8 +88,8 @@ not ok 8 - combined::multiline_description
file: 'file'
line: 42
function: 'func'
- ---
-not ok 9 - combined::null_string
+ ...
+not ok 10 - combined::null_string
---
reason: |
String mismatch: "expected" != actual ("this one fails")
@@ -88,5 +98,55 @@ not ok 9 - combined::null_string
file: 'file'
line: 42
function: 'func'
+ ...
+not ok 11 - combined::failf
+ ---
+ reason: |
+ Test failed.
+ some reason: foo
+ at:
+ file: 'file'
+ line: 42
+ function: 'func'
+ ...
+not ok 12 - combined::compare_i
---
-1..9
+ reason: |
+ Expected comparison to hold: two < 1
+ 2 >= 1
+ at:
+ file: 'file'
+ line: 42
+ function: 'func'
+ ...
+not ok 13 - combined::compare_i_with_format
+ ---
+ reason: |
+ Expected comparison to hold: two < 1
+ foo: bar
+ at:
+ file: 'file'
+ line: 42
+ function: 'func'
+ ...
+not ok 14 - combined::compare_u
+ ---
+ reason: |
+ Expected comparison to hold: two < 1
+ 2 >= 1
+ at:
+ file: 'file'
+ line: 42
+ function: 'func'
+ ...
+not ok 15 - combined::compare_u_with_format
+ ---
+ reason: |
+ Expected comparison to hold: two < 1
+ foo: bar
+ at:
+ file: 'file'
+ line: 42
+ function: 'func'
+ ...
+1..15
diff --git a/t/unit-tests/clar/test/expected/without_arguments b/t/unit-tests/clar/test/expected/without_arguments
index 1111d418a0..9891f45a70 100644
--- a/t/unit-tests/clar/test/expected/without_arguments
+++ b/t/unit-tests/clar/test/expected/without_arguments
@@ -1,6 +1,6 @@
Loaded 1 suites:
Started (test status codes: OK='.' FAILURE='F' SKIPPED='S')
-FFFFFFFFF
+FFFFFFFFFFFFFFF
1) Failure:
combined::1 [file:42]
@@ -22,27 +22,57 @@ combined::strings_with_length [file:42]
5) Failure:
combined::int [file:42]
- 101 != value ("extra note on failing test")
+ Expected comparison to hold: 101 == value
101 != 100
6) Failure:
+combined::int_note [file:42]
+ Expected comparison to hold: 101 == value
+ extra note on failing test
+
+ 7) Failure:
combined::int_fmt [file:42]
- 022 != value
+ Expected comparison to hold: 022 == value
0022 != 0144
- 7) Failure:
+ 8) Failure:
combined::bool [file:42]
0 != value
0 != 1
- 8) Failure:
+ 9) Failure:
combined::multiline_description [file:42]
Function call failed: -1
description line 1
description line 2
- 9) Failure:
+ 10) Failure:
combined::null_string [file:42]
String mismatch: "expected" != actual ("this one fails")
'expected' != NULL
+ 11) Failure:
+combined::failf [file:42]
+ Test failed.
+ some reason: foo
+
+ 12) Failure:
+combined::compare_i [file:42]
+ Expected comparison to hold: two < 1
+ 2 >= 1
+
+ 13) Failure:
+combined::compare_i_with_format [file:42]
+ Expected comparison to hold: two < 1
+ foo: bar
+
+ 14) Failure:
+combined::compare_u [file:42]
+ Expected comparison to hold: two < 1
+ 2 >= 1
+
+ 15) Failure:
+combined::compare_u_with_format [file:42]
+ Expected comparison to hold: two < 1
+ foo: bar
+
diff --git a/t/unit-tests/clar/test/selftest.c b/t/unit-tests/clar/test/selftest.c
index eed83e4512..6eadc64c48 100644
--- a/t/unit-tests/clar/test/selftest.c
+++ b/t/unit-tests/clar/test/selftest.c
@@ -298,7 +298,7 @@ void test_selftest__help(void)
void test_selftest__without_arguments(void)
{
- cl_invoke(assert_output("combined", "without_arguments", 9, NULL));
+ cl_invoke(assert_output("combined", "without_arguments", 15, NULL));
}
void test_selftest__specific_test(void)
@@ -313,12 +313,12 @@ void test_selftest__stop_on_failure(void)
void test_selftest__quiet(void)
{
- cl_invoke(assert_output("combined", "quiet", 9, "-q", NULL));
+ cl_invoke(assert_output("combined", "quiet", 15, "-q", NULL));
}
void test_selftest__tap(void)
{
- cl_invoke(assert_output("combined", "tap", 9, "-t", NULL));
+ cl_invoke(assert_output("combined", "tap", 15, "-t", NULL));
}
void test_selftest__suite_names(void)
@@ -329,7 +329,7 @@ void test_selftest__suite_names(void)
void test_selftest__summary_without_filename(void)
{
struct stat st;
- cl_invoke(assert_output("combined", "summary_without_filename", 9, "-r", NULL));
+ cl_invoke(assert_output("combined", "summary_without_filename", 15, "-r", NULL));
/* The summary contains timestamps, so we cannot verify its contents. */
cl_must_pass(stat("summary.xml", &st));
}
@@ -337,7 +337,7 @@ void test_selftest__summary_without_filename(void)
void test_selftest__summary_with_filename(void)
{
struct stat st;
- cl_invoke(assert_output("combined", "summary_with_filename", 9, "-rdifferent.xml", NULL));
+ cl_invoke(assert_output("combined", "summary_with_filename", 15, "-rdifferent.xml", NULL));
/* The summary contains timestamps, so we cannot verify its contents. */
cl_must_pass(stat("different.xml", &st));
}
diff --git a/t/unit-tests/clar/test/suites/combined.c b/t/unit-tests/clar/test/suites/combined.c
index e8b41c98c3..9e9dbc2fb1 100644
--- a/t/unit-tests/clar/test/suites/combined.c
+++ b/t/unit-tests/clar/test/suites/combined.c
@@ -55,7 +55,12 @@ void test_combined__strings_with_length(void)
void test_combined__int(void)
{
int value = 100;
- cl_assert_equal_i(100, value);
+ cl_assert_equal_i(101, value);
+}
+
+void test_combined__int_note(void)
+{
+ int value = 100;
cl_assert_equal_i_(101, value, "extra note on failing test");
}
@@ -83,3 +88,61 @@ void test_combined__null_string(void)
cl_assert_equal_s(actual, actual);
cl_assert_equal_s_("expected", actual, "this one fails");
}
+
+void test_combined__failf(void)
+{
+ cl_failf("some reason: %s", "foo");
+}
+
+void test_combined__compare_i(void)
+{
+ int one = 1, two = 2;
+
+ cl_assert_equal_i(one, 1);
+ cl_assert_equal_i(one, 1);
+ cl_assert_equal_i_(one, 1, "format");
+ cl_assert_lt_i(one, 2);
+ cl_assert_lt_i_(one, 2, "format");
+ cl_assert_le_i(one, 2);
+ cl_assert_le_i(two, 2);
+ cl_assert_le_i_(two, 2, "format");
+ cl_assert_gt_i(two, 1);
+ cl_assert_gt_i_(two, 1, "format");
+ cl_assert_ge_i(two, 2);
+ cl_assert_ge_i(3, two);
+ cl_assert_ge_i_(3, two, "format");
+
+ cl_assert_lt_i(two, 1); /* this one fails */
+}
+
+void test_combined__compare_i_with_format(void)
+{
+ int two = 2;
+ cl_assert_lt_i_(two, 1, "foo: %s", "bar");
+}
+
+void test_combined__compare_u(void)
+{
+ unsigned one = 1, two = 2;
+
+ cl_assert_equal_u(one, 1);
+ cl_assert_equal_u_(one, 1, "format");
+ cl_assert_lt_u(one, 2);
+ cl_assert_lt_u_(one, 2, "format");
+ cl_assert_le_u(one, 2);
+ cl_assert_le_u(two, 2);
+ cl_assert_le_u_(two, 2, "format");
+ cl_assert_gt_u(two, 1);
+ cl_assert_gt_u_(two, 1, "format");
+ cl_assert_ge_u(two, 2);
+ cl_assert_ge_u(3, two);
+ cl_assert_ge_u_(3, two, "format");
+
+ cl_assert_lt_u(two, 1); /* this one fails */
+}
+
+void test_combined__compare_u_with_format(void)
+{
+ unsigned two = 2;
+ cl_assert_lt_u_(two, 1, "foo: %s", "bar");
+}
diff --git a/t/unit-tests/unit-test.h b/t/unit-tests/unit-test.h
index 39a0b72a05..5398b44917 100644
--- a/t/unit-tests/unit-test.h
+++ b/t/unit-tests/unit-test.h
@@ -7,9 +7,3 @@
#else
# include GIT_CLAR_DECLS_H
#endif
-
-#define cl_failf(fmt, ...) do { \
- char desc[4096]; \
- snprintf(desc, sizeof(desc), fmt, __VA_ARGS__); \
- clar__fail(__FILE__, __func__, __LINE__, "Test failed.", desc, 1); \
-} while (0)
--
2.52.0.239.gd5f0c6e74e.dirty
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v2 2/3] t/unit-tests: demonstrate use of integer comparison assertions
2025-12-06 11:47 ` [PATCH v2 0/3] Update clar for improved integer handling Patrick Steinhardt
2025-12-06 11:47 ` [PATCH v2 1/3] t/unit-tests: update clar to 39f11fe Patrick Steinhardt
@ 2025-12-06 11:47 ` Patrick Steinhardt
2025-12-06 11:47 ` [PATCH v2 3/3] gitattributes: disable blank-at-eof errors for clar test expectations Patrick Steinhardt
2026-01-06 11:01 ` [PATCH v2 0/3] Update clar for improved integer handling Karthik Nayak
3 siblings, 0 replies; 19+ messages in thread
From: Patrick Steinhardt @ 2025-12-06 11:47 UTC (permalink / raw)
To: git; +Cc: Jeff King, Phillip Wood
The clar project has introduced a couple of new assertions that perform
relative integer comparisons, like "greater than" or "less or equal".
Adapt the reftable-record unit tests to demonstrate their usage.
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
t/unit-tests/u-reftable-record.c | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/t/unit-tests/u-reftable-record.c b/t/unit-tests/u-reftable-record.c
index 6c8c0d5374..1bf2e170dc 100644
--- a/t/unit-tests/u-reftable-record.c
+++ b/t/unit-tests/u-reftable-record.c
@@ -51,10 +51,10 @@ void test_reftable_record__varint_roundtrip(void)
int n = put_var_int(&out, in);
uint64_t got = 0;
- cl_assert(n > 0);
+ cl_assert_gt_i(n, 0);
out.len = n;
n = get_var_int(&got, &out);
- cl_assert(n > 0);
+ cl_assert_gt_i(n, 0);
cl_assert_equal_i(got, in);
}
@@ -110,7 +110,7 @@ void test_reftable_record__ref_record_comparison(void)
cl_assert(reftable_record_equal(&in[1], &in[2],
REFTABLE_HASH_SIZE_SHA1) == 0);
cl_assert_equal_i(reftable_record_cmp(&in[1], &in[2], &cmp), 0);
- cl_assert(cmp > 0);
+ cl_assert_gt_i(cmp, 0);
in[1].u.ref.value_type = in[0].u.ref.value_type;
cl_assert(reftable_record_equal(&in[0], &in[1],
@@ -184,7 +184,7 @@ void test_reftable_record__ref_record_roundtrip(void)
reftable_record_key(&in, &key);
n = reftable_record_encode(&in, dest, REFTABLE_HASH_SIZE_SHA1);
- cl_assert(n > 0);
+ cl_assert_gt_i(n, 0);
/* decode into a non-zero reftable_record to test for leaks. */
m = reftable_record_decode(&out, key, i, dest, REFTABLE_HASH_SIZE_SHA1, &scratch);
@@ -228,11 +228,11 @@ void test_reftable_record__log_record_comparison(void)
cl_assert_equal_i(reftable_record_equal(&in[1], &in[2],
REFTABLE_HASH_SIZE_SHA1), 0);
cl_assert_equal_i(reftable_record_cmp(&in[1], &in[2], &cmp), 0);
- cl_assert(cmp > 0);
+ cl_assert_gt_i(cmp, 0);
/* comparison should be reversed for equal keys, because
* comparison is now performed on the basis of update indices */
cl_assert_equal_i(reftable_record_cmp(&in[0], &in[1], &cmp), 0);
- cl_assert(cmp < 0);
+ cl_assert_lt_i(cmp, 0);
in[1].u.log.update_index = in[0].u.log.update_index;
cl_assert(reftable_record_equal(&in[0], &in[1],
@@ -344,7 +344,7 @@ void test_reftable_record__log_record_roundtrip(void)
reftable_record_key(&rec, &key);
n = reftable_record_encode(&rec, dest, REFTABLE_HASH_SIZE_SHA1);
- cl_assert(n >= 0);
+ cl_assert_ge_i(n, 0);
valtype = reftable_record_val_type(&rec);
m = reftable_record_decode(&out, key, valtype, dest,
REFTABLE_HASH_SIZE_SHA1, &scratch);
@@ -382,7 +382,7 @@ void test_reftable_record__key_roundtrip(void)
extra = 6;
n = reftable_encode_key(&restart, dest, last_key, key, extra);
cl_assert(!restart);
- cl_assert(n > 0);
+ cl_assert_gt_i(n, 0);
cl_assert_equal_i(reftable_buf_addstr(&roundtrip,
"refs/heads/master"), 0);
@@ -432,7 +432,7 @@ void test_reftable_record__obj_record_comparison(void)
cl_assert_equal_i(reftable_record_equal(&in[1], &in[2],
REFTABLE_HASH_SIZE_SHA1), 0);
cl_assert_equal_i(reftable_record_cmp(&in[1], &in[2], &cmp), 0);
- cl_assert(cmp > 0);
+ cl_assert_gt_i(cmp, 0);
in[1].u.obj.offset_len = in[0].u.obj.offset_len;
cl_assert(reftable_record_equal(&in[0], &in[1], REFTABLE_HASH_SIZE_SHA1) != 0);
@@ -485,7 +485,7 @@ void test_reftable_record__obj_record_roundtrip(void)
t_copy(&in);
reftable_record_key(&in, &key);
n = reftable_record_encode(&in, dest, REFTABLE_HASH_SIZE_SHA1);
- cl_assert(n > 0);
+ cl_assert_gt_i(n, 0);
extra = reftable_record_val_type(&in);
m = reftable_record_decode(&out, key, extra, dest,
REFTABLE_HASH_SIZE_SHA1, &scratch);
@@ -535,7 +535,7 @@ void test_reftable_record__index_record_comparison(void)
cl_assert_equal_i(reftable_record_equal(&in[1], &in[2],
REFTABLE_HASH_SIZE_SHA1), 0);
cl_assert_equal_i(reftable_record_cmp(&in[1], &in[2], &cmp), 0);
- cl_assert(cmp > 0);
+ cl_assert_gt_i(cmp, 0);
in[1].u.idx.offset = in[0].u.idx.offset;
cl_assert(reftable_record_equal(&in[0], &in[1],
--
2.52.0.239.gd5f0c6e74e.dirty
^ permalink raw reply related [flat|nested] 19+ messages in thread
* [PATCH v2 3/3] gitattributes: disable blank-at-eof errors for clar test expectations
2025-12-06 11:47 ` [PATCH v2 0/3] Update clar for improved integer handling Patrick Steinhardt
2025-12-06 11:47 ` [PATCH v2 1/3] t/unit-tests: update clar to 39f11fe Patrick Steinhardt
2025-12-06 11:47 ` [PATCH v2 2/3] t/unit-tests: demonstrate use of integer comparison assertions Patrick Steinhardt
@ 2025-12-06 11:47 ` Patrick Steinhardt
2026-01-06 11:01 ` [PATCH v2 0/3] Update clar for improved integer handling Karthik Nayak
3 siblings, 0 replies; 19+ messages in thread
From: Patrick Steinhardt @ 2025-12-06 11:47 UTC (permalink / raw)
To: git; +Cc: Jeff King, Phillip Wood, Junio C Hamano
The clar unit testing framework carries a couple of files that contain
expected output for its self-tests. Some of these files expectedly end
with a blank line at the end of the file, which Git would consider to be
a whitespace error by default.
Teach our gitattributes to ignore those errors.
Suggested-by: Junio C Hamano <gitster@pobox.com>
Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
.gitattributes | 1 +
1 file changed, 1 insertion(+)
diff --git a/.gitattributes b/.gitattributes
index 700743c3f5..38b1c52fe0 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -17,3 +17,4 @@ CODE_OF_CONDUCT.md -whitespace
/Documentation/gitk.adoc conflict-marker-size=32
/Documentation/user-manual.adoc conflict-marker-size=32
/t/t????-*.sh conflict-marker-size=32
+/t/unit-tests/clar/test/expected/* whitespace=-blank-at-eof
--
2.52.0.239.gd5f0c6e74e.dirty
^ permalink raw reply related [flat|nested] 19+ messages in thread
* Re: [PATCH v2 1/3] t/unit-tests: update clar to 39f11fe
2025-12-06 11:47 ` [PATCH v2 1/3] t/unit-tests: update clar to 39f11fe Patrick Steinhardt
@ 2026-01-06 10:59 ` Karthik Nayak
2026-01-06 11:16 ` Patrick Steinhardt
0 siblings, 1 reply; 19+ messages in thread
From: Karthik Nayak @ 2026-01-06 10:59 UTC (permalink / raw)
To: Patrick Steinhardt, git; +Cc: Jeff King, Phillip Wood
[-- Attachment #1: Type: text/plain, Size: 6795 bytes --]
Patrick Steinhardt <ps@pks.im> writes:
> Update clar to commit 39f11fe (Merge pull request #131 from
> pks-gitlab/pks-integer-double-evaluation, 2025-12-05). This commit
> includes the following changes relevant to Git:
>
Nit: There is a newer commit merged into the clar repository, but I
don't think it is so important to include.
> - There are now typesafe integer comparison functions. Furthermore,
> the range of comparison functions has been included to also have
> relative comparisons, like "greater than".
>
> - There is a new `cl_failf()` macro that allows the caller to specify
> an error message with formatting directives.
>
> - The TAP format has been fixed to correctly terminate YAML blocks
> with "...\n" instead of "---\n".
>
> Note that we already had a `cl_failf()` function declared in our own
> sources. This function is equivalent to the upstreamed function, so we
> can simply drop it now.
>
[snip]
> @@ -149,6 +150,7 @@ const char *cl_fixture_basename(const char *fixture_name);
> * Forced failure/warning
> */
> #define cl_fail(desc) clar__fail(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Test failed.", desc, 1)
> +#define cl_failf(desc,...) clar__failf(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, "Test failed.", desc, __VA_ARGS__)
Nit: While most of the function accept description with variable
arguments, this is the only one which has the '...f()' format explicitly
separated out. It would be nicer if we simply make this part of
'cl_fail()', no?
> #define cl_warning(desc) clar__fail(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Warning during test execution:", desc, 0)
>
> #define cl_skip() clar__skip()
> @@ -168,9 +170,42 @@ const char *cl_fixture_basename(const char *fixture_name);
> #define cl_assert_equal_wcsn(wcs1,wcs2,len) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #wcs1 " != " #wcs2, 1, "%.*ls", (wcs1), (wcs2), (int)(len))
> #define cl_assert_equal_wcsn_(wcs1,wcs2,len,note) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,"String mismatch: " #wcs1 " != " #wcs2 " (" #note ")", 1, "%.*ls", (wcs1), (wcs2), (int)(len))
>
> -#define cl_assert_equal_i(i1,i2) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#i1 " != " #i2, 1, "%d", (int)(i1), (int)(i2))
> -#define cl_assert_equal_i_(i1,i2,note) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#i1 " != " #i2 " (" #note ")", 1, "%d", (i1), (i2))
> -#define cl_assert_equal_i_fmt(i1,i2,fmt) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#i1 " != " #i2, 1, (fmt), (int)(i1), (int)(i2))
> +#define cl_assert_compare_i_(i1, i2, cmp, error, ...) clar__assert_compare_i(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, cmp, \
> + (i1), (i2), "Expected comparison to hold: " error, __VA_ARGS__)
> +#define cl_assert_compare_i(i1, i2, cmp, error, fmt) do { \
> + intmax_t v1 = (i1), v2 = (i2); \
> + clar__assert_compare_i(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, cmp, \
> + v1, v2, "Expected comparison to hold: " error, fmt, v1, v2); \
> +} while (0)
So we use local variables here to avoid double evaluation of the
arguments passed. We also use 'intmax_t' since this would avoid any size
truncation. Looks good.
> +#define cl_assert_equal_i_(i1, i2, ...) cl_assert_compare_i_(i1, i2, CLAR_COMPARISON_EQ, #i1 " == " #i2, __VA_ARGS__)
> +#define cl_assert_equal_i(i1, i2) cl_assert_compare_i (i1, i2, CLAR_COMPARISON_EQ, #i1 " == " #i2, "%"PRIdMAX " != %"PRIdMAX)
> +#define cl_assert_equal_i_fmt(i1, i2, fmt) cl_assert_compare_i_(i1, i2, CLAR_COMPARISON_EQ, #i1 " == " #i2, fmt " != " fmt, (int)(i1), (int)(i2))
> +#define cl_assert_lt_i_(i1, i2, ...) cl_assert_compare_i_(i1, i2, CLAR_COMPARISON_LT, #i1 " < " #i2, __VA_ARGS__)
> +#define cl_assert_lt_i(i1, i2) cl_assert_compare_i (i1, i2, CLAR_COMPARISON_LT, #i1 " < " #i2, "%"PRIdMAX " >= %"PRIdMAX)
> +#define cl_assert_le_i_(i1, i2, ...) cl_assert_compare_i_(i1, i2, CLAR_COMPARISON_LE, #i1 " <= " #i2, __VA_ARGS__)
> +#define cl_assert_le_i(i1, i2) cl_assert_compare_i (i1, i2, CLAR_COMPARISON_LE, #i1 " <= " #i2, "%"PRIdMAX " > %"PRIdMAX)
> +#define cl_assert_gt_i_(i1, i2, ...) cl_assert_compare_i_(i1, i2, CLAR_COMPARISON_GT, #i1 " > " #i2, __VA_ARGS__)
> +#define cl_assert_gt_i(i1, i2) cl_assert_compare_i (i1, i2, CLAR_COMPARISON_GT, #i1 " > " #i2, "%"PRIdMAX " <= %"PRIdMAX)
> +#define cl_assert_ge_i_(i1, i2, ...) cl_assert_compare_i_(i1, i2, CLAR_COMPARISON_GE, #i1 " >= " #i2, __VA_ARGS__)
> +#define cl_assert_ge_i(i1, i2) cl_assert_compare_i (i1, i2, CLAR_COMPARISON_GE, #i1 " >= " #i2, "%"PRIdMAX " < %"PRIdMAX)
> +
> +#define cl_assert_compare_u_(u1, u2, cmp, error, ...) clar__assert_compare_u(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, cmp, \
> + (u1), (u2), "Expected comparison to hold: " error, __VA_ARGS__)
> +#define cl_assert_compare_u(u1, u2, cmp, error, fmt) do { \
> + uintmax_t v1 = (u1), v2 = (u2); \
> + clar__assert_compare_u(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, cmp, \
> + v1, v2, "Expected comparison to hold: " error, fmt, v1, v2); \
> +} while (0)
> +#define cl_assert_equal_u_(u1, u2, ...) cl_assert_compare_u_(u1, u2, CLAR_COMPARISON_EQ, #u1 " == " #u2, __VA_ARGS__)
> +#define cl_assert_equal_u(u1, u2) cl_assert_compare_u (u1, u2, CLAR_COMPARISON_EQ, #u1 " == " #u2, "%"PRIuMAX " != %"PRIuMAX)
> +#define cl_assert_lt_u_(u1, u2, ...) cl_assert_compare_u_(u1, u2, CLAR_COMPARISON_LT, #u1 " < " #u2, __VA_ARGS__)
> +#define cl_assert_lt_u(u1, u2) cl_assert_compare_u (u1, u2, CLAR_COMPARISON_LT, #u1 " < " #u2, "%"PRIuMAX " >= %"PRIuMAX)
> +#define cl_assert_le_u_(u1, u2, ...) cl_assert_compare_u_(u1, u2, CLAR_COMPARISON_LE, #u1 " <= " #u2, __VA_ARGS__)
> +#define cl_assert_le_u(u1, u2) cl_assert_compare_u (u1, u2, CLAR_COMPARISON_LE, #u1 " <= " #u2, "%"PRIuMAX " > %"PRIuMAX)
> +#define cl_assert_gt_u_(u1, u2, ...) cl_assert_compare_u_(u1, u2, CLAR_COMPARISON_GT, #u1 " > " #u2, __VA_ARGS__)
> +#define cl_assert_gt_u(u1, u2) cl_assert_compare_u (u1, u2, CLAR_COMPARISON_GT, #u1 " > " #u2, "%"PRIuMAX " <= %"PRIuMAX)
> +#define cl_assert_ge_u_(u1, u2, ...) cl_assert_compare_u_(u1, u2, CLAR_COMPARISON_GE, #u1 " >= " #u2, __VA_ARGS__)
> +#define cl_assert_ge_u(u1, u2) cl_assert_compare_u (u1, u2, CLAR_COMPARISON_GE, #u1 " >= " #u2, "%"PRIuMAX " < %"PRIuMAX)
>
> #define cl_assert_equal_b(b1,b2) clar__assert_equal(CLAR_CURRENT_FILE,CLAR_CURRENT_FUNC,CLAR_CURRENT_LINE,#b1 " != " #b2, 1, "%d", (int)((b1) != 0),(int)((b2) != 0))
[snip]
[1]: https://github.com/clar-test/clar/commits/main/
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 0/3] Update clar for improved integer handling
2025-12-06 11:47 ` [PATCH v2 0/3] Update clar for improved integer handling Patrick Steinhardt
` (2 preceding siblings ...)
2025-12-06 11:47 ` [PATCH v2 3/3] gitattributes: disable blank-at-eof errors for clar test expectations Patrick Steinhardt
@ 2026-01-06 11:01 ` Karthik Nayak
2026-01-06 11:16 ` Patrick Steinhardt
3 siblings, 1 reply; 19+ messages in thread
From: Karthik Nayak @ 2026-01-06 11:01 UTC (permalink / raw)
To: Patrick Steinhardt, git; +Cc: Jeff King, Phillip Wood, Junio C Hamano
[-- Attachment #1: Type: text/plain, Size: 708 bytes --]
Patrick Steinhardt <ps@pks.im> writes:
> Hi,
>
> this patch series updates clar. Most importantly, the update contains
> properly typed handling of integers as well as a set of new asserts that
> perform relative comparisons, like "less than" or "greater or equal".
>
> Thanks!
>
I went through the changes and they look good. I didn't know about
double evaluation of arguments in macros before, so that was good to
read about. Thanks
> Patrick
>
> ---
> Changes in v2:
> - EDITME: describe what is new in this series revision.
> - EDITME: use bulletpoints and terse descriptions.
> - Link to v1: https://lore.kernel.org/r/20251205-b4-pks-clar-update-v1-0-fd70aac2ab90@pks.im
>
Easter egg? :)
- Karthik
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 0/3] Update clar for improved integer handling
2026-01-06 11:01 ` [PATCH v2 0/3] Update clar for improved integer handling Karthik Nayak
@ 2026-01-06 11:16 ` Patrick Steinhardt
2026-01-07 3:53 ` Junio C Hamano
0 siblings, 1 reply; 19+ messages in thread
From: Patrick Steinhardt @ 2026-01-06 11:16 UTC (permalink / raw)
To: Karthik Nayak; +Cc: git, Jeff King, Phillip Wood, Junio C Hamano
On Tue, Jan 06, 2026 at 03:01:51AM -0800, Karthik Nayak wrote:
> Patrick Steinhardt <ps@pks.im> writes:
>
> > Hi,
> >
> > this patch series updates clar. Most importantly, the update contains
> > properly typed handling of integers as well as a set of new asserts that
> > perform relative comparisons, like "less than" or "greater or equal".
> >
> > Thanks!
> >
>
> I went through the changes and they look good. I didn't know about
> double evaluation of arguments in macros before, so that was good to
> read about. Thanks
>
> > Patrick
> >
> > ---
> > Changes in v2:
> > - EDITME: describe what is new in this series revision.
> > - EDITME: use bulletpoints and terse descriptions.
> > - Link to v1: https://lore.kernel.org/r/20251205-b4-pks-clar-update-v1-0-fd70aac2ab90@pks.im
> >
>
> Easter egg? :)
Oops :) Thanks for your review!
Patrick
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 1/3] t/unit-tests: update clar to 39f11fe
2026-01-06 10:59 ` Karthik Nayak
@ 2026-01-06 11:16 ` Patrick Steinhardt
2026-01-06 16:28 ` Karthik Nayak
2026-01-07 7:40 ` Jeff King
0 siblings, 2 replies; 19+ messages in thread
From: Patrick Steinhardt @ 2026-01-06 11:16 UTC (permalink / raw)
To: Karthik Nayak; +Cc: git, Jeff King, Phillip Wood
On Tue, Jan 06, 2026 at 02:59:21AM -0800, Karthik Nayak wrote:
> Patrick Steinhardt <ps@pks.im> writes:
>
> > Update clar to commit 39f11fe (Merge pull request #131 from
> > pks-gitlab/pks-integer-double-evaluation, 2025-12-05). This commit
> > includes the following changes relevant to Git:
> >
>
> Nit: There is a newer commit merged into the clar repository, but I
> don't think it is so important to include.
Yeah, I don't really think it's necessary. If this series needs a reroll
I'll include it, but otherwise I'll keep this series as-is.
> > @@ -149,6 +150,7 @@ const char *cl_fixture_basename(const char *fixture_name);
> > * Forced failure/warning
> > */
> > #define cl_fail(desc) clar__fail(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Test failed.", desc, 1)
> > +#define cl_failf(desc,...) clar__failf(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, "Test failed.", desc, __VA_ARGS__)
>
> Nit: While most of the function accept description with variable
> arguments, this is the only one which has the '...f()' format explicitly
> separated out. It would be nicer if we simply make this part of
> 'cl_fail()', no?
The problem is that we cannot do so easily. Varargs require at least one
argument to be present, so we cannot make this `cl_fail(desc, ...)`
without breaking the case where there are no variable arguments:
In file included from ../t/unit-tests/clar/clar.c:1053:
../t/unit-tests/clar/clar/fs.h:460:3: error: expected expression
460 | cl_fail("Cannot copy; cannot stat destination");
| ^
../t/unit-tests/clar/clar.h:152:132: note: expanded from macro 'cl_fail'
152 | #define cl_fail(desc,...) clar__failf(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, "Test failed.", desc, __VA_ARGS__)
| ^
The alternative would be to make this `cl_fail(...)` instead, but to the
best of my knowledge this isn't even a valid construct.
Patrick
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 1/3] t/unit-tests: update clar to 39f11fe
2026-01-06 11:16 ` Patrick Steinhardt
@ 2026-01-06 16:28 ` Karthik Nayak
2026-01-07 7:40 ` Jeff King
1 sibling, 0 replies; 19+ messages in thread
From: Karthik Nayak @ 2026-01-06 16:28 UTC (permalink / raw)
To: Patrick Steinhardt; +Cc: git, Jeff King, Phillip Wood
[-- Attachment #1: Type: text/plain, Size: 2242 bytes --]
Patrick Steinhardt <ps@pks.im> writes:
> On Tue, Jan 06, 2026 at 02:59:21AM -0800, Karthik Nayak wrote:
>> Patrick Steinhardt <ps@pks.im> writes:
>>
>> > Update clar to commit 39f11fe (Merge pull request #131 from
>> > pks-gitlab/pks-integer-double-evaluation, 2025-12-05). This commit
>> > includes the following changes relevant to Git:
>> >
>>
>> Nit: There is a newer commit merged into the clar repository, but I
>> don't think it is so important to include.
>
> Yeah, I don't really think it's necessary. If this series needs a reroll
> I'll include it, but otherwise I'll keep this series as-is.
>
Agreed.
>> > @@ -149,6 +150,7 @@ const char *cl_fixture_basename(const char *fixture_name);
>> > * Forced failure/warning
>> > */
>> > #define cl_fail(desc) clar__fail(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, "Test failed.", desc, 1)
>> > +#define cl_failf(desc,...) clar__failf(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, "Test failed.", desc, __VA_ARGS__)
>>
>> Nit: While most of the function accept description with variable
>> arguments, this is the only one which has the '...f()' format explicitly
>> separated out. It would be nicer if we simply make this part of
>> 'cl_fail()', no?
>
> The problem is that we cannot do so easily. Varargs require at least one
> argument to be present, so we cannot make this `cl_fail(desc, ...)`
> without breaking the case where there are no variable arguments:
>
> In file included from ../t/unit-tests/clar/clar.c:1053:
> ../t/unit-tests/clar/clar/fs.h:460:3: error: expected expression
> 460 | cl_fail("Cannot copy; cannot stat destination");
> | ^
> ../t/unit-tests/clar/clar.h:152:132: note: expanded from macro 'cl_fail'
> 152 | #define cl_fail(desc,...) clar__failf(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, "Test failed.", desc, __VA_ARGS__)
> | ^
>
> The alternative would be to make this `cl_fail(...)` instead, but to the
> best of my knowledge this isn't even a valid construct.
>
> Patrick
Ah right. Thanks for the explanation.
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 0/3] Update clar for improved integer handling
2026-01-06 11:16 ` Patrick Steinhardt
@ 2026-01-07 3:53 ` Junio C Hamano
2026-01-07 7:01 ` Patrick Steinhardt
0 siblings, 1 reply; 19+ messages in thread
From: Junio C Hamano @ 2026-01-07 3:53 UTC (permalink / raw)
To: Patrick Steinhardt; +Cc: Karthik Nayak, git, Jeff King, Phillip Wood
Patrick Steinhardt <ps@pks.im> writes:
>> > Changes in v2:
>> > - EDITME: describe what is new in this series revision.
>> > - EDITME: use bulletpoints and terse descriptions.
>> > - Link to v1: https://lore.kernel.org/r/20251205-b4-pks-clar-update-v1-0-fd70aac2ab90@pks.im
>> >
>>
>> Easter egg? :)
>
> Oops :) Thanks for your review!
Looking good. Shall we mark it for 'next'?
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 0/3] Update clar for improved integer handling
2026-01-07 3:53 ` Junio C Hamano
@ 2026-01-07 7:01 ` Patrick Steinhardt
0 siblings, 0 replies; 19+ messages in thread
From: Patrick Steinhardt @ 2026-01-07 7:01 UTC (permalink / raw)
To: Junio C Hamano; +Cc: Karthik Nayak, git, Jeff King, Phillip Wood
On Wed, Jan 07, 2026 at 12:53:38PM +0900, Junio C Hamano wrote:
> Patrick Steinhardt <ps@pks.im> writes:
>
> >> > Changes in v2:
> >> > - EDITME: describe what is new in this series revision.
> >> > - EDITME: use bulletpoints and terse descriptions.
> >> > - Link to v1: https://lore.kernel.org/r/20251205-b4-pks-clar-update-v1-0-fd70aac2ab90@pks.im
> >> >
> >>
> >> Easter egg? :)
> >
> > Oops :) Thanks for your review!
>
> Looking good. Shall we mark it for 'next'?
Yeah, I think this topic should be good to go. Thanks!
Patrick
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH v2 1/3] t/unit-tests: update clar to 39f11fe
2026-01-06 11:16 ` Patrick Steinhardt
2026-01-06 16:28 ` Karthik Nayak
@ 2026-01-07 7:40 ` Jeff King
1 sibling, 0 replies; 19+ messages in thread
From: Jeff King @ 2026-01-07 7:40 UTC (permalink / raw)
To: Patrick Steinhardt; +Cc: Karthik Nayak, git, Phillip Wood
On Tue, Jan 06, 2026 at 12:16:28PM +0100, Patrick Steinhardt wrote:
> The problem is that we cannot do so easily. Varargs require at least one
> argument to be present, so we cannot make this `cl_fail(desc, ...)`
> without breaking the case where there are no variable arguments:
>
> In file included from ../t/unit-tests/clar/clar.c:1053:
> ../t/unit-tests/clar/clar/fs.h:460:3: error: expected expression
> 460 | cl_fail("Cannot copy; cannot stat destination");
> | ^
> ../t/unit-tests/clar/clar.h:152:132: note: expanded from macro 'cl_fail'
> 152 | #define cl_fail(desc,...) clar__failf(CLAR_CURRENT_FILE, CLAR_CURRENT_FUNC, CLAR_CURRENT_LINE, 1, "Test failed.", desc, __VA_ARGS__)
> | ^
>
> The alternative would be to make this `cl_fail(...)` instead, but to the
> best of my knowledge this isn't even a valid construct.
It is valid; that's how we define BUG(), for example.
There are other options like GNU's "## __VA_ARGS__", but I think eating
the format argument with the "..." is the only portable way, at least
for standard versions we'd support. I think C23 added __VA_OPT__.
-Peff
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2026-01-07 7:40 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-05 12:57 [PATCH 0/2] Update clar for improved integer handling Patrick Steinhardt
2025-12-05 12:57 ` [PATCH 1/2] t/unit-tests: update clar to 39f11fe Patrick Steinhardt
2025-12-05 18:40 ` Jeff King
2025-12-06 11:39 ` Patrick Steinhardt
2025-12-06 5:27 ` Junio C Hamano
2025-12-06 11:46 ` Patrick Steinhardt
2025-12-05 12:57 ` [PATCH 2/2] t/unit-tests: demonstrate use of integer comparison assertions Patrick Steinhardt
2025-12-06 11:47 ` [PATCH v2 0/3] Update clar for improved integer handling Patrick Steinhardt
2025-12-06 11:47 ` [PATCH v2 1/3] t/unit-tests: update clar to 39f11fe Patrick Steinhardt
2026-01-06 10:59 ` Karthik Nayak
2026-01-06 11:16 ` Patrick Steinhardt
2026-01-06 16:28 ` Karthik Nayak
2026-01-07 7:40 ` Jeff King
2025-12-06 11:47 ` [PATCH v2 2/3] t/unit-tests: demonstrate use of integer comparison assertions Patrick Steinhardt
2025-12-06 11:47 ` [PATCH v2 3/3] gitattributes: disable blank-at-eof errors for clar test expectations Patrick Steinhardt
2026-01-06 11:01 ` [PATCH v2 0/3] Update clar for improved integer handling Karthik Nayak
2026-01-06 11:16 ` Patrick Steinhardt
2026-01-07 3:53 ` Junio C Hamano
2026-01-07 7:01 ` Patrick Steinhardt
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).