git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [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; 11+ 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] 11+ 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; 11+ 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] 11+ 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; 11+ 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] 11+ 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; 11+ 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] 11+ 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; 11+ 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] 11+ 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; 11+ 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] 11+ 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; 11+ 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] 11+ 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
                     ` (2 more replies)
  2 siblings, 3 replies; 11+ 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] 11+ 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
  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
  2 siblings, 0 replies; 11+ 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] 11+ 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
  2 siblings, 0 replies; 11+ 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] 11+ 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
  2 siblings, 0 replies; 11+ 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] 11+ messages in thread

end of thread, other threads:[~2025-12-06 11:48 UTC | newest]

Thread overview: 11+ 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
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

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).