TAP line filter BIO.
authorPauli <paul.dale@oracle.com>
Wed, 21 Jun 2017 23:35:08 +0000 (09:35 +1000)
committerPauli <paul.dale@oracle.com>
Wed, 21 Jun 2017 23:35:08 +0000 (09:35 +1000)
This is an implementation of a BIO filter that produce TAP compatible output
for the test framework.  The current test indentation level is honoured.

The test output functions have been modified to not attempt to indent
their output and to not include the leading '#' character.

The filter is applied to bio_err only.  bio_out is left unchanged, although
tests using bio_out have been modified to use bio_err instead.

Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/3732)

test/asn1_encode_test.c
test/build.info
test/ecdsatest.c
test/testutil/basic_output.c
test/testutil/cb.c
test/testutil/format_output.c
test/testutil/tap_bio.c [new file with mode: 0644]
test/testutil/tests.c
test/testutil/tu_local.h

index 3da07503e7ea47a1e666702180575f8c64963495..9b8cdcaf3a4542fa6d148ef4bf2df4e3239dcce8 100644 (file)
@@ -717,7 +717,7 @@ static int do_print_item(const TEST_PACKAGE *package)
     OPENSSL_assert(package->encode_expectations_elem_size <= DATA_BUF_SIZE);
 
     (void)RAND_bytes(buf, (int)package->encode_expectations_elem_size);
-    ret = ASN1_item_print(bio_out, o, 0, i, NULL);
+    ret = ASN1_item_print(bio_err, o, 0, i, NULL);
 
     return ret;
 }
index 205ba60fc3b6ad9b14a2cce973ec316dd50e805b..f5d8d408853db99bd29902b67ceb7822fb469bde 100644 (file)
@@ -11,7 +11,7 @@ IF[{- !$disabled{tests} -}]
   LIBS_NO_INST=libtestutil.a
   SOURCE[libtestutil.a]=testutil/basic_output.c testutil/output_helpers.c \
           testutil/driver.c testutil/tests.c testutil/cb.c testutil/stanza.c \
-          testutil/format_output.c \
+          testutil/format_output.c testutil/tap_bio.c \
           {- rebase_files("../apps", $target{apps_aux_src}) -} \
           testutil/test_main.c testutil/main.c
   INCLUDE[libtestutil.a]=.. ../include
index 54f1a526d94257b73668efb421d90d9507db0592..841934e51c69e544d8247aaa41dc30c9aad7bacf 100644 (file)
 
 #include <openssl/opensslconf.h> /* To see if OPENSSL_NO_EC is defined */
 
-#ifdef OPENSSL_NO_EC
-int main(int argc, char *argv[])
-{
-    puts("Elliptic curves are disabled.");
-    return 0;
-}
-#else
+#ifndef OPENSSL_NO_EC
 
 # include <openssl/crypto.h>
 # include <openssl/bio.h>
@@ -403,9 +397,13 @@ static int test_builtin(void)
 
 void register_tests(void)
 {
+#ifdef OPENSSL_NO_EC
+    TEST_note("Elliptic curves are disabled.");
+#else
     /* initialize the prng */
     RAND_seed(rnd_seed, sizeof(rnd_seed));
     ADD_TEST(x9_62_tests);
     ADD_TEST(test_builtin);
+#endif
 }
 #endif
index 6e1f99a5adbdac167a42c7193513e2fcd6df90d3..b69c59f7759fa69d50bbd2f3cb33a26f82586d7d 100644 (file)
@@ -9,6 +9,7 @@
 
 #include "../testutil.h"
 #include "output.h"
+#include "tu_local.h"
 
 #include <openssl/crypto.h>
 #include <openssl/bio.h>
