v2-0001-Add-suite-of-macros-for-writing-TAP-tests-in-C.patch
text/x-patch
Filename: v2-0001-Add-suite-of-macros-for-writing-TAP-tests-in-C.patch
Type: text/x-patch
Part: 0
Patch
Format: format-patch
Series: patch v2-0001
Subject: Add suite of macros for writing TAP tests in C.
| File | + | − |
|---|---|---|
| src/include/lib/pg_tap.h | 138 | 0 |
From fc46ee76fa3aa0e9b24218126168db14acc8222d Mon Sep 17 00:00:00 2001
From: Thomas Munro <thomas.munro@gmail.com>
Date: Tue, 11 Oct 2022 17:26:02 +1300
Subject: [PATCH v2 01/10] Add suite of macros for writing TAP tests in C.
Historically we had to load test modules into a PostgreSQL backend or
write an ad-hoc standalone program to test C code. Let's provide a
convenient way to write stand-alone tests for low-level C code.
This commit defines a small set of macros that spit out results in TAP
format. These can be improved and extended as required.
---
src/include/lib/pg_tap.h | 138 +++++++++++++++++++++++++++++++++++++++
1 file changed, 138 insertions(+)
create mode 100644 src/include/lib/pg_tap.h
diff --git a/src/include/lib/pg_tap.h b/src/include/lib/pg_tap.h
new file mode 100644
index 0000000000..3da46ac5d5
--- /dev/null
+++ b/src/include/lib/pg_tap.h
@@ -0,0 +1,138 @@
+/*
+ * Simple macros for writing tests in C that print results in TAP format,
+ * as consumed by "prove".
+ *
+ * Specification for the output format: https://testanything.org/
+ */
+
+#ifndef PG_TAP_H
+#define PG_TAP_H
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+/* Counters are global, so we can break our tests into multiple functions. */
+static int pg_test_count;
+static int pg_fail_count;
+static int pg_todo_count;
+
+/*
+ * Require an expression to be true. Used for set-up steps that are not
+ * reported as a test.
+ */
+#define PG_REQUIRE(expr) \
+if (!(expr)) { \
+ printf("Bail out! requirement (" #expr ") failed at %s:%d\n", \
+ __FILE__, __LINE__); \
+ exit(EXIT_FAILURE); \
+}
+
+/*
+ * Like PG_REQUIRE, but log strerror(errno) before bailing.
+ */
+#define PG_REQUIRE_SYS(expr) \
+if (!(expr)) { \
+ printf("Bail out! requirement (" #expr ") failed at %s:%d, error: %s\n", \
+ __FILE__, __LINE__, strerror(errno)); \
+ exit(EXIT_FAILURE); \
+}
+
+/*
+ * Test that an expression is true. An optional message can be provided,
+ * defaulting to the expression itself if not provided.
+ */
+#define PG_EXPECT(expr, ...) \
+do { \
+ const char *messages[] = {#expr, __VA_ARGS__}; \
+ const char *message = messages[lengthof(messages) - 1]; \
+ pg_test_count++; \
+ if (expr) { \
+ printf("ok %d - %s\n", pg_test_count, message); \
+ } else { \
+ if (pg_todo_count == 0) \
+ pg_fail_count++; \
+ printf("not ok %d - %s (at %s:%d)%s\n", pg_test_count, \
+ message, __FILE__, __LINE__, \
+ pg_todo_count > 0 ? " # TODO" : ""); \
+ } \
+} while (0)
+
+/*
+ * Like PG_EXPECT(), but also log strerror(errno) on failure.
+ */
+#define PG_EXPECT_SYS(expr, ...) \
+do { \
+ const char *messages[] = {#expr, __VA_ARGS__}; \
+ const char *message = messages[lengthof(messages) - 1]; \
+ pg_test_count++; \
+ if (expr) { \
+ printf("ok %d - %s\n", pg_test_count, message); \
+ } else { \
+ if (pg_todo_count == 0) \
+ pg_fail_count++; \
+ printf("not ok %d - %s (at %s:%d), error: %s%s\n", pg_test_count, \
+ message, __FILE__, __LINE__, strerror(errno), \
+ pg_todo_count > 0 ? " # TODO" : ""); \
+ } \
+} while (0)
+
+
+/*
+ * Test that one int expression is equal to another, logging the values if not.
+ */
+#define PG_EXPECT_EQ(expr1, expr2, ...) \
+do { \
+ const char *messages[] = {#expr1 " == " #expr2, __VA_ARGS__}; \
+ const char *message = messages[lengthof(messages) - 1]; \
+ int expr1_val = (expr1); \
+ int expr2_val = (expr2); \
+ pg_test_count++; \
+ if (expr1_val == expr2_val) { \
+ printf("ok %d - %s\n", pg_test_count, message); \
+ } else { \
+ if (pg_todo_count == 0) \
+ pg_fail_count++; \
+ printf("not ok %d - %s: %d != %d (at %s:%d)%s\n", pg_test_count, \
+ message, expr1_val, expr2_val, __FILE__, __LINE__, \
+ pg_todo_count > 0 ? " # TODO" : ""); \
+ } \
+} while (0)
+
+/*
+ * Test that one C string expression is equal to another, logging the values if
+ * not.
+ */
+#define PG_EXPECT_EQ_STR(expr1, expr2, ...) \
+do { \
+ const char *messages[] = {#expr1 " matches " #expr2, __VA_ARGS__}; \
+ const char *message = messages[lengthof(messages) - 1]; \
+ const char *expr1_val = (expr1); \
+ const char *expr2_val = (expr2); \
+ pg_test_count++; \
+ if (strcmp(expr1_val, expr2_val) == 0) { \
+ printf("ok %d - %s\n", pg_test_count, message); \
+ } else { \
+ if (pg_todo_count == 0) \
+ pg_fail_count++; \
+ printf("not ok %d - %s: \"%s\" vs \"%s\" (at %s:%d) %s\n", \
+ pg_test_count, \
+ message, expr1_val, expr2_val, __FILE__, __LINE__, \
+ pg_todo_count > 0 ? " # TODO" : ""); \
+ } \
+} while (0)
+
+/*
+ * The main function of a test program should begin and end with these
+ * functions.
+ */
+#define PG_BEGIN_TESTS() \
+ setbuf(stdout, NULL); /* disable buffering for Windows */
+
+#define PG_END_TESTS() printf("1..%d\n", pg_test_count); \
+ return EXIT_SUCCESS
+
+#define PG_BEGIN_TODO() pg_todo_count++
+#define PG_END_TODO() pg_todo_count--
+
+#endif
--
2.35.1