v11-0002-Tests-of-vect-and-uniqsortvect-containers-and-of.patch
text/x-patch
Filename: v11-0002-Tests-of-vect-and-uniqsortvect-containers-and-of.patch
Type: text/x-patch
Part: 1
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v11-0002
Subject: Tests of vect and uniqsortvect containers and of bitpack algorithms.
| File | + | − |
|---|---|---|
| GNUmakefile.in | 1 | 0 |
| src/Makefile.global.in | 1 | 1 |
| src/test/dfor/.gitignore | 3 | 0 |
| src/test/dfor/Makefile | 54 | 0 |
| src/test/dfor/meson.build | 62 | 0 |
| src/test/dfor/test_bitpack_u16.c | 357 | 0 |
| src/test/dfor/test.h | 31 | 0 |
| src/test/dfor/test_uniqsortvect_u16.c | 263 | 0 |
| src/test/dfor/test_vect_u16.c | 168 | 0 |
| src/test/libtap/COPYING | 165 | 0 |
| src/test/libtap/.gitignore | 13 | 0 |
| src/test/libtap/INSTALL | 41 | 0 |
| src/test/libtap/Makefile | 73 | 0 |
| src/test/libtap/Makefile.win | 37 | 0 |
| src/test/libtap/README.md | 268 | 0 |
| src/test/libtap/tap.c | 421 | 0 |
| src/test/libtap/tap.h | 115 | 0 |
| src/test/libtap/.travis.yml | 13 | 0 |
| src/test/Makefile | 1 | 0 |
| src/test/meson.build | 1 | 0 |
From 7c1e2f16fc37302cd2816dc8f8142ff6c38583f9 Mon Sep 17 00:00:00 2001
From: Evgeny Voropaev <evorop@gmail.com>
Date: Mon, 13 Apr 2026 20:18:42 +0800
Subject: [PATCH v11 2/5] Tests of vect and uniqsortvect containers and of
bitpack algorithms.
Unit tests for the vect and the bitpack units are imlemented. Unit tests
are implemented as binary applications written in C language (ELF
executables) that support the TAP protocol and are run using the Prove
utility.
The new Makefile target, check-unit, is integrated into the PostgreSQL
build system and allows running the unit tests using the command 'make
check-unit'.
Author: Evgeny Voropaev <evgeny.voropaev@tantorlabs.com> <evorop@gmail.com>
Reviewed by: Andrey Borodin <x4mmm@yandex-team.ru>
---
GNUmakefile.in | 1 +
src/Makefile.global.in | 2 +-
src/test/Makefile | 1 +
src/test/dfor/.gitignore | 3 +
src/test/dfor/Makefile | 54 ++++
src/test/dfor/meson.build | 62 ++++
src/test/dfor/test.h | 31 ++
src/test/dfor/test_bitpack_u16.c | 357 ++++++++++++++++++++++
src/test/dfor/test_uniqsortvect_u16.c | 263 ++++++++++++++++
src/test/dfor/test_vect_u16.c | 168 ++++++++++
src/test/libtap/.gitignore | 13 +
src/test/libtap/.travis.yml | 13 +
src/test/libtap/COPYING | 165 ++++++++++
src/test/libtap/INSTALL | 41 +++
src/test/libtap/Makefile | 73 +++++
src/test/libtap/Makefile.win | 37 +++
src/test/libtap/README.md | 268 ++++++++++++++++
src/test/libtap/tap.c | 421 ++++++++++++++++++++++++++
src/test/libtap/tap.h | 115 +++++++
src/test/meson.build | 1 +
20 files changed, 2088 insertions(+), 1 deletion(-)
create mode 100644 src/test/dfor/.gitignore
create mode 100644 src/test/dfor/Makefile
create mode 100644 src/test/dfor/meson.build
create mode 100644 src/test/dfor/test.h
create mode 100644 src/test/dfor/test_bitpack_u16.c
create mode 100644 src/test/dfor/test_uniqsortvect_u16.c
create mode 100644 src/test/dfor/test_vect_u16.c
create mode 100644 src/test/libtap/.gitignore
create mode 100644 src/test/libtap/.travis.yml
create mode 100644 src/test/libtap/COPYING
create mode 100644 src/test/libtap/INSTALL
create mode 100644 src/test/libtap/Makefile
create mode 100644 src/test/libtap/Makefile.win
create mode 100644 src/test/libtap/README.md
create mode 100644 src/test/libtap/tap.c
create mode 100644 src/test/libtap/tap.h
diff --git a/GNUmakefile.in b/GNUmakefile.in
index cf6e759486e..3d9a42d6ad4 100644
--- a/GNUmakefile.in
+++ b/GNUmakefile.in
@@ -69,6 +69,7 @@ check check-tests installcheck installcheck-parallel installcheck-tests: submake
$(MAKE) -C src/test/regress $@
$(call recurse,check-world,src/test src/pl src/interfaces contrib src/bin src/tools/pg_bsd_indent,check)
+$(call recurse,check-unit,src/test,check-unit)
$(call recurse,checkprep, src/test src/pl src/interfaces contrib src/bin)
$(call recurse,installcheck-world,src/test src/pl src/interfaces contrib src/bin,installcheck)
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index cef1ad7f87d..0b6a22be18b 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -19,7 +19,7 @@
#
# Meta configuration
-standard_targets = all install installdirs uninstall clean distclean coverage check checkprep installcheck init-po update-po
+standard_targets = all install installdirs uninstall clean distclean coverage check checkprep installcheck check-unit init-po update-po
# these targets should recurse even into subdirectories not being built:
standard_always_targets = clean distclean
diff --git a/src/test/Makefile b/src/test/Makefile
index 3eb0a06abb4..aba8db1f483 100644
--- a/src/test/Makefile
+++ b/src/test/Makefile
@@ -14,6 +14,7 @@ include $(top_builddir)/src/Makefile.global
SUBDIRS = \
authentication \
+ dfor \
isolation \
modules \
perl \
diff --git a/src/test/dfor/.gitignore b/src/test/dfor/.gitignore
new file mode 100644
index 00000000000..0d77a51216b
--- /dev/null
+++ b/src/test/dfor/.gitignore
@@ -0,0 +1,3 @@
+test_bitpack_u16
+test_uniqsortvect_u16
+test_vect_u16
diff --git a/src/test/dfor/Makefile b/src/test/dfor/Makefile
new file mode 100644
index 00000000000..4fc9f4bc1ba
--- /dev/null
+++ b/src/test/dfor/Makefile
@@ -0,0 +1,54 @@
+#-------------------------------------------------------------------------
+# File: src/test/dfor/Makefile
+#-------------------------------------------------------------------------
+
+subdir = src/test/dfor
+top_builddir = ../../..
+dfor_dir := $(top_builddir)/src/backend/lib
+
+include $(dfor_dir)/Makefile.dfor
+
+# Ensure dependency tracking works
+OBJS += $(OBJS_DFOR)
+
+include $(top_builddir)/src/Makefile.global
+
+# This fixes a problem in some CI jobs
+DEPDIR ?= ".deps"
+
+# Object files of vect, bitpack and dfor used by these unit-tests are in the same
+# directory as this Makefile. Tests don't use ones from src/backend/lib and compile
+# different ones for themselves.
+$(info Use OBJS_DFOR=$(OBJS_DFOR) from current directory $(subdir). \
+ They are built on sources from $(dfor_dir))
+
+$(OBJS_DFOR): %.o: $(dfor_dir)/%.c
+ @if test ! -d $(DEPDIR); then mkdir -p $(DEPDIR); fi
+ $(CC) $(CFLAGS) $(CPPFLAGS) -DFRONTEND \
+ -c $< \
+ -MMD -MP -MF $(DEPDIR)/$(notdir $<:.c=.Po) \
+ -o $@
+
+LIBTAP_OBJS = $(top_builddir)/src/test/libtap/tap.o
+
+TESTS= test_vect_u16 \
+ test_uniqsortvect_u16 \
+ test_bitpack_u16
+
+$(TESTS:%=%.o): CPPFLAGS += -I$(top_builddir)/src/test -DFRONTEND
+
+all: $(TESTS)
+
+$(TESTS): %: %.o $(LIBTAP_OBJS) $(OBJS_DFOR)
+ $(CC) $(CFLAGS) $(CPPFLAGS) $^ $(LDFLAGS) $(LIBS) -o $@$(X)
+
+check-unit: $(TESTS)
+ echo "# +++ Unit tests in $(subdir) +++" && \
+ cd $(top_builddir)/$(subdir) && \
+ $(PROVE) $(PROVE_FLAGS) \
+ -v $(addprefix ./,$(if $(PROVE_TESTS), $(PROVE_TESTS), $(TESTS)))
+
+check: check-unit
+
+clean distclean:
+ rm -rf $(TESTS) *.o
diff --git a/src/test/dfor/meson.build b/src/test/dfor/meson.build
new file mode 100644
index 00000000000..ce762c52430
--- /dev/null
+++ b/src/test/dfor/meson.build
@@ -0,0 +1,62 @@
+dfor_dir = join_paths(meson.project_source_root(), 'src/backend/lib')
+
+# Object files of vect, bitpack and dfor used by these unit-tests are in the same
+# directory as this meson.build. Tests don't use ones from src/backend/lib and
+# compile different ones for themselves. In Meson/Ninja build system we unite
+# them into a static library.
+
+dfor_sources = files(
+ join_paths(dfor_dir, 'vect_u16.c'),
+ join_paths(dfor_dir, 'bitpack_u16.c'),
+)
+
+dfor_test_lib = static_library(
+ 'dfor_test_lib',
+ dfor_sources,
+ include_directories: [
+ include_directories('../../..'), # top_builddir
+ include_directories('../'), # src/test
+ postgres_inc, # src/include here
+ ],
+ c_args: ['-DFRONTEND'],
+)
+
+# We also build libtap as a static library
+
+libtap = static_library(
+ 'tap',
+ '../../test/libtap/tap.c',
+ include_directories:
+ include_directories('../../..'), # top_builddir
+)
+
+# Each test is an ELF executable
+
+test_names = [
+ 'test_vect_u16',
+ 'test_uniqsortvect_u16',
+ 'test_bitpack_u16',
+]
+
+foreach t : test_names
+ exe = executable(
+ t,
+ t + '.c',
+ link_with: [
+ dfor_test_lib,
+ libtap,
+ common_static, # Provides pg_printf and other common utilities
+ pgport_static, # Provides OS-portability functions
+ ],
+ dependencies: [os_deps, libintl],
+ include_directories: [
+ include_directories('../../..'), # top_builddir
+ include_directories('../'), # src/test
+ postgres_inc, # src/include here
+ ],
+ # Backend code often requires these arguments to identify as backend
+ c_args: ['-DFRONTEND'],
+ )
+
+ test(t, exe, suite: 'dfor')
+endforeach
diff --git a/src/test/dfor/test.h b/src/test/dfor/test.h
new file mode 100644
index 00000000000..f6c54aad95f
--- /dev/null
+++ b/src/test/dfor/test.h
@@ -0,0 +1,31 @@
+
+/*
+ * test.h
+ */
+#ifndef _TEST_H_
+#define _TEST_H_
+
+#include <inttypes.h>
+#include <stdio.h>
+
+static inline void
+test_print_u8_array(size_t cnt, uint8_t arr[], const char *name)
+{
+ printf("%s(hex): { ", name);
+ for (size_t j = 0; j < cnt - 1; j++)
+ printf("%02" PRIx8 ", ", arr[j]);
+
+ printf("%02" PRIx8 " }\n", arr[cnt - 1]);
+}
+
+static inline void
+test_print_u16_array(size_t cnt, uint16_t arr[], const char *name)
+{
+ printf("%s(hex): { ", name);
+ for (size_t j = 0; j < cnt - 1; j++)
+ printf("%04" PRIx16 ", ", arr[j]);
+
+ printf("%04" PRIx16 "}\n", arr[cnt - 1]);
+}
+
+#endif /* _TEST_H_ */
\ No newline at end of file
diff --git a/src/test/dfor/test_bitpack_u16.c b/src/test/dfor/test_bitpack_u16.c
new file mode 100644
index 00000000000..da84bb2f22e
--- /dev/null
+++ b/src/test/dfor/test_bitpack_u16.c
@@ -0,0 +1,357 @@
+/*
+ * test_bitpack.c
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "lib/bitpack_u16.h"
+#include "lib/vect_u16.h"
+#include "libtap/tap.h"
+
+int
+main(void)
+{
+ plan(195);
+ printf("========================================\n");
+ printf("Test MASK AND WIDTH CALCULATION\n");
+ {
+ cmp_ok(1, "==", (uint16_t)width_u16_from_val(0x00),
+ "Width of 00 is equal to 1 bit.");
+ cmp_ok(2, "==", (uint16_t)width_u16_from_val(0x02),
+ "Width of 02 is equal to 2 bits.");
+ cmp_ok(2, "==", (uint16_t)width_u16_from_val(0x02),
+ "Width of 02 is equal to 2 bits.");
+ cmp_ok(2, "==", (uint16_t)width_u16_from_val(0x03),
+ "Width of 03 is equal to 2 bits.");
+ cmp_ok(3, "==", (uint16_t)width_u16_from_val(0x04),
+ "Width of 04 is equal to 3 bits.");
+ cmp_ok(3, "==", (uint16_t)width_u16_from_val(0x05),
+ "Width of 05 is equal to 3 bits.");
+ cmp_ok(4, "==", (uint16_t)width_u16_from_val(0x08),
+ "Width of 08 is equal to 4 bits.");
+ cmp_ok(4, "==", (uint16_t)width_u16_from_val(0x0A),
+ "Width of 10 is equal to 4 bits.");
+ cmp_ok(4, "==", (uint16_t)width_u16_from_val(0x0F),
+ "Width of 15 is equal to 4 bits.");
+ cmp_ok(5, "==", (uint16_t)width_u16_from_val(0x10),
+ "Width of 16 is equal to 5 bits.");
+ cmp_ok(5, "==", (uint16_t)width_u16_from_val(0x1F),
+ "Width of 31 is equal to 5 bits.");
+ cmp_ok(6, "==", (uint16_t)width_u16_from_val(0x20),
+ "Width of 32 is equal to 6 bits.");
+ cmp_ok(7, "==", (uint16_t)width_u16_from_val(0x40),
+ "Width of 64 is equal to 7 bits.");
+ cmp_ok(8, "==", (uint16_t)width_u16_from_val(0x80),
+ "Width of 128 is equal to 8 bits.");
+ cmp_ok(13, "==", (uint16_t)width_u16_from_val(0x1000),
+ "Width of 0x01000 is equal to 13 bits.");
+ cmp_ok(16, "==", (uint16_t)width_u16_from_val(0x8ABC),
+ "Width of 0x08ABC is equal to 15 bits.");
+
+ cmp_ok(0x1, "==", (uint16_t)width_u16_to_mask(1),
+ "Mask from width 1 is 00000001(bin).");
+ cmp_ok(0x3, "==", (uint16_t)width_u16_to_mask(2),
+ "Mask from width 2 is 00000011(bin).");
+ cmp_ok(0x7, "==", (uint16_t)width_u16_to_mask(3),
+ "Mask from width 3 is 00000111(bin).");
+ cmp_ok(0x3FF, "==", (uint16_t)width_u16_to_mask(10),
+ "Mask from width 10 is 0x3FF(bin).");
+ cmp_ok(0x7FFF, "==", (uint16_t)width_u16_to_mask(15),
+ "Mask from width 15 is 0x7FFF(bin).");
+ cmp_ok(0xFFFF, "==", (uint16_t)width_u16_to_mask(16),
+ "Mask from width 16 is 0xFFFF(bin).");
+ }
+ printf("Test MASK AND WIDTH CALCULATION PASSED\n");
+ printf("========================================\n\n");
+
+ printf("========================================\n");
+ printf("Test BITPACK PACKING\n");
+ {
+#define SIZEOFPACK 60U
+ uint8_t pack[SIZEOFPACK];
+ size_t caret = 0;
+ memset(pack, 0, SIZEOFPACK);
+ /*
+ * Since we implemented the nulifying of bits according to a mask (see
+ * the bitpack function), we can use even a pack not prepared in advance
+ * and comprising garbage. But we want to check value of each byte of
+ * the pack in this test and we simplify this task by using a zeroed
+ * pack.
+ */
+
+ for (int j = 0; j < 8; j++) {
+ caret = bitpack_u16_pack(pack, caret, 1, 1);
+ caret = bitpack_u16_pack(pack, caret, 0, 1);
+ }
+ cmp_ok(16, "==", caret, "Caret = 16.");
+ cmp_ok(0x55, "==", pack[0], "Saved bit-by-bit: first byte is 0x55.");
+ cmp_ok(0x55, "==", pack[1], "Saved bit-by-bit: second byte is 0x55.");
+
+ for (int j = 0; j < 8; j++) {
+ caret = bitpack_u16_pack(pack, caret, 0x02 /* 10(bin) */, 2);
+ }
+
+ cmp_ok(32, "==", caret, "Caret = 32.");
+ cmp_ok(0xAA, "==", pack[2],
+ "Saved with two-bit width: first byte is 0xAA.");
+ cmp_ok(0xAA, "==", pack[3],
+ "Saved with two-bit width: second byte is 0xAA.");
+
+ for (int j = 0; j < 8; j++) {
+ caret = bitpack_u16_pack(pack, caret, 0x05 /* 101(bin) */, 3);
+ caret = bitpack_u16_pack(pack, caret, 0x02 /* 010(bin) */, 3);
+ }
+
+ cmp_ok(80, "==", caret, "Caret = 80.");
+ cmp_ok(0x55, "==", pack[4],
+ "Saved with three-bit width: first byte is 0x55.");
+ cmp_ok(0x55, "==", pack[5],
+ "Saved with three-bit width: second byte is 0x55.");
+ cmp_ok(0x55, "==", pack[6],
+ "Saved with three-bit width: second byte is 0x55.");
+ cmp_ok(0x55, "==", pack[7],
+ "Saved with three-bit width: first byte is 0x55.");
+ cmp_ok(0x55, "==", pack[8],
+ "Saved with three-bit width: second byte is 0x55.");
+ cmp_ok(0x55, "==", pack[9],
+ "Saved with three-bit width: second byte is 0x55.");
+
+ caret = bitpack_u16_pack(pack, caret, 0x0B, 4);
+ caret = bitpack_u16_pack(pack, caret, 0x0C, 4);
+ caret = bitpack_u16_pack(pack, caret, 0x0D, 4);
+ caret = bitpack_u16_pack(pack, caret, 0x0E, 4);
+
+ cmp_ok(96, "==", caret, "Caret = 96.");
+ cmp_ok(0xCB, "==", pack[10],
+ "Saved with four-bit width: first byte is 0xCB.");
+ cmp_ok(0xED, "==", pack[11],
+ "Saved with four-bit width: second byte is 0xED.");
+
+ for (int j = 0; j < 8; j++) {
+ caret = bitpack_u16_pack(pack, caret, 0x07 /* 00111b */, 5);
+ }
+
+ cmp_ok(136, "==", caret, "Caret = 136.");
+ cmp_ok(0xE7, "==", pack[12],
+ "Saved with five-bit width: first byte is 0xE7.");
+ cmp_ok(0x9C, "==", pack[13],
+ "Saved with five-bit width: second byte is 0x9C.");
+ cmp_ok(0x73, "==", pack[14],
+ "Saved with five-bit width: third byte is 0x73.");
+ cmp_ok(0xCE, "==", pack[15],
+ "Saved with five-bit width: fourth byte is 0xCE.");
+ cmp_ok(0x39, "==", pack[16],
+ "Saved with five-bit width: fifth byte is 0x39.");
+
+ for (int j = 0; j < 4; j++)
+ caret = bitpack_u16_pack(pack, caret, 0x07 /* 000111b */, 6);
+
+ cmp_ok(160, "==", caret, "Caret = 160.");
+ cmp_ok(0xC7, "==", pack[17],
+ "Saved with six-bit width: first byte is 0xC7.");
+ cmp_ok(0x71, "==", pack[18],
+ "Saved with six-bit width: second byte is 0x71.");
+ cmp_ok(0x1C, "==", pack[19],
+ "Saved with six-bit width: third byte is 0x1C.");
+
+ for (int j = 0; j < 8; j++)
+ caret = bitpack_u16_pack(pack, caret, 0x57 /* 1010111b */, 7);
+
+ cmp_ok(216, "==", caret, "Caret = 216.");
+ cmp_ok(0xD7, "==", pack[20],
+ "Saved with seven-bit width: byte1 is 0xD7.");
+ cmp_ok(0xEB, "==", pack[21],
+ "Saved with seven-bit width: byte2 is 0xEB.");
+ cmp_ok(0xF5, "==", pack[22],
+ "Saved with seven-bit width: byte3 is 0xF5.");
+ cmp_ok(0x7A, "==", pack[23],
+ "Saved with seven-bit width: byte4 is 0x7A.");
+ cmp_ok(0xBD, "==", pack[24],
+ "Saved with seven-bit width: byte5 is 0xBD.");
+ cmp_ok(0x5E, "==", pack[25],
+ "Saved with seven-bit width: byte6 is 0x5E.");
+ cmp_ok(0xAF, "==", pack[26],
+ "Saved with seven-bit width: byte7 is 0xAF.");
+
+ caret = bitpack_u16_pack(pack, caret, 0xBA, 8);
+ caret = bitpack_u16_pack(pack, caret, 0xDC, 8);
+ caret = bitpack_u16_pack(pack, caret, 0xFE, 8);
+
+ cmp_ok(240, "==", caret, "Caret = 240.");
+ cmp_ok(0xBA, "==", pack[27],
+ "Saved with eight-bit width: byte1 is 0xBA.");
+ cmp_ok(0xDC, "==", pack[28],
+ "Saved with eight-bit width: byte2 is 0xDC.");
+ cmp_ok(0xFE, "==", pack[29],
+ "Saved with eight-bit width: byte3 is 0xFE.");
+
+ caret = bitpack_u16_pack(
+ pack, caret, 0x00,
+ 4); /* move to 4 bit for fun and again continue with 8-bit width */
+ caret = bitpack_u16_pack(pack, caret, 0x32, 8);
+ caret = bitpack_u16_pack(pack, caret, 0x54, 8);
+ caret = bitpack_u16_pack(pack, caret, 0x76, 8);
+ caret = bitpack_u16_pack(pack, caret, 0x98, 8);
+
+ cmp_ok(276, "==", caret, "Caret = 276.");
+ cmp_ok(0x20, "==", pack[30],
+ "Saved with eight-bit width but shifted by 4: is 0x20.");
+ cmp_ok(0x43, "==", pack[31],
+ "Saved with eight-bit width but shifted by 4: is 0x43.");
+ cmp_ok(0x65, "==", pack[32],
+ "Saved with eight-bit width but shifted by 4: is 0x65.");
+ cmp_ok(0x87, "==", pack[33],
+ "Saved with eight-bit width but shifted by 4: is 0x87.");
+ cmp_ok(0x09, "==", pack[34],
+ "Saved with eight-bit width but shifted by 4: is 0x09.");
+
+ caret = bitpack_u16_pack(
+ pack, caret, 0x00,
+ 4); /* move to 4 bit for fun and again continue with 8-bit width */
+ cmp_ok(280, "==", caret, "Caret = 280.");
+ cmp_ok(0x09, "==", pack[34],
+ "Added padding 0x0, width=4. Byte in pack is still 0x09.");
+
+ for (int j = 0; j < 3; j++)
+ caret = bitpack_u16_pack(pack, caret, 0x1671 /* 1011001110001b */,
+ 13);
+
+ cmp_ok(319, "==", caret, "Caret = 319.");
+ cmp_ok(0x71, "==", pack[35], "Saved with thirteen-bit width: is 0x71.");
+ cmp_ok(0x36, "==", pack[36], "Saved with thirteen-bit width: is 0x36.");
+ cmp_ok(0xCE, "==", pack[37], "Saved with thirteen-bit width: is 0xCE.");
+ cmp_ok(0xC6, "==", pack[38], "Saved with thirteen-bit width: is 0xC6.");
+ cmp_ok(0x59, "==", pack[39], "Saved with thirteen-bit width: is 0x59.");
+
+ caret = bitpack_u16_pack(pack, caret, 0x1 /* PADDING */, 1);
+ cmp_ok(320, "==", caret, "Caret = 320.");
+ cmp_ok(0xD9, "==", pack[39],
+ "After padding with 0x01, w=1: 0x59 -> 0xD9.");
+
+ for (int j = 0; j < 5; j++)
+ caret = bitpack_u16_pack(pack, caret, 0xCDEF, 16);
+
+ cmp_ok(400, "==", caret, "Caret = 400.");
+ for (int i = 40; i < 50;) {
+ cmp_ok(0xEF, "==", pack[i++], "Packed with width=16. 0xEF.");
+ cmp_ok(0xCD, "==", pack[i++], "Packed with width=16. 0xC.");
+ }
+
+ caret = bitpack_u16_pack(pack, caret,
+ 0x0 /* PADDING in order to shift by 1 bit*/,
+ 1);
+ cmp_ok(401, "==", caret, "Caret = 401.");
+
+ for (int j = 0; j < 3; j++)
+ caret = bitpack_u16_pack(pack, caret, 0x5555, 16);
+
+ cmp_ok(449, "==", caret, "Caret = 401.");
+ for (int i = 50; i < 56;)
+ cmp_ok(0xAA, "==", pack[i++],
+ "16-bit value saved with shift by 1 bit 0x55->0xAA.");
+
+ cmp_ok(0x0, "==", pack[56], "1 higher bit is alone .");
+
+ printf("Test BITPACK PACKING PASSED\n");
+ printf("========================================\n\n");
+
+ printf("========================================\n");
+ printf("Test BITPACK UNPACKING\n");
+
+ caret = 0;
+
+ for (int j = 0; j < 8; j++) {
+ cmp_ok(0x01, "==", bitpack_u16_unpack(pack, &caret, 1));
+ cmp_ok(0x00, "==", bitpack_u16_unpack(pack, &caret, 1));
+ }
+ cmp_ok(caret, "==", 16);
+
+ for (int j = 0; j < 8; j++)
+ cmp_ok(0x02, "==", bitpack_u16_unpack(pack, &caret, 2));
+
+ cmp_ok(32, "==", caret, "Caret = 32.");
+
+ for (int j = 0; j < 8; j++) {
+ cmp_ok(0x05, "==", bitpack_u16_unpack(pack, &caret, 3));
+ cmp_ok(0x02, "==", bitpack_u16_unpack(pack, &caret, 3));
+ }
+ cmp_ok(80, "==", caret, "Caret = 80.");
+
+ cmp_ok(0x0B, "==", bitpack_u16_unpack(pack, &caret, 4));
+ cmp_ok(0x0C, "==", bitpack_u16_unpack(pack, &caret, 4));
+ cmp_ok(0x0D, "==", bitpack_u16_unpack(pack, &caret, 4));
+ cmp_ok(0x0E, "==", bitpack_u16_unpack(pack, &caret, 4));
+
+ cmp_ok(96, "==", caret, "Caret = 96.");
+
+ for (int j = 0; j < 8; j++)
+ cmp_ok(0x07, "==", bitpack_u16_unpack(pack, &caret, 5),
+ "width=5, val=00111b");
+
+ cmp_ok(136, "==", caret, "Caret = 136.");
+
+ for (int j = 0; j < 4; j++)
+ cmp_ok(0x07, "==", bitpack_u16_unpack(pack, &caret, 6),
+ "width=6, val=000111b");
+
+ cmp_ok(160, "==", caret, "Caret = 160.");
+
+ for (int j = 0; j < 8; j++)
+ cmp_ok(0x57, "==", bitpack_u16_unpack(pack, &caret, 7),
+ "width=7, val=1010111b (0x57)");
+
+ cmp_ok(216, "==", caret, "Caret = 216.");
+
+ cmp_ok(0xBA, "==", bitpack_u16_unpack(pack, &caret, 8),
+ "width=8, val=0xBA");
+ cmp_ok(0xDC, "==", bitpack_u16_unpack(pack, &caret, 8),
+ "width=8, val=0xDC");
+ cmp_ok(0xFE, "==", bitpack_u16_unpack(pack, &caret, 8),
+ "width=8, val=0xFE");
+
+ cmp_ok(240, "==", caret, "Caret = 240.");
+
+ cmp_ok(0x0, "==", bitpack_u16_unpack(pack, &caret, 4),
+ "width=4, val=0x0, for fun");
+
+ cmp_ok(0x32, "==", bitpack_u16_unpack(pack, &caret, 8),
+ "width=8, val=0x32");
+ cmp_ok(0x54, "==", bitpack_u16_unpack(pack, &caret, 8),
+ "width=8, val=0x54");
+ cmp_ok(0x76, "==", bitpack_u16_unpack(pack, &caret, 8),
+ "width=8, val=0x76");
+ cmp_ok(0x98, "==", bitpack_u16_unpack(pack, &caret, 8),
+ "width=8, val=0x98");
+
+ cmp_ok(0x0, "==", bitpack_u16_unpack(pack, &caret, 4),
+ "width=4, val=0x0, for fun padding again");
+
+ for (int j = 0; j < 3; j++)
+ cmp_ok(0x1671, "==", bitpack_u16_unpack(pack, &caret, 13),
+ "width=13, val=0x1671 (1011001110001b)");
+
+ cmp_ok(319, "==", caret, "Caret = 319.");
+
+ cmp_ok(0x1, "==", bitpack_u16_unpack(pack, &caret, 1),
+ "width=1, val=0x1");
+ cmp_ok(320, "==", caret, "Caret = 320.");
+
+ for (int j = 0; j < 5; j++)
+ cmp_ok(0xCDEF, "==", bitpack_u16_unpack(pack, &caret, 16),
+ "18-bit value alligned with bytes in pack.");
+
+ cmp_ok(400, "==", caret, "Caret = 400.");
+ cmp_ok(0x0, "==", bitpack_u16_unpack(pack, &caret, 1),
+ "1-bit width value (padding for shift).");
+ cmp_ok(401, "==", caret, "Caret = 401.");
+
+ for (int j = 0; j < 3; j++)
+ cmp_ok(0x5555, "==", bitpack_u16_unpack(pack, &caret, 16),
+ "16-bit width value shifted by 1 bit.");
+
+ cmp_ok(449, "==", caret, "Caret = 449.");
+ }
+
+ done_testing();
+}
diff --git a/src/test/dfor/test_uniqsortvect_u16.c b/src/test/dfor/test_uniqsortvect_u16.c
new file mode 100644
index 00000000000..4ddce8b0b3d
--- /dev/null
+++ b/src/test/dfor/test_uniqsortvect_u16.c
@@ -0,0 +1,263 @@
+/*
+ * test_uniqsortvect.c
+ */
+
+#include "lib/vect_u16.h"
+#include "libtap/tap.h"
+
+int test_usv(size_t src_cnt, uint16_t *src_in, size_t expected_cnt,
+ uint16_t *expected_in);
+
+int
+test_usv(size_t src_cnt, uint16_t *src_in, size_t expected_cnt,
+ uint16_t *expected_in)
+{
+ int result = -1;
+ vect_u16_t src;
+ vect_u16_t expected;
+ uniqsortvect_u16_t x;
+
+ vect_u16_init(&src, src_cnt, NULL);
+ vect_u16_fill(&src, src_cnt, src_in);
+
+ vect_u16_init(&expected, 0, NULL);
+ vect_u16_fill(&expected, expected_cnt, expected_in);
+
+ vect_u16_init(&x, 0, NULL);
+
+ for (size_t i = 0; i < src_cnt; i++)
+ usv_u16_insert(&x, src.m[i]);
+
+ result = vect_u16_compare(&x, &expected);
+
+ vect_u16_clear(&x);
+ vect_u16_clear(&expected);
+ vect_u16_clear(&src);
+ return result;
+}
+
+int
+main(void)
+{
+ plan(56);
+
+ printf("========================================\n");
+ printf("Test CREATE AND DESTROY SORTED UNIQUE VECTOR (EMPTY)\n");
+ {
+ uniqsortvect_u16_t usv;
+ size_t capacity = 10;
+ vect_u16_init(&usv, capacity, NULL);
+ cmp_ok(usv.cap, "==", capacity,
+ "Vectors capacity is equal to requested one");
+ cmp_ok(usv.cnt, "==", 0, "No members in vector");
+ ok(usv.m != NULL, "Array for members is reserved");
+
+ vect_u16_clear(&usv);
+ }
+ printf("Test CREATE AND DESTROY SORTED UNIQUE VECTOR (EMPTY) PASSED\n");
+ printf("========================================\n\n");
+
+ printf("========================================\n");
+ printf("Test SEARCH IN UNIQUE SORT VECT\n");
+ {
+ uniqsortvect_u16_t usv;
+ usv_srch_res_t srch;
+ uint16_t input[4] = { 5, 10, 20, 30 };
+
+ vect_u16_init(&usv, 0, NULL);
+
+ for (size_t i = 0; i < 4; i++)
+ usv_u16_insert(&usv, input[i]);
+
+ srch = usv_u16_search(&usv, 0);
+ cmp_ok(srch.st, "==", USV_SRCH_NOT_FOUND_SMALLEST,
+ "Not found, smallest");
+ cmp_ok(srch.pos, "==", 0, "Pos =0");
+
+ srch = usv_u16_search(&usv, 1);
+ cmp_ok(srch.st, "==", USV_SRCH_NOT_FOUND_SMALLEST,
+ "Not found, smallest");
+ cmp_ok(srch.pos, "==", 0, "Pos =0");
+
+ srch = usv_u16_search(&usv, 5);
+ cmp_ok(srch.st, "==", USV_SRCH_FOUND, "Found");
+ cmp_ok(srch.pos, "==", 0, "Pos =0");
+
+ srch = usv_u16_search(&usv, 6);
+ cmp_ok(srch.st, "==", USV_SRCH_NOT_FOUND, "Not found");
+ cmp_ok(srch.pos, "==", 1, "Pos =1");
+
+ srch = usv_u16_search(&usv, 10);
+ cmp_ok(srch.st, "==", USV_SRCH_FOUND, "Found");
+ cmp_ok(srch.pos, "==", 1, "Pos =1");
+
+ srch = usv_u16_search(&usv, 15);
+ cmp_ok(srch.st, "==", USV_SRCH_NOT_FOUND, "Not found");
+ cmp_ok(srch.pos, "==", 2, "Pos =2");
+
+ srch = usv_u16_search(&usv, 20);
+ cmp_ok(srch.st, "==", USV_SRCH_FOUND, "Found");
+ cmp_ok(srch.pos, "==", 2, "Pos =2");
+
+ srch = usv_u16_search(&usv, 25);
+ cmp_ok(srch.st, "==", USV_SRCH_NOT_FOUND, "Not found");
+ cmp_ok(srch.pos, "==", 3, "Pos =3");
+
+ srch = usv_u16_search(&usv, 30);
+ cmp_ok(srch.st, "==", USV_SRCH_FOUND, "Found");
+ cmp_ok(srch.pos, "==", 3, "Pos =2");
+
+ srch = usv_u16_search(&usv, 45);
+ cmp_ok(srch.st, "==", USV_SRCH_NOT_FOUND_LARGEST, "Not found, largest");
+ cmp_ok(srch.pos, "==", 3, "Pos =3");
+
+ vect_u16_clear(&usv);
+ }
+ {
+ uniqsortvect_u16_t usv;
+ usv_srch_res_t srch;
+ uint16_t input[3] = { 5, 10, 20 };
+ uint16_t buf[3]; /* overindulge in testing the outer memory vector */
+
+ vect_u16_init(&usv, 3, buf);
+
+ for (size_t i = 0; i < 3; i++)
+ usv_u16_insert(&usv, input[i]);
+
+ srch = usv_u16_search(&usv, 0);
+ cmp_ok(srch.st, "==", USV_SRCH_NOT_FOUND_SMALLEST,
+ "Not found, smallest");
+ cmp_ok(srch.pos, "==", 0, "Pos =0");
+
+ srch = usv_u16_search(&usv, 5);
+ cmp_ok(srch.st, "==", USV_SRCH_FOUND, "Found");
+ cmp_ok(srch.pos, "==", 0, "Pos =0");
+
+ srch = usv_u16_search(&usv, 6);
+ cmp_ok(srch.st, "==", USV_SRCH_NOT_FOUND, "Not found");
+ cmp_ok(srch.pos, "==", 1, "Pos =1");
+
+ srch = usv_u16_search(&usv, 10);
+ cmp_ok(srch.st, "==", USV_SRCH_FOUND, "Found");
+ cmp_ok(srch.pos, "==", 1, "Pos =1");
+
+ srch = usv_u16_search(&usv, 15);
+ cmp_ok(srch.st, "==", USV_SRCH_NOT_FOUND, "Not found");
+ cmp_ok(srch.pos, "==", 2, "Pos =2");
+
+ /*
+ * When scopes l and g are neighbours (g-l=1) but
+ * val==m[g] instead of val==m[l].
+ */
+ srch = usv_u16_search(&usv, 20);
+ cmp_ok(srch.st, "==", USV_SRCH_FOUND, "Found");
+ cmp_ok(srch.pos, "==", 2, "Pos =2");
+
+ srch = usv_u16_search(&usv, 21);
+ cmp_ok(srch.st, "==", USV_SRCH_NOT_FOUND_LARGEST, "Not found, largest");
+ cmp_ok(srch.pos, "==", 2, "Pos =2");
+
+ vect_u16_clear(&usv);
+ }
+ { /* single member*/
+
+ uniqsortvect_u16_t usv;
+ usv_srch_res_t srch;
+
+ vect_u16_init(&usv, 3, NULL);
+
+ usv_u16_insert(&usv, 5); /* The only item in list is 5 */
+
+ srch = usv_u16_search(&usv, 0);
+ cmp_ok(srch.st, "==", USV_SRCH_NOT_FOUND_SMALLEST,
+ "Not found, smallest");
+ cmp_ok(srch.pos, "==", 0, "Pos =0");
+
+ srch = usv_u16_search(&usv, 5);
+ cmp_ok(srch.st, "==", USV_SRCH_FOUND, "Found");
+ cmp_ok(srch.pos, "==", 0, "Pos =0");
+
+ srch = usv_u16_search(&usv, 6);
+ cmp_ok(srch.st, "==", USV_SRCH_NOT_FOUND_LARGEST, "Not found, largest");
+ cmp_ok(srch.pos, "==", 0, "Pos =2");
+
+ vect_u16_clear(&usv);
+ }
+ { /* empty vector*/
+
+ uniqsortvect_u16_t usv;
+ usv_srch_res_t srch;
+
+ vect_u16_init(&usv, 1, NULL);
+
+ srch = usv_u16_search(&usv, 0);
+ cmp_ok(srch.st, "==", USV_SRCH_EMPTY, "Vector is empty.");
+ cmp_ok(srch.pos, "==", 0, "Pos =0");
+
+ srch = usv_u16_search(&usv, 4);
+ cmp_ok(srch.st, "==", USV_SRCH_EMPTY, "Vector is empty.");
+ cmp_ok(srch.pos, "==", 0, "Pos =0");
+
+ srch = usv_u16_search(&usv, 5);
+ cmp_ok(srch.st, "==", USV_SRCH_EMPTY, "Vector is empty.");
+ cmp_ok(srch.pos, "==", 0, "Pos =0");
+
+ srch = usv_u16_search(&usv, 6);
+ cmp_ok(srch.st, "==", USV_SRCH_EMPTY, "Vector is empty.");
+ cmp_ok(srch.pos, "==", 0, "Pos =0");
+
+ vect_u16_clear(&usv);
+ }
+ printf("Test SEARCH IN UNIQUE SORT VECT PASSED.\n");
+ printf("========================================\n\n");
+
+ printf("========================================\n");
+ printf("Test ERROR ON NO VECTOR FOR SEARCHING\n");
+ {
+ usv_srch_res_t srch;
+ srch = usv_u16_search(NULL, 0);
+ cmp_ok(srch.st, "==", USV_SRCH_ERROR,
+ "Error: no vector (empty pointer on vectror).");
+ }
+ {
+ uniqsortvect_u16_t usv;
+ usv_srch_res_t srch;
+ vect_u16_init(&usv, 0, NULL);
+
+ srch = usv_u16_search(&usv, 0);
+ cmp_ok(srch.st, "==", USV_SRCH_EMPTY,
+ "Search in empty vector is not an error.");
+
+ vect_u16_clear(&usv);
+ }
+ printf("Test ERROR ON NO VECTOR FOR SEARCHING PASSED\n");
+ printf("========================================\n\n");
+
+ printf("========================================\n");
+ printf("Test CREATED VECTORS ARE SORTED AND UNIQUE\n");
+ {
+ cmp_ok(
+ 0, "==",
+ test_usv(10, (uint16_t[]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, // src
+ 10,
+ (uint16_t[]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }), // expected
+ "Unique sorted vector remains the same.");
+
+ cmp_ok(0, "==",
+ test_usv(10,
+ (uint16_t[]) { 0, 1, 2, 3, 4, 5, 3, 7, 5, 9 }, // src
+ 8, (uint16_t[]) { 0, 1, 2, 3, 4, 5, 7, 9 }), // expected
+ "Duplicates are removed.");
+
+ cmp_ok(
+ 0, "==",
+ test_usv(10, (uint16_t[]) { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }, // src
+ 10,
+ (uint16_t[]) { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }), // expected
+ "Unsorted became sorted.");
+ }
+ printf("Test CREATED VECTORS ARE SORTED AND UNIQUE PASSED\n");
+ printf("========================================\n\n");
+
+ done_testing();
+}
diff --git a/src/test/dfor/test_vect_u16.c b/src/test/dfor/test_vect_u16.c
new file mode 100644
index 00000000000..00efe7dccbe
--- /dev/null
+++ b/src/test/dfor/test_vect_u16.c
@@ -0,0 +1,168 @@
+/*
+ * test_vect_u16.c
+ */
+
+#include "libtap/tap.h"
+#include "lib/vect_u16.h"
+
+int
+main(void)
+{
+ plan(35);
+
+ printf("========================================\n");
+ printf("Test INIT AND CLEAR VECTOR\n");
+ {
+ vect_u16_t v;
+ size_t capacity = 10;
+ cmp_ok(0, "==", vect_u16_init(&v, capacity, NULL),
+ "Result of vect_init is 0");
+
+ cmp_ok(v.cap, "==", capacity,
+ "Vectors capacity is equal to requested one");
+ cmp_ok(v.cnt, "==", 0, "No members in vector");
+ ok(v.m != NULL, "Array for members is reserved");
+ cmp_ok(v.mem_is_outer, "==", false, "Vector does not use outer memory");
+
+ vect_u16_clear(&v);
+
+ cmp_ok(v.cap, "==", 0, "Vectors capacity is 0 after cleanup");
+ cmp_ok(v.cnt, "==", 0, "No members in vector after cleanup");
+ ok(v.m == NULL, "Array for members is absent");
+ cmp_ok(v.mem_is_outer, "==", false, "Vector does not use outer memory");
+ }
+ printf("Test INIT AND CLEAR VECTOR PASSED\n");
+ printf("========================================\n\n");
+
+ printf("========================================\n");
+ printf("Test INIT AND FILL VECTOR\n");
+ {
+ vect_u16_t v;
+ size_t capacity = 10;
+ const uint16_t vals[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ cmp_ok(0, "==", vect_u16_init(&v, capacity, NULL),
+ "Result of vect_init is 0");
+ cmp_ok(0, "==", vect_u16_fill(&v, capacity, vals),
+ "Result of vect_fill is 0");
+
+ cmp_ok(v.cap, "==", capacity,
+ "Vectors capacity is equal to requested one");
+ ok(v.m != NULL, "Array for members is reserved");
+ cmp_ok(v.cnt, "==", capacity, "Members are in vector.");
+ {
+ int equal = 0;
+ for (size_t i = 0; i < capacity; i++) {
+ if (v.m[i] == i)
+ equal = equal + 1;
+ else
+ break;
+ }
+ cmp_ok(equal, "==", 10, "Members are correct");
+ }
+ vect_u16_clear(&v);
+ }
+ printf("Test INIT AND FILL VECTOR PASSED\n");
+ printf("========================================\n\n");
+
+ printf("========================================\n");
+ printf("Test INIT AND FILL VECTOR with zero capcaity\n");
+ {
+ vect_u16_t v;
+ size_t capacity = 0;
+
+ cmp_ok(0, "==", vect_u16_init(&v, capacity, NULL),
+ "Result of vect_init is 0");
+ cmp_ok(0, "==", vect_u16_fill(&v, capacity, NULL),
+ "Result of vect_fill is 0");
+
+ cmp_ok(v.cap, "==", 0, "Vector's capacity is zero");
+ ok(v.m == NULL,
+ "Pointer to members is NULL (array for members is not reserved)");
+ ok(v.cnt == 0, "Counter of members is zero.");
+ vect_u16_clear(&v);
+ }
+ {
+ vect_u16_t v;
+ size_t capacity = 10;
+ const uint16_t vals[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+ cmp_ok(0, "==", vect_u16_init(&v, 0, NULL), "Result of vect_init is 0");
+ cmp_ok(0, "==", vect_u16_fill(&v, capacity, vals),
+ "Result of vect_fill is 0");
+
+ cmp_ok(v.cap, "==", capacity,
+ "Vector's capacity is not zero after filling");
+ ok(v.m != NULL,
+ "Pointer to members is not NULL fater filling (array for members has been reserved)");
+ ok(v.cnt == capacity, "Counter of members is not zero after filling.");
+ vect_u16_clear(&v);
+ }
+ printf("Test INIT AND FILL VECTOR with zero capcaity is finished\n");
+ printf("========================================\n\n");
+
+ printf("========================================\n");
+ printf("Test COMPARE VECTORS\n");
+ {
+ vect_u16_t a, b, c, d;
+
+ uint16_t avals[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ uint16_t bvals[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ uint16_t cvals[] = { 1, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+ uint16_t dvals[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
+
+ vect_u16_init(&a, 0, NULL);
+ vect_u16_init(&b, 0, NULL);
+ vect_u16_init(&c, 0, NULL);
+ vect_u16_init(&d, 0, NULL);
+
+ vect_u16_fill(&a, 10, avals);
+ vect_u16_fill(&b, 10, bvals);
+ vect_u16_fill(&c, 10, cvals);
+ vect_u16_fill(&d, 9, dvals);
+
+ cmp_ok(0, "==", vect_u16_compare(&a, &b), "Vectors are equal");
+ cmp_ok(-1, "==", vect_u16_compare(&a, &c),
+ "Vectors are not equal because of value of members");
+ cmp_ok(-1, "==", vect_u16_compare(&a, &d),
+ "Vectors are not equal because of number of members");
+ }
+ printf("Test COMPARE VECTORS is finished. \n");
+ printf("========================================\n\n");
+
+ printf("========================================\n");
+ printf("Test VECTOR WITH OUTER MEMORY\n");
+ {
+#define VECT_CAP 100
+ vect_u16_t vect;
+ uint16_t buf[VECT_CAP]; /* uint16_t is the item's type */
+ vect_u16_init(&vect, VECT_CAP, buf);
+ cmp_ok(
+ vect.cap, "==", VECT_CAP,
+ "Initialisation of vector having external memory resulted in proper capacity.");
+ cmp_ok(
+ vect.cnt, "==", 0,
+ "Initialisation of vector having external memory resulted in proper number of items.");
+ ok(((void *)vect.m == (void *)buf),
+ "Initialisation of vector having external memory set buf to vect->m.");
+ ok(vect.mem_is_outer,
+ "Initialisation of vector having external memory set mem_is_outer flag.");
+
+ for (size_t i = 0; i < VECT_CAP; i++)
+ {
+ if (vect_u16_append(&vect, i) != 0)
+ fail(
+ "ERROR: New value can't be appended into vector having external memory.");
+ }
+ pass(
+ "All values have been appended into vector having external memory.");
+
+ cmp_ok(vect.cnt, "==", VECT_CAP, "Vector is full.");
+ cmp_ok(vect_u16_append(&vect, VECT_CAP), "==", -1,
+ "Once vector is full, extra item can't be appended.");
+ }
+ printf("Test VECTOR WITH OUTER MEMORY is finished\n");
+ printf("========================================\n");
+
+ done_testing();
+}
diff --git a/src/test/libtap/.gitignore b/src/test/libtap/.gitignore
new file mode 100644
index 00000000000..2c95d046c7d
--- /dev/null
+++ b/src/test/libtap/.gitignore
@@ -0,0 +1,13 @@
+/t/*
+!/t/*.*
+/t/*.exe
+/t/*.got
+*.a
+*.lo
+*.o
+*.so
+*.pc
+usr/
+*.sw?
+/.deps
+/.dirstamp
diff --git a/src/test/libtap/.travis.yml b/src/test/libtap/.travis.yml
new file mode 100644
index 00000000000..6f9809e1b99
--- /dev/null
+++ b/src/test/libtap/.travis.yml
@@ -0,0 +1,13 @@
+language: c
+
+compiler:
+ - gcc
+ - clang
+
+before_install: sudo apt-get install -y libtest-differences-perl
+
+install: make CC=$CC install
+
+script: make CC=$CC test
+
+after_script: make uninstall
diff --git a/src/test/libtap/COPYING b/src/test/libtap/COPYING
new file mode 100644
index 00000000000..65c5ca88a67
--- /dev/null
+++ b/src/test/libtap/COPYING
@@ -0,0 +1,165 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+ This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+ 0. Additional Definitions.
+
+ As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+ "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+ An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+ A "Combined Work" is a work produced by combining or linking an
+Application with the Library. The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+ The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+ The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+ 1. Exception to Section 3 of the GNU GPL.
+
+ You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+ 2. Conveying Modified Versions.
+
+ If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+ a) under this License, provided that you make a good faith effort to
+ ensure that, in the event an Application does not supply the
+ function or data, the facility still operates, and performs
+ whatever part of its purpose remains meaningful, or
+
+ b) under the GNU GPL, with none of the additional permissions of
+ this License applicable to that copy.
+
+ 3. Object Code Incorporating Material from Library Header Files.
+
+ The object code form of an Application may incorporate material from
+a header file that is part of the Library. You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+ a) Give prominent notice with each copy of the object code that the
+ Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the object code with a copy of the GNU GPL and this license
+ document.
+
+ 4. Combined Works.
+
+ You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+ a) Give prominent notice with each copy of the Combined Work that
+ the Library is used in it and that the Library and its use are
+ covered by this License.
+
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
+ document.
+
+ c) For a Combined Work that displays copyright notices during
+ execution, include the copyright notice for the Library among
+ these notices, as well as a reference directing the user to the
+ copies of the GNU GPL and this license document.
+
+ d) Do one of the following:
+
+ 0) Convey the Minimal Corresponding Source under the terms of this
+ License, and the Corresponding Application Code in a form
+ suitable for, and under terms that permit, the user to
+ recombine or relink the Application with a modified version of
+ the Linked Version to produce a modified Combined Work, in the
+ manner specified by section 6 of the GNU GPL for conveying
+ Corresponding Source.
+
+ 1) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (a) uses at run time
+ a copy of the Library already present on the user's computer
+ system, and (b) will operate properly with a modified version
+ of the Library that is interface-compatible with the Linked
+ Version.
+
+ e) Provide Installation Information, but only if you would otherwise
+ be required to provide such information under section 6 of the
+ GNU GPL, and only to the extent that such information is
+ necessary to install and execute a modified version of the
+ Combined Work produced by recombining or relinking the
+ Application with a modified version of the Linked Version. (If
+ you use option 4d0, the Installation Information must accompany
+ the Minimal Corresponding Source and Corresponding Application
+ Code. If you use option 4d1, you must provide the Installation
+ Information in the manner specified by section 6 of the GNU GPL
+ for conveying Corresponding Source.)
+
+ 5. Combined Libraries.
+
+ You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+ a) Accompany the combined library with a copy of the same work based
+ on the Library, uncombined with any other library facilities,
+ conveyed under the terms of this License.
+
+ b) Give prominent notice with the combined library that part of it
+ is a work based on the Library, and explaining where to find the
+ accompanying uncombined form of the same work.
+
+ 6. Revised Versions of the GNU Lesser General Public License.
+
+ The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+ If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
diff --git a/src/test/libtap/INSTALL b/src/test/libtap/INSTALL
new file mode 100644
index 00000000000..5b2c76df3d7
--- /dev/null
+++ b/src/test/libtap/INSTALL
@@ -0,0 +1,41 @@
+To install libtap on a Unix-like system:
+
+ $ make
+ $ make check
+ $ make install
+
+To compile with gcc -ansi, run:
+
+ $ ANSI=1 make
+
+To install to a different directory than /usr/local, supply the
+PREFIX variable to make:
+
+ $ PREFIX=/usr make install
+
+On Windows, the library can be created by first setting up the
+correct development environment variables. Usually this is done by
+running vcvars32.bat included in the Visual Studio distribution.
+You should also install gnu make which can be found at
+http://gnuwin32.sourceforge.net/packages/make.htm. Once this is
+done, you should be able to run the following:
+
+ > make -f Makefile.win
+
+If you want to use it directly in another project, you can copy tap.c
+and tap.h there and it shouldn't have a problem compiling.
+
+ $ ls
+ tap.c tap.h test.c
+ $ cat test.c
+ #include "tap.h"
+ int main () {
+ plan(1);
+ ok(50 + 5, "foo %s", "bar");
+ done_testing();
+ }
+ $ gcc test.c tap.c
+ $ a.out
+ 1..1
+ ok 1 - foo bar
+
diff --git a/src/test/libtap/Makefile b/src/test/libtap/Makefile
new file mode 100644
index 00000000000..f020c2839a8
--- /dev/null
+++ b/src/test/libtap/Makefile
@@ -0,0 +1,73 @@
+CC ?= gcc
+CFLAGS += -Wall -I. -fPIC
+PREFIX ?= $(DESTDIR)/usr/local
+TESTS = $(patsubst %.c, %, $(wildcard t/*.c))
+
+ifdef ANSI
+ # -D_BSD_SOURCE for MAP_ANONYMOUS
+ CFLAGS += -ansi -D_BSD_SOURCE
+ LDLIBS += -lbsd-compat
+endif
+
+%:
+ $(CC) $(LDFLAGS) $(TARGET_ARCH) $(filter %.o %.a %.so, $^) $(LDLIBS) -o $@
+
+%.o:
+ $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c $(filter %.c, $^) $(LDLIBS) -o $@
+
+%.a:
+ $(AR) rcs $@ $(filter %.o, $^)
+
+%.so:
+ $(CC) -shared $(LDFLAGS) $(TARGET_ARCH) $(filter %.o, $^) $(LDLIBS) -o $@
+
+all: libtap.a libtap.so tap.pc tests
+
+tap.pc:
+ @echo generating tap.pc
+ @echo 'prefix='$(PREFIX) > tap.pc
+ @echo 'exec_prefix=$${prefix}' >> tap.pc
+ @echo 'libdir=$${prefix}/lib' >> tap.pc
+ @echo 'includedir=$${prefix}/include' >> tap.pc
+ @echo '' >> tap.pc
+ @echo 'Name: libtap' >> tap.pc
+ @echo 'Description: Write tests in C' >> tap.pc
+ @echo 'Version: 0.1.0' >> tap.pc
+ @echo 'URL: https://github.com/zorgnax/libtap' >> tap.pc
+ @echo 'Libs: -L$${libdir} -ltap' >> tap.pc
+ @echo 'Cflags: -I$${includedir}' >> tap.pc
+
+libtap.a: tap.o
+
+libtap.so: tap.o
+
+tap.o: tap.c tap.h
+
+tests: $(TESTS)
+
+$(TESTS): %: %.o libtap.a
+
+$(patsubst %, %.o, $(TESTS)): %.o: %.c tap.h
+ $(CC) $(CFLAGS) -O0 $(CPPFLAGS) $(TARGET_ARCH) -c $(filter %.c, $^) $(LDLIBS) -o $@
+
+clean:
+ rm -rf *.o t/*.o tap.pc libtap.a libtap.so $(TESTS)
+
+install: libtap.a tap.h libtap.so tap.pc
+ mkdir -p $(PREFIX)/lib $(PREFIX)/include $(PREFIX)/lib/pkgconfig
+ install -c libtap.a $(PREFIX)/lib
+ install -c libtap.so $(PREFIX)/lib
+ install -c tap.pc $(PREFIX)/lib/pkgconfig
+ install -c tap.h $(PREFIX)/include
+
+uninstall:
+ rm $(PREFIX)/lib/libtap.a $(PREFIX)/lib/libtap.so $(PREFIX)/include/tap.h
+
+dist:
+ rm libtap.zip
+ zip -r libtap *
+
+check test: all
+ ./t/test
+
+.PHONY: all clean install uninstall dist check test tests
diff --git a/src/test/libtap/Makefile.win b/src/test/libtap/Makefile.win
new file mode 100644
index 00000000000..694d679a1b1
--- /dev/null
+++ b/src/test/libtap/Makefile.win
@@ -0,0 +1,37 @@
+CFLAGS = /Zi /Wall /wd4255 /wd4996 /wd4127 /wd4820 /wd4100 /wd4619 \
+ /wd4514 /wd4668 /I.
+CC = cl /nologo
+TESTS = $(patsubst %.c, %.exe, $(wildcard t/*.c))
+
+%.exe:
+ $(CC) $(LDFLAGS) $(filter %.obj %.lib %.dll, $^) $(LDLIBS) /Fe $@
+
+%.o:
+ $(CC) $(CFLAGS) $(CPPFLAGS) /c $(filter %.c, $^) $(LDLIBS) /Fo $@
+
+%.lib:
+ lib /nologo /out:$@ $(filter %.obj, $^)
+
+%.dll:
+ lib /nologo /out:$@ $(filter %.obj, $^)
+
+all: tap.lib tests
+
+tap.lib: tap.obj
+
+tap.obj: tap.c tap.h
+
+tests: $(TESTS)
+
+$(TESTS): %.exe: %.obj tap.lib
+
+$(patsubst %.exe, %.obj, $(TESTS)): %.obj: %.c tap.h
+
+clean:
+ rm -rf *.obj t/*.obj tap.lib $(TESTS)
+
+check test: all
+ prove
+
+.PHONY: all clean check test tests
+
diff --git a/src/test/libtap/README.md b/src/test/libtap/README.md
new file mode 100644
index 00000000000..5332d526c08
--- /dev/null
+++ b/src/test/libtap/README.md
@@ -0,0 +1,268 @@
+NAME
+====
+
+libtap - Write tests in C
+
+SYNOPSIS
+========
+
+ #include <tap.h>
+
+ int main () {
+ plan(5);
+ int bronze = 1, silver = 2, gold = 3;
+ ok(bronze < silver, "bronze is less than silver");
+ ok(bronze > silver, "not quite");
+ is("gold", "gold", "gold is gold");
+ cmp_ok(silver, "<", gold, "%d <= %d", silver, gold);
+ like("platinum", ".*inum", "platinum matches .*inum");
+ done_testing();
+ }
+
+results in:
+
+ 1..5
+ ok 1 - bronze is less than silver
+ not ok 2 - not quite
+ # Failed test 'not quite'
+ # at t/synopsis.c line 7.
+ ok 3 - gold is gold
+ ok 4 - 2 <= 3
+ ok 5 - platinum matches .*inum
+ # Looks like you failed 1 test of 5 run.
+
+DESCRIPTION
+===========
+
+tap is an easy to read and easy to write way of creating tests for
+your software. This library creates functions that can be used to
+generate it for your C programs. It is implemented using macros
+that include file and line info automatically, and makes it so that
+the format message of each test is optional. It is mostly based on
+the Test::More Perl module.
+
+INSTALL
+=======
+
+On **Unix** systems:
+
+ $ make
+ $ make install
+
+For more detailed installation instructions (eg, for **Windows**), see `INSTALL`.
+
+FUNCTIONS
+=========
+
+- plan(tests)
+- plan(NO_PLAN)
+- plan(SKIP_ALL);
+- plan(SKIP_ALL, fmt, ...)
+
+ Use this to start a series of tests. When you know how many tests there
+ will be, you can put a number as a number of tests you expect to run. If
+ you do not know how many tests there will be, you can use plan(NO_PLAN)
+ or not call this function. When you pass it a number of tests to run, a
+ message similar to the following will appear in the output:
+
+ 1..5
+
+ If you pass it SKIP_ALL, the whole test will be skipped.
+
+- ok(test)
+- ok(test, fmt, ...)
+
+ Specify a test. the test can be any statement returning a true or false
+ value. You may optionally pass a format string describing the test.
+
+ ok(r = reader_new("Of Mice and Men"), "create a new reader");
+ ok(reader_go_to_page(r, 55), "can turn the page");
+ ok(r->page == 55, "page turned to the right one");
+
+ Should print out:
+
+ ok 1 - create a new reader
+ ok 2 - can turn the page
+ ok 3 - page turned to the right one
+
+ On failure, a diagnostic message will be printed out.
+
+ not ok 3 - page turned to the right one
+ # Failed test 'page turned to the right one'
+ # at reader.c line 13.
+
+- is(got, expected)
+- is(got, expected, fmt, ...)
+- isnt(got, unexpected)
+- isnt(got, unexpected, fmt, ...)
+
+ Tests that the string you got is what you expected. with isnt, it is the
+ reverse.
+
+ is("this", "that", "this is that");
+
+ prints:
+
+ not ok 1 - this is that
+ # Failed test 'this is that'
+ # at is.c line 6.
+ # got: 'this'
+ # expected: 'that'
+
+- cmp_ok(a, op, b)
+- cmp_ok(a, op, b, fmt, ...)
+
+ Compares two ints with any binary operator that doesn't require an lvalue.
+ This is nice to use since it provides a better error message than an
+ equivalent ok.
+
+ cmp_ok(420, ">", 666);
+
+ prints:
+
+ not ok 1
+ # Failed test at cmpok.c line 5.
+ # 420
+ # >
+ # 666
+
+- cmp_mem(got, expected, n)
+- cmp_mem(got, expected, n, fmt, ...)
+
+ Tests that the first n bytes of the memory you got is what you expected.
+ NULL pointers for got and expected are handled (if either is NULL,
+ the test fails), but you need to ensure n is not too large.
+
+ char *a = "foo";
+ char *b = "bar";
+ cmp_mem(a, b, 3)
+
+ prints
+
+ not ok 1
+ # Failed test at t/cmp_mem.c line 9.
+ # Difference starts at offset 0
+ # got: 0x66
+ # expected: 0x62
+
+- like(got, expected)
+- like(got, expected, fmt, ...)
+- unlike(got, unexpected)
+- unlike(got, unexpected, fmt, ...)
+
+ Tests that the string you got matches the expected extended POSIX regex.
+ unlike is the reverse. These macros are the equivalent of a skip on
+ Windows.
+
+ like("stranger", "^s.(r).*\\1$", "matches the regex");
+
+ prints:
+
+ ok 1 - matches the regex
+
+- pass()
+- pass(fmt, ...)
+- fail()
+- fail(fmt, ...)
+
+ Speciy that a test succeeded or failed. Use these when the statement is
+ longer than you can fit into the argument given to an ok() test.
+
+- dies_ok(code)
+- dies_ok(code, fmt, ...)
+- lives_ok(code)
+- lives_ok(code, fmt, ...)
+
+ Tests whether the given code causes your program to exit. The code gets
+ passed to a macro that will test it in a forked process. If the code
+ succeeds it will be executed in the parent process. You can test things
+ like passing a function a null pointer and make sure it doesnt
+ dereference it and crash.
+
+ dies_ok({abort();}, "abort does close your program");
+ dies_ok({int x = 0/0;}, "divide by zero crash");
+ lives_ok({pow(3.0, 5.0);}, "nothing wrong with taking 3**5");
+
+ On Windows, these macros are the equivalent of a skip.
+
+- done_testing()
+
+ Summarizes the tests that occurred and exits the main function. If
+ there was no plan, it will print out the number of tests as.
+
+ 1..5
+
+ It will also print a diagnostic message about how many
+ failures there were.
+
+ # Looks like you failed 2 tests of 3 run.
+
+ If all planned tests were successful, it will return 0. If any
+ test fails, it will return 1. If they all passed, but there
+ were missing tests, it will return 2.
+
+- diag(fmt, ...)
+
+ print out a message to the tap output on stdout. Each line is
+ preceeded by a "# " so that you know its a diagnostic message.
+
+ diag("This is\na diag\nto describe\nsomething.");
+
+ prints:
+
+ # This is
+ # a diag
+ # to describe
+ # something
+
+ ok() and this function return an int so you can use it like:
+
+ ok(0) || diag("doh!");
+
+- skip(test, n)
+- skip(test, n, fmt, ...)
+- end_skip
+
+ Skip a series of n tests if test is true. You may give a reason why you are
+ skipping them or not. The (possibly) skipped tests must occur between the
+ skip and end_skip macros.
+
+ skip(TRUE, 2);
+ ok(1);
+ ok(0);
+ end_skip;
+
+ prints:
+
+ ok 1 # skip
+ ok 2 # skip
+
+- todo()
+- todo(fmt, ...)
+- end_todo
+
+ Specifies a series of tests that you expect to fail because they are not
+ yet implemented.
+
+ todo()
+ ok(0);
+ end_todo;
+
+ prints:
+
+ not ok 1 # TODO
+ # Failed (TODO) test at todo.c line 7
+
+- BAIL_OUT()
+- BAIL_OUT(fmt, ...)
+
+ Immediately stops all testing.
+
+ BAIL_OUT("Can't go no further");
+
+ prints
+
+ Bail out! Can't go no further
+
+ and exits with 255.
+
diff --git a/src/test/libtap/tap.c b/src/test/libtap/tap.c
new file mode 100644
index 00000000000..506e4000156
--- /dev/null
+++ b/src/test/libtap/tap.c
@@ -0,0 +1,421 @@
+/*
+libtap - Write tests in C
+Copyright 2012 Jake Gelbman <gelbman@gmail.com>
+This file is licensed under the LGPL
+*/
+
+#define _DEFAULT_SOURCE 1
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "tap.h"
+
+#ifndef _WIN32
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/mman.h>
+
+#include <regex.h>
+
+#ifndef MAP_ANONYMOUS
+#ifdef MAP_ANON
+#define MAP_ANONYMOUS MAP_ANON
+#else
+#error "System does not support mapping anonymous pages"
+#endif
+#endif
+#endif
+
+#if defined(__GNUC__) || defined(__clang__)
+#define PRINTF_ATTR(fmtarg, firstvararg) __attribute__((format(printf, fmtarg, firstvararg)))
+#else
+#define PRINTF_ATTR(fmtarg, firstvararg)
+#endif
+
+static int expected_tests = NO_PLAN;
+static int failed_tests;
+static int current_test;
+static char *todo_mesg;
+
+static char *vstrdupf(const char *fmt, va_list args) PRINTF_ATTR(1,0);
+
+void tap_plan(int tests, const char *fmt, ...) PRINTF_ATTR(2, 3);
+
+int vok_at_loc(const char *file, int line, int test, const char *fmt,
+ va_list args) PRINTF_ATTR(4,0);
+
+int ok_at_loc(const char *file, int line, int test, const char *fmt, ...)
+ PRINTF_ATTR(4, 5);
+
+int is_at_loc(const char *file, int line, const char *got, const char *expected,
+ const char *fmt, ...) PRINTF_ATTR(5, 6);
+
+int isnt_at_loc(const char *file, int line, const char *got,
+ const char *expected, const char *fmt, ...)
+ PRINTF_ATTR(5, 6);
+
+int cmp_ok_at_loc(const char *file, int line, int a, const char *op, int b,
+ const char *fmt, ...)
+ PRINTF_ATTR(6, 7);
+
+int cmp_mem_at_loc(const char *file, int line, const void *got,
+ const void *expected, size_t n, const char *fmt, ...)
+ PRINTF_ATTR(6, 7);
+
+int diag(const char *fmt, ...) PRINTF_ATTR(1, 2);
+
+int bail_out(int ignore, const char *fmt, ...)
+ PRINTF_ATTR(2, 3);
+
+void tap_skip(int n, const char *fmt, ...)
+ PRINTF_ATTR(2, 3);
+
+void tap_todo(int ignore, const char *fmt, ...)
+ PRINTF_ATTR(2, 3);
+
+int like_at_loc(int for_match, const char *file, int line, const char *got,
+ const char *expected, const char *fmt, ...)
+ PRINTF_ATTR(6, 7);
+
+static char *
+vstrdupf(const char *fmt, va_list args)
+{
+ char *str;
+ int size;
+ va_list args2;
+ va_copy(args2, args);
+ if (!fmt)
+ fmt = "";
+ size = vsnprintf(NULL, 0, fmt, args2) + 2;
+ str = malloc(size);
+ if (!str) {
+ perror("malloc error");
+ exit(1);
+ }
+ vsprintf(str, fmt, args);
+ va_end(args2);
+ return str;
+}
+
+void
+tap_plan(int tests, const char *fmt, ...)
+{
+ expected_tests = tests;
+ if (tests == SKIP_ALL) {
+ char *why;
+ va_list args;
+ va_start(args, fmt);
+ why = vstrdupf(fmt, args);
+ va_end(args);
+ printf("1..0 ");
+ diag("SKIP %s\n", why);
+ exit(0);
+ }
+ if (tests != NO_PLAN) {
+ printf("1..%d\n", tests);
+ }
+}
+
+int
+vok_at_loc(const char *file, int line, int test, const char *fmt, va_list args)
+{
+ char *name = vstrdupf(fmt, args);
+ if (!test) {
+ printf("not ");
+ }
+ printf("ok %d", ++current_test);
+ if (*name)
+ printf(" - %s", name);
+ if (todo_mesg) {
+ printf(" # TODO");
+ if (*todo_mesg)
+ printf(" %s", todo_mesg);
+ }
+ printf("\n");
+ if (!test) {
+ printf("# Failed ");
+ if (todo_mesg)
+ printf("(TODO) ");
+ printf("test ");
+ if (*name)
+ printf("'%s'\n# ", name);
+ printf("at %s line %d.\n", file, line);
+ if (!todo_mesg)
+ failed_tests++;
+ }
+ free(name);
+ return test;
+}
+
+int
+ok_at_loc(const char *file, int line, int test, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vok_at_loc(file, line, test, fmt, args);
+ va_end(args);
+ return test;
+}
+
+static int
+mystrcmp(const char *a, const char *b)
+{
+ return a == b ? 0 : !a ? -1 : !b ? 1 : strcmp(a, b);
+}
+
+#define eq(a, b) (!mystrcmp(a, b))
+#define ne(a, b) (mystrcmp(a, b))
+
+int
+is_at_loc(const char *file, int line, const char *got, const char *expected,
+ const char *fmt, ...)
+{
+ int test = eq(got, expected);
+ va_list args;
+ va_start(args, fmt);
+ vok_at_loc(file, line, test, fmt, args);
+ va_end(args);
+ if (!test) {
+ diag(" got: '%s'", got);
+ diag(" expected: '%s'", expected);
+ }
+ return test;
+}
+
+int
+isnt_at_loc(const char *file, int line, const char *got, const char *expected,
+ const char *fmt, ...)
+{
+ int test = ne(got, expected);
+ va_list args;
+ va_start(args, fmt);
+ vok_at_loc(file, line, test, fmt, args);
+ va_end(args);
+ if (!test) {
+ diag(" got: '%s'", got);
+ diag(" expected: anything else");
+ }
+ return test;
+}
+
+int
+cmp_ok_at_loc(const char *file, int line, int a, const char *op, int b,
+ const char *fmt, ...)
+{
+ int test = eq(op, "||") ? a || b :
+ eq(op, "&&") ? a && b :
+ eq(op, "|") ? a | b :
+ eq(op, "^") ? a ^ b :
+ eq(op, "&") ? a & b :
+ eq(op, "==") ? a == b :
+ eq(op, "!=") ? a != b :
+ eq(op, "<") ? a < b :
+ eq(op, ">") ? a > b :
+ eq(op, "<=") ? a <= b :
+ eq(op, ">=") ? a >= b :
+ eq(op, "<<") ? a << b :
+ eq(op, ">>") ? a >> b :
+ eq(op, "+") ? a + b :
+ eq(op, "-") ? a - b :
+ eq(op, "*") ? a * b :
+ eq(op, "/") ? a / b :
+ eq(op, "%") ? a % b :
+ diag("unrecognized operator '%s'", op);
+ va_list args;
+ va_start(args, fmt);
+ vok_at_loc(file, line, test, fmt, args);
+ va_end(args);
+ if (!test) {
+ diag(" %d", a);
+ diag(" %s", op);
+ diag(" %d", b);
+ }
+ return test;
+}
+
+static int
+find_mem_diff(const char *a, const char *b, size_t n, size_t *offset)
+{
+ size_t i;
+ if (a == b)
+ return 0;
+ if (!a || !b)
+ return 2;
+ for (i = 0; i < n; i++) {
+ if (a[i] != b[i]) {
+ *offset = i;
+ return 1;
+ }
+ }
+ return 0;
+}
+
+int
+cmp_mem_at_loc(const char *file, int line, const void *got,
+ const void *expected, size_t n, const char *fmt, ...)
+{
+ size_t offset;
+ int diff = find_mem_diff(got, expected, n, &offset);
+ va_list args;
+ va_start(args, fmt);
+ vok_at_loc(file, line, !diff, fmt, args);
+ va_end(args);
+ if (diff == 1) {
+ diag(" Difference starts at offset %lu", offset);
+ diag(" got: 0x%02x", ((const unsigned char *)got)[offset]);
+ diag(" expected: 0x%02x", ((const unsigned char *)expected)[offset]);
+ } else if (diff == 2) {
+ diag(" got: %s", got ? "not NULL" : "NULL");
+ diag(" expected: %s", expected ? "not NULL" : "NULL");
+ }
+ return !diff;
+}
+
+int
+diag(const char *fmt, ...)
+{
+ va_list args;
+ char *mesg, *line;
+ int i;
+ va_start(args, fmt);
+ if (!fmt) {
+ va_end(args);
+ return 0;
+ }
+ mesg = vstrdupf(fmt, args);
+ line = mesg;
+ for (i = 0; *line; i++) {
+ char c = mesg[i];
+ if (!c || c == '\n') {
+ mesg[i] = '\0';
+ printf("# %s\n", line);
+ if (!c)
+ break;
+ mesg[i] = c;
+ line = mesg + i + 1;
+ }
+ }
+ free(mesg);
+ va_end(args);
+ return 0;
+}
+
+int
+exit_status(void)
+{
+ int retval = 0;
+ if (expected_tests == NO_PLAN) {
+ printf("1..%d\n", current_test);
+ } else if (current_test != expected_tests) {
+ diag("Looks like you planned %d test%s but ran %d.", expected_tests,
+ expected_tests > 1 ? "s" : "", current_test);
+ retval = 2;
+ }
+ if (failed_tests) {
+ diag("Looks like you failed %d test%s of %d run.", failed_tests,
+ failed_tests > 1 ? "s" : "", current_test);
+ retval = 1;
+ }
+ return retval;
+}
+
+int
+bail_out(int ignore, const char *fmt, ...)
+{
+ va_list args;
+ (void)ignore;
+ va_start(args, fmt);
+ printf("Bail out! ");
+ vprintf(fmt, args);
+ printf("\n");
+ va_end(args);
+ exit(255);
+ return 0;
+}
+
+void
+tap_skip(int n, const char *fmt, ...)
+{
+ char *why;
+ va_list args;
+ va_start(args, fmt);
+ why = vstrdupf(fmt, args);
+ va_end(args);
+ while (n-- > 0) {
+ printf("ok %d ", ++current_test);
+ diag("skip %s\n", why);
+ }
+ free(why);
+}
+
+void
+tap_todo(int ignore, const char *fmt, ...)
+{
+ va_list args;
+ (void)ignore;
+ va_start(args, fmt);
+ todo_mesg = vstrdupf(fmt, args);
+ va_end(args);
+}
+
+void
+tap_end_todo(void)
+{
+ free(todo_mesg);
+ todo_mesg = NULL;
+}
+
+#ifndef _WIN32
+/* Create a shared memory int to keep track of whether a piece of code executed
+dies. to be used in the dies_ok and lives_ok macros. */
+int
+tap_test_died(int status)
+{
+ static int *test_died = NULL;
+ int prev;
+ if (!test_died) {
+ test_died = mmap(0, sizeof(int), PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+ *test_died = 0;
+ }
+ prev = *test_died;
+ *test_died = status;
+ return prev;
+}
+
+int
+like_at_loc(int for_match, const char *file, int line, const char *got,
+ const char *expected, const char *fmt, ...)
+{
+ int test;
+ regex_t re;
+ va_list args;
+ int err = regcomp(&re, expected, REG_EXTENDED);
+ if (err) {
+ char errbuf[256];
+ regerror(err, &re, errbuf, sizeof errbuf);
+ fprintf(stderr, "Unable to compile regex '%s': %s at %s line %d\n",
+ expected, errbuf, file, line);
+ exit(255);
+ }
+ err = regexec(&re, got, 0, NULL, 0);
+ regfree(&re);
+ test = for_match ? !err : err;
+ va_start(args, fmt);
+ vok_at_loc(file, line, test, fmt, args);
+ va_end(args);
+ if (!test) {
+ if (for_match) {
+ diag(" '%s'", got);
+ diag(" doesn't match: '%s'", expected);
+ } else {
+ diag(" '%s'", got);
+ diag(" matches: '%s'", expected);
+ }
+ }
+ return test;
+}
+#endif
diff --git a/src/test/libtap/tap.h b/src/test/libtap/tap.h
new file mode 100644
index 00000000000..e366a6affdc
--- /dev/null
+++ b/src/test/libtap/tap.h
@@ -0,0 +1,115 @@
+/*
+libtap - Write tests in C
+Copyright 2012 Jake Gelbman <gelbman@gmail.com>
+This file is licensed under the LGPL
+*/
+
+#ifndef __TAP_H__
+#define __TAP_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef va_copy
+#ifdef __va_copy
+#define va_copy __va_copy
+#else
+#define va_copy(d, s) ((d) = (s))
+#endif
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+int vok_at_loc (const char *file, int line, int test, const char *fmt,
+ va_list args);
+int ok_at_loc (const char *file, int line, int test, const char *fmt,
+ ...);
+int is_at_loc (const char *file, int line, const char *got,
+ const char *expected, const char *fmt, ...);
+int isnt_at_loc (const char *file, int line, const char *got,
+ const char *expected, const char *fmt, ...);
+int cmp_ok_at_loc (const char *file, int line, int a, const char *op,
+ int b, const char *fmt, ...);
+int cmp_mem_at_loc (const char *file, int line, const void *got,
+ const void *expected, size_t n, const char *fmt, ...);
+int bail_out (int ignore, const char *fmt, ...);
+void tap_plan (int tests, const char *fmt, ...);
+int diag (const char *fmt, ...);
+int exit_status (void);
+void tap_skip (int n, const char *fmt, ...);
+void tap_todo (int ignore, const char *fmt, ...);
+void tap_end_todo (void);
+
+#define NO_PLAN -1
+#define SKIP_ALL -2
+#define ok(...) ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL)
+#define is(...) is_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL)
+#define isnt(...) isnt_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL)
+#define cmp_ok(...) cmp_ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL)
+#define cmp_mem(...) cmp_mem_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL)
+#define plan(...) tap_plan(__VA_ARGS__, NULL)
+#define done_testing() return exit_status()
+#define BAIL_OUT(...) bail_out(0, "" __VA_ARGS__, NULL)
+#define pass(...) ok(1, "" __VA_ARGS__)
+#define fail(...) ok(0, "" __VA_ARGS__)
+
+#define skip(test, ...) do {if (test) {tap_skip(__VA_ARGS__, NULL); break;}
+#define end_skip } while (0)
+
+#define todo(...) tap_todo(0, "" __VA_ARGS__, NULL)
+#define end_todo tap_end_todo()
+
+#define dies_ok(...) dies_ok_common(1, __VA_ARGS__)
+#define lives_ok(...) dies_ok_common(0, __VA_ARGS__)
+
+#ifdef _WIN32
+#define like(...) tap_skip(1, "like is not implemented on Windows")
+#define unlike(...) tap_skip(1, "unlike is not implemented on Windows")
+#define dies_ok_common(...) \
+ tap_skip(1, "Death detection is not supported on Windows")
+#else
+#define like(...) like_at_loc(1, __FILE__, __LINE__, __VA_ARGS__, NULL)
+#define unlike(...) like_at_loc(0, __FILE__, __LINE__, __VA_ARGS__, NULL)
+int like_at_loc (int for_match, const char *file, int line,
+ const char *got, const char *expected,
+ const char *fmt, ...);
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+int tap_test_died (int status);
+#define dies_ok_common(for_death, code, ...) \
+ do { \
+ int cpid; \
+ int it_died; \
+ tap_test_died(1); \
+ cpid = fork(); \
+ switch (cpid) { \
+ case -1: \
+ perror("fork error"); \
+ exit(1); \
+ case 0: \
+ close(1); \
+ close(2); \
+ code \
+ tap_test_died(0); \
+ exit(0); \
+ } \
+ if (waitpid(cpid, NULL, 0) < 0) { \
+ perror("waitpid error"); \
+ exit(1); \
+ } \
+ it_died = tap_test_died(0); \
+ if (!it_died) \
+ {code} \
+ ok(for_death ? it_died : !it_died, "" __VA_ARGS__); \
+ } while (0)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/test/meson.build b/src/test/meson.build
index cd45cbf57fb..64fa751a5a5 100644
--- a/src/test/meson.build
+++ b/src/test/meson.build
@@ -8,6 +8,7 @@ subdir('postmaster')
subdir('recovery')
subdir('subscription')
subdir('modules')
+subdir('dfor')
if ssl.found()
subdir('ssl')
--
2.53.0