summaryrefslogtreecommitdiffstats
path: root/tests/unit
diff options
context:
space:
mode:
Diffstat (limited to 'tests/unit')
-rw-r--r--tests/unit/ist.c700
-rw-r--r--tests/unit/test-1-among.c105
-rw-r--r--tests/unit/test-arg.c44
-rw-r--r--tests/unit/test-inherited-fd.py23
-rw-r--r--tests/unit/test-list.c98
-rw-r--r--tests/unit/test-sockpair.py28
6 files changed, 998 insertions, 0 deletions
diff --git a/tests/unit/ist.c b/tests/unit/ist.c
new file mode 100644
index 0000000..43b3438
--- /dev/null
+++ b/tests/unit/ist.c
@@ -0,0 +1,700 @@
+/* ist.c: test code for ist.h
+ *
+ * Build with :
+ * gcc -Iinclude -Wall -W -fomit-frame-pointer -Os tests/ist.c
+ * gcc -Iinclude -Wall -W -fomit-frame-pointer -O1 tests/ist.c
+ * gcc -Iinclude -Wall -W -fomit-frame-pointer -O2 tests/ist.c
+ * gcc -Iinclude -Wall -W -fomit-frame-pointer -O3 tests/ist.c
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <import/ist.h>
+
+
+// pre-extracted from ist.h using the following expression :
+// sed -n '/^static inline/s:^\([^ ]\+\) \([^ ]\+\) \(.*[* ]\)\([^* ]\+(\)\(.*\):\3f_\4\5 { return \4); }\nstatic int test_\4)\n{\n\treturn 0;\n}\n:p' include/common/ist.h
+// sed -n '/^static inline/s:^\([^ ]\+\) \([^ ]\+\) \(.*[* ]\)\([^* ]\+(\)\(.*\):\tif (test_\4)) printf("\4)\\n");:p' include/common/ist.h
+// sed -n '/^static inline/s:^\([^ ]\+\) \([^ ]\+\) \(.*[* ]\)\([^* ]\+(\)\(.*\):\tprintf("%4d \4)\\n", test_\4));:p' include/common/ist.h
+
+struct ist f_ist(const void *str) { return ist(str); }
+static int test_ist()
+{
+ if (ist("foo").ptr == NULL)
+ return __LINE__;
+ if (ist("foo").len != 3)
+ return __LINE__;
+ if (strncmp(ist("foo").ptr, "foo", 3) != 0)
+ return 3;
+ return 0;
+}
+
+struct ist f_ist2(const void *ptr, size_t len) { return ist2(ptr, len); }
+int test_ist2()
+{
+ if (ist2("foo", 3).ptr == NULL)
+ return __LINE__;
+ if (ist2("foo", 3).len != 3)
+ return __LINE__;
+ if (strncmp(ist2("foo", 3).ptr, "foo", 3) != 0)
+ return __LINE__;
+ return 0;
+}
+
+size_t f_istlen(struct ist ist) { return istlen(ist); }
+int test_istlen()
+{
+ if (istlen(ist("foo")) != 3)
+ return __LINE__;
+ if (istlen(ist("")) != 0)
+ return __LINE__;
+ if (istlen(ist(NULL)) != 0)
+ return __LINE__;
+ return 0;
+}
+
+struct ist f_istnext(struct ist ist) { return istnext(ist); }
+int test_istnext()
+{
+ if (istlen(istnext(ist("foo"))) != 2)
+ return __LINE__;
+ if (strncmp(istnext(ist("foo")).ptr, "oo", 2) != 0)
+ return __LINE__;
+ if (istnext(istnext(istnext(istnext(ist("foo"))))).len != 0)
+ return __LINE__;
+ return 0;
+}
+
+struct ist f_istpad(void *buf, const struct ist ist) { return istpad(buf, ist); }
+int test_istpad()
+{
+ char buf[5] = "xxxxx";
+
+ if (strncmp(istpad(buf, ist("foo")).ptr, "foo", 3) != 0)
+ return __LINE__;
+ if (strncmp(buf, "foo", 3) != 0)
+ return __LINE__;
+ if (buf[3] != 0 || buf[4] != 'x')
+ return __LINE__;
+ return 0;
+}
+
+struct ist f_isttrim(struct ist ist, size_t size) { return isttrim(ist, size); }
+int test_isttrim()
+{
+ if (isttrim(ist("foo"), 5).ptr == NULL)
+ return __LINE__;
+
+ if (isttrim(ist("foo"), 5).len != 3)
+ return __LINE__;
+
+ if (strncmp(isttrim(ist("foo"), 5).ptr, "foo", 3) != 0)
+ return __LINE__;
+
+ if (isttrim(ist("foo"), 2).ptr == NULL)
+ return __LINE__;
+
+ if (isttrim(ist("foo"), 2).len != 2)
+ return __LINE__;
+
+ if (strncmp(isttrim(ist("foo"), 2).ptr, "fo", 2) != 0)
+ return __LINE__;
+
+ return 0;
+}
+
+struct ist f_istzero(struct ist ist, size_t size) { return istzero(ist, size); }
+int test_istzero()
+{
+ char buf[5] = "xxxxx";
+
+ if (istzero(ist2(buf, 5), 10).ptr != buf)
+ return __LINE__;
+
+ if (istzero(ist2(buf, 5), 10).len != 5)
+ return __LINE__;
+
+ if (istzero(ist2(buf, 5), 5).len != 4)
+ return __LINE__;
+
+ if (buf[4] != 0)
+ return __LINE__;
+
+ if (istzero(ist2(buf, 5), 0).len != 0)
+ return __LINE__;
+
+ if (buf[0] == 0)
+ return __LINE__;
+
+ return 0;
+}
+
+int f_istdiff(const struct ist ist1, const struct ist ist2) { return istdiff(ist1, ist2); }
+int test_istdiff()
+{
+ if (istdiff(ist(""), ist("")) != 0)
+ return __LINE__;
+
+ if (istdiff(ist("bar"), ist("bar")) != 0)
+ return __LINE__;
+
+ if (istdiff(ist("foo"), ist("")) <= 0)
+ return __LINE__;
+
+ if (istdiff(ist(""), ist("bar")) >= 0)
+ return __LINE__;
+
+ if (istdiff(ist("foo"), ist("bar")) <= 0)
+ return __LINE__;
+
+ if (istdiff(ist("fo"), ist("bar")) <= 0)
+ return __LINE__;
+
+ if (istdiff(ist("bar"), ist("foo")) >= 0)
+ return __LINE__;
+
+ if (istdiff(ist("bar"), ist("fo")) >= 0)
+ return __LINE__;
+
+ return 0;
+}
+
+int f_istmatch(const struct ist ist1, const struct ist ist2) { return istmatch(ist1, ist2); }
+int test_istmatch()
+{
+ if (istmatch(ist(""), ist("")) == 0)
+ return __LINE__;
+
+ if (istmatch(ist("bar"), ist("bar")) == 0)
+ return __LINE__;
+
+ if (istmatch(ist("foo"), ist("")) == 0)
+ return __LINE__;
+
+ if (istmatch(ist(""), ist("bar")) != 0)
+ return __LINE__;
+
+ if (istmatch(ist("foo"), ist("bar")) != 0)
+ return __LINE__;
+
+ if (istmatch(ist("fo"), ist("bar")) != 0)
+ return __LINE__;
+
+ if (istmatch(ist("bar"), ist("foo")) != 0)
+ return __LINE__;
+
+ if (istmatch(ist("bar"), ist("fo")) != 0)
+ return __LINE__;
+
+ if (istmatch(ist("foo"), ist("foobar")) != 0)
+ return __LINE__;
+
+ if (istmatch(ist("foobar"), ist("foo")) == 0)
+ return __LINE__;
+
+ if (istmatch(ist("foobar"), ist("bar")) != 0)
+ return __LINE__;
+
+ return 0;
+}
+
+int f_istnmatch(struct ist ist1, struct ist ist2, size_t count) { return istnmatch(ist1, ist2, count); }
+int test_istnmatch()
+{
+ if (istnmatch(ist(""), ist(""), 1) == 0)
+ return __LINE__;
+
+ if (istnmatch(ist(""), ist(""), 0) == 0)
+ return __LINE__;
+
+ if (istnmatch(ist("bar"), ist("bar"), 4) == 0)
+ return __LINE__;
+
+ if (istnmatch(ist("bar"), ist("bar"), 2) == 0)
+ return __LINE__;
+
+ if (istnmatch(ist("bar"), ist("baz"), 2) == 0)
+ return __LINE__;
+
+ if (istnmatch(ist("foo"), ist(""), 1) == 0)
+ return __LINE__;
+
+ if (istnmatch(ist("foo"), ist(""), 0) == 0)
+ return __LINE__;
+
+ if (istnmatch(ist(""), ist("bar"), 3) != 0)
+ return __LINE__;
+
+ if (istnmatch(ist(""), ist("bar"), 0) == 0)
+ return __LINE__;
+
+ if (istnmatch(ist("foo"), ist("bar"), 4) != 0)
+ return __LINE__;
+
+ if (istnmatch(ist("foo"), ist("bar"), 0) == 0)
+ return __LINE__;
+
+ if (istnmatch(ist("fo"), ist("bar"), 2) != 0)
+ return __LINE__;
+
+ if (istnmatch(ist("bar"), ist("foo"), 3) != 0)
+ return __LINE__;
+
+ if (istnmatch(ist("bar"), ist("fo"), 2) != 0)
+ return __LINE__;
+
+ if (istnmatch(ist("foo"), ist("foobar"), 4) != 0)
+ return __LINE__;
+
+ if (istnmatch(ist("foo"), ist("foobar"), 3) == 0)
+ return __LINE__;
+
+ if (istnmatch(ist("foobar"), ist("fooz"), 4) != 0)
+ return __LINE__;
+
+ if (istnmatch(ist("foobar"), ist("fooz"), 3) == 0)
+ return __LINE__;
+
+ if (istnmatch(ist("foobar"), ist("fooz"), 2) == 0)
+ return __LINE__;
+
+ if (istnmatch(ist("foobar"), ist("bar"), 3) != 0)
+ return __LINE__;
+
+ return 0;
+}
+
+int f_isteq(const struct ist ist1, const struct ist ist2) { return isteq(ist1, ist2); }
+int test_isteq()
+{
+ if (isteq(ist(""), ist("")) == 0)
+ return __LINE__;
+
+ if (isteq(ist("bar"), ist("bar")) == 0)
+ return __LINE__;
+
+ if (isteq(ist("foo"), ist("")) != 0)
+ return __LINE__;
+
+ if (isteq(ist(""), ist("bar")) != 0)
+ return __LINE__;
+
+ if (isteq(ist("foo"), ist("bar")) != 0)
+ return __LINE__;
+
+ if (isteq(ist("fo"), ist("bar")) != 0)
+ return __LINE__;
+
+ if (isteq(ist("bar"), ist("foo")) != 0)
+ return __LINE__;
+
+ if (isteq(ist("bar"), ist("fo")) != 0)
+ return __LINE__;
+
+ if (isteq(ist("foo"), ist("foobar")) != 0)
+ return __LINE__;
+
+ if (isteq(ist("foobar"), ist("foo")) != 0)
+ return __LINE__;
+
+ if (isteq(ist("foobar"), ist("bar")) != 0)
+ return __LINE__;
+
+ return 0;
+}
+
+int f_istneq(struct ist ist1, struct ist ist2, size_t count) { return istneq(ist1, ist2, count); }
+int test_istneq()
+{
+ if (istneq(ist(""), ist(""), 1) == 0)
+ return __LINE__;
+
+ if (istneq(ist(""), ist(""), 0) == 0)
+ return __LINE__;
+
+ if (istneq(ist("bar"), ist("bar"), 4) == 0)
+ return __LINE__;
+
+ if (istneq(ist("bar"), ist("bar"), 2) == 0)
+ return __LINE__;
+
+ if (istneq(ist("bar"), ist("baz"), 2) == 0)
+ return __LINE__;
+
+ if (istneq(ist("foo"), ist(""), 1) != 0)
+ return __LINE__;
+
+ if (istneq(ist("foo"), ist(""), 0) == 0)
+ return __LINE__;
+
+ if (istneq(ist(""), ist("bar"), 3) != 0)
+ return __LINE__;
+
+ if (istneq(ist(""), ist("bar"), 0) == 0)
+ return __LINE__;
+
+ if (istneq(ist("foo"), ist("bar"), 4) != 0)
+ return __LINE__;
+
+ if (istneq(ist("foo"), ist("bar"), 0) == 0)
+ return __LINE__;
+
+ if (istneq(ist("fo"), ist("bar"), 2) != 0)
+ return __LINE__;
+
+ if (istneq(ist("bar"), ist("foo"), 3) != 0)
+ return __LINE__;
+
+ if (istneq(ist("bar"), ist("fo"), 2) != 0)
+ return __LINE__;
+
+ if (istneq(ist("foo"), ist("foobar"), 4) != 0)
+ return __LINE__;
+
+ if (istneq(ist("foo"), ist("foobar"), 3) == 0)
+ return __LINE__;
+
+ if (istneq(ist("foobar"), ist("fooz"), 4) != 0)
+ return __LINE__;
+
+ if (istneq(ist("foobar"), ist("fooz"), 3) == 0)
+ return __LINE__;
+
+ if (istneq(ist("foobar"), ist("fooz"), 2) == 0)
+ return __LINE__;
+
+ if (istneq(ist("foobar"), ist("bar"), 3) != 0)
+ return __LINE__;
+
+ return 0;
+}
+
+ssize_t f_istcpy(struct ist *dst, const struct ist src, size_t count) { return istcpy(dst, src, count); }
+int test_istcpy()
+{
+ char buf[100] = "foobar";
+ struct ist dst = ist(buf);
+
+ if (istcpy(&dst, ist("FOO"), sizeof(buf)) != 3)
+ return __LINE__;
+
+ if (dst.len != 3)
+ return __LINE__;
+
+ if (strcmp(buf, "FOObar") != 0)
+ return __LINE__;
+
+ if (istcpy(&dst, ist("foo"), 2) != -1)
+ return __LINE__;
+
+ if (strcmp(buf, "foObar") != 0)
+ return __LINE__;
+
+ if (istcpy(&dst, ist("foo"), 3) != 3)
+ return __LINE__;
+
+ if (strcmp(buf, "foobar") != 0)
+ return __LINE__;
+
+ return 0;
+}
+
+ssize_t f_istscpy(struct ist *dst, const struct ist src, size_t count) { return istscpy(dst, src, count); }
+int test_istscpy()
+{
+ char buf[100] = "foobar";
+ struct ist dst = ist(buf);
+
+ if (istscpy(&dst, ist("FOO"), sizeof(buf)) != 3)
+ return __LINE__;
+
+ if (dst.len != 3)
+ return __LINE__;
+
+ if (memcmp(buf, "FOO\0ar", 6) != 0)
+ return __LINE__;
+
+ if (istscpy(&dst, ist("foo"), 3) != -1)
+ return __LINE__;
+
+ if (memcmp(buf, "fo\0\0ar", 6) != 0)
+ return __LINE__;
+
+ if (istscpy(&dst, ist("foo"), 3) != -1)
+ return __LINE__;
+
+ if (istscpy(&dst, ist("foo"), 4) != 3)
+ return __LINE__;
+
+ if (memcmp(buf, "foo\0ar", 6) != 0)
+ return __LINE__;
+
+ return 0;
+}
+
+ssize_t f_istcat(struct ist *dst, const struct ist src, size_t count) { return istcat(dst, src, count); }
+int test_istcat()
+{
+ char buf[11] = "foobar";
+ struct ist dst = ist(buf);
+
+ if (istcat(&dst, ist("FOO"), sizeof(buf)) != 9)
+ return __LINE__;
+
+ if (strcmp(buf, "foobarFOO") != 0)
+ return __LINE__;
+
+ if (istcat(&dst, ist("foo"), 10) != -1)
+ return __LINE__;
+
+ if (dst.len != 10)
+ return __LINE__;
+
+ if (strncmp(buf, "foobarFOOf", 10) != 0)
+ return __LINE__;
+
+ if (istcat(&dst, ist("foo"), 3) != -1)
+ return __LINE__;
+
+ if (dst.len != 10)
+ return __LINE__;
+
+ if (strncmp(buf, "foobar", 6) != 0)
+ return __LINE__;
+
+ return 0;
+}
+
+ssize_t f_istscat(struct ist *dst, const struct ist src, size_t count) { return istscat(dst, src, count); }
+int test_istscat()
+{
+ char buf[11] = "foobar";
+ struct ist dst = ist(buf);
+
+ if (istscat(&dst, ist("FOO"), sizeof(buf)) != 9)
+ return __LINE__;
+
+ if (strcmp(buf, "foobarFOO") != 0)
+ return __LINE__;
+
+ if (istscat(&dst, ist("foo"), sizeof(buf)) != -1)
+ return __LINE__;
+
+ if (dst.len != 10)
+ return __LINE__;
+
+ if (strncmp(buf, "foobarFOOf", 10) != 0)
+ return __LINE__;
+
+ if (istscat(&dst, ist("foo"), 3) != -1)
+ return __LINE__;
+
+ if (dst.len != 10)
+ return __LINE__;
+
+ if (strncmp(buf, "foobar", 6) != 0)
+ return __LINE__;
+
+ return 0;
+}
+
+char *f_istchr(const struct ist ist, char chr) { return istchr(ist, chr); }
+int test_istchr()
+{
+ struct ist foobar = ist("foobar");
+
+ if (istchr(foobar, 'f') != foobar.ptr)
+ return __LINE__;
+
+ if (istchr(foobar, 'o') != foobar.ptr + 1)
+ return __LINE__;
+
+ if (istchr(foobar, 'r') != foobar.ptr + 5)
+ return __LINE__;
+
+ if (istchr(foobar, 'X') != NULL)
+ return __LINE__;
+
+ if (istchr(foobar, 0) != NULL)
+ return __LINE__;
+
+ return 0;
+}
+
+struct ist f_istfind(struct ist ist, char chr) { return istfind(ist, chr); }
+int test_istfind()
+{
+ struct ist foobar = ist("foobar");
+
+ if (istfind(foobar, 'f').ptr != foobar.ptr)
+ return __LINE__;
+
+ if (istfind(foobar, 'f').len != 6)
+ return __LINE__;
+
+ if (istfind(foobar, 'o').ptr != foobar.ptr + 1)
+ return __LINE__;
+
+ if (istfind(foobar, 'o').len != 5)
+ return __LINE__;
+
+ if (istfind(foobar, 'r').ptr != foobar.ptr + 5)
+ return __LINE__;
+
+ if (istfind(foobar, 'r').len != 1)
+ return __LINE__;
+
+ if (istfind(foobar, 'X').ptr != foobar.ptr + foobar.len)
+ return __LINE__;
+
+ if (istfind(foobar, 'X').len != 0)
+ return __LINE__;
+
+ if (istfind(foobar, 0).ptr != foobar.ptr + foobar.len)
+ return __LINE__;
+
+ if (istfind(foobar, 0).len != 0)
+ return __LINE__;
+
+ return 0;
+}
+
+struct ist f_istskip(struct ist ist, char chr) { return istskip(ist, chr); }
+int test_istskip()
+{
+ struct ist foobar = ist("foobar");
+ struct ist r = ist("r");
+
+ if (istskip(foobar, 'X').ptr != foobar.ptr)
+ return __LINE__;
+
+ if (istskip(foobar, 'X').len != foobar.len)
+ return __LINE__;
+
+ if (istskip(foobar, 'o').ptr != foobar.ptr)
+ return __LINE__;
+
+ if (istskip(foobar, 'o').len != foobar.len)
+ return __LINE__;
+
+ if (istskip(foobar, 'f').ptr != foobar.ptr + 1)
+ return __LINE__;
+
+ if (istskip(foobar, 'f').len != foobar.len - 1)
+ return __LINE__;
+
+ if (istskip(r, 'r').ptr != r.ptr + 1)
+ return __LINE__;
+
+ if (istskip(r, 'r').len != r.len - 1)
+ return __LINE__;
+
+ if (istskip(foobar, 'X').ptr != foobar.ptr)
+ return __LINE__;
+
+ if (istskip(foobar, 'X').len != foobar.len)
+ return __LINE__;
+
+ if (istskip(r, 0).ptr != r.ptr)
+ return __LINE__;
+
+ if (istskip(r, 0).len != r.len)
+ return __LINE__;
+
+ return 0;
+}
+
+struct ist f_istist(struct ist ist, const struct ist pat) { return istist(ist, pat); }
+int test_istist()
+{
+ struct ist foobar = ist("foobar");
+
+ if (istist(foobar, ist("f")).ptr != foobar.ptr)
+ return __LINE__;
+
+ if (istist(foobar, ist("f")).len != foobar.len)
+ return __LINE__;
+
+ if (istist(foobar, ist("foob")).ptr != foobar.ptr)
+ return __LINE__;
+
+ if (istist(foobar, ist("foob")).len != foobar.len)
+ return __LINE__;
+
+ if (istist(foobar, ist("foobar")).ptr != foobar.ptr)
+ return __LINE__;
+
+ if (istist(foobar, ist("foobar")).len != foobar.len)
+ return __LINE__;
+
+ if (istist(foobar, ist("o")).ptr != foobar.ptr + 1)
+ return __LINE__;
+
+ if (istist(foobar, ist("o")).len != foobar.len - 1)
+ return __LINE__;
+
+ if (istist(foobar, ist("ooba")).ptr != foobar.ptr + 1)
+ return __LINE__;
+
+ if (istist(foobar, ist("ooba")).len != foobar.len - 1)
+ return __LINE__;
+
+ if (istist(foobar, ist("r")).ptr != foobar.ptr + 5)
+ return __LINE__;
+
+ if (istist(foobar, ist("r")).len != foobar.len - 5)
+ return __LINE__;
+
+ if (istist(foobar, ist("X")).ptr != NULL)
+ return __LINE__;
+
+ if (istist(foobar, ist("X")).len != 0)
+ return __LINE__;
+
+ if (istist(foobar, ist("oobaX")).ptr != NULL)
+ return __LINE__;
+
+ if (istist(foobar, ist("oobaX")).len != 0)
+ return __LINE__;
+
+ if (istist(foobar, ist("oobarX")).ptr != NULL)
+ return __LINE__;
+
+ if (istist(foobar, ist("oobarX")).len != 0)
+ return __LINE__;
+
+ if (istist(foobar, ist("")).ptr != foobar.ptr)
+ return __LINE__;
+
+ if (istist(foobar, ist("")).len != foobar.len)
+ return __LINE__;
+
+ return 0;
+}
+
+
+int main(void)
+{
+ printf("%4d ist()\n", test_ist());
+ printf("%4d ist2()\n", test_ist2());
+ printf("%4d istlen()\n", test_istlen());
+ printf("%4d istnext()\n", test_istnext());
+ printf("%4d istpad()\n", test_istpad());
+ printf("%4d isttrim()\n", test_isttrim());
+ printf("%4d istzero()\n", test_istzero());
+ printf("%4d istdiff()\n", test_istdiff());
+ printf("%4d istmatch()\n", test_istmatch());
+ printf("%4d istnmatch()\n", test_istnmatch());
+ printf("%4d isteq()\n", test_isteq());
+ printf("%4d istneq()\n", test_istneq());
+ printf("%4d istcpy()\n", test_istcpy());
+ printf("%4d istscpy()\n", test_istscpy());
+ printf("%4d istcat()\n", test_istcat());
+ printf("%4d istscat()\n", test_istscat());
+ printf("%4d istchr()\n", test_istchr());
+ printf("%4d istfind()\n", test_istfind());
+ printf("%4d istskip()\n", test_istskip());
+ printf("%4d istist()\n", test_istist());
+
+ return 0;
+}
diff --git a/tests/unit/test-1-among.c b/tests/unit/test-1-among.c
new file mode 100644
index 0000000..bd19192
--- /dev/null
+++ b/tests/unit/test-1-among.c
@@ -0,0 +1,105 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+static inline unsigned long statistical_prng()
+{
+ static unsigned long statistical_prng_state = 2463534242U;
+ unsigned long x = statistical_prng_state;
+
+ if (sizeof(long) <= 4) {
+ x ^= x << 13;
+ x ^= x >> 17;
+ x ^= x << 5;
+ } else {
+ x ^= x << 13;
+ x ^= x >> 7;
+ x ^= x << 17;
+ }
+ return statistical_prng_state = x;
+}
+
+/* returns the position of one bit set in <v>, starting at position <bit>, and
+ * searching in other halves if not found. This is intended to be used to
+ * report the position of one bit set among several based on a counter or a
+ * random generator while preserving a relatively good distribution so that
+ * values made of holes in the middle do not see one of the bits around the
+ * hole being returned much more often than the other one. It can be seen as a
+ * disturbed ffsl() where the initial search starts at bit <bit>. The look up
+ * is performed in O(logN) time for N bit words, yielding a bit among 64 in
+ * about 16 cycles. Passing value 0 for <v> makes no sense and -1 is returned
+ * in this case.
+ */
+int one_among(unsigned long v, int bit)
+{
+ /* note, these masks may be produced by ~0UL/((1UL<<scale)+1) but
+ * that's more expensive.
+ */
+ static const unsigned long halves[] = {
+ (unsigned long)0x5555555555555555ULL,
+ (unsigned long)0x3333333333333333ULL,
+ (unsigned long)0x0F0F0F0F0F0F0F0FULL,
+ (unsigned long)0x00FF00FF00FF00FFULL,
+ (unsigned long)0x0000FFFF0000FFFFULL,
+ (unsigned long)0x00000000FFFFFFFFULL
+ };
+ unsigned long halfword = ~0UL;
+ int scope = 0;
+ int mirror;
+ int scale;
+
+ if (!v)
+ return -1;
+
+ /* we check if the exact bit is set or if it's present in a mirror
+ * position based on the current scale we're checking, in which case
+ * it's returned with its current (or mirrored) value. Otherwise we'll
+ * make sure there's at least one bit in the half we're in, and will
+ * scale down to a smaller scope and try again, until we find the
+ * closest bit.
+ */
+ for (scale = (sizeof(long) > 4) ? 5 : 4; scale >= 0; scale--) {
+ halfword >>= (1UL << scale);
+ scope |= (1UL << scale);
+ mirror = bit ^ (1UL << scale);
+ if (v & ((1UL << bit) | (1UL << mirror)))
+ return (v & (1UL << bit)) ? bit : mirror;
+
+ if (!((v >> (bit & scope)) & halves[scale] & halfword))
+ bit = mirror;
+ }
+ return bit;
+}
+
+int main(int argc, char **argv)
+{
+ unsigned long mask;
+ int bit;
+
+ if (argc < 2) {
+ unsigned long long tests = 0;
+ int ret;
+
+ while (1) {
+ mask = statistical_prng(); // note: cannot be zero
+ bit = statistical_prng() % (sizeof(long) * 8);
+ ret = one_among(mask, bit);
+ if (ret < 0 || !((mask >> ret) & 1))
+ printf("###ERR### mask=%#lx bit=%d ret=%d\n", mask, bit, ret);
+ if (!(tests & 0xffffff))
+ printf("count=%Ld mask=%lx bit=%d ret=%d\n", tests, mask, bit, ret);
+ tests++;
+ }
+ }
+
+ mask = atol(argv[1]);
+
+ if (argc < 3) {
+ for (bit = 0; bit < 8*sizeof(long); bit++)
+ printf("v %#x bit %d best %d\n", mask, bit, one_among(mask, bit));
+ } else {
+ bit = atoi(argv[2]);
+ printf("v %#x bit %d best %d\n", mask, bit, one_among(mask, bit));
+ }
+ return 0;
+}
diff --git a/tests/unit/test-arg.c b/tests/unit/test-arg.c
new file mode 100644
index 0000000..1871f8c
--- /dev/null
+++ b/tests/unit/test-arg.c
@@ -0,0 +1,44 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <haproxy/arg.h>
+
+int main(int argc, char **argv)
+{
+ int nbargs, err_arg, mask;
+ struct arg *argp;
+ char *err_msg = NULL;
+ const char *err_ptr = NULL;
+
+ if (argc < 2) {
+ printf("Usage: %s arg_list [arg_mask]\n"
+ " mask defaults to 0x86543290\n"
+ " eg: %s 10k,+20,Host,1.2.3.4,24,::5.6.7.8,120s\n", *argv, *argv);
+ return 1;
+ }
+
+ mask = ARG7(0,SIZE,SINT,STR,IPV4,MSK4,IPV6,TIME);
+ if (argc >= 3)
+ mask = atoll(argv[2]);
+
+ printf("Using mask=0x%08x\n", mask);
+ nbargs = make_arg_list(argv[1], strlen(argv[1]), mask,
+ &argp, &err_msg, &err_ptr, &err_arg, NULL);
+
+ printf("nbargs=%d\n", nbargs);
+ if (nbargs < 0) {
+ printf("err_msg=%s\n", err_msg); free(err_msg);
+ printf("err_ptr=%s (str+%d)\n", err_ptr, err_ptr - argv[1]);
+ printf("err_arg=%d\n", err_arg);
+ return 1;
+ }
+
+ if (nbargs > 0) {
+ int arg;
+
+ for (arg = 0; arg < nbargs; arg++)
+ printf("arg %d: type=%d, int=0x%08x\n",
+ arg, argp[arg].type, *(int*)&argp[arg].data.sint);
+ }
+ return 0;
+}
diff --git a/tests/unit/test-inherited-fd.py b/tests/unit/test-inherited-fd.py
new file mode 100644
index 0000000..b4b076c
--- /dev/null
+++ b/tests/unit/test-inherited-fd.py
@@ -0,0 +1,23 @@
+#!/usr/bin/python
+"""
+Python wrapper example to test the fd@ function,
+You have to bind on fd@${NEWFD} in your haproxy configuration
+
+The configuration parsing should still work upon a reload with the master-worker
+mode.
+
+"""
+
+import socket, subprocess, fcntl
+
+s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
+s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+flags = fcntl.fcntl(s.fileno(), fcntl.F_GETFD)
+flags &= ~fcntl.FD_CLOEXEC
+fcntl.fcntl(s.fileno(), fcntl.F_SETFD, flags)
+
+s.bind((socket.gethostname(), 5555))
+s.listen(1)
+FD = s.fileno()
+
+subprocess.Popen('NEWFD={} ./haproxy -W -f haproxy.cfg'.format(FD), shell=True, close_fds=False)
diff --git a/tests/unit/test-list.c b/tests/unit/test-list.c
new file mode 100644
index 0000000..9e6ac38
--- /dev/null
+++ b/tests/unit/test-list.c
@@ -0,0 +1,98 @@
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#define USE_THREAD
+#include <haproxy/list.h>
+
+/* Stress test the mt_lists.
+ * Compile from the haproxy directory with :
+ * cc -I../../include test-list.c -pthread -O2 -o test-list
+ * The only argument it takes is the number of threads to be used.
+ * ./test-list 4
+ */
+
+struct mt_list pouet_list = MT_LIST_HEAD_INIT(pouet_list);
+#define MAX_ACTION 5000000
+
+__thread unsigned int tid;
+struct pouet_lol {
+ struct mt_list list_elt;
+};
+
+void *thread(void *pouet)
+{
+ struct pouet_lol *lol;
+ struct mt_list *elt1, elt2;
+ tid = (uintptr_t)pouet;
+ int i = 0;
+
+ for (int i = 0; i < MAX_ACTION; i++) {
+ struct pouet_lol *lol;
+ struct mt_list *elt1, elt2;
+ switch (random() % 4) {
+ case 0:
+ lol = malloc(sizeof(*lol));
+ MT_LIST_INIT(&lol->list_elt);
+ MT_LIST_TRY_INSERT(&pouet_list, &lol->list_elt);
+ break;
+ case 1:
+ lol = malloc(sizeof(*lol));
+ MT_LIST_INIT(&lol->list_elt);
+ MT_LIST_TRY_APPEND(&pouet_list, &lol->list_elt);
+ break;
+
+ case 2:
+ lol = MT_LIST_POP(&pouet_list, struct pouet_lol *, list_elt);
+ if (lol)
+ free(lol);
+ break;
+ case 3:
+
+ mt_list_for_each_entry_safe(lol, &pouet_list, list_elt, elt1, elt2)
+
+{
+ if (random() % 2) {
+ MT_LIST_DELETE_SAFE(elt1);
+ free(lol);
+ }
+ if (random() % 2) {
+ break;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+int main(int argc, char *argv[])
+{
+ int nb;
+ pthread_t *pth;
+
+ srandom(time(NULL));
+ if (argc != 2) {
+ printf("Usage: %s <nb_threads>\n", argv[0]);
+ exit(1);
+ }
+ nb = atoi(argv[1]);
+#if 0
+ if (nb < 2) {
+ printf("Need at least 2 threads.\n");
+ exit(1);
+ }
+#endif
+ pth = malloc(nb * sizeof(*pth));
+ if (pth == NULL) {
+ printf("Shot failed to connect.\n");
+ exit(1);
+ }
+ for (int i = 0; i < nb; i++) {
+ pthread_create(&pth[i], NULL, thread, (void *)(uintptr_t)i);
+
+ }
+ for (int i = 0; i < nb; i++)
+ pthread_join(pth[i], NULL);
+ return 0;
+}
diff --git a/tests/unit/test-sockpair.py b/tests/unit/test-sockpair.py
new file mode 100644
index 0000000..922c6d0
--- /dev/null
+++ b/tests/unit/test-sockpair.py
@@ -0,0 +1,28 @@
+#!/usr/bin/python
+"""
+Python wrapper example to test socketpair protocol
+./test-socketpair.py test.cfg
+
+use sockpair@${FD1} and sockpair@${FD2} in your configuration file
+
+"""
+
+import socket, os, sys
+
+s = socket.socketpair(socket.AF_UNIX, socket.SOCK_STREAM)
+os.set_inheritable(s[0].fileno(), 1)
+os.set_inheritable(s[1].fileno(), 1)
+
+FD1 = s[0].fileno()
+FD2 = s[1].fileno()
+
+print("FD1={} FD2={}".format(FD1, FD2))
+
+os.environ["FD1"] = str(FD1)
+os.environ["FD2"] = str(FD2)
+
+cmd = ["./haproxy",
+ "-f",
+ "{}".format(sys.argv[1])
+]
+os.execve(cmd[0], cmd, os.environ)