@@ -20,6 +21,7 @@ void test_open_streams(void)
 {
     bio_out = BIO_new_fp(stdout, BIO_NOCLOSE | BIO_FP_TEXT);
     bio_err = BIO_new_fp(stderr, BIO_NOCLOSE | BIO_FP_TEXT);
+    bio_err = BIO_push(BIO_new(BIO_f_tap()), bio_err);
 
     OPENSSL_assert(bio_out != NULL);
     OPENSSL_assert(bio_err != NULL);
index a291eaaa49fd405ef5e183a7aa053cd1459e69f5..4f5ba080cc04f011bf154246d3911027240c5385 100644 (file)
@@ -12,5 +12,5 @@
 
 int openssl_error_cb(const char *str, size_t len, void *u)
 {
-    return test_printf_stderr("%*s# %s", subtest_level(), "", str);
+    return test_printf_stderr("%s", str);
 }
index ae5fdc99a9b038c90db1458e2e92ca9e41c30cba..ae3bf0ef7703877b4825a500ae3abe688e38a5d5 100644 (file)
@@ -1,3 +1,12 @@
+/*
+ * Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
 #include "../testutil.h"
 #include "output.h"
 #include "tu_local.h"
 /* Output a diff header */
 static void test_diff_header(const char *left, const char *right)
 {
-    test_printf_stderr("%*s# --- %s\n", subtest_level(), "", left);
-    test_printf_stderr("%*s# +++ %s\n", subtest_level(), "", right);
+    test_printf_stderr("--- %s\n", left);
+    test_printf_stderr("+++ %s\n", right);
 }
 
 /* Formatted string output routines */
 static void test_string_null_empty(const char *m, char c)
 {
     if (m == NULL)
-        test_printf_stderr("%*s# % 4s %c NULL\n", subtest_level(), "", "", c);
+        test_printf_stderr("% 4s %c NULL\n", "", c);
     else
-        test_printf_stderr("%*s# % 4u:%c ''\n", subtest_level(), "", 0u, c);
+        test_printf_stderr("% 4u:%c ''\n", 0u, c);
 }
 
 static void test_fail_string_common(const char *prefix, const char *file,
@@ -33,8 +42,7 @@ static void test_fail_string_common(const char *prefix, const char *file,
                                     const char *op, const char *m1, size_t l1,
                                     const char *m2, size_t l2)
 {
-    const int indent = subtest_level();
-    const size_t width = (MAX_STRING_WIDTH - indent - 12) / 16 * 16;
+    const size_t width = (MAX_STRING_WIDTH - subtest_level() - 12) / 16 * 16;
     char b1[MAX_STRING_WIDTH + 1], b2[MAX_STRING_WIDTH + 1];
     char bdiff[MAX_STRING_WIDTH + 1];
     size_t n1, n2, i;
@@ -86,19 +94,18 @@ static void test_fail_string_common(const char *prefix, const char *file,
             bdiff[i] = '\0';
         }
         if (n1 == n2 && !diff) {
-            test_printf_stderr("%*s# % 4u:  '%s'\n", indent, "", cnt,
-                               n2 > n1 ? b2 : b1);
+            test_printf_stderr("% 4u:  '%s'\n", cnt, n2 > n1 ? b2 : b1);
         } else {
             if (cnt == 0 && (m1 == NULL || *m1 == '\0'))
                 test_string_null_empty(m1, '-');
             else if (n1 > 0)
-                test_printf_stderr("%*s# % 4u:- '%s'\n", indent, "", cnt, b1);
+                test_printf_stderr("% 4u:- '%s'\n", cnt, b1);
             if (cnt == 0 && (m2 == NULL || *m2 == '\0'))
                test_string_null_empty(m2, '+');
             else if (n2 > 0)
-                test_printf_stderr("%*s# % 4u:+ '%s'\n", indent, "", cnt, b2);
+                test_printf_stderr("% 4u:+ '%s'\n", cnt, b2);
             if (diff && i > 0)
-                test_printf_stderr("%*s# % 4s    %s\n", indent, "", "", bdiff);
+                test_printf_stderr("% 4s    %s\n", "", bdiff);
         }
         m1 += n1;
         m2 += n2;
@@ -168,8 +175,7 @@ static const int bn_chars = (MAX_STRING_WIDTH - 9) / (BN_OUTPUT_SIZE * 2 + 1)
  */
 static void test_bignum_header_line(void)
 {
-    test_printf_stderr("%*s#  %*s\n", subtest_level(), "", bn_chars + 6,
-                       "bit position");
+    test_printf_stderr(" %*s\n", bn_chars + 6, "bit position");
 }
 
 static const char *test_bignum_zero_null(const BIGNUM *bn)
@@ -188,8 +194,7 @@ static void test_bignum_zero_print(const BIGNUM *bn, char sep)
     const char *v = test_bignum_zero_null(bn);
     const char *suf = bn != NULL ? ":    0" : "";
 
-    test_printf_stderr("%*s# %c%*s%s\n", subtest_level(), "", sep, bn_chars,
-                       v, suf);
+    test_printf_stderr("%c%*s%s\n", sep, bn_chars, v, suf);
 }
 
 /*
@@ -260,7 +265,6 @@ static void test_fail_bignum_common(const char *prefix, const char *file,
                                     const char *op,
                                     const BIGNUM *bn1, const BIGNUM *bn2)
 {
-    const int indent = subtest_level();
     const size_t bytes = bn_bytes;
     char b1[MAX_STRING_WIDTH + 1], b2[MAX_STRING_WIDTH + 1];
     char *p, bdiff[MAX_STRING_WIDTH + 1];
@@ -295,8 +299,7 @@ static void test_fail_bignum_common(const char *prefix, const char *file,
     if (len > MEM_BUFFER_SIZE && (bufp = OPENSSL_malloc(len * 2)) == NULL) {
         bufp = buffer;
         len = MEM_BUFFER_SIZE;
-        test_printf_stderr("%*s# WARNING: these BIGNUMs have been truncated",
-                           indent, "");
+        test_printf_stderr("WARNING: these BIGNUMs have been truncated");
     }
 
     if (bn1 != NULL) {
@@ -326,20 +329,19 @@ static void test_fail_bignum_common(const char *prefix, const char *file,
             }
         *p++ = '\0';
         if (!diff) {
-            test_printf_stderr("%*s#  %s:% 5d\n", indent, "",
-                               n2 > n1 ? b2 : b1, cnt);
+            test_printf_stderr(" %s:% 5d\n", n2 > n1 ? b2 : b1, cnt);
         } else {
             if (cnt == 0 && bn1 == NULL)
-                test_printf_stderr("%*s# -%s\n", indent, "", b1);
+                test_printf_stderr("-%s\n", b1);
             else if (cnt == 0 || n1 > 0)
-                test_printf_stderr("%*s# -%s:% 5d\n", indent, "", b1, cnt);
+                test_printf_stderr("-%s:% 5d\n", b1, cnt);
             if (cnt == 0 && bn2 == NULL)
-                test_printf_stderr("%*s# +%s\n", indent, "", b2);
+                test_printf_stderr("+%s\n", b2);
             else if (cnt == 0 || n2 > 0)
-                test_printf_stderr("%*s# +%s:% 5d\n", indent, "", b2, cnt);
+                test_printf_stderr("+%s:% 5d\n", b2, cnt);
             if (real_diff && (cnt == 0 || (n1 > 0 && n2 > 0))
                     && bn1 != NULL && bn2 != NULL)
-                test_printf_stderr("%*s#  %s\n", indent, "", bdiff);
+                test_printf_stderr(" %s\n", bdiff);
         }
         if (m1 != NULL)
             m1 += bytes;
@@ -380,8 +382,8 @@ void test_fail_bignum_mono_message(const char *prefix, const char *file,
 void test_output_bignum(const char *name, const BIGNUM *bn)
 {
     if (bn == NULL || BN_is_zero(bn)) {
-        test_printf_stderr("%*s# bignum: '%s' = %s\n", subtest_level(), "",
-                           name, test_bignum_zero_null(bn));
+        test_printf_stderr("bignum: '%s' = %s", name,
+                           test_bignum_zero_null(bn));
     } else if (BN_num_bytes(bn) <= BN_OUTPUT_SIZE) {
         unsigned char buf[BN_OUTPUT_SIZE];
         char out[2 * sizeof(buf) + 1];
@@ -391,8 +393,8 @@ void test_output_bignum(const char *name, const BIGNUM *bn)
         hex_convert_memory(buf, n, p, BN_OUTPUT_SIZE);
         while (*p == '0' && *++p != '\0')
             ;
-        test_printf_stderr("%*s# bignum: '%s' = %s0x%s\n", subtest_level(), "",
-                           name, BN_is_negative(bn) ? "-" : "", p);
+        test_printf_stderr("bignum: '%s' = %s0x%s\n", name,
+                           BN_is_negative(bn) ? "-" : "", p);
     } else {
         test_fail_bignum_common("bignum", NULL, 0, NULL, NULL, NULL, name,
                                 bn, bn);
@@ -404,12 +406,12 @@ void test_output_bignum(const char *name, const BIGNUM *bn)
 /*
  * Handle zero length blocks of memory or NULL pointers to memory
  */
-static void test_memory_null_empty(const unsigned char *m, int indent, char c)
+static void test_memory_null_empty(const unsigned char *m, char c)
 {
     if (m == NULL)
-        test_printf_stderr("%*s# % 4s %c%s\n", indent, "", "", c, "NULL");
+        test_printf_stderr("% 4s %c%s\n", "", c, "NULL");
     else
-        test_printf_stderr("%*s# %04x %c%s\n", indent, "", 0u, c, "empty");
+        test_printf_stderr("%04x %c%s\n", 0u, c, "empty");
 }
 
 /*
@@ -422,7 +424,6 @@ static void test_fail_memory_common(const char *prefix, const char *file,
                                     const unsigned char *m1, size_t l1,
                                     const unsigned char *m2, size_t l2)
 {
-    const int indent = subtest_level();
     const size_t bytes = (MAX_STRING_WIDTH - 9) / 17 * 8;
     char b1[MAX_STRING_WIDTH + 1], b2[MAX_STRING_WIDTH + 1];
     char *p, bdiff[MAX_STRING_WIDTH + 1];
@@ -436,11 +437,11 @@ static void test_fail_memory_common(const char *prefix, const char *file,
         l2 = 0;
     if (l1 == 0 && l2 == 0) {
         if ((m1 == NULL) == (m2 == NULL)) {
-            test_memory_null_empty(m1, indent, ' ');
+            test_memory_null_empty(m1, ' ');
         } else {
             test_diff_header(left, right);
-            test_memory_null_empty(m1, indent, '-');
-            test_memory_null_empty(m2, indent, '+');
+            test_memory_null_empty(m1, '-');
+            test_memory_null_empty(m2, '+');
         }
         goto fin;
     }
@@ -481,18 +482,18 @@ static void test_fail_memory_common(const char *prefix, const char *file,
         }
 
         if (n1 == n2 && !diff) {
-            test_printf_stderr("%*s# %04x: %s\n", indent, "", cnt, b1);
+            test_printf_stderr("%04x: %s\n", cnt, b1);
         } else {
             if (cnt == 0 && (m1 == NULL || l1 == 0))
-                test_memory_null_empty(m1, indent, '-');
+                test_memory_null_empty(m1, '-');
             else if (n1 > 0)
-                test_printf_stderr("%*s# %04x:-%s\n", indent, "", cnt, b1);
+                test_printf_stderr("%04x:-%s\n", cnt, b1);
             if (cnt == 0 && (m2 == NULL || l2 == 0))
-                test_memory_null_empty(m2, indent, '+');
+                test_memory_null_empty(m2, '+');
             else if (n2 > 0)
-                test_printf_stderr("%*s# %04x:+%s\n", indent, "", cnt, b2);
+                test_printf_stderr("%04x:+%s\n", cnt, b2);
             if (diff && i > 0)
-                test_printf_stderr("%*s# % 4s  %s\n", indent, "", "", bdiff);
+                test_printf_stderr("% 4s  %s\n", "", bdiff);
         }
         m1 += n1;
         m2 += n2;
diff --git a/test/testutil/tap_bio.c b/test/testutil/tap_bio.c
new file mode 100644 (file)
index 0000000..43c95c0
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2017 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright (c) 2017, Oracle and/or its affiliates.  All rights reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <string.h>
+#include "tu_local.h"
+
+static int tap_write_ex(BIO *b, const char *buf, size_t size, size_t *in_size);
+static int tap_read_ex(BIO *b, char *buf, size_t size, size_t *out_size);
+static int tap_puts(BIO *b, const char *str);
+static int tap_gets(BIO *b, char *str, int size);
+static long tap_ctrl(BIO *b, int cmd, long arg1, void *arg2);
+static int tap_new(BIO *b);
+static int tap_free(BIO *b);
+static long tap_callback_ctrl(BIO *h, int cmd, bio_info_cb *fp);
+
+const BIO_METHOD *BIO_f_tap(void)
+{
+    static BIO_METHOD *tap = NULL;
+
+    if (tap == NULL) {
+        tap = BIO_meth_new(BIO_TYPE_START | BIO_TYPE_FILTER, "tap");
+        if (tap != NULL) {
+            BIO_meth_set_write_ex(tap, tap_write_ex);
+            BIO_meth_set_read_ex(tap, tap_read_ex);
+            BIO_meth_set_puts(tap, tap_puts);
+            BIO_meth_set_gets(tap, tap_gets);
+            BIO_meth_set_ctrl(tap, tap_ctrl);
+            BIO_meth_set_create(tap, tap_new);
+            BIO_meth_set_destroy(tap, tap_free);
+            BIO_meth_set_callback_ctrl(tap, tap_callback_ctrl);
+        }
+    }
+    return tap;
+}
+
+static int tap_new(BIO *b)
+{
+    BIO_set_data(b, NULL);
+    BIO_set_init(b, 1);
+    return 1;
+}
+
+static int tap_free(BIO *b)
+{
+    if (b == NULL)
+        return 0;
+    BIO_set_data(b, NULL);
+    BIO_set_init(b, 0);
+    return 1;
+}
+
+static int tap_read_ex(BIO *b, char *buf, size_t size, size_t *out_size)
+{
+    BIO *next = BIO_next(b);
+    int ret = 0;
+
+    ret = BIO_read_ex(next, buf, size, out_size);
+    BIO_clear_retry_flags(b);
+    BIO_copy_next_retry(b);
+    return ret;
+}
+
+/*
+ * Output a string to the specified bio and return 1 if successful.
+ */
+static int write_string(BIO *b, const char *buf, size_t n)
+{
+    size_t m;
+
+    return BIO_write_ex(b, buf, n, &m) != 0 && m == n;
+}
+
+/*
+ * Write some data.
+ *
+ * This function implements a simple state machine that detects new lines.
+ * It indents the output and prefixes it with a '#' character.
+ *
+ * It returns the number of input characters that were output in in_size.
+ * More characters than this will likely have been output however any calling
+ * code will be unable to correctly assess the actual number of characters
+ * emitted and would be prone to failure if the actual number were returned.
+ *
+ * The BIO_data field is used as our state.  If it is NULL, we've just
+ * seen a new line.  If it is not NULL, we're processing characters in a line.
+ */
+static int tap_write_ex(BIO *b, const char *buf, size_t size, size_t *in_size)
+{
+    BIO *next = BIO_next(b);
+    size_t i;
+    int j;
+
+    for (i = 0; i < size; i++) {
+        if (BIO_get_data(b) == NULL) {
+            BIO_set_data(b, "");
+            for (j = 0; j < subtest_level(); j++)
+                if (!write_string(next, " ", 1))
+                    goto err;
+            if (!write_string(next, "# ", 2))
+                goto err;
+        }
+        if (!write_string(next, buf + i, 1))
+            goto err;
+        if (buf[i] == '\n')
+            BIO_set_data(b, NULL);
+    }
+    *in_size = i;
+    return 1;
+
+err:
+    *in_size = i;
+    return 0;
+}
+
+static long tap_ctrl(BIO *b, int cmd, long num, void *ptr)
+{
+    BIO *next = BIO_next(b);
+    switch (cmd) {
+    case BIO_CTRL_RESET:
+        BIO_set_data(b, NULL);
+        break;
+
+    default:
+        break;
+    }
+    return BIO_ctrl(next, cmd, num, ptr);
+}
+
+static long tap_callback_ctrl(BIO *b, int cmd, bio_info_cb *fp)
+{
+    return BIO_callback_ctrl(BIO_next(b), cmd, fp);
+}
+
+static int tap_gets(BIO *b, char *buf, int size)
+{
+    return BIO_gets(BIO_next(b), buf, size);
+}
+
+static int tap_puts(BIO *b, const char *str)
+{
+    size_t m;
+
+    if (!tap_write_ex(b, str, strlen(str), &m))
+        return 0;
+    return m;
+}
index 283f1c789ddfa0a05715d5fc9e11a31216a47f77..b2d95db8593b08472e74344e558eeef5bf8c4492 100644 (file)
@@ -27,8 +27,7 @@ void test_fail_message_prefix(const char *prefix, const char *file,
                               const char *left, const char *right,
                               const char *op)
 {
-    test_printf_stderr("%*s# %s: ", subtest_level(), "",
-                       prefix != NULL ? prefix : "ERROR");
+    test_printf_stderr("%s: ", prefix != NULL ? prefix : "ERROR");
     if (type)
         test_printf_stderr("(%s) ", type);
     if (op != NULL) {
@@ -79,7 +78,6 @@ static void test_fail_message_va(const char *prefix, const char *file,
 {
     test_fail_message_prefix(prefix, file, line, type, left, right, op);
     if (fmt != NULL) {
-        test_printf_stderr("%*s# ", subtest_level(), "");
         test_vprintf_stderr(fmt, ap);
         test_printf_stderr("\n");
     }
@@ -150,7 +148,6 @@ void test_note(const char *fmt, ...)
     if (fmt != NULL) {
         va_list ap;
 
-        test_printf_stderr("%*s# ", subtest_level(), "");
         va_start(ap, fmt);
         test_vprintf_stderr(fmt, ap);
         va_end(ap);
index a42f2c3ee777fae9de34678fc713ee64431db7b0..5f69a1383a3aef31a8e960cf7bdac7d1fc2b8c39 100644 (file)
@@ -9,9 +9,11 @@
 
 #include <stdlib.h>              /* size_t */
 #include <openssl/bn.h>
+#include <openssl/bio.h>
 
 int subtest_level(void);
 int openssl_error_cb(const char *str, size_t len, void *u);
+const BIO_METHOD *BIO_f_tap(void);
 
 void test_fail_message_prefix(const char *prefix, const char *file,
                               int line, const char *type,